Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c700d81
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
c511c14
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
eef1267
Initial plan
Copilot Apr 20, 2026
002fcb6
Fix MarkdownCodeBlock rendering codeblocks with incorrect background …
Copilot Apr 20, 2026
9b04c9b
Merge branch 'develop' into copilot/fix-markdown-codeblock-background
tig Apr 20, 2026
6c77b70
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
c743916
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
95a095b
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
83fe8f7
Merge branch 'develop' into copilot/fix-markdown-codeblock-background
tig Apr 20, 2026
0854803
Merge branch 'copilot/fix-markdown-codeblock-background' of github.co…
tig Apr 20, 2026
10e1773
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
033a494
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
f11f46b
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
9fc2f9e
Fix Markdown code block background and highlighter logic
tig Apr 20, 2026
909ace4
Merge branch 'develop' into copilot/fix-markdown-codeblock-background
tig Apr 20, 2026
86f541a
fixed gitversion yml bug
tig Apr 20, 2026
83082d8
Fix SyntaxHighlighter/UseThemeBackground setters to invalidate layout
tig Apr 20, 2026
f2cfae4
Default UseThemeBackground to true
tig Apr 20, 2026
b3a01ae
Add ThemeName property to ISyntaxHighlighter interface
tig Apr 20, 2026
8aeb7ad
Auto-select syntax theme based on terminal background
tig Apr 20, 2026
3e9ddc4
Fix code block dimmer direction for light themes
tig Apr 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 23 additions & 18 deletions Examples/UICatalog/Scenarios/Deepdives.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ public override void Main ()
Height = Dim.Fill (1)
};

_markdownView = new Markdown
{
Width = Dim.Fill (), Height = Dim.Fill (), SyntaxHighlighter = new TextMateSyntaxHighlighter (ThemeName.Abbys), UseThemeBackground = true
};
_markdownView = new Markdown { Width = Dim.Fill (), Height = Dim.Fill (), SyntaxHighlighter = new TextMateSyntaxHighlighter () };

_markdownView.ViewportSettings |= ViewportSettingsFlags.HasHorizontalScrollBar;

Expand Down Expand Up @@ -114,7 +111,13 @@ public override void Main ()

Shortcut contentWidthShortcut = new () { CommandView = _contentWidthUpDown, Text = "Content Width" };

DropDownList<ThemeName> themeDropDown = new () { ReadOnly = true, CanFocus = false, Value = ThemeName.Abbys, Autocomplete = null };
DropDownList<ThemeName> themeDropDown = new ()
{
ReadOnly = true,
CanFocus = false,
Value = (Enum.TryParse (_markdownView.SyntaxHighlighter.ThemeName, out ThemeName theme) ? theme : ThemeName.DarkPlus),
Autocomplete = null
};

themeDropDown.ValueChanged += (_, e) =>
{
Expand All @@ -123,18 +126,25 @@ public override void Main ()
return;
}

TextMateSyntaxHighlighter highlighter = new (themeName);
_markdownView.SyntaxHighlighter = highlighter;

// Force re-layout so code blocks pick up new theme
string text = _markdownView.Text;
_markdownView.Text = string.Empty;
_markdownView.Text = text;
_markdownView.SyntaxHighlighter = new TextMateSyntaxHighlighter (themeName);
};

Shortcut themeShortcut = new () { Text = "_Theme:", CommandView = themeDropDown, MouseHighlightStates = MouseState.None };

CheckBox themeBgCheckBox = new () { Text = "Theme _BG", Value = CheckState.UnChecked };
// Auto-select a light or dark syntax theme based on the terminal's actual background color.
_app.Driver!.DefaultAttributeChanged += (_, e) =>
{
if (_markdownView is null || e.NewValue is not { } attr)
{
return;
}

ThemeName autoTheme = TextMateSyntaxHighlighter.GetThemeForBackground (attr.Background);
_markdownView.SyntaxHighlighter = new TextMateSyntaxHighlighter (autoTheme);
themeDropDown.Value = autoTheme;
};

CheckBox themeBgCheckBox = new () { Text = "Theme _BG", Value = _markdownView.UseThemeBackground ? CheckState.Checked : CheckState.UnChecked };

themeBgCheckBox.ValueChanged += (_, e) =>
{
Expand All @@ -144,11 +154,6 @@ public override void Main ()
}

