VS2010 syntax coloring: how to obtain the previous

2019-07-04 03:08发布

问题:

I'm trying to play with the new syntax coloring capabilities of VS2010 based on Noah Richards' diff coloring sample. The goal is to create syntax coloring for SpecFlow (http://www.specflow.org).

In my case, finding the syntax elements are fairly complex and not line-level. Therefore, when I implement the GetClassificationSpans I don't want to re-parse the entire file, but rather take the state of the beginning of the changed text and parsing the content from that point on.

I thought that I can get the previous classifications as ClassificationTags. I did this using the IBufferTagAggregatorFactoryService class.

It works, but I'm not sure whether this is the best way to go. Shall I create only tag aggregator for the entire classifier class or I can create it every time when GetClassificationSpans is called? Shall I create a special tag to remember the parsing state?

Maybe this is anyway not the right way to go, I'm also interested in other suggestions.

Br, Gaspar

Edit: I've found a good article series in the topic: http://www.hill30.com/MikeFeingoldBlog/index.php/2009/07/31/django-editor-in-vs-2010-part-1-colors/

回答1:

Essentially, you'll have to remember the state yourself. Most VS language services keep a state cookie for the beginning of each line that they update on text change.

At any point, getting classifications (through either a classifier aggregator or tag aggregator) will always result into a call into the current classifiers/taggers, so it won't be returning any type of cached state (or the "last" classifications returned). The editor doesn't really cache this information, and just acts as a dumb pass-through for the information your classifier provides to the visible lines being formatted.

Also, If you do it from a classifier (provided by either an IClassifierProvider or ITaggerProvider), you are setting yourself up for some nasty recursion, especially if your classifier responds to GetClassificationSpans by calling into the aggregator (which then calls back into your classifier for some earlier text, etc.). If your classifier needs to consume other classifications to work correctly (and not its own classifications), the only safe way to write that is to:

  1. Implement your "classifier" as an ITagger<IClassificationTag>, and provide it from an IViewTaggerProvider.
  2. Grab an ITagAggregator<IClassificationTag> from an IBufferTagAggregatorFactoryService, but only once.
  3. Implement IDisposable on your tagger and dispose the tag aggregator in Dispose().