Skip to content

Commit a06dad5

Browse files
authored
Merge pull request #3772 from BDisp/v2_3771_textview-no-printable-rune-fix
Fixes #3771. TextView doesn't consider no-printable rune in draw and cursor position.
2 parents bc1aeaa + ffe5154 commit a06dad5

34 files changed

+1680
-1145
lines changed

Terminal.Gui/Drawing/Cell.cs

Lines changed: 152 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,18 @@
44
/// Represents a single row/column in a Terminal.Gui rendering surface (e.g. <see cref="LineCanvas"/> and
55
/// <see cref="ConsoleDriver"/>).
66
/// </summary>
7-
public record struct Cell ()
7+
public record struct Cell (Attribute? Attribute = null, bool IsDirty = false, Rune Rune = default)
88
{
9-
109
/// <summary>The attributes to use when drawing the Glyph.</summary>
11-
public Attribute? Attribute { get; set; } = null;
10+
public Attribute? Attribute { get; set; } = Attribute;
1211

1312
/// <summary>
1413
/// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.Cell"/> has been modified since the
1514
/// last time it was drawn.
1615
/// </summary>
17-
public bool IsDirty { get; set; } = false;
16+
public bool IsDirty { get; set; } = IsDirty;
1817

19-
private Rune _rune = default;
18+
private Rune _rune = Rune;
2019

2120
/// <summary>The character to display. If <see cref="Rune"/> is <see langword="null"/>, then <see cref="Rune"/> is ignored.</summary>
2221
public Rune Rune
@@ -29,6 +28,8 @@ public Rune Rune
2928
}
3029
}
3130

31+
private List<Rune> _combiningMarks;
32+
3233
/// <summary>
3334
/// The combining marks for <see cref="Rune"/> that when combined makes this Cell a combining sequence. If
3435
/// <see cref="CombiningMarks"/> empty, then <see cref="CombiningMarks"/> is ignored.
@@ -37,8 +38,153 @@ public Rune Rune
3738
/// Only valid in the rare case where <see cref="Rune"/> is a combining sequence that could not be normalized to a
3839
/// single Rune.
3940
/// </remarks>
40-
internal List<Rune> CombiningMarks { get; } = new ();
41+
internal List<Rune> CombiningMarks
42+
{
43+
get => _combiningMarks ?? [];
44+
private set => _combiningMarks = value ?? [];
45+
}
4146

