[Lazarus] SynEdit.TextBetweenPoints (Martin?)

Bart bartjunk64 at gmail.com
Sat Aug 10 19:28:24 CEST 2019


Hi,

Consider this piece of code.
On a form have a TSynEdit (named: Ed) and a TSpeedButton.

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  BB, BE: TPoint;
  BackwardsSel: Boolean;
  SelLength: Integer;
const
  Pre = '{';
  Post = '}';
begin
  writeln('===================');
  writeln;
  with Ed do
  begin
    BB := BlockBegin;
    BE := BlockEnd;
    BackwardsSel := IsBackwardSel;
    SelLength := SelEnd-SelStart;
    writeln('BlockBegin  =',bb.x,',',bb.y);
    writeln('BlockEnd    =',be.x,',',be.y);
    writeln('SelLength   =',SelLength);
    writeln('BackwardsSel=',BackwardsSel);


    //BB is always before BE even if IsBackwardSel=TRUE
    //move caret to the end of the selection
    LogicalcaretXY := BlockEnd;
    //SetLogicalCaret clears the selection, so restore it
    BlockBegin := BB;
    BlockEnd := BE;

    BB := BlockBegin;
    BE := BlockEnd;
    writeln('After SetLogicalCaret');
    writeln('BlockBegin  =',bb.x,',',bb.y);
    writeln('BlockEnd    =',be.x,',',be.y);
    //Insert Pre at blockbegin, so in front of the selection: block
moves to the right, blockbegin.x and blockend.x will increase
    SetTextBetweenPoints(BB, BB, Pre, [setMoveBlock], scamIgnore,
smaMoveUp, smNormal);
    BB := BlockBegin;
    BE := BlockEnd;

    writeln('After SetTextBetweenPoints(BB,BB,...)');
    writeln('BlockBegin  =',bb.x,',',bb.y);
    writeln('BlockEnd    =',be.x,',',be.y);

    //Insert Post at blockend, the block does NOT move, so this should
NOT affect the value of blockbegin or blockend
    SetTextBetweenPoints(BE, BE, Post, [setMoveBlock], scamIgnore,
smaMoveUp, smNormal);
    //Now the caret needs to be moved to BlockBegin, but unfortunately
this unselects the selection
    //so we save where it ends, then restore it
    BB := BlockBegin;
    BE := BlockEnd;

    writeln('After SetTextBetweenPoints(BE,BE,...)');
    writeln('BlockBegin  =',bb.x,',',bb.y);
    writeln('BlockEnd    =',be.x,',',be.y);


    if not BackwardsSel then
      LogicalCaretXY := BlockEnd
    else
      LogicalCaretXY := BlockBegin;
    BlockBegin := BB;
    BlockEnd := BE;

    writeln('After SetLogicalCaret');
    writeln('BlockBegin  =',bb.x,',',bb.y);
    writeln('BlockEnd    =',be.x,',',be.y);
  end;
  writeln;
  writeln('===================');
  writeln;
end;

It's intention is to put Pre in front of the current selection and
Post after it.
The original selected text should still be selected after it, and the
caret must be at the end of the selected text.

Build and run.

Now in an empty synedit type a single character e.g. '1' (at point (1,1))
Run the code.

It works as expected.
The text is now {1} and the 1 is selected.

Now clear the synedit again.
Run the code again.
This time the text will be {} (as expected), but the entire {} will be selected.

Here's the debug output:

Case 1 (1 character at (1,1) selected):

BlockBegin  =1,1
BlockEnd    =2,1
SelLength   =1
BackwardsSel=FALSE
After SetLogicalCaret
BlockBegin  =1,1
BlockEnd    =2,1
After SetTextBetweenPoints(BB,BB,...)
BlockBegin  =2,1
BlockEnd    =3,1
After SetTextBetweenPoints(BE,BE,...)
BlockBegin  =2,1
BlockEnd    =3,1
After SetLogicalCaret
BlockBegin  =2,1
BlockEnd    =3,1

Case 2 (no text selected)
BlockBegin  =1,1
BlockEnd    =1,1
SelLength   =0
BackwardsSel=FALSE
After SetLogicalCaret
BlockBegin  =1,1
BlockEnd    =1,1
After SetTextBetweenPoints(BB,BB,...)
BlockBegin  =1,1
BlockEnd    =2,1
After SetTextBetweenPoints(BE,BE,...)
BlockBegin  =1,1
BlockEnd    =3,1
After SetLogicalCaret
BlockBegin  =1,1
BlockEnd    =3,1

===================

When text is selected, SetTextBetweenPoints will move the block to the
right if we insert text before it and adjust BlockBegin and BlockEnd
accordingly.

However when no text is selected, BlockBegin. remains unchanged, but
BlockEnd is incremented, which IMO is wrong: BlockBegin.X should be
incremented by the amount dicated by the contents of Pre (in this case
BlockBegin.X should be incremented by 1).

Is this a bug (in SetTextBetweenPoints?) or do I need to adjust my
code for the case where no text is selected?

-- 
Bart


More information about the lazarus mailing list