Skip to content

Commit d5a780b

Browse files
committed
Fixed WriteAsciiStyled
1 parent d50307a commit d5a780b

File tree

9 files changed

+241
-27
lines changed

9 files changed

+241
-27
lines changed

src/Colorful.Console.Tests/project.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
2-
"version": "1.0.4",
2+
"version": "1.0.5",
33
"title": "Colorful.Console Tests",
44
"description": "Style your C# console output!",
55
"releaseNotes": "Switched to DNX",
6-
"authors": [ "Tom Akita", "Muhammad Rehan Saeed" ],
6+
"authors": [ "Tom Akita", "Muhammad Rehan Saeed", "Matt Furden" ],
77
"owners": [ "Tom Akita" ],
88
"copyright": "@ Tom Akita. All rights Reserved.",
99
"tags": [ "Style", "Styled", "Output", "Colourful", "Colorful", "Console", "Command", "Line", "ASCII", "Art", "FIGlet" ],
@@ -19,7 +19,7 @@
1919
"net461": { }
2020
},
2121
"dependencies": {
22-
"Colorful.Console": "1.0.4",
22+
"Colorful.Console": "1.0.5",
2323
"NUnit": "3.0.1",
2424
"NUnit.Runners": "3.0.1"
2525
}

src/Colorful.Console/ColorfulConsoleBack.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,34 @@ private static void MapToScreen(IEnumerable<KeyValuePair<string, Color>> styleMa
5050
System.Console.ResetColor();
5151
}
5252

