Skip to content

Fixes #4817. CharMap: handle zero-width ModifierSymbol runes without throwing#4818

Merged
tig merged 3 commits intov2_developfrom
copilot/fix-charmap-zero-width-modifier
Mar 10, 2026
Merged

Fixes #4817. CharMap: handle zero-width ModifierSymbol runes without throwing#4818
tig merged 3 commits intov2_developfrom
copilot/fix-charmap-zero-width-modifier

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 9, 2026

Fixes #4817

CharMap.RenderGrapheme threw InvalidOperationException for UnicodeCategory.ModifierSymbol characters with column width 0 (e.g. emoji skin tone modifiers U+1F3FB–U+1F3FF), which are designed to combine with a preceding base glyph and cannot render standalone.

Changes

  • CharMap.csRenderGrapheme: Add case UnicodeCategory.ModifierSymbol: rendering a highlighted "M" placeholder when width == 0 (consistent with Format"F"), or the grapheme normally when width > 0
  • CharMap.csdefault branch: Replace throw new InvalidOperationException with a highlighted "?" fallback, making the renderer resilient to any future zero-width Unicode categories not yet explicitly handled
  • CharMapTests.cs: Add Draw_ModifierSymbol_CodePoint_Does_Not_Throw — draws a CharMap at U+1F3FB and asserts no exception

Pull Request checklist:

  • I've named my PR in the form of "Fixes #issue. Terse description."
  • My code follows the style guidelines of Terminal.Gui - if you use Visual Studio, hit CTRL-K-D to automatically reformat your files before committing.
  • My code follows the Terminal.Gui library design guidelines
  • I ran dotnet test before commit
  • I have made corresponding changes to the API documentation (using /// style comments)
  • My changes generate no new warnings
  • I have checked my code and corrected any poor grammar or misspellings
  • I conducted basic QA to assure all features are working
Original prompt

This section details on the original issue you should resolve

<issue_title>CharMap throws InvalidOperationException for zero-width ModifierSymbol runes (e.g. U+1F3FB skin tone modifiers)</issue_title>
<issue_description>## Bug Description

CharMap.RenderGrapheme throws an InvalidOperationException when rendering Unicode code points that have UnicodeCategory.ModifierSymbol and a column width of 0. This occurs when scrolling through or displaying emoji skin tone modifier characters (U+1F3FB-U+1F3FF).

Exception:

System.InvalidOperationException: The Rune has zero width and no special-case UnicodeCategory logic applies.

Root Cause

The RenderGrapheme local function in CharMap.OnDrawingContent has a switch on UnicodeCategory that handles several zero-width categories (Format, NonSpacingMark, SpacingCombiningMark, EnclosingMark, Control, etc.), but does not handle UnicodeCategory.ModifierSymbol.

Characters like U+1F3FB (EMOJI MODIFIER FITZPATRICK TYPE-1-2) are classified as ModifierSymbol and report a column width of 0 from GetColumns() because they are designed to combine with a preceding base emoji rather than render standalone. When these fall through to the default branch with width == 0, the exception is thrown.

Steps to Reproduce

  1. Run the CharMap demo/view
  2. Navigate to the U+1F3Fx range (emoji skin tone modifiers)
  3. The view throws InvalidOperationException

Proposed Fix

Add a case UnicodeCategory.ModifierSymbol: to the switch statement in RenderGrapheme. Since these are modifier characters that cannot render standalone (zero width), they should display a highlighted placeholder (consistent with how Format characters show F):

// Modifier symbol (e.g. emoji skin tone modifiers U+1F3FB-U+1F3FF) that reports
// width of 0 because it is designed to combine with a preceding base emoji.
case UnicodeCategory.ModifierSymbol:
    if (width > 0)
    {
        AddStr (grapheme);
    }
    else
    {
        SetAttributeForRole (VisualRole.Highlight);
        AddStr ("M");
        SetAttributeForRole (VisualRole.Normal);
    }
    break;

Alternatively, the default branch could be made more resilient by replacing the throw with a fallback rendering, since other UnicodeCategory values with zero-width characters may exist or be introduced in future Unicode versions.

Affected File

  • Terminal.Gui/Views/CharMap/CharMap.cs - RenderGrapheme local function inside OnDrawingContent</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

… (e.g. U+1F3FB)

Co-authored-by: tig <585482+tig@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix CharMap InvalidOperationException for ModifierSymbol Fixes #issue. CharMap: handle zero-width ModifierSymbol runes without throwing Mar 9, 2026
Copilot finished work on behalf of tig March 9, 2026 15:48
@tig tig changed the title Fixes #issue. CharMap: handle zero-width ModifierSymbol runes without throwing Fixes #4817. CharMap: handle zero-width ModifierSymbol runes without throwing Mar 10, 2026
@tig tig marked this pull request as ready for review March 10, 2026 02:10
@tig tig self-requested a review as a code owner March 10, 2026 02:10
@tig tig requested review from BDisp and Copilot and removed request for tig March 10, 2026 02:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes CharMap rendering crashes when encountering zero-width UnicodeCategory.ModifierSymbol runes (e.g., emoji skin tone modifiers), and makes the renderer resilient to any future zero-width categories by using a placeholder instead of throwing.

Changes:

  • Add explicit rendering for UnicodeCategory.ModifierSymbol in CharMap.RenderGrapheme, showing a highlighted "M" placeholder when the rune’s column width is 0.
  • Replace the zero-width default-case InvalidOperationException with a highlighted "?" fallback to prevent crashes.
  • Add a unit test that draws CharMap at U+1F3FB and asserts no exception is thrown.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
Terminal.Gui/Views/CharMap/CharMap.cs Adds ModifierSymbol handling and replaces zero-width default-case throw with a safe placeholder render.
Tests/UnitTestsParallelizable/Views/CharMapTests.cs Adds a draw regression test for a zero-width ModifierSymbol code point (U+1F3FB).

Copy link
Copy Markdown
Collaborator

@BDisp BDisp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well handled.

@BDisp
Copy link
Copy Markdown
Collaborator

BDisp commented Mar 10, 2026

Cancelled after 60 minutes is a very long time. Are you sure it's running in degraded mode on Windows?

@tig
Copy link
Copy Markdown
Collaborator

tig commented Mar 10, 2026

The Link PR has a bug. I've fixed it in the kitty PR.

@tig tig merged commit 2b3788a into v2_develop Mar 10, 2026
11 checks passed
@tig tig deleted the copilot/fix-charmap-zero-width-modifier branch March 10, 2026 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CharMap throws InvalidOperationException for zero-width ModifierSymbol runes (e.g. U+1F3FB skin tone modifiers)

4 participants