mirror of
https://github.com/golang/go
synced 2024-11-26 03:47:57 -07:00
Add flag -tabindent to gofmt: forces use of
tabs for indentation even if -spaces is set. Changes to gofmt: - added -tabindent flag - don't recompute parser and printer mode repeatedly Changes to go/printer: - provide new printing mode TabIndent Changes to tabwriter: - implement new mode TabIndent to use tabs independent of the actual padding character for leading empty columns - distinguish between minimal cell width and tab width (tabwidth is only used if the output contains tabs, minwidth and padding are always considered) - fixed and added more comments - some additional factoring By default, -tabindent is disabled and the default gofmt behavior is unchanged. By setting -spaces and -tabindent, gofmt will use tabs for indentation but do any other alignment with spaces. This permits a user to change the visible indentation by simply changing the editor's tab width and the code will remain properly aligned without the need to rerun gofmt. R=rsc https://golang.org/cl/163068
This commit is contained in:
parent
e89441ba8f
commit
dc7355a974
@ -31,12 +31,17 @@ var (
|
|||||||
|
|
||||||
// layout control
|
// layout control
|
||||||
tabwidth = flag.Int("tabwidth", 8, "tab width");
|
tabwidth = flag.Int("tabwidth", 8, "tab width");
|
||||||
|
tabindent = flag.Bool("tabindent", false, "indent with tabs independent of -spaces");
|
||||||
usespaces = flag.Bool("spaces", false, "align with spaces instead of tabs");
|
usespaces = flag.Bool("spaces", false, "align with spaces instead of tabs");
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
var exitCode = 0
|
var (
|
||||||
var rewrite func(*ast.File) *ast.File
|
exitCode = 0;
|
||||||
|
rewrite func(*ast.File) *ast.File;
|
||||||
|
parserMode uint;
|
||||||
|
printerMode uint;
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func report(err os.Error) {
|
func report(err os.Error) {
|
||||||
@ -52,24 +57,25 @@ func usage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func parserMode() uint {
|
func initParserMode() {
|
||||||
mode := uint(0);
|
parserMode = uint(0);
|
||||||
if *comments {
|
if *comments {
|
||||||
mode |= parser.ParseComments
|
parserMode |= parser.ParseComments
|
||||||
}
|
}
|
||||||
if *trace {
|
if *trace {
|
||||||
mode |= parser.Trace
|
parserMode |= parser.Trace
|
||||||
}
|
}
|
||||||
return mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func printerMode() uint {
|
func initPrinterMode() {
|
||||||
mode := uint(0);
|
printerMode = uint(0);
|
||||||
if *usespaces {
|
if *tabindent {
|
||||||
mode |= printer.UseSpaces
|
printerMode |= printer.TabIndent
|
||||||
|
}
|
||||||
|
if *usespaces {
|
||||||
|
printerMode |= printer.UseSpaces
|
||||||
}
|
}
|
||||||
return mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -85,7 +91,7 @@ func processFile(f *os.File) os.Error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := parser.ParseFile(f.Name(), src, parserMode());
|
file, err := parser.ParseFile(f.Name(), src, parserMode);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -95,7 +101,7 @@ func processFile(f *os.File) os.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var res bytes.Buffer;
|
var res bytes.Buffer;
|
||||||
_, err = (&printer.Config{printerMode(), *tabwidth, nil}).Fprint(&res, file);
|
_, err = (&printer.Config{printerMode, *tabwidth, nil}).Fprint(&res, file);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -175,6 +181,8 @@ func main() {
|
|||||||
os.Exit(2);
|
os.Exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initParserMode();
|
||||||
|
initPrinterMode();
|
||||||
initRewrite();
|
initRewrite();
|
||||||
|
|
||||||
if flag.NArg() == 0 {
|
if flag.NArg() == 0 {
|
||||||
|
@ -892,7 +892,8 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
|
|||||||
const (
|
const (
|
||||||
GenHTML uint = 1 << iota; // generate HTML
|
GenHTML uint = 1 << iota; // generate HTML
|
||||||
RawFormat; // do not use a tabwriter; if set, UseSpaces is ignored
|
RawFormat; // do not use a tabwriter; if set, UseSpaces is ignored
|
||||||
UseSpaces; // use spaces instead of tabs for indentation and alignment
|
TabIndent; // use tabs for indentation independent of UseSpaces
|
||||||
|
UseSpaces; // use spaces instead of tabs for alignment
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -937,15 +938,23 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
|
|||||||
// setup tabwriter if needed and redirect output
|
// setup tabwriter if needed and redirect output
|
||||||
var tw *tabwriter.Writer;
|
var tw *tabwriter.Writer;
|
||||||
if cfg.Mode&RawFormat == 0 {
|
if cfg.Mode&RawFormat == 0 {
|
||||||
|
minwidth := cfg.Tabwidth;
|
||||||
|
|
||||||
padchar := byte('\t');
|
padchar := byte('\t');
|
||||||
if cfg.Mode&UseSpaces != 0 {
|
if cfg.Mode&UseSpaces != 0 {
|
||||||
padchar = ' '
|
padchar = ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
twmode := tabwriter.DiscardEmptyColumns;
|
twmode := tabwriter.DiscardEmptyColumns;
|
||||||
if cfg.Mode&GenHTML != 0 {
|
if cfg.Mode&GenHTML != 0 {
|
||||||
twmode |= tabwriter.FilterHTML
|
twmode |= tabwriter.FilterHTML
|
||||||
}
|
}
|
||||||
tw = tabwriter.NewWriter(output, cfg.Tabwidth, 1, padchar, twmode);
|
if cfg.Mode&TabIndent != 0 {
|
||||||
|
minwidth = 0;
|
||||||
|
twmode |= tabwriter.TabIndent;
|
||||||
|
}
|
||||||
|
|
||||||
|
tw = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode);
|
||||||
output = tw;
|
output = tw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ import (
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Filter implementation
|
// Filter implementation
|
||||||
|
|
||||||
// A cell represents a segment of text delineated by tabs, formfeed,
|
// A cell represents a segment of text terminated by tabs or line breaks.
|
||||||
// or newline chars. The text itself is stored in a separate buffer;
|
// The text itself is stored in a separate buffer; cell only describes the
|
||||||
// cell only describes the segment's size in bytes, its width in runes,
|
// segment's size in bytes, its width in runes, and whether it's an htab
|
||||||
// and whether it's an htab ('\t') or vtab ('\v') terminated call.
|
// ('\t') terminated cell.
|
||||||
//
|
//
|
||||||
type cell struct {
|
type cell struct {
|
||||||
size int; // cell size in bytes
|
size int; // cell size in bytes
|
||||||
@ -38,15 +38,16 @@ type cell struct {
|
|||||||
// tab-delimited columns in its input to align them
|
// tab-delimited columns in its input to align them
|
||||||
// in the output.
|
// in the output.
|
||||||
//
|
//
|
||||||
// The Writer treats incoming bytes as UTF-8 encoded text
|
// The Writer treats incoming bytes as UTF-8 encoded text consisting
|
||||||
// consisting of tab-terminated cells. Cells in adjacent lines
|
// of cells terminated by (horizontal or vertical) tabs or line
|
||||||
// constitute a column. The Writer inserts padding as needed
|
// breaks (newline or formfeed characters). Cells in adjacent lines
|
||||||
// to make all cells in a column have the same width, effectively
|
// constitute a column. The Writer inserts padding as needed to
|
||||||
// aligning the columns. Note that cells are tab-terminated,
|
// make all cells in a column have the same width, effectively
|
||||||
// not tab-separated: trailing non-tab text at the end of a line
|
// aligning the columns. It assumes that all characters have the
|
||||||
// is not part of any cell.
|
// same width except for tabs for which a tabwidth must be specified.
|
||||||
|
// Note that cells are tab-terminated, not tab-separated: trailing
|
||||||
|
// non-tab text at the end of a line does not form a column cell.
|
||||||
//
|
//
|
||||||
// Horizontal and vertical tabs may be used to terminate a cell.
|
|
||||||
// If DiscardEmptyColumns is set, empty columns that are terminated
|
// If DiscardEmptyColumns is set, empty columns that are terminated
|
||||||
// entirely by vertical (or "soft") tabs are discarded. Columns
|
// entirely by vertical (or "soft") tabs are discarded. Columns
|
||||||
// terminated by horizontal (or "hard") tabs are not affected by
|
// terminated by horizontal (or "hard") tabs are not affected by
|
||||||
@ -78,17 +79,18 @@ type cell struct {
|
|||||||
type Writer struct {
|
type Writer struct {
|
||||||
// configuration
|
// configuration
|
||||||
output io.Writer;
|
output io.Writer;
|
||||||
cellwidth int;
|
minwidth int;
|
||||||
|
tabwidth int;
|
||||||
padding int;
|
padding int;
|
||||||
padbytes [8]byte;
|
padbytes [8]byte;
|
||||||
flags uint;
|
flags uint;
|
||||||
|
|
||||||
// current state
|
// current state
|
||||||
buf bytes.Buffer; // collected text w/o tabs, newlines, or formfeed chars
|
buf bytes.Buffer; // collected text excluding tabs or line breaks
|
||||||
pos int; // buffer position up to which width of incomplete cell has been computed
|
pos int; // buffer position up to which cell.width of incomplete cell has been computed
|
||||||
cell cell; // current incomplete cell; cell.width is up to buf[pos] w/o ignored sections
|
cell cell; // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
|
||||||
endChar byte; // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
|
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
|
lines vector.Vector; // list of lines; each line is a list of cells
|
||||||
widths vector.IntVector; // list of column widths in runes - re-used during formatting
|
widths vector.IntVector; // list of column widths in runes - re-used during formatting
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,9 +115,9 @@ func (b *Writer) reset() {
|
|||||||
|
|
||||||
// Internal representation (current state):
|
// Internal representation (current state):
|
||||||
//
|
//
|
||||||
// - all text written is appended to buf; formfeed chars, tabs and newlines are stripped away
|
// - all text written is appended to buf; tabs and line breaks are stripped away
|
||||||
// - at any given time there is a (possibly empty) incomplete cell at the end
|
// - at any given time there is a (possibly empty) incomplete cell at the end
|
||||||
// (the cell starts after a tab, formfeed, or newline)
|
// (the cell starts after a tab or line break)
|
||||||
// - cell.size is the number of bytes belonging to the cell so far
|
// - cell.size is the number of bytes belonging to the cell so far
|
||||||
// - cell.width is text width in runes of that cell from the start of the cell to
|
// - cell.width is text width in runes of that cell from the start of the cell to
|
||||||
// position pos; html tags and entities are excluded from this width if html
|
// position pos; html tags and entities are excluded from this width if html
|
||||||
@ -149,6 +151,10 @@ const (
|
|||||||
// the input in the first place.
|
// the input in the first place.
|
||||||
DiscardEmptyColumns;
|
DiscardEmptyColumns;
|
||||||
|
|
||||||
|
// Always use tabs for indentation columns (i.e., padding of
|
||||||
|
// leading empty cells on the left) independent of padchar.
|
||||||
|
TabIndent;
|
||||||
|
|
||||||
// Print a vertical bar ('|') between columns (after formatting).
|
// Print a vertical bar ('|') between columns (after formatting).
|
||||||
// Discarded colums appear as zero-width columns ("||").
|
// Discarded colums appear as zero-width columns ("||").
|
||||||
Debug;
|
Debug;
|
||||||
@ -158,37 +164,36 @@ const (
|
|||||||
// A Writer must be initialized with a call to Init. The first parameter (output)
|
// A Writer must be initialized with a call to Init. The first parameter (output)
|
||||||
// specifies the filter output. The remaining parameters control the formatting:
|
// specifies the filter output. The remaining parameters control the formatting:
|
||||||
//
|
//
|
||||||
// cellwidth minimal cell width
|
// minwidth minimal cell width including any padding
|
||||||
// padding cell padding added to cell before computing its width
|
// tabwidth width of tab characters (equivalent number of spaces)
|
||||||
|
// padding padding added to a cell before computing its width
|
||||||
// padchar ASCII char used for padding
|
// padchar ASCII char used for padding
|
||||||
// if padchar == '\t', the Writer will assume that the
|
// if padchar == '\t', the Writer will assume that the
|
||||||
// width of a '\t' in the formatted output is cellwidth,
|
// width of a '\t' in the formatted output is tabwidth,
|
||||||
// and cells are left-aligned independent of align_left
|
// and cells are left-aligned independent of align_left
|
||||||
// (for correct-looking results, cellwidth must correspond
|
// (for correct-looking results, tabwidth must correspond
|
||||||
// to the tab width in the viewer displaying the result)
|
// to the tab width in the viewer displaying the result)
|
||||||
// flags formatting control
|
// flags formatting control
|
||||||
//
|
//
|
||||||
// To format in tab-separated columns with a tab stop of 8:
|
// To format in tab-separated columns with a tab stop of 8:
|
||||||
// b.Init(w, 8, 1, '\t', 0);
|
// b.Init(w, 8, 1, 8, '\t', 0);
|
||||||
//
|
//
|
||||||
// To format in space-separated columns with at least 4 spaces between columns:
|
// To format in space-separated columns with at least 4 spaces between columns:
|
||||||
// b.Init(w, 1, 4, ' ', 0);
|
// b.Init(w, 0, 4, 8, ' ', 0);
|
||||||
//
|
//
|
||||||
func (b *Writer) Init(output io.Writer, cellwidth, padding int, padchar byte, flags uint) *Writer {
|
func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
|
||||||
if cellwidth < 0 {
|
if minwidth < 0 || tabwidth < 0 || padding < 0 {
|
||||||
panic("negative cellwidth")
|
panic("negative minwidth, tabwidth, or padding")
|
||||||
}
|
|
||||||
if padding < 0 {
|
|
||||||
panic("negative padding")
|
|
||||||
}
|
}
|
||||||
b.output = output;
|
b.output = output;
|
||||||
b.cellwidth = cellwidth;
|
b.minwidth = minwidth;
|
||||||
|
b.tabwidth = tabwidth;
|
||||||
b.padding = padding;
|
b.padding = padding;
|
||||||
for i := len(b.padbytes) - 1; i >= 0; i-- {
|
for i := range b.padbytes {
|
||||||
b.padbytes[i] = padchar
|
b.padbytes[i] = padchar
|
||||||
}
|
}
|
||||||
if padchar == '\t' {
|
if padchar == '\t' {
|
||||||
// tab enforces left-alignment
|
// tab padding enforces left-alignment
|
||||||
flags &^= AlignRight
|
flags &^= AlignRight
|
||||||
}
|
}
|
||||||
b.flags = flags;
|
b.flags = flags;
|
||||||
@ -200,22 +205,20 @@ func (b *Writer) Init(output io.Writer, cellwidth, padding int, padchar byte, fl
|
|||||||
|
|
||||||
|
|
||||||
// debugging support (keep code around)
|
// debugging support (keep code around)
|
||||||
/*
|
|
||||||
func (b *Writer) dump() {
|
func (b *Writer) dump() {
|
||||||
pos := 0;
|
pos := 0;
|
||||||
for i := 0; i < b.lines_size.Len(); i++ {
|
for i := 0; i < b.lines.Len(); i++ {
|
||||||
line_size, line_width := b.line(i);
|
line := b.line(i);
|
||||||
print("(", i, ") ");
|
print("(", i, ") ");
|
||||||
for j := 0; j < line_size.Len(); j++ {
|
for j := 0; j < line.Len(); j++ {
|
||||||
s := line_size.At(j);
|
c := line.At(j).(cell);
|
||||||
print("[", string(b.buf.slice(pos, pos + s)), "]");
|
print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]");
|
||||||
pos += s;
|
pos += c.size;
|
||||||
}
|
}
|
||||||
print("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
print("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Writer) write0(buf []byte) os.Error {
|
func (b *Writer) write0(buf []byte) os.Error {
|
||||||
@ -227,35 +230,40 @@ func (b *Writer) write0(buf []byte) os.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var newline = []byte{'\n'}
|
func (b *Writer) writeN(src []byte, n int) os.Error {
|
||||||
|
for n > len(src) {
|
||||||
func (b *Writer) writePadding(textw, cellw int) os.Error {
|
if err := b.write0(src); err != nil {
|
||||||
if b.cellwidth == 0 {
|
return err
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
n -= len(src);
|
||||||
if b.padbytes[0] == '\t' {
|
|
||||||
// make cell width a multiple of cellwidth
|
|
||||||
cellw = ((cellw + b.cellwidth - 1) / b.cellwidth) * b.cellwidth
|
|
||||||
}
|
}
|
||||||
|
return b.write0(src[0:n]);
|
||||||
|
}
|
||||||
|
|
||||||
n := cellw - textw;
|
|
||||||
|
var (
|
||||||
|
newline = []byte{'\n'};
|
||||||
|
tabs = []byte{'\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t'};
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func (b *Writer) writePadding(textw, cellw int, useTabs bool) os.Error {
|
||||||
|
if b.padbytes[0] == '\t' || useTabs {
|
||||||
|
// padding is done with tabs
|
||||||
|
if b.tabwidth == 0 {
|
||||||
|
return nil // tabs have no width - can't do any padding
|
||||||
|
}
|
||||||
|
// make cellw the smallest multiple of b.tabwidth
|
||||||
|
cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth;
|
||||||
|
n := cellw - textw; // amount of padding
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
panic("internal error")
|
panic("internal error")
|
||||||
}
|
}
|
||||||
|
return b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth);
|
||||||
if b.padbytes[0] == '\t' {
|
|
||||||
n = (n + b.cellwidth - 1) / b.cellwidth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for n > len(b.padbytes) {
|
// padding is done with non-tab characters
|
||||||
if err := b.write0(&b.padbytes); err != nil {
|
return b.writeN(&b.padbytes, cellw-textw);
|
||||||
return err
|
|
||||||
}
|
|
||||||
n -= len(b.padbytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.write0(b.padbytes[0:n]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -265,6 +273,10 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error)
|
|||||||
pos = pos0;
|
pos = pos0;
|
||||||
for i := line0; i < line1; i++ {
|
for i := line0; i < line1; i++ {
|
||||||
line := b.line(i);
|
line := b.line(i);
|
||||||
|
|
||||||
|
// if TabIndent is set, use tabs to pad leading empty cells
|
||||||
|
useTabs := b.flags&TabIndent != 0;
|
||||||
|
|
||||||
for j := 0; j < line.Len(); j++ {
|
for j := 0; j < line.Len(); j++ {
|
||||||
c := line.At(j).(cell);
|
c := line.At(j).(cell);
|
||||||
|
|
||||||
@ -273,23 +285,30 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch {
|
|
||||||
default: // align left
|
|
||||||
|
|
||||||
|
if c.size == 0 {
|
||||||
|
// empty cell
|
||||||
|
if j < b.widths.Len() {
|
||||||
|
if err = b.writePadding(c.width, b.widths.At(j), useTabs); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// non-empty cell
|
||||||
|
useTabs = false;
|
||||||
|
if b.flags&AlignRight == 0 { // align left
|
||||||
if err = b.write0(b.buf.Bytes()[pos : pos+c.size]); err != nil {
|
if err = b.write0(b.buf.Bytes()[pos : pos+c.size]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pos += c.size;
|
pos += c.size;
|
||||||
if j < b.widths.Len() {
|
if j < b.widths.Len() {
|
||||||
if err = b.writePadding(c.width, b.widths.At(j)); err != nil {
|
if err = b.writePadding(c.width, b.widths.At(j), false); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else { // align right
|
||||||
case b.flags&AlignRight != 0: // align right
|
|
||||||
|
|
||||||
if j < b.widths.Len() {
|
if j < b.widths.Len() {
|
||||||
if err = b.writePadding(c.width, b.widths.At(j)); err != nil {
|
if err = b.writePadding(c.width, b.widths.At(j), false); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,6 +318,7 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error)
|
|||||||
pos += c.size;
|
pos += c.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if i+1 == b.lines.Len() {
|
if i+1 == b.lines.Len() {
|
||||||
// last buffered line - we don't have a newline, so just write
|
// last buffered line - we don't have a newline, so just write
|
||||||
@ -344,7 +364,7 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
|||||||
line0 = this;
|
line0 = this;
|
||||||
|
|
||||||
// column block begin
|
// column block begin
|
||||||
width := b.cellwidth; // minimal column width
|
width := b.minwidth; // minimal column width
|
||||||
discardable := true; // true if all cells in this column are empty and "soft"
|
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);
|
||||||
@ -551,6 +571,6 @@ func (b *Writer) Write(buf []byte) (n int, err os.Error) {
|
|||||||
// NewWriter allocates and initializes a new tabwriter.Writer.
|
// NewWriter allocates and initializes a new tabwriter.Writer.
|
||||||
// The parameters are the same as for the the Init function.
|
// The parameters are the same as for the the Init function.
|
||||||
//
|
//
|
||||||
func NewWriter(output io.Writer, cellwidth, padding int, padchar byte, flags uint) *Writer {
|
func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
|
||||||
return new(Writer).Init(output, cellwidth, padding, padchar, flags)
|
return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags)
|
||||||
}
|
}
|
||||||
|
@ -64,12 +64,12 @@ func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected s
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func check(t *testing.T, testname string, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
|
func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
|
||||||
var b buffer;
|
var b buffer;
|
||||||
b.init(1000);
|
b.init(1000);
|
||||||
|
|
||||||
var w Writer;
|
var w Writer;
|
||||||
w.Init(&b, tabwidth, padding, padchar, flags);
|
w.Init(&b, minwidth, tabwidth, padding, padchar, flags);
|
||||||
|
|
||||||
// write all at once
|
// write all at once
|
||||||
b.clear();
|
b.clear();
|
||||||
@ -98,7 +98,7 @@ func check(t *testing.T, testname string, tabwidth, padding int, padchar byte, f
|
|||||||
|
|
||||||
type entry struct {
|
type entry struct {
|
||||||
testname string;
|
testname string;
|
||||||
tabwidth, padding int;
|
minwidth, tabwidth, padding int;
|
||||||
padchar byte;
|
padchar byte;
|
||||||
flags uint;
|
flags uint;
|
||||||
src, expected string;
|
src, expected string;
|
||||||
@ -108,182 +108,182 @@ type entry struct {
|
|||||||
var tests = []entry{
|
var tests = []entry{
|
||||||
entry{
|
entry{
|
||||||
"1a",
|
"1a",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"1a debug",
|
"1a debug",
|
||||||
8, 1, '.', Debug,
|
8, 0, 1, '.', Debug,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"1b esc",
|
"1b esc",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"\xff\xff",
|
"\xff\xff",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"1c esc",
|
"1c esc",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"\xff\t\xff",
|
"\xff\t\xff",
|
||||||
"\t",
|
"\t",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"1d esc",
|
"1d esc",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"\xff\"foo\t\n\tbar\"\xff",
|
"\xff\"foo\t\n\tbar\"\xff",
|
||||||
"\"foo\t\n\tbar\"",
|
"\"foo\t\n\tbar\"",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"1e esc",
|
"1e esc",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"abc\xff\tdef", // unterminated escape
|
"abc\xff\tdef", // unterminated escape
|
||||||
"abc\tdef",
|
"abc\tdef",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"2",
|
"2",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"\n\n\n",
|
"\n\n\n",
|
||||||
"\n\n\n",
|
"\n\n\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"3",
|
"3",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"a\nb\nc",
|
"a\nb\nc",
|
||||||
"a\nb\nc",
|
"a\nb\nc",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"4a",
|
"4a",
|
||||||
8, 1, '.', 0,
|
8, 0, 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{
|
entry{
|
||||||
"4b",
|
"4b",
|
||||||
8, 1, '.', AlignRight,
|
8, 0, 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{
|
entry{
|
||||||
"5",
|
"5",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"*\t*",
|
"*\t*",
|
||||||
"*.......*",
|
"*.......*",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"5b",
|
"5b",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"*\t*\n",
|
"*\t*\n",
|
||||||
"*.......*\n",
|
"*.......*\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"5c",
|
"5c",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"*\t*\t",
|
"*\t*\t",
|
||||||
"*.......*",
|
"*.......*",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"5c debug",
|
"5c debug",
|
||||||
8, 1, '.', Debug,
|
8, 0, 1, '.', Debug,
|
||||||
"*\t*\t",
|
"*\t*\t",
|
||||||
"*.......|*",
|
"*.......|*",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"5d",
|
"5d",
|
||||||
8, 1, '.', AlignRight,
|
8, 0, 1, '.', AlignRight,
|
||||||
"*\t*\t",
|
"*\t*\t",
|
||||||
".......**",
|
".......**",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"6",
|
"6",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"\t\n",
|
"\t\n",
|
||||||
"........\n",
|
"........\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"7a",
|
"7a",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"a) foo",
|
"a) foo",
|
||||||
"a) foo",
|
"a) foo",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"7b",
|
"7b",
|
||||||
8, 1, ' ', 0,
|
8, 0, 1, ' ', 0,
|
||||||
"b) foo\tbar",
|
"b) foo\tbar",
|
||||||
"b) foo bar",
|
"b) foo bar",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"7c",
|
"7c",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"c) foo\tbar\t",
|
"c) foo\tbar\t",
|
||||||
"c) foo..bar",
|
"c) foo..bar",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"7d",
|
"7d",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"d) foo\tbar\n",
|
"d) foo\tbar\n",
|
||||||
"d) foo..bar\n",
|
"d) foo..bar\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"7e",
|
"7e",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"e) foo\tbar\t\n",
|
"e) foo\tbar\t\n",
|
||||||
"e) foo..bar.....\n",
|
"e) foo..bar.....\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"7f",
|
"7f",
|
||||||
8, 1, '.', FilterHTML,
|
8, 0, 1, '.', FilterHTML,
|
||||||
"f) f<o\t<b>bar</b>\t\n",
|
"f) f<o\t<b>bar</b>\t\n",
|
||||||
"f) f<o..<b>bar</b>.....\n",
|
"f) f<o..<b>bar</b>.....\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"7g",
|
"7g",
|
||||||
8, 1, '.', FilterHTML,
|
8, 0, 1, '.', FilterHTML,
|
||||||
"g) f<o\t<b>bar</b>\t non-terminated entity &",
|
"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{
|
entry{
|
||||||
"7g debug",
|
"7g debug",
|
||||||
8, 1, '.', FilterHTML | Debug,
|
8, 0, 1, '.', FilterHTML | Debug,
|
||||||
"g) f<o\t<b>bar</b>\t non-terminated entity &",
|
"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{
|
entry{
|
||||||
"8",
|
"8",
|
||||||
8, 1, '*', 0,
|
8, 0, 1, '*', 0,
|
||||||
"Hello, world!\n",
|
"Hello, world!\n",
|
||||||
"Hello, world!\n",
|
"Hello, world!\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"9a",
|
"9a",
|
||||||
1, 0, '.', 0,
|
1, 0, 0, '.', 0,
|
||||||
"1\t2\t3\t4\n"
|
"1\t2\t3\t4\n"
|
||||||
"11\t222\t3333\t44444\n",
|
"11\t222\t3333\t44444\n",
|
||||||
|
|
||||||
@ -293,7 +293,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"9b",
|
"9b",
|
||||||
1, 0, '.', FilterHTML,
|
1, 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",
|
"11\t222\t3333\t44444\n",
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"9c",
|
"9c",
|
||||||
1, 0, '.', 0,
|
1, 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",
|
"11\t222\t3333\t44444\n",
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"9c debug",
|
"9c debug",
|
||||||
1, 0, '.', Debug,
|
1, 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",
|
"11\t222\t3333\t44444\n",
|
||||||
|
|
||||||
@ -323,21 +323,21 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"10a",
|
"10a",
|
||||||
5, 0, '.', 0,
|
5, 0, 0, '.', 0,
|
||||||
"1\t2\t3\t4\n",
|
"1\t2\t3\t4\n",
|
||||||
"1....2....3....4\n",
|
"1....2....3....4\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"10b",
|
"10b",
|
||||||
5, 0, '.', 0,
|
5, 0, 0, '.', 0,
|
||||||
"1\t2\t3\t4\t\n",
|
"1\t2\t3\t4\t\n",
|
||||||
"1....2....3....4....\n",
|
"1....2....3....4....\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"11",
|
"11",
|
||||||
8, 1, '.', 0,
|
8, 0, 1, '.', 0,
|
||||||
"本\tb\tc\n"
|
"本\tb\tc\n"
|
||||||
"aa\t\u672c\u672c\u672c\tcccc\tddddd\n"
|
"aa\t\u672c\u672c\u672c\tcccc\tddddd\n"
|
||||||
"aaa\tbbbb\n",
|
"aaa\tbbbb\n",
|
||||||
@ -349,7 +349,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"12a",
|
"12a",
|
||||||
8, 1, ' ', AlignRight,
|
8, 0, 1, ' ', AlignRight,
|
||||||
"a\tè\tc\t\n"
|
"a\tè\tc\t\n"
|
||||||
"aa\tèèè\tcccc\tddddd\t\n"
|
"aa\tèèè\tcccc\tddddd\t\n"
|
||||||
"aaa\tèèèè\t\n",
|
"aaa\tèèèè\t\n",
|
||||||
@ -361,7 +361,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"12b",
|
"12b",
|
||||||
2, 0, ' ', 0,
|
2, 0, 0, ' ', 0,
|
||||||
"a\tb\tc\n"
|
"a\tb\tc\n"
|
||||||
"aa\tbbb\tcccc\n"
|
"aa\tbbb\tcccc\n"
|
||||||
"aaa\tbbbb\n",
|
"aaa\tbbbb\n",
|
||||||
@ -373,7 +373,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"12c",
|
"12c",
|
||||||
8, 1, '_', 0,
|
8, 0, 1, '_', 0,
|
||||||
"a\tb\tc\n"
|
"a\tb\tc\n"
|
||||||
"aa\tbbb\tcccc\n"
|
"aa\tbbb\tcccc\n"
|
||||||
"aaa\tbbbb\n",
|
"aaa\tbbbb\n",
|
||||||
@ -385,7 +385,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"13a",
|
"13a",
|
||||||
4, 1, '-', 0,
|
4, 0, 1, '-', 0,
|
||||||
"4444\t日本語\t22\t1\t333\n"
|
"4444\t日本語\t22\t1\t333\n"
|
||||||
"999999999\t22\n"
|
"999999999\t22\n"
|
||||||
"7\t22\n"
|
"7\t22\n"
|
||||||
@ -405,7 +405,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"13b",
|
"13b",
|
||||||
4, 3, '.', 0,
|
4, 0, 3, '.', 0,
|
||||||
"4444\t333\t22\t1\t333\n"
|
"4444\t333\t22\t1\t333\n"
|
||||||
"999999999\t22\n"
|
"999999999\t22\n"
|
||||||
"7\t22\n"
|
"7\t22\n"
|
||||||
@ -425,7 +425,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"13c",
|
"13c",
|
||||||
8, 1, '\t', FilterHTML,
|
8, 8, 1, '\t', FilterHTML,
|
||||||
"4444\t333\t22\t1\t333\n"
|
"4444\t333\t22\t1\t333\n"
|
||||||
"999999999\t22\n"
|
"999999999\t22\n"
|
||||||
"7\t22\n"
|
"7\t22\n"
|
||||||
@ -445,7 +445,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"14",
|
"14",
|
||||||
1, 2, ' ', AlignRight,
|
1, 0, 2, ' ', AlignRight,
|
||||||
".0\t.3\t2.4\t-5.1\t\n"
|
".0\t.3\t2.4\t-5.1\t\n"
|
||||||
"23.0\t12345678.9\t2.4\t-989.4\t\n"
|
"23.0\t12345678.9\t2.4\t-989.4\t\n"
|
||||||
"5.1\t12.0\t2.4\t-7.0\t\n"
|
"5.1\t12.0\t2.4\t-7.0\t\n"
|
||||||
@ -463,7 +463,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"14 debug",
|
"14 debug",
|
||||||
1, 2, ' ', AlignRight | Debug,
|
1, 0, 2, ' ', AlignRight | Debug,
|
||||||
".0\t.3\t2.4\t-5.1\t\n"
|
".0\t.3\t2.4\t-5.1\t\n"
|
||||||
"23.0\t12345678.9\t2.4\t-989.4\t\n"
|
"23.0\t12345678.9\t2.4\t-989.4\t\n"
|
||||||
"5.1\t12.0\t2.4\t-7.0\t\n"
|
"5.1\t12.0\t2.4\t-7.0\t\n"
|
||||||
@ -481,35 +481,35 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"15a",
|
"15a",
|
||||||
4, 0, '.', 0,
|
4, 0, 0, '.', 0,
|
||||||
"a\t\tb",
|
"a\t\tb",
|
||||||
"a.......b",
|
"a.......b",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"15b",
|
"15b",
|
||||||
4, 0, '.', DiscardEmptyColumns,
|
4, 0, 0, '.', DiscardEmptyColumns,
|
||||||
"a\t\tb", // htabs - do not discard column
|
"a\t\tb", // htabs - do not discard column
|
||||||
"a.......b",
|
"a.......b",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"15c",
|
"15c",
|
||||||
4, 0, '.', DiscardEmptyColumns,
|
4, 0, 0, '.', DiscardEmptyColumns,
|
||||||
"a\v\vb",
|
"a\v\vb",
|
||||||
"a...b",
|
"a...b",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"15d",
|
"15d",
|
||||||
4, 0, '.', AlignRight | DiscardEmptyColumns,
|
4, 0, 0, '.', AlignRight | DiscardEmptyColumns,
|
||||||
"a\v\vb",
|
"a\v\vb",
|
||||||
"...ab",
|
"...ab",
|
||||||
},
|
},
|
||||||
|
|
||||||
entry{
|
entry{
|
||||||
"16a",
|
"16a",
|
||||||
100, 0, '\t', 0,
|
100, 100, 0, '\t', 0,
|
||||||
"a\tb\t\td\n"
|
"a\tb\t\td\n"
|
||||||
"a\tb\t\td\te\n"
|
"a\tb\t\td\te\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
@ -525,7 +525,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"16b",
|
"16b",
|
||||||
100, 0, '\t', DiscardEmptyColumns,
|
100, 100, 0, '\t', DiscardEmptyColumns,
|
||||||
"a\vb\v\vd\n"
|
"a\vb\v\vd\n"
|
||||||
"a\vb\v\vd\ve\n"
|
"a\vb\v\vd\ve\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
@ -541,7 +541,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"16b debug",
|
"16b debug",
|
||||||
100, 0, '\t', DiscardEmptyColumns | Debug,
|
100, 100, 0, '\t', DiscardEmptyColumns | Debug,
|
||||||
"a\vb\v\vd\n"
|
"a\vb\v\vd\n"
|
||||||
"a\vb\v\vd\ve\n"
|
"a\vb\v\vd\ve\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
@ -557,7 +557,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"16c",
|
"16c",
|
||||||
100, 0, '\t', DiscardEmptyColumns,
|
100, 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\tb\t\td\te\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
@ -573,7 +573,7 @@ var tests = []entry{
|
|||||||
|
|
||||||
entry{
|
entry{
|
||||||
"16c debug",
|
"16c debug",
|
||||||
100, 0, '\t', DiscardEmptyColumns | Debug,
|
100, 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\tb\t\td\te\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
@ -591,6 +591,6 @@ var tests = []entry{
|
|||||||
|
|
||||||
func Test(t *testing.T) {
|
func Test(t *testing.T) {
|
||||||
for _, e := range tests {
|
for _, e := range tests {
|
||||||
check(t, e.testname, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
|
check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user