-
Notifications
You must be signed in to change notification settings - Fork 747
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add VS2010 syntax colorizer to the source control
- Loading branch information
1 parent
c4a768f
commit bd3128d
Showing
8 changed files
with
543 additions
and
0 deletions.
There are no files selected for viewing
23 changes: 23 additions & 0 deletions
23
IdeIntegration/Vs2010Integration/GherkinFileClassificationDefinition.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System.ComponentModel.Composition; | ||
using Microsoft.VisualStudio.Text.Classification; | ||
using Microsoft.VisualStudio.Utilities; | ||
|
||
namespace GherkinFileClassifier | ||
{ | ||
internal static class GherkinFileClassificationDefinition | ||
{ | ||
[Export] | ||
[Name("gherkin")] | ||
[BaseDefinition("text")] | ||
internal static ContentTypeDefinition diffContentTypeDefinition = null; | ||
|
||
[Export] | ||
[FileExtension(".feature")] | ||
[ContentType("gherkin")] | ||
internal static FileExtensionToContentTypeDefinition patchFileExtensionDefinition = null; | ||
|
||
[Export(typeof(ClassificationTypeDefinition))] | ||
[Name("gherkin.tag")] | ||
internal static ClassificationTypeDefinition GherkinTagClassifierType = null; | ||
} | ||
} |
118 changes: 118 additions & 0 deletions
118
IdeIntegration/Vs2010Integration/GherkinFileClassifier.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Collections.Generic; | ||
using System.ComponentModel.Composition; | ||
using System.Windows.Media; | ||
using Microsoft.VisualStudio.Text; | ||
using Microsoft.VisualStudio.Text.Classification; | ||
using Microsoft.VisualStudio.Text.Tagging; | ||
using Microsoft.VisualStudio.Utilities; | ||
|
||
namespace GherkinFileClassifier | ||
{ | ||
|
||
#region Provider definition | ||
/// <summary> | ||
/// This class causes a classifier to be added to the set of classifiers. Since | ||
/// the content type is set to "text", this classifier applies to all text files | ||
/// </summary> | ||
[Export(typeof(IClassifierProvider))] | ||
[ContentType("gherkin")] | ||
internal class GherkinFileClassifierProvider : IClassifierProvider | ||
{ | ||
/// <summary> | ||
/// Import the classification registry to be used for getting a reference | ||
/// to the custom classification type later. | ||
/// </summary> | ||
[Import] | ||
internal IClassificationTypeRegistryService ClassificationRegistry = null; // Set via MEF | ||
|
||
[Import] | ||
internal IBufferTagAggregatorFactoryService BufferTagAggregatorFactoryService { get; set; } | ||
|
||
public IClassifier GetClassifier(ITextBuffer buffer) | ||
{ | ||
return buffer.Properties.GetOrCreateSingletonProperty(() => | ||
new GherkinFileClassifier(buffer, ClassificationRegistry, BufferTagAggregatorFactoryService)); | ||
} | ||
} | ||
#endregion //provider def | ||
|
||
#region Classifier | ||
/// <summary> | ||
/// Classifier that classifies all text as an instance of the OrinaryClassifierType | ||
/// </summary> | ||
class GherkinFileClassifier : IClassifier | ||
{ | ||
private readonly IClassificationTypeRegistryService classificationTypeRegistryService; | ||
|
||
internal IBufferTagAggregatorFactoryService BufferTagAggregatorFactoryService { get; private set; } | ||
|
||
internal GherkinFileClassifier(ITextBuffer buffer, IClassificationTypeRegistryService classificationTypeRegistryService, IBufferTagAggregatorFactoryService bufferTagAggregatorFactoryService) | ||
{ | ||
BufferTagAggregatorFactoryService = bufferTagAggregatorFactoryService; | ||
this.classificationTypeRegistryService = classificationTypeRegistryService; | ||
|
||
buffer.Changed += new EventHandler<TextContentChangedEventArgs>(buffer_Changed); | ||
} | ||
|
||
private IList<ClassificationSpan> lastClassification = null; | ||
|
||
void buffer_Changed(object sender, TextContentChangedEventArgs e) | ||
{ | ||
var chStart = e.Changes.Min(ch => ch.NewPosition); | ||
var chEnd = e.Changes.Max(ch => ch.NewPosition + ch.NewLength); | ||
var chSpan = new Span(chStart, chEnd); | ||
|
||
SnapshotSpan allText = new SnapshotSpan(e.After, 0, e.After.Length); | ||
var newClassification = SyntaxColorer.GetClassificationSpans(allText, classificationTypeRegistryService); | ||
|
||
bool fullRefresh = false; | ||
|
||
if (lastClassification != null) | ||
{ | ||
var overlappingClassifications = lastClassification.Where(cs => cs.Span.OverlapsWith(chSpan)).Select(cs => cs.ClassificationType); | ||
fullRefresh |= overlappingClassifications.Any(cl => cl.Classification.Equals("string", StringComparison.InvariantCultureIgnoreCase)); | ||
} | ||
if (!fullRefresh) | ||
{ | ||
var overlappingClassifications = newClassification.Where(cs => cs.Span.OverlapsWith(chSpan)).Select(cs => cs.ClassificationType); | ||
fullRefresh |= overlappingClassifications.Any(cl => cl.Classification.Equals("string", StringComparison.InvariantCultureIgnoreCase)); | ||
} | ||
|
||
lastClassification = newClassification; | ||
|
||
if (fullRefresh) | ||
{ | ||
if (ClassificationChanged != null) | ||
ClassificationChanged(this, new ClassificationChangedEventArgs( | ||
new SnapshotSpan(e.After, 0, e.After.Length))); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// This method scans the given SnapshotSpan for potential matches for this classification. | ||
/// In this instance, it classifies everything and returns each span as a new ClassificationSpan. | ||
/// </summary> | ||
/// <param name="span">The span currently being classified</param> | ||
/// <returns>A list of ClassificationSpans that represent spans identified to be of this classification</returns> | ||
public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span) | ||
{ | ||
if (lastClassification == null) | ||
{ | ||
SnapshotSpan allText = new SnapshotSpan(span.Snapshot, 0, span.Snapshot.Length); | ||
lastClassification = SyntaxColorer.GetClassificationSpans(allText, classificationTypeRegistryService); | ||
} | ||
|
||
return lastClassification; | ||
} | ||
|
||
#pragma warning disable 67 | ||
// This event gets raised if a non-text change would affect the classification in some way, | ||
// for example typing /* would cause the clssification to change in C# without directly | ||
// affecting the span. | ||
public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged; | ||
#pragma warning restore 67 | ||
} | ||
#endregion //Classifier | ||
} |
22 changes: 22 additions & 0 deletions
22
IdeIntegration/Vs2010Integration/GherkinFileClassifierFormat.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System.ComponentModel.Composition; | ||
using System.Windows.Media; | ||
using Microsoft.VisualStudio.Text.Classification; | ||
using Microsoft.VisualStudio.Utilities; | ||
|
||
namespace GherkinFileClassifier | ||
{ | ||
[Export(typeof(EditorFormatDefinition))] | ||
[ClassificationType(ClassificationTypeNames = "gherkin.tag")] | ||
[Name("gherkin.tag")] | ||
[UserVisible(true)] //this should be visible to the end user | ||
[Order(Before = Priority.Default)] //set the priority to be after the default classifiers | ||
internal sealed class GherkinFileClassifierFormat : ClassificationFormatDefinition | ||
{ | ||
public GherkinFileClassifierFormat() | ||
{ | ||
this.DisplayName = "Gherkin Tag"; //human readable version of the name | ||
this.ForegroundColor = Colors.Gray; | ||
this.IsItalic = true; | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
IdeIntegration/Vs2010Integration/Properties/AssemblyInfo.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System.Reflection; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
// General Information about an assembly is controlled through the following | ||
// set of attributes. Change these attribute values to modify the information | ||
// associated with an assembly. | ||
[assembly: AssemblyTitle("GherkinFileClassifier")] | ||
[assembly: AssemblyDescription("")] | ||
[assembly: AssemblyConfiguration("")] | ||
[assembly: AssemblyCompany("")] | ||
[assembly: AssemblyProduct("GherkinFileClassifier")] | ||
[assembly: AssemblyCopyright("")] | ||
[assembly: AssemblyTrademark("")] | ||
[assembly: AssemblyCulture("")] | ||
|
||
// Setting ComVisible to false makes the types in this assembly not visible | ||
// to COM components. If you need to access a type in this assembly from | ||
// COM, set the ComVisible attribute to true on that type. | ||
[assembly: ComVisible(false)] | ||
|
||
// Version information for an assembly consists of the following four values: | ||
// | ||
// Major Version | ||
// Minor Version | ||
// Build Number | ||
// Revision | ||
// | ||
// You can specify all the values or you can default the Build and Revision Numbers | ||
// by using the '*' as shown below: | ||
// [assembly: AssemblyVersion("1.0.*")] | ||
[assembly: AssemblyVersion("1.0.0.0")] | ||
[assembly: AssemblyFileVersion("1.0.0.0")] |
198 changes: 198 additions & 0 deletions
198
IdeIntegration/Vs2010Integration/SyntaxColoringListener.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.Serialization; | ||
using System.Text; | ||
using java.util; | ||
using gherkin; | ||
using Microsoft.VisualStudio.Text; | ||
using Microsoft.VisualStudio.Text.Classification; | ||
|
||
namespace GherkinFileClassifier | ||
{ | ||
public class ListeningDoneException : Exception | ||
{ | ||
} | ||
|
||
public class SyntaxColorer | ||
{ | ||
public static IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan snapshotSpan, IClassificationTypeRegistryService registry) | ||
{ | ||
// string fileContent = snapshotSpan.Snapshot.GetText(0, snapshotSpan.End.Position); | ||
string fileContent = snapshotSpan.Snapshot.GetText(); | ||
var gherkinListener = new SyntaxColoringListener(snapshotSpan, registry); | ||
|
||
I18n languageService = new I18n("en"); | ||
|
||
try | ||
{ | ||
Lexer lexer = languageService.lexer(gherkinListener); | ||
lexer.scan(fileContent, null, 0); | ||
return gherkinListener.Classifications; | ||
} | ||
catch (Exception ex) | ||
{ | ||
/* | ||
var errorClassificationType = registry.GetClassificationType("error"); | ||
int startIndex = 0; | ||
if (gherkinListener.Classifications.Any()) | ||
{ | ||
var last = gherkinListener.Classifications.Last(); | ||
startIndex = last.Span.Start + last.Span.Length; | ||
} | ||
gherkinListener.Classifications.Add(new ClassificationSpan( | ||
new SnapshotSpan(snapshotSpan.Snapshot, startIndex, snapshotSpan.Snapshot.Length - startIndex), | ||
errorClassificationType)); | ||
*/ | ||
|
||
return gherkinListener.Classifications; | ||
} | ||
|
||
} | ||
} | ||
|
||
public class SyntaxColoringListener : Listener | ||
{ | ||
public SnapshotSpan SnapshotSpan { get; set; } | ||
public List<ClassificationSpan> Classifications { get; private set; } | ||
private int startLine; | ||
private int endLine; | ||
|
||
private readonly IClassificationType keywordClassificationType; | ||
private readonly IClassificationType commentClassificationType; | ||
private readonly IClassificationType tagClassificationType; | ||
private readonly IClassificationType multilineTextClassificationType; | ||
|
||
public SyntaxColoringListener(SnapshotSpan snapshotSpan, IClassificationTypeRegistryService registry) | ||
{ | ||
SnapshotSpan = snapshotSpan; | ||
startLine = SnapshotSpan.Start.GetContainingLine().LineNumber; | ||
endLine = SnapshotSpan.End.GetContainingLine().LineNumber; | ||
|
||
Classifications = new List<ClassificationSpan>(); | ||
|
||
keywordClassificationType = registry.GetClassificationType("keyword"); | ||
commentClassificationType = registry.GetClassificationType("comment"); | ||
tagClassificationType = registry.GetClassificationType("gherkin.tag"); | ||
multilineTextClassificationType = registry.GetClassificationType("string"); | ||
} | ||
|
||
private int? GetEditorLine(int line) | ||
{ | ||
var editorLine = line - 1; | ||
// if (editorLine > endLine) | ||
// throw new ListeningDoneException(); | ||
// if (editorLine < startLine) | ||
// return null; | ||
return editorLine; | ||
} | ||
|
||
private void AddClassification(IClassificationType classificationType, int startIndex, int length) | ||
{ | ||
Classifications.Add( | ||
new ClassificationSpan( | ||
new SnapshotSpan(SnapshotSpan.Snapshot, new Span(startIndex, length)), | ||
classificationType)); | ||
} | ||
|
||
private void ColorizeLine(int line, IClassificationType classificationType) | ||
{ | ||
var editorLine = GetEditorLine(line); | ||
if (editorLine == null) | ||
return; | ||
|
||
var snapshotLine = SnapshotSpan.Snapshot.GetLineFromLineNumber(editorLine.Value); | ||
AddClassification(classificationType, snapshotLine.Start, snapshotLine.LengthIncludingLineBreak); | ||
} | ||
|
||
private void ColorizeLinePart(string lineTextPart, int line, IClassificationType classificationType) | ||
{ | ||
var editorLine = GetEditorLine(line); | ||
if (editorLine == null) | ||
return; | ||
|
||
var snapshotLine = SnapshotSpan.Snapshot.GetLineFromLineNumber(editorLine.Value); | ||
|
||
int startIndex = snapshotLine.GetText().IndexOf(lineTextPart); | ||
if (startIndex < 0) | ||
return; | ||
|
||
AddClassification(classificationType, snapshotLine.Start + startIndex, lineTextPart.Length); | ||
} | ||
|
||
public void location(string str, int line) | ||
{ | ||
|
||
} | ||
|
||
public void pyString(string text, int line) | ||
{ | ||
int lineCount = text.Count(c => c.Equals('\n')) + 1 + 2; | ||
for (int currentLine = line; currentLine < line + lineCount; currentLine++) | ||
{ | ||
ColorizeLine(currentLine, multilineTextClassificationType); | ||
} | ||
} | ||
|
||
public void feature(string keyword, string str2, string str3, int line) | ||
{ | ||
RegisterKeyword(keyword, line); | ||
} | ||
|
||
public void background(string keyword, string str2, string str3, int line) | ||
{ | ||
RegisterKeyword(keyword, line); | ||
} | ||
|
||
public void scenario(string keyword, string str2, string str3, int line) | ||
{ | ||
RegisterKeyword(keyword, line); | ||
} | ||
|
||
public void scenarioOutline(string keyword, string str2, string str3, int line) | ||
{ | ||
RegisterKeyword(keyword, line); | ||
} | ||
|
||
public void examples(string keyword, string str2, string str3, int line) | ||
{ | ||
RegisterKeyword(keyword, line); | ||
} | ||
|
||
public void step(string keyword, string text, int line) | ||
{ | ||
RegisterKeyword(keyword, line); | ||
} | ||
|
||
private void RegisterKeyword(string keyword, int line) | ||
{ | ||
ColorizeLinePart(keyword, line, keywordClassificationType); | ||
} | ||
|
||
public void comment(string commentText, int line) | ||
{ | ||
ColorizeLine(line, commentClassificationType); | ||
} | ||
|
||
public void tag(string tagName, int line) | ||
{ | ||
ColorizeLinePart(tagName, line, tagClassificationType); | ||
} | ||
|
||
public void eof() | ||
{ | ||
|
||
} | ||
|
||
public void syntaxError(string str1, string str2, List l, int line) | ||
{ | ||
|
||
} | ||
|
||
public void row(List l, int line) | ||
{ | ||
|
||
} | ||
} | ||
} |
Oops, something went wrong.