2012-03-11 56 views
1

我的ITagger正在生成標籤,但是,visual studio沒有顯示語法着色。 這裏是ITagger代碼:Visual Studio MEF&Irony:無語法高亮

[Export(typeof(ITaggerProvider))] 
    [ContentType("FDL")] 
    [TagType(typeof(ClassificationTag))] 
    internal sealed class FDLClassifierProvider : ITaggerProvider 
    { 

     [Export] 
     [Name("FDL")] 
     [BaseDefinition("code")] 
     internal static ContentTypeDefinition FDLContentType = null; 

     [Export] 
     [FileExtension(".fdl")] 
     [ContentType("FDL")] 
     internal static FileExtensionToContentTypeDefinition FDLFileType = null; 

     [Import] 
     internal IClassificationTypeRegistryService ClassificationTypeRegistry = null; 

     [Import] 
     internal IBufferTagAggregatorFactoryService aggregatorFactory = null; 

     public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag 
     { 
      return new FDLClassifier(buffer, ClassificationTypeRegistry) as ITagger<T>; 
     } 
    } 

    /// <summary> 
    /// This is effectively the replacement to the LineScanner from 2008. 
    /// This class must handle very quick processing times during GetTags() 
    /// as it is called very frequently! 
    /// </summary> 
    internal sealed class FDLClassifier : ITagger<ClassificationTag> 
    { 
     ITextBuffer _buffer; 
     Grammar _grammar; 
     Irony.Parsing.Parser _parser; 

     IDictionary<Irony.Parsing.TokenType, ClassificationTag> _fdlTags; 
     ClassificationTag _commentTag; 


     public event EventHandler<SnapshotSpanEventArgs> TagsChanged; 

     Dictionary<int, int> _lineStates = new Dictionary<int, int>(); 

     internal FDLClassifier(ITextBuffer buffer, 
           IClassificationTypeRegistryService typeService) 
     { 
      _buffer = buffer; 

      _grammar = new Grammar(); 
      _parser = new Irony.Parsing.Parser(_grammar); 
      _parser.Context.Mode = Irony.Parsing.ParseMode.VsLineScan; 

      _fdlTags = new Dictionary<Irony.Parsing.TokenType, ClassificationTag>(); 
      _fdlTags[Irony.Parsing.TokenType.Text] = BuildTag(typeService, PredefinedClassificationTypeNames.Character); 
      _fdlTags[Irony.Parsing.TokenType.Keyword] = BuildTag(typeService, PredefinedClassificationTypeNames.Keyword); 
      _fdlTags[Irony.Parsing.TokenType.Identifier] = BuildTag(typeService, PredefinedClassificationTypeNames.Identifier); 
      _fdlTags[Irony.Parsing.TokenType.String] = BuildTag(typeService, PredefinedClassificationTypeNames.String); 
      _fdlTags[Irony.Parsing.TokenType.Literal] = BuildTag(typeService, PredefinedClassificationTypeNames.Literal); 
      _fdlTags[Irony.Parsing.TokenType.Operator] = BuildTag(typeService, PredefinedClassificationTypeNames.Operator); 
      _fdlTags[Irony.Parsing.TokenType.LineComment] = BuildTag(typeService, PredefinedClassificationTypeNames.Comment); 
      _fdlTags[Irony.Parsing.TokenType.Comment] = BuildTag(typeService, PredefinedClassificationTypeNames.Comment); 

      _commentTag = BuildTag(typeService, PredefinedClassificationTypeNames.Comment); 

      InitializeLineStates(_buffer.CurrentSnapshot); 
     } 

     /// <summary> 
     /// In the context of a classification tagger, this is called initially w/ spans for all 
     /// content in the file. 
     /// It is called immediately after the user modifies text given the span of text that was modified. 
     /// It is also called for all lines that are newly visible due to scrolling. 
     /// This function gets called ALOT. Keep processing times to a minimal and try to only handle 1 line at a 
     /// time. 
     /// </summary> 
     /// <param name="spans"></param> 
     /// <returns></returns> 
     public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans) 
     { 
      if (spans.Count == 0) 
       yield break; 

      var snapShot = spans[0].Snapshot; 
      foreach (var span in spans) 
      { 
       var startLine = span.Start.GetContainingLine(); 
       var endLine = span.End.GetContainingLine(); 

       var startLineNumber = startLine.LineNumber; 
       var endLineNumber = endLine.LineNumber; 

       for (int i = startLineNumber; i <= endLineNumber; i++) 
       { 
        var line = spans[0].Snapshot.GetLineFromLineNumber(i); 
        _parser.Scanner.VsSetSource(line.GetText(), 0); 

        int state = 0; 
        _lineStates.TryGetValue(i, out state); 

        var token = _parser.Scanner.VsReadToken(ref state); 
        while (token != null) 
        { 
         if (token.Category == Irony.Parsing.TokenCategory.Content) 
         { 
          if (token.EditorInfo != null) 
          { 
           ClassificationTag tag; 
           if (_fdlTags.TryGetValue(token.EditorInfo.Type, out tag)) 
           { 
            var location = new SnapshotSpan(snapShot, line.Start.Position + token.Location.Position, token.Length); 
            yield return new TagSpan<ClassificationTag>(location, tag); 

           } 
          } 
         } 
         else if (token.Category == Irony.Parsing.TokenCategory.Comment) 
         { 

          var location = new SnapshotSpan(snapShot, line.Start.Position + token.Location.Position, token.Length); 
          yield return new TagSpan<ClassificationTag>(location, _commentTag); 
         } 

         token = _parser.Scanner.VsReadToken(ref state); 
        } 

        int oldState = 0; 
        _lineStates.TryGetValue(i + 1, out oldState); 
        _lineStates[i + 1] = state; 

        //We're going into overtime, process new tags and send the event that these spans need updating! 
        if (oldState != state) 
        { 
         var lineNumber = endLineNumber; 
         while (oldState != state && lineNumber < snapShot.LineCount) 
         { 
          lineNumber++; 
          var dummyToken = _parser.Scanner.VsReadToken(ref state); 
          while (dummyToken != null) 
          { 
           dummyToken = _parser.Scanner.VsReadToken(ref state); 
          } 

          _lineStates.TryGetValue(lineNumber + 1, out oldState); 
          _lineStates[lineNumber + 1] = state; 
         } 

         if (lineNumber >= snapShot.LineCount) 
          lineNumber = snapShot.LineCount - 1; 

         var lastLine = snapShot.GetLineFromLineNumber(lineNumber); 
         if (lastLine != null && this.TagsChanged != null) 
         { 
          int length = lastLine.End.Position - endLine.End.Position; 
          var snapShotSpan = new SnapshotSpan(snapShot, endLine.End.Position, length); 
          this.TagsChanged(this, new SnapshotSpanEventArgs(snapShotSpan)); 
         } 
        } 
       } 
      } 
     } 

     private ClassificationTag BuildTag(IClassificationTypeRegistryService typeService, string type) 
     { 
      var classificationType = typeService.GetClassificationType(type); 
      return new ClassificationTag(classificationType); 
     } 

     /// <summary> 
     /// Initializes the line states based on the snapshot. 
     /// </summary> 
     private void InitializeLineStates(ITextSnapshot snapShot) 
     { 
      _lineStates[0] = 0; 
      foreach (var line in snapShot.Lines) 
      { 
       int state = 0; 
       _parser.Scanner.VsSetSource(line.GetText(), 0); 

       var dummyToken = _parser.Scanner.VsReadToken(ref state); 
       while (dummyToken != null) 
       { 
        dummyToken = _parser.Scanner.VsReadToken(ref state); 
       } 

       _lineStates[line.LineNumber + 1] = state; 
      } 
     } 
    } 

