1

ITagger<IClassificationTag>正在生成标签,但是,Visual Studio 没有显示语法着色。这是代码ITagger<IClassificationTag>

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

1 回答 1

2

您是否有机会阅读 Ben Morrison 的文章 -编写您的第一个 Visual Studio 语言服务,他解释了如何使用 Irony 进行 VS 语言服务(语法高亮是其中的一部分)?

更新:对于 Irony,请参阅对 Visual Studio 2015 中使用 Irony 语法的类似线程语法高亮的评论?

PS 您还可以在这里找到一些有价值的信息 - MSDN 论坛:Visual Studio 可扩展性

于 2012-03-14T07:19:13.770 回答