4247
/// <inheritdoc/>
4348
public override string ToString () { return $"[{Rune}, {Attribute}]"; }
49+
50+
/// <summary>Converts the string into a <see cref="List{Cell}"/>.</summary>
51+
/// <param name="str">The string to convert.</param>
52+
/// <param name="attribute">The <see cref="Gui.ColorScheme"/> to use.</param>
53+
/// <returns></returns>
54+
public static List<Cell> ToCellList (string str, Attribute? attribute = null)
55+
{
56+
List<Cell> cells = new ();
57+
58+
foreach (Rune rune in str.EnumerateRunes ())
59+
{
60+
cells.Add (new () { Rune = rune, Attribute = attribute });
61+
}
62+
63+
return cells;
64+
}
65+
66+
/// <summary>
67+
/// Splits a string into a List that will contain a <see cref="List{Cell}"/> for each line.
68+
/// </summary>
69+
/// <param name="content">The string content.</param>
70+
/// <param name="attribute">The color scheme.</param>
71+
/// <returns>A <see cref="List{Cell}"/> for each line.</returns>
72+
public static List<List<Cell>> StringToLinesOfCells (string content, Attribute? attribute = null)
73+
{
74+
List<Cell> cells = content.EnumerateRunes ()
75+
.Select (x => new Cell { Rune = x, Attribute = attribute })
76+
.ToList ();
77+
78+
return SplitNewLines (cells);
79+
}
80+
81+
/// <summary>Converts a <see cref="Cell"/> generic collection into a string.</summary>
82+
/// <param name="cells">The enumerable cell to convert.</param>
83+
/// <returns></returns>
84+
public static string ToString (IEnumerable<Cell> cells)
85+
{
86+
var str = string.Empty;
87+
88+
foreach (Cell cell in cells)
89+
{
90+
str += cell.Rune.ToString ();
91+
}
92+
93+
return str;
94+
}
95+
96+
/// <summary>Converts a <see cref="List{Cell}"/> generic collection into a string.</summary>
97+
/// <param name="cellsList">The enumerable cell to convert.</param>
98+
/// <returns></returns>
99+
public static string ToString (List<List<Cell>> cellsList)
100+
{
101+
var str = string.Empty;
102+
103+
for (var i = 0; i < cellsList.Count; i++)
104+
{
105+
IEnumerable<Cell> cellList = cellsList [i];
106+
str += ToString (cellList);
107+
108+
if (i + 1 < cellsList.Count)
109+
{
110+
str += Environment.NewLine;
111+
}
112+
}
113+
114+
return str;
115+
}
116+
117+
// Turns the string into cells, this does not split the contents on a newline if it is present.
118+
119+
internal static List<Cell> StringToCells (string str, Attribute? attribute = null)
120+
{
121+
List<Cell> cells = [];
122+
123+
foreach (Rune rune in str.ToRunes ())
124+
{
125+
cells.Add (new () { Rune = rune, Attribute = attribute });
126+
}
127+
128+
return cells;
129+
}
130+
131+
internal static List<Cell> ToCells (IEnumerable<Rune> runes, Attribute? attribute = null)
132+
{
133+
List<Cell> cells = new ();
134+
135+
foreach (Rune rune in runes)
136+
{
137+
cells.Add (new () { Rune = rune, Attribute = attribute });
138+
}
139+
140+
return cells;
141+
}
142+
143+
private static List<List<Cell>> SplitNewLines (List<Cell> cells)
144+
{
145+
List<List<Cell>> lines = [];
146+
int start = 0, i = 0;
147+
var hasCR = false;
148+
149+
// ASCII code 13 = Carriage Return.
150+
// ASCII code 10 = Line Feed.
151+
for (; i < cells.Count; i++)
152+
{
153+
if (cells [i].Rune.Value == 13)
154+
{
155+
hasCR = true;
156+
157+
continue;
158+
}
159+
160+
if (cells [i].Rune.Value == 10)
161+
{
162+
if (i - start > 0)
163+
{
164+
lines.Add (cells.GetRange (start, hasCR ? i - 1 - start : i - start));
165+
}
166+
else
167+
{
168+
lines.Add (StringToCells (string.Empty));
169+
}
170+
171+
start = i + 1;
172+
hasCR = false;
173+
}
174+
}
175+
176+
if (i - start >= 0)
177+
{
178+
lines.Add (cells.GetRange (start, i - start));
179+
}
180+
181+
return lines;
182+
}
183+
184+
/// <summary>
185+
/// Splits a rune cell list into a List that will contain a <see cref="List{Cell}"/> for each line.
186+
/// </summary>
187+
/// <param name="cells">The cells list.</param>
188+
/// <returns></returns>
189+
public static List<List<Cell>> ToCells (List<Cell> cells) { return SplitNewLines (cells); }
44190
}

Terminal.Gui/Views/RuneCellEventArgs.cs renamed to Terminal.Gui/Drawing/CellEventArgs.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
namespace Terminal.Gui;
22

