Ver código fonte

Fixes #4259. Our wcwidth library is out of date (#4281)

* Update package versions and remove hack code from RuneExtensions

Updated several package versions in `Directory.Packages.props`, including `JetBrains.Annotations`, `Microsoft.Extensions.Logging.Abstractions`, `System.IO.Abstractions`, and `Wcwidth`.

Refactored methods in `RuneExtensions.cs`:
- Simplified `GetColumns` by removing special Unicode handling.
- Renamed constants to follow naming conventions.
- Improved logic and readability in `DecodeSurrogatePair`, `Encode`, and `GetEncodingLength`.
- Streamlined `IsSurrogatePair` and `MakePrintable` for clarity and efficiency.

* Update package version ranges for flexibility

Updated the `JetBrains.Annotations` package to use a version range
starting from `2025.2.2` to allow future updates. Adjusted the
`Microsoft.Extensions.Logging.Abstractions` package to a version
range `[9.0.0,10)` for compatibility. Changed `System.IO.Abstractions`
to a range `[22.0.16,23)` and `Wcwidth` to `[3.0.0,)` to enable
future updates within specified ranges.
Tig 2 meses atrás
pai
commit
b83bcc2fdb
2 arquivos alterados com 34 adições e 37 exclusões
  1. 4 4
      Directory.Packages.props
  2. 30 33
      Terminal.Gui/Text/RuneExtensions.cs

+ 4 - 4
Directory.Packages.props

@@ -11,14 +11,14 @@
     <PackageVersion Include="Microsoft.Net.Compilers.Toolset" Version="4.11.0" />
     <PackageVersion Include="Microsoft.SourceLink.GitHub" Version="[8,9)" />
     <PackageVersion Include="ColorHelper" Version="[1.8.1,2)" />
-    <PackageVersion Include="JetBrains.Annotations" Version="[2024.3.0,)" />
+    <PackageVersion Include="JetBrains.Annotations" Version="[2025.2.2,)" />
     <PackageVersion Include="Microsoft.CodeAnalysis" Version="4.11.0" />
     <PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.11.0" />
     <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
-    <PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="[9.0.2,10)" />
+    <PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="[9.0.0,10)" />
     <PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.6" />
-    <PackageVersion Include="System.IO.Abstractions" Version="[22.0.11,23)" />
-    <PackageVersion Include="Wcwidth" Version="[2,3)" />
+    <PackageVersion Include="System.IO.Abstractions" Version="[22.0.16,23)" />
+    <PackageVersion Include="Wcwidth" Version="[3.0.0,)" />
     <PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="[1.21.2,2)" />
     <PackageVersion Include="Serilog" Version="4.2.0" />
     <PackageVersion Include="Serilog.Extensions.Logging" Version="9.0.0" />

+ 30 - 33
Terminal.Gui/Text/RuneExtensions.cs

@@ -37,22 +37,27 @@ public static class RuneExtensions
     public static bool DecodeSurrogatePair (this Rune rune, out char []? chars)
     {
         bool isSingleUtf16CodeUnit = rune.IsBmp;
+
         if (isSingleUtf16CodeUnit)
         {
             chars = null;
+
             return false;
         }
 
-        const int maxCharsPerRune = 2;
-        Span<char> charBuffer = stackalloc char[maxCharsPerRune];
+        const int MAX_CHARS_PER_RUNE = 2;
+        Span<char> charBuffer = stackalloc char [MAX_CHARS_PER_RUNE];
         int charsWritten = rune.EncodeToUtf16 (charBuffer);
+
         if (charsWritten >= 2 && char.IsSurrogatePair (charBuffer [0], charBuffer [1]))
         {
             chars = charBuffer [..charsWritten].ToArray ();
+
             return true;
         }
 
         chars = null;
+
         return false;
     }
 
@@ -65,23 +70,26 @@ public static class RuneExtensions
     /// <returns>he number of bytes written into the destination buffer.</returns>
     public static int Encode (this Rune rune, byte [] dest, int start = 0, int count = -1)
     {
-        const int maxUtf8BytesPerRune = 4;
-        Span<byte> bytes = stackalloc byte[maxUtf8BytesPerRune];
+        const int MAX_UTF8_BYTES_PER_RUNE = 4;
+        Span<byte> bytes = stackalloc byte [MAX_UTF8_BYTES_PER_RUNE];
         int writtenBytes = rune.EncodeToUtf8 (bytes);
 
         int bytesToCopy = count == -1
-            ? writtenBytes
-            : Math.Min (count, writtenBytes);
-        int bytesWritten = 0;
-        for (int i = 0; i < bytesToCopy; i++)
+                              ? writtenBytes
+                              : Math.Min (count, writtenBytes);
+        var bytesWritten = 0;
+
+        for (var i = 0; i < bytesToCopy; i++)
         {
             if (bytes [i] == '\0')
             {
                 break;
             }
+
             dest [start + i] = bytes [i];
             bytesWritten++;
         }
+
         return bytesWritten;
     }
 
