SourceEditor: Fixed searching from cursor, if selection exists / Cleanup Search code. Issue #0014449

git-svn-id: trunk@27952 -
This commit is contained in:
martin 2010-10-29 18:44:13 +00:00
parent ed30c1caeb
commit 1099ea482a
4 changed files with 63 additions and 137 deletions

View File

@ -824,10 +824,8 @@ type
{$IFDEF SYN_LAZARUS}const {$ENDIF}RowCol: TPoint): TPoint; {$IFDEF SYN_LAZARUS}const {$ENDIF}RowCol: TPoint): TPoint;
function SearchReplace(const ASearch, AReplace: string; function SearchReplace(const ASearch, AReplace: string;
AOptions: TSynSearchOptions): integer; AOptions: TSynSearchOptions): integer;
{$IFDEF SYN_LAZARUS}
function SearchReplaceEx(const ASearch, AReplace: string; function SearchReplaceEx(const ASearch, AReplace: string;
AOptions: TSynSearchOptions; AStart: TPoint): integer; AOptions: TSynSearchOptions; AStart: TPoint): integer;
{$ENDIF}
procedure SelectAll; procedure SelectAll;
Procedure SetHighlightSearch(const ASearch: String; AOptions: TSynSearchOptions); Procedure SetHighlightSearch(const ASearch: String; AOptions: TSynSearchOptions);
procedure SelectToBrace; procedure SelectToBrace;
@ -6991,14 +6989,22 @@ end;
// find / replace // find / replace
function TCustomSynEdit.SearchReplace(const ASearch, AReplace: string; function TCustomSynEdit.SearchReplace(const ASearch, AReplace: string;
AOptions: TSynSearchOptions): integer; AOptions: TSynSearchOptions): integer;
{$IFDEF SYN_LAZARUS} var
StartPos: TPoint;
begin begin
Result := SearchReplaceEx(ASearch, AReplace, AOptions, LogicalCaretXY); if (ssoFindContinue in AOptions) and SelAvail then begin
if ssoBackwards in AOptions then
StartPos := BlockBegin
else
StartPos := BlockEnd;
end
else
StartPos := LogicalCaretXY;
Result := SearchReplaceEx(ASearch, AReplace, AOptions, StartPos);
end; end;
function TCustomSynEdit.SearchReplaceEx(const ASearch, AReplace: string; function TCustomSynEdit.SearchReplaceEx(const ASearch, AReplace: string;
AOptions: TSynSearchOptions; AStart: TPoint): integer; AOptions: TSynSearchOptions; AStart: TPoint): integer;
{$ENDIF}
var var
ptStart, ptEnd: TPoint; // start and end of the search range ptStart, ptEnd: TPoint; // start and end of the search range
ptCurrent: TPoint; // current search position ptCurrent: TPoint; // current search position
@ -7007,12 +7013,8 @@ var
bPrompt: boolean; bPrompt: boolean;
bReplace, bReplaceAll: boolean; bReplace, bReplaceAll: boolean;
nAction: TSynReplaceAction; nAction: TSynReplaceAction;
{$IFDEF SYN_LAZARUS}
CurReplace: string; CurReplace: string;
ptFoundStart, ptFoundEnd: TPoint; ptFoundStart, ptFoundEnd: TPoint;
{$ELSE}
n, nSearchLen, nReplaceLen, nInLine: integer;
{$ENDIF}
function InValidSearchRange(First, Last: integer): boolean; function InValidSearchRange(First, Last: integer): boolean;
begin begin
@ -7060,9 +7062,9 @@ begin
ptEnd.X := Length(FTheLinesView[ptEnd.Y - 1]) + 1; ptEnd.X := Length(FTheLinesView[ptEnd.Y - 1]) + 1;
if bFromCursor then if bFromCursor then
if bBackward then if bBackward then
ptEnd := {$IFDEF SYN_LAZARUS}AStart{$ELSE}CaretXY{$ENDIF} ptEnd := AStart
else else
ptStart := {$IFDEF SYN_LAZARUS}AStart{$ELSE}CaretXY{$ENDIF}; ptStart := AStart;
if bBackward then ptCurrent := ptEnd else ptCurrent := ptStart; if bBackward then ptCurrent := ptEnd else ptCurrent := ptStart;
end; end;
// initialize the search engine // initialize the search engine
@ -7070,18 +7072,12 @@ begin
fTSearch.Whole := ssoWholeWord in AOptions; fTSearch.Whole := ssoWholeWord in AOptions;
fTSearch.Pattern := ASearch; fTSearch.Pattern := ASearch;
fTSearch.RegularExpressions := ssoRegExpr in AOptions; fTSearch.RegularExpressions := ssoRegExpr in AOptions;
{$IFDEF SYN_LAZARUS}
fTSearch.RegExprMultiLine := ssoRegExprMultiLine in AOptions; fTSearch.RegExprMultiLine := ssoRegExprMultiLine in AOptions;
fTSearch.Replacement:=AReplace; fTSearch.Replacement:=AReplace;
fTSearch.Backwards:=bBackward; fTSearch.Backwards:=bBackward;
{$ELSE}
nSearchLen := Length(ASearch);
nReplaceLen := Length(AReplace);
{$ENDIF}
// search while the current search position is inside of the search range // search while the current search position is inside of the search range
IncPaintLock; IncPaintLock;
try try
{$IFDEF SYN_LAZARUS}
//DebugLn(['TCustomSynEdit.SearchReplace ptStart=',dbgs(ptStart),' ptEnd=',dbgs(ptEnd),' ASearch="',dbgstr(ASearch),'" AReplace="',dbgstr(AReplace),'"']); //DebugLn(['TCustomSynEdit.SearchReplace ptStart=',dbgs(ptStart),' ptEnd=',dbgs(ptEnd),' ASearch="',dbgstr(ASearch),'" AReplace="',dbgstr(AReplace),'"']);
while fTSearch.FindNextOne(FTheLinesView,ptStart,ptEnd,ptFoundStart,ptFoundEnd) do while fTSearch.FindNextOne(FTheLinesView,ptStart,ptEnd,ptFoundStart,ptFoundEnd) do
begin begin
@ -7156,60 +7152,6 @@ begin
end; end;
//DebugLn(['TCustomSynEdit.SearchReplace FIND NEXT ptStart=',dbgs(ptStart),' ptEnd=',dbgs(ptEnd)]); //DebugLn(['TCustomSynEdit.SearchReplace FIND NEXT ptStart=',dbgs(ptStart),' ptEnd=',dbgs(ptEnd)]);
end; end;
{$ELSE}
while (ptCurrent.Y >= ptStart.Y) and (ptCurrent.Y <= ptEnd.Y) do begin
nInLine := fTSearch.FindAll(Lines[ptCurrent.Y - 1]);
if bBackward then n := Pred(fTSearch.ResultCount) else n := 0;
// Operate on all results in this line.
while nInLine > 0 do begin
nFound := fTSearch.Results[n];
if bBackward then Dec(n) else Inc(n);
Dec(nInLine);
// Is the search result entirely in the search range?
if not InValidSearchRange(nFound, nFound + nSearchLen) then continue;
Inc(Result);
// Select the text, so the user can see it in the OnReplaceText event
// handler or as the search result.
ptCurrent.X := nFound;
BlockBegin := ptCurrent;
if bBackward then CaretXY := ptCurrent;
Inc(ptCurrent.X, nSearchLen);
BlockEnd := ptCurrent;
if not bBackward then CaretXY := ptCurrent;
// If it's a search only we can leave the procedure now.
if not (bReplace or bReplaceAll) then exit;
// Prompt and replace or replace all. If user chooses to replace
// all after prompting, turn off prompting.
if bPrompt and Assigned(fOnReplaceText) then begin
EnsureCursorPosVisible;
nAction := DoOnReplaceText(ASearch,AReplace,ptCurrent.Y, nFound);
if nAction = raCancel then exit;
end else
nAction := raReplace;
if not (nAction = raSkip) then begin
// user has been prompted and has requested to silently replace all
// so turn off prompting
if nAction = raReplaceAll then begin
if not bReplaceAll then begin
bReplaceAll := TRUE;
end;
bPrompt := False;
end;
SetSelTextExternal(AReplace);
end;
// fix the caret position and the remaining results
if not bBackward then begin
CaretX := nFound + nReplaceLen;
if (nSearchLen <> nReplaceLen) and (nAction <> raSkip) then
fTSearch.FixResults(nFound, nSearchLen - nReplaceLen);
end;
if not bReplaceAll then
exit;
end;
// search next / previous line
if bBackward then Dec(ptCurrent.Y) else Inc(ptCurrent.Y);
end;
{$ENDIF}
finally finally
DecPaintLock; DecPaintLock;
end; end;

