Adjust CharMap scenario with graphemes

This commit is contained in:
BDisp
2025-11-14 20:53:08 +00:00
parent 5e87af7307
commit ff538e31e7

View File

@@ -148,10 +148,8 @@ public class CharMap : View, IDesignable
break;
}
var rune = new Rune (cp);
Span<char> utf16 = new char [2];
rune.EncodeToUtf16 (utf16);
UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory (utf16 [0]);
string grapheme = new Rune (cp).ToString ();
UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory (cp);
if (cat == ShowUnicodeCategory.Value)
{
anyVisible = true;
@@ -685,7 +683,7 @@ public class CharMap : View, IDesignable
// Don't render out-of-range scalars
if (scalar > MAX_CODE_POINT)
{
AddRune (' ');
AddStr (" ");
if (visibleRow == selectedRowIndex && col == selectedCol)
{
SetAttributeForRole (VisualRole.Normal);
@@ -693,22 +691,20 @@ public class CharMap : View, IDesignable
continue;
}
var rune = (Rune)'?';
string grapheme = "?";
if (Rune.IsValid (scalar))
{
rune = new (scalar);
grapheme = new Rune (scalar).ToString ();
}
int width = rune.GetColumns ();
int width = grapheme.GetColumns ();
// Compute visibility based on ShowUnicodeCategory
bool isVisible = Rune.IsValid (scalar);
if (isVisible && ShowUnicodeCategory.HasValue)
{
Span<char> filterUtf16 = new char [2];
rune.EncodeToUtf16 (filterUtf16);
UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory (filterUtf16 [0]);
UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory (scalar);
isVisible = cat == ShowUnicodeCategory.Value;
}
@@ -717,11 +713,11 @@ public class CharMap : View, IDesignable
// Glyph row
if (isVisible)
{
RenderRune (rune, width);
RenderGrapheme (grapheme, width, scalar);
}
else
{
AddRune (' ');
AddStr (" ");
}
}
else
@@ -736,7 +732,7 @@ public class CharMap : View, IDesignable
}
else
{
AddRune (' ');
AddStr (" ");
}
}
@@ -750,21 +746,18 @@ public class CharMap : View, IDesignable
return true;
void RenderRune (Rune rune, int width)
void RenderGrapheme (string grapheme, int width, int scalar)
{
// Get the UnicodeCategory
Span<char> utf16 = new char [2];
int charCount = rune.EncodeToUtf16 (utf16);
// Get the bidi class for the first code unit
// For most bidi characters, the first code unit is sufficient
UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory (utf16 [0]);
UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory (scalar);
switch (category)
{
case UnicodeCategory.OtherNotAssigned:
SetAttributeForRole (VisualRole.Highlight);
AddRune (Rune.ReplacementChar);
AddStr (Rune.ReplacementChar.ToString ());
SetAttributeForRole (VisualRole.Normal);
break;
@@ -773,7 +766,7 @@ public class CharMap : View, IDesignable
// These report width of 0 and don't render on their own.
case UnicodeCategory.Format:
SetAttributeForRole (VisualRole.Highlight);
AddRune ('F');
AddStr ("F");
SetAttributeForRole (VisualRole.Normal);
break;
@@ -786,38 +779,8 @@ public class CharMap : View, IDesignable
case UnicodeCategory.EnclosingMark:
if (width > 0)
{
AddRune (rune);
AddStr (grapheme);
}
else
{
if (rune.IsCombiningMark ())
{
// This is a hack to work around the fact that combining marks
// a) can't be rendered on their own
// b) that don't normalize are not properly supported in
// any known terminal (esp Windows/AtlasEngine).
// See Issue #2616
var sb = new StringBuilder ();
sb.Append ('a');
sb.Append (rune);
// Try normalizing after combining with 'a'. If it normalizes, at least
// it'll show on the 'a'. If not, just show the replacement char.
string normal = sb.ToString ().Normalize (NormalizationForm.FormC);
if (normal.Length == 1)
{
AddRune ((Rune)normal [0]);
}
else
{
SetAttributeForRole (VisualRole.Highlight);
AddRune ('M');
SetAttributeForRole (VisualRole.Normal);
}
}
}
break;
// These report width of 0, but render as 1
@@ -825,20 +788,28 @@ public class CharMap : View, IDesignable
case UnicodeCategory.LineSeparator:
case UnicodeCategory.ParagraphSeparator:
case UnicodeCategory.Surrogate:
AddRune (rune);
AddStr (grapheme);
break;
case UnicodeCategory.OtherLetter:
AddStr (grapheme);
if (width == 0)
{
AddStr (" ");
}
break;
default:
// Draw the rune
if (width > 0)
{
AddRune (rune);
AddStr (grapheme);
}
else
{
throw new InvalidOperationException ($"The Rune \"{rune}\" (U+{rune.Value:x6}) has zero width and no special-case UnicodeCategory logic applies.");
throw new InvalidOperationException ($"The Rune \"{grapheme}\" (U+{Rune.GetRuneAt (grapheme, 0).Value:x6}) has zero width and no special-case UnicodeCategory logic applies.");
}
break;