Best way to implement a Trigger?

SyntaxEditor for WPF Forum

Posted 10 years ago by Jan Bannister
Version: 9.1.0500
Avatar
What is the best way to find out the 'word' before the caret?
For example, if I type

if(index = 0 && blah.

I would like to be able to easily figure out that the word "blah." is just before the caret. But the editor.ActiveView.GetCurrentWordText() function just returns "."

I've tried get hold of the text in other ways but the closest I can get is grabbing the whole line. But I can't see how to get hold of the caret position within that line.

I used to use triggers for this before...

Any suggestions?

Thanks in advance,
Jan

Comments (7)

Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Jan,

You'd want to get an ITextSnapshotReader via editor.ActiveView.GetReader() then use that to iterate through the text. You can iterate by text, token, etc.

How are you hooking into key input right now? In SyntaxEditor for WinForms, we had a KeyTyped event that you could respond to. We still need to add something similar to WPF so that you'd easily be able to handle "." presses and show a completion list in response.

Right now the editor views are receiving the key input and they handle it. Therefore the SyntaxEditor control never receives the event. One thing we're considering doing is raising the event on the root SyntaxEditor control too.

Alternatively (or in addition), we add a virtual method on the SyntaxLanguage class like OnSyntaxEditorTextInput that would be called. This way your language could directly handle keypresses (which is hour our WinForms add-ons work).

Which do you prefer, just the language method, both, or some other option?


Actipro Software Support

Posted 10 years ago by Craig - Varigence, Inc.
Avatar
In my project, for displaying completion lists, the technique we're trying is creating a class that extends EditorViewInputProcessorBase and overriding OnTextInput. In OnTextInput, I can check each key press and then call a function to display the intelliprompt list when a period is entered.

From reading the documentation, it seemed like editor processing was provided to replace the KeyTyped event. I kinda like it since it encourages me to not have a bunch of operations in a single KeyTyped handler; instead, I can create multiple extended classes and override OnTextInput as needed. Thus, I have no problem with using this approach and dumping KeyTyped.

Alternatively, as all the completion list examples I saw were command based, I was wondering if it'd be easier to keep the command but allow multiple input bindings so instead of just Ctrl+Space, other characters could trigger it the command, like a "." character. (Note that I do find it weird that in the samples, you always seem to remove the intelliprompt command and then rebind it separately).

I do think adding the virtual method in the SyntaxLanguage would be valuable for others.
Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
We've been working on this today. Let me summarize where we are planning on going with it and please comment back:

1) New interfaces: ICodeDocumentEventSink, ISyntaxEditorEventSink
1a) ICodeDocumentEventSink - Has support for ICodeDocument text change events
1b) ISyntaxEditorEventSink - Has support for many SyntaxEditor events

2) SyntaxLanguageEventSinkBase abstract class that implements the interfaces above... your implementations would inherit that class and override OnSyntaxEditorTextInput, etc. It would have a reference to the ISyntaxLanguage for which it was created. Therefore you could look for "." being typed and call a method on your language in response to that.

3) ISyntaxLanguage.EventSink property added. When events occur, SE and the document examine that property to see if it implements ICodeDocumentEventSink or ISyntaxEditorEventSink and if so, notifies the object of the event.

4) OnDocumentTextChanging, OnDocumentTextChanged methods moved from SyntaxLanguage to SyntaxLanguageEventSinkBase

The idea here is that we have separated out the overridable event handling messages from the language class itself. Thus you can swap in and out event sink objects if you wish, without changing the language class at all.

The editor view input processors were originally intended to be short-lifetime objects that are only used while IntelliPrompt sessions are open (like a completion list is displayed). However after digging into this, we're finding that they have a lot in common with the "event sink" idea.

Do you like these proposed changes and also, should we combine the idea with the input processors more to have some sort of unified model? Let's get your thoughts and hopefully we can get some changes in for the next maintenance release. Thanks!


Actipro Software Support

Posted 10 years ago by Jan Bannister
Avatar
I'm probably missing something but that feels quite complex to me. I feel that there should be some way of looking into the document model of the editor but I'll leave that up to you guys.

To solve my issue I currently use this.

void _editor_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.OemPeriod)
{
var line = _editor.ActiveView.CurrentSnapshotLine.Text;
var caret = _editor.Caret;
var pos = caret.Position;
var typed = line.Substring(0, pos.Character);

if (typed.EndsWith("blah."))
{
...

This works but seems a little bit round-about.
Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Quick update... for the next build we've added a better place to look for things like '.' keypresses.

The SyntaxEditor.DocumentTextChanged event provides all we need to support this but we did have to make a tweak here to get it working with completion list. So in the next build, this is all you'd have to do:
private void OnEditorDocumentTextChanged(object sender, EditorSnapshotChangedEventArgs e) {
    // The e.TypedText is not null only when a Typing change occurs with a single operation that
    //    inserts text, so we can check that to display the completion list when "." is typed
    switch (e.TypedText) {
        case ".":
            this.ShowCompletionList();
            break;
    }
}
The TypedText property is new for EditorSnapshotChangedEventArgs. If your text change is a Typing change (generated via TextInput, etc.) and it has a single insert operation, that will be filled in with the text inserted by the operation. Otherwise it is null. So it's a handy way to see if the end user typed something and to respond accordingly. In the sample above, we look to see if a "." character was typed and if so, display the completion list.

Jan, I'll reply again soon with some more info on how to grab the text before the dot.


Actipro Software Support

Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Jan,

Here's an example (works in next build) that shows how to look for a "." typed by the end user and to only show the completion list if the "." is after a "this" C# keyword:
private void OnEditorDocumentTextChanged(object sender, EditorSnapshotChangedEventArgs e) {
    // The e.TypedText is not null only when a Typing change occurs with a single operation that inserts text,
    //   so we can check that to display the completion list when "." is typed
    switch (e.TypedText) {
        case ".": {
            // Use a snapshot reader to iterate backwards through the active view's current text
            ITextSnapshotReader reader = editor.ActiveView.GetReader();
            reader.ReadCharacterReverseThrough('.');
            IToken token = reader.ReadTokenReverse();

            // In production code, a token ID comparison would be better than this string comparison
            if ((token != null) && (reader.TokenText == "this")) {
                // A dot was typed after a "this" keyword so show the completion list
                this.ShowCompletionList(false);
            }
            break;
        }
    }
}
This code first checks to see if a "." was typed. If so, it grabs an ITextSnapshotReader for the active view's current snapshot. It scans back past the "." that was typed, then reads the token before the ".". At this point you may wish to continue reading back through tokens if the token is a whitespace token but we don't show that in this sample. Next we check the TokenText to see if it is the "this" keyword, however if tokens IDs are available, it would be better to do a token ID comparison here. If the token was a "this" keyword we show the list.

Hope this helps to get you going once you get the next build (should be in June sometime). All of these things will be able to be done within ISyntaxLanguage implementations via the event sink model described in previous posts of this thread.


Actipro Software Support

Posted 10 years ago by Jan Bannister
Avatar
That looks a neat solution.
I'll use it once I get the new version of the WPF Studio.

Thanks a mill,
Jan
The latest build of this product (v2019.1 build 0683) 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.