_markdownView.UseThemeBackground = e.NewValue == CheckState.Checked;

// Force re-layout
string text = _markdownView.Text;
_markdownView.Text = string.Empty;
_markdownView.Text = text;
};

Shortcut themeBgShortcut = new () { CommandView = themeBgCheckBox };
Expand Down
51 changes: 36 additions & 15 deletions Examples/UICatalog/Scenarios/MarkdownTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ public override void Main ()
using IApplication app = Application.Create ();
app.Init ();

Window window = new () { Title = "Markdown Tester", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.None };
Window window = new ()
{
Title = "Markdown Tester",
Width = Dim.Fill (),
Height = Dim.Fill (),
BorderStyle = LineStyle.None,
SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Accent)
};

// --- Source editor (top half) ---
FrameView editorFrame = new ()
Expand Down Expand Up @@ -58,9 +65,7 @@ public override void Main ()
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill (),
Text = Markdown.DefaultMarkdownSample,
SyntaxHighlighter = new TextMateSyntaxHighlighter (),
UseThemeBackground = true
SyntaxHighlighter = new TextMateSyntaxHighlighter ()
};

previewFrame.Add (preview);
Expand All @@ -74,33 +79,49 @@ public override void Main ()

Shortcut quitShortcut = new () { Title = "Quit", Key = Key.Esc, Action = app.RequestStop };

DropDownList<ThemeName> themeDropDown = new () { Value = ThemeName.DarkPlus, ReadOnly = true, CanFocus = false };
DropDownList<ThemeName> themeDropDown = new ()
{
Value = (preview.SyntaxHighlighter as TextMateSyntaxHighlighter)?.ThemeName ?? ThemeName.DarkPlus,
ReadOnly = true,
CanFocus = false
};

themeDropDown.ValueChanged += (_, e) =>
{
if (e.Value is { } themeName)
if (e.Value is not { } themeName)
{
TextMateSyntaxHighlighter highlighter = new (themeName);
preview.SyntaxHighlighter = highlighter;
preview.Text = editor.Text;
return;
}
preview.SyntaxHighlighter = new TextMateSyntaxHighlighter (themeName);
preview.Text = editor.Text;
};

Shortcut themeShortcut = new () { Title = "Theme", CommandView = themeDropDown };

CheckBox themeBgCheckBox = new () { Text = "Theme _BG", Value = CheckState.UnChecked };
// Auto-select a light or dark syntax theme based on the terminal's actual background color.
app.Driver!.DefaultAttributeChanged += (_, e) =>
{
if (e.NewValue is not { } attr)
{
return;
}

ThemeName autoTheme = TextMateSyntaxHighlighter.GetThemeForBackground (attr.Background);
preview.SyntaxHighlighter = new TextMateSyntaxHighlighter (autoTheme);
themeDropDown.Value = autoTheme;
};

themeBgCheckBox.ValueChanged += (_, e) =>
{
preview.UseThemeBackground = e.NewValue == CheckState.Checked;
preview.Text = editor.Text;
};
CheckBox themeBgCheckBox = new () { Text = "Theme _BG", Value = preview.UseThemeBackground ? CheckState.Checked : CheckState.UnChecked };

themeBgCheckBox.ValueChanged += (_, e) => { preview.UseThemeBackground = e.NewValue == CheckState.Checked; };

Shortcut themeBgShortcut = new () { CommandView = themeBgCheckBox };

statusBar.Add (themeShortcut, themeBgShortcut, quitShortcut);
window.Add (statusBar);

preview.Text = editor.Text;

app.Run (window);
window.Dispose ();
}
Expand Down
27 changes: 15 additions & 12 deletions Examples/mdv/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,7 @@ static void RunFullScreen (List<string> files, ThemeName syntaxTheme)
{
Width = Dim.Fill (),
Height = Dim.Fill (1), // leave room for StatusBar
SyntaxHighlighter = new TextMateSyntaxHighlighter (syntaxTheme),
UseThemeBackground = true
SyntaxHighlighter = new TextMateSyntaxHighlighter (syntaxTheme)
};

// Vertical scrollbar is already enabled by MarkdownView constructor
Expand Down Expand Up @@ -295,26 +294,30 @@ static void RunFullScreen (List<string> files, ThemeName syntaxTheme)
return;
}

TextMateSyntaxHighlighter highlighter = new (themeName);
markdownView.SyntaxHighlighter = highlighter;

