Recent

Author Topic: Synedit - search and replace  (Read 13070 times)

Aeternitas

  • New Member
  • *
  • Posts: 42
    • The Dark Forests Web
Synedit - search and replace
« on: January 12, 2013, 01:14:37 pm »
Hi,

I'm making environment of a programming language and I want to build in the search and replace function.

I made some function, but it seems to be buggy. See the following code:

Find function:
Code: [Select]
procedure TForm10.Button1Click(Sender: TObject);
var
  FindS: String;
  IPos, FLen, SLen: Integer;

begin
  FPos:=Form1.GetCursorOffset;

  Found:= False;
    FLen := Length(LabeledEdit1.Text);
    SLen := Length(Edits[Form1.PageControl1.PageIndex].Edit.Text);
    FindS := LabeledEdit1.Text;

    if (CheckBox1.Checked=true) then
       IPos := Pos(FindS, Copy(Edits[Form1.PageControl1.PageIndex].Edit.Text,FPos+1,SLen-FPos))
    else
       IPos := Pos(AnsiUpperCase(FindS),AnsiUpperCase( Copy(Edits[Form1.PageControl1.PageIndex].Edit.Text,FPos+1,SLen-FPos)));

    If IPos > 0 then begin
      FPos := FPos + IPos;
 
      Edits[Form1.PageControl1.PageIndex].Edit.SelStart:= FPos;
      setSelLength(Edits[Form1.PageControl1.PageIndex].Edit, FLen);     
     
      Edits[Form1.PageControl1.PageIndex].Edit.SetFocus;
      Found := True;
      FPos:=FPos+FLen-1;
    end;
   

end;     

Replace function:
Code: [Select]
procedure TForm10.Button2Click(Sender: TObject);
begin
  Button1Click(nil);

  if (Length(Edits[Form1.PageControl1.PageIndex].Edit.SelText)>0) then
    Edits[Form1.PageControl1.PageIndex].Edit.SelText:=LabeledEdit2.Text;
end;

Functions used:
Code: [Select]
procedure TForm10.SetSelLength(var textComponent:TSynEdit; newValue:integer);
  begin
    textComponent.SelEnd:=textComponent.SelStart+newValue ;
  end;

and:
Code: [Select]
function TForm1.GetCursorOffset: integer;
var
  i: integer;
begin
  Result:=0;

  For i:=0 to Edits[PageControl1.PageIndex].Edit.CaretY-2 do
    Result:=Result+2+Length(Edits[PageControl1.PageIndex].Edit.Lines[i]);

  Result:=Result+Edits[PageControl1.PageIndex].Edit.CaretX+3;
end;

The last function makes so one can search from the caret position. But it is something wrong with it. The result is not correct.

Also the replacement is wrong. Sometimes good, sometimes several letters wrong.

I also wanna ask, how to change the code so one can search backwards.

OS: Windows.

Thank you in advance.
« Last Edit: January 12, 2013, 01:18:36 pm by Aeternitas »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10670
  • Debugger - SynEdit - and more
    • wiki
Re: Synedit - search and replace
« Reply #1 on: January 12, 2013, 02:32:18 pm »
Without having read all the code, a few things:

1) Why not stick with the x/y notion? Wyt trying to map the caret into an offset of the entire text?

But anyway, if necessary: TSynMemo has code to do that (I really should move that to SynEdit, one day...).

SynMemo and SynEdit are identical, except for:
- SynMemo has the caret to offset and back
- SynMemo has a forwarder to Lines.Append or similar
- SynMemo has less published properties (they are there, but they are only public)

2)
 Result:=Result+Edits[PageControl1.PageIndex].Edit.CaretX+3

That is wrong. Use "LogicalCaretX - 1"

CaretX is the screen pos (screen column) (also called Physical in source)
LogicalCaretX is the bytepos

For the he line 'A'#9'ü' with a tab width of 4. (note utf8 'ü' uses 2 bytes
Before a :                 Log = 1 Phys = 1
Between a and #9 : Log = 2 Phys = 2
Between #9 and ü : Log = 3 Phys = 5
After ü :                    Log = 5 Phys = 6

So if you are before 'a', then you do want to add 0, that is  "LogicalCaretX - 1"


BlockBegin/End are always logical.

3) SynEdit has SearchReplaceEx: very powerful. If you do not specify the "replace flag", then it is a search.

Returns 0, if not found,  1 if found (on replace: number of replaced).
Found item will be selected.

Aeternitas

  • New Member
  • *
  • Posts: 42
    • The Dark Forests Web
Re: Synedit - search and replace
« Reply #2 on: January 12, 2013, 03:50:31 pm »
Thank you. It worked. :)

One more question. I want to make special (export) function, which searches for every text behind // and every text between "..." with exception of "...x", where x is a number. Then takes all these texts, copies them into special textual file. There will be some corrections or so outside. Then another (import) function, which returns everything back, but of course so changed.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10670
  • Debugger - SynEdit - and more
    • wiki
