Text and Current Line Offsets Not Matching in SyntaxEditor

SyntaxEditor for WPF Forum

Posted 2 months ago by david lin
Version: 24.1.1
Platform: .NET 8
Environment: Windows 10 (64-bit)
Avatar

Hello Actipro Developers,

I'm currently implementing a custom shortcut for line breaks in SyntaxEditor through code.
Since I couldn’t find any official method that directly supports this feature in the documentation, I decided to implement it myself.

Here is my code:

 private void OnEditorPreviewKeyDown(object sender, KeyEventArgs e)
 {
     var isEnter = e.Key == Key.Return;

     var index = editor.ActiveView.Selection.CaretOffset;

     var mods = Keyboard.Modifiers;

     if (isEnter)
     {
         if ((mods & ModifierKeys.Control) != 0)
         {
             editor.Text = editor.Text
                 .Insert(editor.ActiveView.CurrentViewLine.EndOffset, Environment.NewLine);

             editor.ActiveView.Selection.CaretOffset 
                 = editor.ActiveView.CurrentViewLine.NextLine.StartOffset;

             e.Handled = true;
         }
     }
 }

As shown in the code, when pressing Ctrl+Enter, a new line should be inserted immediately below the current one, and the caret should move to the beginning of that new line.

However, I noticed that the value returned by editor.ActiveView.CurrentViewLine.EndOffset does not match the actual editor.Offset.
Because of this mismatch, the custom line break doesn’t behave as expected.

debug img

From what I can tell, the offset calculation seems to ignore characters like \r\n, which might be causing the inconsistency.

It seems that the offset calculation removes or ignores the \r\n characters, which makes it difficult to insert a new line at a specific character index.
I don’t quite understand why this happens, and it causes some trouble when trying to calculate the correct position for inserting a newline.

Could you please advise whether there’s a more convenient or recommended way to insert a new line programmatically in SyntaxEditor?

Thank you!

Attached is the complete project address

[Modified 2 months ago]

Comments (3)

Posted 2 months ago by david lin
Avatar

I realized that my previous description lacked some context, which may have affected the clarity of the issue. Here’s a more detailed explanation:

When I need to insert a new line, I first obtain the end position of the current line and then insert a newline from that position.

However, since the CurrentLine in SyntaxEditor returns a character index that excludes characters like \r\n, the value of editor.ActiveView.CurrentViewLine.EndOffset becomes smaller than the actual text offset.


As a result, the insertion occurs before the true end of the line, which unintentionally cuts off part of the text instead of appending a newline after the line.

You can see the detailed behavior in the attached file.
However, please do not start testing from the first line, as the first line is not affected by the issue caused by the removed \r\n characters.

Answer - Posted 2 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi David,

From the beginning, SyntaxEditor has always normalized line terminators internally to LF (\n) only.  This made things like lexing and parsing much easier, among other areas, since it avoided the need for complex logic to look for possible two character line terminators.  There are overloads for document methods like GetText and GetSubstring that allow you to convert the line terminators back to CRLF form, or something else if desired.  All our offsets are consistent zero-based integers that are relative to the document character positions where LF-only is used for line terminators.

That being said, in recent years we have regretted making that original decision since it does throw the offsets off from the original source document.  We also would like to be able to present which line terminators are used to the end user and possibly warn if mixed line terminators were in a loaded document.  The good news is that we have been working on updating our codebase to support retention of the original line terminators throughout the document, and we hope to have that feature in v26.1.  It's been a rather massive undertaking that affects a lot of areas in SyntaxEditor.

What you are trying to do should really be implemented as an edit action, which is how we've implemented all our SyntaxEditor functionality in response to keyboard shortcuts.  There is an Edit Actions QuickStart that shows how to build one.

In fact, we already have an OpenLineBelowAction implemented that is activated by Ctrl+Shift+Enter and is I believe what you are trying to do.  So you may not need to write your own at all.

We currently have OpenLineAboveAction (the opposite) wired to Ctrl+Enter.  If you wanted both Ctrl+Enter and Ctrl+Shift+Enter to perform OpenLineBelowAction, you'd need to remove the existing input binding and add a new one like this:

var inputBindings = editor.InputBindings;
inputBindings.Remove(inputBindings.OfType<KeyBinding>().First(b => b.Key == Key.Enter && b.Modifiers == ModifierKeys.Control));
inputBindings.Add(new KeyBinding(EditorCommands.OpenLineBelow, Key.Enter, ModifierKeys.Control));

Some more notes on your post.  I think what you're running into here is that the SyntaxEditor.Text property you are using in your code is a convenience property that returns the full document text converted back to CRLF form.  That is throwing the offsets off from what we are reporting.  Even if you used SyntaxEditor.Document.GetText(LineTerminator.Newline) to get the text, that is not a recommended way to do this.  Our document text is stored in a tree structure internally and rebuilding full document text to a string is not ideal unless necessary since it involves a lot more processing than simply using the SyntaxEditor.Document.InsertText method or others like that on the document itself.  By using those methods, the offsets will all be valid.  Another downside of where you set editor.Text is that it completely replaces the entire document text for this one edit action, which will reset change tracking and affect scroll position.  Using the document methods like InsertText will not have those negative side effects.

Anyhow, please let us know if the existing edit action we have will work for you.


Actipro Software Support

Posted 2 months ago by david lin
Avatar

Yes, thank you for your suggestions! They gave me a deeper understanding of SyntaxEditor.
Also, the commands in EditorCommands are exactly what we were looking for.

Thanks again!

The latest build of this product (v25.1.2) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.