Add exclude folder(s) capacity in Find in Files

This PR allows users to provide the list of excluding folder names/patterns in "Filters" field.
Eclusion operator is alway "!" at the begining. In order to distinguish folder from file, "\" should be used as prefix of the folder name/pattern, following "!". That allows the exclusion of the directories under the root directory you want to search (the 1st level of matched directories).

If users need to exclude folders with the same name (or names matched the specific pattern) in all levels, the + should be put between "!" and "\" to exclude them recursively.

Here is a sample:
Filters: *.* !\bin !+\test !+\log*
Directory: c:\myProject\

So the excluded directories could be:

    c:\myProject\bin\
    c:\myProject\log\
    c:\myProject\logs\
    c:\myProject\src\log4j\
    c:\myProject\test\
    c:\myProject\src\test\

The following directories will not be excluded:

    c:\myProject\foo\tests\
    c:\myProject\foo\bin\

Note that "inclusion of folder" is not allowed, and such pattern will be ignored.

Fix #2433, fix #8350, close #10927
This commit is contained in:
Don Ho 2021-12-20 18:10:13 +01:00
parent ac52f406f3
commit b5d646b4cd
7 changed files with 38 additions and 13 deletions

View File

@ -955,6 +955,27 @@ bool matchInList(const TCHAR *fileName, const std::vector<generic_string> & patt
return is_matched;
}
bool matchInExcludeDirList(const TCHAR* dirName, const std::vector<generic_string>& patterns, size_t level)
{
for (size_t i = 0, len = patterns.size(); i < len; ++i)
{
size_t patterLen = patterns[i].length();
if (patterLen > 3 && patterns[i][0] == '!' && patterns[i][1] == '+' && patterns[i][2] == '\\') // check for !+\folderPattern: for all levels - search this pattern recursively
{
if (PathMatchSpec(dirName, patterns[i].c_str() + 3))
return true;
}
else if (patterLen > 2 && patterns[i][0] == '!' && patterns[i][1] == '\\') // check for !\folderPattern: exclusive pattern for only the 1st level
{
if (level == 1)
if (PathMatchSpec(dirName, patterns[i].c_str() + 2))
return true;
}
}
return false;
}
bool allPatternsAreExclusion(const std::vector<generic_string> patterns)
{
bool oneInclusionPatternFound = false;

View File

@ -83,6 +83,7 @@ std::string getFileContent(const TCHAR *file2read);
generic_string relativeFilePathToFullFilePath(const TCHAR *relativeFilePath);
void writeFileContent(const TCHAR *file2write, const char *content2write);
bool matchInList(const TCHAR *fileName, const std::vector<generic_string> & patterns);
bool matchInExcludeDirList(const TCHAR* dirName, const std::vector<generic_string>& patterns, size_t level);
bool allPatternsAreExclusion(const std::vector<generic_string> patterns);
class WcharMbcsConvertor final

View File

@ -1465,8 +1465,9 @@ void Notepad_plus::removeDuplicateLines()
_findReplaceDlg.processAll(ProcessReplaceAll, &env, isEntireDoc);
}
void Notepad_plus::getMatchedFileNames(const TCHAR *dir, const vector<generic_string> & patterns, vector<generic_string> & fileNames, bool isRecursive, bool isInHiddenDir)
void Notepad_plus::getMatchedFileNames(const TCHAR *dir, size_t level, const vector<generic_string> & patterns, vector<generic_string> & fileNames, bool isRecursive, bool isInHiddenDir)
{
level++;
generic_string dirFilter(dir);
dirFilter += TEXT("*.*");
WIN32_FIND_DATA foundData;
@ -1484,12 +1485,13 @@ void Notepad_plus::getMatchedFileNames(const TCHAR *dir, const vector<generic_st
}
else if (isRecursive)
{
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0) &&
!matchInExcludeDirList(foundData.cFileName, patterns, level))
{
generic_string pathDir(dir);
pathDir += foundData.cFileName;
pathDir += TEXT("\\");
getMatchedFileNames(pathDir.c_str(), patterns, fileNames, isRecursive, isInHiddenDir);
getMatchedFileNames(pathDir.c_str(), level, patterns, fileNames, isRecursive, isInHiddenDir);
}
}
}
@ -1513,12 +1515,13 @@ void Notepad_plus::getMatchedFileNames(const TCHAR *dir, const vector<generic_st
}
else if (isRecursive)
{
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0) &&
!matchInExcludeDirList(foundData.cFileName, patterns, level))
{
generic_string pathDir(dir);
pathDir += foundData.cFileName;
pathDir += TEXT("\\");
getMatchedFileNames(pathDir.c_str(), patterns, fileNames, isRecursive, isInHiddenDir);
getMatchedFileNames(pathDir.c_str(), level, patterns, fileNames, isRecursive, isInHiddenDir);
}
}
}
@ -1548,7 +1551,7 @@ bool Notepad_plus::createFilelistForFiles(vector<generic_string> & fileNames)
bool isRecursive = _findReplaceDlg.isRecursive();
bool isInHiddenDir = _findReplaceDlg.isInHiddenDir();
getMatchedFileNames(dir2Search, patterns2Match, fileNames, isRecursive, isInHiddenDir);
getMatchedFileNames(dir2Search, 0, patterns2Match, fileNames, isRecursive, isInHiddenDir);
return true;
}

