Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ public void AppendWithEmbeddedNewLine()
Assert.Equal(new string[] { "A", "B" }, sb);
}

[Fact]
public void AppendWithTrailingNewLine()
{
var sb = new StructuredStringBuilder();
sb.AppendLine($"A{Environment.NewLine}");
Assert.Equal(new string[] { "A", "" }, sb);
}

[Fact]
public void AppendNull()
{
Expand All @@ -27,4 +35,76 @@ public void AppendEmpty()
sb.AppendLine(String.Empty);
Assert.Equal(new string[] { "" }, sb);
}
}

[Fact]
public void AppendContinuesTheLine()
{
var sb = new StructuredStringBuilder();
sb.Append("A");
sb.Append("B", endWithNewLine: true);
sb.Append("C");
Assert.Equal(new string[] { "AB" }, sb);
Assert.Equal($"AB{Environment.NewLine}C", sb.ToString());
}

[Fact]
public void AppendLineIndentsByDepth()
{
var sb = new StructuredStringBuilder();
sb.AppendLine("A");
using (sb.Brace())
{
sb.AppendLine("B");
using (sb.IncreaseDepth())
{
sb.AppendLine("C");
}
}
Assert.Equal(new string[] { "A", "[", " B", " C", "]" }, sb);
}

[Fact]
public void AppendLineWithExtraLine()
{
var sb = new StructuredStringBuilder();
sb.AppendLine("A", extraLine: true);
sb.AppendLine("B");
Assert.Equal(new string[] { "A", "", "B" }, sb);
}

[Fact]
public void AppendItemNamesTheValue()
{
var sb = new StructuredStringBuilder();
sb.AppendItem(5, "Count");
sb.AppendItem(6);
sb.AppendItem((string?)null, "Missing");
Assert.Equal(new string[] { "Count => 5", "6" }, sb);
}

[Fact]
public void Empty()
{
var sb = new StructuredStringBuilder();
Assert.True(sb.Empty);
sb.Append(" ");
Assert.True(sb.Empty);
sb.AppendLine();
Assert.False(sb.Empty);
}

[Fact]
public void EditLines()
{
var sb = new StructuredStringBuilder();
sb.AppendLine("A");
sb.AppendLine("B");
sb.Insert(1, "X");
sb[0] = "Y";
Assert.Equal("X", sb[1]);
sb.RemoveAt(2);
Assert.Equal(2, sb.Count);
Assert.Equal(new string[] { "Y", "X" }, sb);
Assert.Throws<IndexOutOfRangeException>(() => sb[2]);
}
}
2 changes: 1 addition & 1 deletion Noggog.CSharpExt/StructuredStrings/Line.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public Line(StructuredStringBuilder sb, bool appendNewLine = true)
{
_sb = sb;
_appendNewLine = appendNewLine;
_sb.Append(_sb.DepthStr);
_sb.AppendIndentation();
}

public void Dispose()
Expand Down
103 changes: 41 additions & 62 deletions Noggog.CSharpExt/StructuredStrings/StructuredStringBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,13 @@ namespace Noggog.StructuredStrings;

public class StructuredStringBuilder : IEnumerable<string>
{
private static readonly string[] NewLineArr = new[] { Environment.NewLine };

public int Depth;
private readonly List<string> _strings = new();
public string DepthStr
{
get
{
StringBuilder sb = new StringBuilder();
sb.Append(' ', Depth * _depthCount);
return sb.ToString();
}
}
public bool Empty
{
get
{
if (_strings.Count > 1) return false;
if (_strings.Count == 0) return true;
return string.IsNullOrWhiteSpace(_strings[0]);
}
}
// The line being written is kept apart from the finished ones, so that appending to it
// copies nothing until it ends.
private readonly List<string> _lines = new();
private readonly StringBuilder _line = new();
public string DepthStr => new string(' ', Depth * _depthCount);
public bool Empty => _lines.Count == 0 && string.IsNullOrWhiteSpace(_line.ToString());

#if NETSTANDARD2_0
#else
Expand All @@ -41,26 +26,19 @@ public bool Empty
#endif
private readonly int _depthCount;

public int Count => _strings.Count - 1;
public int Count => _lines.Count;

public string this[int index]
{
get
{
CheckIndex(index);
return _strings[index];
return _lines[index];
}
set
{
CheckIndex(index);
if (index == _strings.Count - 1)
{
AppendLine(value);
}
else
{
_strings[index] = value;
}
_lines[index] = value;
}
}

Expand All @@ -72,18 +50,17 @@ public StructuredStringBuilder()
public StructuredStringBuilder(int depthCount)
{
_depthCount = depthCount;
AppendLine();
}

public void Insert(int index, string str)
{
CheckIndex(index);
_strings.Insert(index, str);
_lines.Insert(index, str);
}

private void CheckIndex(int index)
{
if (index >= _strings.Count - 1 || index < 0)
if (index >= _lines.Count || index < 0)
{
throw new IndexOutOfRangeException();
}
Expand All @@ -96,37 +73,37 @@ public void Append(string? str, bool endWithNewLine = false)
#else
_lineAppended.OnNext(str);
#endif
if (str.StartsWith(Environment.NewLine))
if (str.StartsWith(Environment.NewLine, StringComparison.Ordinal))
{
_strings.Add("");
EndLine();
return;
}
string[] split = str.Split(NewLineArr, StringSplitOptions.None);
split.First(
(s, first) =>
{
if (_strings.Count == 0)
{
_strings.Add(s);
}
else
{
if (first)
{
_strings[_strings.Count - 1] = _strings[_strings.Count - 1] + s;
}
else
{
_strings.Add(s);
}
}
});
var start = 0;
int newLine;
while ((newLine = str.IndexOf(Environment.NewLine, start, StringComparison.Ordinal)) >= 0)
{
_line.Append(str, start, newLine - start);
EndLine();
start = newLine + Environment.NewLine.Length;
}
_line.Append(str, start, str.Length - start);
if (endWithNewLine)
{
Append(Environment.NewLine, endWithNewLine: false);
}
}

private void EndLine()
{
_lines.Add(_line.ToString());
_line.Clear();
}

internal void AppendIndentation()
{
_line.Append(' ', Depth * _depthCount);
}

public void AppendLine()
{
Append(Environment.NewLine);
Expand Down Expand Up @@ -158,9 +135,11 @@ public void AppendLines(IEnumerable<string?> strs, string delimeter)

public void AppendLine(string? str, bool extraLine = false, bool appendNewLine = true)
{
using (new Line(this, appendNewLine))
AppendIndentation();
Append(str);
if (appendNewLine)
{
Append(str);
AppendLine();
}

if (extraLine)
Expand Down Expand Up @@ -191,12 +170,12 @@ public void AppendItem(IPrintable? item, string? name = null)
public void RemoveAt(int index)
{
CheckIndex(index);
_strings.RemoveAt(index);
_lines.RemoveAt(index);
}

public string GetString()
{
return string.Join(Environment.NewLine, _strings);
return string.Join(Environment.NewLine, _lines.Append(_line.ToString()));
}

public override string ToString()
Expand All @@ -206,9 +185,9 @@ public override string ToString()

public IEnumerator<string> GetEnumerator()
{
for (int i = 0; i < _strings.Count - 1; i++)
for (int i = 0; i < _lines.Count; i++)
{
yield return _strings[i];
yield return _lines[i];
}
}

Expand Down