string text = markdownView.Text;
markdownView.Text = string.Empty;
markdownView.Text = text;
markdownView.SyntaxHighlighter = new TextMateSyntaxHighlighter (themeName);
};

statusItems.Add (new Shortcut { Title = "Theme", CommandView = themeDropDown });

// Auto-select a light or dark syntax theme based on the terminal's actual background color.
app.Driver!.DefaultAttributeChanged += (_, e) =>
{
if (e.NewValue is not { } attr)
{
return;
}

ThemeName autoTheme = TextMateSyntaxHighlighter.GetThemeForBackground (attr.Background);
markdownView.SyntaxHighlighter = new TextMateSyntaxHighlighter (autoTheme);
themeDropDown.Value = autoTheme;
};

// Theme background toggle
CheckBox themeBgCheckBox = new () { Text = "Theme _BG", Value = CheckState.Checked };

themeBgCheckBox.ValueChanged += (_, e) =>
{
markdownView.UseThemeBackground = e.NewValue == CheckState.Checked;

string text = markdownView.Text;
markdownView.Text = string.Empty;
markdownView.Text = text;
};

statusItems.Add (new Shortcut { CommandView = themeBgCheckBox });
Expand Down
6 changes: 3 additions & 3 deletions GitVersion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# - develop: Develop branch for V2
#
# Package Naming:
# - from develop: 2.1.0-develop.1 (minor version increments)
# - from develop: 2.0.0-develop.1 (patch version increments)
# - from main (pre-release): 2.0.0-prealpha.1 or 2.0.0-beta.1
# - from main (release): 2.0.0 (patch version increments)
#
Expand Down Expand Up @@ -46,8 +46,8 @@ branches:
regex: develop
# Adds 'develop' as pre-release label (e.g., 2.1.0-develop.1)
label: develop
# Increments minor version (x.y+1.z) on commits
increment: Minor
# Increments patch version (x.y.z+1) on commits
increment: Patch
Comment thread
tig marked this conversation as resolved.
# No source branches specified as this is the root of development
source-branches: []
# Indicates this branch feeds into release branches
Expand Down
5 changes: 5 additions & 0 deletions Terminal.Gui/Drawing/Markdown/ISyntaxHighlighter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ public interface ISyntaxHighlighter
/// </summary>
void ResetState ();

/// <summary>
/// Gets the name of the currently active syntax highlighting theme.
/// </summary>
string ThemeName { get; }

