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;
function SearchReplace(const ASearch, AReplace: string;
AOptions: TSynSearchOptions): integer;
{$IFDEF SYN_LAZARUS}
function SearchReplaceEx(const ASearch, AReplace: string;
AOptions: TSynSearchOptions; AStart: TPoint): integer;
{$ENDIF}
procedure SelectAll;
Procedure SetHighlightSearch(const ASearch: String; AOptions: TSynSearchOptions);
procedure SelectToBrace;
@ -6991,14 +6989,22 @@ end;
// find / replace
function TCustomSynEdit.SearchReplace(const ASearch, AReplace: string;
AOptions: TSynSearchOptions): integer;
{$IFDEF SYN_LAZARUS}
var
StartPos: TPoint;
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;
function TCustomSynEdit.SearchReplaceEx(const ASearch, AReplace: string;
AOptions: TSynSearchOptions; AStart: TPoint): integer;
{$ENDIF}
var
ptStart, ptEnd: TPoint; // start and end of the search range
ptCurrent: TPoint; // current search position
@ -7007,12 +7013,8 @@ var
bPrompt: boolean;
bReplace, bReplaceAll: boolean;
nAction: TSynReplaceAction;
{$IFDEF SYN_LAZARUS}
CurReplace: string;
ptFoundStart, ptFoundEnd: TPoint;
{$ELSE}
n, nSearchLen, nReplaceLen, nInLine: integer;
{$ENDIF}
function InValidSearchRange(First, Last: integer): boolean;
begin
@ -7060,9 +7062,9 @@ begin
ptEnd.X := Length(FTheLinesView[ptEnd.Y - 1]) + 1;
if bFromCursor then
if bBackward then
ptEnd := {$IFDEF SYN_LAZARUS}AStart{$ELSE}CaretXY{$ENDIF}
ptEnd := AStart
else
ptStart := {$IFDEF SYN_LAZARUS}AStart{$ELSE}CaretXY{$ENDIF};
ptStart := AStart;
if bBackward then ptCurrent := ptEnd else ptCurrent := ptStart;
end;
// initialize the search engine
@ -7070,18 +7072,12 @@ begin
fTSearch.Whole := ssoWholeWord in AOptions;
fTSearch.Pattern := ASearch;
fTSearch.RegularExpressions := ssoRegExpr in AOptions;
{$IFDEF SYN_LAZARUS}
fTSearch.RegExprMultiLine := ssoRegExprMultiLine in AOptions;
fTSearch.Replacement:=AReplace;
fTSearch.Backwards:=bBackward;
{$ELSE}
nSearchLen := Length(ASearch);
nReplaceLen := Length(AReplace);
{$ENDIF}
// search while the current search position is inside of the search range
IncPaintLock;
try
{$IFDEF SYN_LAZARUS}
//DebugLn(['TCustomSynEdit.SearchReplace ptStart=',dbgs(ptStart),' ptEnd=',dbgs(ptEnd),' ASearch="',dbgstr(ASearch),'" AReplace="',dbgstr(AReplace),'"']);
while fTSearch.FindNextOne(FTheLinesView,ptStart,ptEnd,ptFoundStart,ptFoundEnd) do
begin
@ -7156,60 +7152,6 @@ begin
end;
//DebugLn(['TCustomSynEdit.SearchReplace FIND NEXT ptStart=',dbgs(ptStart),' ptEnd=',dbgs(ptEnd)]);
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
DecPaintLock;
end;

View File

@ -69,11 +69,17 @@ type
TSynSelectionMode = (smNormal, smLine, smColumn, smCurrent);
{$IFDEF SYN_LAZARUS}{$PACKENUM 4}{$ENDIF SYN_LAZARUS}
TSynSearchOption = (ssoMatchCase, ssoWholeWord, ssoBackwards,
ssoEntireScope, ssoSelectedOnly, ssoReplace, ssoReplaceAll, ssoPrompt
{$IFDEF SYN_LAZARUS},
ssoSearchInReplacement,// continue search in replacement
ssoRegExpr, ssoRegExprMultiLine{$ENDIF});
TSynSearchOption =
( ssoMatchCase, ssoWholeWord,
ssoBackwards,
ssoEntireScope, ssoSelectedOnly,
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;
{$IFDEF SYN_LAZARUS}

View File

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

View File

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