c# - VSIX IClassifier assigning multiple ClassificationTypes -


using standard template managed make custom highlighter turns occurrences of string "archive?????key" (where ???? collection of characters allowed in variable names) pink. "archive" , "key" portions become pink , "????" portion become maroon. far understand vsix highlighters (and don't) means defining 2 classificationformatdefinitions, every time try break project.

my getclassificationspans method (which significant deviation standard template) looks like:

public ilist<classificationspan> getclassificationspans(snapshotspan span) {   list<classificationspan> spans = new list<classificationspan>();    string text = span.gettext();   int idx0 = 0;   int idx1;    while (true)   {     idx0 = text.indexof(keyprefix, idx0);     if (idx0 < 0)       break;      idx1 = text.indexof(keysuffix, idx0 + 6);     if (idx1 < 0)       break;      // todo: make sure prefix , suffix part of same object identifier.     string name = text.substring(idx0 + lengthprefix, idx1 - idx0 - lengthprefix);     string full = text.substring(idx0, idx1 - idx0 + keysuffix.length);      snapshotspan span0 = new snapshotspan(span.start + idx0, idx1 - idx0 + lengthsuffix);     snapshotspan span1 = new snapshotspan(span.start + idx0 + lengthprefix, idx1 - idx0 - lengthprefix);     snapshotspan span2 = new snapshotspan(span.start + idx1, lengthsuffix);      spans.add(new classificationspan(span0, classificationtype));     spans.add(new classificationspan(span1, classificationtype)); // i'd assign different iclassificationtype span.     spans.add(new classificationspan(span2, classificationtype));     idx0 = idx1 + 5;   }   return spans; } 

and span1 want assign different style. not understand how classifier, format, provider, , definition classes needed 1 (!) thing relate each other , ones can made aware of multiple styles.

the templates ok getting started, it's simpler reimplement more directly once know direction you're going in.

here's how pieces fit together:

  • a classifier (really, iclassificationtag tagger) yields classification tag-spans given section of text buffer on demand.
  • classification tag-spans consist of span in buffer tag applies to, , classification tag itself. classification tag specifies classification type apply.
  • classification types used relate tags of classification given format.
  • formats (specifically, classificationformatdefinitions) exported via mef (as editorformatdefinitions) vs can discover them , use them colour spans have associated classification type. (optionally) appear in fonts & colors options.
  • a classifier provider exported via mef in order vs discover it; gives vs means of instantiating classifier each open buffer (and discovering tags in it).

so, you're after code defines , exports 2 classification format definitions associated 2 classification types, respectively. classifier needs produce tags of both types accordingly. here's example (untested):

public static class classifications {     // these strings used form classification types     // , bind types formats     public const string archivekey    = "myproject/archivekey";     public const string archivekeyvar = "myproject/archivekeyvar";      // these mef exports define types     [export]     [name(archivekey)]     private static classificationtypedefinition archivekeytype = null;      [export]     [name(archivekeyvar)]     private static classificationtypedefinition archivekeyvartype = null;      // these format definitions specify how things     [export(typeof(editorformatdefinition))]     [classificationtype(classificationtypenames = archivekey)]     [uservisible(true)]  // controls whether appears in fonts & colors options user configuration     [name(archivekey)]   // reuse classification type name     [order(after = priority.default, before = priority.high)] // optionally include attribute if classification should                                                               // take precedence on of builtin ones keywords     public sealed class archivekeyformatdefinition : classificationformatdefinition     {         public archivekeyformatdefinition()         {             foregroundcolor = color.fromrgb(0xff, 0x69, 0xb4);  // pink!             displayname = "this display in fonts & colors";         }     }      [export(typeof(editorformatdefinition))]     [classificationtype(classificationtypenames = archivekeyvar)]     [uservisible(true)]     [name(archivekeyvar)]     [order(after = priority.default, before = priority.high)]     public sealed class archivekeyvarformatdefinition : classificationformatdefinition     {         public archivekeyvarformatdefinition()         {             foregroundcolor = color.fromrgb(0xb0, 0x30, 0x60);  // maroon             displayname = "this display in fonts & colors";         }     } } 

the provider:

[export(typeof(itaggerprovider))] [contenttype("text")]    // or whatever content type tagger applies [tagtype(typeof(classificationtag))] public class archivekeyclassifierprovider : itaggerprovider {     [import]     public iclassificationtyperegistryservice classificationtyperegistry { get; set; }      public itagger<t> createtagger<t>(itextbuffer buffer) t : itag     {         return buffer.properties.getorcreatesingletonproperty(() =>             new archivekeyclassifier(buffer, classificationtyperegistry)) itagger<t>;     } } 

finally, tagger itself:

public class archivekeyclassifier : itagger<classificationtag> {     public event eventhandler<snapshotspaneventargs> tagschanged;      private dictionary<string, classificationtag> _tags;      public archivekeyclassifier(itextbuffer subjectbuffer, iclassificationtyperegistryservice classificationregistry)     {         // build tags correspond each of possible classifications         _tags = new dictionary<string, classificationtag> {             { classifications.archivekey,    buildtag(classificationregistry, classifications.archivekey) },             { classifications.archivekeyvar, buildtag(classificationregistry, classifications.archivekeyvar) }         };     }      public ienumerable<itagspan<classificationtag>> gettags(normalizedsnapshotspancollection spans)     {         if (spans.count == 0)             yield break;          foreach (var span in spans) {             if (span.isempty)                 continue;              foreach (var identspan in lexidentifiers(span)) {                 var ident = identspan.gettext();                 if (!ident.startswith("archive") || !ident.endswith("key"))                     continue;                  var varspan = new snapshotspan(                     identspan.start + "archive".length,                     identspan.end - "key".length);                  yield return new tagspan<classificationtag>(new snapshotspan(identspan.start, varspan.start), _tags[classifications.archivekey]);                 yield return new tagspan<classificationtag>(varspan, _tags[classifications.archivekeyvar]);                 yield return new tagspan<classificationtag>(new snapshotspan(varspan.end, identspan.end), _tags[classifications.archivekey]);             }         }     }      private static ienumerable<snapshotspan> lexidentifiers(snapshotspan span)     {         // tokenize string identifiers , numbers, returning identifiers         var s = span.gettext();         (int = 0; < s.length; ) {             if (char.isletter(s[i])) {                 var start = i;                 (++i; < s.length && istokenchar(s[i]); ++i);                 yield return new snapshotspan(span.start + start, - start);                 continue;             }             if (char.isdigit(s[i])) {                 (++i; < s.length && istokenchar(s[i]); ++i);                 continue;             }             ++i;         }     }      private static bool istokenchar(char c)     {         return char.isletterordigit(c) || c == '_';     }      private static classificationtag buildtag(iclassificationtyperegistryservice classificationregistry, string typename)     {         return new classificationtag(classificationregistry.getclassificationtype(typename));     } } 

one more note: in order accelerate startup, vs keeps cache of mef exports. however, cache not invalidated when should be. additionally, if change default colour of existing classification format definition, there's chance change won't picked because vs saves previous values in registry. mitigate this, it's best run batch script in between compiles when mef- or format-related changes clear things. here's example vs2013 , exp root suffix (used default when testing vsixes):

@echo off  del "%localappdata%\microsoft\visualstudio\12.0exp\componentmodelcache\microsoft.visualstudio.default.cache" 2> nul rmdir /s /q "%localappdata%\microsoft\visualstudio\12.0exp\componentmodelcache" 2> nul  reg delete hkcu\software\microsoft\visualstudio\12.0exp\fontandcolors\cache\{75a05685-00a8-4ded-bae5-e7a50bfa929a} /f  

Popular posts from this blog

php - How should I create my API for mobile applications (Needs Authentication) -

python 3.x - PyQt5 - Signal : pyqtSignal no method connect -

5 Reasons to Blog Anonymously (and 5 Reasons Not To)