forked from aers/FFXIVClientStructs
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathIndentedStringBuilder.cs
279 lines (232 loc) · 8.01 KB
/
IndentedStringBuilder.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// https://github.com/dotnet/efcore/blob/main/src/EFCore/Infrastructure/IndentedStringBuilder.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClientStructs.InteropGenerator;
/// <summary>
/// <para>
/// A thin wrapper over <see cref="StringBuilder" /> that adds indentation to each line built.
/// </para>
/// <para>
/// This type is typically used by database providers (and other extensions). It is generally
/// not used in application code.
/// </para>
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-providers">Implementation of database providers and extensions</see>
/// for more information and examples.
/// </remarks>
public class IndentedStringBuilder
{
private const byte IndentSize = 4;
private int _indent;
private bool _indentPending = true;
private readonly StringBuilder _stringBuilder = new();
/// <summary>
/// Gets the current indent level.
/// </summary>
/// <value>The current indent level.</value>
public virtual int IndentCount
=> _indent;
/// <summary>
/// The current length of the built string.
/// </summary>
public virtual int Length
=> _stringBuilder.Length;
/// <summary>
/// Appends the current indent and then the given string to the string being built.
/// </summary>
/// <param name="value">The string to append.</param>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder Append(string value)
{
DoIndent();
_stringBuilder.Append(value);
return this;
}
/// <summary>
/// Appends the current indent and then the given char to the string being built.
/// </summary>
/// <param name="value">The char to append.</param>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder Append(char value)
{
DoIndent();
_stringBuilder.Append(value);
return this;
}
/// <summary>
/// Appends the current indent and then the given strings to the string being built.
/// </summary>
/// <param name="value">The strings to append.</param>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder Append(IEnumerable<string> value)
{
DoIndent();
foreach (var str in value)
{
_stringBuilder.Append(str);
}
return this;
}
/// <summary>
/// Appends the current indent and then the given chars to the string being built.
/// </summary>
/// <param name="value">The chars to append.</param>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder Append(IEnumerable<char> value)
{
DoIndent();
foreach (var chr in value)
{
_stringBuilder.Append(chr);
}
return this;
}
/// <summary>
/// Appends a new line to the string being built.
/// </summary>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder AppendLine()
{
AppendLine(string.Empty);
return this;
}
/// <summary>
/// Appends the current indent, the given string, and a new line to the string being built.
/// </summary>
/// <remarks>
/// If the given string itself contains a new line, the part of the string after that new line will not be indented.
/// </remarks>
/// <param name="value">The string to append.</param>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder AppendLine(string value)
{
if (value.Length != 0)
{
DoIndent();
}
_stringBuilder.AppendLine(value);
_indentPending = true;
return this;
}
/// <summary>
/// Separates the given string into lines, and then appends each line, prefixed
/// by the current indent and followed by a new line, to the string being built.
/// </summary>
/// <param name="value">The string to append.</param>
/// <param name="skipFinalNewline">If <see langword="true" />, then the terminating new line is not added after the last line.</param>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder AppendLines(string value, bool skipFinalNewline = false)
{
using (var reader = new StringReader(value))
{
var first = true;
string? line;
while ((line = reader.ReadLine()) != null)
{
if (first)
{
first = false;
}
else
{
AppendLine();
}
if (line.Length != 0)
{
Append(line);
}
}
}
if (!skipFinalNewline)
{
AppendLine();
}
return this;
}
/// <summary>
/// Resets this builder ready to build a new string.
/// </summary>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder Clear()
{
_stringBuilder.Clear();
_indent = 0;
return this;
}
/// <summary>
/// Increments the indent.
/// </summary>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder IncrementIndent()
{
_indent++;
return this;
}
/// <summary>
/// Decrements the indent.
/// </summary>
/// <returns>This builder so that additional calls can be chained.</returns>
public virtual IndentedStringBuilder DecrementIndent()
{
if (_indent > 0)
{
_indent--;
}
return this;
}
/// <summary>
/// Creates a scoped indenter that will increment the indent, then decrement it when disposed.
/// </summary>
/// <returns>An indenter.</returns>
public virtual IDisposable Indent()
=> new Indenter(this);
/// <summary>
/// Temporarily disables all indentation. Restores the original indentation when the returned object is disposed.
/// </summary>
/// <returns>An object that restores the original indentation when disposed.</returns>
public virtual IDisposable SuspendIndent()
=> new IndentSuspender(this);
/// <summary>
/// Returns the built string.
/// </summary>
/// <returns>The built string.</returns>
public override string ToString()
=> _stringBuilder.ToString();
private void DoIndent()
{
if (_indentPending && _indent > 0)
{
_stringBuilder.Append(' ', _indent * IndentSize);
}
_indentPending = false;
}
private sealed class Indenter : IDisposable
{
private readonly IndentedStringBuilder _stringBuilder;
public Indenter(IndentedStringBuilder stringBuilder)
{
_stringBuilder = stringBuilder;
_stringBuilder.IncrementIndent();
}
public void Dispose()
=> _stringBuilder.DecrementIndent();
}
private sealed class IndentSuspender : IDisposable
{
private readonly IndentedStringBuilder _stringBuilder;
private readonly int _indent;
public IndentSuspender(IndentedStringBuilder stringBuilder)
{
_stringBuilder = stringBuilder;
_indent = _stringBuilder._indent;
_stringBuilder._indent = 0;
}
public void Dispose()
=> _stringBuilder._indent = _indent;
}
}