diff --git a/components/filebrowser/ctrlfilebrowser.pas b/components/filebrowser/ctrlfilebrowser.pas index ffef4cf8ac..af4dd639f0 100644 --- a/components/filebrowser/ctrlfilebrowser.pas +++ b/components/filebrowser/ctrlfilebrowser.pas @@ -9,9 +9,12 @@ uses LazIDEIntf, MenuIntf, IDECommands, ProjectIntf, IDEOptEditorIntf, IDEWindowIntf, BaseIDEIntf; Type - TFileSearchOption = (fsoMatchOnlyFileName,fsoAbsolutePaths); + TFileSearchOption = (fsoMatchOnlyFileName,fsoAbsolutePaths,fsoUseLetters); TFileSearchOptions = Set of TFileSearchOption; + TFilenameMatchOption = (fmoFileNameOnly,fmoLetters); + TFilenameMatchOptions = set of TFilenameMatchOption; + { TFileBrowserController } TFileBrowserController = class(TComponent) private @@ -68,7 +71,7 @@ Type procedure WriteConfig; virtual; procedure ReadConfig; virtual; procedure IndexRootDir; - function FindFiles(aPattern: String; aList: TStrings; aMatchOnlyFileName: boolean; aMask : TMaskList): Integer; + function FindFiles(aPattern: String; aOutFileList: TStrings; aMatchOptions : TFilenameMatchOptions; aExtMask : TMaskList): Integer; procedure Notification(AComponent: TComponent; Operation: TOperation); override; Property Root : TFileSystemEntry Read FRoot; property StartDir: TStartDir read FStartDir write SetStartDir; @@ -176,6 +179,8 @@ begin Include(Opts,fsoMatchOnlyFileName); if GetValue(KeySearchAbsoluteFilenames,False) then Include(Opts,fsoAbsolutePaths); + if GetValue(KeySearchLetters,False) then + Include(Opts,fsoUseLetters); SearchOptions:=Opts; finally Free; @@ -272,6 +277,7 @@ begin SetDeleteValue(KeySyncCurrentEditor,FSyncCurrentEditor, DefaultSyncCurrentEditor); SetDeleteValue(KeySearchMatchOnlyFilename,fsoMatchOnlyFileName in SearchOptions,False); SetDeleteValue(KeySearchAbsoluteFilenames,fsoAbsolutePaths in SearchOptions,False); + SetDeleteValue(KeySearchLetters,fsoUseLetters in SearchOptions,False); FNeedSave := False; finally Free; @@ -297,28 +303,57 @@ begin AddIDEMessage(mluVerbose,Format(SSearchingFiles,[lDir]),'',0,0,SViewFilebrowser); end; -function TFileBrowserController.FindFiles(aPattern: String; aList: TStrings; aMatchOnlyFileName: boolean; aMask: TMaskList - ): Integer; +function TFileBrowserController.FindFiles(aPattern: String; aOutFileList: TStrings; + aMatchOptions : TFilenameMatchOptions; aExtMask: TMaskList): Integer; + + function MatchesPattern(const aName: string; aStartPos: Integer; const aPtrn: string): Boolean; + var + lPtrnLen,lNameLen,lPtrnPos, lNamePos: Integer; + begin + lPtrnPos := 1; + lPtrnLen := Length(aPtrn); + lNameLen := Length(aName); + lNamePos := aStartPos; + + while (lPtrnPos <= lPtrnLen) and (lNamePos <= lNameLen) do + begin + if aName[lNamePos] = aPtrn[lPtrnPos] then + Inc(lPtrnPos); + Inc(lNamePos); + end; + + Result := (lPtrnPos > lPtrnLen); + end; var - s,ptrn : String; - i,ps : integer; + lPtrn, lFilename : String; + lStartPos,lFileIdx: Integer; + isMatch : Boolean; begin Result:=0; if (FFileList=Nil) or (Length(aPattern)<2) then exit; - ptrn:=LowerCase(aPattern); - For I:=0 to FFileList.Count-1 do - begin - S:=FFileList[i]; - if aMatchOnlyFileName then - ps:=rpos(PathDelim,S) + + lPtrn := Lowercase(aPattern); + + For lFileIdx:=0 to FFileList.Count-1 do + begin + lFilename := Lowercase(FFileList[lFileIdx]); + if fmoFileNameOnly in aMatchOptions then + lStartPos:=rpos(PathDelim,lFileName)+1 else - ps:=1; - if (Pos(ptrn,LowerCase(S),Ps)>0) then - if (aMask=Nil) or (aMask.Matches(ExtractFileName(S))) then - aList.AddObject(S,FFileList.Objects[i]); + lStartPos:=1; + + if (aExtMask=Nil) or (aExtMask.Matches(lFilename)) then + begin + if fmoLetters in aMatchOptions then + isMatch:=MatchesPattern(lFilename, lStartPos, lPtrn) + else + IsMatch:=(Pos(lPtrn,lFileName,lStartPos)>0); + if IsMatch then + aOutFileList.AddObject(FFileList[lFileIdx], FFileList.Objects[lFileIdx]); end; + end; end; procedure TFileBrowserController.ConfigWindow(AForm: TFileBrowserForm); diff --git a/components/filebrowser/filebrowsertypes.pas b/components/filebrowser/filebrowsertypes.pas index ed02ed7ae7..ac74cf33e2 100644 --- a/components/filebrowser/filebrowsertypes.pas +++ b/components/filebrowser/filebrowsertypes.pas @@ -127,6 +127,7 @@ const KeySyncCurrentEditor = 'SyncCurrentEditor'; KeySearchMatchOnlyFilename = 'MatchOnlyFileNames'; KeySearchAbsoluteFilenames = 'AbsoluteFileNames'; + KeySearchLetters = 'SearchLetters'; SViewFilebrowser = 'File browser'; diff --git a/components/filebrowser/fraconfigfilebrowser.lfm b/components/filebrowser/fraconfigfilebrowser.lfm index c45a15cec9..699eaebfb5 100644 --- a/components/filebrowser/fraconfigfilebrowser.lfm +++ b/components/filebrowser/fraconfigfilebrowser.lfm @@ -1,9 +1,9 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 0 - Height = 582 + Height = 618 Top = 0 Width = 803 - ClientHeight = 582 + ClientHeight = 618 ClientWidth = 803 TabOrder = 0 DesignLeft = 616 @@ -15,12 +15,12 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Width = 803 Align = alTop Caption = 'Root directory' - ClientHeight = 174 + ClientHeight = 173 ClientWidth = 801 TabOrder = 0 object DERootDir: TDirectoryEdit Left = 38 - Height = 28 + Height = 34 Top = 128 Width = 754 ShowHidden = False @@ -34,7 +34,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 16 Height = 23 Top = 96 - Width = 175 + Width = 191 Caption = 'Always use this directory' TabOrder = 1 end @@ -42,7 +42,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 14 Height = 23 Top = 36 - Width = 118 + Width = 131 Caption = 'Filesystem root' TabOrder = 2 end @@ -50,7 +50,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 14 Height = 23 Top = 9 - Width = 197 + Width = 220 Caption = 'Use current project directory' Checked = True TabOrder = 3 @@ -60,7 +60,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 14 Height = 23 Top = 64 - Width = 110 + Width = 122 Caption = 'User directory' TabOrder = 4 end @@ -72,12 +72,12 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Width = 803 Align = alTop Caption = 'Initial directory' - ClientHeight = 135 + ClientHeight = 134 ClientWidth = 801 TabOrder = 1 object DEStartDir: TDirectoryEdit Left = 38 - Height = 28 + Height = 34 Top = 89 Width = 752 ShowHidden = False @@ -91,7 +91,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 14 Height = 23 Top = 65 - Width = 175 + Width = 191 Caption = 'Always use this directory' TabOrder = 1 end @@ -99,7 +99,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 14 Height = 23 Top = 36 - Width = 179 + Width = 198 Caption = 'Use last opened directory' TabOrder = 2 end @@ -107,7 +107,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 14 Height = 23 Top = 8 - Width = 197 + Width = 220 Caption = 'Use current project directory' Checked = True TabOrder = 3 @@ -116,19 +116,19 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame end object GBSearch: TGroupBox Left = 0 - Height = 97 + Height = 129 Top = 456 Width = 803 Align = alTop Caption = 'Search' - ClientHeight = 80 + ClientHeight = 111 ClientWidth = 801 TabOrder = 2 object CBMatchOnlyFilename: TCheckBox Left = 8 Height = 23 Top = 16 - Width = 205 + Width = 223 Caption = 'Search matches only filename' TabOrder = 0 end @@ -136,10 +136,18 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 8 Height = 23 Top = 48 - Width = 177 + Width = 191 Caption = 'Show absolute filenames' TabOrder = 1 end + object CBUseLetters: TCheckBox + Left = 8 + Height = 23 + Top = 81 + Width = 285 + Caption = 'Match individual letters of search term' + TabOrder = 2 + end end object GBFileTree: TGroupBox Left = 0 @@ -148,14 +156,14 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Width = 803 Align = alTop Caption = 'File browser tree' - ClientHeight = 96 + ClientHeight = 95 ClientWidth = 801 TabOrder = 3 object CBShowFilesInline: TCheckBox Left = 24 Height = 23 Top = 8 - Width = 191 + Width = 207 Caption = 'Show files in main tree view' TabOrder = 0 OnChange = CBShowFilesInlineChange @@ -166,7 +174,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 52 Height = 23 Top = 39 - Width = 197 + Width = 218 BorderSpacing.Top = 8 Caption = 'Show directories before files' TabOrder = 1 @@ -178,7 +186,7 @@ object FileBrowserOptionsFrame: TFileBrowserOptionsFrame Left = 24 Height = 23 Top = 70 - Width = 277 + Width = 304 BorderSpacing.Top = 8 Caption = 'Keep synchronized with current editor file' TabOrder = 2 diff --git a/components/filebrowser/fraconfigfilebrowser.pas b/components/filebrowser/fraconfigfilebrowser.pas index bd5a36059f..d192f1cffa 100644 --- a/components/filebrowser/fraconfigfilebrowser.pas +++ b/components/filebrowser/fraconfigfilebrowser.pas @@ -20,6 +20,7 @@ type CBSyncCurrentEditor: TCheckBox; CBMatchOnlyFilename: TCheckBox; CBUseAbsoluteFilenames: TCheckBox; + CBUseLetters: TCheckBox; DEStartDir: TDirectoryEdit; DERootDir: TDirectoryEdit; GBStartDir: TGroupBox; @@ -110,6 +111,7 @@ begin CBSyncCurrentEditor.Checked:=C.SyncCurrentEditor; CBUseAbsoluteFilenames.Checked:=fsoAbsolutePaths in C.SearchOptions; CBMatchOnlyFilename.Checked:=fsoMatchOnlyFileName in C.SearchOptions; + CBUseLetters.Checked:=fsoUseLetters in C.SearchOptions; CheckDirsBeforeFiles; end; @@ -157,10 +159,13 @@ begin Include(SO,fsoAbsolutePaths); if CBMatchOnlyFilename.Checked then Include(SO,fsoMatchOnlyFileName); + if CBUseLetters.Checked then + Include(SO,fsoUseLetters); C.SearchOptions:=SO; // Re-index if lRootDir<>C.GetResolvedRootDir then C.IndexRootDir; + C.WriteConfig; end; class function TFileBrowserOptionsFrame.SupportedOptionsClass: TAbstractIDEOptionsClass; diff --git a/components/filebrowser/frmfilesearcher.pas b/components/filebrowser/frmfilesearcher.pas index 21ca1de7ea..c506f267cd 100644 --- a/components/filebrowser/frmfilesearcher.pas +++ b/components/filebrowser/frmfilesearcher.pas @@ -51,13 +51,22 @@ end; procedure TFileSearcherForm.DoFilter; +var + lMatchOptions : TFilenameMatchOptions; + begin if Not Assigned(FController) or (Length(edtSearch.Text)<2) then exit; + lMatchOptions:=[]; + if (fsoMatchOnlyFileName in FController.SearchOptions) then + Include(lMatchOptions,fmoFileNameOnly); + if (fsoUseLetters in FController.SearchOptions) then + Include(lMatchOptions,fmoLetters); + LBFiles.Items.BeginUpdate; try LBFiles.Items.Clear; - FController.FindFiles(edtSearch.Text,LBFiles.Items,(fsoMatchOnlyFileName in FController.SearchOptions),FMask); + FController.FindFiles(edtSearch.Text,LBFiles.Items,lMatchOptions,FMask); finally LBFiles.Items.EndUpdate; end;