This bit of code is useful for code formatting while doing code generation, for formatting using screens in console applications, and potentially for any situation where you might need to render a text based document in multiple parts with different indentation levels.
Introduction
I was recently writing a code generator using some of my old code from Rolex - a powerful multilanguage code generator that creates tokenizers/lexers given input specifications files that consist of a series of named regular expressions.
That tool uses something called the CodeDOM to do most of the heavy lifting in terms of code formatting, but these days, I'm about simplifying, and I don't need the CodeDOM and its ability to render code in multiple languages. I don't use Visual Basic so it seems kind of silly to go through all of the work of supporting it when someone can just link it as a library. So now I'm writing code out directly in C# instead. It's faster, but it leaves me missing some things, among them automatic code formatting.
This doesn't do automatic code formatting, but it does make it so I, or more the point, you - can easily indent blocks of code, or otherwise sections of text, like XML, HTML, or anything where indentation is important.
Using the Code
Using the code involves dropping the following class wholesale into a new file in your code. Rather than provide a download, the entire implementation is simple enough to just provide here:
using System;
using System.IO;
using System.Text;
class IndentedTextWriter : TextWriter
{
bool _needIndent;
TextWriter _writer;
public IndentedTextWriter(TextWriter writer)
{
if (writer == null) throw new ArgumentNullException();
_writer = writer;
_needIndent = false;
}
public override Encoding Encoding => _writer.Encoding;
public override void Write(char value)
{
if(_needIndent)
{
_writer.Write(_Indent(IndentLevel));
_needIndent = false;
}
if (value == '\n')
{
_needIndent = true;
_writer.Write("\n");
}
else
_writer.Write(value);
}
public int IndentLevel { get; set; } = 0;
public string Indent { get; set; } = " ";
string _Indent(int level)
{
if (level<=0) return "";
var len = level * Indent.Length;
var sb = new StringBuilder(len, len) ;
for(var i = 0;i<level;++i)
{
sb.Append(Indent);
}
return sb.ToString();
}
}
Using it goes something like the following, which was adapted from an actual application of mine (in progress):
var tw = new IndentedTextWriter(Console.Out);
if(!string.IsNullOrEmpty(codenamespace))
{
tw.WriteLine("namespace {0}", codenamespace);
tw.WriteLine("{");
++tw.IndentLevel;
}
CodeGenerator.GenerateCodeAttribute(tw);
tw.WriteLine("partial class {0}", codeclass);
tw.WriteLine("{");
++tw.IndentLevel;
CodeGenerator.GenerateUnicodeFetchMethod(tw);
--tw.IndentLevel;
tw.WriteLine("}");
if (!string.IsNullOrEmpty(codenamespace))
{
--tw.IndentLevel;
tw.WriteLine("}");
}
As I said, the above code was adapted from an actual application. It's not all shown here, but enough is shown to illustrate how to use the IndentedTextWriter
class.
Notice above we're just writing things out, and then we can increase the indent by manipulating IndentLevel
. You can also change the string used as the indent by modifying the Indent
property, which defaults to four spaces. Once the IndentLevel
is modified, subsequent writes proceed at that level, allowing you to transparently indent portions of the written document. Above, you can see that if codenamespace
is specified, only then does the rest of the code get indented, and then we can simply pass the IndentedTextWriter
around like a regular TextWriter
and anything that writes to it will write out at that indentation level. You can also nest it by creating an IndentedTextWriter
over another IndentedTextWriter
in case you need that.
I hope this solves a thing for you.
History
- 23rd October, 2021 - Initial submission