語法:

[Language("FDL", "6.0", "Feature Description Language")] 
    public class Grammar: Irony.Parsing.Grammar 
    { 
     public Grammar():base(true) 
     { 
      #region NonTerminals 

      var blockComment = new CommentTerminal("block-comment", "/*", "*/"); 
      var lineComment = new CommentTerminal("line-comment", "//", "\r", "\n", "\u2085", "\u2028", "\u2029"); 
      NonGrammarTerminals.Add(blockComment); 
      NonGrammarTerminals.Add(lineComment); 
      var identifier = new IdentifierTerminal("identifier"); 
      var stringLit = new StringLiteral("string"); 

      #endregion 
      #region Symbols 
      MarkPunctuation(";", ",", ":"); 
      RegisterBracePair("{", "}"); 
      RegisterBracePair("<", ">"); 
      RegisterBracePair("[", "]"); 
      RegisterBracePair("(", ")"); 
      #endregion 
      #region Keywords 
      var action = Keyword("action"); 
      var actionBoxFont = Keyword("actionBoxFont"); 
      var actionBoxFontSize = Keyword("actionBoxFontSize"); 
      var allocate = Keyword("allocate"); 
      // rest of grammar omitted for brevity. 
      #endregion 
     } 
     KeyTerm Keyword(string keyword) 
     { 
      var term = ToTerm(keyword); 
      MarkReservedWords(keyword); 
      term.EditorInfo = new TokenEditorInfo(TokenType.Keyword, TokenColor.Keyword, TokenTriggers.None); 
      return term; 
     } 
    } 

回答

2

你有機會來看看本·莫里森的文章 - Writing Your First Visual Studio Language Service,他解釋瞭如何使用反諷的VS語言服務(語法高亮是它的一部分)?

更新:諷刺看my comment類似線程Syntax highlight in Visual Studio 2015 using Irony grammar?

附:你也可以在這裏找到一些有價值的信息 - MSDN Forums: Visual Studio Extensibility

+0

我指的文章說他們使用原始的ManagedMyC示例(基於Babel的東西),並將其改爲使用Irony而不是Babel。 – 2015-09-06 18:30:50

+0

Ooops感謝德米特里的澄清。 +1 – MickyD 2015-09-07 00:25:31