]> Cypherpunks repositories - gostls13.git/commitdiff
support for "hard" and "soft" tabs:
authorRobert Griesemer <gri@golang.org>
Wed, 7 Oct 2009 17:55:45 +0000 (10:55 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 7 Oct 2009 17:55:45 +0000 (10:55 -0700)
- soft-tab separated columns can be discarded if empty and DiscardEmptyColumns is set
- hard-tab separated columns are never discarded

R=rsc
DELTA=63  (42 added, 7 deleted, 14 changed)
OCL=35421
CL=35435

src/pkg/tabwriter/tabwriter.go
src/pkg/tabwriter/tabwriter_test.go

index 5103f6ce28ad0468f20f03c38283208f29e9516f..15ffc79ccde5e8091495fd191ae6029641ddc534 100644 (file)
@@ -23,11 +23,13 @@ import (
 
 // A cell represents a segment of text delineated by tabs, form-feed,
 // or newline chars. The text itself is stored in a separate buffer;
-// cell only describes the segment's size in bytes and width in runes.
+// cell only describes the segment's size in bytes, its width in runes,
+// 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')
 }
 
 
@@ -43,6 +45,12 @@ type cell struct {
 // not tab-separated: trailing non-tab text at the end of a line
 // is not part of any cell.
 //
+// Horizontal and vertical tabs may be used to terminate a cell.
+// If DiscardEmptyColumns is set, empty columns that are terminated
+// entirely by vertical (or "soft") tabs are discarded. Columns
+// terminated by horizontal (or "hard") tabs are not affected by
+// this flag.
+//
 // The Writer assumes that all characters have the same width;
 // this may not be true in some fonts, especially with certain
 // UTF-8 characters.
@@ -314,16 +322,19 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
 
                        // column block begin
                        width := b.cellwidth;  // minimal column width
-                       wsum := 0;  // the sum of all unpadded cell widths in this column
+                       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 {
                                        // cell exists in this column
-                                       w := line.At(column).(cell).width;
-                                       wsum += w;
+                                       c := line.At(column).(cell);
                                        // update width
-                                       if t := w + b.padding; t > width {
-                                               width = t;
+                                       if w := c.width + b.padding; w > width {
+                                               width = w;
+                                       }
+                                       // update discardable
+                                       if c.width > 0 || c.htab {
+                                               discardable = false;
                                        }
                                } else {
                                        break
@@ -332,7 +343,7 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
                        // column block end
 
                        // discard empty columns if necessary
-                       if wsum == 0 && b.flags & DiscardEmptyColumns != 0 {
+                       if discardable && b.flags & DiscardEmptyColumns != 0 {
                                width = 0;
                        }
 
@@ -391,7 +402,8 @@ func (b *Writer) terminateHTML() {
 // Terminate the current cell by adding it to the list of cells of the
 // current line. Returns the number of cells in that line.
 //
-func (b *Writer) terminateCell() int {
+func (b *Writer) terminateCell(htab bool) int {
+       b.cell.htab = htab;
        line := b.line(b.lines.Len() - 1);
        line.Push(b.cell);
        b.cell = cell{};
@@ -411,7 +423,7 @@ func (b *Writer) Flush() os.Error {
                        // inside html tag/entity - terminate it even if incomplete
                        b.terminateHTML();
                }
-               b.terminateCell();
+               b.terminateCell(false);
        }
 
        // format contents of buffer
@@ -435,12 +447,12 @@ func (b *Writer) Write(buf []byte) (written int, err os.Error) {
                if b.html_char == 0 {
                        // outside html tag/entity
                        switch ch {
-                       case '\t', '\n', '\f':
+                       case '\t', '\v', '\n', '\f':
                                // end of cell
                                b.append(buf[i0 : i], true);
                                i0 = i+1;  // exclude ch from (next) cell
-                               ncells := b.terminateCell();
-                               if ch != '\t' {
+                               ncells := b.terminateCell(ch == '\t');
+                               if ch == '\n' || ch == '\f' {
                                        // terminate line
                                        b.addLine();
                                        if ch == '\f' || ncells == 1 {
index 6b2fa862e4da978a06be9c55a93eeb931caa794e..b43a269805ce134c66bf8f9885eadda714692637 100644 (file)
@@ -418,14 +418,21 @@ var tests = []entry {
        entry{
                "15b",
                4, 0, '.', DiscardEmptyColumns,
-               "a\t\tb",
-               "a...b"
+               "a\t\tb",  // htabs - do not discard column
+               "a.......b"
        },
 
        entry{
                "15c",
+               4, 0, '.', DiscardEmptyColumns,
+               "a\v\vb",
+               "a...b"
+       },
+
+       entry{
+               "15d",
                4, 0, '.', AlignRight | DiscardEmptyColumns,
-               "a\t\tb",
+               "a\v\vb",
                "...ab"
        },
 
@@ -448,14 +455,30 @@ var tests = []entry {
        entry{
                "16b",
                100, 0, '\t', DiscardEmptyColumns,
-               "a\tb\t\td\n"
+               "a\vb\v\vd\n"
+               "a\vb\v\vd\ve\n"
+               "a\n"
+               "a\vb\vc\vd\n"
+               "a\vb\vc\vd\ve\n",
+
+               "a\tb\td\n"
+               "a\tb\td\te\n"
+               "a\n"
+               "a\tb\tc\td\n"
+               "a\tb\tc\td\te\n"
+       },
+
+       entry{
+               "16c",
+               100, 0, '\t', DiscardEmptyColumns,
+               "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\tc\td\te\n",
 
-               "a\tb\td\n"
-               "a\tb\td\te\n"
+               "a\tb\t\td\n"
+               "a\tb\t\td\te\n"
                "a\n"
                "a\tb\tc\td\n"
                "a\tb\tc\td\te\n"