aboutsummaryrefslogtreecommitdiffhomepage
path: root/csharp/src/ProtocolBuffers/TextGenerator.cs
blob: 30cbf0fdca37487e5d39f2aff41bb8822f197121 (plain)
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
#region Copyright notice and license

// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// http://github.com/jskeet/dotnet-protobufs/
// Original C++/Java/Python code:
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#endregion

using System;
using System.IO;
using System.Text;

namespace Google.ProtocolBuffers
{
    /// <summary>
    /// Helper class to control indentation. Used for TextFormat and by ProtoGen.
    /// </summary>
    public sealed class TextGenerator
    {
        /// <summary>
        /// The string to use at the end of each line. We assume that "Print" is only called using \n
        /// to indicate a line break; that's what we use to detect when we need to indent etc, and
        /// *just* the \n is replaced with the contents of lineBreak.
        /// </summary>
        private readonly string lineBreak;

        /// <summary>
        /// Writer to write formatted text to.
        /// </summary>
        private readonly TextWriter writer;

        /// <summary>
        /// Keeps track of whether the next piece of text should be indented
        /// </summary>
        private bool atStartOfLine = true;

        /// <summary>
        /// Keeps track of the current level of indentation
        /// </summary>
        private readonly StringBuilder indent = new StringBuilder();

        /// <summary>
        /// Creates a generator writing to the given writer. The writer
        /// is not closed by this class.
        /// </summary>
        public TextGenerator(TextWriter writer, string lineBreak)
        {
            this.writer = writer;
            this.lineBreak = lineBreak;
        }

        /// <summary>
        /// Indents text by two spaces. After calling Indent(), two spaces
        /// will be inserted at the beginning of each line of text. Indent() may
        /// be called multiple times to produce deeper indents.
        /// </summary>
        public void Indent()
        {
            indent.Append("  ");
        }

        /// <summary>
        /// Reduces the current indent level by two spaces.
        /// </summary>
        public void Outdent()
        {
            if (indent.Length == 0)
            {
                throw new InvalidOperationException("Too many calls to Outdent()");
            }
            indent.Length -= 2;
        }

        public void WriteLine(string text)
        {
            Print(text);
            Print("\n");
        }

        public void WriteLine(string format, params object[] args)
        {
            WriteLine(string.Format(format, args));
        }

        public void WriteLine()
        {
            WriteLine("");
        }

        /// <summary>
        /// Prints the given text to the output stream, indenting at line boundaries.
        /// </summary>
        /// <param name="text"></param>
        public void Print(string text)
        {
            int pos = 0;

            for (int i = 0; i < text.Length; i++)
            {
                if (text[i] == '\n')
                {
                    // Strip off the \n from what we write
                    Write(text.Substring(pos, i - pos));
                    Write(lineBreak);
                    pos = i + 1;
                    atStartOfLine = true;
                }
            }
            Write(text.Substring(pos));
        }

        public void Write(string format, params object[] args)
        {
            Write(string.Format(format, args));
        }

        private void Write(string data)
        {
            if (data.Length == 0)
            {
                return;
            }
            if (atStartOfLine)
            {
                atStartOfLine = false;
                writer.Write(indent);
            }
            writer.Write(data);
        }
    }
}