View File

@ -69,11 +69,17 @@ type
TSynSelectionMode = (smNormal, smLine, smColumn, smCurrent); TSynSelectionMode = (smNormal, smLine, smColumn, smCurrent);
{$IFDEF SYN_LAZARUS}{$PACKENUM 4}{$ENDIF SYN_LAZARUS} {$IFDEF SYN_LAZARUS}{$PACKENUM 4}{$ENDIF SYN_LAZARUS}
TSynSearchOption = (ssoMatchCase, ssoWholeWord, ssoBackwards, TSynSearchOption =
ssoEntireScope, ssoSelectedOnly, ssoReplace, ssoReplaceAll, ssoPrompt ( ssoMatchCase, ssoWholeWord,
{$IFDEF SYN_LAZARUS}, ssoBackwards,
ssoSearchInReplacement,// continue search in replacement ssoEntireScope, ssoSelectedOnly,
ssoRegExpr, ssoRegExprMultiLine{$ENDIF}); ssoReplace, ssoReplaceAll,
ssoPrompt,
ssoSearchInReplacement, // continue search-replace in replacement (with ssoReplaceAll) // replace recursive
ssoRegExpr, ssoRegExprMultiLine,
ssoFindContinue // Assume the current selection is the last match, and start search behind selection
// (before if ssoBackward) // Default is to start at caret (Only SearchReplace / SearchReplaceEx has start/end param)
);
TSynSearchOptions = set of TSynSearchOption; TSynSearchOptions = set of TSynSearchOption;
{$IFDEF SYN_LAZARUS} {$IFDEF SYN_LAZARUS}

