Replies: 3 comments
|
This is super cool |
0 replies
|
Yes, and it works quite well. It's integrated into AvaloniaEdit, and we are actively using Plastic SCM. |
0 replies
|
I ended up creating the following using Spectre.Console;
using Spectre.Console.Rendering;
using TextMateSharp.Grammars;
using TextMateSharp.Registry;
using TextMateSharp.Themes;
public sealed class SourceCodeText : JustInTimeRenderable
{
private readonly string _sourceCode;
private readonly Theme _theme;
private readonly IGrammar _grammar;
public SourceCodeText(
string sourceCode,
string scopeName,
ThemeName themeName = ThemeName.DarkPlus
)
{
_sourceCode = sourceCode;
var options = new RegistryOptions(themeName);
var registry = new Registry(options);
_theme = registry.GetTheme();
_grammar = registry.LoadGrammar(scopeName);
if (_grammar is null)
throw new ArgumentOutOfRangeException(
nameof(scopeName),
"Failed to load the grammar for the provided scope."
);
}
public SourceCodeText(string sourceCode, Theme theme, IGrammar grammar)
{
_sourceCode = sourceCode;
_theme = theme;
_grammar = grammar;
}
protected override IRenderable Build()
{
IStateStack? ruleStack = null;
var paragraph = new Paragraph() { Justification = Justify.Left, Overflow = Overflow.Fold };
var isFirstLine = true;
foreach (var line in _sourceCode.EnumerateLines())
{
if (isFirstLine)
isFirstLine = false;
else
paragraph.Append(Environment.NewLine);
// Tokenise the line
var result = _grammar.TokenizeLine(new string(line), ruleStack, TimeSpan.MaxValue);
// Update the current ruleStack
ruleStack = result.RuleStack;
// Append tokens for the line
foreach (IToken token in result.Tokens)
{
var startIndex = Math.Min(token.StartIndex, line.Length);
var endIndex = Math.Min(token.EndIndex, line.Length);
var tokenSpan = line.Slice(startIndex, endIndex - startIndex);
paragraph.Append(new string(tokenSpan), GetTokenStyle(token, _theme));
}
}
return paragraph;
}
private static Style GetTokenStyle(IToken token, Theme theme)
{
var foregroundThemeColor = Color.Default;
var backgroundThemeColor = Color.Default;
var fontDecoration = Decoration.None;
foreach (var themeRule in theme.Match(token.Scopes))
{
if (foregroundThemeColor == Color.Default && themeRule.foreground > 0)
foregroundThemeColor = Color.FromHex(theme.GetColor(themeRule.foreground));
if (backgroundThemeColor == Color.Default && themeRule.background > 0)
backgroundThemeColor = Color.FromHex(theme.GetColor(themeRule.background));
if (fontDecoration == Decoration.None && themeRule.fontStyle > 0)
{
if ((themeRule.fontStyle & FontStyle.Bold) != 0)
{
fontDecoration |= Decoration.Bold;
}
if ((themeRule.fontStyle & FontStyle.Italic) != 0)
{
fontDecoration |= Decoration.Italic;
}
if ((themeRule.fontStyle & FontStyle.Underline) != 0)
{
fontDecoration |= Decoration.Underline;
}
if ((themeRule.fontStyle & FontStyle.Strikethrough) != 0)
{
fontDecoration |= Decoration.Strikethrough;
}
}
}
return new Style(foregroundThemeColor, backgroundThemeColor, fontDecoration);
}
} |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Hi, I recently ported TextMate grammars support to C#.
Thanks to your awesome project, I was able to add syntax highlight support to the console:
TextMateSharpsupports more than 50 grammars, feel free to take a look at the DemoApplication, just in case you want to add syntax highlight support toSpectre.Console:-).All reactions