View File

@ -571,7 +571,7 @@ private:
bool findInOpenedFiles();
bool findInCurrentFile(bool isEntireDoc);
void getMatchedFileNames(const TCHAR *dir, const std::vector<generic_string> & patterns, std::vector<generic_string> & fileNames, bool isRecursive, bool isInHiddenDir);
void getMatchedFileNames(const TCHAR *dir, size_t level, const std::vector<generic_string> & patterns, std::vector<generic_string> & fileNames, bool isRecursive, bool isInHiddenDir);
void doSynScorll(HWND hW);
void setWorkingDir(const TCHAR *dir);
bool str2Cliboard(const generic_string & str2cpy);

View File

@ -205,7 +205,7 @@ void Notepad_plus_Window::init(HINSTANCE hInst, HWND parent, const TCHAR *cmdLin
std::wstring localizationDir = nppDir;
pathAppend(localizationDir, TEXT("localization\\"));
_notepad_plus_plus_core.getMatchedFileNames(localizationDir.c_str(), patterns, fileNames, false, false);
_notepad_plus_plus_core.getMatchedFileNames(localizationDir.c_str(), 0, patterns, fileNames, false, false);
for (size_t i = 0, len = fileNames.size(); i < len; ++i)
localizationSwitcher.addLanguageFromXml(fileNames[i]);
@ -220,7 +220,7 @@ void Notepad_plus_Window::init(HINSTANCE hInst, HWND parent, const TCHAR *cmdLin
{
appDataThemeDir = nppParams.getAppDataNppDir();
pathAppend(appDataThemeDir, TEXT("themes\\"));
_notepad_plus_plus_core.getMatchedFileNames(appDataThemeDir.c_str(), patterns, fileNames, false, false);
_notepad_plus_plus_core.getMatchedFileNames(appDataThemeDir.c_str(), 0, patterns, fileNames, false, false);
for (size_t i = 0, len = fileNames.size() ; i < len ; ++i)
{
themeSwitcher.addThemeFromXml(fileNames[i]);
@ -236,7 +236,7 @@ void Notepad_plus_Window::init(HINSTANCE hInst, HWND parent, const TCHAR *cmdLin
// Set theme directory to their installation directory
themeSwitcher.setThemeDirPath(nppThemeDir);
_notepad_plus_plus_core.getMatchedFileNames(nppThemeDir.c_str(), patterns, fileNames, false, false);
_notepad_plus_plus_core.getMatchedFileNames(nppThemeDir.c_str(), 0, patterns, fileNames, false, false);
for (size_t i = 0, len = fileNames.size(); i < len ; ++i)
{
generic_string themeName( themeSwitcher.getThemeFromXmlFileName(fileNames[i].c_str()) );

View File

@ -414,7 +414,7 @@ BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive,
// and avoid to call (if pass string) :
// string (const string& str, size_t pos, size_t len = npos);
getMatchedFileNames(dir.c_str(), patterns, fileNames, isRecursive, false);
getMatchedFileNames(dir.c_str(), 0, patterns, fileNames, isRecursive, false);
}
}
else
@ -424,7 +424,7 @@ BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive,
fileNameStr += TEXT("\\");
patterns.push_back(TEXT("*"));
getMatchedFileNames(fileNameStr.c_str(), patterns, fileNames, true, false);
getMatchedFileNames(fileNameStr.c_str(), 0, patterns, fileNames, true, false);
}
bool ok2Open = true;

View File

@ -1066,7 +1066,7 @@ INT_PTR CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
generic_string checkboxTip = pNativeSpeaker->getLocalizedStrFromID("two-find-buttons-tip", TEXT("2 find buttons mode"));
_2ButtonsTip = CreateToolTip(IDC_2_BUTTONS_MODE, _hSelf, _hInst, const_cast<PTSTR>(checkboxTip.c_str()), _isRTL);
generic_string findInFilesFilterTip = pNativeSpeaker->getLocalizedStrFromID("find-in-files-filter-tip", TEXT("Find in cpp, cxx, h, hxx && hpp:\r*.cpp *.cxx *.h *.hxx *.hpp\r\rFind in all files except exe, obj && log:\r*.* !*.exe !*.obj !*.log"));
generic_string findInFilesFilterTip = pNativeSpeaker->getLocalizedStrFromID("find-in-files-filter-tip", TEXT("Find in cpp, cxx, h, hxx && hpp:\r*.cpp *.cxx *.h *.hxx *.hpp\r\rFind in all files except exe, obj && log:\r*.* !*.exe !*.obj !*.log\r\rFind in all files but exclude folders tests, bin && bin64:\r*.* !\\tests !\\bin*\r\rFind in all files but exclude all folders log or logs recursively:\r*.* !+\\log*"));
_filterTip = CreateToolTip(IDD_FINDINFILES_FILTERS_STATIC, _hSelf, _hInst, const_cast<PTSTR>(findInFilesFilterTip.c_str()), _isRTL);
::SetWindowTextW(::GetDlgItem(_hSelf, IDC_FINDPREV), TEXT(""));