Showing Filtered Text

SyntaxEditor for WPF Forum

Posted 5 years ago by Matt Gerrans
Version: 14.2.0610
Avatar

What is the right way to go about showing a different view of the actual text in the Syntax Editor relative to what is stored?

In other words, the actual text might be something like this:

   This sentence has a @special@attrib1=value1, attrib2=value2@ marked up word in it.

What I want to see in the editor is only this text:

   This sentence has a special marked up word in it.

But the word "special" should have some adornment to show it has attributes; it will also have a context menu where a dialog can be opened to edit the attributes.

With the Winforms Syntax Editor, we would intercept the Text property, remove the markup and add a indicator range, then when saving, go throug those indicators and add the text back in.   So you never see the markup in the editor (just the squiggly indicator), but add/edit/remove via the popup dialog, even though the markup is saved in the text that's saved to file.

Comments (9)

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

Hi Matt,

The WPF SyntaxEditor has some very nice features where you can collapse (hide) regions of text but they remain in the document. You also can inject adornments in their place.  Take a look at the "Collased Regions - Advanced" QuickStart since it exactly shows these features.  The adornments can be any custom WPF element, like a button.  We show a button adornment in the "Adornments 6" QuickStart.


Actipro Software Support

Posted 5 years ago by Matt Gerrans
Avatar

The collapsed regions is a cool feature that we'll probaby move to at some point in the future, but as the text isn't that editable now and its constraints are managed by the dialog, I just want to get the squiggle tags working for it on the short term.   The problem I'm having is that the when the GetTags() method is called in my SquiggleTagger class is called, it doesn't have any context.   The class that manages the SyntaxEditor maintains the list of marked up ranges and it knows what should be tagged, but in the context of GetTags() I don't know how to access the EditorManager that is relevant to the event.

I see that I can get the CodeDocumentTaggerProvider after registering my tagger, but I don't know how I can get the correct instance of the tagger in my editor manager, or how to get the correct instance of my editor manager from within GetTags().   How do I get the correct context information to the GetTags() method (or the tagger instance)?

By the way, in the adornment example you mentioned, the collapsed regions have a tooltip that shows the text in the collapsed region, but it isn't clear where that gets set.    How is that working?    (note that this question is not as important as the one above, so if you only answer one, make it that one!)

Thanks!

Posted 5 years ago by Matt Gerrans
Avatar

Additional question: is it possible to make the collapsed text editable?   For example we might have something display like this:

set an alarm for <alarm_datetime> called <alarm_name>

While the real underlying text is this:
set an alarm for <alarm_datetime> @called@Grammar="True" SemanticPattern="True" score="100"@ <alarm_name>

because the word "called" has markup associated with it.   Note that any or all of the words (including the special kinds of words in <> or other delimiters) can have markup.

Marked up words should have squiggly underlines, a tooltip that shows the markup attribute and a context menu that will pop up the markup editor dialog.    In addition to this, you can simply edit the word itself, so you could change "called" to "calling" in place and it will keep its markup.    Is it possible to edit an injected adornment in the same way?   That is, would it be possible to edit the replacement word "called" in the adornment and to likewise have the corresponding "called" in "@called@Grammar="True" SemanticPattern="True" score="100"@" (the actual text) change to "calling" so it would then be "@calling@Grammar="True" SemanticPattern="True" score="100"@"?


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

Hi Matt,

If you want to use the normal "pull" sort of mechanism where GetTags asks for tagged ranges and you provide them on demand, the tagger should generally have a Document property that gives you access to the document being edited in the editor.  Note that a single document can be edited at the same time by multiple SyntaxEditors so there's no way to go from document to an editor.  You could however store a reference to your editor manager in the Document.Properties collection.  That way it would be accessible to the tagger.

Another option if you want to store the data in the document itself is to use a CollectionTagger<T>.  With those, you can basically treat it like a collection of tagged ranges and add/remove them.  There are several usages of CollectionTagger<T> in the samples.

For the quick info, it's working since in the language, we registered this service:

this.RegisterService(new CollapsedRegionQuickInfoProvider());&nbsp;

For the other question, if you are replacing text with an adornment, you are injecting a custom WPF element as the adornment. The text that is replaced there wouldn't be editable. You would need to edit it in a popup.

Or if you did want it editable in the main editor, you would need to collapse the two areas surrouding the text instead of the whole area. But that might lead to other issues for you depending on what you are trying to achieve.


Actipro Software Support

Posted 5 years ago by Matt Gerrans
Avatar

Thanks, that helped; I had not discovered the Document Properties.

It also turns out we were using the Tokens property of the document.   It looks like that is gone now.    It looks like token tagging would replace that, but if I have a token "foo" that was tagged and is now showing a squiggly line, then it is edited to be "foob" I need to somehow identify that this new thing "foob" corresponds to the old token "foo."   Are the tokens from the last parse available somewhere?   Would I do something similar to GettingStarted02 where it collects the function tokens?

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

Hi Matt,

Yes in the WinForms version we stored the Tokens for the entire document.  In the WPF version, we don't store tokens and instead generate them on demand.  This reduces overall memory usage and makes it easier to support the snapshot concept where each snapshot is an immutable copy of a document state and can have its own token stream.  

We don't retain tokens anywhere but you could do so using some concepts like in Getting Started #2 and then retain them in the parse data.  Then you could watch parse data change events.


Actipro Software Support

Posted 5 years ago by Matt Gerrans
Avatar

Yup, I figured out how to do this by updating my Markup tracker in OnDocumentTextChanged(), but I was having a problem with the QuiggleTagger getting its GetTags() called before OnDocumentTextChanged() occured, so the squiggles would not show properly.   Adding a call to InvalidateViews() after updating my Markup ranges (which GetTags() looks at to decide if a token needs markup did the trick, though I'm not sure if that's the best way to do this.

Since several different type of our tokens can have this markup, I'm not sure how I would integrate this into the language better.   As mentioned above, I'll look at using collapsible regions in the future (after some working with this, I concluded will also make life easier if the tokens are not editable once they've been marked up -- it is a real headache keeping markup on tokens through all the possible things that can occur with editing and copy/paste and would be a lot cleaner if the markup were detached before the token was changed, or something along those lines).

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

Hi Matt,

If you are using the "pull" sort of approach I had mentioned for your tagger, you could raise its TagsChanged event when things changed.  That way, the editor would end up knowing to invalidate the range you specify in the event args.  That might be cleaner than doing the InvalidateViews call.


Actipro Software Support

Posted 5 years ago by Matt Gerrans
Avatar

Okay I did this:  

   MarkupSquiggleTagger tagger;
   Editor.Document.Properties.TryGetValue(typeof(MarkupSquiggleTagger), out tagger);
   if (tagger != null)
   {
      tagger.RaiseTagsChanged(new TagsChangedEventArgs(args.ChangedSnapshotRange));
   }

 And after adding RaiseTagsChanged() to my tagger and having it call OnTagsChagned(), that seems to work as well.

Thanks.

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.