@@ -111,22 +119,7 @@ public static class RuneExtensions
     ///     The number of columns required to fit the rune, 0 if the argument is the null character, or -1 if the value is
     ///     not printable, otherwise the number of columns that the rune occupies.
     /// </returns>
-    public static int GetColumns (this Rune rune)
-    {
-        int value = rune.Value;
-
-        // TODO: Remove this code when #4259 is fixed
-        // TODO: See https://github.com/gui-cs/Terminal.Gui/issues/4259
-        if (value is >= 0x2630 and <= 0x2637 ||  // Trigrams
-            value is >= 0x268A and <= 0x268F ||  // Monograms/Digrams
-            value is >= 0x4DC0 and <= 0x4DFF)    // Hexagrams
-        {
-            return 2; // Assume double-width due to Windows Terminal font rendering
-        }
-
-        // Fallback to original GetWidth for other code points
-        return UnicodeCalculator.GetWidth (rune);
-    }
+    public static int GetColumns (this Rune rune) { return UnicodeCalculator.GetWidth (rune); }
 
     /// <summary>Get number of bytes required to encode the rune, based on the provided encoding.</summary>
     /// <remarks>This is a Terminal.Gui extension method to <see cref="System.Text.Rune"/> to support TUI text manipulation.</remarks>
@@ -137,21 +130,23 @@ public static class RuneExtensions
     {
         encoding ??= Encoding.UTF8;
 
-        const int maxCharsPerRune = 2;
+        const int MAX_CHARS_PER_RUNE = 2;
+
         // Get characters with UTF16 to keep that part independent of selected encoding.
-        Span<char> charBuffer = stackalloc char[maxCharsPerRune];
-        int charsWritten = rune.EncodeToUtf16(charBuffer);
-        Span<char> chars = charBuffer[..charsWritten];
+        Span<char> charBuffer = stackalloc char [MAX_CHARS_PER_RUNE];
+        int charsWritten = rune.EncodeToUtf16 (charBuffer);
+        Span<char> chars = charBuffer [..charsWritten];
 
         int maxEncodedLength = encoding.GetMaxByteCount (charsWritten);
-        Span<byte> byteBuffer = stackalloc byte[maxEncodedLength];
+        Span<byte> byteBuffer = stackalloc byte [maxEncodedLength];
         int bytesEncoded = encoding.GetBytes (chars, byteBuffer);
-        ReadOnlySpan<byte> encodedBytes = byteBuffer[..bytesEncoded];
+        ReadOnlySpan<byte> encodedBytes = byteBuffer [..bytesEncoded];
 
         if (encodedBytes [^1] == '\0')
         {
             return encodedBytes.Length - 1;
         }
+
         return encodedBytes.Length;
     }
 
@@ -175,14 +170,16 @@ public static class RuneExtensions
     public static bool IsSurrogatePair (this Rune rune)
     {
         bool isSingleUtf16CodeUnit = rune.IsBmp;
+
         if (isSingleUtf16CodeUnit)
         {
             return false;
         }
 
-        const int maxCharsPerRune = 2;
-        Span<char> charBuffer = stackalloc char[maxCharsPerRune];
+        const int MAX_CHARS_PER_RUNE = 2;
+        Span<char> charBuffer = stackalloc char [MAX_CHARS_PER_RUNE];
         int charsWritten = rune.EncodeToUtf16 (charBuffer);
+
         return charsWritten >= 2 && char.IsSurrogatePair (charBuffer [0], charBuffer [1]);
     }
 
@@ -193,5 +190,5 @@ public static class RuneExtensions
     /// <remarks>This is a Terminal.Gui extension method to <see cref="System.Text.Rune"/> to support TUI text manipulation.</remarks>
     /// <param name="rune"></param>
     /// <returns></returns>
-    public static Rune MakePrintable (this Rune rune) { return Rune.IsControl (rune) ? new Rune (rune.Value + 0x2400) : rune; }
+    public static Rune MakePrintable (this Rune rune) { return Rune.IsControl (rune) ? new (rune.Value + 0x2400) : rune; }
 }