-1

I am trying to indent block of strings in a StringBuilder, but what I am getting is just the indentation of 1st line. I understand why it is doing so, but don't know if there is any easy way to achieve what I am looking for.

void Main()
{
    var subLines = new StringBuilder();
    subLines.AppendLine("Sub Line1");
    subLines.AppendLine("Sub Line2");
    subLines.AppendLine("Sub Line3");

    var mainLines = new StringBuilder();
    mainLines.AppendLine("Main Line 1");
    mainLines.AppendLine("Main Line 2");    
    mainLines.Append("\t").Append(subLines.ToString());
    mainLines.AppendLine("Main Line 3");
    mainLines.ToString().Dump();
}

Actual Output

Main Line 1
Main Line 2
    Sub Line1
Sub Line2
Sub Line3
Main Line 3

Expected Output

Main Line 1
Main Line 2
   Sub Line1
   Sub Line2
   Sub Line3
Main Line 3

I have also tried using IndentedTextWriter, but gives the same results.

public static class StringBuilderExtensions
{ 
    public static StringBuilder AppendIndented(this StringBuilder sb, string text)
    {
        var textWriter = new StringWriter(sb);
        var indentWriter = new IndentedTextWriter(textWriter, "\t\t");
        indentWriter.WriteLine("");
        indentWriter.Indent = 1;
        indentWriter.WriteLine(text);

        return sb;
    }
}

Any thoughts on how can I achieve block indentation?

Marshal
  • 6,551
  • 13
  • 55
  • 91
  • 3
    You're adding `\t`, and then adding `subLines`. Nowhere do you say to break `subLines` into individual lines, and add a `\t` at the beginning of *each* line. Perhaps you wanted something like `foreach (var line in subLines.Split("\n")) { mainLines.Append("\t").AppendLine(line); }`? – canton7 May 07 '21 at 12:29
  • StringBuilder has no (automatic) formatting capabilities, you have to build it yourself. Right now you are adding a single TAB character and then a bunch of lines that know nothing about that TAB – Hans Kesting May 07 '21 at 12:32
  • @canton7 Thank you that is what I was looking for, I have created a little extension method for that. If you'd like to post that as an answer, I'll accept it. – Marshal May 07 '21 at 12:36
  • @HansKesting: Yup, you are right. I understood why it was doing that, but wanted to see if there is any inbuilt solution available in the framework to achieve the results. Thank you :) – Marshal May 07 '21 at 12:36
  • 1
    https://stackoverflow.com/a/2547800/17034 – Hans Passant May 07 '21 at 13:07

3 Answers3

2

Taking cue from canton7's comment, here's an extension method that I created to achieve the results.

  public static class StringBuilderExtensions
    {
        public static StringBuilder AppendIndented(this StringBuilder sb, string textBlock)
        {
            foreach (var line in textBlock.TrimEnd().Split('\n'))
                if (!string.IsNullOrWhiteSpace(line))
                    sb.AppendLine($"\t{line}");
            return sb;
        }
    }

Usage

    var subLines = new StringBuilder();
    subLines.AppendLine("Sub Line1");
    subLines.AppendLine("Sub Line2");
    subLines.AppendLine("Sub Line3");

    var mainLines = new StringBuilder();
    mainLines.AppendLine("Main Line 1");
    mainLines.AppendLine("Main Line 2");
    mainLines.AppendIntended(sublines);
    mainLines.AppendLine("Main Line 3");
    
Marshal
  • 6,551
  • 13
  • 55
  • 91
0

This might help

      static void Main()
    {
        var subLines = new StringBuilder();
        subLines.AppendLine("Sub Line1");
        subLines.AppendLine("Sub Line2");
        subLines.AppendLine("Sub Line3");

        var mainLines = new StringBuilder();
                   
        ApplyIndentation(mainLines,subLines);
      
        mainLines.ToString();
        Console.WriteLine(mainLines);
      

    }
    private static void ApplyIndentation(StringBuilder mainLines, StringBuilder subLines)
    {
        
        string[] delim = { Environment.NewLine, "\n" };
        string[] lines = subLines.ToString().Split(delim, StringSplitOptions.None);
        mainLines.AppendLine("Main Line 1");
        mainLines.AppendLine("Main Line 2");
        foreach (string line in lines)
        {
            mainLines.Append(Indent(3)).AppendLine(line);
            
        }
        mainLines.AppendLine("Main Line 3");

    }
    public static string Indent(int count)
    {
        return "".PadLeft(count);
    }
  • This gets the desired output, but the only issue in my context is that `sublines` should be unaware about the indentation. `MainLines` needs the control of indentation. – Marshal May 07 '21 at 13:07
  • Just edited and added a method - might work for you – Zeeshan Abbas May 07 '21 at 14:46
0

You can create your own implementation of StringBuilder that matches the Debug methods of Debug.Indent() & Debug.UnIndent()

public class StringBuilderIndented
{
    private StringBuilder sb;

    public string _Indent = "";

    public StringBuilderIndented()
    {
        sb = new StringBuilder();
    }

    public void Indent()
    {
        _Indent += new string(' ', 5);
    }

    public void WriteLine(string str)
    {
        sb.AppendLine(_Indent+str);
    }
    public void Unindent()
    {
        if (_Indent.Length >= 5)
            _Indent = new string(' ', _Indent.Length - 5);
        else
            _Indent = "";
    }

    public override string ToString()
    {
        return sb.ToString();
    }

}

Usage:

Then in code where Debug is used for writing you can replace it with your stringbuilder call

    private static void WriteLog()
    {
        var Debug = new StringBuilderIndented();
        Debug.WriteLine("Main Line 1");
        Debug.WriteLine("Main Line 2");
        Debug.Indent();
        Debug.WriteLine("Sub Line 1");
        Debug.WriteLine("Sub Line 2");
        Debug.Indent();
        Debug.WriteLine("Sub Sub Line 1");
        Debug.WriteLine("Sub Sub Line 2");
        Debug.Unindent();
        Debug.WriteLine("Sub Line 3");
        Debug.Unindent();
        Debug.WriteLine("Main Line 3");
        Trace.WriteLine(Debug.ToString());
    }
    

Output:

Main Line 1
Main Line 2
     Sub Line 1
     Sub Line 2
          Sub Sub Line 1
          Sub Sub Line 2
     Sub Line 3
Main Line 3
Hemendr
  • 673
  • 6
  • 12