public void Sum_Of_ColumnWidth_Is_Always_Equal_To_ConsoleWidth_And_RuneCount_Is_Always_Equal_To_String_Length() { const int start = 0x000000; const int end = 0x10ffff; for (int i = start; i <= end; i++) { Rune r = new Rune((uint)i); if (!r.IsValid) { continue; } ustring us = ustring.Make(r); string hex = i.ToString("x6"); int v = int.Parse(hex, System.Globalization.NumberStyles.HexNumber); string s = char.ConvertFromUtf32(v); if (!r.IsSurrogatePair) { Assert.AreEqual(r.ToString(), us); Assert.AreEqual(us, s); Assert.AreEqual(Rune.ColumnWidth(r), us.ConsoleWidth); Assert.AreEqual(s.Sum(c => Rune.ColumnWidth(c)), us.ConsoleWidth); Assert.AreEqual(us.RuneCount, s.Length); } else { Assert.AreEqual(r.ToString(), us.ToString()); Assert.AreEqual(us.ToString(), s); Assert.AreEqual(Rune.ColumnWidth(r), us.ConsoleWidth); Assert.AreEqual(s.Sum(c => Rune.ColumnWidth(c)), us.ConsoleWidth); Assert.AreEqual(us.RuneCount, s.Length); } } }
public override void AddRune(Rune rune) { if (Clip.Contains(ccol, crow)) { if (needMove) { Curses.move(crow, ccol); needMove = false; } Curses.addch((int)(uint)rune); } else { needMove = true; } if (sync) { Application.Driver.Refresh(); } ccol++; var runeWidth = Rune.ColumnWidth(rune); if (runeWidth > 1) { for (int i = 1; i < runeWidth; i++) { ccol++; } } }
public void Test_Range(int start, int end) { for (int i = start; i <= end; i++) { Rune r = new Rune((uint)i); ustring us = ustring.Make(r); string hex = i.ToString("x6"); int v = int.Parse(hex, System.Globalization.NumberStyles.HexNumber); string s = char.ConvertFromUtf32(v); if (!r.IsSurrogatePair) { Assert.AreEqual(r.ToString(), us); Assert.AreEqual(us, s); Assert.AreEqual(Rune.ColumnWidth(r), us.ConsoleWidth); } else { Assert.AreEqual(r.ToString(), us.ToString()); Assert.AreEqual(us.ToString(), s); Assert.AreEqual(Rune.ColumnWidth(r), us.ConsoleWidth); } Assert.AreEqual(s.Sum(c => Rune.ColumnWidth(c)), us.ConsoleWidth); Assert.AreEqual(us.RuneCount, s.Length); } }
public override void AddRune(Rune rune) { var position = crow * Cols + ccol; if (Clip.Contains(ccol, crow)) { OutputBuffer [position].Attributes = (ushort)currentAttribute; OutputBuffer [position].Char.UnicodeChar = (char)rune; WindowsConsole.SmallRect.Update(ref damageRegion, (short)ccol, (short)crow); } ccol++; var runeWidth = Rune.ColumnWidth(rune); if (runeWidth > 1) { for (int i = 1; i < runeWidth; i++) { AddStr(" "); } } if (ccol == Cols) { ccol = 0; if (crow + 1 < Rows) { crow++; } } if (sync) { UpdateScreen(); } }
/// <summary> /// Returns the width of the line including prefix and the results /// of <see cref="TreeView{T}.AspectGetter"/> (the line body). /// </summary> /// <returns></returns> public virtual int GetWidth(ConsoleDriver driver) { return (GetLinePrefix(driver).Sum(Rune.ColumnWidth) + Rune.ColumnWidth(GetExpandableSymbol(driver)) + (tree.AspectGetter(Model) ?? "").Length); }
public void Test_SumColumnWidth_UnicodeLength() { Assert.Equal(11, "hello there".Sum(c => Rune.ColumnWidth(c))); // Creates a string with the peculiar (french?) r symbol String surrogate = "Les Mise" + Char.ConvertFromUtf32(Int32.Parse("0301", NumberStyles.HexNumber)) + "rables"; // The unicode width of this string is shorter than the string length! Assert.Equal(14, surrogate.Sum(c => Rune.ColumnWidth(c))); Assert.Equal(15, surrogate.Length); }
private void PopulateGraphResults(DataTable dt, string countColumnName, AggregateContinuousDateAxis axis) { // if (chart1.Legends.Count == 0) // chart1.Legends.Add(new Legend()); // clear any lingering settings graphView.Reset(); // Work out how much screen real estate we have var boundsWidth = graphView.Bounds.Width; var boundsHeight = graphView.Bounds.Height; if (boundsWidth == 0) { boundsWidth = TabView.Bounds.Width - 4; } if (boundsHeight == 0) { boundsHeight = TabView.Bounds.Height - 4; } var titleWidth = aggregate.Name.Sum(c => Rune.ColumnWidth(c)); var titleStartX = (boundsWidth / 2) - (titleWidth / 2); var title = new TextAnnotation() { ScreenPosition = new Point(titleStartX, 0), Text = aggregate.Name, BeforeSeries = false }; graphView.Annotations.Add(title); // if no time axis then we have a regular bar chart if (axis == null) { if (dt.Columns.Count == 2) { SetupBarSeries(dt, countColumnName, boundsWidth, boundsHeight); } else { SetupMultiBarSeries(dt, countColumnName, boundsWidth, boundsHeight); } } else { SetupLineGraph(dt, axis, countColumnName, boundsWidth, boundsHeight); } }
public override void AddRune(Rune rune) { if (contents.Length != Rows * Cols * 3) { return; } rune = MakePrintable(rune); var runeWidth = Rune.ColumnWidth(rune); if (Clip.Contains(ccol, crow) && ccol + Math.Max(runeWidth, 1) <= Cols) { contents [crow, ccol, 0] = (int)(uint)rune; contents [crow, ccol, 1] = currentAttribute; contents [crow, ccol, 2] = 1; dirtyLine [crow] = true; ccol++; if (runeWidth > 1) { for (int i = 1; i < runeWidth; i++) { if (ccol < cols) { contents [crow, ccol, 2] = 0; } else { break; } ccol++; } } } else if (ccol < cols && crow < rows) { contents [crow, ccol, 2] = 1; dirtyLine [crow] = true; } //if (ccol == Cols) { // ccol = 0; // if (crow + 1 < Rows) // crow++; //} if (sync) { UpdateScreen(); } }
public override void UpdateScreen() { int top = Top; int left = Left; int rows = Math.Min(FakeConsole.WindowHeight + top, Rows); int cols = Cols; var savedRow = FakeConsole.CursorTop; var savedCol = FakeConsole.CursorLeft; for (int row = 0; row < rows; row++) { if (!dirtyLine [row]) { continue; } dirtyLine [row] = false; for (int col = 0; col < cols; col++) { FakeConsole.CursorTop = row; FakeConsole.CursorLeft = col; for (; col < cols; col++) { if (col > 0 && contents [row, col, 2] == 0 && Rune.ColumnWidth((char)contents [row, col - 1, 0]) > 1) { FakeConsole.CursorLeft = col + 1; continue; } var color = contents [row, col, 1]; if (color != redrawColor) { SetColor(color); } FakeConsole.Write((char)contents [row, col, 0]); contents [row, col, 2] = 0; } } } FakeConsole.CursorTop = savedRow; FakeConsole.CursorLeft = savedCol; }
private string TruncateOrPad(string text, int width) { if (string.IsNullOrEmpty(text)) { return(text); } // if value is not wide enough if (text.Sum(c => Rune.ColumnWidth(c)) < width) { // pad it out with spaces to the given alignment int toPad = width - (text.Sum(c => Rune.ColumnWidth(c))); return(text + new string (' ', toPad)); } // value is too wide return(new string (text.TakeWhile(c => (width -= Rune.ColumnWidth(c)) >= 0).ToArray())); }
bool ProcessStringUseRune(string s) { var us = ustring.Make(s); int i = 0; string rs = ""; foreach (Rune rune in us) { if (rune == Rune.Error) { throw new Exception("String was not well-formed UTF-16."); } Assert.IsTrue(Rune.ValidRune(rune)); i += Rune.ColumnWidth(rune); // increment the iterator by the number of chars in this Rune rs += rune.ToString(); } Assert.AreEqual(us.ConsoleWidth, i); Assert.AreEqual(s, rs); return(true); }
bool ProcessStringUseRune(string s) { var us = ustring.Make(s); string rs = ""; Rune codePoint; List <Rune> runes = new List <Rune>(); int colWidth = 0; for (int i = 0; i < s.Length; i++) { Rune rune = new Rune(s[i]); if (rune.IsValid) { Assert.IsTrue(Rune.ValidRune(rune)); runes.Add(rune); Assert.AreEqual((uint)s[i], (uint)rune); Assert.False(rune.IsSurrogatePair); } else if (i + 1 < s.Length && (Rune.EncodeSurrogatePair(s[i], s[i + 1], out codePoint))) { Assert.IsFalse(Rune.ValidRune(rune)); rune = codePoint; runes.Add(rune); string sp = new string(new char[] { s[i], s[i + 1] }); Assert.AreEqual(sp, codePoint.ToString()); Assert.True(codePoint.IsSurrogatePair); i++; // Increment the iterator by the number of surrogate pair } else { Assert.False(rune.IsValid); throw new Exception("String was not well-formed UTF-16."); } colWidth += Rune.ColumnWidth(rune); // Increment the column width of this Rune rs += rune.ToString(); } Assert.AreEqual(us.ConsoleWidth, colWidth); Assert.AreEqual(s, rs); Assert.AreEqual(s, ustring.Make(runes).ToString()); return(true); }
public void Test_Right_To_Left_Runes() { Rune r0 = 0x020000; Rune r7 = 0x020007; Rune r1b = 0x02001b; Rune r9b = 0x02009b; Assert.AreEqual(1, Rune.ColumnWidth(r0)); Assert.AreEqual(1, Rune.ColumnWidth(r7)); Assert.AreEqual(1, Rune.ColumnWidth(r1b)); Assert.AreEqual(1, Rune.ColumnWidth(r9b)); Rune.DecodeSurrogatePair("𐨁", out char[] chars); var rtl = new Rune(chars[0], chars[1]); var rtlp = new Rune('\ud802', '\ude01'); var s = "\U00010a01"; Assert.AreEqual(0, Rune.ColumnWidth(rtl)); Assert.AreEqual(0, Rune.ColumnWidth(rtlp)); Assert.AreEqual(2, s.Length); }
public void Test_Surrogate_Pairs_Range() { for (uint h = 0xd800; h <= 0xdbff; h++) { for (uint l = 0xdc00; l <= 0xdfff; l++) { Rune r = new Rune(h, l); ustring us = ustring.Make(r); string hex = ((uint)r).ToString("x6"); int v = int.Parse(hex, System.Globalization.NumberStyles.HexNumber); string s = char.ConvertFromUtf32(v); Assert.True(v >= 0x10000 && v <= Rune.MaxRune); Assert.AreEqual(r.ToString(), us.ToString()); Assert.AreEqual(us.ToString(), s); Assert.AreEqual(Rune.ColumnWidth(r), us.ConsoleWidth); Assert.AreEqual(s.Sum(c => Rune.ColumnWidth(c)), us.ConsoleWidth); Assert.AreEqual(us.RuneCount, s.Length); } } }
/// <summary> /// Draws the line including any starting/ending anchors /// </summary> /// <param name="bounds"></param> public override void Redraw(Rect bounds) { base.Redraw(bounds); Move(0, 0); Driver.SetAttribute(GetNormalColor()); var hLineWidth = Math.Max(1, Rune.ColumnWidth(Driver.HLine)); var dEnd = Orientation == Orientation.Horizontal ? bounds.Width : bounds.Height; for (int d = 0; d < dEnd; d += hLineWidth) { if (Orientation == Orientation.Horizontal) { Move(d, 0); } else { Move(0, d); } Rune rune = LineRune; if (d == 0) { rune = StartingAnchor ?? LineRune; } else if (d == dEnd - 1) { rune = EndingAnchor ?? LineRune; } Driver.AddRune(rune); } }
void RenderUstr(ustring ustr, int col, int line, int width) { int byteLen = ustr.Length; int used = 0; for (int i = 0; i < byteLen;) { (var rune, var size) = Utf8.DecodeRune(ustr, i, i - byteLen); var count = Rune.ColumnWidth(rune); if (used + count >= width) { break; } Driver.AddRune(rune); used += count; i += size; } for (; used < width; used++) { Driver.AddRune(' '); } }
// A slightly adapted method from gui.cs: https://github.com/migueldeicaza/gui.cs/blob/fc1faba7452ccbdf49028ac49f0c9f0f42bbae91/Terminal.Gui/Views/ListView.cs#L433-L461 private void RenderUstr(ConsoleDriver driver, ustring ustr, int col, int line, int width) { int used = 0; int index = 0; while (index < ustr.Length) { (var rune, var size) = Utf8.DecodeRune(ustr, index, index - ustr.Length); var count = Rune.ColumnWidth(rune); if (used + count > width) { break; } driver.AddRune(rune); used += count; index += size; } while (used < width) { driver.AddRune(' '); used++; } }
void RenderLine(ConsoleDriver driver, IHasStats toRender, int col, int line, int width) { string suffix = " "; //Get relation to player if (toRender is IActor a) { var world = a.CurrentLocation.World; var relationship = world.Relationships.SumBetween(a, world.Player); if (relationship < -40) { suffix = "---"; } else if (relationship < -20) { suffix = "-- "; } else if (relationship < 0) { suffix = "- "; } else if (relationship > 40) { suffix = "+++"; } else if (relationship > 20) { suffix = "++ "; } else if (relationship > 0) { suffix = "+ "; } } //allow for the suffix var ustring = toRender.ToString(); ustring = ustring.Substring(0, Math.Min(ustring.Length, width - 3)) + suffix; ustring = ustring.PadRight(width); int byteLen = ustring.Length; int used = 0; for (int i = 0; i < byteLen;) { (var rune, var size) = Utf8.DecodeRune(ustring, i, i - byteLen); var count = Rune.ColumnWidth(rune); if (used + count >= width) { break; } if (rune == '-') { driver.SetAttribute(_red); } else if (rune == '+') { driver.SetAttribute(_green); } else { driver.SetAttribute(_normal); } driver.AddRune(rune); used += count; i += size; } for (; used < width; used++) { driver.AddRune(' '); } }
public void TestColumnWidth() { Assert.AreEqual(1, Rune.ColumnWidth(a)); Assert.AreEqual("a", a.ToString()); Assert.AreEqual(1, a.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(a)); Assert.AreEqual(1, Rune.ColumnWidth(b)); Assert.AreEqual("b", b.ToString()); Assert.AreEqual(1, b.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(b)); var rl = a < b; Assert.IsTrue(rl); Assert.AreEqual(1, Rune.ColumnWidth(c)); Assert.AreEqual("{", c.ToString()); Assert.AreEqual(1, c.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(c)); Assert.AreEqual(2, Rune.ColumnWidth(d)); Assert.AreEqual("ᅐ", d.ToString()); Assert.AreEqual(1, d.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(d)); Assert.AreEqual(0, Rune.ColumnWidth(e)); Assert.AreEqual("ᅡ", e.ToString()); Assert.AreEqual(1, e.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(e)); Assert.AreEqual(-1, Rune.ColumnWidth(f)); Assert.AreEqual(1, f.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(f)); Assert.AreEqual(-1, Rune.ColumnWidth(g)); Assert.AreEqual(1, g.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(g)); var uh = ustring.Make(h); (var runeh, var sizeh) = Rune.DecodeRune(uh); Assert.AreEqual(2, Rune.ColumnWidth(runeh)); Assert.AreEqual("🨁", h); Assert.AreEqual(2, runeh.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(runeh)); Assert.AreEqual(sizeh, Rune.RuneLen(runeh)); for (int i = 0; i < uh.Length - 1; i++) { Assert.False(Rune.DecodeSurrogatePair(uh[i], uh[i + 1]) > 0); } Assert.IsTrue(Rune.ValidRune(runeh)); Assert.True(Rune.Valid(uh.ToByteArray())); Assert.True(Rune.FullRune(uh.ToByteArray())); Assert.AreEqual(1, Rune.RuneCount(uh)); (var runelh, var sizelh) = Rune.DecodeLastRune(uh); Assert.AreEqual(2, Rune.ColumnWidth(runelh)); Assert.AreEqual(2, runelh.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(runelh)); Assert.AreEqual(sizelh, Rune.RuneLen(runelh)); Assert.IsTrue(Rune.ValidRune(runelh)); var ui = ustring.Make(i); (var runei, var sizei) = Rune.DecodeRune(ui); Assert.AreEqual(1, Rune.ColumnWidth(runei)); Assert.AreEqual("", i); Assert.AreEqual(2, runei.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(runei)); Assert.AreEqual(sizei, Rune.RuneLen(runei)); for (int i = 0; i < ui.Length - 1; i++) { Assert.False(Rune.DecodeSurrogatePair(ui[i], ui[i + 1]) > 0); } Assert.IsTrue(Rune.ValidRune(runei)); Assert.True(Rune.Valid(ui.ToByteArray())); Assert.True(Rune.FullRune(ui.ToByteArray())); (var runeli, var sizeli) = Rune.DecodeLastRune(ui); Assert.AreEqual(1, Rune.ColumnWidth(runeli)); Assert.AreEqual(2, runeli.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(runeli)); Assert.AreEqual(sizeli, Rune.RuneLen(runeli)); Assert.IsTrue(Rune.ValidRune(runeli)); Assert.AreNotEqual(Rune.ColumnWidth(runeh), Rune.ColumnWidth(runei)); Assert.AreNotEqual(h, i); Assert.AreEqual(runeh.ToString().Length, runei.ToString().Length); Assert.AreEqual(Rune.RuneLen(runeh), Rune.RuneLen(runei)); Assert.AreEqual(Rune.RuneLen(runeh), Rune.RuneLen(runei)); var uj = ustring.Make(j); (var runej, var sizej) = Rune.DecodeRune(uj); Assert.AreEqual(0, Rune.ColumnWidth(j)); Assert.AreEqual(0, Rune.ColumnWidth(uj.RuneAt(0))); Assert.AreEqual(j, uj.RuneAt(0)); Assert.AreEqual("⃐", j.ToString()); Assert.AreEqual("⃐", uj.ToString()); Assert.AreEqual(1, j.ToString().Length); Assert.AreEqual(1, runej.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(j)); Assert.AreEqual(sizej, Rune.RuneLen(runej)); Assert.AreEqual(1, Rune.ColumnWidth(k)); Assert.AreEqual("■", k.ToString()); Assert.AreEqual(1, k.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(k)); Assert.AreEqual(1, Rune.ColumnWidth(l)); Assert.AreEqual("□", l.ToString()); Assert.AreEqual(1, l.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(l)); Assert.AreEqual(1, Rune.ColumnWidth(m)); Assert.AreEqual("", m.ToString()); Assert.AreEqual(1, m.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(m)); var rn = Rune.DecodeRune(ustring.Make(n)).rune; Assert.AreEqual(1, Rune.ColumnWidth(rn)); Assert.AreEqual("🍕", rn.ToString()); Assert.AreEqual(2, rn.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(rn)); Assert.AreEqual(1, Rune.ColumnWidth(o)); Assert.AreEqual("🍕", o.ToString()); Assert.AreEqual(2, o.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(o)); var rp = Rune.DecodeRune(ustring.Make(p)).rune; Assert.AreEqual(1, Rune.ColumnWidth(rp)); Assert.AreEqual("🍕", p); Assert.AreEqual(2, p.Length); Assert.AreEqual(4, Rune.RuneLen(rp)); Assert.AreEqual(1, Rune.ColumnWidth(q)); Assert.AreEqual("℃", q.ToString()); Assert.AreEqual(1, q.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(q)); var rq = Rune.DecodeRune(ustring.Make(q)).rune; Assert.AreEqual(1, Rune.ColumnWidth(rq)); Assert.AreEqual("℃", rq.ToString()); Assert.AreEqual(1, rq.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(rq)); Assert.AreEqual(2, Rune.ColumnWidth(r)); Assert.AreEqual("ᄀ", r.ToString()); Assert.AreEqual(1, r.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(r)); Assert.AreEqual(1, Rune.ColumnWidth(s)); Assert.AreEqual("━", s.ToString()); Assert.AreEqual(1, s.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(s)); var buff = new byte[4]; var sb = Rune.EncodeRune('\u2503', buff); var scb = char.ConvertToUtf32("℃", 0); var scr = '℃'.ToString().Length; }
public override void AddRune(Rune rune) { rune = MakePrintable(rune); var runeWidth = Rune.ColumnWidth(rune); var validClip = IsValidContent(ccol, crow, Clip); if (validClip) { if (needMove) { //MockConsole.CursorLeft = ccol; //MockConsole.CursorTop = crow; needMove = false; } if (runeWidth < 2 && ccol > 0 && Rune.ColumnWidth((char)contents [crow, ccol - 1, 0]) > 1) { contents [crow, ccol - 1, 0] = (int)(uint)' '; } else if (runeWidth < 2 && ccol <= Clip.Right - 1 && Rune.ColumnWidth((char)contents [crow, ccol, 0]) > 1) { contents [crow, ccol + 1, 0] = (int)(uint)' '; contents [crow, ccol + 1, 2] = 1; } if (runeWidth > 1 && ccol == Clip.Right - 1) { contents [crow, ccol, 0] = (int)(uint)' '; } else { contents [crow, ccol, 0] = (int)(uint)rune; } contents [crow, ccol, 1] = currentAttribute; contents [crow, ccol, 2] = 1; dirtyLine [crow] = true; } else { needMove = true; } ccol++; if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { contents [crow, ccol, 1] = currentAttribute; contents [crow, ccol, 2] = 0; } ccol++; } //if (ccol == Cols) { // ccol = 0; // if (crow + 1 < Rows) // crow++; //} if (sync) { UpdateScreen(); } }
/// <summary> /// Renders the current <see cref="Model"/> on the specified line <paramref name="y"/> /// </summary> /// <param name="driver"></param> /// <param name="colorScheme"></param> /// <param name="y"></param> /// <param name="availableWidth"></param> public virtual void Draw(ConsoleDriver driver, ColorScheme colorScheme, int y, int availableWidth) { // true if the current line of the tree is the selected one and control has focus bool isSelected = tree.IsSelected(Model) && tree.HasFocus; Attribute lineColor = isSelected ? colorScheme.Focus : colorScheme.Normal; driver.SetAttribute(lineColor); // Everything on line before the expansion run and branch text Rune [] prefix = GetLinePrefix(driver).ToArray(); Rune expansion = GetExpandableSymbol(driver); string lineBody = tree.AspectGetter(Model) ?? ""; tree.Move(0, y); // if we have scrolled to the right then bits of the prefix will have dispeared off the screen int toSkip = tree.ScrollOffsetHorizontal; // Draw the line prefix (all paralell lanes or whitespace and an expand/collapse/leaf symbol) foreach (Rune r in prefix) { if (toSkip > 0) { toSkip--; } else { driver.AddRune(r); availableWidth -= Rune.ColumnWidth(r); } } // pick color for expanded symbol if (tree.Style.ColorExpandSymbol || tree.Style.InvertExpandSymbolColors) { Attribute color; if (tree.Style.ColorExpandSymbol) { color = isSelected ? tree.ColorScheme.HotFocus : tree.ColorScheme.HotNormal; } else { color = lineColor; } if (tree.Style.InvertExpandSymbolColors) { color = new Attribute(color.Background, color.Foreground); } driver.SetAttribute(color); } if (toSkip > 0) { toSkip--; } else { driver.AddRune(expansion); availableWidth -= Rune.ColumnWidth(expansion); } // horizontal scrolling has already skipped the prefix but now must also skip some of the line body if (toSkip > 0) { if (toSkip > lineBody.Length) { lineBody = ""; } else { lineBody = lineBody.Substring(toSkip); } } // If body of line is too long if (lineBody.Sum(l => Rune.ColumnWidth(l)) > availableWidth) { // remaining space is zero and truncate the line lineBody = new string (lineBody.TakeWhile(c => (availableWidth -= Rune.ColumnWidth(c)) >= 0).ToArray()); availableWidth = 0; } else { // line is short so remaining width will be whatever comes after the line body availableWidth -= lineBody.Length; } // default behaviour is for model to use the color scheme // of the tree view var modelColor = lineColor; // if custom color delegate invoke it if (tree.ColorGetter != null) { var modelScheme = tree.ColorGetter(Model); // if custom color scheme is defined for this Model if (modelScheme != null) { // use it modelColor = isSelected ? modelScheme.Focus : modelScheme.Normal; } } driver.SetAttribute(modelColor); driver.AddStr(lineBody); driver.SetAttribute(lineColor); if (availableWidth > 0) { driver.AddStr(new string (' ', availableWidth)); } driver.SetAttribute(colorScheme.Normal); }
public void TestColumnWidth() { Rune a = 'a'; Rune b = 'b'; Rune c = 123; Rune d = '\u1150'; // 0x1150 ᅐ Unicode Technical Report #11 Rune e = '\u1161'; // 0x1161 ᅡ null character with column equal to 0 Rune f = 31; // non printable character Rune g = 127; // non printable character string h = "\U0001fa01"; string i = "\U000e0fe1"; Rune j = '\u20D0'; Rune k = '\u25a0'; Rune l = '\u25a1'; Rune m = '\uf61e'; byte[] n = new byte[4] { 0xf0, 0x9f, 0x8d, 0x95 }; // UTF-8 Encoding Rune o = new Rune('\ud83c', '\udf55'); // UTF-16 Encoding; string p = "\U0001F355"; // UTF-32 Encoding Rune q = '\u2103'; Rune r = '\u1100'; Rune s = '\u2501'; Assert.AreEqual(1, Rune.ColumnWidth(a)); Assert.AreEqual("a", a.ToString()); Assert.AreEqual(1, a.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(a)); Assert.AreEqual(1, Rune.ColumnWidth(b)); Assert.AreEqual("b", b.ToString()); Assert.AreEqual(1, b.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(b)); var rl = a < b; Assert.IsTrue(rl); Assert.AreEqual(1, Rune.ColumnWidth(c)); Assert.AreEqual("{", c.ToString()); Assert.AreEqual(1, c.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(c)); Assert.AreEqual(2, Rune.ColumnWidth(d)); Assert.AreEqual("ᅐ", d.ToString()); Assert.AreEqual(1, d.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(d)); Assert.AreEqual(2, Rune.ColumnWidth(e)); string join = "\u1104\u1161"; Assert.AreEqual("따", join); Assert.AreEqual(4, join.Sum(x => Rune.ColumnWidth(x))); Assert.IsFalse(Rune.DecodeSurrogatePair(join, out _)); Assert.AreEqual("ᅡ", e.ToString()); Assert.AreEqual(1, e.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(e)); Assert.AreEqual(-1, Rune.ColumnWidth(f)); Assert.AreEqual(1, f.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(f)); Assert.AreEqual(-1, Rune.ColumnWidth(g)); Assert.AreEqual(1, g.ToString().Length); Assert.AreEqual(1, Rune.RuneLen(g)); var uh = ustring.Make(h); (var runeh, var sizeh) = Rune.DecodeRune(uh); Assert.AreEqual(2, Rune.ColumnWidth(runeh)); Assert.AreEqual("🨁", h); Assert.AreEqual(2, runeh.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(runeh)); Assert.AreEqual(sizeh, Rune.RuneLen(runeh)); for (int x = 0; x < uh.Length - 1; x++) { Assert.False(Rune.EncodeSurrogatePair(uh[x], uh[x + 1], out _)); } Assert.IsTrue(Rune.ValidRune(runeh)); Assert.True(Rune.Valid(uh.ToByteArray())); Assert.True(Rune.FullRune(uh.ToByteArray())); Assert.AreEqual(1, Rune.RuneCount(uh)); (var runelh, var sizelh) = Rune.DecodeLastRune(uh); Assert.AreEqual(2, Rune.ColumnWidth(runelh)); Assert.AreEqual(2, runelh.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(runelh)); Assert.AreEqual(sizelh, Rune.RuneLen(runelh)); Assert.IsTrue(Rune.ValidRune(runelh)); var ui = ustring.Make(i); (var runei, var sizei) = Rune.DecodeRune(ui); Assert.AreEqual(1, Rune.ColumnWidth(runei)); Assert.AreEqual("", i); Assert.AreEqual(2, runei.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(runei)); Assert.AreEqual(sizei, Rune.RuneLen(runei)); for (int x = 0; x < ui.Length - 1; x++) { Assert.False(Rune.EncodeSurrogatePair(ui[x], ui[x + 1], out _)); } Assert.IsTrue(Rune.ValidRune(runei)); Assert.True(Rune.Valid(ui.ToByteArray())); Assert.True(Rune.FullRune(ui.ToByteArray())); (var runeli, var sizeli) = Rune.DecodeLastRune(ui); Assert.AreEqual(1, Rune.ColumnWidth(runeli)); Assert.AreEqual(2, runeli.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(runeli)); Assert.AreEqual(sizeli, Rune.RuneLen(runeli)); Assert.IsTrue(Rune.ValidRune(runeli)); Assert.AreNotEqual(Rune.ColumnWidth(runeh), Rune.ColumnWidth(runei)); Assert.AreNotEqual(h, i); Assert.AreEqual(runeh.ToString().Length, runei.ToString().Length); Assert.AreEqual(Rune.RuneLen(runeh), Rune.RuneLen(runei)); Assert.AreEqual(Rune.RuneLen(runeh), Rune.RuneLen(runei)); var uj = ustring.Make(j); (var runej, var sizej) = Rune.DecodeRune(uj); Assert.AreEqual(0, Rune.ColumnWidth(j)); Assert.AreEqual(0, Rune.ColumnWidth(uj.RuneAt(0))); Assert.AreEqual(j, uj.RuneAt(0)); Assert.AreEqual("⃐", j.ToString()); Assert.AreEqual("⃐", uj.ToString()); Assert.AreEqual(1, j.ToString().Length); Assert.AreEqual(1, runej.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(j)); Assert.AreEqual(sizej, Rune.RuneLen(runej)); Assert.AreEqual(1, Rune.ColumnWidth(k)); Assert.AreEqual("■", k.ToString()); Assert.AreEqual(1, k.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(k)); Assert.AreEqual(1, Rune.ColumnWidth(l)); Assert.AreEqual("□", l.ToString()); Assert.AreEqual(1, l.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(l)); Assert.AreEqual(1, Rune.ColumnWidth(m)); Assert.AreEqual("", m.ToString()); Assert.AreEqual(1, m.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(m)); var rn = Rune.DecodeRune(ustring.Make(n)).rune; Assert.AreEqual(1, Rune.ColumnWidth(rn)); Assert.AreEqual("🍕", rn.ToString()); Assert.AreEqual(2, rn.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(rn)); Assert.AreEqual(1, Rune.ColumnWidth(o)); Assert.AreEqual("🍕", o.ToString()); Assert.AreEqual(2, o.ToString().Length); Assert.AreEqual(4, Rune.RuneLen(o)); var rp = Rune.DecodeRune(ustring.Make(p)).rune; Assert.AreEqual(1, Rune.ColumnWidth(rp)); Assert.AreEqual("🍕", p); Assert.AreEqual(2, p.Length); Assert.AreEqual(4, Rune.RuneLen(rp)); Assert.AreEqual(1, Rune.ColumnWidth(q)); Assert.AreEqual("℃", q.ToString()); Assert.AreEqual(1, q.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(q)); var rq = Rune.DecodeRune(ustring.Make(q)).rune; Assert.AreEqual(1, Rune.ColumnWidth(rq)); Assert.AreEqual("℃", rq.ToString()); Assert.AreEqual(1, rq.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(rq)); Assert.AreEqual(2, Rune.ColumnWidth(r)); Assert.AreEqual("ᄀ", r.ToString()); Assert.AreEqual(1, r.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(r)); Assert.AreEqual(1, Rune.ColumnWidth(s)); Assert.AreEqual("━", s.ToString()); Assert.AreEqual(1, s.ToString().Length); Assert.AreEqual(3, Rune.RuneLen(s)); var buff = new byte[4]; var sb = Rune.EncodeRune('\u2503', buff); Assert.AreEqual(1, Rune.ColumnWidth('\u2503')); (var rune, var size) = Rune.DecodeRune(ustring.Make('\u2503')); Assert.AreEqual(sb, size); Assert.AreEqual('\u2503', (uint)rune); var scb = char.ConvertToUtf32("℃", 0); var scr = '℃'.ToString().Length; Assert.AreEqual(scr, Rune.ColumnWidth((uint)scb)); buff = new byte[4]; sb = Rune.EncodeRune('\u1100', buff); Assert.AreEqual(2, Rune.ColumnWidth('\u1100')); Assert.AreEqual(2, ustring.Make('\u1100').ConsoleWidth); Assert.AreEqual(1, '\u1100'.ToString().Length); // Length as string returns 1 but in reality it occupies 2 columns. (rune, size) = Rune.DecodeRune(ustring.Make('\u1100')); Assert.AreEqual(sb, size); Assert.AreEqual('\u1100', (uint)rune); string str = "\u2615"; Assert.AreEqual("☕", str); Assert.AreEqual(1, str.Sum(x => Rune.ColumnWidth(x))); Assert.AreEqual(1, ((ustring)str).ConsoleWidth); Assert.AreEqual(1, Rune.RuneCount(str)); Assert.AreEqual(1, str.Length); str = "\u2615\ufe0f"; // Identical but \ufe0f forces it to be rendered as a colorful image as compared to a monochrome text variant. Assert.AreEqual("☕️", str); Assert.AreEqual(1, str.Sum(x => Rune.ColumnWidth(x))); Assert.AreEqual(1, ((ustring)str).ConsoleWidth); Assert.AreEqual(2, Rune.RuneCount(str)); Assert.AreEqual(2, str.Length); str = "\u231a"; Assert.AreEqual("⌚", str); Assert.AreEqual(2, str.Sum(x => Rune.ColumnWidth(x))); Assert.AreEqual(2, ((ustring)str).ConsoleWidth); Assert.AreEqual(1, Rune.RuneCount(str)); Assert.AreEqual(1, str.Length); str = "\u231b"; Assert.AreEqual("⌛", str); Assert.AreEqual(2, str.Sum(x => Rune.ColumnWidth(x))); Assert.AreEqual(2, ((ustring)str).ConsoleWidth); Assert.AreEqual(1, Rune.RuneCount(str)); Assert.AreEqual(1, str.Length); str = "\u231c"; Assert.AreEqual("⌜", str); Assert.AreEqual(1, str.Sum(x => Rune.ColumnWidth(x))); Assert.AreEqual(1, ((ustring)str).ConsoleWidth); Assert.AreEqual(1, Rune.RuneCount(str)); Assert.AreEqual(1, str.Length); str = "\u1dc0"; Assert.AreEqual("᷀", str); Assert.AreEqual(0, str.Sum(x => Rune.ColumnWidth(x))); Assert.AreEqual(0, ((ustring)str).ConsoleWidth); Assert.AreEqual(1, Rune.RuneCount(str)); Assert.AreEqual(1, str.Length); str = "\ud83e\udd16"; Assert.AreEqual("🤖", str); Assert.AreEqual(2, str.Sum(x => Rune.ColumnWidth(x))); Assert.AreEqual(2, ((ustring)str).ConsoleWidth); Assert.AreEqual(1, Rune.RuneCount(str)); // Here returns 1 because is a valid surrogate pair resulting in only rune >=U+10000..U+10FFFF Assert.AreEqual(2, str.Length); // String always preserves the originals values of each surrogate pair str = "\U0001f9e0"; Assert.AreEqual("🧠", str); Assert.AreEqual(2, str.Sum(x => Rune.ColumnWidth(x))); Assert.AreEqual(2, ((ustring)str).ConsoleWidth); Assert.AreEqual(1, Rune.RuneCount(str)); Assert.AreEqual(2, str.Length); }
public void TestRune() { Rune a = new Rune('a'); Assert.AreEqual(1, Rune.ColumnWidth(a)); Assert.AreEqual(1, a.ToString().Length); Assert.AreEqual("a", a.ToString()); Rune b = new Rune(0x0061); Assert.AreEqual(1, Rune.ColumnWidth(b)); Assert.AreEqual(1, b.ToString().Length); Assert.AreEqual("a", b.ToString()); Rune c = new Rune('\u0061'); Assert.AreEqual(1, Rune.ColumnWidth(c)); Assert.AreEqual(1, c.ToString().Length); Assert.AreEqual("a", c.ToString()); Rune d = new Rune(0x10421); Assert.AreEqual(1, Rune.ColumnWidth(d)); Assert.AreEqual(2, d.ToString().Length); Assert.AreEqual("𐐡", d.ToString()); Assert.False(Rune.EncodeSurrogatePair('\ud799', '\udc21', out _)); Assert.Throws <ArgumentOutOfRangeException>(() => new Rune('\ud799', '\udc21')); Rune e = new Rune('\ud801', '\udc21'); Assert.AreEqual(1, Rune.ColumnWidth(e)); Assert.AreEqual(2, e.ToString().Length); Assert.AreEqual("𐐡", e.ToString()); Assert.False(new Rune('\ud801').IsValid); Rune f = new Rune('\ud83c', '\udf39'); Assert.AreEqual(1, Rune.ColumnWidth(f)); Assert.AreEqual(2, f.ToString().Length); Assert.AreEqual("🌹", f.ToString()); Assert.DoesNotThrow(() => new Rune(0x10ffff)); Rune g = new Rune(0x10ffff); string s = "\U0010ffff"; Assert.AreEqual(1, Rune.ColumnWidth(g)); Assert.AreEqual(1, ustring.Make(s).ConsoleWidth); Assert.AreEqual(2, g.ToString().Length); Assert.AreEqual(2, s.Length); Assert.AreEqual("", g.ToString()); Assert.AreEqual("", s); Assert.AreEqual(g.ToString(), s); Assert.Throws <ArgumentOutOfRangeException>(() => new Rune(0x12345678)); var h = new Rune('\u1150'); Assert.AreEqual(2, Rune.ColumnWidth(h)); Assert.AreEqual(1, h.ToString().Length); Assert.AreEqual("ᅐ", h.ToString()); var i = new Rune('\u4F60'); Assert.AreEqual(2, Rune.ColumnWidth(i)); Assert.AreEqual(1, i.ToString().Length); Assert.AreEqual("你", i.ToString()); var j = new Rune('\u597D'); Assert.AreEqual(2, Rune.ColumnWidth(j)); Assert.AreEqual(1, j.ToString().Length); Assert.AreEqual("好", j.ToString()); var k = new Rune('\ud83d', '\udc02'); Assert.AreEqual(1, Rune.ColumnWidth(k)); Assert.AreEqual(2, k.ToString().Length); Assert.AreEqual("🐂", k.ToString()); var l = new Rune('\ud801', '\udcbb'); Assert.AreEqual(1, Rune.ColumnWidth(l)); Assert.AreEqual(2, l.ToString().Length); Assert.AreEqual("𐒻", l.ToString()); var m = new Rune('\ud801', '\udccf'); Assert.AreEqual(1, Rune.ColumnWidth(m)); Assert.AreEqual(2, m.ToString().Length); Assert.AreEqual("𐓏", m.ToString()); var n = new Rune('\u00e1'); Assert.AreEqual(1, Rune.ColumnWidth(n)); Assert.AreEqual(1, n.ToString().Length); Assert.AreEqual("á", n.ToString()); var o = new Rune('\ud83d', '\udd2e'); Assert.AreEqual(1, Rune.ColumnWidth(o)); Assert.AreEqual(2, o.ToString().Length); Assert.AreEqual("🔮", o.ToString()); var p = new Rune('\u2329'); Assert.AreEqual(1, Rune.ColumnWidth(p)); Assert.AreEqual(1, p.ToString().Length); Assert.AreEqual("〈", p.ToString()); var q = new Rune('\u232a'); Assert.AreEqual(1, Rune.ColumnWidth(q)); Assert.AreEqual(1, q.ToString().Length); Assert.AreEqual("〉", q.ToString()); var r = Rune.DecodeRune(ustring.Make("\U0000232a")).rune; Assert.AreEqual(1, Rune.ColumnWidth(r)); Assert.AreEqual(1, r.ToString().Length); Assert.AreEqual("〉", r.ToString()); PrintTextElementCount(ustring.Make('\u00e1'), "á", 1, 1, 1, 1); PrintTextElementCount(ustring.Make('\u0061', '\u0301'), "á", 1, 2, 2, 1); PrintTextElementCount(ustring.Make('\u0065', '\u0301'), "é", 1, 2, 2, 1); PrintTextElementCount(ustring.Make(new Rune[] { new Rune(0x1f469), new Rune(0x1f3fd), new Rune('\u200d'), new Rune(0x1f692) }), "👩🏽🚒", 3, 7, 7, 4); PrintTextElementCount(ustring.Make(new Rune[] { new Rune(0x1f469), new Rune(0x1f3fd), new Rune('\u200d'), new Rune(0x1f692) }), "\U0001f469\U0001f3fd\u200d\U0001f692", 3, 7, 7, 4); PrintTextElementCount(ustring.Make(new Rune('\ud801', '\udccf')), "\ud801\udccf", 1, 2, 2, 1); }
public void Test_IsWideChar() { Assert.True(Rune.IsWideChar(0x115e)); Assert.AreEqual(2, Rune.ColumnWidth(0x115e)); Assert.False(Rune.IsWideChar(0x116f)); }
public void Test_IsNonSpacingChar() { Rune l = '\u0370'; Assert.False(Rune.IsNonSpacingChar(l, out _)); Assert.AreEqual(1, Rune.ColumnWidth(l)); Assert.AreEqual(1, ustring.Make(l).ConsoleWidth); Rune ns = '\u302a'; Assert.True(Rune.IsNonSpacingChar(ns, out _)); Assert.AreEqual(2, Rune.ColumnWidth(ns)); Assert.AreEqual(2, ustring.Make(ns).ConsoleWidth); l = '\u006f'; ns = '\u0302'; var s = "\u006f\u0302"; Assert.AreEqual(1, Rune.ColumnWidth(l)); Assert.AreEqual(0, Rune.ColumnWidth(ns)); var ul = ustring.Make(l); Assert.AreEqual("o", ul); var uns = ustring.Make(ns); Assert.AreEqual("̂", uns); var f = ustring.Make($"{l}{ns}"); Assert.AreEqual("ô", f); Assert.AreEqual(f, s); Assert.AreEqual(1, f.ConsoleWidth); Assert.AreEqual(1, s.Sum(c => Rune.ColumnWidth(c))); Assert.AreEqual(2, s.Length); (var rune, var size) = Rune.DecodeRune(f); Assert.AreEqual(rune, l); Assert.AreEqual(1, size); l = '\u0041'; ns = '\u0305'; s = "\u0041\u0305"; Assert.AreEqual(1, Rune.ColumnWidth(l)); Assert.AreEqual(0, Rune.ColumnWidth(ns)); ul = ustring.Make(l); Assert.AreEqual("A", ul); uns = ustring.Make(ns); Assert.AreEqual("̅", uns); f = ustring.Make($"{l}{ns}"); Assert.AreEqual("A̅", f); Assert.AreEqual(f, s); Assert.AreEqual(1, f.ConsoleWidth); Assert.AreEqual(1, s.Sum(c => Rune.ColumnWidth(c))); Assert.AreEqual(2, s.Length); (rune, size) = Rune.DecodeRune(f); Assert.AreEqual(rune, l); Assert.AreEqual(1, size); l = '\u0061'; ns = '\u0308'; s = "\u0061\u0308"; Assert.AreEqual(1, Rune.ColumnWidth(l)); Assert.AreEqual(0, Rune.ColumnWidth(ns)); ul = ustring.Make(l); Assert.AreEqual("a", ul); uns = ustring.Make(ns); Assert.AreEqual("̈", uns); f = ustring.Make($"{l}{ns}"); Assert.AreEqual("ä", f); Assert.AreEqual(f, s); Assert.AreEqual(1, f.ConsoleWidth); Assert.AreEqual(1, s.Sum(c => Rune.ColumnWidth(c))); Assert.AreEqual(2, s.Length); (rune, size) = Rune.DecodeRune(f); Assert.AreEqual(rune, l); Assert.AreEqual(1, size); l = '\u4f00'; ns = '\u302a'; s = "\u4f00\u302a"; Assert.AreEqual(2, Rune.ColumnWidth(l)); Assert.AreEqual(2, Rune.ColumnWidth(ns)); ul = ustring.Make(l); Assert.AreEqual("伀", ul); uns = ustring.Make(ns); Assert.AreEqual("〪", uns); f = ustring.Make($"{l}{ns}"); Assert.AreEqual("伀〪", f); // Occupies 4 columns. Assert.AreEqual(f, s); Assert.AreEqual(4, f.ConsoleWidth); Assert.AreEqual(4, s.Sum(c => Rune.ColumnWidth(c))); Assert.AreEqual(2, s.Length); (rune, size) = Rune.DecodeRune(f); Assert.AreEqual(rune, l); Assert.AreEqual(3, size); }