now using SynRegExpr for Find-Replace in IDE

git-svn-id: trunk@3775 -
This commit is contained in:
mattias 2003-01-01 17:45:43 +00:00
parent 8a39b9a4b9
commit aa746f870e
3 changed files with 172 additions and 65 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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';