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

Refactor tests, splitting out Consolonia.NUnit library and a ton of unit tests #143

Merged
merged 56 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
f087bf5
Add support for Surragate sequences
tomlm Nov 6, 2024
9446c9b
fix release build warning.
tomlm Nov 6, 2024
637747c
* fix unit tests
tomlm Nov 6, 2024
559fe7b
Automated JetBrains cleanup
github-actions[bot] Nov 6, 2024
ef299e5
use Text...everything works except for double char emojiis
tomlm Nov 7, 2024
ebc751d
formatting merge
tomlm Nov 7, 2024
e0a2a52
use TextShaper.Text for render text instead of trying to render from …
tomlm Nov 7, 2024
352bb67
FINALLY I have emoticons rendering correctly
tomlm Nov 8, 2024
adeb5ea
added scroll bars to textlbock gallery page
tomlm Nov 8, 2024
c174f9b
update sample to show that CJK wide chars work
tomlm Nov 8, 2024
479460b
removed unused using statements
tomlm Nov 8, 2024
cc417f8
update unit tests for textblock
tomlm Nov 8, 2024
7e36247
lint feedback, adopt WcWidth for accurate calculation of char width
tomlm Nov 8, 2024
88ebb08
properly calculate GlyphInfos in textshaper
tomlm Nov 8, 2024
5891381
fix bugs found by coderabbit. Nice job code rabbit!
tomlm Nov 8, 2024
e4e247b
remove using
tomlm Nov 8, 2024
532ac52
add detection of complex emojii
tomlm Nov 8, 2024
b7c1e35
fix calc of glyph
tomlm Nov 8, 2024
8cab697
update unitestconsole
tomlm Nov 8, 2024
78710e5
add comment
tomlm Nov 8, 2024
2be4221
fix
tomlm Nov 8, 2024
265eb64
ah, finally figured out the using issue. Visual studio didn't conside…
tomlm Nov 8, 2024
8c76411
argh. Lint is killing me!
tomlm Nov 8, 2024
0b478fc
Automated JetBrains cleanup
github-actions[bot] Nov 8, 2024
9791ab4
Merge branch 'main' into tomlm/rune
tomlm Nov 9, 2024
6c008eb
Merge branch 'main' into tomlm/rune
tomlm Nov 9, 2024
272b00f
merge
tomlm Nov 9, 2024
d4fc7f1
make list readonly
tomlm Nov 9, 2024
019a80f
Automated JetBrains cleanup
github-actions[bot] Nov 9, 2024
a823630
cleanup
tomlm Nov 9, 2024
3a5efde
add comments
tomlm Nov 9, 2024
61b9697
Merge branch 'tomlm/rune' of https://github.com/jinek/Consolonia into…
tomlm Nov 9, 2024
40dedcc
removed accidental comment of /// instead of //
tomlm Nov 9, 2024
379870e
Automated JetBrains cleanup
github-actions[bot] Nov 9, 2024
e7be04e
rename files
tomlm Nov 9, 2024
b3f061b
update unit tests
tomlm Nov 9, 2024
4501daf
Merge branch 'tomlm/rune' into tomlm/tests
tomlm Nov 9, 2024
2cdcef3
Split unit tests out from consolonia support package
tomlm Nov 9, 2024
7658c8c
lint fixes
tomlm Nov 9, 2024
19c4e98
fix typo
tomlm Nov 9, 2024
0aa8d6b
more using
tomlm Nov 9, 2024
ee434d6
feedback from taskrabbit
tomlm Nov 9, 2024
de05026
d
tomlm Nov 9, 2024
89b24bd
Remove this NUnit.Internal This is suggested by CodeRabbit, doesn't s…
tomlm Nov 9, 2024
66553d4
Automated JetBrains cleanup
github-actions[bot] Nov 9, 2024
7ff4812
implement equality for Pixel, PixelForeground, PixelBackground, and s…
tomlm Nov 10, 2024
d858667
add hashcode unit test
tomlm Nov 10, 2024
2e4dd41
Automated JetBrains cleanup
github-actions[bot] Nov 10, 2024
428a67f
Merge branch 'main' into tomlm/tests
tomlm Nov 10, 2024
a03c8ec
cleanup from code merge
tomlm Nov 10, 2024
2c4c60a
fix lint
tomlm Nov 10, 2024
f0c50e7
Automated JetBrains cleanup
github-actions[bot] Nov 10, 2024
82addcc
bug fix on equality, update unit test to cover case
tomlm Nov 10, 2024
dca3aa2
Merge branch 'tomlm/tests' of https://github.com/jinek/Consolonia int…
tomlm Nov 10, 2024
14ae365
split complex test into individual test cases
tomlm Nov 10, 2024
cbb342e
avoid linq for creating glyph and advances array fix test names
tomlm Nov 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Consolonia.Core/Assembly.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Consolonia.TestsCore")]
[assembly: InternalsVisibleTo("Consolonia.Core.Tests")]