/// <summary>
/// Gets the default background color from the active syntax highlighting theme.
/// Used by code block views to fill their viewport background consistently with
Expand Down
6 changes: 5 additions & 1 deletion Terminal.Gui/Drawing/Markdown/MarkdownAttributeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ public static Attribute GetAttributeForSegment (View view, StyledSegment segment
{
if (segment.Attribute is { } explicitAttr)
{
return explicitAttr;
// When a caller-provided background override is present, apply it even to
// segments that carry an explicit attribute from the highlighter. This keeps
// the token foreground colours but ensures the background matches the fill
// colour of the containing code block / viewport.
return themeBackground is { } overrideBg ? explicitAttr with { Background = overrideBg } : explicitAttr;
}

// Use the provided theme background, or fall back to the view's normal background.
Expand Down
11 changes: 7 additions & 4 deletions Terminal.Gui/Drawing/Markdown/TextMateSyntaxHighlighter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class TextMateSyntaxHighlighter : ISyntaxHighlighter
/// </param>
public TextMateSyntaxHighlighter (ThemeName theme = ThemeName.DarkPlus)
{
CurrentThemeName = theme;
ThemeName = theme;
_registryOptions = new RegistryOptions (theme);
_registry = new Registry (_registryOptions);
CacheThemeDefaults ();
Expand Down Expand Up @@ -138,8 +138,11 @@ public IReadOnlyList<StyledSegment> Highlight (string code, string? language)
/// <returns>A theme appropriate for the background luminance.</returns>
public static ThemeName GetThemeForBackground (Color background) => background.IsDarkColor () ? ThemeName.DarkPlus : ThemeName.LightPlus;

/// <summary>Gets the <see cref="ThemeName"/> that is currently active.</summary>
public ThemeName CurrentThemeName { get; private set; }
/// <summary>Gets the <see cref="TextMateSharp.Grammars.ThemeName"/> that is currently active.</summary>
public ThemeName ThemeName { get; private set; }

/// <inheritdoc/>
string ISyntaxHighlighter.ThemeName => ThemeName.ToString ();

/// <inheritdoc/>
public Color? DefaultBackground => _defaultBackground;
Expand Down Expand Up @@ -188,7 +191,7 @@ public IReadOnlyList<StyledSegment> Highlight (string code, string? language)
/// <param name="theme">The new VS Code theme to use.</param>
public void SetTheme (ThemeName theme)
{
CurrentThemeName = theme;
ThemeName = theme;
_registryOptions = new RegistryOptions (theme);
_registry = new Registry (_registryOptions);
_grammarCache.Clear ();
Expand Down
10 changes: 9 additions & 1 deletion Terminal.Gui/Drivers/DriverImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,18 @@ private void OnSizeMonitorOnSizeChanged (object? _, SizeChangedEventArgs e) =>
/// <inheritdoc/>
public Attribute? DefaultAttribute { get; private set; }

/// <inheritdoc/>
public event EventHandler<ValueChangedEventArgs<Attribute?>>? DefaultAttributeChanged;

/// <summary>
/// Sets the terminal's default attribute (queried via OSC 10/11).
/// </summary>
internal void SetDefaultAttribute (Attribute attr) => DefaultAttribute = attr;
internal void SetDefaultAttribute (Attribute attr)
{
Attribute? old = DefaultAttribute;
DefaultAttribute = attr;
DefaultAttributeChanged?.Invoke (this, new ValueChangedEventArgs<Attribute?> (old, attr));
}

/// <inheritdoc/>
public TerminalColorCapabilities? ColorCapabilities { get; private set; }
Expand Down
5 changes: 5 additions & 0 deletions Terminal.Gui/Drivers/IDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ public interface IDriver : IDisposable
/// </summary>
Attribute? DefaultAttribute { get; }

/// <summary>
/// Raised when <see cref="DefaultAttribute"/> changes (e.g. after terminal color detection completes).
/// </summary>
event EventHandler<ValueChangedEventArgs<Attribute?>>? DefaultAttributeChanged;

/// <summary>
/// Gets the terminal's color capabilities as detected from environment variables.
/// <see langword="null"/> if detection has not been performed.
Expand Down
32 changes: 29 additions & 3 deletions Terminal.Gui/Views/Markdown/Markdown.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,41 @@ public MarkdownPipeline? MarkdownPipeline

/// <summary>Gets or sets an optional syntax highlighter for fenced code blocks.</summary>
/// <value>An <see cref="ISyntaxHighlighter"/> implementation, or <see langword="null"/> for plain-text code blocks.</value>
public ISyntaxHighlighter? SyntaxHighlighter { get; set; }
public ISyntaxHighlighter? SyntaxHighlighter
{
get;
set
{
if (ReferenceEquals (field, value))
{
return;
}

field = value;
InvalidateParsedAndLayout ();
}
}

/// <summary>
/// Gets or sets whether the view fills its background with the syntax highlighting theme's
/// editor background color. When <see langword="true"/> and a <see cref="SyntaxHighlighter"/>
/// is set, the theme's <see cref="ISyntaxHighlighter.DefaultBackground"/> is used for the
/// entire viewport, headings, body text, and table cells. Defaults to <see langword="false"/>.
/// entire viewport, headings, body text, and table cells. Defaults to <see langword="true"/>.
/// </summary>
public bool UseThemeBackground { get; set; }
public bool UseThemeBackground
{
get;
set
{
if (field == value)
{
return;
}

field = value;
InvalidateParsedAndLayout ();
}
} = true;

/// <summary>
/// Gets or sets whether heading lines include the <c>#</c> prefix (e.g. <c># </c>, <c>## </c>).
Expand Down
2 changes: 1 addition & 1 deletion Terminal.Gui/Views/Markdown/MarkdownCodeBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ protected override bool OnDrawingContent (DrawContext? context)

foreach (StyledSegment segment in segments)
{
Attribute attr = MarkdownAttributeHelper.GetAttributeForSegment (this, segment, SyntaxHighlighter);
Attribute attr = MarkdownAttributeHelper.GetAttributeForSegment (this, segment, SyntaxHighlighter, codeBg);
SetAttribute (attr);

foreach (string grapheme in GraphemeHelper.GetGraphemes (segment.Text))
Expand Down
Loading
Loading