소스 검색

Added Search feture vor editors

Simon Grossenbacher 8 년 전
부모
커밋
47fc6f2f65
11개의 변경된 파일642개의 추가작업 그리고 11개의 파일을 삭제
  1. BIN
      RESTDebugger.exe
  2. 7 2
      prj/RESTDebugger.dpr
  3. 5 0
      prj/RESTDebugger.dproj
  4. 6 6
      prj/RESTDebugger.stat
  5. 106 0
      src/_SearchTextHightlighterSynEditPlugin.pas
  6. 1 0
      src/_frmBiggerEditor.dfm
  7. 22 1
      src/_frmBiggerEditor.pas
  8. 32 0
      src/_frmMain.dfm
  9. 139 2
      src/_frmMain.pas
  10. 115 0
      src/_frmSearch.dfm
  11. 209 0
      src/_frmSearch.pas

BIN
RESTDebugger.exe


+ 7 - 2
prj/RESTDebugger.dpr

@@ -1,10 +1,14 @@
 program RESTDebugger;
 
 uses
-  {$IFDEF DEBUG}FastMM4,{$ENDIF}
+  {$IFDEF DEBUG}
+  FastMM4,
+  {$ENDIF }
   Vcl.Forms,
   _frmMain in '..\src\_frmMain.pas' {frmMain},
-  _frmBiggerEditor in '..\src\_frmBiggerEditor.pas' {frmBiggerEditor};
+  _frmBiggerEditor in '..\src\_frmBiggerEditor.pas' {frmBiggerEditor},
+  _frmSearch in '..\src\_frmSearch.pas' {frmSearch},
+  _SearchTextHightlighterSynEditPlugin in '..\src\_SearchTextHightlighterSynEditPlugin.pas';
 
 {$R *.res}
 
@@ -13,5 +17,6 @@ begin
   Application.MainFormOnTaskbar := True;
   Application.CreateForm(TfrmMain, frmMain);
   Application.CreateForm(TfrmBiggerEditor, frmBiggerEditor);
+  Application.CreateForm(TfrmSearch, frmSearch);
   Application.Run;
 end.

+ 5 - 0
prj/RESTDebugger.dproj

@@ -160,6 +160,11 @@
         <DCCReference Include="..\src\_frmBiggerEditor.pas">
             <Form>frmBiggerEditor</Form>
         </DCCReference>
+        <DCCReference Include="..\src\_frmSearch.pas">
+            <Form>frmSearch</Form>
+            <FormType>dfm</FormType>
+        </DCCReference>
+        <DCCReference Include="..\src\_SearchTextHightlighterSynEditPlugin.pas"/>
         <BuildConfiguration Include="Release">
             <Key>Cfg_2</Key>
             <CfgParent>Base</CfgParent>

+ 6 - 6
prj/RESTDebugger.stat

@@ -1,10 +1,10 @@
 [Stats]
-EditorSecs=17546
-DesignerSecs=5179
-InspectorSecs=2757
-CompileSecs=818061
-OtherSecs=4657
+EditorSecs=18948
+DesignerSecs=5395
+InspectorSecs=2773
+CompileSecs=893867
+OtherSecs=4796
 StartTime=27.10.2016 18:27:37
 RealKeys=0
 EffectiveKeys=0
-DebugSecs=13466
+DebugSecs=14059

+ 106 - 0
src/_SearchTextHightlighterSynEditPlugin.pas