[assembly: CLSCompliant(false)] //todo: should we make it compliant?
3 changes: 2 additions & 1 deletion src/Consolonia.Core/Consolonia.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
<PackageReference Include="Avalonia.FreeDesktop" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Skia" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="$(AvaloniaVersion)" />
<PackageReference Include="NullLib.ConsoleEx" Version="1.0.4.4" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.8" />
<PackageReference Include="Unicode.net" Version="2.0.0" />
<PackageReference Include="Wcwidth" Version="2.0.0" />
</ItemGroup>

</Project>
Expand Down
2 changes: 2 additions & 0 deletions src/Consolonia.Core/Drawing/ConsoleBrush.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System;
using System.Diagnostics;
using Avalonia;
using Avalonia.Media;
using Consolonia.Core.Drawing.PixelBufferImplementation;
using Consolonia.Core.Infrastructure;

namespace Consolonia.Core.Drawing
{
[DebuggerDisplay("{Color} [{Mode}]")]
public class ConsoleBrush : AvaloniaObject, IImmutableBrush
{
public static readonly StyledProperty<Color> ColorProperty =
Expand Down
91 changes: 44 additions & 47 deletions src/Consolonia.Core/Drawing/DrawingContextImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
using Avalonia;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Media.TextFormatting;
using Avalonia.Platform;
using Consolonia.Core.Drawing.PixelBufferImplementation;
using Consolonia.Core.Helpers;
using Consolonia.Core.Infrastructure;
using Consolonia.Core.InternalHelpers;
using Consolonia.Core.Text;
Expand All @@ -24,7 +26,8 @@ internal class DrawingContextImpl : IDrawingContextImpl
private const byte HorizontalEndPattern = 0b0001;

public const int UnderlineThickness = 10;
public const int StrikthroughThickness = 11;
public const int StrikethroughThickness = 11;

private readonly Stack<Rect> _clipStack = new(100);
private readonly ConsoleWindow _consoleWindow;
private readonly PixelBuffer _pixelBuffer;
Expand Down Expand Up @@ -91,7 +94,8 @@ public void DrawBitmap(IBitmapImpl source, double opacity, Rect sourceRect, Rect
Color foreground = GetForegroundColorForQuadPixel(quadColors, quadPixel);
Color background = GetBackgroundColorForQuadPixel(quadColors, quadPixel);

var imagePixel = new Pixel(new PixelForeground(new SimpleSymbol(quadPixel), color: foreground),
var imagePixel = new Pixel(
new PixelForeground(new SimpleSymbol(quadPixel), color: foreground),
new PixelBackground(background));
CurrentClip.ExecuteWithClipping(new Point(px, py),
() =>
Expand Down Expand Up @@ -206,9 +210,9 @@ public void DrawGlyphRun(IBrush foreground, IGlyphRunImpl glyphRun)
return;
}

string charactersDoDraw =
string.Concat(glyphRunImpl.GlyphIndices.Select(us => (char)us).ToArray());
DrawStringInternal(foreground, charactersDoDraw, glyphRun.GlyphTypeface);
var shapedBuffer = (ShapedBuffer)glyphRunImpl.GlyphInfos;
string text = shapedBuffer.Text.ToString();
DrawStringInternal(foreground, text, glyphRun.GlyphTypeface);
}

public IDrawingContextLayerImpl CreateLayer(Size size)
Expand Down Expand Up @@ -302,9 +306,11 @@ private void DrawLineInternal(IPen pen, Line line)
line = TransformLineInternal(line);

Point head = line.PStart;

if (IfMoveConsoleCaretMove(pen, head))
if (pen.Brush is MoveConsoleCaretToPositionBrush)
{
_pixelBuffer.SetCaretPosition((PixelBufferCoordinate)head);
return;
}

if (line.Vertical == false && pen.Thickness > 1)
{
Expand All @@ -328,7 +334,7 @@ private void ApplyTextDecorationLineInternal(ref Point head, IPen pen, Line line
TextDecorationCollection textDecoration = pen.Thickness switch
{
UnderlineThickness => TextDecorations.Underline,
StrikthroughThickness => TextDecorations.Strikethrough,
StrikethroughThickness => TextDecorations.Strikethrough,
_ => throw new ArgumentOutOfRangeException($"Unsupported thickness {pen.Thickness}")
};

Expand All @@ -342,10 +348,10 @@ private void ApplyTextDecorationLineInternal(ref Point head, IPen pen, Line line
pixel =>
{
var newPixelForeground = new PixelForeground(pixel.Foreground.Symbol,
pixel.Foreground.Color,
pixel.Foreground.Weight,
pixel.Foreground.Style,
textDecoration,
pixel.Foreground.Color);
textDecoration);
return pixel.Blend(new Pixel(newPixelForeground, pixel.Background));
});
});
Expand All @@ -366,8 +372,11 @@ private void DrawRectangleLineInternal(IPen pen, Line line)

Point head = line.PStart;

if (IfMoveConsoleCaretMove(pen, head))
if (pen.Brush is MoveConsoleCaretToPositionBrush)
{
_pixelBuffer.SetCaretPosition((PixelBufferCoordinate)head);
return;
}

var extractColorCheckPlatformSupported = ExtractColorOrNullWithPlatformCheck(pen, out var lineStyle);
if (extractColorCheckPlatformSupported == null)
Expand Down Expand Up @@ -398,22 +407,6 @@ private Line TransformLineInternal(Line line)
return line;
}

/// <summary>
/// If the pen brush is a MoveConsoleCaretToPositionBrush, move the caret
/// </summary>
/// <param name="pen"></param>
/// <param name="head"></param>
/// <returns></returns>
private bool IfMoveConsoleCaretMove(IPen pen, Point head)
{
if (pen.Brush is not MoveConsoleCaretToPositionBrush)
return false;

CurrentClip.ExecuteWithClipping(head,
() => { _pixelBuffer.Set((PixelBufferCoordinate)head, pixel => pixel.Blend(new Pixel(true))); });
return true;
}

/// <summary>
/// Extract color from pen brush
/// </summary>
Expand Down Expand Up @@ -486,7 +479,7 @@ private void DrawPixelAndMoveHead(ref Point head, Line line, LineStyle? lineStyl
}
}

