// and whether it's an htab ('\t') or vtab ('\v') terminated call.
//
type cell struct {
- size int; // cell size in bytes
- width int; // cell width in runes
- htab bool; // true if the cell is terminated by an htab ('\t')
+ size int; // cell size in bytes
+ width int; // cell width in runes
+ htab bool; // true if the cell is terminated by an htab ('\t')
}
//
type Writer struct {
// configuration
- output io.Writer;
- cellwidth int;
- padding int;
- padbytes [8]byte;
- flags uint;
+ output io.Writer;
+ cellwidth int;
+ padding int;
+ padbytes [8]byte;
+ flags uint;
// current state
- buf bytes.Buffer; // collected text w/o tabs, newlines, or formfeed chars
- pos int; // buffer position up to which width of incomplete cell has been computed
- cell cell; // current incomplete cell; cell.width is up to buf[pos] w/o ignored sections
- endChar byte; // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
- lines vector.Vector; // list if lines; each line is a list of cells
- widths vector.IntVector; // list of column widths in runes - re-used during formatting
+ buf bytes.Buffer; // collected text w/o tabs, newlines, or formfeed chars
+ pos int; // buffer position up to which width of incomplete cell has been computed
+ cell cell; // current incomplete cell; cell.width is up to buf[pos] w/o ignored sections
+ endChar byte; // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
+ lines vector.Vector; // list if lines; each line is a list of cells
+ widths vector.IntVector; // list of column widths in runes - re-used during formatting
}
const (
// Ignore html tags and treat entities (starting with '&'
// and ending in ';') as single characters (width = 1).
- FilterHTML uint = 1 << iota;
+ FilterHTML uint = 1<<iota;
// Force right-alignment of cell content.
// Default is left-alignment.
b.output = output;
b.cellwidth = cellwidth;
b.padding = padding;
- for i := len(b.padbytes) - 1; i >= 0; i-- {
+ for i := len(b.padbytes)-1; i >= 0; i-- {
b.padbytes[i] = padchar;
}
if padchar == '\t' {
cellw = ((cellw + b.cellwidth - 1) / b.cellwidth) * b.cellwidth;
}
- n := cellw - textw;
+ n := cellw-textw;
if n < 0 {
panic("internal error");
}
n -= len(b.padbytes);
}
- return b.write0(b.padbytes[0 : n]);
+ return b.write0(b.padbytes[0:n]);
}
-var vbar = []byte{'|'};
+var vbar = []byte{'|'}
func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error) {
pos = pos0;
for j := 0; j < line.Len(); j++ {
c := line.At(j).(cell);
- if j > 0 && b.flags&Debug != 0 {
+ if j > 0 && b.flags & Debug != 0 {
if err = b.write0(vbar); err != nil {
return;
}
}
switch {
- default: // align left
+ default: // align left
if err = b.write0(b.buf.Bytes()[pos : pos + c.size]); err != nil {
return;
}
}
- case b.flags & AlignRight != 0: // align right
+ case b.flags & AlignRight != 0: // align right
if j < b.widths.Len() {
if err = b.writePadding(c.width, b.widths.At(j)); err != nil {
line0 = this;
// column block begin
- width := b.cellwidth; // minimal column width
- discardable := true; // true if all cells in this column are empty and "soft"
+ width := b.cellwidth; // minimal column width
+ discardable := true; // true if all cells in this column are empty and "soft"
for ; this < line1; this++ {
line = b.line(this);
if column < line.Len() - 1 {
discardable = false;
}
} else {
- break
+ break;
}
}
// column block end
//
// The value 0xff was chosen because it cannot appear in a valid UTF-8 sequence.
//
-const Escape ='\xff'
+const Escape = '\xff'
// Start escaped mode.
func (b *Writer) startEscape(ch byte) {
switch ch {
- case Escape: b.endChar = Escape;
- case '<': b.endChar = '>';
- case '&': b.endChar = ';';
+ case Escape:
+ b.endChar = Escape;
+ case '<':
+ b.endChar = '>';
+ case '&':
+ b.endChar = ';';
}
}
//
func (b *Writer) endEscape() {
switch b.endChar {
- case Escape: b.updateWidth();
- case '>': // tag of zero width
- case ';': b.cell.width++; // entity, count as one rune
+ case Escape:
+ b.updateWidth();
+ case '>': // tag of zero width
+ case ';':
+ b.cell.width++; // entity, count as one rune
}
b.pos = b.buf.Len();
b.endChar = 0;
switch ch {
case '\t', '\v', '\n', '\f':
// end of cell
- b.append(buf[n : i]);
+ b.append(buf[n:i]);
b.updateWidth();
- n = i+1; // ch consumed
+ n = i+1; // ch consumed
ncells := b.terminateCell(ch == '\t');
if ch == '\n' || ch == '\f' {
// terminate line
case Escape:
// start of escaped sequence
- b.append(buf[n : i]);
+ b.append(buf[n:i]);
b.updateWidth();
- n = i+1; // exclude Escape
+ n = i+1; // exclude Escape
b.startEscape(Escape);
case '<', '&':
// possibly an html tag/entity
if b.flags & FilterHTML != 0 {
// begin of tag/entity
- b.append(buf[n : i]);
+ b.append(buf[n:i]);
b.updateWidth();
n = i;
b.startEscape(ch);
// end of tag/entity
j := i+1;
if ch == Escape {
- j = i; // exclude Escape
+ j = i; // exclude Escape
}
- b.append(buf[n : j]);
- n = i+1; // ch consumed
+ b.append(buf[n:j]);
+ n = i+1; // ch consumed
b.endEscape();
}
}
}
// append leftover text
- b.append(buf[n : len(buf)]);
+ b.append(buf[n:len(buf)]);
n = len(buf);
return;
}
// The parameters are the same as for the the Init function.
//
func NewWriter(output io.Writer, cellwidth, padding int, padchar byte, flags uint) *Writer {
- return new(Writer).Init(output, cellwidth, padding, padchar, flags)
+ return new(Writer).Init(output, cellwidth, padding, padchar, flags);
}
func (b *buffer) init(n int) {
- b.a = make([]byte, n)[0 : 0];
+ b.a = make([]byte, n)[0:0];
}
func (b *buffer) clear() {
- b.a = b.a[0 : 0];
+ b.a = b.a[0:0];
}
func (b *buffer) Write(buf []byte) (written int, err os.Error) {
n := len(b.a);
m := len(buf);
- if n + m <= cap(b.a) {
- b.a = b.a[0 : n + m];
+ if n+m <= cap(b.a) {
+ b.a = b.a[0 : n+m];
for i := 0; i < m; i++ {
b.a[n+i] = buf[i];
}
res := b.String();
if res != expected {
- t.Errorf("--- test: %s\n--- src:\n%s\n--- found:\n%s\n--- expected:\n%s\n", testname, src, res, expected)
+ t.Errorf("--- test: %s\n--- src:\n%s\n--- found:\n%s\n--- expected:\n%s\n", testname, src, res, expected);
}
}
write(t, testname, &w, src[i : i+d]);
i, d = i+d, d+1;
if i+d > len(src) {
- d = len(src) - i;
+ d = len(src)-i;
}
}
verify(t, testname, &w, &b, src, expected);
type entry struct {
- testname string;
- tabwidth, padding int;
- padchar byte;
- flags uint;
- src, expected string;
+ testname string;
+ tabwidth, padding int;
+ padchar byte;
+ flags uint;
+ src, expected string;
}
-var tests = []entry {
+var tests = []entry{
entry{
"1a",
8, 1, '.', 0,
"",
- ""
+ "",
},
entry{
"1a debug",
8, 1, '.', Debug,
"",
- ""
+ "",
},
entry{
"1b esc",
8, 1, '.', 0,
"\xff\xff",
- ""
+ "",
},
entry{
"1c esc",
8, 1, '.', 0,
"\xff\t\xff",
- "\t"
+ "\t",
},
entry{
entry{
"1e esc",
8, 1, '.', 0,
- "abc\xff\tdef", // unterminated escape
+ "abc\xff\tdef", // unterminated escape
"abc\tdef",
},
"2",
8, 1, '.', 0,
"\n\n\n",
- "\n\n\n"
+ "\n\n\n",
},
entry{
"3",
8, 1, '.', 0,
"a\nb\nc",
- "a\nb\nc"
+ "a\nb\nc",
},
entry{
"4a",
8, 1, '.', 0,
- "\t", // '\t' terminates an empty cell on last line - nothing to print
- ""
+ "\t", // '\t' terminates an empty cell on last line - nothing to print
+ "",
},
entry{
"4b",
8, 1, '.', AlignRight,
- "\t", // '\t' terminates an empty cell on last line - nothing to print
- ""
+ "\t", // '\t' terminates an empty cell on last line - nothing to print
+ "",
},
entry{
"5",
8, 1, '.', 0,
"*\t*",
- "*.......*"
+ "*.......*",
},
entry{
"5b",
8, 1, '.', 0,
"*\t*\n",
- "*.......*\n"
+ "*.......*\n",
},
entry{
"5c",
8, 1, '.', 0,
"*\t*\t",
- "*.......*"
+ "*.......*",
},
entry{
"5c debug",
8, 1, '.', Debug,
"*\t*\t",
- "*.......|*"
+ "*.......|*",
},
entry{
"5d",
8, 1, '.', AlignRight,
"*\t*\t",
- ".......**"
+ ".......**",
},
entry{
"6",
8, 1, '.', 0,
"\t\n",
- "........\n"
+ "........\n",
},
entry{
"7a",
8, 1, '.', 0,
"a) foo",
- "a) foo"
+ "a) foo",
},
entry{
"7b",
8, 1, ' ', 0,
"b) foo\tbar",
- "b) foo bar"
+ "b) foo bar",
},
entry{
"7c",
8, 1, '.', 0,
"c) foo\tbar\t",
- "c) foo..bar"
+ "c) foo..bar",
},
entry{
"7d",
8, 1, '.', 0,
"d) foo\tbar\n",
- "d) foo..bar\n"
+ "d) foo..bar\n",
},
entry{
"7e",
8, 1, '.', 0,
"e) foo\tbar\t\n",
- "e) foo..bar.....\n"
+ "e) foo..bar.....\n",
},
entry{
"7f",
8, 1, '.', FilterHTML,
"f) f<o\t<b>bar</b>\t\n",
- "f) f<o..<b>bar</b>.....\n"
+ "f) f<o..<b>bar</b>.....\n",
},
entry{
"7g",
8, 1, '.', FilterHTML,
"g) f<o\t<b>bar</b>\t non-terminated entity &",
- "g) f<o..<b>bar</b>..... non-terminated entity &"
+ "g) f<o..<b>bar</b>..... non-terminated entity &",
},
entry{
"7g debug",
8, 1, '.', FilterHTML | Debug,
"g) f<o\t<b>bar</b>\t non-terminated entity &",
- "g) f<o..|<b>bar</b>.....| non-terminated entity &"
+ "g) f<o..|<b>bar</b>.....| non-terminated entity &",
},
entry{
"8",
8, 1, '*', 0,
"Hello, world!\n",
- "Hello, world!\n"
+ "Hello, world!\n",
},
entry{
"11\t222\t3333\t44444\n",
"1.2..3...4\n"
- "11222333344444\n"
+ "11222333344444\n",
},
entry{
"9b",
0, 0, '.', FilterHTML,
- "1\t2<!---\f--->\t3\t4\n" // \f inside HTML is ignored
+ "1\t2<!---\f--->\t3\t4\n" // \f inside HTML is ignored
"11\t222\t3333\t44444\n",
"1.2<!---\f--->..3...4\n"
- "11222333344444\n"
+ "11222333344444\n",
},
entry{
"9c",
0, 0, '.', 0,
- "1\t2\t3\t4\f" // \f causes a newline and flush
+ "1\t2\t3\t4\f" // \f causes a newline and flush
"11\t222\t3333\t44444\n",
"1234\n"
- "11222333344444\n"
+ "11222333344444\n",
},
entry{
"9c debug",
0, 0, '.', Debug,
- "1\t2\t3\t4\f" // \f causes a newline and flush
+ "1\t2\t3\t4\f" // \f causes a newline and flush
"11\t222\t3333\t44444\n",
"1|2|3|4\n"
- "11|222|3333|44444\n"
+ "11|222|3333|44444\n",
},
entry{
"10a",
5, 0, '.', 0,
"1\t2\t3\t4\n",
- "1....2....3....4\n"
+ "1....2....3....4\n",
},
entry{
"10b",
5, 0, '.', 0,
"1\t2\t3\t4\t\n",
- "1....2....3....4....\n"
+ "1....2....3....4....\n",
},
entry{
"本.......b.......c\n"
"aa......本本本.....cccc....ddddd\n"
- "aaa.....bbbb\n"
+ "aaa.....bbbb\n",
},
entry{
" a è c\n"
" aa èèè cccc ddddd\n"
- " aaa èèèè\n"
+ " aaa èèèè\n",
},
entry{
"a b c\n"
"aa bbbcccc\n"
- "aaabbbb\n"
+ "aaabbbb\n",
},
entry{
"a_______b_______c\n"
"aa______bbb_____cccc\n"
- "aaa_____bbbb\n"
+ "aaa_____bbbb\n",
},
entry{
"------------------88888888\n"
"\n"
"666666-666666-666666----4444\n"
- "1------1------999999999-0000000000\n"
+ "1------1------999999999-0000000000\n",
},
entry{
"....................88888888\n"
"\n"
"666666...666666...666666......4444\n"
- "1........1........999999999...0000000000\n"
+ "1........1........999999999...0000000000\n",
},
entry{
"\t\t\t\t88888888\n"
"\n"
"666666\t666666\t666666\t\t4444\n"
- "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n"
+ "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
},
entry{
" 5.1 12.0 2.4 -7.0\n"
" .0 0.0 332.0 8908.0\n"
" .0 -.3 456.4 22.1\n"
- " .0 1.2 44.4 -13.3"
+ " .0 1.2 44.4 -13.3",
},
entry{
" 5.1| 12.0| 2.4| -7.0|\n"
" .0| 0.0| 332.0| 8908.0|\n"
" .0| -.3| 456.4| 22.1|\n"
- " .0| 1.2| 44.4| -13.3|"
+ " .0| 1.2| 44.4| -13.3|",
},
entry{
"15a",
4, 0, '.', 0,
"a\t\tb",
- "a.......b"
+ "a.......b",
},
entry{
"15b",
4, 0, '.', DiscardEmptyColumns,
- "a\t\tb", // htabs - do not discard column
- "a.......b"
+ "a\t\tb", // htabs - do not discard column
+ "a.......b",
},
entry{
"15c",
4, 0, '.', DiscardEmptyColumns,
"a\v\vb",
- "a...b"
+ "a...b",
},
entry{
"15d",
4, 0, '.', AlignRight | DiscardEmptyColumns,
"a\v\vb",
- "...ab"
+ "...ab",
},
entry{
"a\tb\t\td\te\n"
"a\n"
"a\tb\tc\td\n"
- "a\tb\tc\td\te\n"
+ "a\tb\tc\td\te\n",
},
entry{
"a\tb\td\te\n"
"a\n"
"a\tb\tc\td\n"
- "a\tb\tc\td\te\n"
+ "a\tb\tc\td\te\n",
},
entry{
"a\t|b\t||d\t|e\n"
"a\n"
"a\t|b\t|c\t|d\n"
- "a\t|b\t|c\t|d\t|e\n"
+ "a\t|b\t|c\t|d\t|e\n",
},
entry{
"16c",
100, 0, '\t', DiscardEmptyColumns,
- "a\tb\t\td\n" // hard tabs - do not discard column
+ "a\tb\t\td\n" // hard tabs - do not discard column
"a\tb\t\td\te\n"
"a\n"
"a\tb\tc\td\n"
"a\tb\t\td\te\n"
"a\n"
"a\tb\tc\td\n"
- "a\tb\tc\td\te\n"
+ "a\tb\tc\td\te\n",
},
entry{
"16c debug",
100, 0, '\t', DiscardEmptyColumns | Debug,
- "a\tb\t\td\n" // hard tabs - do not discard column
+ "a\tb\t\td\n" // hard tabs - do not discard column
"a\tb\t\td\te\n"
"a\n"
"a\tb\tc\td\n"
"a\t|b\t|\t|d\t|e\n"
"a\n"
"a\t|b\t|c\t|d\n"
- "a\t|b\t|c\t|d\t|e\n"
+ "a\t|b\t|c\t|d\t|e\n",
},
}