mirror of
https://github.com/golang/go
synced 2024-11-12 09:50:21 -07:00
support for "hard" and "soft" tabs:
- 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
This commit is contained in:
parent
c2874976e4
commit
f77b255c38
@ -23,11 +23,13 @@ import (
|
|||||||
|
|
||||||
// A cell represents a segment of text delineated by tabs, form-feed,
|
// A cell represents a segment of text delineated by tabs, form-feed,
|
||||||
// or newline chars. The text itself is stored in a separate buffer;
|
// 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 {
|
type cell struct {
|
||||||
size int; // cell size in bytes
|
size int; // cell size in bytes
|
||||||
width int; // cell width in runes
|
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
|
// not tab-separated: trailing non-tab text at the end of a line
|
||||||
// is not part of any cell.
|
// 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;
|
// The Writer assumes that all characters have the same width;
|
||||||
// this may not be true in some fonts, especially with certain
|
// this may not be true in some fonts, especially with certain
|
||||||
// UTF-8 characters.
|
// UTF-8 characters.
|
||||||
@ -314,16 +322,19 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
|||||||
|
|
||||||
// column block begin
|
// column block begin
|
||||||
width := b.cellwidth; // minimal column width
|
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++ {
|
for ; this < line1; this++ {
|
||||||
line = b.line(this);
|
line = b.line(this);
|
||||||
if column < line.Len() - 1 {
|
if column < line.Len() - 1 {
|
||||||
// cell exists in this column
|
// cell exists in this column
|
||||||
w := line.At(column).(cell).width;
|
c := line.At(column).(cell);
|
||||||
wsum += w;
|
|
||||||
// update width
|
// update width
|
||||||
if t := w + b.padding; t > width {
|
if w := c.width + b.padding; w > width {
|
||||||
width = t;
|
width = w;
|
||||||
|
}
|
||||||
|
// update discardable
|
||||||
|
if c.width > 0 || c.htab {
|
||||||
|
discardable = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
@ -332,7 +343,7 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
|||||||
// column block end
|
// column block end
|
||||||
|
|
||||||
// discard empty columns if necessary
|
// discard empty columns if necessary
|
||||||
if wsum == 0 && b.flags & DiscardEmptyColumns != 0 {
|
if discardable && b.flags & DiscardEmptyColumns != 0 {
|
||||||
width = 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
|
// Terminate the current cell by adding it to the list of cells of the
|
||||||
// current line. Returns the number of cells in that line.
|
// 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 := b.line(b.lines.Len() - 1);
|
||||||
line.Push(b.cell);
|
line.Push(b.cell);
|
||||||
b.cell = cell{};
|
b.cell = cell{};
|
||||||
@ -411,7 +423,7 @@ func (b *Writer) Flush() os.Error {
|
|||||||
// inside html tag/entity - terminate it even if incomplete
|
// inside html tag/entity - terminate it even if incomplete
|
||||||
b.terminateHTML();
|
b.terminateHTML();
|
||||||
}
|
}
|
||||||
b.terminateCell();
|
b.terminateCell(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// format contents of buffer
|
// format contents of buffer
|
||||||
@ -435,12 +447,12 @@ func (b *Writer) Write(buf []byte) (written int, err os.Error) {
|
|||||||
if b.html_char == 0 {
|
if b.html_char == 0 {
|
||||||
// outside html tag/entity
|
// outside html tag/entity
|
||||||
switch ch {
|
switch ch {
|
||||||
case '\t', '\n', '\f':
|
case '\t', '\v', '\n', '\f':
|
||||||
// end of cell
|
// end of cell
|
||||||
b.append(buf[i0 : i], true);
|
b.append(buf[i0 : i], true);
|
||||||
i0 = i+1; // exclude ch from (next) cell
|
i0 = i+1; // exclude ch from (next) cell
|
||||||
ncells := b.terminateCell();
|
ncells := b.terminateCell(ch == '\t');
|
||||||
if ch != '\t' {
|
if ch == '\n' || ch == '\f' {
|
||||||
// terminate line
|
// terminate line
|
||||||
b.addLine();
|
b.addLine();
|
||||||
if ch == '\f' || ncells == 1 {
|
if ch == '\f' || ncells == 1 {
|
||||||
|
@ -418,14 +418,21 @@ var tests = []entry {
|
|||||||
entry{
|
entry{
|
||||||
"15b",
|
"15b",
|
||||||
4, 0, '.', DiscardEmptyColumns,
|
4, 0, '.', DiscardEmptyColumns,
|
||||||
"a\t\tb",
|
"a\t\tb", // htabs - do not discard column
|
||||||
"a...b"
|
"a.......b"
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"15c",
|
"15c",
|
||||||
|
4, 0, '.', DiscardEmptyColumns,
|
||||||
|
"a\v\vb",
|
||||||
|
"a...b"
|
||||||
|
},
|
||||||
|
|
||||||
|
entry{
|
||||||
|
"15d",
|
||||||
4, 0, '.', AlignRight | DiscardEmptyColumns,
|
4, 0, '.', AlignRight | DiscardEmptyColumns,
|
||||||
"a\t\tb",
|
"a\v\vb",
|
||||||
"...ab"
|
"...ab"
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -448,14 +455,30 @@ var tests = []entry {
|
|||||||
entry{
|
entry{
|
||||||
"16b",
|
"16b",
|
||||||
100, 0, '\t', DiscardEmptyColumns,
|
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\tb\t\td\te\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
"a\tb\tc\td\n"
|
"a\tb\tc\td\n"
|
||||||
"a\tb\tc\td\te\n",
|
"a\tb\tc\td\te\n",
|
||||||
|
|
||||||
"a\tb\td\n"
|
"a\tb\t\td\n"
|
||||||
"a\tb\td\te\n"
|
"a\tb\t\td\te\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
"a\tb\tc\td\n"
|
"a\tb\tc\td\n"
|
||||||
"a\tb\tc\td\te\n"
|
"a\tb\tc\td\te\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user