diff --git a/ide/findinfilesdlg.pas b/ide/findinfilesdlg.pas index cc5df73c56..94da1fb072 100644 --- a/ide/findinfilesdlg.pas +++ b/ide/findinfilesdlg.pas @@ -133,6 +133,10 @@ begin OkButton.Caption := lisLazBuildOk; CancelButton.Caption := dlgCancel; + {$IFDEF EnableMultiReplace} + ReplaceCheckBox.Enabled:=true; + {$ENDIF} + UpdateReplaceCheck; end; diff --git a/ide/frmsearch.pas b/ide/frmsearch.pas index 493649aa97..977ab98867 100644 --- a/ide/frmsearch.pas +++ b/ide/frmsearch.pas @@ -36,6 +36,8 @@ uses Graphics, Dialogs, ExtCtrls, StdCtrls, Buttons, FileUtil, // synedit, codetools SynRegExpr, SourceLog, KeywordFuncLists, + // IDEIntf + LazIDEIntf, SrcEditorIntf, // ide LazarusIDEStrConsts, InputHistory, FindInFilesDlg, SearchResultView; @@ -65,7 +67,7 @@ type fMatches: longint; fPad: string; fParsedMasks: TStringList; //Holds the parsed masks. - frecursive: boolean; + fRecursive: boolean; fRegExp: Boolean; FReplaceText: string; fResultsList: TStrings; @@ -77,6 +79,8 @@ type fSearchProject: boolean; fTheDirectory: string; fWholeWord: Boolean; + fReplace: boolean; + fReplaceAll: boolean; procedure SearchFile(TheFileName: string); procedure DoFindInFiles(TheFileName: string); procedure DoFindInSearchList; @@ -99,7 +103,7 @@ type property SearchMask: string read fMask write fMask; property Pad: string read fPad write fPad; property ResultsWindow: integer read fResultsWindow write fResultsWindow; - end; + end; var SearchForm: TSearchForm; @@ -110,7 +114,7 @@ implementation procedure TSearchForm.btnAbortCLICK(Sender: TObject); begin - fAbort:= true; + fAbort:= true; end; procedure TSearchForm.SearchFormCREATE(Sender: TObject); @@ -123,6 +127,8 @@ begin Caption:=dlgSearchCaption; fWholeWord:= false; + fReplace:=false; + fReplaceAll:=false; fCaseSensitive:= false; fRecursive:= True; fAbort:= false; @@ -144,6 +150,8 @@ end; procedure TSearchForm.SetOptions(TheOptions: TLazFindInFileSearchOptions); begin fWholeWord:= (fifWholeWord in TheOptions); + fReplace:=(fifReplace in TheOptions); + fReplaceAll:=(fifReplaceAll in TheOptions); fCaseSensitive:= (fifMatchCase in TheOptions); fRegExp := (fifRegExpr in TheOptions); frecursive:= (fifIncludeSubDirs in TheOptions); @@ -157,8 +165,11 @@ begin Result:=[]; if fWholeWord then include(Result,fifWholeWord); if fCaseSensitive then include(Result,fifMatchCase); + if fReplace then include(Result,fifReplace); + if fReplaceAll then include(Result,fifReplaceAll); if fRegExp then include(Result,fifRegExpr); if fRecursive then include(Result,fifIncludeSubDirs); + if fRecursive then include(Result,fifIncludeSubDirs); if fSearchProject then include(Result, fifSearchProject); if fSearchOpen then include(Result,fifSearchOpen); if fSearchFiles then include(Result,fifSearchDirectories); @@ -263,11 +274,6 @@ procedure TSearchForm.SearchFile(TheFileName: string); Result:=copy(Line,StartPos,EndPos-StartPos); end; - procedure DoReplaceLine; - begin - - end; - {Start SearchFile ============================================================} var ThisFile: TSourceLog; //The original File being searched @@ -284,14 +290,50 @@ var LastMatchEnd: Integer; WorkLine: String; TrimmedCurLine: String; - Replace: boolean; SearchAllHitsInLine: boolean; + PromptOnReplace: boolean; + + procedure DoReplaceLine; + var + ASearch: String; + AReplace: String; + Action: TSrcEditReplaceAction; + begin + // ask the user + if PromptOnReplace then begin + // open the place in the source editor + if LazarusIDE.DoOpenFileAndJumpToPos(TheFileName,Point(Match,Line),-1,-1, + [ofUseCache,ofDoNotLoadResource,ofVirtualFile,ofRegularFile]) + <>mrOk then + begin + fAbort:=true; + exit; + end; + ASearch:=copy(CurLine,Match,MatchLen); + AReplace:=ReplaceText; + SourceEditorWindow.ActiveEditor.AskReplace(Self,ASearch,AReplace, + Line,Match,Action); + case Action of + seraSkip: exit; + seraReplace: ; + seraReplaceAll: PromptOnReplace:=false; + else + fAbort:=true; + exit; + end; + end; + // TODO: create change text + end; + begin + if fAbort then exit; + ThisFile:=nil; UpperFile:=nil; RE:=nil; - Replace:=[fifReplace,fifReplaceAll]*SearchOptions<>[]; - SearchAllHitsInLine:=Replace; + PromptOnReplace:=fReplace; + SearchAllHitsInLine:=fReplace; + fResultsList.BeginUpdate; try MatchLen:= Length(fSearchFor); @@ -356,10 +398,9 @@ begin // add found place if Found then begin - DebugLn('TSearchForm.SearchFile CurLine="',CurLine,'" Found=',dbgs(Found),' Match=',dbgs(Match),' MatchLen=',dbgs(MatchLen),' Line=',dbgs(Line)); - if Replace then begin + //DebugLn('TSearchForm.SearchFile CurLine="',CurLine,'" Found=',dbgs(Found),' Match=',dbgs(Match),' MatchLen=',dbgs(MatchLen),' Line=',dbgs(Line)); + if fReplace then DoReplaceLine; - end; TrimmedMatch:=Match; TrimmedCurLine:=TrimLineAndMatch(CurLine,TrimmedMatch); SearchResultsView.AddMatch(fResultsWindow, @@ -368,7 +409,7 @@ begin UpdateMatches; end else break; - until (not SearchAllHitsInLine) or (MatchLen<1); + until fAbort or (not SearchAllHitsInLine) or (MatchLen<1); // check abort if fAbort and not fAborting then diff --git a/ide/searchresultview.pp b/ide/searchresultview.pp index ee062cc09c..c592db9066 100644 --- a/ide/searchresultview.pp +++ b/ide/searchresultview.pp @@ -173,7 +173,7 @@ procedure TSearchResultsView.Form1Create(Sender: TObject); var ALayout: TIDEWindowLayout; begin - FMaxItems:=10; + FMaxItems:=500; ResultsNoteBook.Options:= ResultsNoteBook.Options+[nboShowCloseButtons]; ResultsNoteBook.Update; diff --git a/ide/uniteditor.pp b/ide/uniteditor.pp index d15c75c0ea..553920646d 100644 --- a/ide/uniteditor.pp +++ b/ide/uniteditor.pp @@ -216,6 +216,8 @@ type // dialogs procedure StartFindAndReplace(Replace:boolean); + procedure AskReplace(Sender: TObject; const ASearch, AReplace: + string; Line, Column: integer; var Action: TSrcEditReplaceAction); override; procedure OnReplace(Sender: TObject; const ASearch, AReplace: string; Line, Column: integer; var Action: TSynReplaceAction); function DoFindAndReplace: Integer; @@ -1069,6 +1071,23 @@ begin end;//End try-finally end; +procedure TSourceEditor.AskReplace(Sender: TObject; const ASearch, + AReplace: string; Line, Column: integer; var Action: TSrcEditReplaceAction); +var + SynAction: TSynReplaceAction; +begin + SynAction:=raCancel; + OnReplace(Sender, ASearch, AReplace, Line, Column, SynAction); + case SynAction of + raSkip: Action:=seraSkip; + raReplaceAll: Action:=seraReplaceAll; + raReplace: Action:=seraReplace; + raCancel: Action:=seraCancel; + else + RaiseGDBException('TSourceEditor.AskReplace: inconsistency'); + end; +end; + {------------------------------F I N D A G A I N ----------------------------} procedure TSourceEditor.FindNext; var diff --git a/ideintf/srceditorintf.pas b/ideintf/srceditorintf.pas index 36f76619de..abf75457bc 100644 --- a/ideintf/srceditorintf.pas +++ b/ideintf/srceditorintf.pas @@ -28,6 +28,7 @@ type sesoRegExpr, sesoRegExprMultiLine); TSrcEditSearchOptions = set of TSrcEditSearchOption; + TSrcEditReplaceAction = (seraCancel, seraSkip, seraReplace, seraReplaceAll); { TSourceEditorInterface } @@ -68,6 +69,9 @@ type procedure SelectText(const StartPos, EndPos: TPoint); virtual; abstract; procedure ReplaceLines(StartLine, EndLine: integer; const NewText: string); virtual; abstract; procedure ReplaceText(const StartPos, EndPos: TPoint; const NewText: string); + procedure AskReplace(Sender: TObject; const ASearch, AReplace: string; + Line, Column: integer; + var Action: TSrcEditReplaceAction); virtual; abstract; procedure CopyToClipboard; virtual; abstract; procedure CutToClipboard; virtual; abstract;