7

I'm using TSynEdit as a more user-friendly TMemo, mostly for the advanced shortcuts, UNDO/REDO, and so on.

Other things are OK, except the wordwrap behavior, please check the attached screenshot below, SynEdit has a strange space shown on the left-most side.

How to avoid that and make it look like TMemo?

enter image description here

The TSynEdit's key property settings:

    synEdit1.UseCodeFolding := False;
    synEdit1.Options := [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, 
eoGroupUndo, eoScrollPastEol, eoSmartTabDelete, 
eoSmartTabs, eoTabsToSpaces];
      synEdit1.ScrollBars := ssVertical;
      synEdit1.TabWidth := 4;
      synEdit1.WantTabs := True;
      synEdit1.WordWrap := True;
      synEdit1.FontSmoothing := fsmNone;
Edwin Yip
  • 4,089
  • 4
  • 40
  • 86
  • I can't find a way myself either. – Jerry Dodge Feb 02 '19 at 16:23
  • @JerryDodge: Hmm, this behaviour seems to be quite deliberate, but I can't see why it should be. An odd thing is that depending on the width of the SynMemo, a few lines don't have a starting space. – MartynA Feb 02 '19 at 19:27
  • Haven't used *SynEdit* for many many years, but I wonder what *eoAutoIndent* does. – Rudy Velthuis Feb 03 '19 at 00:24
  • @RudyVelthuis The comment on eoAutoIndent is `Will indent the caret on new lines with the same amount of leading white space as the preceding line`, but neither this nor any of the other `eoXXX` options (including `eoTrimTrailingSpaces`) seem to make any difference to the behaviour in the screen shot: the only thing which *does* is the `WordWrap` property. of the `SynEdit`. Same is true for the SynMemo, too. – MartynA Feb 03 '19 at 07:32
  • I guess the intention is that you can see that the text has been wrapped and it's not a newline. Since you have the source code it must be very easy to change the behaviour. – David Heffernan Feb 03 '19 at 12:03
  • It is even worse. Sometimes a space is shown, ometimes it is not. I guess it should simply not display the line breaking spaces when wrapping. It doesn't wrpa properly: sometimes it wraps in the middle of a word instead of at the word start. – Rudy Velthuis Feb 03 '19 at 13:03
  • @DavidHeffernan, correct, that's the intention. I guess it's not easy, since you have to understand the library architecture and read through the source code. – Edwin Yip Feb 03 '19 at 13:35
  • Well, it's not going to be hard. Look for the Paint method of the control and take it from there. – David Heffernan Feb 03 '19 at 13:39
  • It puts the character it wraps on from the source text at the start of the next line instead of at the end of the previous line. In the example the space between **of** and **the** is at the end of the first line for TMemo and at the start of the second line for TSynEdit. – Brian Feb 04 '19 at 21:37

1 Answers1

4

This is not a complete, tested answer to the q, but may offer the determined reader a jumping-of point to a functional solution.

The word-wrapping behaviour of a TSynEdit is determined by its current TSynWordWrapPlugin. The default plugin is defined in SynEditWordWrap.Pas and contains the procedure TSynWordWrapPlugin.WrapLines method, starting at line 512 in the version I downloaded yesterday using the D10.2.3 GetIt Manager.

Starting at line 560 there is the block of code which, as far as I can tell, accounts for the space at the start of each wrapped line as illustrated in the q:

      if Editor.IsWordBreakChar(vRunner^) then
      begin
        vRowEnd := vRunner;
        break;
      end;
      Dec(vRunner);

vRunner and vRowEnd are among a number of PWideChar variables used in the WrapLines method.

Watching the behaviour of this code, which is inside a while loop (which is looking for a place to do a word-wrap), it operates so that when Editor.IsWordBreakChar(vRunner^) returns true, the vRunner pointer has already moved backwards past the word-break char, which is why it (the space) ends up on the following line, causing the problem noted by the OP.

Changing the code to

      if Editor.IsWordBreakChar(vRunner^) then
      begin
        {ma} Inc(vRunner);  //  WARNING: not fully tested
        vRowEnd := vRunner;
        break;
      end;
      Dec(vRunner);

forces the vRunner pointer forwards past the word-break character so that the space is included at the end of the line rather than at the start of the next one, so the SynEdit then displays its wrapped text like the standard TMemo.

Personally, I would not use this change, but would instead see if I could persuade the SynEdit developers to provide an official solution. if I did use the change shown above, I certainly wouldn't do it by changing the source of SynEditWordWrap.Pas, I would do it by writing a replacement for TSynWordWrapPlugin and I would include a check that the inc(vRunner) does not exceed the valid bounds of the buffer being used to do the word-wrapping.

MartynA
  • 30,454
  • 4
  • 32
  • 73
  • Thanks for the hint! I definitely will look into it when I use TSynEdit for more than just a memo. – Edwin Yip Feb 04 '19 at 15:04
  • I confirm @MartynA's suggested changes works at first try! I'll keep monitoring possible issues and update back here. – Edwin Yip Mar 03 '19 at 07:56