Re: Synedit - search and replace
« Reply #3 on: January 12, 2013, 04:34:44 pm »
Not sure what you mean?
like
Code: [Select]
  some line
  next line // copy me ...1
  line 3 // do not copy
  line 4 // also not copy ... no number
  line 5 // copy or not? ... no number yet, but ...4

Assuming the ... must be on the same line as the // ?

You can loop over al lines, and use "pos"

or regular expression search. Not tested but probably
//(.*?)\.\.\.[0-9]

Aeternitas

  • New Member
  • *
  • Posts: 42
    • The Dark Forests Web
Re: Synedit - search and replace
« Reply #4 on: January 12, 2013, 04:50:33 pm »
Example:

not copied text text text // copy me
not copied text text text "copy me", "do not copy me because there is number7" // copy me

And then back.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10670
  • Debugger - SynEdit - and more
    • wiki
Re: Synedit - search and replace
« Reply #5 on: January 12, 2013, 05:14:32 pm »
Then you probably end up writing your own search. looping over each line.

the // can be done via regular expression. Including testing for numbers. It gets complicated in case of
Code: [Select]
  not copied // no no no 7 // copy me, or do I belong to the 1st ?

But the "" can only be done by testing yourself, since a search, does not know, what is opening, and what is closing ".
Code: [Select]
  "1", "2"
should not copy anything. But a search would get the ", "


Aeternitas

  • New Member
  • *
  • Posts: 42
    • The Dark Forests Web
Re: Synedit - search and replace
« Reply #6 on: January 19, 2013, 07:41:58 pm »
How can I select from caret position to the end of line?

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10670
  • Debugger - SynEdit - and more
    • wiki
Re: Synedit - search and replace
« Reply #7 on: January 19, 2013, 08:16:07 pm »
BeginUpdate;
BlockBegin := LogigcalCaretXY;
BlockEnd:= Point(Length(Lines[CaretY-1])+1,  CaretY);
LogigcalCaretXY := BlockEnd; 
EndUpdate;

You do NOT have to set the caret  at the end, and you can swap BlockBegin/BlockEnd (however you mus always first set BlockBegin)


Unless you use persistent blocks, the selection will be unselected, if the caret moves to anywhere else.


Aeternitas

  • New Member
  • *
  • Posts: 42
    • The Dark Forests Web
Re: Synedit - search and replace
« Reply #8 on: January 20, 2013, 01:12:53 am »
Thx, it works.

Aeternitas

  • New Member
  • *
  • Posts: 42
    • The Dark Forests Web
Re: Synedit - search and replace
« Reply #9 on: January 22, 2013, 06:34:42 pm »
Another question. Let's say I have a caret on some place and I want to find out next word (that is containing letters only). Just find out, not move the caret. How can I do it?

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10670
  • Debugger - SynEdit - and more
    • wiki
Re: Synedit - search and replace
« Reply #10 on: January 22, 2013, 08:11:34 pm »
    procedure GetWordBoundsAtRowCol(const XY: TPoint; out StartX, EndX: integer);

There are some protected methods too, if you inherit or use class helpers:
    function NextWordLogicalPos(ABoundary: TLazSynWordBoundary = swbWordBegin; WordEndForDelete : Boolean = false): TPoint;
    function PrevWordLogicalPos(ABoundary: TLazSynWordBoundary = swbWordBegin): TPoint;

Aeternitas

  • New Member
  • *
  • Posts: 42
    • The Dark Forests Web
Re: Synedit - search and replace
« Reply #11 on: January 22, 2013, 08:51:57 pm »
So I tried this:

Code: [Select]
Edits[PageControl1.PageIndex].Edit.GetWordBoundsAtRowCol(Edits[PageControl1.PageIndex].Edit.LogicalCaretXY,x1,x2);
        nextword:=copy(Edits[PageControl1.PageIndex].Edit.Text, x1, x2);

or

Code: [Select]
Edits[PageControl1.PageIndex].Edit.GetWordBoundsAtRowCol(Edits[PageControl1.PageIndex].Edit.LogicalCaretXY,x1,x2);
        nextword:=copy(Edits[PageControl1.PageIndex].Edit.LineText, x1, x2);

but it doesn't work. Problem is, there is no word on position and I need to find word. There is a word further on, but I don't know how to find it (the word might be also on the next line).

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10670
  • Debugger - SynEdit - and more
    • wiki
Re: Synedit - search and replace
« Reply #12 on: January 22, 2013, 09:42:33 pm »
Then you need to inherit, or use classhelpers.

And then you can access

    function NextWordLogicalPos(ABoundary: TLazSynWordBoundary = swbWordBegin; WordEndForDelete : Boolean = false): TPoint;

pos := SynEdit.NextWordLogicalPos(swbWordBegin);

Search starts at caret.

Also I am not sure. IIRC word depends on highlighter. e.g "_" or "$" being part or not part of a word.

 (Calling convention could change in future, but not likely)

--

You can also create an instance of TSynWordBreaker. But it only works on 1 line.
You need to search the code for examples.

--

Otherwise, you can always scan the text yourself.

 

TinyPortal © 2005-2018