mirror of https://github.com/golang/go.git
- factored out tabwriter a separate writer filter
(to be moved into std lib eventually) - rewrote tabwriter to use byte buffers instead of strings (byte buffers to be moved into stdlib eventually) - support for recent syntax changes - no space printed after function name and before function parameters - comments still disabled due to a known bug R=r OCL=19430 CL=19430
This commit is contained in:
parent
337af31781
commit
654bc2badc
|
|
@ -32,7 +32,8 @@ parser.6: scanner.6 ast.6
|
||||||
|
|
||||||
platform.6: utils.6
|
platform.6: utils.6
|
||||||
|
|
||||||
printer.6: scanner.6 ast.6
|
printer.6: scanner.6 ast.6 tabwriter.6
|
||||||
|
|
||||||
|
|
||||||
%.6: %.go
|
%.6: %.go
|
||||||
$(G) $(F) $<
|
$(G) $(F) $<
|
||||||
|
|
|
||||||
|
|
@ -469,8 +469,14 @@ func (P *Parser) ParseFunctionType() *AST.Type {
|
||||||
func (P *Parser) ParseMethodSpec(list *AST.List) {
|
func (P *Parser) ParseMethodSpec(list *AST.List) {
|
||||||
P.Trace("MethodDecl");
|
P.Trace("MethodDecl");
|
||||||
|
|
||||||
list.Add(P.ParseIdent());
|
list.Add(P.ParseIdentList());
|
||||||
list.Add(AST.NewTypeExpr(P.ParseFunctionType()));
|
t := AST.BadType;
|
||||||
|
if P.sixg {
|
||||||
|
t = P.ParseType();
|
||||||
|
} else {
|
||||||
|
t = P.ParseFunctionType();
|
||||||
|
}
|
||||||
|
list.Add(AST.NewTypeExpr(t));
|
||||||
|
|
||||||
P.Ecart();
|
P.Ecart();
|
||||||
}
|
}
|
||||||
|
|
@ -1485,7 +1491,8 @@ func (P *Parser) ParseDeclaration() *AST.Decl {
|
||||||
|
|
||||||
d := AST.BadDecl;
|
d := AST.BadDecl;
|
||||||
exported := false;
|
exported := false;
|
||||||
if P.tok == Scanner.EXPORT {
|
// TODO don't use bool flag for export
|
||||||
|
if P.tok == Scanner.EXPORT || P.tok == Scanner.PACKAGE {
|
||||||
if P.scope_lev == 0 {
|
if P.scope_lev == 0 {
|
||||||
exported = true;
|
exported = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ import Scanner "scanner"
|
||||||
import AST "ast"
|
import AST "ast"
|
||||||
import Flag "flag"
|
import Flag "flag"
|
||||||
import Fmt "fmt"
|
import Fmt "fmt"
|
||||||
|
import IO "io"
|
||||||
|
import OS "os"
|
||||||
|
import TabWriter "tabwriter"
|
||||||
|
|
||||||
var tabwith = Flag.Int("tabwidth", 4, nil, "tab width");
|
var tabwith = Flag.Int("tabwidth", 4, nil, "tab width");
|
||||||
var comments = Flag.Bool("comments", false, nil, "enable printing of comments");
|
var comments = Flag.Bool("comments", false, nil, "enable printing of comments");
|
||||||
|
|
@ -24,180 +27,11 @@ func assert(p bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func PrintBlanks(n int) {
|
|
||||||
// TODO make this faster
|
|
||||||
for ; n > 0; n-- {
|
|
||||||
print(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Implemententation of flexible tab stops.
|
|
||||||
|
|
||||||
// Buffer is a representation for a list of lines consisting of
|
|
||||||
// cells. A new cell is added for each Tab() call, and a new line
|
|
||||||
// is added for each Newline() call.
|
|
||||||
//
|
|
||||||
// The lines are formatted and printed such that all cells in a column
|
|
||||||
// of adjacent cells have the same width (by adding padding). For more
|
|
||||||
// details see: http://nickgravgaard.com/elastictabstops/index.html .
|
|
||||||
|
|
||||||
type Buffer struct {
|
|
||||||
cell string; // current cell (last cell in last line, not in lines yet)
|
|
||||||
lines AST.List; // list of lines; each line is a list of cells (strings)
|
|
||||||
widths AST.List; // list of column widths - (re-)used during formatting
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Implementation
|
|
||||||
// (Do not use these functions outside the Buffer implementation).
|
|
||||||
|
|
||||||
func (b *Buffer) AddLine() {
|
|
||||||
b.lines.Add(AST.NewList());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Buffer) Line(i int) *AST.List {
|
|
||||||
return b.lines.at(i).(*AST.List);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Buffer) LastLine() *AST.List {
|
|
||||||
return b.lines.last().(*AST.List);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// debugging support
|
|
||||||
func (b *Buffer) Dump() {
|
|
||||||
for i := 0; i < b.lines.len(); i++ {
|
|
||||||
line := b.Line(i);
|
|
||||||
print("(", i, ") ");
|
|
||||||
for j := 0; j < line.len(); j++ {
|
|
||||||
print("[", line.at(j).(string), "]");
|
|
||||||
}
|
|
||||||
print("\n");
|
|
||||||
}
|
|
||||||
print("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Buffer) PrintLines(line0, line1 int) {
|
|
||||||
for i := line0; i < line1; i++ {
|
|
||||||
line := b.Line(i);
|
|
||||||
for j := 0; j < line.len(); j++ {
|
|
||||||
s := line.at(j).(string);
|
|
||||||
print(s);
|
|
||||||
if j < b.widths.len() {
|
|
||||||
nsep := b.widths.at(j).(int) - len(s);
|
|
||||||
assert(nsep >= 0);
|
|
||||||
PrintBlanks(nsep);
|
|
||||||
} else {
|
|
||||||
assert(j == b.widths.len());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Buffer) Format(line0, line1 int) {
|
|
||||||
column := b.widths.len();
|
|
||||||
|
|
||||||
last := line0;
|
|
||||||
for this := line0; this < line1; this++ {
|
|
||||||
line := b.Line(this);
|
|
||||||
|
|
||||||
if column < line.len() - 1 {
|
|
||||||
// cell exists in this column
|
|
||||||
// (note that the last cell per line is ignored)
|
|
||||||
|
|
||||||
// print unprinted lines until beginning of block
|
|
||||||
b.PrintLines(last, this);
|
|
||||||
last = this;
|
|
||||||
|
|
||||||
// column block begin
|
|
||||||
width := int(tabwith.IVal()); // minimal width
|
|
||||||
for ; this < line1; this++ {
|
|
||||||
line := b.Line(this);
|
|
||||||
if column < line.len() - 1 {
|
|
||||||
// cell exists in this column
|
|
||||||
// update width
|
|
||||||
w := len(line.at(column).(string)) + 1; // 1 = minimum space between cells
|
|
||||||
if w > width {
|
|
||||||
width = w;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// column block end
|
|
||||||
|
|
||||||
// format and print all columns to the right of this column
|
|
||||||
// (we know the widths of this column and all columns to the left)
|
|
||||||
b.widths.Add(width);
|
|
||||||
b.Format(last, this);
|
|
||||||
b.widths.Pop();
|
|
||||||
last = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// print unprinted lines until end
|
|
||||||
b.PrintLines(last, line1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Buffer interface
|
|
||||||
// (Use these functions to interact with Buffers).
|
|
||||||
|
|
||||||
func (b *Buffer) Init() {
|
|
||||||
b.lines.Init();
|
|
||||||
b.widths.Init();
|
|
||||||
b.AddLine(); // the very first line
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Buffer) EmptyLine() bool {
|
|
||||||
return b.LastLine().len() == 0 && len(b.cell) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Buffer) Tab() {
|
|
||||||
b.LastLine().Add(b.cell);
|
|
||||||
b.cell = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Buffer) Newline() {
|
|
||||||
b.Tab(); // add last cell to current line
|
|
||||||
|
|
||||||
if b.LastLine().len() == 1 {
|
|
||||||
// The current line has only one cell which does not have an impact
|
|
||||||
// on the formatting of the following lines (the last cell per line
|
|
||||||
// is ignored by Format), thus we can print the buffer contents.
|
|
||||||
assert(b.widths.len() == 0);
|
|
||||||
b.Format(0, b.lines.len());
|
|
||||||
assert(b.widths.len() == 0);
|
|
||||||
|
|
||||||
// reset the buffer
|
|
||||||
b.lines.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
b.AddLine();
|
|
||||||
assert(len(b.cell) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (b *Buffer) Print(s string) {
|
|
||||||
b.cell += s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Printer
|
// Printer
|
||||||
|
|
||||||
export type Printer struct {
|
export type Printer struct {
|
||||||
buf Buffer;
|
writer IO.Write;
|
||||||
|
|
||||||
// formatting control
|
// formatting control
|
||||||
lastpos int; // pos after last string
|
lastpos int; // pos after last string
|
||||||
|
|
@ -213,13 +47,18 @@ export type Printer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (P *Printer) Printf(fmt string, s ...) {
|
||||||
|
Fmt.fprintf(P.writer, fmt, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func (P *Printer) String(pos int, s string) {
|
func (P *Printer) String(pos int, s string) {
|
||||||
if pos == 0 {
|
if pos == 0 {
|
||||||
pos = P.lastpos; // estimate
|
pos = P.lastpos; // estimate
|
||||||
}
|
}
|
||||||
|
|
||||||
if P.semi && P.level > 0 { // no semicolons at level 0
|
if P.semi && P.level > 0 { // no semicolons at level 0
|
||||||
P.buf.Print(";");
|
P.Printf(";");
|
||||||
}
|
}
|
||||||
|
|
||||||
//print("--", pos, "[", s, "]\n");
|
//print("--", pos, "[", s, "]\n");
|
||||||
|
|
@ -238,26 +77,25 @@ func (P *Printer) String(pos int, s string) {
|
||||||
case Scanner.COMMENT_BB:
|
case Scanner.COMMENT_BB:
|
||||||
// black space before and after comment on the same line
|
// black space before and after comment on the same line
|
||||||
// - print surrounded by blanks
|
// - print surrounded by blanks
|
||||||
P.buf.Print(" ");
|
P.Printf(" %s ", text);
|
||||||
P.buf.Print(text);
|
|
||||||
P.buf.Print(" ");
|
|
||||||
|
|
||||||
case Scanner.COMMENT_BW:
|
case Scanner.COMMENT_BW:
|
||||||
// only white space after comment on the same line
|
// only white space after comment on the same line
|
||||||
// - put into next cell
|
// - put into next cell
|
||||||
P.buf.Tab();
|
P.Printf("\t%s", text);
|
||||||
P.buf.Print(text);
|
|
||||||
|
|
||||||
case Scanner.COMMENT_WW, Scanner.COMMENT_WB:
|
case Scanner.COMMENT_WW, Scanner.COMMENT_WB:
|
||||||
// only white space before comment on the same line
|
// only white space before comment on the same line
|
||||||
// - indent
|
// - indent
|
||||||
|
/*
|
||||||
if !P.buf.EmptyLine() {
|
if !P.buf.EmptyLine() {
|
||||||
P.buf.Newline();
|
P.buf.Newline();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
for i := P.indent; i > 0; i-- {
|
for i := P.indent; i > 0; i-- {
|
||||||
P.buf.Tab();
|
P.Printf("\t");
|
||||||
}
|
}
|
||||||
P.buf.Print(text);
|
P.Printf("%s", text);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("UNREACHABLE");
|
panic("UNREACHABLE");
|
||||||
|
|
@ -266,9 +104,9 @@ func (P *Printer) String(pos int, s string) {
|
||||||
if text[1] == '/' {
|
if text[1] == '/' {
|
||||||
// line comments must end in newline
|
// line comments must end in newline
|
||||||
// TODO should we set P.newl instead?
|
// TODO should we set P.newl instead?
|
||||||
P.buf.Newline();
|
P.Printf("\n");
|
||||||
for i := P.indent; i > 0; i-- {
|
for i := P.indent; i > 0; i-- {
|
||||||
P.buf.Tab();
|
P.Printf("\t");
|
||||||
}
|
}
|
||||||
at_line_begin = true;
|
at_line_begin = true;
|
||||||
}
|
}
|
||||||
|
|
@ -286,19 +124,18 @@ func (P *Printer) String(pos int, s string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if P.newl > 0 {
|
if P.newl > 0 {
|
||||||
P.buf.Newline();
|
P.Printf("\n");
|
||||||
if P.newl > 1 {
|
if P.newl > 1 {
|
||||||
for i := P.newl; i > 1; i-- {
|
for i := P.newl; i > 1; i-- {
|
||||||
//P.buf.Flush();
|
P.Printf("\n");
|
||||||
P.buf.Newline();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := P.indent; i > 0; i-- {
|
for i := P.indent; i > 0; i-- {
|
||||||
P.buf.Tab();
|
P.Printf("\t");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
P.buf.Print(s);
|
P.Printf("%s", s);
|
||||||
|
|
||||||
P.lastpos = pos + len(s);
|
P.lastpos = pos + len(s);
|
||||||
P.semi, P.newl = false, 0;
|
P.semi, P.newl = false, 0;
|
||||||
|
|
@ -311,8 +148,7 @@ func (P *Printer) Blank() {
|
||||||
|
|
||||||
|
|
||||||
func (P *Printer) Tab() {
|
func (P *Printer) Tab() {
|
||||||
P.String(0, "");
|
P.String(0, "\t");
|
||||||
P.buf.Tab();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -712,7 +548,9 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
|
||||||
P.Expr(d.ident);
|
P.Expr(d.ident);
|
||||||
|
|
||||||
if d.typ != nil {
|
if d.typ != nil {
|
||||||
P.Blank();
|
if d.tok != Scanner.FUNC {
|
||||||
|
P.Blank();
|
||||||
|
}
|
||||||
P.Type(d.typ);
|
P.Type(d.typ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -756,7 +594,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
|
||||||
|
|
||||||
func (P *Printer) Program(p *AST.Program) {
|
func (P *Printer) Program(p *AST.Program) {
|
||||||
// TODO should initialize all fields?
|
// TODO should initialize all fields?
|
||||||
P.buf.Init();
|
P.writer = TabWriter.MakeTabWriter(OS.Stdout, 4);
|
||||||
|
|
||||||
P.clist = p.comments;
|
P.clist = p.comments;
|
||||||
P.cindex = 0;
|
P.cindex = 0;
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,14 @@ var (
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// the prolog
|
// the prologue
|
||||||
for i := 0; i <= 10 /* limit */; i++ {
|
for i := 0; i <= 10 /* limit */; i++ {
|
||||||
println(i); // the index
|
println(i); // the index
|
||||||
println(i + 1); // the index + 1
|
println(i + 1); // the index + 1
|
||||||
println(i + 1000); // the index + 1000
|
println(i + 1000); // the index + 1000
|
||||||
println();
|
println();
|
||||||
}
|
}
|
||||||
// the epilog
|
// the epilogue
|
||||||
println("foo"); // foo
|
println("foo"); // foo
|
||||||
println("foobar"); // foobar
|
println("foobar"); // foobar
|
||||||
var x int;
|
var x int;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,285 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package tabwriter
|
||||||
|
|
||||||
|
import (
|
||||||
|
OS "os";
|
||||||
|
IO "io";
|
||||||
|
Vector "vector";
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// ByteArray
|
||||||
|
|
||||||
|
type ByteArray struct {
|
||||||
|
a *[]byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *ByteArray) Init(initial_size int) {
|
||||||
|
b.a = new([]byte, initial_size)[0 : 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *ByteArray) Clear() {
|
||||||
|
b.a = b.a[0 : 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *ByteArray) Len() int {
|
||||||
|
return len(b.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *ByteArray) At(i int) byte {
|
||||||
|
return b.a[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *ByteArray) Set(i int, x byte) {
|
||||||
|
b.a[i] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *ByteArray) Slice(i, j int) *[]byte {
|
||||||
|
return b.a[i : j]; // BUG should really be &b.a[i : j]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *ByteArray) Append(s *[]byte) {
|
||||||
|
a := b.a;
|
||||||
|
n := len(a);
|
||||||
|
m := n + len(s);
|
||||||
|
|
||||||
|
if m > cap(a) {
|
||||||
|
n2 := 2*n;
|
||||||
|
if m > n2 {
|
||||||
|
n2 = m;
|
||||||
|
}
|
||||||
|
b := new([]byte, n2);
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
b[i] = a[i];
|
||||||
|
}
|
||||||
|
a = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = a[0 : m];
|
||||||
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
|
a[n + i] = s[i];
|
||||||
|
}
|
||||||
|
b.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Implemententation of flexible tab stops.
|
||||||
|
|
||||||
|
// TabWriter is a representation for a list of lines consisting of
|
||||||
|
// cells. A new cell is added for each Tab() call, and a new line
|
||||||
|
// is added for each Newline() call.
|
||||||
|
//
|
||||||
|
// The lines are formatted and printed such that all cells in a column
|
||||||
|
// of adjacent cells have the same width (by adding padding). For more
|
||||||
|
// details see: http://nickgravgaard.com/elastictabstops/index.html .
|
||||||
|
|
||||||
|
type TabWriter struct {
|
||||||
|
// configuration
|
||||||
|
writer IO.Write;
|
||||||
|
tabwidth int;
|
||||||
|
|
||||||
|
// current state
|
||||||
|
buf ByteArray; // the collected text w/o tabs and newlines
|
||||||
|
width int; // width of last incomplete cell
|
||||||
|
lines Vector.Vector; // list of lines; each line is a list of cell widths
|
||||||
|
widths Vector.Vector; // list of column widths - (re-)used during formatting
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) AddLine() {
|
||||||
|
b.lines.Append(Vector.New());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) Init(writer IO.Write, tabwidth int) {
|
||||||
|
b.writer = writer;
|
||||||
|
b.tabwidth = tabwidth;
|
||||||
|
|
||||||
|
b.buf.Init(1024);
|
||||||
|
b.lines.Init();
|
||||||
|
b.widths.Init();
|
||||||
|
b.AddLine(); // the very first line
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) Line(i int) *Vector.Vector {
|
||||||
|
return b.lines.At(i).(*Vector.Vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) LastLine() *Vector.Vector {
|
||||||
|
return b.lines.At(b.lines.Len() - 1).(*Vector.Vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// debugging support
|
||||||
|
func (b *TabWriter) Dump() {
|
||||||
|
pos := 0;
|
||||||
|
for i := 0; i < b.lines.Len(); i++ {
|
||||||
|
line := b.Line(i);
|
||||||
|
print("(", i, ") ");
|
||||||
|
for j := 0; j < line.Len(); j++ {
|
||||||
|
w := line.At(j).(int);
|
||||||
|
print("[", string(b.buf.a[pos : pos + w]), "]");
|
||||||
|
pos += w;
|
||||||
|
}
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var Blanks = &[]byte{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}
|
||||||
|
var Newline = &[]byte{'\n'}
|
||||||
|
|
||||||
|
func (b *TabWriter) WriteBlanks(n int) {
|
||||||
|
for n >= len(Blanks) {
|
||||||
|
m, err := b.writer.Write(Blanks);
|
||||||
|
n -= len(Blanks);
|
||||||
|
}
|
||||||
|
m, err := b.writer.Write(Blanks[0 : n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) PrintLines(pos int, line0, line1 int) int {
|
||||||
|
for i := line0; i < line1; i++ {
|
||||||
|
line := b.Line(i);
|
||||||
|
for j := 0; j < line.Len(); j++ {
|
||||||
|
w := line.At(j).(int);
|
||||||
|
m, err := b.writer.Write(b.buf.a[pos : pos + w]);
|
||||||
|
if m != w {
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
pos += w;
|
||||||
|
if j < b.widths.Len() {
|
||||||
|
b.WriteBlanks(b.widths.At(j).(int) - w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m, err := b.writer.Write(Newline);
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) Format(pos int, line0, line1 int) int {
|
||||||
|
column := b.widths.Len();
|
||||||
|
|
||||||
|
last := line0;
|
||||||
|
for this := line0; this < line1; this++ {
|
||||||
|
line := b.Line(this);
|
||||||
|
|
||||||
|
if column < line.Len() - 1 {
|
||||||
|
// cell exists in this column
|
||||||
|
// (note that the last cell per line is ignored)
|
||||||
|
|
||||||
|
// print unprinted lines until beginning of block
|
||||||
|
pos = b.PrintLines(pos, last, this);
|
||||||
|
last = this;
|
||||||
|
|
||||||
|
// column block begin
|
||||||
|
width := b.tabwidth; // minimal width
|
||||||
|
for ; this < line1; this++ {
|
||||||
|
line = b.Line(this);
|
||||||
|
if column < line.Len() - 1 {
|
||||||
|
// cell exists in this column
|
||||||
|
// update width
|
||||||
|
w := line.At(column).(int) + 1; // 1 = minimum space between cells
|
||||||
|
if w > width {
|
||||||
|
width = w;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// column block end
|
||||||
|
|
||||||
|
// format and print all columns to the right of this column
|
||||||
|
// (we know the widths of this column and all columns to the left)
|
||||||
|
b.widths.Append(width);
|
||||||
|
pos = b.Format(pos, last, this);
|
||||||
|
b.widths.Remove(b.widths.Len() - 1);
|
||||||
|
last = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print unprinted lines until end
|
||||||
|
return b.PrintLines(pos, last, line1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) EmptyLine() bool {
|
||||||
|
return b.LastLine().Len() == 0 && b.width == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) Tab() {
|
||||||
|
b.LastLine().Append(b.width);
|
||||||
|
b.width = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) Newline() {
|
||||||
|
b.Tab(); // add last cell to current line
|
||||||
|
|
||||||
|
if b.LastLine().Len() == 1 {
|
||||||
|
// The current line has only one cell which does not have an impact
|
||||||
|
// on the formatting of the following lines (the last cell per line
|
||||||
|
// is ignored by Format), thus we can print the TabWriter contents.
|
||||||
|
if b.widths.Len() != 0 {
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
//b.Dump();
|
||||||
|
b.Format(0, 0, b.lines.Len());
|
||||||
|
if b.widths.Len() != 0 {
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the TabWriter
|
||||||
|
b.width = 0;
|
||||||
|
b.buf.Clear();
|
||||||
|
b.lines.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
b.AddLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *TabWriter) Write(buf *[]byte) (i int, err *OS.Error) {
|
||||||
|
i0, n := 0, len(buf);
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
switch buf[i] {
|
||||||
|
case '\t':
|
||||||
|
b.width += i - i0;
|
||||||
|
b.buf.Append(buf[i0 : i]);
|
||||||
|
i0 = i + 1; // don't append '\t'
|
||||||
|
b.Tab();
|
||||||
|
case '\n':
|
||||||
|
b.width += i - i0;
|
||||||
|
b.buf.Append(buf[i0 : i]);
|
||||||
|
i0 = i + 1; // don't append '\n'
|
||||||
|
b.Newline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.width += n - i0;
|
||||||
|
b.buf.Append(buf[i0 : n]);
|
||||||
|
return i, nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export func MakeTabWriter(writer IO.Write, tabwidth int) IO.Write {
|
||||||
|
b := new(TabWriter);
|
||||||
|
b.Init(writer, tabwidth);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue