Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Surrogate Unicode sequences #139

Merged
merged 39 commits into from
Nov 10, 2024
Merged

Add support for Surrogate Unicode sequences #139

merged 39 commits into from
Nov 10, 2024

Conversation

tomlm
Copy link
Collaborator

@tomlm tomlm commented Nov 6, 2024

Fix for #112

image

Core Changes

  • Changed symbols to Rune class
  • Threaded Rune through the pipeline
  • Added gallery samples with surrogate, emoji and right to left examples.

Misc changes

  • fixed type with strikthorugh=>strikethrough
  • Added debugDisplay attributes to help with debugging

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced support for complex emoji rendering, including new properties and methods for better text handling.
    • Introduced new static methods for printing pixels and measuring text width.
    • Added new TextBlock elements showcasing diverse text features, including emojis and international characters.
    • New properties for symbol representation, including Text and Width, across various structures.
  • Bug Fixes

    • Improved handling of glyph metrics and text shaping processes.
    • Refined blending behavior for pixel foregrounds and backgrounds.
  • Documentation

    • Updated comments and summaries across various classes and methods for clarity.
  • Chores

    • Updated project dependencies by removing and adding relevant packages.

tomlm added 2 commits November 5, 2024 19:09
Core Changes
* Changed symbols to Rune class
* Threaded Rune through the pipeline
* Added gallery samples with surrogate, emoji and right to left examples.

Misc changes
* fixed type with strikthorugh=>strikethrough
* Added debugDisplay attributes to help with debugging
Copy link
Contributor

coderabbitai bot commented Nov 6, 2024

Walkthrough

This pull request introduces multiple changes across various files in the Consolonia project, focusing on improving text rendering and handling, particularly for complex emojis and glyphs. Key modifications include the correction of constants, the introduction of new properties and methods to support emoji rendering, and enhancements to existing methods for better clarity and functionality. The project dependencies are also updated, reflecting a shift in library usage.

Changes

File Change Summary
src/Consolonia.Core/Drawing/DrawingContextImpl.cs Corrected StrikthroughThickness to StrikethroughThickness, added GlyphMetrics dictionary, restructured DrawBitmap, renamed DrawStringInternal parameter from str to text, refined tab handling, and adjusted pixel logic.
src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs Added DebuggerDisplay, replaced GetCharacter with GetBoxSymbol, introduced Text and Width properties, and changed return type of UpRightDownLeftFromPattern method.
src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs Removed GetCharacter method, added Text and Width properties, and updated comments on Blend method.
src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs Added DebuggerDisplay, removed constructors accepting char and byte, updated Blend method for improved blending logic.
src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackground.cs Added DebuggerDisplay attribute for better debugging representation.
src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs Added DebuggerDisplay, updated constructor to handle null symbol, and modified Blend method to always attempt blending.
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs Added parameterless constructor, updated constructors, and modified IsWhiteSpace and Blend methods.
src/Consolonia.Core/Drawing/RenderTarget.cs Changed _cache type from char to string, updated RenderToDevice method for new type handling.
src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs Introduced TestEmoji, updated constructor for UTF-8 encoding, and modified Print method for text width calculation.
src/Consolonia.Core/Text/GlyphTypeface.cs Added constant Glyph, updated glyph retrieval methods to return the constant instead of actual glyphs.
src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml Updated TextBlock elements and added new elements for emojis and international characters.
src/Tests/Consolonia.TestsCore/UnitTestConsole.cs Updated Print method for character handling, modified PrintBuffer method, and added SupportsComplexEmoji property.
src/Consolonia.Core/Text/GlyphRunImpl.cs Removed GlyphIndices property, updated GlyphInfos property to be IReadOnlyList<GlyphInfo>, and simplified Bounds calculation.
src/Consolonia.Core/Text/TextShaper.cs Removed Convert method and updated ShapeText to simplify text shaping logic.
src/Consolonia.Themes.TurboVision/Templates/Controls/Helpers/SymbolsControl.cs Added using directive and modified Text property setter to use ShapeText.
src/Consolonia.Core/Consolonia.Core.csproj Removed NullLib.ConsoleEx reference, added Unicode.net and Wcwidth references.
src/Consolonia.Core/Drawing/ConsoleBrush.cs Added DebuggerDisplay attribute for better debugging output.
src/Tests/Consolonia.GalleryTests/TextBlockTests.cs Updated assertions in PerformSingleTest method for more diverse text validation.
src/Consolonia.Core/Helpers/Extensions.cs Added Print, GetGlyphs, and MeasureText methods for enhanced text handling.
src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs Removed UTF-8 encoding setting in constructor.
src/Consolonia.Core/Infrastructure/IConsole.cs Added SupportsComplexEmoji property.
src/Consolonia.PlatformSupport/WindowsConsole.cs Removed UTF-8 encoding setting.

Possibly related PRs

🐰 In the garden of code, we hop and play,
With emojis and glyphs, we brighten the day!
Strikethroughs corrected, and pixels refined,
In Consolonia's world, joy we find!
So let’s celebrate changes, both big and small,
For in this code garden, there's magic for all! 🌼✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (11)
src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (1)

14-18: Consider enhancing method documentation.

While the addition of XML documentation is good, the method's documentation could be more descriptive:

  • What does "blend" mean in this context?
  • What is the expected behavior when blending symbols?
  • What are the constraints or requirements for the symbolAbove parameter?
  • What type of ISymbol is returned?

Consider expanding the documentation like this:

 /// <summary>
-/// Blend 2 symbols together
+/// Combines two symbols to create a composite symbol, typically used for overlapping UI elements
 /// </summary>
-/// <param name="symbolAbove"></param>
+/// <param name="symbolAbove">The symbol to blend on top of the current symbol</param>
-/// <returns></returns>
+/// <returns>A new ISymbol representing the blended result</returns>
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1)

21-21: Consider using an auto-property

The current property implementation can be simplified.

-        public Rune Rune => _rune;
+        public Rune Rune { get; }
🧰 Tools
🪛 GitHub Check: build

[notice] 21-21:
"[ConvertToAutoPropertyWhenPossible] Convert into auto-property" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs(21,21)

src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml (2)

33-37: LGTM! Consider adding tooltips for accessibility.

The surrogate characters demonstration is well-structured and includes good examples of both emoji and complex script characters.

Consider adding tooltips to explain what each character represents, especially for the Osage script example:

-            <SelectableTextBlock Text="𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟"/>
+            <SelectableTextBlock Text="𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟" ToolTip="Example of Osage script (Native American language)"/>

38-41: Consider improving the RTL demonstration clarity.

While the RTL implementation is correct, the current layout might be confusing to users. The label "RightToLeft:" appears at the end due to the RTL flow direction.

Consider this alternative structure for better clarity:

-        <WrapPanel FlowDirection="RightToLeft">
-            <SelectableTextBlock Text="من اليمين إلى اليسار" />
-            <SelectableTextBlock Text="RightToLeft:"/>
-        </WrapPanel>
+        <StackPanel>
+            <TextBlock Text="Right-to-Left Text Example:" />
+            <WrapPanel FlowDirection="RightToLeft">
+                <SelectableTextBlock Text="من اليمين إلى اليسار" ToolTip="Arabic text: 'From right to left'" />
+            </WrapPanel>
+        </StackPanel>

This change would:

  1. Keep the label outside the RTL context for better readability
  2. Add a tooltip explaining the Arabic text
  3. Use a more descriptive label
src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (2)

147-147: Document the caret character choice

The Unicode character 'Ꮖ' (Cherokee Letter Tsi) is being used as a caret symbol. Consider adding a comment explaining why this specific character was chosen, or define it as a named constant for better maintainability.

-    Rune rune = pixel.IsCaret ? new Rune('Ꮖ') : pixel.Foreground.Symbol.Rune;
+    private const char CARET_CHAR = 'Ꮖ'; // Cherokee Letter Tsi - chosen for its distinct visual appearance
+    Rune rune = pixel.IsCaret ? new Rune(CARET_CHAR) : pixel.Foreground.Symbol.Rune;

148-148: Address the cursor drawing TODO comment

The comment indicates an unresolved issue with cursor drawing. This should be investigated and resolved, especially since it's related to the caret functionality we're currently modifying.

Would you like me to help investigate the cursor drawing issue or create a GitHub issue to track this?

src/Consolonia.Core/Drawing/RenderTarget.cs (2)

137-141: Improve tuple declaration readability.

While the change to use Rune is correct, the tuple declaration could be more readable.

Consider this more concise and aligned format:

-(Color background, Color foreground, FontWeight weight, FontStyle style, TextDecorationCollection
-    textDecorations, Rune rune) 
-        pixelSpread = (pixel.Background.Color, pixel.Foreground.Color, pixel.Foreground.Weight,
-        pixel.Foreground.Style, pixel.Foreground.TextDecorations,
-        pixel.Foreground.Symbol.Rune);
+(Color background, Color foreground, FontWeight weight, FontStyle style,
+ TextDecorationCollection textDecorations, Rune rune) pixelSpread = (
+    pixel.Background.Color,
+    pixel.Foreground.Color,
+    pixel.Foreground.Weight,
+    pixel.Foreground.Style,
+    pixel.Foreground.TextDecorations,
+    pixel.Foreground.Symbol.Rune
+);

24-24: Consider performance implications of Rune usage.

While the switch to Rune is necessary for proper Unicode support, it's worth noting that operations on Rune might have different performance characteristics compared to char. Consider:

  1. Benchmarking the rendering performance with various Unicode ranges
  2. Adding performance tests to catch any regressions
  3. Documenting any performance trade-offs made for Unicode support

Would you like help setting up performance benchmarks for these changes?

Also applies to: 137-141, 207-210

src/Consolonia.Core/Drawing/DrawingContextImpl.cs (2)

165-177: Consider simplifying the nested loop structure

While the current implementation is correct, consider extracting the pixel drawing logic into a separate method to reduce nesting and improve readability.

-for (int x = 0; x < width; x++)
-    for (int y = 0; y < height; y++)
-    {
-        int px = (int)(r2.TopLeft.X + x);
-        int py = (int)(r2.TopLeft.Y + y);
-
-        ConsoleBrush backgroundBrush = ConsoleBrush.FromPosition(brush, x, y, (int)width, (int)height);
-        CurrentClip.ExecuteWithClipping(new Point(px, py), () =>
-        {
-            _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py),
-                (pixel, bb) => pixel.Blend(new Pixel(new PixelBackground(bb.Mode, bb.Color))),
-                backgroundBrush);
-        });
-    }
+private void DrawRectanglePixel(int x, int y, Rect r2, IBrush brush, double width, double height)
+{
+    int px = (int)(r2.TopLeft.X + x);
+    int py = (int)(r2.TopLeft.Y + y);
+    
+    ConsoleBrush backgroundBrush = ConsoleBrush.FromPosition(brush, x, y, (int)width, (int)height);
+    CurrentClip.ExecuteWithClipping(new Point(px, py), () =>
+    {
+        _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py),
+            (pixel, bb) => pixel.Blend(new Pixel(new PixelBackground(bb.Mode, bb.Color))),
+            backgroundBrush);
+    });
+}
+
+for (int x = 0; x < width; x++)
+    for (int y = 0; y < height; y++)
+        DrawRectanglePixel(x, y, r2, brush, width, height);

513-514: Extract tab size as a constant

The tab size (8) should be extracted as a named constant at the class level for better maintainability and configuration.

+    private const int TabSize = 8;
-    const int tabSize = 8;
src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (1)

24-24: Simplify object creation using target-typed 'new'

Since the type Rune is evident from the property return type, you can use a target-typed new expression to make the code more concise.

-public Rune Rune => new Rune(GetBoxSymbol());
+public Rune Rune => new(GetBoxSymbol());
🧰 Tools
🪛 GitHub Check: build

[notice] 24-24:
"[ArrangeObjectCreationWhenTypeEvident] Redundant type specification" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs(24,33)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d03adf2 and 9446c9b.

