2012-03-11 15 views
1

私のITaggerはタグを生成していますが、visual studioは構文の色付けを表示していません。Visual Studio MEF&Irony:構文なしhiglighting

[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; 
      } 
     } 
    } 

文法:ここ はITaggerのコードです

[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 commentSyntax highlight in Visual Studio 2015 using Irony grammar?

P.S.を見ますMSDN Forums: Visual Studio Extensibility

+0

私が言及している記事では、元のManagedMyCの例(Babelのものに基づいています)を使用し、Babelの代わりにIronyを使用するように変更しました。 –

+0

ドミトリーの説明に感謝します。 +1 – MickyD

関連する問題