@@ -0,0 +1,106 @@
+unit _SearchTextHightlighterSynEditPlugin;
+
+interface
+
+uses
+  Windows, Classes, Graphics, SynEdit, SynEditTypes, SynEditHighlighter,
+  SynEditPlugins;
+
+type
+  TSearchTextHightlighterSynEditPlugin = class(TSynEditPlugin)
+  private
+    FAttribute: TSynHighlighterAttributes;
+  protected
+    procedure AfterPaint(ACanvas: TCanvas; const AClip: TRect;
+      FirstLine, LastLine: Integer); override;
+  public
+    procedure AfterConstruction; override;
+    destructor Destroy; override;
+
+    property Attribute: TSynHighlighterAttributes read FAttribute write FAttribute;
+  end;
+
+implementation
+
+{ TEditorFrameSynEditPlugin }
+
+procedure TSearchTextHightlighterSynEditPlugin.AfterConstruction;
+begin
+  inherited;
+  FAttribute := TSynHighlighterAttributes.Create('SearchText', 'Search Text Highlighter');
+end;
+
+destructor TSearchTextHightlighterSynEditPlugin.Destroy;
+begin
+  FAttribute.Free;
+  inherited;
+end;
+
+procedure TSearchTextHightlighterSynEditPlugin.AfterPaint(ACanvas: TCanvas;
+  const AClip: TRect; FirstLine, LastLine: Integer);
+var
+  SearchText, SearchResultText: string;
+  Pt: TPoint;
+  Rct: TRect;
+  OldFont: TFont;
+  LineIndex, Count, ItemIndex: Integer;
+  CurrCoord: TBufferCoord;
+begin
+  inherited;
+
+  if not Assigned(Editor.SearchEngine) then
+    Exit;
+
+  SearchText := Editor.SearchEngine.Pattern;
+  if SearchText = '' then
+    Exit;
+
+  OldFont := TFont.Create;
+  try
+    OldFont.Assign(ACanvas.Font);
+
+    if Attribute.Background <> clNone then
+    begin
+      ACanvas.Brush.Color := Attribute.Background;
+      ACanvas.Brush.Style := bsSolid
+    end
+    else
+      ACanvas.Brush.Style := bsClear;
+
+    if Attribute.Foreground <> clNone then
+    begin
+      ACanvas.Pen.Color := Attribute.Foreground;
+      ACanvas.Pen.Style := psSolid;
+    end
+    else
+      ACanvas.Pen.Style := psClear;
+
+    for LineIndex := FirstLine to LastLine do
+    begin
+      Count := Editor.SearchEngine.FindAll(Editor.Lines[LineIndex - 1]);
+      for ItemIndex := 0 to Count - 1 do
+      begin
+        CurrCoord := BufferCoord(Editor.SearchEngine.Results[ItemIndex], LineIndex);
+        if CurrCoord = Editor.BlockBegin then
+          Continue;
+
+        SearchResultText := Copy(Editor.Lines[LineIndex - 1], Editor.SearchEngine.Results[ItemIndex],
+          Editor.SearchEngine.Lengths[ItemIndex]);
+
+        Pt := Editor.RowColumnToPixels(Editor.BufferToDisplayPos(CurrCoord));
+        Rct := Rect(Pt.X, Pt.Y, Pt.X + Editor.CharWidth * Length(SearchResultText),
+          Pt.Y + Editor.LineHeight);
+
+        ACanvas.FillRect(Rct);
+        ACanvas.TextRect(Rct, Pt.X, Pt.Y, SearchResultText);
+      end
+    end;
+
+    ACanvas.Font.Assign(OldFont);
+  finally
+    OldFont.Free;
+  end;
+end;
+
+end.
+

+ 1 - 0
src/_frmBiggerEditor.dfm

@@ -17,6 +17,7 @@ object frmBiggerEditor: TfrmBiggerEditor
   OldCreateOrder = False
   Position = poDefault
   OnClose = FormClose
+  OnCreate = FormCreate
   OnKeyPress = FormKeyPress
   OnShow = FormShow
   PixelsPerInch = 96

+ 22 - 1
src/_frmBiggerEditor.pas

@@ -4,7 +4,7 @@ interface
 
 uses
   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
-  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, SynEdit;
+  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, SynEdit, _SearchTextHightlighterSynEditPlugin;
 
 type
   TfrmBiggerEditor = class(TForm)