3-
/// <summary>Args for events that relate to a specific <see cref="RuneCell"/>.</summary>
4-
public class RuneCellEventArgs
3+
/// <summary>Args for events that relate to a specific <see cref="Cell"/>.</summary>
4+
public record struct CellEventArgs
55
{
6-
/// <summary>Creates a new instance of the <see cref="RuneCellEventArgs"/> class.</summary>
6+
/// <summary>Creates a new instance of the <see cref="CellEventArgs"/> class.</summary>
77
/// <param name="line">The line.</param>
88
/// <param name="col">The col index.</param>
99
/// <param name="unwrappedPosition">The unwrapped row and col index.</param>
10-
public RuneCellEventArgs (List<RuneCell> line, int col, (int Row, int Col) unwrappedPosition)
10+
public CellEventArgs (List<Cell> line, int col, (int Row, int Col) unwrappedPosition)
1111
{
1212
Line = line;
1313
Col = col;
1414
UnwrappedPosition = unwrappedPosition;
1515
}
1616

17-
/// <summary>The index of the RuneCell in the line.</summary>
17+
/// <summary>The index of the Cell in the line.</summary>
1818
public int Col { get; }
1919

20-
/// <summary>The list of runes the RuneCell is part of.</summary>
21-
public List<RuneCell> Line { get; }
20+
/// <summary>The list of runes the Cell is part of.</summary>
21+
public List<Cell> Line { get; }
2222

2323
/// <summary>
24-
/// The unwrapped row and column index into the text containing the RuneCell. Unwrapped means the text without
24+
/// The unwrapped row and column index into the text containing the Cell. Unwrapped means the text without
2525
/// word wrapping or other visual formatting having been applied.
2626
/// </summary>
2727
public (int Row, int Col) UnwrappedPosition { get; }

Terminal.Gui/Drawing/LineCanvas.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public void AddLine (
138138
int length,
139139
Orientation orientation,
140140
LineStyle style,
141-
Attribute? attribute = default
141+
Attribute? attribute = null
142142
)
143143
{
144144
_cachedViewport = Rectangle.Empty;

Terminal.Gui/Drawing/StraightLine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public StraightLine (
1616
int length,
1717
Orientation orientation,
1818
LineStyle style,
19-
Attribute? attribute = default
19+
Attribute? attribute = null
2020
)
2121
{
2222
Start = start;

Terminal.Gui/Resources/Strings.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Terminal.Gui/Resources/Strings.fr-FR.resx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -117,27 +117,27 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<data name="ctxSelectAll" xml:space="preserve">
121+
<value>Tout _sélectionner</value>
122+
</data>
123+
<data name="ctxDeleteAll" xml:space="preserve">
124+
<value>_Tout supprimer</value>
125+
</data>
120126
<data name="ctxCopy" xml:space="preserve">
121127
<value>_Copier</value>
122128
</data>
123129
<data name="ctxCut" xml:space="preserve">
124130
<value>Co_uper</value>
125131
</data>
126-
<data name="ctxDeleteAll" xml:space="preserve">
127-
<value>_Tout supprimer</value>
128-
</data>
129132
<data name="ctxPaste" xml:space="preserve">
130133
<value>C_oller</value>
131134
</data>
132-
<data name="ctxRedo" xml:space="preserve">
133-
<value>_Rétablir</value>
134-
</data>
135-
<data name="ctxSelectAll" xml:space="preserve">
136-
<value>Tout _sélectionner</value>
137-
</data>
138135
<data name="ctxUndo" xml:space="preserve">
139136
<value>_Annuler</value>
140137
</data>
138+
<data name="ctxRedo" xml:space="preserve">
139+
<value>_Rétablir</value>
140+
</data>
141141
<data name="fdDirectory" xml:space="preserve">
142142
<value>_Dossier</value>
143143
</data>
@@ -168,16 +168,19 @@
168168
<data name="wzNext" xml:space="preserve">
169169
<value>Prochai_n...</value>
170170
</data>
171+
<data name="btnOpen" xml:space="preserve">
172+
<value>Ouvrir</value>
173+
</data>
171174
<data name="btnSave" xml:space="preserve">
172175
<value>Enregistrer</value>
173176
</data>
174177
<data name="btnSaveAs" xml:space="preserve">
175178
<value>E_nregistrer sous</value>
176179
</data>
177-
<data name="btnOpen" xml:space="preserve">
178-
<value>Ouvrir</value>
179-
</data>
180180
<data name="dpTitle" xml:space="preserve">
181181
<value>Sélecteur de Date</value>
182182
</data>
183+
<data name="ctxColors" xml:space="preserve">
184+
<value>Cou_leurs</value>
185+
</data>
183186
</root>

0 commit comments

Comments
 (0)