View File

@ -323,7 +323,8 @@ const
'Prompt', 'Prompt',
'SearchInReplacement', 'SearchInReplacement',
'RegExpr', 'RegExpr',
'RegExprMultiLine' 'RegExprMultiLine',
'ssoFindContinue'
); );
LazFindInFileSearchOptionsDefault = [fifSearchOpen]; LazFindInFileSearchOptionsDefault = [fifSearchOpen];
LazFindInFileSearchOptionNames: array[TLazFindInFileSearchOption] of string =( LazFindInFileSearchOptionNames: array[TLazFindInFileSearchOption] of string =(

View File

@ -347,7 +347,7 @@ type
string; Line, Column: integer; var Action: TSrcEditReplaceAction); override; string; Line, Column: integer; var Action: TSrcEditReplaceAction); override;
procedure OnReplace(Sender: TObject; const ASearch, AReplace: procedure OnReplace(Sender: TObject; const ASearch, AReplace:
string; Line, Column: integer; var Action: TSynReplaceAction); string; Line, Column: integer; var Action: TSynReplaceAction);
function DoFindAndReplace: Integer; function DoFindAndReplace(aFindText, aReplaceText: String; anOptions: TSynSearchOptions): Integer;
procedure FindNextUTF8; procedure FindNextUTF8;
procedure FindPrevious; procedure FindPrevious;
procedure FindNextWordOccurrence(DirectionForward: boolean); procedure FindNextWordOccurrence(DirectionForward: boolean);
@ -2485,7 +2485,8 @@ begin
InputHistories.AddToReplaceHistory(LazFindReplaceDialog.ReplaceText); InputHistories.AddToReplaceHistory(LazFindReplaceDialog.ReplaceText);
InputHistories.AddToFindHistory(LazFindReplaceDialog.FindText); InputHistories.AddToFindHistory(LazFindReplaceDialog.FindText);
InputHistories.Save; InputHistories.Save;
DoFindAndReplace; DoFindAndReplace(LazFindReplaceDialog.FindText, LazFindReplaceDialog.ReplaceText,
LazFindReplaceDialog.Options);
finally finally
//Restore original find options //Restore original find options
if bSelectedTextOption then if bSelectedTextOption then
@ -2518,44 +2519,39 @@ procedure TSourceEditor.FindNextUTF8;
var var
OldOptions: TSynSearchOptions; OldOptions: TSynSearchOptions;
begin begin
if snIncrementalFind in FSourceNoteBook.States if snIncrementalFind in FSourceNoteBook.States then begin
then begin
FSourceNoteBook.IncrementalSearch(True, False); FSourceNoteBook.IncrementalSearch(True, False);
end end
else if LazFindReplaceDialog.FindText = '' else if LazFindReplaceDialog.FindText = '' then begin
then begin
StartFindAndReplace(False) StartFindAndReplace(False)
end end
else begin else begin
OldOptions:=LazFindReplaceDialog.Options; DoFindAndReplace(LazFindReplaceDialog.FindText, LazFindReplaceDialog.ReplaceText,
LazFindReplaceDialog.Options:=LazFindReplaceDialog.Options LazFindReplaceDialog.Options - [ssoEntireScope, ssoSelectedOnly, ssoReplaceAll]
-[ssoEntireScope,ssoReplaceAll]; + [ssoFindContinue]);
DoFindAndReplace;
LazFindReplaceDialog.Options:=OldOptions;
end; end;
End; End;
{---------------------------F I N D P R E V I O U S ------------------------} {---------------------------F I N D P R E V I O U S ------------------------}
procedure TSourceEditor.FindPrevious; procedure TSourceEditor.FindPrevious;
var var
OldOptions: TSynSearchOptions; SrchOptions: TSynSearchOptions;
begin begin
if snIncrementalFind in FSourceNoteBook.States if snIncrementalFind in FSourceNoteBook.States then begin
then begin
FSourceNoteBook.IncrementalSearch(True, True); FSourceNoteBook.IncrementalSearch(True, True);
end end
else begin else if LazFindReplaceDialog.FindText = '' then begin
OldOptions:=LazFindReplaceDialog.Options; // TODO: maybe start with default set to backwards direction? But StartFindAndReplace replaces it with input-history
LazFindReplaceDialog.Options:=LazFindReplaceDialog.Options-[ssoEntireScope]; StartFindAndReplace(False);
if ssoBackwards in LazFindReplaceDialog.Options then end else begin
LazFindReplaceDialog.Options:=LazFindReplaceDialog.Options-[ssoBackwards] SrchOptions:=LazFindReplaceDialog.Options - [ssoEntireScope, ssoSelectedOnly, ssoReplaceAll]
+ [ssoFindContinue];
if ssoBackwards in SrchOptions then
SrchOptions := SrchOptions - [ssoBackwards]
else else
LazFindReplaceDialog.Options:=LazFindReplaceDialog.Options+[ssoBackwards]; SrchOptions := SrchOptions + [ssoBackwards];
if LazFindReplaceDialog.FindText = '' then DoFindAndReplace(LazFindReplaceDialog.FindText, LazFindReplaceDialog.ReplaceText,
StartFindAndReplace(False) SrchOptions);
else
DoFindAndReplace;
LazFindReplaceDialog.Options:=OldOptions;
end; end;
end; end;
@ -2580,37 +2576,25 @@ begin
'',Flags); '',Flags);
end; end;
function TSourceEditor.DoFindAndReplace: integer; function TSourceEditor.DoFindAndReplace(aFindText, aReplaceText: String;
anOptions: TSynSearchOptions): integer;
var var
OldCaretXY: TPoint; OldCaretXY: TPoint;
AText, ACaption: String; AText, ACaption: String;
NewTopLine: integer; NewTopLine: integer;
begin begin
Result:=0; Result:=0;
if SourceNotebook<>nil then if (ssoReplace in anOptions) and ReadOnly then begin
Manager.AddJumpPointClicked(Self);
if (ssoReplace in LazFindReplaceDialog.Options)
and ReadOnly then begin
DebugLn(['TSourceEditor.DoFindAndReplace Read only']); DebugLn(['TSourceEditor.DoFindAndReplace Read only']);
exit; exit;
end; end;
if SourceNotebook<>nil then
Manager.AddJumpPointClicked(Self);
OldCaretXY:=EditorComponent.CaretXY; OldCaretXY:=EditorComponent.CaretXY;
if EditorComponent.SelAvail and //debugln('TSourceEditor.DoFindAndReplace A aFindText="',dbgstr(aFindText),'" ssoEntireScope=',dbgs(ssoEntireScope in anOptions),' ssoBackwards=',dbgs(ssoBackwards in anOptions));
not(ssoSelectedOnly in LazFindReplaceDialog.Options)
then begin
// Adjust the cursor. to exclude the selection from being searched
// needed for find next / find previous
if ssoBackwards in LazFindReplaceDialog.Options then
EditorComponent.LogicalCaretXY:=EditorComponent.BlockBegin
else
EditorComponent.LogicalCaretXY:=EditorComponent.BlockEnd
end;
//debugln('TSourceEditor.DoFindAndReplace A LazFindReplaceDialog.FindText="',dbgstr(LazFindReplaceDialog.FindText),'" ssoEntireScope=',dbgs(ssoEntireScope in LazFindReplaceDialog.Options),' ssoBackwards=',dbgs(ssoBackwards in LazFindReplaceDialog.Options));
try try
Result:=EditorComponent.SearchReplace( Result:=EditorComponent.SearchReplace(aFindText, aReplaceText, anOptions);
LazFindReplaceDialog.FindText,LazFindReplaceDialog.ReplaceText,
LazFindReplaceDialog.Options);
except except
on E: ERegExpr do begin on E: ERegExpr do begin
MessageDlg(lisUEErrorInRegularExpression, MessageDlg(lisUEErrorInRegularExpression,
@ -2621,20 +2605,15 @@ begin
if (OldCaretXY.X = EditorComponent.CaretX) and if (OldCaretXY.X = EditorComponent.CaretX) and
(OldCaretXY.Y = EditorComponent.CaretY) and (OldCaretXY.Y = EditorComponent.CaretY) and
not (ssoReplaceAll in LazFindReplaceDialog.Options) then not (ssoReplaceAll in anOptions)
begin then begin
ACaption := lisUENotFound; ACaption := lisUENotFound;
AText := Format(lisUESearchStringNotFound, [ValidUTF8String(LazFindReplaceDialog.FindText)]); AText := Format(lisUESearchStringNotFound, [ValidUTF8String(aFindText)]);
MessageDlg(ACaption, AText, mtInformation, [mbOk], 0); MessageDlg(ACaption, AText, mtInformation, [mbOk], 0);
Manager.DeleteLastJumpPointClicked(Self); Manager.DeleteLastJumpPointClicked(Self);
end else end
if (EditorComponent.CaretY <= EditorComponent.TopLine + 1) or else begin
(EditorComponent.CaretY >= EditorComponent.TopLine + EditorComponent.LinesInWindow - 1) then CenterCursor(True);
begin
NewTopLine := EditorComponent.CaretY - (EditorComponent.LinesInWindow div 2);
if NewTopLine < 1 then
NewTopLine := 1;
EditorComponent.TopLine := NewTopLine;
end; end;
end; end;
@ -4566,17 +4545,15 @@ const
ssoRegExprMultiLine ssoRegExprMultiLine
); );
var var
OldOptions, NewOptions: TSynSearchOptions; NewOptions: TSynSearchOptions;
o: TSrcEditSearchOption; o: TSrcEditSearchOption;
begin begin
OldOptions:=LazFindReplaceDialog.Options;
NewOptions:=[]; NewOptions:=[];
for o:=Low(TSrcEditSearchOption) to High(TSrcEditSearchOption) do for o:=Low(TSrcEditSearchOption) to High(TSrcEditSearchOption) do
if o in SearchOptions then if o in SearchOptions then
Include(NewOptions,SrcEdit2SynEditSearchOption[o]); Include(NewOptions,SrcEdit2SynEditSearchOption[o]);
LazFindReplaceDialog.Options:=NewOptions; Result:=DoFindAndReplace(LazFindReplaceDialog.FindText, LazFindReplaceDialog.ReplaceText,
Result:=DoFindAndReplace; NewOptions);
LazFindReplaceDialog.Options:=OldOptions;
end; end;
function TSourceEditor.GetSourceText: string; function TSourceEditor.GetSourceText: string;