@@ -16,6 +16,7 @@ type
     procedure EditorBiggerEditorKeyUp(Sender: TObject; var Key: Word;
       Shift: TShiftState);
     procedure FormKeyPress(Sender: TObject; var Key: Char);
+    procedure FormCreate(Sender: TObject);
   private
     FMainActiveEditor: TSynEdit;
   public
@@ -38,6 +39,18 @@ begin
   begin
     Close;
   end;
+
+  if Key = vkF3 then
+  begin
+    frmMain.ActiveEditor := EditorBiggerEditor;
+    frmMain.DoSearchReplaceText(false, false);
+  end;
+
+  if (Key = 70) and (Shift = [ssCtrl]) then
+  begin
+    frmMain.ActiveEditor := EditorBiggerEditor;
+    frmMain.ShowSearchReplaceDialog(false);
+  end;
 end;
 
 procedure TfrmBiggerEditor.EditorBiggerEditorMouseUp(Sender: TObject;
@@ -66,6 +79,14 @@ begin
   EditorBiggerEditor.Lines.Clear;
 end;
 
+procedure TfrmBiggerEditor.FormCreate(Sender: TObject);
+begin
+  with TSearchTextHightlighterSynEditPlugin.Create(EditorBiggerEditor) do
+  begin
+    Attribute.Background := $0078AAFF;
+  end;
+end;
+
 procedure TfrmBiggerEditor.FormKeyPress(Sender: TObject; var Key: Char);
 begin
   if Key = #27 then

+ 32 - 0
src/_frmMain.dfm

@@ -134,6 +134,10 @@ object frmMain: TfrmMain
     object tabContent: TcxTabSheet
       Caption = 'Response Content'
       ImageIndex = 0
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object EditorContent: TSynEdit
         Left = 0
         Top = 0
@@ -166,6 +170,10 @@ object frmMain: TfrmMain
     object tabHeaders: TcxTabSheet
       Caption = 'Response Headers'
       ImageIndex = 1
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object EditorResponseHeaders: TSynEdit
         Left = 0
         Top = 0
@@ -346,6 +354,10 @@ object frmMain: TfrmMain
       object tabURLParams: TcxTabSheet
         Caption = 'URL Parameters'
         ImageIndex = 0
+        ExplicitLeft = 0
+        ExplicitTop = 0
+        ExplicitWidth = 0
+        ExplicitHeight = 0
         object Panel3: TPanel
           Left = 0
           Top = 0
@@ -396,6 +408,10 @@ object frmMain: TfrmMain
       object cxTabSheet2: TcxTabSheet
         Caption = 'Extra Headers'
         ImageIndex = 1
+        ExplicitLeft = 0
+        ExplicitTop = 0
+        ExplicitWidth = 0
+        ExplicitHeight = 0
         object Panel4: TPanel
           Left = 0
           Top = 0
@@ -445,6 +461,10 @@ object frmMain: TfrmMain
       object cxTabSheet3: TcxTabSheet
         Caption = 'Authentication'
         ImageIndex = 3
+        ExplicitLeft = 0
+        ExplicitTop = 0
+        ExplicitWidth = 0
+        ExplicitHeight = 0
         object Label9: TLabel
           Left = 15
           Top = 47
@@ -482,6 +502,10 @@ object frmMain: TfrmMain
       object tabPostData: TcxTabSheet
         Caption = 'Post Data'
         ImageIndex = 2
+        ExplicitLeft = 0
+        ExplicitTop = 0
+        ExplicitWidth = 0
+        ExplicitHeight = 0
         object Panel5: TPanel
           Left = 0
           Top = 0
@@ -1732,4 +1756,12 @@ object frmMain: TfrmMain
     Left = 640
     Top = 331
   end
+  object SynEditSearch: TSynEditSearch
+    Left = 565
+    Top = 523
+  end
+  object SynEditRegexSearch: TSynEditRegexSearch
+    Left = 565
+    Top = 588
+  end
 end

+ 139 - 2
src/_frmMain.pas

@@ -14,7 +14,8 @@ uses
   cxButtons, dxSkinscxPCPainter,
   dxBarBuiltInMenu, cxPC, System.ImageList, Vcl.ImgList, cxCheckBox, cxImageList,
   SynEdit, SynHighlighterJSON, SynEditHighlighter, SynHighlighterIni,
-  SynHighlighterXML, SynHighlighterHtml;
+  SynHighlighterXML, SynHighlighterHtml, SynEditRegexSearch, SynEditMiscClasses,
+  SynEditSearch, _SearchTextHightlighterSynEditPlugin, SynEditTypes;
 
 type
   TMethodType = (mtGET, mtPOST, mtPATCH, mtPUT, mtDELETE);
@@ -105,6 +106,8 @@ type
     pmnuBiggerEditor: TdxBarButton;
     btnPasteFullURL: TcxButton;
     SynHTMLSyn: TSynHTMLSyn;
+    SynEditSearch: TSynEditSearch;
+    SynEditRegexSearch: TSynEditRegexSearch;
     procedure FormShow(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
@@ -175,6 +178,7 @@ type
     FIsTempProjectLoaded: Boolean;
     FTempProjectFile: string;
     FRoamingSavePath: string;
+    FSearchFromCaret: Boolean;
     function GetTempProjectFile: string;
     function GetAppVersion: string;
     procedure UpdateFullURL;
@@ -193,8 +197,24 @@ type
   public
     MainConfig: TJSONConfig;
     ActiveEditor: TSynEdit;
+    procedure DoSearchReplaceText(AReplace: Boolean; ABackwards: Boolean);
+    procedure ShowSearchReplaceDialog(AReplace: Boolean);
   end;
 
+var
+  gbSearchBackwards: Boolean;
+  gbSearchCaseSensitive: Boolean;
+  gbSearchFromCaret: Boolean;
+  gbSearchSelectionOnly: Boolean;
+  gbSearchTextAtCaret: Boolean;
+  gbSearchWholeWords: Boolean;
+  gbSearchRegex: Boolean;
+
+  gsSearchText: string;
+  gsSearchTextHistory: string;
+  gsReplaceText: string;
+  gsReplaceTextHistory: string;
+
 var
   frmMain: TfrmMain;
 
@@ -203,7 +223,7 @@ implementation
 {$R *.dfm}
 
 uses System.NetEncoding, System.UITypes, _EncryptStr, JsonDataObjects, IdGlobal, System.IOUtils, uRwXmlDOM,
-  _frmBiggerEditor, IdUri;
+  _frmBiggerEditor, IdUri, _frmSearch;
 
 procedure TfrmMain.tbbtnRunClick(Sender: TObject);
 begin
@@ -577,6 +597,35 @@ begin
   UpdateEditor(HTTP.Response.RawHeaders.Text);
 end;
 
+procedure TfrmMain.DoSearchReplaceText(AReplace, ABackwards: Boolean);
+var
+  Options: TSynSearchOptions;
+begin
+  if AReplace then
+    Options := [ssoPrompt, ssoReplace, ssoReplaceAll]
+  else
+    Options := [];
+  if ABackwards then
+    Include(Options, ssoBackwards);
+  if gbSearchCaseSensitive then
+    Include(Options, ssoMatchCase);
+  if not FSearchFromCaret then
+    Include(Options, ssoEntireScope);
+  if gbSearchSelectionOnly then
+    Include(Options, ssoSelectedOnly);
+  if gbSearchWholeWords then
+    Include(Options, ssoWholeWord);
+  if gbSearchRegex then
+    ActiveEditor.SearchEngine := SynEditRegexSearch
+  else
+    ActiveEditor.SearchEngine := SynEditSearch;
+
+  if ActiveEditor.SearchReplace(gsSearchText, gsReplaceText, Options) = 0 then
+  begin
+    MessageDlg('Text not found.', mtInformation, [mbOK], 0);
+  end;
+end;
+
 procedure TfrmMain.dxBarButton6Click(Sender: TObject);
 begin
   Close;
@@ -610,6 +659,18 @@ begin
     ActiveEditor := EditorContent;
     pmnuBiggerEditorClick(Sender);
   end;
+
+  if Key = vkF3 then
+  begin
+    ActiveEditor := EditorContent;
+    DoSearchReplaceText(false, false);
+  end;
+
+  if (Key = 70) and (Shift = [ssCtrl]) then
+  begin
+    ActiveEditor := EditorContent;
+    ShowSearchReplaceDialog(false);
+  end;
 end;
 
 procedure TfrmMain.EditorContentMouseUp(Sender: TObject; Button: TMouseButton;
@@ -739,6 +800,20 @@ begin
   MainConfig.WriteInteger('MainWindowPos', 'Height', Height);
   MainConfig.WriteBool('MainWindowPos', 'StayOnTop', FormStyle = fsStayOnTop);
 
+  MainConfig.WriteBool('Search', 'gbSearchBackwards', gbSearchBackwards);
+  MainConfig.WriteBool('Search', 'gbSearchCaseSensitive', gbSearchCaseSensitive);
+  MainConfig.WriteBool('Search', 'gbSearchFromCaret', gbSearchFromCaret);
+  MainConfig.WriteBool('Search', 'gbSearchSelectionOnly', gbSearchSelectionOnly);
+  MainConfig.WriteBool('Search', 'gbSearchTextAtCaret', gbSearchTextAtCaret);
+  MainConfig.WriteBool('Search', 'gbSearchWholeWords', gbSearchWholeWords);
+  MainConfig.WriteBool('Search', 'gbSearchRegex', gbSearchRegex);
+
+  MainConfig.WriteString('Search', 'gsSearchText', gsSearchText);
+  MainConfig.WriteString('Search', 'gsSearchTextHistory', gsSearchTextHistory);
+  MainConfig.WriteString('Search', 'gsReplaceText', gsReplaceText);
+  MainConfig.WriteString('Search', 'gsReplaceTextHistory', gsReplaceTextHistory);
+
+
   SavePreset;
 
   if FProjectConfig.FileModified then
@@ -811,6 +886,12 @@ begin
     end;
   end;
 
+
+  with TSearchTextHightlighterSynEditPlugin.Create(EditorContent) do
+  begin
+    Attribute.Background := $0078AAFF;
+  end;
+
   LoadProject;
 end;
 
@@ -865,6 +946,20 @@ begin
 
   dxStatusBar.Panels[1].Text := '';
   dxStatusBar.Panels[2].Text := '';
+
+
+  gbSearchBackwards := MainConfig.ReadBool('Search', 'gbSearchBackwards', gbSearchBackwards);
+  gbSearchCaseSensitive := MainConfig.ReadBool('Search', 'gbSearchCaseSensitive', gbSearchCaseSensitive);
+  gbSearchFromCaret :=MainConfig.ReadBool('Search', 'gbSearchFromCaret', gbSearchFromCaret);
+  gbSearchSelectionOnly := MainConfig.ReadBool('Search', 'gbSearchSelectionOnly', gbSearchSelectionOnly);
+  gbSearchTextAtCaret := MainConfig.ReadBool('Search', 'gbSearchTextAtCaret', gbSearchTextAtCaret);
+  gbSearchWholeWords := MainConfig.ReadBool('Search', 'gbSearchWholeWords', gbSearchWholeWords);
+  gbSearchRegex := MainConfig.ReadBool('Search', 'gbSearchRegex', gbSearchRegex);
+
+  gsSearchText := MainConfig.ReadString('Search', 'gsSearchText', gsSearchText);
+  gsSearchTextHistory := MainConfig.ReadString('Search', 'gsSearchTextHistory', gsSearchTextHistory);
+  gsReplaceText := MainConfig.ReadString('Search', 'gsReplaceText', gsReplaceText);
+  gsReplaceTextHistory := MainConfig.ReadString('Search', 'gsReplaceTextHistory', gsReplaceTextHistory);
 end;
 
 function TfrmMain.GetAppVersion: string;
@@ -1240,4 +1335,46 @@ begin
   MessageDlg(AErrorText, mtError, [mbOK], 0);
 end;
 
+procedure TfrmMain.ShowSearchReplaceDialog(AReplace: Boolean);
+begin
+  with frmSearch do
+  begin
+    // assign search options
+    SearchBackwards := gbSearchBackwards;
+    SearchCaseSensitive := gbSearchCaseSensitive;
+    SearchFromCursor := gbSearchFromCaret;
+    SearchInSelectionOnly := gbSearchSelectionOnly;
+    // start with last search text
+    SearchText := gsSearchText;
+    if gbSearchTextAtCaret then
+    begin
+      // if something is selected search for that text
+      if ActiveEditor.SelAvail and (ActiveEditor.BlockBegin.Line = ActiveEditor.BlockEnd.Line)
+      then
+        SearchText := ActiveEditor.SelText
+      else
+        SearchText := ActiveEditor.GetWordAtRowCol(ActiveEditor.CaretXY);
+    end;
+    SearchTextHistory := gsSearchTextHistory;
+    SearchWholeWords := gbSearchWholeWords;
+    if ShowModal = mrOK then
+    begin
+      gbSearchBackwards := SearchBackwards;
+      gbSearchCaseSensitive := SearchCaseSensitive;
+      gbSearchFromCaret := SearchFromCursor;
+      gbSearchSelectionOnly := SearchInSelectionOnly;
+      gbSearchWholeWords := SearchWholeWords;
+      gbSearchRegex := SearchRegularExpression;
+      gsSearchText := SearchText;
+      gsSearchTextHistory := SearchTextHistory;
+      FSearchFromCaret := gbSearchFromCaret;
+      if gsSearchText <> '' then
+      begin
+        DoSearchReplaceText(AReplace, gbSearchBackwards);
+        FSearchFromCaret := TRUE;
+      end;
+    end;
+  end;
+end;
+
 end.

+ 115 - 0
src/_frmSearch.dfm

@@ -0,0 +1,115 @@
+object frmSearch: TfrmSearch
+  Left = 132
+  Top = 168
+  BorderStyle = bsDialog
+  Caption = 'Search Text'
+  ClientHeight = 180
+  ClientWidth = 332
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poDefault
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Label1: TLabel
+    Left = 8
+    Top = 12
+    Width = 52
+    Height = 13
+    Caption = '&Search for:'
+  end
+  object cbSearchText: TComboBox
+    Left = 96
+    Top = 8
+    Width = 228
+    Height = 21
+    TabOrder = 0
+  end
+  object gbSearchOptions: TGroupBox
+    Left = 8
+    Top = 40
+    Width = 154
+    Height = 127
+    Caption = 'Options'
+    TabOrder = 1
+    object cbSearchCaseSensitive: TCheckBox
+      Left = 8
+      Top = 17
+      Width = 140
+      Height = 17
+      Caption = 'C&ase sensitivity'
+      TabOrder = 0
+    end
+    object cbSearchWholeWords: TCheckBox
+      Left = 8
+      Top = 39
+      Width = 140
+      Height = 17
+      Caption = '&Whole words only'
+      TabOrder = 1
+    end
+    object cbSearchFromCursor: TCheckBox
+      Left = 8
+      Top = 61
+      Width = 140
+      Height = 17
+      Caption = 'Search from &caret'
+      TabOrder = 2
+    end
+    object cbSearchSelectedOnly: TCheckBox
+      Left = 8
+      Top = 83
+      Width = 140
+      Height = 17
+      Caption = '&Selected text only'
+      TabOrder = 3
+    end
+    object cbRegularExpression: TCheckBox
+      Left = 8
+      Top = 104
+      Width = 140
+      Height = 17
+      Caption = '&Regular expression'
+      TabOrder = 4
+    end
+  end
+  object rgSearchDirection: TRadioGroup
+    Left = 170
+    Top = 40
+    Width = 154
+    Height = 65
+    Caption = 'Direction'
+    ItemIndex = 0
+    Items.Strings = (
+      '&Forward'
+      '&Backward')
+    TabOrder = 2
+  end
+  object btnOK: TButton
+    Left = 170
+    Top = 149
+    Width = 75
+    Height = 23
+    Caption = 'OK'
+    Default = True
+    ModalResult = 1
+    TabOrder = 3
+  end
+  object btnCancel: TButton
+    Left = 249
+    Top = 149
+    Width = 75
+    Height = 23
+    Cancel = True
+    Caption = 'Cancel'
+    ModalResult = 2
+    TabOrder = 4
+  end
+end

+ 209 - 0
src/_frmSearch.pas

@@ -0,0 +1,209 @@
+unit _frmSearch;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  StdCtrls, ExtCtrls;
+
+type
+  TfrmSearch = class(TForm)
+    Label1: TLabel;
+    cbSearchText: TComboBox;
+    rgSearchDirection: TRadioGroup;
+    gbSearchOptions: TGroupBox;
+    cbSearchCaseSensitive: TCheckBox;
+    cbSearchWholeWords: TCheckBox;
+    cbSearchFromCursor: TCheckBox;
+    cbSearchSelectedOnly: TCheckBox;
+    btnOK: TButton;
+    btnCancel: TButton;
+    cbRegularExpression: TCheckBox;
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormClose(Sender: TObject; var Action: TCloseAction);
+    procedure FormShow(Sender: TObject);
+  private
+    function GetSearchBackwards: boolean;
+    function GetSearchCaseSensitive: boolean;
+    function GetSearchFromCursor: boolean;
+    function GetSearchInSelection: boolean;
+    function GetSearchText: string;
+    function GetSearchTextHistory: string;
+    function GetSearchWholeWords: boolean;
+    procedure SetSearchBackwards(Value: boolean);
+    procedure SetSearchCaseSensitive(Value: boolean);
+    procedure SetSearchFromCursor(Value: boolean);
+    procedure SetSearchInSelection(Value: boolean);
+    procedure SetSearchText(Value: string);
+    procedure SetSearchTextHistory(Value: string);
+    procedure SetSearchWholeWords(Value: boolean);
+    procedure SetSearchRegularExpression(const Value: boolean);
+    function GetSearchRegularExpression: boolean;
+  public
+    property SearchBackwards: boolean read GetSearchBackwards
+      write SetSearchBackwards;
+    property SearchCaseSensitive: boolean read GetSearchCaseSensitive
+      write SetSearchCaseSensitive;
+    property SearchFromCursor: boolean read GetSearchFromCursor
+      write SetSearchFromCursor;
+    property SearchInSelectionOnly: boolean read GetSearchInSelection
+      write SetSearchInSelection;
+    property SearchText: string read GetSearchText write SetSearchText;
+    property SearchTextHistory: string read GetSearchTextHistory
+      write SetSearchTextHistory;
+    property SearchWholeWords: boolean read GetSearchWholeWords
+      write SetSearchWholeWords;
+    property SearchRegularExpression: boolean read GetSearchRegularExpression
+      write SetSearchRegularExpression;
+  end;
+
+var
+  frmSearch: TfrmSearch;
+
+implementation
+
+{$R *.DFM}
+
+uses _frmMain;
+
+
+function TfrmSearch.GetSearchBackwards: boolean;
+begin
+  Result := rgSearchDirection.ItemIndex = 1;
+end;
+
+function TfrmSearch.GetSearchCaseSensitive: boolean;
+begin
+  Result := cbSearchCaseSensitive.Checked;
+end;
+
+function TfrmSearch.GetSearchFromCursor: boolean;
+begin
+  Result := cbSearchFromCursor.Checked;
+end;
+
+function TfrmSearch.GetSearchInSelection: boolean;
+begin
+  Result := cbSearchSelectedOnly.Checked;
+end;
+
+function TfrmSearch.GetSearchRegularExpression: boolean;
+begin
+  Result := cbRegularExpression.Checked;
+end;
+
+function TfrmSearch.GetSearchText: string;
+begin
+  Result := cbSearchText.Text;
+end;
+
+function TfrmSearch.GetSearchTextHistory: string;
+var
+  i: integer;
+begin
+  Result := '';
+  for i := 0 to cbSearchText.Items.Count - 1 do begin
+    if i >= 10 then
+      break;
+    if i > 0 then
+      Result := Result + #13#10;
+    Result := Result + cbSearchText.Items[i];
+  end;
+end;
+
+function TfrmSearch.GetSearchWholeWords: boolean;
+begin
+  Result := cbSearchWholeWords.Checked;
+end;
+
+procedure TfrmSearch.SetSearchBackwards(Value: boolean);
+begin
+  rgSearchDirection.ItemIndex := Ord(Value);
+end;
+
+procedure TfrmSearch.SetSearchCaseSensitive(Value: boolean);
+begin
+  cbSearchCaseSensitive.Checked := Value;
+end;
+
+procedure TfrmSearch.SetSearchFromCursor(Value: boolean);
+begin
+  cbSearchFromCursor.Checked := Value;
+end;
+
+procedure TfrmSearch.SetSearchInSelection(Value: boolean);
+begin
+  cbSearchSelectedOnly.Checked := Value;
+end;
+
+procedure TfrmSearch.SetSearchText(Value: string);
+begin
+  cbSearchText.Text := Value;
+end;
+
+procedure TfrmSearch.SetSearchTextHistory(Value: string);
+begin
+  cbSearchText.Items.Text := Value;
+end;
+
+procedure TfrmSearch.SetSearchWholeWords(Value: boolean);
+begin
+  cbSearchWholeWords.Checked := Value;
+end;
+
+procedure TfrmSearch.SetSearchRegularExpression(
+  const Value: boolean);
+begin
+  cbRegularExpression.Checked := Value;
+end;
+
+{ event handlers }
+
+procedure TfrmSearch.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+  frmMain.MainConfig.WriteInteger('SearchPos', 'Left', Left);
+  frmMain.MainConfig.WriteInteger('SearchPos', 'Top', Top);
+end;
+
+procedure TfrmSearch.FormCloseQuery(Sender: TObject;
+  var CanClose: Boolean);
+var
+  s: string;
+  i: integer;
+begin
+  if ModalResult = mrOK then begin
+    s := cbSearchText.Text;
+    if s <> '' then begin
+      i := cbSearchText.Items.IndexOf(s);
+      if i > -1 then begin
+        cbSearchText.Items.Delete(i);
+        cbSearchText.Items.Insert(0, s);
+        cbSearchText.Text := s;
+      end else
+        cbSearchText.Items.Insert(0, s);
+    end;
+  end;
+end;
+
+procedure TfrmSearch.FormShow(Sender: TObject);
+begin
+  Left := frmMain.MainConfig.ReadInteger('SearchPos', 'Left', Round((Screen.Width - Width) div 2));
+
+  if Left >= Screen.Width then
+  begin
+    Left := 10;
+  end;
+
+  Top := frmMain.MainConfig.ReadInteger('SearchPos', 'Top', Round((Screen.Height - Height) div 2));
+
+  if Top >= Screen.Height then
+  begin
+    Top := 10;
+  end;
+
+  cbSearchText.SetFocus;
+end;
+
+end.
+
+