An interpreter for grammar files as defined by TextMate. TextMate grammars use the oniguruma dialect (https://github.com/kkos/oniguruma). Supports loading grammar files only from JSON format. Cross-grammar injections are currently not supported.
TextMateSharp is a port of microsoft/vscode-textmate that brings TextMate grammars to the .NET ecosystem. The implementation is based on the Java port eclipse/tm4e.
TextMateSharp uses a wrapper via NuGet packages around the Oniguruma regex engine. Thanks @aikawayataro for your contribution.
TextMateSharp is used by AvaloniaEdit.
TextMateSharp is available as NuGet packages:
- TextMateSharp - Core library
- TextMateSharp.Grammars - Bundled grammars and themes
dotnet add package TextMateSharp
dotnet add package TextMateSharp.GrammarsTextMateSharp.Grammars includes syntax highlighting for 50+ languages including:
C#, C/C++, Java, JavaScript, TypeScript, Python, Ruby, Rust, Go, Swift, Dart, PHP, SQL, HTML, CSS, SCSS, Less, JSON, XML, YAML, Markdown, LaTeX, Lua, PowerShell, Bash, F#, VB.NET, and many more.
The following themes are included:
Abyss, Dark, Dark+, Dimmed Monokai, Kimbie Dark, Light, Light+, One Dark, Monokai, Quiet Light, Red, Solarized Dark, Solarized Light, Tomorrow Night Blue, High Contrast Light, High Contrast Dark, Dracula, Atom One Light, Atom One Dark, Visual Studio Light, Visual Studio Dark.
Execute dotnet build under the TextMateSharp folder:
cd src/TextMateSharp
dotnet buildusing System;
using System.Collections.Generic;
using TextMateSharp.Grammars;
using TextMateSharp.Themes;
namespace TextMateSharp;
class Program
{
static void Main(string[] args)
{
try
{
Registry.Registry registry = new Registry.Registry(
new RegistryOptions(ThemeName.DarkPlus));
List<string> textLines = new List<string>();
textLines.Add("using static System; /* comment here */");
textLines.Add("namespace Example");
textLines.Add("{");
textLines.Add("}");
IGrammar grammar = registry.LoadGrammar("source.cs");
IStateStack? ruleStack = null;
foreach (var line in textLines)
{
Console.WriteLine($"Tokenizing line: {line}");
ITokenizeLineResult result = grammar.TokenizeLine(line, ruleStack, TimeSpan.MaxValue);
ruleStack = result.RuleStack;
foreach (var token in result.Tokens)
{
int startIndex = (token.StartIndex > line.Length) ? line.Length : token.StartIndex;
int endIndex = (token.EndIndex > line.Length) ? line.Length : token.EndIndex;
Console.WriteLine(
" - token from {0} to {1} -->{2}<-- with scopes {3}",
startIndex,
endIndex,
line.Substring(startIndex, endIndex - startIndex),
string.Join(",", token.Scopes));
Theme theme = registry.GetTheme();
foreach (var themeRule in theme.Match(token.Scopes))
{
Console.WriteLine(
" - Matched theme rule: " +
"[bg: {0}, fg:{1}, fontStyle: {2}]",
theme.GetColor(themeRule.background),
theme.GetColor(themeRule.foreground),
themeRule.fontStyle);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("ERROR: " + ex.Message);
}
}
}Output:
Tokenizing line: using static System; /* comment here */
- token from 0 to 5 -->using<-- with scopes source.cs,keyword.other.directive.using.cs
- Matched theme rule: [bg: , fg:#569CD6, fontStyle: NotSet]
- token from 5 to 6 --> <-- with scopes source.cs
- token from 6 to 12 -->static<-- with scopes source.cs,keyword.other.directive.static.cs
- Matched theme rule: [bg: , fg:#569CD6, fontStyle: NotSet]
- token from 12 to 13 --> <-- with scopes source.cs
- token from 13 to 19 -->System<-- with scopes source.cs,entity.name.type.cs
- Matched theme rule: [bg: , fg:#4EC9B0, fontStyle: NotSet]
- token from 19 to 20 -->;<-- with scopes source.cs,punctuation.terminator.statement.cs
- token from 20 to 21 --> <-- with scopes source.cs
- token from 21 to 23 -->/*<-- with scopes source.cs,comment.block.cs,punctuation.definition.comment.cs
- Matched theme rule: [bg: , fg:#6A9955, fontStyle: NotSet]
- token from 23 to 37 --> comment here <-- with scopes source.cs,comment.block.cs
- Matched theme rule: [bg: , fg:#6A9955, fontStyle: NotSet]
- token from 37 to 39 -->*/<-- with scopes source.cs,comment.block.cs,punctuation.definition.comment.cs
- Matched theme rule: [bg: , fg:#6A9955, fontStyle: NotSet]
Tokenizing line: namespace Example
- token from 0 to 9 -->namespace<-- with scopes source.cs,storage.type.namespace.cs
- Matched theme rule: [bg: , fg:#569CD6, fontStyle: NotSet]
- token from 9 to 10 --> <-- with scopes source.cs
- token from 10 to 17 -->Example<-- with scopes source.cs,entity.name.type.namespace.cs
- Matched theme rule: [bg: , fg:#4EC9B0, fontStyle: NotSet]
Tokenizing line: {
- token from 0 to 1 -->{<-- with scopes source.cs,punctuation.curlybrace.open.cs
Tokenizing line: }
- token from 0 to 1 -->}<-- with scopes source.cs,punctuation.curlybrace.close.cs
There is a demo project in the TextMateSharp.Demo folder.
Build and run:
cd src/TextMateSharp.Demo
dotnet build
dotnet run -- ./testdata/samplefiles/sample.csTextMateSharp is licensed under the MIT License.
