I try to create a syntax highlight for my language in Visual Studio 2015. I created a VSIX Project under C# -> Extensibility. Inside the .vsixmanifest file under the Assets section I added MefComponent which points to my current project.
I have already defined the language grammar using Irony, and I have defined a classifier. But, unfortunately I don't get syntax highlight. I assume my token tagger is not working properly.
I found some examples online like for Ook
language or other simple languages, but they don't use Irony. Is there any sample where I can find a complete language implementation in Visual Studio where the grammar is defined with Irony? And please
I need something new, not from ancient times.
If someone can check the below code and reply what the problem is, I would be glad.
Here you can find my classification type:
internal static class OrdinaryClassificationDefinition
{
[Export(typeof(ClassificationTypeDefinition))]
[Name("keyword")]
internal static ClassificationTypeDefinition toyKeyWord = null;
}
And here is my classifier:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Language.StandardClassification;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Utilities;
using Irony.Parsing;
using toyVS.Grammar;
namespace toyVS.Classification{[Export(typeof(ITaggerProvider))][ContentType("toy")][TagType(typeof(ClassificationTag))]internalsealedclass toyClassifierProvider :ITaggerProvider{[Export][Name("toy")][BaseDefinition("code")]internalstaticContentTypeDefinition toyContentType =null;[Export][FileExtension(".toy")][ContentType("toy")]internalstaticFileExtensionToContentTypeDefinition toyFileType =null;[Import]internalIClassificationTypeRegistryServiceClassificationTypeRegistry=null;[Import]internalIBufferTagAggregatorFactoryService aggregatorFactory =null;publicITagger<T>CreateTagger<T>(ITextBuffer buffer)where T :ITag{returnnew toyClassifier(buffer,ClassificationTypeRegistry)asITagger<T>;}}internalsealedclass toyClassifier :ITagger<ClassificationTag>{ITextBuffer _buffer;
toyGrammar _grammar;Parser _parser;IDictionary<TokenType,ClassificationTag> _toyTags;ClassificationTag _commentTag;publiceventEventHandler<SnapshotSpanEventArgs>TagsChanged;Dictionary<int,int> _lineStates =newDictionary<int,int>();internal toyClassifier(ITextBuffer buffer,IClassificationTypeRegistryService typeService){
_buffer = buffer;
_grammar = toyGrammar.Instance;
_parser =newParser(_grammar);
_parser.Context.Mode=ParseMode.VsLineScan;
_toyTags =newDictionary<TokenType,ClassificationTag>();
_toyTags[TokenType.Text]=BuildTag(typeService,PredefinedClassificationTypeNames.Character);
_toyTags[TokenType.Keyword]=BuildTag(typeService,PredefinedClassificationTypeNames.Keyword);
_toyTags[TokenType.Identifier]=BuildTag(typeService,PredefinedClassificationTypeNames.Identifier);
_toyTags[TokenType.String]=BuildTag(typeService,PredefinedClassificationTypeNames.String);
_toyTags[TokenType.Literal]=BuildTag(typeService,PredefinedClassificationTypeNames.Literal);
_toyTags[TokenType.Operator]=BuildTag(typeService,PredefinedClassificationTypeNames.Operator);
_toyTags[TokenType.LineComment]=BuildTag(typeService,PredefinedClassificationTypeNames.Comment);
_toyTags[TokenType.Comment]=BuildTag(typeService,PredefinedClassificationTypeNames.Comment);
_commentTag =BuildTag(typeService,PredefinedClassificationTypeNames.Comment);InitializeLineStates(_buffer.CurrentSnapshot);}publicIEnumerable<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==TokenCategory.Content){if(token.EditorInfo!=null){ClassificationTag tag;if(_toyTags.TryGetValue(token.EditorInfo.Type,out tag)){var location =newSnapshotSpan(snapshot, line.Start.Position+ token.Location.Position, token.Length);
yield returnnewTagSpan<ClassificationTag>(location, tag);}}}elseif(token.Category==TokenCategory.Comment){var location =newSnapshotSpan(snapshot, line.Start.Position+ token.Location.Position, token.Length);
yield returnnewTagSpan<ClassificationTag>(location, _commentTag);}
token = _parser.Scanner.VsReadToken(ref state);}int oldState =0;
_lineStates.TryGetValue(i +1,out oldState);
_lineStates[i +1]= state;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 =newSnapshotSpan(snapshot, endLine.End.Position, length);this.TagsChanged(this,newSnapshotSpanEventArgs(snapShotSpan));}}}}}privateClassificationTagBuildTag(IClassificationTypeRegistryService typeService,string type){returnnewClassificationTag(typeService.GetClassificationType(type));}privatevoidInitializeLineStates(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;}}}}