mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-14 07:02:50 +02:00
now using SynRegExpr for Find-Replace in IDE
git-svn-id: trunk@3775 -
This commit is contained in:
parent
8a39b9a4b9
commit
aa746f870e
@ -43,12 +43,22 @@ interface
|
||||
|
||||
uses
|
||||
Classes
|
||||
{$IFDEF SYN_LAZARUS}, RegExpr{$ENDIF};
|
||||
{$IFDEF SYN_LAZARUS}, SynRegExpr{$ENDIF};
|
||||
|
||||
procedure MakeCompTable(Sensitive: boolean);
|
||||
procedure MakeDelimiterTable;
|
||||
|
||||
type
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
TSynEditSearchResult = class
|
||||
public
|
||||
Start: integer;
|
||||
Len: integer;
|
||||
Replace: string;
|
||||
constructor Create(NewStart, NewLen: integer; const NewReplace: string);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
TSynEditSearch = class(TObject)
|
||||
private
|
||||
Run: PChar;
|
||||
@ -66,11 +76,11 @@ type
|
||||
fShiftInitialized: boolean;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
FoundLen: integer;
|
||||
RegExprEngine : TRegExprEngine;
|
||||
RegExprEngine : TRegExpr;
|
||||
fRegExpr: Boolean;
|
||||
fRegExprFlags: TRegExprFlags;
|
||||
fResultLens: TList;
|
||||
fRegExprSingleLine: boolean;
|
||||
fRegExprReplace: string;
|
||||
fReplacement: string;
|
||||
function GetResultLen(Index: integer): integer;
|
||||
procedure SetRegExpr(const NewValue: boolean);
|
||||
{$ENDIF}
|
||||
@ -97,10 +107,16 @@ type
|
||||
property Sensitive: Boolean read fSensitive write SetSensitive;
|
||||
property Whole: Boolean read fWhole write fWhole;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
public
|
||||
procedure ClearResults;
|
||||
function GetReplace(Index: integer): string;
|
||||
property RegularExpressions: Boolean read fRegExpr write SetRegExpr;
|
||||
property ResultLengths[Index: integer]: integer read GetResultLen;
|
||||
property RegExprSingleLine: Boolean
|
||||
read fRegExprSingleLine write fRegExprSingleLine;
|
||||
property RegExprReplace: string
|
||||
read fRegExprReplace write fRegExprReplace;
|
||||
property Replacement: string read fReplacement write fReplacement;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
@ -108,8 +124,7 @@ implementation
|
||||
|
||||
uses
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
LCLLinux,
|
||||
LCLType,
|
||||
LCLLinux, LCLType,
|
||||
{$ELSE}
|
||||
Windows,
|
||||
{$ENDIF}
|
||||
@ -146,20 +161,20 @@ begin
|
||||
for c := #0 to #255 do DelimTable[c] := not IsCharAlphaNumeric(c);
|
||||
end;
|
||||
|
||||
{ TSynEditSearch }
|
||||
|
||||
constructor TSynEditSearch.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
fResults := TList.Create;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
fRegExpr:=false;
|
||||
fResultLens := TList.Create;
|
||||
fRegExprSingleLine:=true;
|
||||
RegExprEngine:=TRegExpr.Create;
|
||||
FoundLen:=0;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
{ TSynEditSearch }
|
||||
|
||||
function TSynEditSearch.GetFinished: Boolean;
|
||||
begin
|
||||
Result := (Run >= TheEnd) or (PatLen >= fTextLen);
|
||||
@ -169,7 +184,11 @@ function TSynEditSearch.GetResult(Index: integer): integer;
|
||||
begin
|
||||
Result := 0;
|
||||
if (Index >= 0) and (Index < fResults.Count) then
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
Result := TSynEditSearchResult(fResults[Index]).Start;
|
||||
{$ELSE}
|
||||
Result := integer(fResults[Index]);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
function TSynEditSearch.GetResultCount: integer;
|
||||
@ -184,8 +203,12 @@ begin
|
||||
if (Delta <> 0) and (fResults.Count > 0) then begin
|
||||
i := Pred(fResults.Count);
|
||||
while i >= 0 do begin
|
||||
if integer(fResults[i]) <= First then break;
|
||||
if GetResult(i) <= First then break;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
dec(TSynEditSearchResult(fResults[i]).Start,Delta);
|
||||
{$ELSE}
|
||||
fResults[i] := pointer(integer(fResults[i]) - Delta);
|
||||
{$ENDIF}
|
||||
Dec(i);
|
||||
end;
|
||||
end;
|
||||
@ -264,12 +287,14 @@ begin
|
||||
end else begin
|
||||
// regular expressions
|
||||
inc(Run);
|
||||
if not RegExprPos(RegExprEngine,Run,Result,FoundLen) then begin
|
||||
Run:=TheEnd;
|
||||
Result:=0;
|
||||
if RegExprEngine.ExecPos(Run-Origin+1) then begin
|
||||
Result:=RegExprEngine.MatchPos[0];
|
||||
FoundLen:=RegExprEngine.MatchLen[0];
|
||||
Run:=Origin+Result-1;
|
||||
end else begin
|
||||
inc(Run,Result);
|
||||
Result:=Run-Origin+1;
|
||||
Result:=0;
|
||||
FoundLen:=0;
|
||||
Run:=TheEnd;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
@ -277,11 +302,11 @@ end;
|
||||
|
||||
destructor TSynEditSearch.Destroy;
|
||||
begin
|
||||
fResults.Free;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
DestroyRegExprEngine(RegExprEngine);
|
||||
fResultLens.Free;
|
||||
ClearResults;
|
||||
RegExprEngine.Free;
|
||||
{$ENDIF}
|
||||
fResults.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
@ -290,6 +315,9 @@ begin
|
||||
if Pat <> Value then begin
|
||||
Pat := Value;
|
||||
fShiftInitialized := FALSE;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
PatLen:=length(Pat);
|
||||
{$ENDIF}
|
||||
end;
|
||||
fCount := 0;
|
||||
end;
|
||||
@ -301,10 +329,7 @@ begin
|
||||
MakeCompTable(Value);
|
||||
fShiftInitialized := FALSE;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
if fSensitive then
|
||||
Exclude(fRegExprFlags,REF_CaseInsensitive)
|
||||
else
|
||||
Include(fRegExprFlags,REF_CaseInsensitive);
|
||||
RegExprEngine.ModifierI:=not fSensitive;
|
||||
{$ENDIF}
|
||||
end;
|
||||
end;
|
||||
@ -312,20 +337,28 @@ end;
|
||||
function TSynEditSearch.FindAll(const NewText: string): integer;
|
||||
var
|
||||
Found: integer;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
TheReplace: string;
|
||||
{$ENDIF}
|
||||
begin
|
||||
if not fShiftInitialized then
|
||||
InitShiftTable;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
ClearResults;
|
||||
{$ELSE}
|
||||
// never shrink Capacity
|
||||
fResults.Count := 0;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
if fRegExpr then fResultLens.Count := 0;
|
||||
{$ENDIF}
|
||||
Found := FindFirst(NewText);
|
||||
while Found > 0 do
|
||||
begin
|
||||
fResults.Add(pointer(Found));
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
if fRegExpr then fResultLens.Add(pointer(FoundLen));
|
||||
TheReplace:=Replacement;
|
||||
if fRegExpr then
|
||||
TheReplace:=RegExprEngine.Substitute(Replacement);
|
||||
fResults.Add(TSynEditSearchResult.Create(Found,FoundLen,TheReplace));
|
||||
{$ELSE}
|
||||
fResults.Add(pointer(Found));
|
||||
{$ENDIF}
|
||||
Found := Next;
|
||||
end;
|
||||
@ -336,25 +369,16 @@ function TSynEditSearch.FindFirst(const NewText: string): Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
fTextLen := Length(NewText);
|
||||
if fTextLen=0 then exit;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
if fRegExpr then begin
|
||||
DestroyRegExprEngine(RegExprEngine);
|
||||
if fSensitive then
|
||||
Exclude(fRegExprFlags,REF_CaseInsensitive)
|
||||
else
|
||||
Include(fRegExprFlags,REF_CaseInsensitive);
|
||||
if fRegExprSingleLine then begin
|
||||
Include(fRegExprFlags,REF_SingleLine);
|
||||
Exclude(fRegExprFlags,REF_MultiLine);
|
||||
end else begin
|
||||
Exclude(fRegExprFlags,REF_SingleLine);
|
||||
Include(fRegExprFlags,REF_MultiLine);
|
||||
end;
|
||||
RegExprEngine:=GenerateRegExprEngine(PChar(Pat+#0),fRegExprFlags);
|
||||
PatLen:=length(Pat);
|
||||
RegExprEngine.ModifierI:=not fSensitive;
|
||||
RegExprEngine.ModifierM:=not fRegExprSingleLine;
|
||||
RegExprEngine.Expression:=Pat;
|
||||
RegExprEngine.InputString:=NewText;
|
||||
end;
|
||||
{$ENDIF}
|
||||
if fTextLen >= PatLen then
|
||||
if (fTextLen >= PatLen) or fRegExpr then
|
||||
begin
|
||||
Origin := PChar(NewText);
|
||||
TheEnd := Origin + fTextLen;
|
||||
@ -364,10 +388,27 @@ begin
|
||||
end;
|
||||
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
procedure TSynEditSearch.ClearResults;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i:=0 to fResults.Count-1 do
|
||||
TSynEditSearchResult(fResults[i]).Free;
|
||||
fResults.Clear;
|
||||
end;
|
||||
|
||||
function TSynEditSearch.GetReplace(Index: integer): string;
|
||||
begin
|
||||
if (Index >= 0) and (Index < fResults.Count) then
|
||||
Result := TSynEditSearchResult(fResults[Index]).Replace
|
||||
else
|
||||
Result := Replacement;
|
||||
end;
|
||||
|
||||
function TSynEditSearch.GetResultLen(Index: integer): integer;
|
||||
begin
|
||||
if (Index>=0) and (Index<fResultLens.Count) then
|
||||
Result:=Integer(fResultLens[Index])
|
||||
if (Index>=0) and (Index<fResults.Count) then
|
||||
Result := TSynEditSearchResult(fResults[Index]).Len
|
||||
else
|
||||
Result:=FoundLen;
|
||||
end;
|
||||
@ -377,9 +418,20 @@ begin
|
||||
if NewValue=fRegExpr then exit;
|
||||
fRegExpr:=NewValue;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
{ TSynEditSearchResult }
|
||||
|
||||
constructor TSynEditSearchResult.Create(NewStart, NewLen: integer;
|
||||
const NewReplace: string);
|
||||
begin
|
||||
Start:=NewStart;
|
||||
Len:=NewLen;
|
||||
Replace:=NewReplace;
|
||||
end;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
initialization
|
||||
CompTableSensitive := True; // force the table initialization
|
||||
MakeCompTable(False);
|
||||
|
@ -41,7 +41,8 @@ interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, LCLType, Controls, StdCtrls, Forms, Buttons, ExtCtrls,
|
||||
LResources, SynEditTypes, SynEdit, IDEProcs, LazarusIdeStrConsts;
|
||||
LResources, Dialogs, SynEditTypes, SynRegExpr, SynEdit, IDEProcs,
|
||||
LazarusIdeStrConsts;
|
||||
|
||||
type
|
||||
TFindDlgComponent = (fdcText, fdcReplace);
|
||||
@ -57,6 +58,7 @@ type
|
||||
CaseSensitiveCheckBox:TCheckBox;
|
||||
WholeWordsOnlyCheckBox:TCheckBox;
|
||||
RegularExpressionsCheckBox:TCheckBox;
|
||||
MultiLineCheckBox:TCheckBox;
|
||||
PromptOnReplaceCheckBox:TCheckBox;
|
||||
DirectionRadioGroup:TRadioGroup;
|
||||
ScopeRadioGroup:TRadioGroup;
|
||||
@ -72,6 +74,8 @@ type
|
||||
private
|
||||
FOnKey: TOnFindDlgKey;
|
||||
fReplaceAllClickedLast:boolean;
|
||||
RegExpr: TRegExpr;
|
||||
function CheckInput: boolean;
|
||||
function GetComponentText(c: TFindDlgComponent): string;
|
||||
procedure SetComponentText(c: TFindDlgComponent; const AValue: string);
|
||||
procedure SetOnKey(const AValue: TOnFindDlgKey);
|
||||
@ -84,6 +88,7 @@ type
|
||||
procedure SetComboBoxText(AComboBox:TComboBox;const AText:AnsiString);
|
||||
public
|
||||
constructor Create(TheOwner:TComponent); override;
|
||||
destructor Destroy; override;
|
||||
public
|
||||
property Options:TSynSearchOptions read GetOptions write SetOptions;
|
||||
property FindText:AnsiString read GetFindText write SetFindText;
|
||||
@ -108,7 +113,7 @@ begin
|
||||
Name:='LazFindReplaceDialog';
|
||||
Caption:='';
|
||||
Width:=400;
|
||||
Height:=266;
|
||||
Height:=300;
|
||||
BorderStyle:= bsDialog;
|
||||
Position:=poDesigned;
|
||||
|
||||
@ -169,7 +174,7 @@ begin
|
||||
Left:=4;
|
||||
Top:=58;
|
||||
Width:=194;
|
||||
Height:=105;
|
||||
Height:=150;
|
||||
Caption:=dlgFROpts ;
|
||||
Visible:=true;
|
||||
end;
|
||||
@ -182,7 +187,6 @@ begin
|
||||
Left:=8;
|
||||
Top:=6;
|
||||
Width:=155;
|
||||
Height:=17;
|
||||
Caption:=dlgCaseSensitive ;
|
||||
Visible:=true;
|
||||
end;
|
||||
@ -193,9 +197,8 @@ begin
|
||||
Parent:=OptionsGroupBox;
|
||||
AutoSize := False;
|
||||
Left:=8;
|
||||
Top:=26;
|
||||
Top:=31;
|
||||
Width:=155;
|
||||
Height:=17;
|
||||
Caption:=dlgWholeWordsOnly;
|
||||
Visible:=true;
|
||||
end;
|
||||
@ -206,22 +209,33 @@ begin
|
||||
Parent:=OptionsGroupBox;
|
||||
AutoSize := False;
|
||||
Left:=8;
|
||||
Top:=46;
|
||||
Top:=56;
|
||||
Width:=155;
|
||||
Height:=17;
|
||||
Caption:=dlgRegularExpressions ;
|
||||
Caption:=dlgRegularExpressions;
|
||||
Visible:=true;
|
||||
end;
|
||||
|
||||
MultiLineCheckBox:=TCheckBox.Create(Self);
|
||||
with MultiLineCheckBox do begin
|
||||
Name:='MultiLineCheckBox';
|
||||
Parent:=OptionsGroupBox;
|
||||
AutoSize := False;
|
||||
Left:=8;
|
||||
Top:=81;
|
||||
Width:=155;
|
||||
Caption:=dlgMultiLine;
|
||||
Visible:=true;
|
||||
Enabled:=false;
|
||||
end;
|
||||
|
||||
PromptOnReplaceCheckBox:=TCheckBox.Create(Self);
|
||||
with PromptOnReplaceCheckBox do begin
|
||||
Name:='PromptOnReplaceCheckBox';
|
||||
Parent:=OptionsGroupBox;
|
||||
AutoSize := False;
|
||||
Left:=8;
|
||||
Top:=66;
|
||||
Top:=106;
|
||||
Width:=135;
|
||||
Height:=17;
|
||||
Caption:=dlgPromptOnReplace ;
|
||||
Checked:=true;
|
||||
Visible:=true;
|
||||
@ -234,7 +248,7 @@ begin
|
||||
Left:= 202;
|
||||
Top:= 58;
|
||||
Width:= 194;
|
||||
Height:=105;
|
||||
Height:=65;
|
||||
Caption:=dlgSROrigin;
|
||||
with Items do begin
|
||||
BeginUpdate;
|
||||
@ -251,8 +265,8 @@ begin
|
||||
with ScopeRadioGroup do begin
|
||||
Name:='ScopeRadioGroup';
|
||||
Parent:=Self;
|
||||
Left:=4;
|
||||
Top:=168;
|
||||
Left:=202;
|
||||
Top:=128;
|
||||
Width:=194;
|
||||
Height:=65;
|
||||
Caption:=dlgScope;
|
||||
@ -272,7 +286,7 @@ begin
|
||||
Name:='DirectionRadioGroup';
|
||||
Parent:=Self;
|
||||
Left:=202;
|
||||
Top:=168;
|
||||
Top:=198;
|
||||
Width:=194;
|
||||
Height:=65;
|
||||
Caption:=dlgDirection;
|
||||
@ -291,8 +305,8 @@ begin
|
||||
with OkButton do begin
|
||||
Name:='OkButton';
|
||||
Parent:= Self;
|
||||
Left:= 143;
|
||||
Top:= 237;
|
||||
Left:= 130;
|
||||
Top:= 268;
|
||||
Caption:='Ok';
|
||||
OnClick:=@OkButtonClick;
|
||||
Visible:=true;
|
||||
@ -302,8 +316,8 @@ begin
|
||||
with ReplaceAllButton do begin
|
||||
Name:='ReplaceAllButton';
|
||||
Parent:= Self;
|
||||
Left:= 222;
|
||||
Top:= 237;
|
||||
Left:= 210;
|
||||
Top:= 268;
|
||||
Width:=99;
|
||||
Caption:=dlgReplaceAll;
|
||||
OnClick:=@ReplaceAllButtonClick;
|
||||
@ -314,8 +328,8 @@ begin
|
||||
with CancelButton do begin
|
||||
Name:='CancelButton';
|
||||
Parent:= Self;
|
||||
Left:= 321;
|
||||
Top:= 237;
|
||||
Left:= 320;
|
||||
Top:= 268;
|
||||
Caption:=dlgCancel;
|
||||
OnClick:=@CancelButtonClick;
|
||||
Visible:=true;
|
||||
@ -326,6 +340,12 @@ begin
|
||||
TextToFindComboBox.SetFocus;
|
||||
end;
|
||||
|
||||
destructor TLazFindReplaceDialog.Destroy;
|
||||
begin
|
||||
RegExpr.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TLazFindReplaceDialog.TextToFindComboBoxKeyDown(
|
||||
Sender: TObject; var Key:Word; Shift:TShiftState);
|
||||
var Component: TFindDlgComponent;
|
||||
@ -354,6 +374,7 @@ end;
|
||||
|
||||
procedure TLazFindReplaceDialog.OkButtonClick(Sender:TObject);
|
||||
begin
|
||||
if not CheckInput then exit;
|
||||
fReplaceAllClickedLast:=false;
|
||||
TextToFindComboBox.SetFocus;
|
||||
ModalResult:=mrOk;
|
||||
@ -361,6 +382,7 @@ end;
|
||||
|
||||
procedure TLazFindReplaceDialog.ReplaceAllButtonClick(Sender:TObject);
|
||||
begin
|
||||
if not CheckInput then exit;
|
||||
fReplaceAllClickedLast:=true;
|
||||
TextToFindComboBox.SetFocus;
|
||||
ModalResult:=mrAll;
|
||||
@ -372,6 +394,36 @@ begin
|
||||
ModalResult:=mrCancel;
|
||||
end;
|
||||
|
||||
function TLazFindReplaceDialog.CheckInput: boolean;
|
||||
begin
|
||||
Result:=false;
|
||||
if RegularExpressionsCheckBox.Checked then begin
|
||||
if RegExpr=nil then RegExpr:=TRegExpr.Create;
|
||||
try
|
||||
RegExpr.Expression:=FindText;
|
||||
RegExpr.Exec('test');
|
||||
except
|
||||
on E: ERegExpr do begin
|
||||
MessageDlg('Error in regular expression',
|
||||
E.Message,mtError,[mbCancel],0);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
if ReplaceTextComboBox.Enabled then begin
|
||||
try
|
||||
RegExpr.Substitute(ReplaceText);
|
||||
except
|
||||
on E: ERegExpr do begin
|
||||
MessageDlg('Error in regular expression',
|
||||
E.Message,mtError,[mbCancel],0);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
Result:=true;
|
||||
end;
|
||||
|
||||
function TLazFindReplaceDialog.GetComponentText(c: TFindDlgComponent): string;
|
||||
begin
|
||||
case c of
|
||||
@ -401,6 +453,7 @@ begin
|
||||
CaseSensitiveCheckBox.Checked:=ssoMatchCase in NewOptions;
|
||||
WholeWordsOnlyCheckBox.Checked:=ssoWholeWord in NewOptions;
|
||||
RegularExpressionsCheckBox.Checked:=ssoRegExpr in NewOptions;
|
||||
MultiLineCheckBox.Checked:=ssoRegExprMultiLine in NewOptions;
|
||||
PromptOnReplaceCheckBox.Checked:=ssoPrompt in NewOptions;
|
||||
if ssoEntireScope in NewOptions
|
||||
then OriginRadioGroup.ItemIndex:=1
|
||||
@ -430,6 +483,7 @@ begin
|
||||
if CaseSensitiveCheckBox.Checked then Include(Result,ssoMatchCase);
|
||||
if WholeWordsOnlyCheckBox.Checked then Include(Result,ssoWholeWord);
|
||||
if RegularExpressionsCheckBox.Checked then Include(Result,ssoRegExpr);
|
||||
if MultiLineCheckBox.Checked then Include(Result,ssoRegExprMultiLine);
|
||||
if PromptOnReplaceCheckBox.Checked then Include(Result,ssoPrompt);
|
||||
if OriginRadioGroup.ItemIndex=1 then Include(Result,ssoEntireScope);
|
||||
if ScopeRadioGroup.ItemIndex=1 then include(Result,ssoSelectedOnly);
|
||||
|
@ -630,6 +630,7 @@ resourcestring
|
||||
dlgCaseSensitive = 'Case Sensitive';
|
||||
dlgWholeWordsOnly = 'Whole Words Only';
|
||||
dlgRegularExpressions = 'Regular Expressions';
|
||||
dlgMultiLine = 'Multi Line';
|
||||
dlgPromptOnReplace = 'Prompt On Replace';
|
||||
dlgSROrigin = 'Origin';
|
||||
dlgFromCursor = 'From Cursor';
|
||||
|
Loading…
Reference in New Issue
Block a user