53+
private static void MapToScreen(StyledString styledString, string trailer)
54+
{
55+
int rowLength = styledString.CharacterGeometry.GetLength(0);
56+
int columnLength = styledString.CharacterGeometry.GetLength(1);
57+
for (int row = 0; row < rowLength; row++)
58+
{
59+
for (int column = 0; column < columnLength; column++)
60+
{
61+
System.Console.ForegroundColor = colorManager.GetConsoleColor(styledString.ColorGeometry[row, column]);
62+
63+
if (row == rowLength - 1 && column == columnLength - 1)
64+
{
65+
System.Console.Write(styledString.CharacterGeometry[row, column] + trailer);
66+
}
67+
else if (column == columnLength - 1)
68+
{
69+
System.Console.Write(styledString.CharacterGeometry[row, column] + "\r\n");
70+
}
71+
else
72+
{
73+
System.Console.Write(styledString.CharacterGeometry[row, column]);
74+
}
75+
}
76+
}
77+
78+
System.Console.ResetColor();
79+
}
80+
5381
private static void WriteInColor<T>(Action<T> action, T target, Color color)
5482
{
5583
System.Console.ForegroundColor = colorManager.GetConsoleColor(color);
@@ -88,6 +116,45 @@ private static void WriteInColorStyled<T>(string trailer, T target, StyleSheet s
88116
MapToScreen(annotationMap, trailer);
89117
}
90118

119+
private static void WriteAsciiInColorStyled(string trailer, StyledString target, StyleSheet styleSheet)
120+
{
121+
TextAnnotator annotator = new TextAnnotator(styleSheet);
122+
List<KeyValuePair<string, Color>> annotationMap = annotator.GetAnnotationMap(target.AbstractValue); // Should eventually be target.AsStyledString() everywhere...?
123+
124+
PopulateColorGeometry(annotationMap, target);
125+
126+
MapToScreen(target, trailer);
127+
}
128+
129+
private static void PopulateColorGeometry(IEnumerable<KeyValuePair<string, Color>> annotationMap, StyledString target)
130+
{
131+
int abstractCharCount = 0;
132+
foreach (KeyValuePair<string, Color> fragment in annotationMap)
133+
{
134+
for (int i = 0; i < fragment.Key.Length; i++)
135+
{
136+
// This will run O(n^2) times...but with DP, could be O(n).
137+
// Just need to keep a third array that keeps track of each abstract char's width, so you never iterate past that.
138+
// This third array would be one-dimensional.
139+
140+
int rowLength = target.CharacterIndexGeometry.GetLength(0);
141+
int columnLength = target.CharacterIndexGeometry.GetLength(1);
142+
for (int row = 0; row < rowLength; row++)
143+
{
144+
for (int column = 0; column < columnLength; column++)
145+
{
146+
if (target.CharacterIndexGeometry[row, column] == abstractCharCount)
147+
{
148+
target.ColorGeometry[row, column] = fragment.Value;
149+
}
150+
}
151+
}
152+
153+
abstractCharCount++;
154+
}
155+
}
156+
}
157+
91158
private static void WriteChunkInColorStyled(string trailer, char[] buffer, int index, int count, StyleSheet styleSheet)
92159
{
93160
string chunk = buffer.AsString().Substring(index, count);

src/Colorful.Console/ColorfulConsoleFront.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -909,9 +909,9 @@ public static void WriteLineAlternating(object value, ColorAlternator alternator
909909
WriteInColorAlternating(System.Console.WriteLine, value, alternator);
910910
}
911911

912-
public static void WriteLineStyled(object value, StyleSheet styleSheet)
912+
public static void WriteLineStyled(StyledString value, StyleSheet styleSheet)
913913
{
914-
WriteInColorStyled(WRITELINE_TRAILER, value, styleSheet);
914+
WriteAsciiInColorStyled(WRITELINE_TRAILER, value, styleSheet);
915915
}
916916

917917
public static void WriteLine(string value)
@@ -1154,7 +1154,7 @@ public static void WriteAscii(string value)
11541154

11551155
public static void WriteAscii(string value, FigletFont font)
11561156
{
1157-
WriteLine(GetFiglet(font).ToAscii(value));
1157+
WriteLine(GetFiglet(font).ToAscii(value).ConcreteValue);
11581158
}
11591159

11601160
public static void WriteAscii(string value, Color color)
@@ -1164,7 +1164,7 @@ public static void WriteAscii(string value, Color color)
11641164

11651165
public static void WriteAscii(string value, FigletFont font, Color color)
11661166
{
1167-
WriteLine(GetFiglet(font).ToAscii(value), color);
1167+
WriteLine(GetFiglet(font).ToAscii(value).ConcreteValue, color);
11681168
}
11691169

11701170
public static void WriteAsciiAlternating(string value, ColorAlternator alternator)
@@ -1174,7 +1174,7 @@ public static void WriteAsciiAlternating(string value, ColorAlternator alternato
11741174

11751175
public static void WriteAsciiAlternating(string value, FigletFont font, ColorAlternator alternator)
11761176
{
1177-
foreach (var line in GetFiglet(font).ToAscii(value).Split('\n'))
1177+
foreach (var line in GetFiglet(font).ToAscii(value).ConcreteValue.Split('\n'))
11781178
{
11791179
WriteLineAlternating(line, alternator);
11801180
}

src/Colorful.Console/Figlet.cs

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
using System;
44
using System.Text;
55
using System.Text.RegularExpressions;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Drawing;
9+
610
public class Figlet
711
{
812
private readonly FigletFont font;
@@ -19,23 +23,69 @@ public Figlet(FigletFont font)
1923
this.font = font;
2024
}
2125

22-
public string ToAscii(string value)
26+
public StyledString ToAscii(string value)
2327
{
2428
if (value == null) { throw new ArgumentNullException(nameof(value)); }
2529

2630
StringBuilder stringBuilder = new StringBuilder();
2731

28-
for (int i = 1; i <= font.Height; i++)
32+
int stringWidth = GetStringWidth(font, value);
33+
char[,] characterGeometry = new char[font.Height + 1, stringWidth];
34+
int[,] characterIndexGeometry = new int[font.Height + 1, stringWidth];
35+
Color[,] colorGeometry = new Color[font.Height + 1, stringWidth];
36+
37+
for (int line = 1; line <= font.Height; line++)
2938
{
30-
foreach (var character in value)
39+
int runningWidthTotal = 0;
40+
41+
for (int c = 0; c < value.Length; c++)
3142
{
32-
stringBuilder.Append(GetCharacter(this.font, character, i));
43+
char character = value[c];
44+
string fragment = GetCharacter(this.font, character, line);
45+
46+
stringBuilder.Append(fragment);
47+
CalculateCharacterGeometries(fragment, c, runningWidthTotal, line, characterGeometry, characterIndexGeometry);
48+
49+
runningWidthTotal += fragment.Length;
3350
}
3451

3552
stringBuilder.AppendLine();
3653
}
3754

38-
return stringBuilder.ToString();
55+
StyledString styledString = new StyledString(value, stringBuilder.ToString());
56+
styledString.CharacterGeometry = characterGeometry;
57+
styledString.CharacterIndexGeometry = characterIndexGeometry;
58+
styledString.ColorGeometry = colorGeometry;
59+
60+
return styledString;
61+
}
62+
63+
private static void CalculateCharacterGeometries(string fragment, int characterIndex, int runningWidthTotal, int line, char[,] charGeometry, int[,] indexGeometry)
64+
{
65+
for (int i = runningWidthTotal; i < runningWidthTotal + fragment.Length; i++)
66+
{
67+
charGeometry[line, i] = fragment[i - runningWidthTotal];
68+
indexGeometry[line, i] = characterIndex;
69+
}
70+
}
71+
72+
private static int GetStringWidth(FigletFont font, string value)
73+
{
74+
List<int> charWidths = new List<int>();
75+
foreach (var character in value)
76+
{
77+
int charWidth = 0;
78+
for (int line = 1; line <= font.Height; line++)
79+
{
80+
string figletCharacter = GetCharacter(font, character, line);
81+
82+
charWidth = figletCharacter.Length > charWidth ? figletCharacter.Length : charWidth;
83+
}
84+
85+
charWidths.Add(charWidth);
86+
}
87+
88+
return charWidths.Sum();
3989
}
4090

4191
private static string GetCharacter(FigletFont font, char character, int line)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using System.Drawing;
6+
7+
namespace Colorful
8+
{
9+
// NOTE: The StyledString class is meant to replace a number of instances of System.String in this project.
10+
// However, it's currently only used in the WriteLineStyled method, becuase I'd like to have better
11+
// test coverage before using it in the rest of the project.
12+
13+
/// <summary>
14+
/// A string encoded with style!
15+
/// </summary>
16+
public sealed class StyledString : IEquatable<StyledString>
17+
{
18+
/// <summary>
19+
/// The one-dimensional representation of the StyledString. Maps 1:1 with System.String.
20+
/// </summary>
21+
public string AbstractValue { get; private set; }
22+
/// <summary>
23+
/// The n-dimensional (n &le; 2, in this case) representation of the StyledString.
24+
/// In the case of FIGlet fonts, for example, this would be the string's two-dimensional FIGlet representation.
25+
/// </summary>
26+
public string ConcreteValue { get; private set; }
27+
28+
//
29+
// The three geometry members, below, should be encapsulated into a single data structure.
30+
//
31+
32+
/// <summary>
33+
/// A matrix of colors that corresponds to each concrete character in the StyledString.
34+
/// Dimensions are [row, column].
35+
/// </summary>
36+
public Color[,] ColorGeometry { get; set; }
37+
38+
/// <summary>
39+
/// A matrix of concrete characters that corresponds to each concrete character in the StyledString.
40+
/// In other words, this is a two-dimensional representation of the StyledString.ConcreteValue property.
41+
/// </summary>
42+
public char[,] CharacterGeometry { get; set; }
43+
44+
/// <summary>
45+
/// A matrix of abstract character indices that corresponds to each concrete character in the StyledString.
46+
/// Dimensions are [row, column].
47+
/// </summary>
48+
public int[,] CharacterIndexGeometry { get; set; }
49+
50+
public StyledString(string oneDimensionalRepresentation)
51+
{
52+
AbstractValue = oneDimensionalRepresentation;
53+
}
54+
55+
public StyledString(string oneDimensionalRepresentation, string twoDimensionalRepresentation)
56+
{
57+
AbstractValue = oneDimensionalRepresentation;
58+
ConcreteValue = twoDimensionalRepresentation;
59+
}
60+
61+
// Does not take styling information into account...and it needs to be taken into account.
62+
public bool Equals(StyledString other)
63+
{
64+
if (other == null)
65+
{
66+
return false;
67+
}
68+
69+
return this.AbstractValue == other.AbstractValue
70+
&& this.ConcreteValue == other.ConcreteValue;
71+
}
72+
73+
public override bool Equals(object obj)
74+
{
75+
return Equals(obj as StyledString);
76+
}
77+
78+
// Does not take styling information into account...and it needs to be taken into account.
79+
public override int GetHashCode()
80+
{
81+
int hash = 163;
82+
83+
hash *= 79 + AbstractValue.GetHashCode();
84+
hash *= 79 + ConcreteValue.GetHashCode();
85+
86+
return hash;
87+
}
88+
89+
/// <summary>
90+
/// Returns the StyledString's concrete representation.
91+
/// </summary>
92+
/// <returns></returns>
93+
public override string ToString()
94+
{
95+
return ConcreteValue;
96+
}
97+
}
98+
}

src/Colorful.Console/project.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
2-
"version": "1.0.4",
2+
"version": "1.0.5",
33
"title": "Colorful.Console",
44
"description": "Style your C# console output!",
55
"releaseNotes": "Switched to DNX",
6-
"authors": [ "Tom Akita", "Muhammad Rehan Saeed" ],
6+
"authors": [ "Tom Akita", "Muhammad Rehan Saeed", "Matt Furden" ],
77
"owners": [ "Tom Akita" ],
88
"copyright": "@ Tom Akita. All rights Reserved.",
99
"tags": [ "Style", "Styled", "Output", "Colourful", "Colorful", "Console", "Command", "Line", "ASCII", "Art", "FIGlet" ],

src/ExampleConsoleApplication/ExampleConsoleApplication.xproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@
44
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
55
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
66
</PropertyGroup>
7-
87
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
98
<PropertyGroup Label="Globals">
109
<ProjectGuid>e69ffe1e-88df-47ba-b878-c8d737369def</ProjectGuid>
1110
<RootNamespace>ExampleConsoleApplication</RootNamespace>
1211
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
1312
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
1413
</PropertyGroup>
15-
1614
<PropertyGroup>
1715
<SchemaVersion>2.0</SchemaVersion>
1816
</PropertyGroup>
17+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
1918
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
20-
</Project>
19+
</Project>

src/ExampleConsoleApplication/Examples.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ static void Main(string[] args)
3232
{
3333
var font = FigletFont.Load((Stream)resource.Value);
3434
Figlet figlet = new Figlet(font);
35-
string asciiArt = figlet.ToAscii("Hello World");
35+
string asciiArt = figlet.ToAscii("Hello World").ConcreteValue;
3636
Console.WriteLine(asciiArt);
3737
Console.WriteLine();
3838
}

0 commit comments

Comments
 (0)