From 12756a29d84a183a0ab28e9a2d5e36543a92467e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 20:24:24 +0000
Subject: [PATCH] Fix Cell.Grapheme validation allocation by adding
GetGraphemeCount
Added allocation-free grapheme counting to GraphemeHelper:
- New GetGraphemeCount() method counts graphemes without materializing array
- Uses TextElementEnumerator directly, avoiding .ToArray() allocation
- Updated Cell.Grapheme setter to use GetGraphemeCount() instead of .ToArray().Length
Impact: Eliminates allocation on every Cell.Grapheme property set
- Validation now happens without intermediate array allocation
- Particularly beneficial for cell-based operations and grid rendering
All unit tests pass (12,055 parallelizable + 1,173 non-parallel)
Co-authored-by: tig <585482+tig@users.noreply.github.com>
---
Terminal.Gui/Drawing/Cell.cs | 2 +-
Terminal.Gui/Drawing/GraphemeHelper.cs | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/Terminal.Gui/Drawing/Cell.cs b/Terminal.Gui/Drawing/Cell.cs
index f7da577ad..6e9aff593 100644
--- a/Terminal.Gui/Drawing/Cell.cs
+++ b/Terminal.Gui/Drawing/Cell.cs
@@ -27,7 +27,7 @@ public record struct Cell (Attribute? Attribute = null, bool IsDirty = false, st
readonly get => _grapheme;
set
{
- if (GraphemeHelper.GetGraphemes(value).ToArray().Length > 1)
+ if (GraphemeHelper.GetGraphemeCount (value) > 1)
{
throw new InvalidOperationException ($"Only a single {nameof (Grapheme)} cluster is allowed per Cell.");
}
diff --git a/Terminal.Gui/Drawing/GraphemeHelper.cs b/Terminal.Gui/Drawing/GraphemeHelper.cs
index 4ae00148c..918270727 100644
--- a/Terminal.Gui/Drawing/GraphemeHelper.cs
+++ b/Terminal.Gui/Drawing/GraphemeHelper.cs
@@ -46,4 +46,27 @@ public static class GraphemeHelper
yield return element;
}
}
+
+ ///
+ /// Counts the number of grapheme clusters in a string without allocating intermediate collections.
+ ///
+ /// The string to count graphemes in.
+ /// The number of grapheme clusters, or 0 if the string is null or empty.
+ public static int GetGraphemeCount (string text)
+ {
+ if (string.IsNullOrEmpty (text))
+ {
+ return 0;
+ }
+
+ TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator (text);
+ var count = 0;
+
+ while (enumerator.MoveNext ())
+ {
+ count++;
+ }
+
+ return count;
+ }
}