private void DrawStringInternal(IBrush foreground, string str, IGlyphTypeface typeface, Point origin = new())
private void DrawStringInternal(IBrush foreground, string text, IGlyphTypeface typeface, Point origin = new())
{
foreground = ConsoleBrush.FromBrush(foreground);
if (foreground is not ConsoleBrush { Mode: PixelBackgroundMode.Colored } consoleBrush)
Expand All @@ -495,23 +488,27 @@ private void DrawPixelAndMoveHead(ref Point head, Line line, LineStyle? lineStyl
return;
}

//if (!Transform.IsTranslateOnly()) ConsoloniaPlatform.RaiseNotSupported(15);
// if (!Transform.IsTranslateOnly()) ConsoloniaPlatform.RaiseNotSupported(15);

Point whereToDraw = origin.Transform(Transform);
int currentXPosition = 0;
int currentYPosition = 0;

//todo: support surrogates
foreach (char c in str)
// Each glyph maps to a pixel as a starting point.
// Emoji's and Ligatures are complex strings, so they start at a point and then overlap following pixels
// the x and y are adjusted accodingly.
foreach (string glyph in text.GetGlyphs(_consoleWindow.Console.SupportsComplexEmoji))
{
Point characterPoint = whereToDraw.Transform(Matrix.CreateTranslation(currentXPosition++, 0));
Point characterPoint =
whereToDraw.Transform(Matrix.CreateTranslation(currentXPosition, currentYPosition));
Color foregroundColor = consoleBrush.Color;

switch (c)
switch (glyph)
{
case '\t':
case "\t":
{
const int tabSize = 8;
var consolePixel = new Pixel(' ', foregroundColor);
var consolePixel = new Pixel(new SimpleSymbol(' '), foregroundColor);
for (int j = 0; j < tabSize; j++)
{
Point newCharacterPoint = characterPoint.WithX(characterPoint.X + j);
Expand All @@ -525,26 +522,26 @@ private void DrawPixelAndMoveHead(ref Point head, Line line, LineStyle? lineStyl
currentXPosition += tabSize - 1;
}
break;
case '\n':
{
/* 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);*/
}
break;
case '\u200B':
currentXPosition--;
case "\r":
case "\f":
case "\n":
currentXPosition = 0;
currentYPosition++;
break;
default:
{
var consolePixel = new Pixel(c, foregroundColor, typeface.Style, typeface.Weight);
var symbol = new SimpleSymbol(glyph);
var consolePixel = new Pixel(symbol, foregroundColor, typeface.Style, typeface.Weight);
CurrentClip.ExecuteWithClipping(characterPoint, () =>
{
_pixelBuffer.Set((PixelBufferCoordinate)characterPoint,
(oldPixel, cp) => oldPixel.Blend(cp), consolePixel);
});

if (symbol.Width > 1)
currentXPosition += symbol.Width;
else
currentXPosition++;
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
using System;
using System.Diagnostics;

namespace Consolonia.Core.Drawing.PixelBufferImplementation
{
/// <summary>
/// https://en.wikipedia.org/wiki/Box-drawing_character
/// </summary>
[DebuggerDisplay("DrawingBox {Text}")]
public struct DrawingBoxSymbol : ISymbol
{
// all 0bXXXX_0000 are special values
private const byte BoldSymbol = 0b0001_0000;
private const byte EmptySymbol = 0b0;
private readonly byte _upRightDownLeft;

public DrawingBoxSymbol(byte upRightDownLeft)
{
_upRightDownLeft = upRightDownLeft;
Text = GetBoxSymbol(_upRightDownLeft).ToString();
}

private byte _upRightDownLeft;
public string Text { get; private init; }

public ushort Width { get; } = 1;

/// <summary>
/// https://en.wikipedia.org/wiki/Code_page_437
/// </summary>
char ISymbol.GetCharacter()
private static char GetBoxSymbol(byte upRightDownLeft)
{
//DOS linedraw characters are not ordered in any programmatic manner, and calculating a particular character shape needs to use a look-up table. from https://en.wikipedia.org/wiki/Box-drawing_character

byte leftPart = (byte)(_upRightDownLeft & 0b1111_0000);
byte leftPart = (byte)(upRightDownLeft & 0b1111_0000);
bool hasLeftPart = leftPart > 0;

switch (_upRightDownLeft & 0b0000_1111)
switch (upRightDownLeft & 0b0000_1111)
{
case 0b0000_1000:
case 0b0000_0010:
Expand All @@ -50,7 +56,7 @@ char ISymbol.GetCharacter()

default:
{
return _upRightDownLeft switch
return upRightDownLeft switch
{
EmptySymbol => char.MinValue,
BoldSymbol => '█',
Expand Down Expand Up @@ -101,27 +107,27 @@ public ISymbol Blend(ref ISymbol symbolAbove)
{
if (symbolAbove.IsWhiteSpace()) return this;

if (symbolAbove is not DrawingBoxSymbol drawingBoxSymbol) return symbolAbove;
if (symbolAbove is not DrawingBoxSymbol drawingBoxSymbol)
return symbolAbove;

if (drawingBoxSymbol._upRightDownLeft == BoldSymbol || _upRightDownLeft == BoldSymbol)
_upRightDownLeft = BoldSymbol;
else
_upRightDownLeft |= drawingBoxSymbol._upRightDownLeft;

return this;
return new DrawingBoxSymbol(BoldSymbol);

return new DrawingBoxSymbol((byte)(_upRightDownLeft | drawingBoxSymbol._upRightDownLeft));
}

public static byte UpRightDownLeftFromPattern(byte pattern, LineStyle lineStyle)
public static DrawingBoxSymbol UpRightDownLeftFromPattern(byte pattern, LineStyle lineStyle)
{
if (pattern == EmptySymbol) return EmptySymbol;
if (pattern == EmptySymbol) return new DrawingBoxSymbol(EmptySymbol);
switch (lineStyle)
{
case LineStyle.SingleLine:
return pattern;
return new DrawingBoxSymbol(pattern);
case LineStyle.Bold:
return BoldSymbol;
return new DrawingBoxSymbol(BoldSymbol);
case LineStyle.DoubleLine:
byte leftPart = (byte)(pattern << 4);
return (byte)(leftPart | pattern);
return new DrawingBoxSymbol((byte)(leftPart | pattern));
default:
throw new ArgumentOutOfRangeException(nameof(lineStyle), lineStyle, null);
}
Expand Down
17 changes: 16 additions & 1 deletion src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,23 @@ namespace Consolonia.Core.Drawing.PixelBufferImplementation
{
public interface ISymbol
{
char GetCharacter();
/// <summary>
/// The text for the symbol (This can be single character or unicode encoding for Emoji's and the like)
/// </summary>
string Text { get; }

/// <summary>
/// The number of characters the symbol takes up
/// </summary>
ushort Width { get; }

bool IsWhiteSpace();

/// <summary>
/// Blend 2 symbols together
/// </summary>
/// <param name="symbolAbove"></param>
/// <returns></returns>
ISymbol Blend(ref ISymbol symbolAbove);
}
}
Loading
Loading