📒 Files selected for processing (12)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (7 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (4 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (1 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs (2 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackground.cs (1 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs (1 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1 hunks)
  • src/Consolonia.Core/Drawing/RenderTarget.cs (4 hunks)
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (1 hunks)
  • src/Consolonia.Core/Text/GlyphTypeface.cs (1 hunks)
  • src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml (1 hunks)
  • src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackground.cs
  • src/Consolonia.Core/Text/GlyphTypeface.cs
🧰 Additional context used
🪛 GitHub Check: build
src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs

[notice] 24-24:
"[ArrangeObjectCreationWhenTypeEvident] Redundant type specification" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs(24,33)

src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs

[warning] 14-14:
"[ConstantNullCoalescingCondition] '??' left operand is never null" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs(14,32)

src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs

[notice] 21-21:
"[ConvertToAutoPropertyWhenPossible] Convert into auto-property" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs(21,21)

🔇 Additional comments (19)
src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (2)

1-1: LGTM! Appropriate namespace import for Rune support.

The addition of System.Text import is necessary for the Rune type, which provides better Unicode handling capabilities including surrogate pairs.


7-10: Excellent improvement to Unicode handling.

The transition from GetCharacter() to Rune property is a solid architectural choice that better supports Unicode surrogate pairs and follows modern C# practices.

Let's verify the impact of this breaking change:

✅ Verification successful

Breaking change has been properly implemented across the codebase

The verification shows that all implementations of ISymbol (SimpleSymbol and DrawingBoxSymbol) have correctly implemented the Rune property, and there are no remaining references to the old GetCharacter() method. The change has been consistently applied throughout the codebase:

  • SimpleSymbol implements Rune property returning _rune field
  • DrawingBoxSymbol implements Rune property using GetBoxSymbol()
  • All usages across the codebase reference the new Rune property
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all implementations of ISymbol to ensure they're updated
# Expected: All implementations should now implement the Rune property instead of GetCharacter

# Search for ISymbol implementations
ast-grep --pattern 'class $_ : $$$ISymbol$$$'

# Search for any remaining GetCharacter references that might need updating
rg "GetCharacter"

Length of output: 65


Script:

#!/bin/bash
# Let's try a more comprehensive search approach

# Find all files that might contain ISymbol implementations
fd "\.cs$" | xargs rg -l "ISymbol"

# Search for class implementations with different syntax
rg "class.*:.*ISymbol" -A 5

# Look for files containing "Rune" to see the implementation
rg "Rune" -A 2

Length of output: 7419

src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (3)

1-6: LGTM! Good debugging improvements

The addition of the DebuggerDisplay attribute will improve debugging experience by showing the actual Unicode character.


23-28: LGTM! Clean and efficient implementation

The simplified implementations of IsWhiteSpace() and Blend() are clear and leverage the Rune type's built-in functionality correctly.


9-19: Verify surrogate pair handling

The switch to Rune type is a good improvement for Unicode support. The implementation looks correct, but let's verify the surrogate pair handling.

src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs (2)

7-7: LGTM: Improved debugging display for Unicode characters

The new DebuggerDisplay attribute enhances debugging by showing the actual Unicode character through the Rune property, which is particularly useful when working with surrogate pairs and emojis.


Line range hint 39-46: Verify Unicode blending behavior

The Blend method should be tested with various Unicode scenarios:

  • Surrogate pairs
  • Right-to-left text
  • Combining characters

Let's verify the Unicode handling in the codebase:

✅ Verification successful

Let me gather more specific information about the Unicode handling implementation.


Based on the gathered information, I can now provide the final response:

Unicode handling is properly implemented with Rune support

The codebase correctly handles Unicode through the following implementations:

  • Uses System.Text.Runes for character representation instead of raw char
  • Implements proper blending through ISymbol interface with Rune property
  • Handles control characters and zero-width characters (e.g., \u200B)
  • Supports box-drawing characters with proper Unicode code points

The concerns about RTL and surrogate pairs are addressed by the framework-level Rune implementation, which inherently handles these cases correctly.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for Unicode-related test cases and handling

# Look for Unicode test cases
echo "Searching for Unicode-related tests..."
rg -l "surrogate|emoji|RTL|combining\scharacter" --type cs

# Check for Unicode-specific handling in Symbol implementations
echo "Checking Symbol implementations for Unicode handling..."
ast-grep --pattern 'class $_ : ISymbol {
  $$$
  Rune $_ { get; }
  $$$
}'

Length of output: 386


Script:

#!/bin/bash
# Check Symbol.Blend implementation and related tests
echo "Checking Symbol.Blend implementation..."
rg -A 10 "Blend\(" --type cs

# Look for Rune-related tests
echo "Checking Rune-related tests..."
rg -A 5 "Rune" --type cs --glob "*Test*.cs"

# Check for any Unicode character handling
echo "Checking Unicode character handling..."
rg -A 5 "char|Char|Unicode" --type cs --glob "src/Consolonia.Core/Drawing/**/*.cs"

Length of output: 29330

🧰 Tools
🪛 GitHub Check: build

[warning] 14-14:
"[ConstantNullCoalescingCondition] '??' left operand is never null" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs(14,32)

src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs (3)

2-11: LGTM! Well-structured debugging support added.

The DebuggerDisplay attribute provides a clear and informative view of the pixel's state during debugging, showing both the Unicode character (via Rune) and its associated colors.


25-27: LGTM! Good improvement for Unicode support.

The switch to Rune from char is a positive change that properly handles surrogate pairs and other Unicode sequences.


25-27: Verify the removal of byte-based drawing box symbol constructor.

The removal of public Pixel(byte drawingBoxSymbol, Color foregroundColor) constructor might affect existing box-drawing functionality. Let's verify all usages have been properly updated.

✅ Verification successful

Based on the search results, I can now generate the final response:

The removal of byte-based constructor is safe as the box-drawing functionality has been properly migrated

The codebase shows that box-drawing symbols are now handled through the DrawingBoxSymbol struct (src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs), which implements ISymbol. The removed constructor is not used anywhere in the codebase, and box drawing is now done through the SimpleSymbol or DrawingBoxSymbol types, which are properly passed to the remaining Pixel constructors.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for potential usages of the removed constructor with box drawing symbols
rg -l "new Pixel\(\s*0x[0-9a-fA-F]+\s*,|new Pixel\(\s*[0-9]+\s*," 

# Search for box drawing related code that might need updates
rg -i "box.*draw|draw.*box|[│─┌┐└┘├┤┬┴┼]"

Length of output: 4879

src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (2)

Line range hint 89-92: LGTM: KeyInput method signature enhancement

The addition of the optional modifiers parameter with a default value maintains backward compatibility while providing enhanced input handling capabilities.


147-149: LGTM: Proper Unicode handling with Rune

The switch to using Rune instead of char is a solid improvement that properly supports Unicode surrogate pairs and complex characters. The implementation correctly handles both the caret and regular symbols.

src/Consolonia.Core/Drawing/RenderTarget.cs (2)

207-210: Clarify handling of specific Unicode characters.

The control character handling is correct, but there's a commented condition about specific Chinese characters ('保' or '哥'). This suggests potential issues with certain Unicode ranges that should be addressed.

Let's check for similar patterns in tests:

#!/bin/bash
# Description: Look for Unicode-related test cases
# Expect: Comprehensive Unicode testing including Chinese characters

rg -g '*Test*.cs' '保|哥|Rune.IsControl'

Consider:

  1. Documenting why these specific characters were problematic
  2. Adding comprehensive tests for various Unicode ranges
  3. Creating a configuration option for character substitution rules

24-24: LGTM! Verify cache initialization.

The switch from char to Rune in the cache type is appropriate for proper Unicode support. This change enables handling of surrogate pairs and other Unicode sequences correctly.

Let's verify the cache initialization is consistent:

✅ Verification successful

The previous command had syntax issues. Let's try a broader search to understand the cache initialization and usage patterns. We'll look for:

  1. How _cache is initialized
  2. Any Rune-related array initialization
  3. The field declaration pattern itself

This will help us verify if the change from char to Rune is consistently implemented throughout the codebase.


Let's try a broader search pattern to catch any cache-related code and Rune array initialization. The previous patterns might have been too specific. Also, let's look at the actual file content to understand the context better.


Cache initialization and usage is properly implemented with Rune type

The verification shows that:

  1. The cache field is correctly declared with Rune type
  2. Cache initialization in InitializeCache method properly uses the same tuple type with Rune
  3. Cache usage in RenderToDevice method correctly compares and assigns Rune values
  4. The implementation is consistent throughout the file with no remnants of char-based cache
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining char usages in cache-related code
# Expect: No direct char usage in cache initialization or access

rg -g '*.cs' 'new.*char.*\[,\]|_cache.*=.*char' 

Length of output: 134


Script:

#!/bin/bash
# Let's check the cache initialization and usage patterns more broadly
rg -g '*.cs' '_cache\s*=\s*new' -A 3

# Also check for Rune-related array initialization
rg -g '*.cs' 'new\s+(?:Rune|System\.Text\.Rune).*\[,\]' -A 3

# Look for cache field declaration and initialization
ast-grep --pattern 'private $_[,] _cache;'

Length of output: 146


Script:

#!/bin/bash
# Let's try a simpler approach to find cache-related code
rg -g '*.cs' '_cache' -B 2 -A 2

# Also search for any Rune array initialization with less strict pattern
rg -g '*.cs' 'new.*Rune.*\[' -B 2 -A 2

# Look at the RenderTarget.cs file directly to see initialization
cat src/Consolonia.Core/Drawing/RenderTarget.cs

Length of output: 9779

src/Consolonia.Core/Drawing/DrawingContextImpl.cs (4)

27-27: LGTM: Spelling correction

The constant name has been correctly updated from StrikthroughThickness to StrikethroughThickness.


73-102: LGTM: Improved bitmap drawing implementation

The changes enhance code readability through:

  • Clear comments explaining the quad pixel logic
  • Better variable naming
  • Structured code organization

153-157: LGTM: Proper ISceneBrush content handling

The implementation correctly handles the scene brush content with proper null checking and scoping.


503-504: LGTM: Improved Unicode support

The implementation now correctly uses EnumerateRunes() for proper handling of Unicode surrogate pairs and emojis.

src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (1)

101-114: Unicode handling enhancements are correctly implemented

The updates in the Print method effectively handle complex Unicode characters, ensuring accurate caret positioning when printing text that includes multi-byte characters.

tomlm and others added 2 commits November 6, 2024 09:25
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (13)
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (3)

9-9: Consider adding XML documentation.

While the field implementation is correct, adding XML documentation would help explain the purpose of using Rune and the significance of the null character initialization.

+/// <summary>
+/// Represents a Unicode character using a Rune type for proper surrogate pair support.
+/// Initialized to null character by default.
+/// </summary>
 private readonly Rune _rune = new Rune('\0');

11-13: Remove redundant initialization in parameterless constructor.

The field is already initialized with new Rune('\0'), making the constructor's initialization redundant.

 public SimpleSymbol()
 {
-    _rune = new Rune('\0');
 }

27-27: Consider improving Blend method readability.

While the logic is correct, the expression could be more explicit about its intent.

-=> (symbolAbove.Rune.Value != '\0') ? symbolAbove : this;
+=> !symbolAbove.Rune.IsEmpty ? symbolAbove : this;
src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs (2)

Line range hint 22-22: Update outdated Unicode documentation

The comment "working with 16 bit unicode only" is now incorrect since the Symbol property uses Rune which supports the full Unicode range including surrogate pairs.

-        public ISymbol Symbol { get; } //now working with 16 bit unicode only for simplicity //todo: reference here
+        public ISymbol Symbol { get; } // Supports full Unicode range including surrogate pairs

Line range hint 39-47: Clean up redundant checks and outdated comments

The Blend method contains:

  1. A redundant null check since PixelForeground constructor already ensures Symbol is never null
  2. An outdated TODO comment about default(char) which is no longer relevant with Rune implementation
         public PixelForeground Blend(PixelForeground pixelAboveForeground)
         {
-            //todo: check default(char) is there
             ISymbol symbolAbove = pixelAboveForeground.Symbol;
-            ArgumentNullException.ThrowIfNull(symbolAbove);

             ISymbol newSymbol = Symbol.Blend(ref symbolAbove);
src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (2)

21-21: Consider adding parameter validation in the constructor.

While the initialization of _caretPosition is correct, the constructor should validate the width and height parameters to prevent creation of invalid buffers.

 public PixelBuffer(ushort width, ushort height)
 {
+    if (width == 0 || height == 0)
+        throw new ArgumentException("Width and height must be greater than zero");
     Width = width;
     Height = height;
     _buffer = new Pixel[width, height];
     _caretPosition = new PixelBufferCoordinate(0, 0);
 }

100-104: Consider parallel processing for large buffers.

While the loop restructuring improves readability, consider adding parallel processing support for better performance with large buffers.

 public void ForeachReadonly(Action<PixelBufferCoordinate, Pixel> action)
 {
-    for (ushort j = 0; j < Height; j++)
-        for (ushort i = 0; i < Width; i++)
-        {
-            Pixel pixel = this[(PixelBufferCoordinate)(i, j)];
-            action(new PixelBufferCoordinate(i, j), pixel);
-        }
+    Parallel.For(0, Height, j =>
+    {
+        for (ushort i = 0; i < Width; i++)
+        {
+            Pixel pixel = this[(PixelBufferCoordinate)(i, (ushort)j)];
+            action(new PixelBufferCoordinate(i, (ushort)j), pixel);
+        }
+    });
 }

Note: Only use parallel processing if the action delegate is thread-safe and the buffer size justifies the overhead.

src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs (1)

69-73: Consider improving transparency handling readability.

While the logic is correct, consider these improvements:

  1. The comment could be more precise: "Skip blending if the foreground is transparent"
  2. The complex transparency check could be extracted to a descriptive method

Consider this refactor:

-    // if the foreground is transparent, ignore pixelAbove foreground.
-    newForeground = pixelAbove.Foreground.Color != Colors.Transparent ? Foreground.Blend(pixelAbove.Foreground) : Foreground;
-    
-    // background is transparent, ignore pixelAbove background.
-    newBackground = Background; 
+    // Skip blending if the foreground is transparent
+    newForeground = ShouldBlendForeground(pixelAbove) 
+        ? Foreground.Blend(pixelAbove.Foreground) 
+        : Foreground;
+    // Background remains unchanged when transparent
+    newBackground = Background;

+private bool ShouldBlendForeground(Pixel pixelAbove) => 
+    pixelAbove.Foreground.Color != Colors.Transparent;
src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (1)

151-153: Consider documenting the caret character choice.

While the change to Rune is good, the choice of 'Ꮖ' (Cherokee letter 'TLI') as a caret character is unusual. Consider:

  1. Documenting why this specific character was chosen
  2. Using a more conventional caret character like '^' or '▊' (block cursor)

Also, there's a TODO comment about cursor drawing issues that should be tracked.

Would you like me to:

  1. Suggest alternative caret characters that are more conventional?
  2. Help create an issue to track the cursor drawing problem mentioned in the TODO?
src/Consolonia.Core/Drawing/DrawingContextImpl.cs (4)

153-157: Consider consistent brace formatting.

The opening brace could be on the same line as the case statement to match the codebase style.

-                    case ISceneBrush sceneBrush:
-                        {
+                    case ISceneBrush sceneBrush: {

165-177: Consider addressing the ReSharper TODO comment.

The comment indicates that the closure access should be replaced with a parameter. This would improve code quality and remove the need for the ReSharper disable directive.

-                    // ReSharper disable once AccessToModifiedClosure todo: pass as a parameter
-                    _pixelBuffer.Set((PixelBufferCoordinate)h,
-                        (pixel, bb) => pixel.Blend(new Pixel(new PixelBackground(bb.Mode, bb.Color))),
-                        backgroundBrush);
+                    var currentBrush = backgroundBrush;
+                    _pixelBuffer.Set((PixelBufferCoordinate)h,
+                        (pixel, bb) => pixel.Blend(new Pixel(new PixelBackground(bb.Mode, bb.Color))),
+                        currentBrush);

512-524: Consider making tab size configurable.

The tab size is currently hardcoded to 8. Consider making this configurable through a constant or configuration setting for better flexibility.

-            const int tabSize = 8;
+            private const int DefaultTabSize = 8;
+            private readonly int _tabSize;

528-534: Remove commented code for newline handling.

The commented code for newline handling should be removed as it's not being used and includes uncertainty about its necessity.

-                        {
-                            /* it's not clear if we need to draw anything. Cursor can be placed at the end of the line
-                             var consolePixel =  new Pixel(' ', foregroundColor);

-                            _pixelBuffer.Set((PixelBufferCoordinate)characterPoint,
-                                (oldPixel, cp) => oldPixel.Blend(cp), consolePixel);*/
-                        }
+                        {
+                            // Newline handling is managed by cursor positioning
+                        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9446c9b and 637747c.

📒 Files selected for processing (7)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (8 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs (3 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (3 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs (1 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1 hunks)
  • src/Consolonia.Core/Drawing/RenderTarget.cs (4 hunks)
  • src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (2 hunks)
🔇 Additional comments (19)
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (3)

1-6: LGTM! Good addition of debugging support.

The DebuggerDisplay attribute will improve debugging experience by showing the actual Rune value.


21-21: LGTM! Clean property implementation.

The read-only property provides appropriate access to the internal Rune value.


1-28: Verify Unicode support implementation across the codebase.

Let's ensure the Rune type is consistently used across the codebase for Unicode character handling.

✅ Verification successful

Let me gather more information about the Unicode handling implementation.


Based on the gathered information, I can now provide the final response:

Unicode support implementation is properly integrated across the codebase

The implementation consistently uses Rune type for Unicode character handling:

  • Core implementation in SimpleSymbol correctly uses Rune for character storage and operations
  • Proper Unicode handling in drawing context and render targets
  • Special handling for complex Unicode characters in console output
  • Correct implementation of control character handling and whitespace detection
  • Box-drawing characters properly implemented using Rune
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent Unicode handling implementation

# Check for any remaining direct char usage in symbol-related files
echo "Checking for potential missed char to Rune conversions..."
rg -t cs "char\s+\w+\s*[;=]" --glob "**/*Symbol*.cs"

# Look for potential Unicode handling in tests
echo "Checking for Unicode test coverage..."
rg -t cs "TestMethod|Theory|Fact" -C 5 --glob "**/test/**/*Unicode*.cs"

# Verify Rune usage in related components
echo "Verifying Rune usage in related components..."
ast-grep --pattern 'class $_ { 
  $$$
  char $_ 
  $$$
}'

Length of output: 648


Script:

#!/bin/bash
# Search for all Rune usages to verify consistent implementation
echo "Checking Rune usage across the codebase..."
rg -t cs "Rune" -B 2 -A 2

# Check for any Unicode-related tests
echo "Checking for any Unicode-related tests..."
rg -t cs "Unicode|Rune" --glob "**/test/**/*.cs"

# Look for other symbol implementations
echo "Checking other symbol implementations..."
ast-grep --pattern 'struct $_ : ISymbol {
  $$$
}'

Length of output: 12422

src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs (2)

2-2: LGTM: Improved debugging visibility for Unicode characters

The new DebuggerDisplay attribute effectively shows the Unicode character representation using the Rune property, which aligns well with the PR's Unicode support objectives.

Also applies to: 7-7


Line range hint 7-47: Verify consistent Rune implementation across related components

Since this struct is transitioning to use Rune for Unicode support, we should verify that all related components handle Rune properly.

✅ Verification successful

Rune implementation is consistent across the codebase

The verification shows that:

  • ISymbol interface properly defines Rune property
  • All implementations (SimpleSymbol, DrawingBoxSymbol) correctly use Rune
  • The char usages found are for specific purposes:
    • Input handling in platform-specific code
    • Drawing context's quad pixel characters (block elements for drawing)
    • These usages are appropriate and don't need conversion to Rune
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential inconsistencies in Rune implementation

# Look for other implementations of ISymbol to ensure they're updated for Rune
echo "Checking ISymbol implementations:"
ast-grep --pattern 'class $_ : ISymbol'

# Look for direct char usage that might need to be converted to Rune
echo "Checking for potential char usage that might need Rune conversion:"
rg "char\s+\w+\s*[=;]" --type csharp

Length of output: 913


Script:

#!/bin/bash
# Let's check ISymbol interface and its usages to understand the Rune implementation
echo "Checking ISymbol interface definition:"
rg "interface ISymbol" -A 10 --type csharp

# Check for Rune usage in the codebase
echo "Checking Rune usage:"
rg "Rune" --type csharp

# Check specific files that showed char usage for context
echo "Checking DrawingContextImpl.cs for context:"
rg "GetQuadPixelCharacter|GetColorsPattern" -A 5 --type csharp

Length of output: 6677

src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (1)

14-14: LGTM: Field addition follows best practices.

The new private field _caretPosition is appropriately encapsulated and follows C# naming conventions.

src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs (2)

2-3: LGTM! Good debugging enhancement.

The addition of the DebuggerDisplay attribute with Rune property access will improve debugging experience when dealing with Unicode characters.

Also applies to: 11-11


20-22: LGTM! Good Unicode support enhancement.

The switch from char to Rune is the correct approach for proper Unicode support, especially for surrogate pairs and emojis.

Let's verify the impact of removing the byte-based constructor:

src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (2)

61-71: LGTM! Improved Unicode handling with Rune support.

The change from character-based to Rune-based iteration is a solid improvement that properly handles surrogate pairs and other complex Unicode sequences. The use of EnumerateRunes() ensures correct Unicode character boundaries are respected.


Line range hint 134-134: LGTM! Enhanced input testing capabilities.

The addition of the optional modifiers parameter with a default value maintains backward compatibility while enabling more comprehensive input testing scenarios.

src/Consolonia.Core/Drawing/RenderTarget.cs (5)

24-24: LGTM: Appropriate type change for Unicode support

The change from char to Rune in the cache array is correct and necessary for proper Unicode surrogate pair support.


100-101: LGTM: Consistent cache initialization

The initialization change correctly reflects the type update from char to Rune.


134-135: LGTM: Proper fallback character handling

Good choice of using '░' as a fallback character with proper Rune construction.


137-141: LGTM: Improved tuple structure and naming

Good improvements:

  • Proper Rune type usage for Unicode support
  • Better tuple field naming for improved readability

207-210: Clarify character handling strategy

The control character handling looks good, but there are a few points to consider:

  1. There's a commented code fragment suggesting special handling for specific characters ('保', '哥'). Should this still be implemented?
  2. The comment "some terminals do not print \0" could be more specific about which terminals and conditions.

Let's check for any other special character handling in the codebase:

Consider:

  1. Adding a comment explaining which terminals have issues with control characters
  2. Creating a dedicated method for character substitution logic
  3. If needed, restore special handling for CJK characters with proper documentation

Example refactor:

-                var rune = pixel.Foreground.Symbol.Rune;
-                if (Rune.IsControl(rune)) /*|| character is '保' or '哥'*/
-                    rune = new Rune(' '); // some terminals do not print \0
-                _stringBuilder.Append(rune);
+                var rune = pixel.Foreground.Symbol.Rune;
+                _stringBuilder.Append(GetSafeCharacter(rune));
+
+                private static Rune GetSafeCharacter(Rune rune)
+                {
+                    // Some terminal emulators (e.g., Windows Console) cannot properly handle control characters
+                    if (Rune.IsControl(rune))
+                        return new Rune(' ');
+                    return rune;
+                }
✅ Verification successful

Control character handling is appropriate, commented code can be removed

The current implementation of control character handling is correct and consistent with the codebase:

  1. The control character check using Rune.IsControl() is the standard approach used throughout the codebase
  2. The space character substitution is a proper fallback, as evidenced by similar patterns in test cases
  3. The commented code about CJK characters ('保', '哥') appears to be obsolete and can be safely removed, as there's no special handling of these characters elsewhere in the codebase
  4. The comment about terminals not printing '\0' is accurate, as shown by the test cases where control characters are explicitly skipped
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for special character handling patterns
rg -l "IsControl|Rune.*['\u4fdd\u54e5']|// some terminals"

Length of output: 468


Script:

#!/bin/bash
# Let's check the actual usage of Rune.IsControl and special character handling
rg -A 3 "IsControl|Rune.*['\u4fdd\u54e5']|// some terminals" --no-filename

# Also check for any related tests or documentation
fd -e md -e cs -x grep -l "terminal.*character\|control.*character\|special.*character"

Length of output: 2312


Script:

#!/bin/bash
# Let's check the test cases and documentation for character handling
rg -A 5 "control.*character|special.*character" ./src/Tests/Consolonia.TestsCore/UnitTestConsole.cs

# Also check GlyphTypeface for any relevant character handling documentation
rg -A 5 "control.*character|special.*character" ./src/Consolonia.Core/Text/GlyphTypeface.cs

Length of output: 779

src/Consolonia.Core/Drawing/DrawingContextImpl.cs (4)

27-27: LGTM: Spelling correction from "Strikthorugh" to "Strikethrough".

The constant name has been corrected to use proper spelling, improving code readability.


73-102: LGTM: Improved code readability with better comments and formatting.

The changes enhance code maintainability by:

  • Adding clear comments explaining the quad pixel logic
  • Using more descriptive variable names
  • Better formatting of the nested loops

502-503: LGTM: Improved Unicode support using Rune.

The change to use EnumerateRunes() properly handles Unicode characters, including surrogate pairs and emojis.


541-547: LGTM: Proper handling of typeface styles.

The pixel creation now correctly includes typeface style and weight information, ensuring proper rendering of styled text.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (5)
src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (2)

7-10: Enhance property documentation

While the documentation is present, it could be more descriptive to help implementers understand:

  • The purpose of this property in the context of Unicode support
  • Any special handling required for surrogate pairs

Consider expanding the documentation:

 /// <summary>
-    The rune for the symbol
+    The Unicode character (rune) representing this symbol. Supports full Unicode range
+    including surrogate pairs and emoji sequences.
 /// </summary>

14-18: Improve Blend method documentation

The current documentation lacks essential details about the blending operation.

Consider expanding the documentation:

 /// <summary>
-    Blend 2 symbols together
+    Combines this symbol with another symbol placed above it, following
+    specific blending rules for Unicode characters and their visual representation.
 /// </summary>
 /// <param name="symbolAbove">
+    The symbol to blend with the current symbol. This symbol is considered
+    to be visually above the current symbol.
 /// </param>
-/// <returns></returns>
+/// <returns>A new symbol representing the result of blending the two symbols</returns>
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (2)

19-19: Consider adding XML documentation.

The Rune property implementation is correct and immutable. Consider adding XML documentation to describe its purpose and the significance of the '\0' default value.

+/// <summary>
+/// Gets the Unicode character represented by this symbol.
+/// A value of '\0' indicates no character (empty symbol).
+/// </summary>
 public Rune Rune { get; } = new('\0');

22-29: Consider improving Blend method implementation.

While the logic is correct, there are a few suggestions for improvement:

  1. The ref keyword on the parameter appears unnecessary since the value isn't modified
  2. The method's purpose could be more explicit with XML documentation
-        public ISymbol Blend(ref ISymbol symbolAbove)
+        /// <summary>
+        /// Combines this symbol with the symbol above it, preferring the above symbol if it's not empty.
+        /// </summary>
+        /// <param name="symbolAbove">The symbol to blend with</param>
+        /// <returns>The resulting blended symbol</returns>
+        public ISymbol Blend(ISymbol symbolAbove)
         {
             return symbolAbove.Rune.Value != '\0' ? symbolAbove : this;
         }
src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (1)

151-153: Review caret character choice and cursor drawing.

A few observations:

  1. Using Cherokee letter TSI ('Ꮖ') as a caret character seems unusual. Consider using a more conventional character like '▊' (U+258A) or '│' (U+2502).
  2. The TODO comment about cursor drawing should be addressed or tracked.

Would you like me to:

  1. Suggest alternative caret characters that are more conventional for console applications?
  2. Help create an issue to track the cursor drawing problem?
-    Rune rune = pixel.IsCaret ? new Rune('Ꮖ') : pixel.Foreground.Symbol.Rune;
+    Rune rune = pixel.IsCaret ? new Rune('▊') : pixel.Foreground.Symbol.Rune;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 637747c and 559fe7b.

📒 Files selected for processing (9)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (7 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (3 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (1 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs (3 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (2 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1 hunks)
  • src/Consolonia.Core/Drawing/RenderTarget.cs (4 hunks)
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (1 hunks)
  • src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs
  • src/Consolonia.Core/Drawing/RenderTarget.cs
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs
🧰 Additional context used
🪛 GitHub Check: build
src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs

[warning] 81-81:
"[RedundantArgumentDefaultValue] The parameter 'isCaret' has the same default value" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs(81,79)

🔇 Additional comments (11)
src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (2)

1-1: LGTM: Required import for Rune type

The System.Text namespace import is necessary for the Rune type usage.


10-10: Verify impact of breaking interface change

The replacement of GetCharacter() with Rune property is a breaking change. Let's verify all implementations are updated.

✅ Verification successful

Breaking interface change has been properly implemented

From the git history and codebase analysis, we can confirm:

  1. The change from GetCharacter() to Rune property was part of a planned feature to "Add support for Surrogate sequences" (commit f087bf5)
  2. All implementations of ISymbol (SimpleSymbol, DrawingBoxSymbol) have been updated to use the new Rune property
  3. No remaining references to GetCharacter() exist in the codebase

The breaking change was properly implemented across all dependent code.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing implementations of ISymbol
ast-grep --pattern 'class $_ : $$$ISymbol$$$'
rg "class.*:.*ISymbol" -A 5

Length of output: 77


Script:

#!/bin/bash
# Let's try a broader search for ISymbol implementations and usages
rg "ISymbol" -l
rg "ISymbol" -A 5

# Also search for files containing 'GetCharacter' to compare old vs new usage
rg "GetCharacter" -A 5

Length of output: 6970


Script:

#!/bin/bash
# Let's check git history for the ISymbol interface to see the change from GetCharacter to Rune
git log -p src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs

# Also check implementations for any remaining GetCharacter references
rg "GetCharacter\(\)" -A 5

Length of output: 4055

src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (2)

1-6: LGTM! Good debugging support added.

The DebuggerDisplay attribute will improve debugging experience by showing the Rune value directly.


9-17: LGTM! Verify all constructor usages are updated.

The constructors properly handle the transition to Rune. However, since the char-based constructor was removed, we should verify that all existing usages have been updated.

✅ Verification successful

All SimpleSymbol constructor usages have been properly updated to use Rune

Based on the search results, all instances of SimpleSymbol constructor calls are using either the parameterless constructor or properly passing a Rune parameter. The found usages in:

  • UnitTestConsole.cs: Uses new SimpleSymbol(rune)
  • DrawingContextImpl.cs: Uses new SimpleSymbol(new Rune(quadPixel))
  • Pixel.cs: Uses both new SimpleSymbol(rune) and parameterless new SimpleSymbol()
  • RenderTarget.cs: Uses new SimpleSymbol(new Rune('░'))

No char-based constructor calls were found, confirming all usages have been updated correctly.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining char-based SimpleSymbol constructor calls that need updating

# Search for potential char-based constructor calls
rg -p "new SimpleSymbol\([^R]" 

# Search for any direct char assignments that might need updating
rg -p "SimpleSymbol.*=.*'[^']'" 

Length of output: 779


Script:

#!/bin/bash
# Let's check the actual implementation of SimpleSymbol to understand its usage pattern
ast-grep --pattern 'class SimpleSymbol {
  $$$
}'

# Also check for any test files that might be using SimpleSymbol
rg -p "SimpleSymbol" "src/Tests" -A 2 -B 2

Length of output: 561

src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (2)

73-87: Previous review comments are still applicable.

The implementation still needs to address the concerns raised in the previous review regarding bounds validation, thread safety, and documentation completeness.

Additionally, there's a redundant explicit false value being passed to the Pixel constructor where it's already the default.

-                new Pixel(oldCaretPixel.Foreground, oldCaretPixel.Background, false);
+                new Pixel(oldCaretPixel.Foreground, oldCaretPixel.Background);
🧰 Tools
🪛 GitHub Check: build

[warning] 81-81:
"[RedundantArgumentDefaultValue] The parameter 'isCaret' has the same default value" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs(81,79)


73-87: Verify Unicode character handling with caret positioning.

Since this PR aims to add support for Surrogate Unicode sequences, we should verify that the caret positioning works correctly with multi-byte Unicode characters.

✅ Verification successful

Based on the code analysis, I can now generate the final response:

The caret positioning implementation is Unicode-aware and safe

The codebase shows proper Unicode handling:

  • Uses Rune type from .NET for Unicode character representation
  • Handles surrogate pairs correctly in InputLessDefaultNetConsole.cs: "if we have complex unicode runes then we need to calculate the position manually, EnumerateRunes is not enough as some runes (like '🥰') are a single rune, but are emitted as two console characters"
  • The PixelBuffer operates on buffer coordinates that are already properly calculated accounting for Unicode width
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for Unicode/Rune-related tests that verify caret positioning
rg -l "SetCaretPosition.*emoji|surrogate|unicode" --type=cs

# Search for related Unicode handling code
ast-grep --pattern 'class $_ {
  $$$
  Rune $_ {
    $$$
  }
  $$$
}'

Length of output: 333


Script:

#!/bin/bash
# Let's examine the content of these files to understand the Unicode handling
rg "SetCaretPosition.*emoji|surrogate|unicode" -B 2 -A 2 --type=cs

# Look for any Rune-related implementations
rg "Rune" -B 2 -A 2 --type=cs

# Check for any buffer coordinate calculations that might handle Unicode
rg "PixelBufferCoordinate.*width|length|size" -B 2 -A 2 --type=cs

Length of output: 47658

🧰 Tools
🪛 GitHub Check: build

[warning] 81-81:
"[RedundantArgumentDefaultValue] The parameter 'isCaret' has the same default value" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs(81,79)

src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (4)

10-10: LGTM! Good improvements for Unicode support and debugging.

The changes effectively support Unicode handling by introducing the Rune property, and the DebuggerDisplay attribute enhances debugging visibility.

Also applies to: 24-24


Line range hint 29-106: Add descriptive exception message.

The previous review comment about adding an informative message to the InvalidOperationException is still valid and should be addressed.


Line range hint 117-132: LGTM! Good improvement in type safety.

The change from returning raw bytes to DrawingBoxSymbol instances improves type safety and encapsulation.


24-24: Verify surrogate pair handling.

While the change to Rune improves Unicode support, let's verify that surrogate pairs are correctly handled in the box-drawing characters implementation.

src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (1)

61-71: Add test coverage for Unicode edge cases.

While the implementation now properly uses Rune for Unicode support, we should add test coverage for:

  1. Surrogate pairs (e.g., 𝄞 or 🎵)
  2. Emoji sequences (e.g., 👨‍👩‍👧‍👦 or 🏳️‍🌈)
  3. Right-to-left text (e.g., Arabic or Hebrew)

Also applies to: 151-153

@tomlm tomlm changed the title Add support for Surrogate Unicode sequences Add support for Surrogate Unicode sequences (DO NOT MERGE) Nov 6, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (4)
src/Consolonia.Core/Text/GlyphRunImpl.cs (2)

1-1: Consider removing unused System namespace

The System namespace appears to be unused in this file. However, verify there are no implicit type usages before removing it.

-using System;
🧰 Tools
🪛 GitHub Check: build

[warning] 1-1:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Text/GlyphRunImpl.cs(1,1)


23-23: Good architectural improvement

The switch from GlyphIndices to GlyphInfos is a positive change that:

  • Provides richer glyph information
  • Better supports Unicode surrogate pairs
  • Keeps all glyph data in one cohesive structure

Consider adding XML documentation to describe the structure and purpose of GlyphInfo for better maintainability.

src/Consolonia.Themes.TurboVision/Templates/Controls/Helpers/SymbolsControl.cs (1)

73-78: Improve robustness of text shaping implementation.

Consider these enhancements:

  1. Add null/empty validation before accessing value.AsMemory()
  2. Make font size configurable instead of hardcoding to 1
  3. Add error handling for text shaping failures

Here's a suggested implementation:

 public string Text
 {
     get => _text;
     set
     {
         _text = value;
-        var glyphs = new TextShaper().ShapeText(value.AsMemory(), new TextShaperOptions(new GlyphTypeface(), 1));
-        _shapedText = new GlyphRun(new GlyphTypeface(),
-            1,
-            (_text ?? string.Empty).AsMemory(),
-            glyphs,
-            default(Point));
+        if (string.IsNullOrEmpty(value))
+        {
+            _shapedText?.Dispose();
+            _shapedText = null;
+            return;
+        }
+
+        try
+        {
+            var fontSize = 1.0f; // Consider making this configurable
+            var glyphs = new TextShaper().ShapeText(
+                value.AsMemory(),
+                new TextShaperOptions(new GlyphTypeface(), fontSize)
+            );
+            _shapedText = new GlyphRun(
+                new GlyphTypeface(),
+                fontSize,
+                value.AsMemory(),
+                glyphs,
+                default(Point)
+            );
+        }
+        catch (Exception ex)
+        {
+            // Consider logging or handling the error appropriately
+            _shapedText = null;
+        }
     }
 }
src/Consolonia.Core/Text/TextShaper.cs (1)

3-4: Remove redundant using directives

The using directives using System.Runtime.InteropServices; and using Avalonia.Controls.Documents; are not required and can be safely removed to clean up the code.

Apply this diff to remove them:

-using System.Runtime.InteropServices;
-using Avalonia.Controls.Documents;
🧰 Tools
🪛 GitHub Check: build

[warning] 3-3:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Text/TextShaper.cs(3,1)


[warning] 4-4:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Text/TextShaper.cs(4,1)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 559fe7b and e0a2a52.

📒 Files selected for processing (5)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (9 hunks)
  • src/Consolonia.Core/Text/GlyphRunImpl.cs (2 hunks)
  • src/Consolonia.Core/Text/TextShaper.cs (2 hunks)
  • src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml (1 hunks)
  • src/Consolonia.Themes.TurboVision/Templates/Controls/Helpers/SymbolsControl.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs
  • src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml
🧰 Additional context used
🪛 GitHub Check: build
src/Consolonia.Core/Text/GlyphRunImpl.cs

[warning] 1-1:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Text/GlyphRunImpl.cs(1,1)

src/Consolonia.Core/Text/TextShaper.cs

[warning] 3-3:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Text/TextShaper.cs(3,1)


[warning] 4-4:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Text/TextShaper.cs(4,1)

🔇 Additional comments (4)
src/Consolonia.Core/Text/GlyphRunImpl.cs (1)

19-20: ⚠️ Potential issue

Review the simplified Bounds calculation

The new Bounds width calculation using glyphInfos.Count assumes all glyphs have a width of 1 unit. This is problematic because:

  1. It doesn't account for variable-width fonts
  2. Complex Unicode characters (including surrogate pairs and emojis) often have different widths
  3. RTL text layout might be affected

The previous implementation likely used GlyphAdvance values to account for actual glyph widths.

Let's verify how this might affect text layout:

src/Consolonia.Themes.TurboVision/Templates/Controls/Helpers/SymbolsControl.cs (2)

9-9: LGTM: Required namespace for enhanced text formatting.

The addition of Avalonia.Media.TextFormatting namespace aligns with the PR's objective to improve Unicode support.


73-78: Verify RTL text handling and Unicode integration.

Since this PR adds support for right-to-left text, we should verify the integration with RTL-specific components.

src/Consolonia.Core/Text/TextShaper.cs (1)

17-17: ⚠️ Potential issue

Avoid casting rune.Value to char to prevent data loss

Casting rune.Value to char can lead to data loss for Unicode code points above U+FFFF, which cannot be represented in a single char. Consider updating ConsoleText.IsWideChar to accept Rune or modify the logic to correctly handle all Unicode characters.

Run the following script to check the definition of ConsoleText.IsWideChar:

This script will help you verify the parameter type of IsWideChar and ensure it accurately processes all Unicode code points.

tomlm added 2 commits November 7, 2024 20:16
* Added code to measure the actual width taken for emoticons and ligatures
* added GlyphMetric cache so we only have to compute glyph widths once.
* Changed ISymbol to have width
* Adjust positiong appropriately
* Fixed bug so we are correctly hadnling \r in multiline textblocks
* Added Unicode library to identify emoticons and such.
* Changed DrawString to compute widths to deal with fact emoticons are wide
* Changed RenderTarget to use symbol widths to properly skip overlapped cells.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (8)
src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (2)

7-10: Consider performance optimization for ASCII characters.

The change from char to string is excellent for Unicode support. However, since most text might be ASCII, consider adding a fast path for single-character cases.

Consider implementing an additional property:

/// <summary>
/// Provides fast access for single-character symbols
/// </summary>
bool IsSingleChar { get; }

12-15: Enhance documentation for surrogate pairs.

The Width property is well-designed, but the documentation could be more specific about Unicode handling.

Consider updating the documentation:

- ///     The number of characters the symbol takes up
+ ///     The display width of the symbol in character cells.
+ ///     For surrogate pairs and combining characters, this may differ from the string length.
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (2)

11-27: Consider adding validation and maintaining width consistency.

The constructors could benefit from some improvements:

  1. The string+width constructor should validate that width > 0
  2. Consider calculating width based on string length for surrogate pairs and combining characters

Here's a suggested improvement:

 public SimpleSymbol(string text, ushort width)
 {
+    if (width == 0)
+        throw new ArgumentException("Width must be greater than 0", nameof(width));
     Text = text;
     Width = width;
 }

34-41: Improve consistency and performance of string checks.

  1. Consider caching the IsWhiteSpace result for performance
  2. Use consistent null checking method (IsNullOrWhiteSpace vs IsNullOrEmpty)
  3. Use consistent string casing (String vs string)

Here's a suggested improvement:

+private bool? _isWhiteSpace;

 public bool IsWhiteSpace()
 {
-    return string.IsNullOrWhiteSpace(Text);
+    return _isWhiteSpace ??= string.IsNullOrWhiteSpace(Text);
 }

 public ISymbol Blend(ref ISymbol symbolAbove)
 {
-    return !String.IsNullOrEmpty(symbolAbove.Text) ? symbolAbove : this;
+    return !string.IsNullOrWhiteSpace(symbolAbove.Text) ? symbolAbove : this;
 }
src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (1)

Line range hint 31-98: The box-drawing character mapping implementation is robust and well-documented.

The implementation correctly handles:

  • All box-drawing character combinations
  • Both single and double-line styles
  • Special cases like bold and empty symbols

Consider adding unit tests to verify the character mappings, especially for edge cases and different line styles, if not already covered.

src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (1)

151-153: Ensure caret visibility across different fonts

The hard-coded Unicode character 'Ꮖ' (U+13D6 CHEROKEE LETTER TSI) for the caret might not be visible in all fonts. Consider:

  1. Using a more commonly supported character
  2. Adding a fallback mechanism
-    string text = pixel.IsCaret ? "Ꮖ" : pixel.Foreground.Symbol.Text;
+    string text = pixel.IsCaret 
+        ? IsCharacterSupported('Ꮖ') ? "Ꮖ" : "█"  // Use block character as fallback
+        : pixel.Foreground.Symbol.Text;

Add this helper method:

private static bool IsCharacterSupported(char c)
{
    // TODO: Implement font support check
    // Could use TextRenderer or similar to verify the character can be displayed
    return true;
}
src/Consolonia.Core/Drawing/RenderTarget.cs (2)

210-213: Consider optimizing string operations and adding RTL support.

The current implementation has two potential areas for improvement:

  1. Performance: Multiple string concatenations in StringBuilder could be optimized for Unicode operations.
  2. RTL Support: The PR objectives mention right-to-left text support, but there's no explicit handling for it here.

Consider these improvements:

- if (pixel.Foreground.Symbol.Text.Length == 0)
-     _stringBuilder.Append(' ');
- else
-     _stringBuilder.Append(pixel.Foreground.Symbol.Text);
+ // Preallocate StringBuilder capacity for better performance
+ if (_stringBuilder.Capacity < _stringBuilder.Length + 4)  // 4 for typical surrogate pair
+     _stringBuilder.EnsureCapacity(_stringBuilder.Length + 4);
+ 
+ var text = pixel.Foreground.Symbol.Text;
+ if (text.Length == 0)
+     _stringBuilder.Append(' ');
+ else {
+     // Handle RTL text if needed
+     if (IsRightToLeft(text))
+         HandleRTLText(_stringBuilder, text);
+     else
+         _stringBuilder.Append(text);
+ }

Would you like me to provide the implementation for IsRightToLeft and HandleRTLText methods?


Line range hint 1-232: Consider documenting Unicode handling strategy.

The transition to string-based rendering is a significant architectural change that affects the entire rendering pipeline. To ensure maintainability and proper handling of all Unicode cases, consider:

  1. Adding documentation about supported Unicode ranges
  2. Documenting performance implications of string-based rendering
  3. Creating test cases for various Unicode scenarios (surrogate pairs, RTL, combining characters)

Would you like me to help create a documentation template or test suite for Unicode handling?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e0a2a52 and adeb5ea.

📒 Files selected for processing (15)
  • src/Consolonia.Core/Consolonia.Core.csproj (1 hunks)
  • src/Consolonia.Core/Drawing/ConsoleBrush.cs (1 hunks)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (9 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (4 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (1 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs (2 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (2 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs (1 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1 hunks)
  • src/Consolonia.Core/Drawing/RenderTarget.cs (4 hunks)
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (4 hunks)
  • src/Consolonia.Core/Text/GlyphTypeface.cs (2 hunks)
  • src/Consolonia.Core/Text/TextShaper.cs (1 hunks)
  • src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml (1 hunks)
  • src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/Consolonia.Core/Drawing/ConsoleBrush.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs
  • src/Consolonia.Core/Text/GlyphTypeface.cs
  • src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml
🔇 Additional comments (13)
src/Consolonia.Core/Consolonia.Core.csproj (2)

10-10: LGTM! Addition of Unicode.net package aligns with PR objectives.

The addition of Unicode.net package will provide better support for handling surrogate Unicode sequences and emojis.


Line range hint 4-11: Verify complete removal of NullLib.ConsoleEx.

Since we're transitioning from NullLib.ConsoleEx to Unicode.net for text handling, let's verify that all references to the old package have been properly migrated.

✅ Verification successful

NullLib.ConsoleEx has been successfully removed from the current codebase

The verification shows that while NullLib.ConsoleEx was previously used (as seen in git history), it has been completely removed from the current codebase. The transition to Unicode.net appears to be complete as:

  • No current package references to NullLib.ConsoleEx exist in any .csproj files
  • No active code imports or usages of NullLib.ConsoleEx remain
  • The new Unicode.net package is properly referenced in Consolonia.Core.csproj
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to NullLib.ConsoleEx in the codebase

# Test 1: Search for any remaining package references
echo "Checking for NullLib.ConsoleEx package references..."
rg -l "NullLib\.ConsoleEx"

# Test 2: Search for any using statements or type references
echo "Checking for NullLib.ConsoleEx usage in code..."
rg "using.*NullLib\.ConsoleEx|NullLib\.ConsoleEx\."

Length of output: 302


Script:

#!/bin/bash
# Let's try a more comprehensive search approach

# Check for any mentions of NullLib in the codebase (case-insensitive)
echo "Checking for any mentions of NullLib..."
rg -i "nulllib"

# Check specifically in csproj files for historical package references
echo "Checking csproj files..."
fd -e csproj --exec cat {}

# Check git history for removed references
echo "Checking git history for NullLib..."
git log -p | rg -i "nulllib"

Length of output: 5715

src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (2)

1-1: LGTM! Required namespace for Unicode handling.

The addition of System.Text namespace is appropriate for the Unicode-related changes.


1-24: Verify consistent implementation across all ISymbol implementations.

The interface changes look good for Unicode support. Let's verify all implementations are updated correctly.

✅ Verification successful

All ISymbol implementations are correctly aligned with interface changes

Both implementations (DrawingBoxSymbol and SimpleSymbol) properly implement:

  • string Text { get; } property with Unicode support
  • ushort Width { get; } property for character width
  • IsWhiteSpace() method
  • Blend(ref ISymbol symbolAbove) method

The implementations are consistent with the interface changes and handle text appropriately:

  • SimpleSymbol supports arbitrary text strings with explicit width
  • DrawingBoxSymbol handles box-drawing characters with proper Unicode output
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Find all implementations of ISymbol
ast-grep --pattern 'class $_ : $$$ISymbol$$$' || ast-grep --pattern 'struct $_ : $$$ISymbol$$$'

# Verify Text property implementation
ast-grep --pattern 'string Text { get; $$$}'

# Verify Width property implementation
ast-grep --pattern 'ushort Width { get; $$$}'

Length of output: 142


Script:

#!/bin/bash
# Let's try a different approach using ripgrep to find implementations
rg "class.*:.*ISymbol" -l
rg "struct.*:.*ISymbol" -l

# Search for files containing ISymbol interface usage
rg "ISymbol" --type cs -l

# Look at actual implementations
rg "class.*:.*ISymbol" -A 20

Length of output: 602


Script:

#!/bin/bash
# Let's examine the actual implementation of both classes we found
echo "=== DrawingBoxSymbol.cs ==="
cat src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs

echo -e "\n=== SimpleSymbol.cs ==="
cat src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs

Length of output: 6721

src/Consolonia.Core/Text/TextShaper.cs (1)

4-4: LGTM: Unicode namespace import aligns with PR objectives.

src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (3)

8-10: LGTM! Good addition of DebuggerDisplay attribute.

The DebuggerDisplay attribute will improve debugging experience by showing the actual text content.


29-31: LGTM! Properties are well-designed.

The read-only properties with proper defaults ensure thread-safety and null-safety.


1-42: Verify handling of surrogate pairs and combining characters.

While the transition to string-based storage enables Unicode support, we should verify the implementation handles all Unicode cases correctly.

#!/bin/bash
# Look for test cases covering surrogate pairs and combining characters
rg -l "surrogate|emoji|combining.*character" --type cs

# Check for Unicode-related test files
fd -e cs test.*unicode -x cat {}
src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (3)

2-2: LGTM! The new debugging and Unicode support changes look good.

The added debugging support and new properties align well with the PR objectives:

  • DebuggerDisplay attribute improves debugging visibility
  • Text property supports Unicode character representation
  • Width property correctly handles the fixed-width nature of box-drawing characters

Also applies to: 10-10, 24-26


119-130: Great improvement in type safety!

The change from returning raw bytes to DrawingBoxSymbol instances is a solid improvement that:

  • Enhances type safety
  • Makes the API more intuitive
  • Reduces the chance of misuse

24-24: Verify Unicode compatibility of box-drawing characters.

Let's ensure the box-drawing characters are properly handled with the new Unicode support:

✅ Verification successful

Box-drawing characters are safely handled with Unicode support

The implementation is safe because:

  • The DrawingBoxSymbol struct uses fixed single-width box-drawing characters (║│═─┼╬╪╫)
  • Characters are explicitly defined as constants and handled through a well-defined pattern system
  • The Width property is explicitly set to 1, ensuring consistent rendering
  • The implementation follows Code Page 437 box-drawing character specifications, which are part of the Unicode standard's compatibility area

The ToString() usage in Text property is safe as these box-drawing characters are single code points that don't involve surrogate pairs or complex Unicode sequences.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if any box-drawing characters are used with surrogate pairs
# or other Unicode sequences that might affect rendering.

# Search for Unicode-related tests or usage
rg -l "DrawingBoxSymbol.*[║│═─┼╬╪╫]" --type=cs

# Look for any Unicode-related configuration or handling
rg -l "Unicode.*DrawingBoxSymbol" --type=cs

Length of output: 94


Script:

#!/bin/bash
# Let's check the implementation of DrawingBoxSymbol to understand how it handles characters
ast-grep --pattern 'class DrawingBoxSymbol {
  $$$
}'

# Also check for any box drawing related constants or character definitions
rg "BoxSymbol|[║│═─┼╬╪╫]" -A 5 -B 5 --type=cs

Length of output: 12254

src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (1)

Line range hint 124-124: LGTM: Clean method signature update

The addition of the optional RawInputModifiers parameter with a default value maintains backward compatibility while adding flexibility.

src/Consolonia.Core/Drawing/RenderTarget.cs (1)

24-24: LGTM: Cache field type change supports Unicode surrogate pairs.

The change from char to string in the cache tuple is essential for proper Unicode support, particularly for characters that require surrogate pairs.

Let's verify there are no remaining char-based caches in the codebase:

✅ Verification successful

The change from char to string in the cache field is appropriate and safe

The codebase analysis shows that while there are still char usages in the codebase, they are used in different contexts:

  • For box-drawing characters and quad-pixel characters which are single-character symbols
  • In the SimpleSymbol constructor which already converts the char to string via ToString()
  • In documentation and parameter descriptions

The cache field change is consistent with the codebase's evolution towards better Unicode support, and there are no other similar cache fields that would need updating.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining char-based caches that might need similar updates
ast-grep --pattern 'char[,]?\s*\](\s*,\s*\])*'

Length of output: 48


Script:

#!/bin/bash
# Let's try a different approach using ripgrep to find char array declarations
rg "char\[.*\]" --type cs

# Also search for char-based collections that might need updates
rg "(List|Array|IEnumerable)<char>" --type cs

Length of output: 75


Script:

#!/bin/bash
# Let's search for any remaining usages of char in the codebase, focusing on the Drawing namespace
rg "char" src/Consolonia.Core/Drawing/ -B 2 -A 2

# Also check for any other cache fields that might need similar updates
ast-grep --pattern '$_[] _cache;'

Length of output: 12484

src/Consolonia.Core/Text/TextShaper.cs Outdated Show resolved Hide resolved
src/Consolonia.Core/Text/TextShaper.cs Outdated Show resolved Hide resolved
src/Tests/Consolonia.TestsCore/UnitTestConsole.cs Outdated Show resolved Hide resolved
src/Consolonia.Core/Drawing/RenderTarget.cs Outdated Show resolved Hide resolved
@tomlm tomlm changed the title Add support for Surrogate Unicode sequences (DO NOT MERGE) Add support for Surrogate Unicode sequences Nov 8, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml (2)

35-41: Excellent Unicode support implementation.

The examples effectively demonstrate the new Unicode capabilities including surrogate pairs, emojis, and international text. Consider adding FlowDirection="RightToLeft" for RTL script examples to ensure proper text layout.

 <StackPanel Spacing="0">
     <TextBlock Text="International chars" TextDecorations="Underline"/>
     <TextBlock Text="Chinese: 中国人 "/>
     <TextBlock Text="Japanese: 漢字学"/>
     <TextBlock Text="Korean: 한국인" />
+    <TextBlock Text="Arabic: مرحبا بالعالم" FlowDirection="RightToLeft" />
 </StackPanel>

42-55: Well-structured style demonstrations.

The systematic approach to demonstrating text styles is excellent. Consider adding comments to document the purpose of each color combination for future maintenance.

 <WrapPanel >
+    <!-- Light text on dark background demonstrations -->
     <TextBlock Text="BOLD" Background="DarkMagenta" Foreground="Yellow" FontWeight="Bold" Margin="1 0"/>
     <TextBlock Text="NORMAL" Background="DarkMagenta" Foreground="Yellow" FontWeight="Normal" Margin="1 0"/>
     <TextBlock Text="LIGHT" Background="DarkMagenta" Foreground="Yellow" FontWeight="Light" Margin="1 0"/>
 </WrapPanel>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between adeb5ea and c174f9b.

📒 Files selected for processing (1)
  • src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml (1 hunks)
🔇 Additional comments (1)
src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml (1)

13-14: LGTM! Good accessibility consideration.

The addition of ScrollViewer with explicit focus support ensures proper keyboard navigation and handles content overflow appropriately.

@tomlm tomlm enabled auto-merge (squash) November 8, 2024 04:41
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (6)
src/Consolonia.Core/Text/TextShaper.cs (2)

20-21: Consider using Buffer.BlockCopy for better performance

The current implementation copies glyphs one by one in a loop. For large text blocks, this could be inefficient.

Consider using a more efficient bulk copy operation:

-for (int i = 0; i < shapedBuffer.Length; i++)
-    shapedBuffer[i] = glyphInfos[i];
+System.Buffer.BlockCopy(glyphInfos, 0, shapedBuffer.Spans, 0, glyphInfos.Length * sizeof(GlyphInfo));

13-21: Implement comprehensive Unicode support

The current implementation doesn't fully address the PR's objective of supporting Unicode surrogate sequences. A complete solution should handle:

  1. Proper Unicode character preservation
  2. Correct character width calculation
  3. Combining characters
  4. Grapheme clusters
  5. Complex script shaping

Consider implementing a more robust text shaping pipeline:

  1. Use a proper text shaping engine like HarfBuzz
  2. Handle grapheme clusters properly using StringInfo
  3. Support combining characters
  4. Implement proper width calculation for CJK, emoji, etc.

Would you like me to provide a detailed implementation proposal that addresses all these aspects?

src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (2)

15-19: Consider using char.ToString(IFormatProvider) for culture-aware string conversion.

While the current implementation works, using char.ToString() might not handle all culture-specific cases correctly. Consider using char.ToString(CultureInfo.InvariantCulture) for more robust Unicode handling.

-            Text = character.ToString();
+            Text = character.ToString(System.Globalization.CultureInfo.InvariantCulture);

38-38: Improve Blend method with pattern matching and string.IsNullOrEmpty.

The current implementation can be improved for consistency and readability.

-            return !String.IsNullOrEmpty(symbolAbove.Text) ? symbolAbove : this;
+            return symbolAbove is { Text: { Length: > 0 } } ? symbolAbove : this;

Alternatively, if you prefer the null check approach:

-            return !String.IsNullOrEmpty(symbolAbove.Text) ? symbolAbove : this;
+            return !string.IsNullOrEmpty(symbolAbove.Text) ? symbolAbove : this;
src/Tests/Consolonia.GalleryTests/TextBlockTests.cs (1)

24-28: Consider adding RTL text examples and improving test organization.

While the current tests cover various Unicode sequences, consider these improvements:

  1. Add right-to-left text examples as mentioned in the PR objectives
  2. Organize tests into logical groups with descriptive comments
  3. Add assertions for mixed RTL/LTR text scenarios

Example structure:

 // multiline
 "│Lorem ipsum dolor sit amet, consectetur adipiscing",
 "│elit. Vivamus magna. Cras in mi at felis aliquet",
 "│congue. Ut a est eget ligula molestie gravida.",
-// special chars, emojis, etc.
-"𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟", "𝄞","🎵", ""𝔉𝔞𝔫𝔠𝔶"","ff","fi","½");
+// Indigenous languages (Osage script)
+"𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟",
+// Musical notation
+"𝄞", "🎵",
+// Mathematical notation (Fraktur)
+""𝔉𝔞𝔫𝔠𝔶"",
+// Typography (Ligatures and fractions)
+"ff", "fi", "½",
+// Right-to-left text
+"שָׁלוֹם", // Hebrew
+"مرحبا", // Arabic
+// Mixed RTL/LTR
+"Hello مرحبا World");
src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (1)

9-9: LGTM! Consider enhancing the DebuggerDisplay format.

The new properties and debugging support look good. The Text property aligns well with Unicode support goals, and the Width property correctly reflects the single-character nature of box symbols.

Consider making the DebuggerDisplay more informative:

-[DebuggerDisplay("DrawingBox {Text}")]
+[DebuggerDisplay("DrawingBox: {Text} (0x{_upRightDownLeft:X2})")]

Also applies to: 23-25

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c174f9b and cc417f8.

📒 Files selected for processing (8)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (9 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (4 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs (1 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs (2 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1 hunks)
  • src/Consolonia.Core/Text/GlyphRunImpl.cs (1 hunks)
  • src/Consolonia.Core/Text/TextShaper.cs (1 hunks)
  • src/Tests/Consolonia.GalleryTests/TextBlockTests.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs
  • src/Consolonia.Core/Text/GlyphRunImpl.cs
🔇 Additional comments (6)
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (3)

1-6: LGTM! Clean imports and helpful debug display.

The imports are minimal and the DebuggerDisplay attribute will improve debugging experience by showing the Text content.


27-29: LGTM! Well-designed immutable properties.

The properties are correctly implemented as read-only, maintaining immutability of the struct.


21-24: Verify Width handling for surrogate pairs.

The Width parameter is crucial for correct rendering of surrogate pairs and combining characters. Ensure that the width calculation in the calling code correctly accounts for the full Unicode grapheme clusters.

src/Tests/Consolonia.GalleryTests/TextBlockTests.cs (1)

1-1: LGTM: Required imports added for Unicode text handling.

The new imports are necessary for supporting the enhanced text rendering capabilities and TextBlock controls.

Also applies to: 3-4

src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs (2)

Line range hint 118-133: Great improvement in type safety!

The change from returning raw bytes to returning DrawingBoxSymbol instances is a solid improvement that:

  • Enhances type safety
  • Makes the API more intuitive
  • Maintains consistency with the struct's design

Line range hint 30-97: LGTM! The box symbol mapping is comprehensive.

The private GetBoxSymbol method provides a robust implementation for box drawing characters. The switch expressions are well-organized and cover all valid combinations of the _upRightDownLeft patterns.

Let's verify that all box drawing characters are properly handled:

✅ Verification successful

The box symbol mapping implementation is well-structured and complete

Based on the code shown in the review comment, the implementation comprehensively handles all valid combinations of box drawing characters through:

  • Simple cases for vertical (│, ║) and horizontal (─, ═) lines
  • Complex intersections (┼, ╬, ╪, ╫)
  • All corner variants (└, ┌, ┐, ┘) with their bold/double-line counterparts
  • T-junction variants (├, ┤, ┬, ┴) with their bold/double-line counterparts
  • Special cases for empty and bold symbols

The switch expressions are well-organized and the bit manipulation approach using _upRightDownLeft is an efficient way to determine the appropriate box drawing character.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any missing box drawing character cases
# Look for switch expressions without corresponding box drawing characters

ast-grep --pattern 'switch ($_) {
  $$$
  _ => throw new InvalidOperationException()
  $$$
}'

Length of output: 95


Script:

#!/bin/bash
# Let's try a different approach to find the switch expression in the GetBoxSymbol method
ast-grep --pattern 'return $_ switch
{
  $$$
  _ => throw new InvalidOperationException()
  $$$
}'

Length of output: 100


Script:

#!/bin/bash
# Let's search for the file content directly using ripgrep
rg -U "private char GetBoxSymbol.*?\{.*?throw new InvalidOperationException\(\)" -A 100 --multiline

Length of output: 101

src/Tests/Consolonia.GalleryTests/TextBlockTests.cs Outdated Show resolved Hide resolved
@jinek
Copy link
Owner

jinek commented Nov 8, 2024

I have tried it, when switching to TextBlock in gallery application stops responding, nothing redrawn. I could not figure out why. Sorry, can not debug these days.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (10)
src/Tests/Consolonia.GalleryTests/TextBlockTests.cs (1)

2-3: Verify the necessity of newly added using directives.

The static analysis indicates that the following using directives are currently unused:

  • Avalonia.Controls
  • Avalonia.Media
  • NUnit.Framework.Internal

If these are intended for future test additions, consider adding a comment explaining their purpose. Otherwise, they can be safely removed.

Also applies to: 7-7

🧰 Tools
🪛 GitHub Check: build

[warning] 2-2:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Tests/Consolonia.GalleryTests/TextBlockTests.cs(2,1)


[warning] 3-3:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Tests/Consolonia.GalleryTests/TextBlockTests.cs(3,1)

src/Consolonia.Core/Helpers/Extensions.cs (1)

18-27: Consider adding parameter validation.

While the implementation looks good and aligns with the Unicode support objectives, consider adding null checks for the parameters to prevent potential runtime exceptions.

 public static void Print(this IConsole console, PixelBufferCoordinate point, Pixel pixel)
 {
+    if (console == null)
+        throw new ArgumentNullException(nameof(console));
+    if (pixel.Foreground == null)
+        throw new ArgumentNullException(nameof(pixel), "Pixel.Foreground cannot be null");
+
     console.Print(point, 
         pixel.Background.Color, 
         pixel.Foreground.Color, 
         pixel.Foreground.Style, 
         pixel.Foreground.Weight, 
         pixel.Foreground.TextDecorations, 
         pixel.Foreground.Symbol.Text);
 }
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (2)

12-17: Consider documenting the width=1 design decision.

While using String.Empty with width=1 is a good approach for maintaining layout, it would be helpful to document why this specific width was chosen for empty symbols.

 public SimpleSymbol()
 {
-    // we use String.Empty to represent an empty symbol. It still takes up space, but it's invisible
+    // Empty symbols use String.Empty with width=1 to maintain consistent layout spacing.
+    // This ensures empty cells still occupy space in the buffer while remaining invisible.
     Text = string.Empty;
     Width = 1;
 }

47-47: Fix String casing for consistency.

Use string instead of String to match the codebase style.

-            return !String.IsNullOrEmpty(symbolAbove.Text) ? symbolAbove : this;
+            return !string.IsNullOrEmpty(symbolAbove.Text) ? symbolAbove : this;
🧰 Tools
🪛 GitHub Check: build

[notice] 47-47:
"[BuiltInTypeReferenceStyleForMemberAccess] Built-in type reference is inconsistent with code style settings" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs(47,21)

src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (2)

73-76: Improve XML documentation.

The XML documentation is incomplete. Add a description for the point parameter and document any exceptions that may be thrown.


79-82: Clean up commented code and standardize variable declarations.

  1. Remove the commented parameter /*, false*/ as it's no longer needed.
  2. Consider standardizing the use of var vs explicit type declarations for consistency.
-            Pixel oldCaretPixel = _buffer[_caretPosition.X, _caretPosition.Y];
-            _buffer[_caretPosition.X, _caretPosition.Y] =
-                new Pixel(oldCaretPixel.Foreground, oldCaretPixel.Background /*, false*/);
+            var oldCaretPixel = _buffer[_caretPosition.X, _caretPosition.Y];
+            _buffer[_caretPosition.X, _caretPosition.Y] =
+                new Pixel(oldCaretPixel.Foreground, oldCaretPixel.Background);
src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (2)

2-2: Remove unused import.

The System.Diagnostics namespace is not used in this file and can be safely removed.

-using System.Diagnostics;
🧰 Tools
🪛 GitHub Check: build

[warning] 2-2:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs(2,1)


Line range hint 71-108: Consider performance optimizations to address reported unresponsiveness.

The Print method performs multiple string operations and console writes which could contribute to the reported TextBlock unresponsiveness. Consider these optimizations:

  1. Cache the StringBuilder initial capacity based on common use cases
  2. Batch console writes where possible
  3. Consider using a buffer pool for frequently used string operations

Would you like me to provide a detailed implementation of these optimizations?

src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (2)

151-151: Consider using standard caret symbol

Using the Cherokee letter 'Ꮖ' as a caret symbol is not ideal:

  • It may not be supported in all fonts
  • It could be confused with actual text content
  • Traditional caret symbols like '▊' or '█' would be more appropriate
-    string text = pixel.IsCaret ? "Ꮖ" : pixel.Foreground.Symbol.Text;
+    string text = pixel.IsCaret ? "█" : pixel.Foreground.Symbol.Text;

152-152: Address TODO comment about cursor drawing

The TODO comment indicates an unresolved issue with cursor drawing. This should be investigated and fixed as it's directly related to the Unicode support changes.

Would you like me to help investigate the cursor drawing issue or create a GitHub issue to track this?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between cc417f8 and 7e36247.

📒 Files selected for processing (12)
  • src/Consolonia.Core/Consolonia.Core.csproj (1 hunks)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (9 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (2 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1 hunks)
  • src/Consolonia.Core/Helpers/Extensions.cs (2 hunks)
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (3 hunks)
  • src/Consolonia.Core/Text/GlyphTypeface.cs (2 hunks)
  • src/Consolonia.Core/Text/TextShaper.cs (1 hunks)
  • src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml (2 hunks)
  • src/Consolonia.Themes.TurboVision/Templates/Controls/Helpers/SymbolsControl.cs (2 hunks)
  • src/Tests/Consolonia.GalleryTests/TextBlockTests.cs (2 hunks)
  • src/Tests/Consolonia.TestsCore/UnitTestConsole.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/Consolonia.Core/Consolonia.Core.csproj
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs
  • src/Consolonia.Core/Text/GlyphTypeface.cs
  • src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml
  • src/Consolonia.Themes.TurboVision/Templates/Controls/Helpers/SymbolsControl.cs
🧰 Additional context used
🪛 GitHub Check: build
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs

[notice] 47-47:
"[BuiltInTypeReferenceStyleForMemberAccess] Built-in type reference is inconsistent with code style settings" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs(47,21)

src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs

[warning] 2-2:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs(2,1)


[warning] 12-12:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs(12,1)

src/Tests/Consolonia.GalleryTests/TextBlockTests.cs

[warning] 2-2:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Tests/Consolonia.GalleryTests/TextBlockTests.cs(2,1)


[warning] 3-3:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Tests/Consolonia.GalleryTests/TextBlockTests.cs(3,1)


[warning] 7-7:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Tests/Consolonia.GalleryTests/TextBlockTests.cs(7,1)

🔇 Additional comments (13)
src/Consolonia.Core/Text/TextShaper.cs (1)

13-20: Verify text shaping performance impact

Let's analyze the codebase for potential performance bottlenecks and similar implementations.

✅ Verification successful

Based on the shell script results, I can now provide a final response regarding the performance impact of the text shaping changes:

Text shaping implementation is performance-efficient

The current implementation is actually optimal for the console-based rendering context:

  • It uses EnumerateRunes() which is the most efficient way to process Unicode text in .NET
  • The ShapedBuffer allocation happens once with a pre-calculated size
  • The implementation avoids multiple allocations by using array indexing instead of creating new collections

The codebase shows this pattern is consistently used across other performance-critical paths:

  • DrawingContextImpl.cs uses the same rune enumeration pattern
  • SimpleSymbol.cs follows similar efficient text processing approach
  • No redundant string allocations or conversions are found
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other text shaping implementations and potential bottlenecks

echo "Searching for other text shaping implementations..."
ast-grep --pattern 'class $_ : ITextShaperImpl {
  $$$
}'

echo "Looking for similar string processing patterns..."
rg -A 5 "EnumerateRunes|ShapedBuffer|GlyphInfo" --type cs

echo "Checking for performance-critical paths..."
rg -A 5 "TextBlock|TextShaper" --type cs

Length of output: 11926

src/Tests/Consolonia.GalleryTests/TextBlockTests.cs (1)

24-27: ⚠️ Potential issue

Verify text rendering performance with large Unicode sequences.

Given the reported unresponsiveness when switching to TextBlock in the gallery application, we should verify the rendering performance with various text combinations.

Consider adding performance tests that:

  1. Measure rendering time with large Unicode sequences
  2. Test memory usage with extensive surrogate pairs
  3. Include stress tests with rapid text changes
src/Consolonia.Core/Helpers/Extensions.cs (2)

4-5: LGTM! Required namespaces for pixel buffer handling.

The added namespaces are necessary for the new Print method implementation.


26-26: Verify surrogate pair handling in Symbol.Text.

Let's ensure the Unicode surrogate pairs are properly handled throughout the processing pipeline.

✅ Verification successful

Let me gather more specific information about the Unicode handling implementation.


Let me check one more crucial piece - the actual Symbol class implementation and any Unicode-specific handling code.


Unicode surrogate pairs are properly handled in the codebase

The implementation shows robust Unicode support:

  • ISymbol interface explicitly documents support for emoji and Unicode characters
  • The codebase uses NeoSmart.Unicode library for proper Unicode handling
  • SimpleSymbol implementation correctly processes Unicode width using UnicodeCalculator
  • Tests include verification with surrogate pairs, emojis, and complex Unicode characters (𐓏𐓘𐓻𐓘𐓻𐓟, 𝄞, 🎵)
  • Proper UTF-8 encoding is set for console output
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for Symbol class definition and usage to verify Unicode handling
echo "Checking Symbol class implementation..."
ast-grep --pattern 'class Symbol {
  $$$
}'

echo "Checking Symbol.Text property usage..."
rg -l "Symbol\.Text" --type cs

echo "Checking for Unicode-related tests..."
rg -l "surrogate|emoji|Unicode" --glob "**/*Test*.cs"

Length of output: 719


Script:

#!/bin/bash
# Check Symbol class implementation details
echo "Checking Symbol class content..."
rg -A 10 "class Symbol" --type cs

# Check TextBlock tests for Unicode handling
echo "Checking Unicode-related test content..."
rg -C 5 "Unicode|surrogate|emoji" src/Tests/Consolonia.GalleryTests/TextBlockTests.cs

# Check actual Symbol.Text usage in context
echo "Checking Symbol.Text usage context..."
rg -C 3 "Symbol\.Text" --type cs

Length of output: 6428


Script:

#!/bin/bash
# Find and check Symbol interface/class implementation
echo "Looking for ISymbol interface and implementation..."
rg -A 15 "interface ISymbol|class.*:.*ISymbol" --type cs

# Check for any Unicode/string handling methods
echo "Checking string handling methods..."
rg -C 5 "string.*Text.*{.*get" --type cs

# Look for any character encoding related code
echo "Checking encoding related code..."
rg -C 3 "Encoding|UTF|Unicode" --type cs

Length of output: 10196

src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (5)

1-6: Remove unused import System.Text


9-11: LGTM! Good debugging support.

The DebuggerDisplay attribute will help with debugging by showing the Text content.


24-34: LGTM! Well-structured Unicode support.

The string and Rune constructors properly handle width calculation for Unicode characters.


36-38: LGTM! Good immutability design.

The readonly properties in a readonly struct ensure thread-safety and prevent mutation.


51-67: LGTM! Robust Unicode width calculation.

The MeasureGlyph method correctly handles:

  • Complex emoji sequences with zero-width joiners
  • Object replacement characters
  • Multi-width Unicode characters

This aligns well with the PR objective of supporting surrogate sequences.

src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBuffer.cs (3)

14-14: LGTM: Field declaration follows conventions.

The private field declaration for caret position tracking is well-structured and follows naming conventions.


21-21: LGTM: Proper field initialization.

The caret position is correctly initialized to the origin (0,0).


77-90: Consider validating pixel states during caret updates.

The method directly modifies pixels without validating their current state. Consider adding checks to ensure pixels are in a valid state before modification, especially since this is part of Unicode support changes.

Consider adding validation:

 public void SetCaretPosition(PixelBufferCoordinate point)
 {
+    ValidatePixelState(_buffer[_caretPosition.X, _caretPosition.Y]);
     // clear old caret position by merging in IsCaret = false
     var oldCaretPixel = _buffer[_caretPosition.X, _caretPosition.Y];
     _buffer[_caretPosition.X, _caretPosition.Y] =
         new Pixel(oldCaretPixel.Foreground, oldCaretPixel.Background);

     _caretPosition = point;

+    ValidatePixelState(_buffer[point.X, point.Y]);
     // set new caret position by merging in IsCaret = true
     var newCaretPixel = _buffer[_caretPosition.X, _caretPosition.Y];
     _buffer[_caretPosition.X, _caretPosition.Y] =
         new Pixel(newCaretPixel.Foreground, newCaretPixel.Background, true);
 }

+private void ValidatePixelState(Pixel pixel)
+{
+    // Add validation logic here
+    // Example: Check if the pixel's current state is valid for caret positioning
+}
src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (1)

Line range hint 71-71: Previous review comment about exception handling is still applicable.

The concern about handling potential IOException when calling Console.GetCursorPosition() remains unaddressed.

🧰 Tools
🪛 GitHub Check: build

[warning] 2-2:
"[RedundantUsingDirective] Using directive is not required by the code and can be safely removed" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs(2,1)

src/Consolonia.Core/Text/TextShaper.cs Outdated Show resolved Hide resolved
src/Consolonia.Core/Text/TextShaper.cs Outdated Show resolved Hide resolved
src/Tests/Consolonia.GalleryTests/TextBlockTests.cs Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (3)
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1)

25-29: Consider caching glyph width measurements.

Both string and Rune constructors calculate width using MeasureGlyph(). For frequently used glyphs, consider caching these measurements to improve performance.

Consider implementing a static cache:

+ private static readonly ConcurrentDictionary<string, ushort> _widthCache = new();

  public SimpleSymbol(string glyph)
  {
      Text = glyph;
-     Width = Text.MeasureGlyph();
+     Width = _widthCache.GetOrAdd(Text, static text => text.MeasureGlyph());
  }

Also applies to: 31-34

src/Consolonia.Core/Helpers/Extensions.cs (2)

22-31: LGTM: Clean extension method for pixel printing

The method provides a convenient way to print pixels while maintaining a clean separation of concerns. Consider adding XML documentation to clarify the method's purpose and parameters.

Add documentation like this:

+        /// <summary>
+        /// Prints a pixel at the specified coordinate using the console.
+        /// </summary>
+        /// <param name="console">The console to print to</param>
+        /// <param name="point">The coordinate where to print</param>
+        /// <param name="pixel">The pixel containing the styling and content to print</param>
         public static void Print(this IConsole console, PixelBufferCoordinate point, Pixel pixel)

74-91: Consider performance optimization for large strings

The method correctly calculates glyph widths while handling special Unicode characters. However, for better performance with large strings, consider pre-calculating the capacity needed for the enumeration.

Add a capacity hint:

         public static ushort MeasureGlyph(this string glyph)
         {
+            if (string.IsNullOrEmpty(glyph))
+                return 0;
             ushort width = 0;
             ushort lastWidth = 0;
-            foreach (var rune in glyph.EnumerateRunes())
+            var runes = glyph.EnumerateRunes();
+            foreach (var rune in runes)

Also, consider adding validation for null input to prevent potential NullReferenceException.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7e36247 and 88ebb08.

📒 Files selected for processing (4)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (9 hunks)
  • src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (1 hunks)
  • src/Consolonia.Core/Helpers/Extensions.cs (2 hunks)
  • src/Consolonia.Core/Text/TextShaper.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs
🔇 Additional comments (5)
src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs (3)

10-12: LGTM! Good debugging support.

The DebuggerDisplay attribute will improve debugging experience by showing the actual text content.


13-18: LGTM! Well-documented default constructor.

The empty constructor's comment clearly explains the semantic meaning of an empty symbol.


37-39: LGTM! Well-designed immutable properties.

The immutable design with proper initialization aligns well with the struct's readonly nature.

src/Consolonia.Core/Helpers/Extensions.cs (2)

1-9: LGTM: Appropriate dependencies added for Unicode support

The new using directives for NeoSmart.Unicode and other required namespaces are correctly added to support the Unicode functionality.


38-72: Verify GetGlyphs performance impact on UI

Given the reported UI freeze when switching to TextBlock in the gallery application, we should verify if the glyph processing could be causing performance issues with large text blocks.

src/Consolonia.Core/Text/TextShaper.cs Outdated Show resolved Hide resolved
src/Consolonia.Core/Text/TextShaper.cs Outdated Show resolved Hide resolved
src/Consolonia.Core/Helpers/Extensions.cs Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (1)

59-59: Add XML documentation for the SupportsComplexEmoji property.

The property should be documented to explain its purpose and behavior.

Add XML documentation:

+       /// <summary>
+       /// Indicates whether the console supports complex emoji rendering.
+       /// True if the console properly renders surrogate pairs and combining characters.
+       /// </summary>
        public bool SupportsComplexEmoji { get; }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 0b478fc and 6c008eb.

📒 Files selected for processing (1)
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (3 hunks)
🔇 Additional comments (1)
src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (1)

120-125: Verify MeasureText implementation for Unicode handling.

The switch to MeasureText() is good for Unicode support, but we should verify its implementation handles all Unicode cases correctly.

Let's check the MeasureText implementation:

✅ Verification successful

MeasureText implementation handles Unicode correctly

The implementation in Extensions.cs properly handles Unicode text width calculation:

  • Uses Rune for proper Unicode character enumeration
  • Handles complex emoji with zero-width joiners (ZWJ) and object replacement characters
  • Calculates width using UnicodeCalculator.GetWidth
  • Supports complex emoji through SupportsComplexEmoji flag
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify MeasureText implementation for Unicode handling
# Look for the implementation and any related tests

# Find MeasureText implementation
echo "Looking for MeasureText implementation:"
rg -l "MeasureText.*string" --type cs

# Check for related tests
echo -e "\nLooking for related tests:"
rg -l "MeasureText.*Test" --type cs

# Look for Unicode-specific test cases
echo -e "\nLooking for Unicode test cases:"
rg "MeasureText.*[👨🏻‍💻🌍]" --type cs

Length of output: 398


Script:

#!/bin/bash
# Let's examine the MeasureText implementation in Extensions.cs
echo "=== MeasureText Implementation ==="
rg -A 10 "MeasureText" src/Consolonia.Core/Helpers/Extensions.cs

# Let's also check for any string width calculation related tests
echo -e "\n=== String Width Related Tests ==="
rg -l "TestStringWidth|StringWidth.*Test|MeasureText.*Test" --type cs

# Let's look for any Unicode-related string handling
echo -e "\n=== Unicode String Handling ==="
rg "StringInfo|TextElementEnumerator|Rune|GetTextElement" --type cs

Length of output: 1759


Script:

#!/bin/bash
# Let's check the UnicodeCalculator implementation
echo "=== UnicodeCalculator Implementation ==="
rg -A 10 "class UnicodeCalculator" --type cs

# Let's also check for emoji support implementation
echo -e "\n=== Emoji Support Implementation ==="
rg -A 5 "SupportsComplexEmoji" --type cs

# Let's look for any width calculation tests
echo -e "\n=== Width Calculation Tests ==="
rg -A 10 "GetWidth.*Test" --type cs

Length of output: 3605

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (2)
src/Consolonia.Core/Helpers/Extensions.cs (2)

48-84: Simplify complex emoji processing logic.

The nested if conditions make the code harder to follow. Consider extracting emoji processing logic into separate methods.

Here's a suggested refactoring:

+private static bool IsEmojiRelatedCharacter(Rune rune) =>
+    rune.Value == Emoji.ZeroWidthJoiner ||
+    rune.Value == Emoji.ObjectReplacementCharacter ||
+    rune.Value == Codepoints.VariationSelectors.EmojiSymbol ||
+    rune.Value == Codepoints.VariationSelectors.TextSymbol;

+private static bool ShouldAppendToEmoji(Rune lastRune, Rune currentRune) =>
+    lastRune.Value == Codepoints.ZWJ ||
+    lastRune.Value == Codepoints.ORC ||
+    Emoji.IsEmoji(currentRune.ToString());

 while (runes.MoveNext())
     if (console.SupportsComplexEmoji)
     {
-        if (lastRune.Value == Codepoints.ZWJ ||
-            lastRune.Value == Codepoints.ORC ||
-            Emoji.IsEmoji(runes.Current.ToString()))
+        if (ShouldAppendToEmoji(lastRune, runes.Current))
         {
             emoji.Append(runes.Current);
         }
-        else if (runes.Current.Value == Emoji.ZeroWidthJoiner ||
-                 runes.Current.Value == Emoji.ObjectReplacementCharacter ||
-                 rune.Value == Codepoints.VariationSelectors.EmojiSymbol ||
-                 rune.Value == Codepoints.VariationSelectors.TextSymbol)
+        else if (IsEmojiRelatedCharacter(runes.Current))
         {
             emoji.Append(runes.Current);
         }

104-106: Cache SupportsComplexEmoji property outside the loop.

Accessing console.SupportsComplexEmoji in each iteration is inefficient.

 var console = AvaloniaLocator.Current.GetService<IConsole>();
+bool supportsComplexEmoji = console.SupportsComplexEmoji;
 
 ushort width = 0;
 ushort lastWidth = 0;
 foreach (Rune rune in text.EnumerateRunes())
 {
     ushort runeWidth = (ushort)UnicodeCalculator.GetWidth(rune);
-    if (console.SupportsComplexEmoji &&
+    if (supportsComplexEmoji &&
         (rune.Value == Emoji.ZeroWidthJoiner || rune.Value == Emoji.ObjectReplacementCharacter))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 019a80f and 61b9697.

📒 Files selected for processing (3)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs (10 hunks)
  • src/Consolonia.Core/Helpers/Extensions.cs (2 hunks)
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Consolonia.Core/Drawing/DrawingContextImpl.cs
🧰 Additional context used
🪛 GitHub Check: build
src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs

[warning] 29-29:
"[CSharpWarnings::CS1587] XML comment is not placed on a valid language element" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs(29,13)

🔇 Additional comments (5)
src/Consolonia.Core/Helpers/Extensions.cs (2)

22-31: LGTM: Clean and well-structured Print method.

The method follows good practices by:

  • Properly unpacking Pixel properties
  • Following single responsibility principle
  • Using clear parameter names

39-39: Use more specific return type.

As suggested in past review comments, using IReadOnlyCollection<string> or string[] would better indicate immutability.

src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (3)

60-60: LGTM: Well-designed property for emoji support detection.

The read-only property correctly encapsulates the emoji support detection result.


121-126: LGTM: Improved text width calculation for Unicode support.

The change from string.Length to MeasureText() correctly handles the width of Unicode characters, including surrogate pairs and combining characters. This should resolve potential cursor positioning issues with complex Unicode text.


121-126: Verify performance impact of text measurement.

Given the reported TextBlock unresponsiveness, let's verify if there are any performance-critical calls to MeasureText().

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (1)

60-60: Add XML documentation for public API.

Please add XML documentation for the SupportsComplexEmoji property to describe its purpose and behavior.

+        /// <summary>
+        /// Gets whether the console supports complex emoji rendering with surrogate pairs.
+        /// </summary>
         public bool SupportsComplexEmoji { get; }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 40dedcc and 379870e.

📒 Files selected for processing (1)
  • src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (3 hunks)
🔇 Additional comments (3)
src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs (3)

10-10: LGTM!

The addition of the Text namespace import is appropriate for the Unicode text handling functionality.


121-126: LGTM! Improved text width calculation.

The switch to MeasureText() is a good improvement that properly handles Unicode text width measurement, including surrogate pairs and complex emoji sequences.


24-38: Consider thread safety in console initialization.

The emoji support detection involves multiple console operations that could interfere with other threads accessing the console. Consider adding a lock or synchronization mechanism to ensure thread safety during initialization.

…ging regular pixels by falling through the the isCaret section instead of returning the blended pixel.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 51b30fe and c356590.

📒 Files selected for processing (2)
  • src/Consolonia.Core/Text/GlyphTypeface.cs (3 hunks)
  • src/Consolonia.Core/Text/TextShaper.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Consolonia.Core/Text/GlyphTypeface.cs
🔇 Additional comments (2)
src/Consolonia.Core/Text/TextShaper.cs (2)

1-4: Missing required imports for Unicode support

A previous review comment about adding System.Text import for proper Unicode handling is still valid.


12-12: ⚠️ Potential issue

Performance and Unicode validation concerns

The current implementation has two issues:

  1. ToString() creates unnecessary string allocation
  2. No validation for well-formed Unicode sequences

Apply this diff to fix both issues:

-var glyphs = text.Span.ToString().GetGlyphs();
+if (!System.Text.Unicode.Utf16.IsWellFormed(text.Span))
+    throw new ArgumentException("Invalid Unicode sequence", nameof(text));
+var glyphs = text.Span.GetGlyphs();

Likely invalid or redundant comment.

src/Consolonia.Core/Text/TextShaper.cs Show resolved Hide resolved
src/Consolonia.Core/Text/TextShaper.cs Show resolved Hide resolved
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.

3 participants