mirror of
https://github.com/golang/go
synced 2024-11-25 21:57:57 -07:00
printer:
- prepare for generation of HTML id tags and links - do HTML-escaping in central print routine - move tabwriter setup into printer - fixed various TODOs godoc: - removed tabwriter setup, need for various HTML-escaping R=rsc DELTA=210 (107 added, 36 deleted, 67 changed) OCL=32612 CL=32616
This commit is contained in:
parent
d951ce4e45
commit
62718fb5d4
@ -47,7 +47,6 @@ import (
|
|||||||
"strings";
|
"strings";
|
||||||
"sync";
|
"sync";
|
||||||
"syscall";
|
"syscall";
|
||||||
"tabwriter";
|
|
||||||
"template";
|
"template";
|
||||||
"time";
|
"time";
|
||||||
)
|
)
|
||||||
@ -125,11 +124,6 @@ func isPkgDir(dir *os.Dir) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func makeTabwriter(writer io.Writer) *tabwriter.Writer {
|
|
||||||
return tabwriter.NewWriter(writer, *tabwidth, 1, byte(' '), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Parsing
|
// Parsing
|
||||||
|
|
||||||
@ -201,55 +195,66 @@ func parse(path string, mode uint) (*ast.File, *parseErrors) {
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Templates
|
// Templates
|
||||||
|
|
||||||
// Return text for an AST node.
|
// Write an AST-node to w; optionally html-escaped.
|
||||||
func nodeText(node interface{}) []byte {
|
func writeNode(w io.Writer, node interface{}, html bool) {
|
||||||
var buf bytes.Buffer;
|
mode := printer.UseSpaces;
|
||||||
tw := makeTabwriter(&buf);
|
if html {
|
||||||
printer.Fprint(tw, node, 0);
|
mode |= printer.GenHTML;
|
||||||
tw.Flush();
|
}
|
||||||
return buf.Data();
|
printer.Fprint(w, node, mode, *tabwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Convert x, whatever it is, to text form.
|
// Write text to w; optionally html-escaped.
|
||||||
func toText(x interface{}) []byte {
|
func writeText(w io.Writer, text []byte, html bool) {
|
||||||
type Stringer interface { String() string }
|
if html {
|
||||||
|
template.HtmlEscape(w, text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w.Write(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write anything to w; optionally html-escaped.
|
||||||
|
func writeAny(w io.Writer, x interface{}, html bool) {
|
||||||
switch v := x.(type) {
|
switch v := x.(type) {
|
||||||
case []byte:
|
case []byte:
|
||||||
return v;
|
writeText(w, v, html);
|
||||||
case string:
|
case string:
|
||||||
return strings.Bytes(v);
|
writeText(w, strings.Bytes(v), html);
|
||||||
case ast.Decl:
|
case ast.Decl:
|
||||||
return nodeText(v);
|
writeNode(w, v, html);
|
||||||
case ast.Expr:
|
case ast.Expr:
|
||||||
return nodeText(v);
|
writeNode(w, v, html);
|
||||||
case Stringer:
|
default:
|
||||||
// last resort (AST nodes get a String method
|
if html {
|
||||||
// from token.Position - don't call that one)
|
var buf bytes.Buffer;
|
||||||
return strings.Bytes(v.String());
|
fmt.Fprint(&buf, x);
|
||||||
|
writeText(w, buf.Data(), true);
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(w, x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer;
|
|
||||||
fmt.Fprint(&buf, x);
|
|
||||||
return buf.Data();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Template formatter for "html" format.
|
// Template formatter for "html" format.
|
||||||
func htmlFmt(w io.Writer, x interface{}, format string) {
|
func htmlFmt(w io.Writer, x interface{}, format string) {
|
||||||
template.HtmlEscape(w, toText(x));
|
writeAny(w, x, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Template formatter for "html-comment" format.
|
// Template formatter for "html-comment" format.
|
||||||
func htmlCommentFmt(w io.Writer, x interface{}, format string) {
|
func htmlCommentFmt(w io.Writer, x interface{}, format string) {
|
||||||
doc.ToHtml(w, toText(x));
|
var buf bytes.Buffer;
|
||||||
|
writeAny(&buf, x, false);
|
||||||
|
doc.ToHtml(w, buf.Data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Template formatter for "" (default) format.
|
// Template formatter for "" (default) format.
|
||||||
func textFmt(w io.Writer, x interface{}, format string) {
|
func textFmt(w io.Writer, x interface{}, format string) {
|
||||||
w.Write(toText(x));
|
writeAny(w, x, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -337,7 +342,7 @@ func serveGoSource(c *http.Conn, name string) {
|
|||||||
|
|
||||||
var buf bytes.Buffer;
|
var buf bytes.Buffer;
|
||||||
fmt.Fprintln(&buf, "<pre>");
|
fmt.Fprintln(&buf, "<pre>");
|
||||||
template.HtmlEscape(&buf, nodeText(prog));
|
writeNode(&buf, prog, true);
|
||||||
fmt.Fprintln(&buf, "</pre>");
|
fmt.Fprintln(&buf, "</pre>");
|
||||||
|
|
||||||
servePage(c, name + " - Go source", buf.Data());
|
servePage(c, name + " - Go source", buf.Data());
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
pathutil "path";
|
pathutil "path";
|
||||||
"sort";
|
"sort";
|
||||||
"strings";
|
"strings";
|
||||||
"tabwriter";
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -34,8 +33,9 @@ var (
|
|||||||
exports = flag.Bool("x", false, "show exports only");
|
exports = flag.Bool("x", false, "show exports only");
|
||||||
|
|
||||||
// layout control
|
// layout control
|
||||||
tabwidth = flag.Int("tabwidth", 4, "tab width");
|
tabwidth = flag.Int("tabwidth", 8, "tab width");
|
||||||
usetabs = flag.Bool("tabs", false, "align with tabs instead of blanks");
|
rawformat = flag.Bool("rawformat", false, "do not use a tabwriter");
|
||||||
|
usespaces = flag.Bool("spaces", false, "align with blanks instead of tabs");
|
||||||
optcommas = flag.Bool("optcommas", false, "print optional commas");
|
optcommas = flag.Bool("optcommas", false, "print optional commas");
|
||||||
optsemis = flag.Bool("optsemis", false, "print optional semicolons");
|
optsemis = flag.Bool("optsemis", false, "print optional semicolons");
|
||||||
)
|
)
|
||||||
@ -104,6 +104,12 @@ func getPackage(path string) (*ast.Package, os.Error) {
|
|||||||
|
|
||||||
func printerMode() uint {
|
func printerMode() uint {
|
||||||
mode := uint(0);
|
mode := uint(0);
|
||||||
|
if *rawformat {
|
||||||
|
mode |= printer.RawFormat;
|
||||||
|
}
|
||||||
|
if *usespaces {
|
||||||
|
mode |= printer.UseSpaces;
|
||||||
|
}
|
||||||
if *optcommas {
|
if *optcommas {
|
||||||
mode |= printer.OptCommas;
|
mode |= printer.OptCommas;
|
||||||
}
|
}
|
||||||
@ -114,15 +120,6 @@ func printerMode() uint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func makeTabwriter(writer io.Writer) *tabwriter.Writer {
|
|
||||||
padchar := byte(' ');
|
|
||||||
if *usetabs {
|
|
||||||
padchar = '\t';
|
|
||||||
}
|
|
||||||
return tabwriter.NewWriter(writer, *tabwidth, 1, padchar, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Usage = usage;
|
flag.Usage = usage;
|
||||||
flag.Parse();
|
flag.Parse();
|
||||||
@ -144,15 +141,21 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !*silent {
|
if !*silent {
|
||||||
w := makeTabwriter(os.Stdout);
|
|
||||||
if *exports {
|
if *exports {
|
||||||
ast.PackageExports(pkg);
|
ast.PackageExports(pkg);
|
||||||
printer.Fprint(w, ast.MergePackageFiles(pkg), printerMode()); // ignore errors
|
_, err := printer.Fprint(os.Stdout, ast.MergePackageFiles(pkg), printerMode(), *tabwidth);
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprint(os.Stderr, err);
|
||||||
|
os.Exit(2);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, src := range pkg.Files {
|
for _, src := range pkg.Files {
|
||||||
printer.Fprint(w, src, printerMode()); // ignore errors
|
_, err := printer.Fprint(os.Stdout, src, printerMode(), *tabwidth);
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprint(os.Stderr, err);
|
||||||
|
os.Exit(2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Flush();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ fmt.install: io.install os.install reflect.install strconv.install utf8.install
|
|||||||
go/ast.install: go/token.install unicode.install utf8.install
|
go/ast.install: go/token.install unicode.install utf8.install
|
||||||
go/doc.install: container/vector.install fmt.install go/ast.install go/token.install io.install once.install regexp.install sort.install strings.install template.install
|
go/doc.install: container/vector.install fmt.install go/ast.install go/token.install io.install once.install regexp.install sort.install strings.install template.install
|
||||||
go/parser.install: bytes.install container/vector.install fmt.install go/ast.install go/scanner.install go/token.install io.install os.install path.install strings.install
|
go/parser.install: bytes.install container/vector.install fmt.install go/ast.install go/scanner.install go/token.install io.install os.install path.install strings.install
|
||||||
go/printer.install: fmt.install go/ast.install go/token.install io.install os.install reflect.install strings.install
|
go/printer.install: fmt.install go/ast.install go/token.install io.install os.install reflect.install strings.install tabwriter.install
|
||||||
go/scanner.install: bytes.install container/vector.install fmt.install go/token.install io.install os.install sort.install strconv.install unicode.install utf8.install
|
go/scanner.install: bytes.install container/vector.install fmt.install go/token.install io.install os.install sort.install strconv.install unicode.install utf8.install
|
||||||
go/token.install: fmt.install strconv.install
|
go/token.install: fmt.install strconv.install
|
||||||
gob.install: bytes.install fmt.install io.install math.install os.install reflect.install strings.install sync.install unicode.install
|
gob.install: bytes.install fmt.install io.install math.install os.install reflect.install strings.install sync.install unicode.install
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"os";
|
"os";
|
||||||
"reflect";
|
"reflect";
|
||||||
"strings";
|
"strings";
|
||||||
|
"tabwriter";
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -26,7 +27,10 @@ const (
|
|||||||
// to Fprint via the mode parameter.
|
// to Fprint via the mode parameter.
|
||||||
//
|
//
|
||||||
const (
|
const (
|
||||||
OptCommas = 1 << iota; // print optional commas
|
GenHTML uint = 1 << iota; // generate HTML
|
||||||
|
RawFormat; // do not use a tabwriter; if set, UseSpaces is ignored
|
||||||
|
UseSpaces; // use spaces instead of tabs for indentation and alignment
|
||||||
|
OptCommas; // print optional commas
|
||||||
OptSemis; // print optional semicolons
|
OptSemis; // print optional semicolons
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,6 +45,15 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
var (
|
||||||
|
tabs = [...]byte{'\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t'};
|
||||||
|
newlines = [...]byte{'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; // more than maxNewlines
|
||||||
|
ampersand = strings.Bytes("&");
|
||||||
|
lessthan = strings.Bytes("<");
|
||||||
|
greaterthan = strings.Bytes(">");
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
type printer struct {
|
type printer struct {
|
||||||
// configuration (does not change after initialization)
|
// configuration (does not change after initialization)
|
||||||
output io.Writer;
|
output io.Writer;
|
||||||
@ -70,8 +83,7 @@ func (p *printer) init(output io.Writer, mode uint) {
|
|||||||
|
|
||||||
|
|
||||||
// Writing to p.output is done with write0 which also handles errors.
|
// Writing to p.output is done with write0 which also handles errors.
|
||||||
// It should only be called by write and debug routines which are not
|
// Does not indent after newlines, or HTML-escape, or update p.pos.
|
||||||
// supposed to update the p.pos estimation.
|
|
||||||
//
|
//
|
||||||
func (p *printer) write0(data []byte) {
|
func (p *printer) write0(data []byte) {
|
||||||
n, err := p.output.Write(data);
|
n, err := p.output.Write(data);
|
||||||
@ -85,22 +97,55 @@ func (p *printer) write0(data []byte) {
|
|||||||
func (p *printer) write(data []byte) {
|
func (p *printer) write(data []byte) {
|
||||||
i0 := 0;
|
i0 := 0;
|
||||||
for i, b := range data {
|
for i, b := range data {
|
||||||
if b == '\n' || b == '\f' {
|
switch b {
|
||||||
// write segment ending in a newline/formfeed followed by indentation
|
case '\n', '\f':
|
||||||
// TODO(gri) should convert '\f' into '\n' if the output is not going
|
// write segment ending in b followed by indentation
|
||||||
// through tabwriter
|
if p.mode & RawFormat != 0 && b == '\f' {
|
||||||
p.write0(data[i0 : i+1]);
|
// no tabwriter - convert last byte into a newline
|
||||||
// TODO(gri) should not write indentation is there is nothing else
|
p.write0(data[i0 : i]);
|
||||||
// on the line
|
p.write0(newlines[0 : 1]);
|
||||||
for j := p.indent; j > 0; j-- {
|
} else {
|
||||||
p.write0([]byte{'\t'}); // TODO(gri) don't do allocation in every iteration
|
p.write0(data[i0 : i+1]);
|
||||||
}
|
}
|
||||||
i0 = i+1;
|
|
||||||
|
// write indentation
|
||||||
|
// TODO(gri) should not write indentation if there is nothing else
|
||||||
|
// on the line
|
||||||
|
j := p.indent;
|
||||||
|
for ; j > len(tabs); j -= len(tabs) {
|
||||||
|
p.write0(&tabs);
|
||||||
|
}
|
||||||
|
p.write0(tabs[0 : j]);
|
||||||
|
|
||||||
// update p.pos
|
// update p.pos
|
||||||
p.pos.Offset += i+1 - i0 + p.indent;
|
p.pos.Offset += i+1 - i0 + p.indent;
|
||||||
p.pos.Line++;
|
p.pos.Line++;
|
||||||
p.pos.Column = p.indent + 1;
|
p.pos.Column = p.indent + 1;
|
||||||
|
|
||||||
|
// next segment start
|
||||||
|
i0 = i+1;
|
||||||
|
|
||||||
|
case '&', '<', '>':
|
||||||
|
if p.mode & GenHTML != 0 {
|
||||||
|
// write segment ending in b
|
||||||
|
p.write0(data[i0 : i]);
|
||||||
|
|
||||||
|
// write HTML-escaped b
|
||||||
|
var esc []byte;
|
||||||
|
switch b {
|
||||||
|
case '&': esc = ampersand;
|
||||||
|
case '<': esc = lessthan;
|
||||||
|
case '>': esc = greaterthan;
|
||||||
|
}
|
||||||
|
p.write0(esc);
|
||||||
|
|
||||||
|
// update p.pos
|
||||||
|
p.pos.Offset += i+1 - i0;
|
||||||
|
p.pos.Column += i+1 - i0;
|
||||||
|
|
||||||
|
// next segment start
|
||||||
|
i0 = i+1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,33 +159,29 @@ func (p *printer) write(data []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO(gri) Don't go through write and make this more efficient.
|
|
||||||
func (p *printer) writeByte(b byte) {
|
|
||||||
p.write([]byte{b});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (p *printer) writeNewlines(n int) {
|
func (p *printer) writeNewlines(n int) {
|
||||||
if n > maxNewlines {
|
if n > 0 {
|
||||||
n = maxNewlines;
|
if n > maxNewlines {
|
||||||
|
n = maxNewlines;
|
||||||
|
}
|
||||||
|
p.write(newlines[0 : n]);
|
||||||
}
|
}
|
||||||
for ; n > 0; n-- {
|
|
||||||
p.writeByte('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (p *printer) writePos(pos token.Position) {
|
|
||||||
// use write0 so not to disturb the p.pos update by write
|
|
||||||
p.write0(strings.Bytes(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *printer) writeItem(pos token.Position, data []byte) {
|
func (p *printer) writeItem(pos token.Position, data []byte) {
|
||||||
p.pos = pos;
|
p.pos = pos;
|
||||||
if debug {
|
if debug {
|
||||||
p.writePos(pos);
|
// do not update p.pos - use write0
|
||||||
|
p.write0(strings.Bytes(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column)));
|
||||||
}
|
}
|
||||||
|
// TODO(gri) Enable once links are generated.
|
||||||
|
/*
|
||||||
|
if p.mode & GenHTML != 0 {
|
||||||
|
// do not HTML-escape or update p.pos - use write0
|
||||||
|
p.write0(strings.Bytes(fmt.Sprintf("<a id=%x></a>", pos.Offset)));
|
||||||
|
}
|
||||||
|
*/
|
||||||
p.write(data);
|
p.write(data);
|
||||||
p.prev = p.pos;
|
p.prev = p.pos;
|
||||||
}
|
}
|
||||||
@ -172,7 +213,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
|
|||||||
n := comment.Pos().Line - p.prev.Line;
|
n := comment.Pos().Line - p.prev.Line;
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
// comment on the same line as previous item; separate with tab
|
// comment on the same line as previous item; separate with tab
|
||||||
p.writeByte('\t');
|
p.write(tabs[0 : 1]);
|
||||||
} else {
|
} else {
|
||||||
// comment on a different line; separate with newlines
|
// comment on a different line; separate with newlines
|
||||||
p.writeNewlines(n);
|
p.writeNewlines(n);
|
||||||
@ -239,10 +280,16 @@ func (p *printer) intersperseComments(next token.Position) {
|
|||||||
|
|
||||||
|
|
||||||
func (p *printer) writeWhitespace() {
|
func (p *printer) writeWhitespace() {
|
||||||
|
var a [len(p.buffer)]byte;
|
||||||
for i := 0; i < p.buflen; i++ {
|
for i := 0; i < p.buflen; i++ {
|
||||||
p.writeByte(byte(p.buffer[i]));
|
a[i] = byte(p.buffer[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var b []byte = &a;
|
||||||
|
b = b[0 : p.buflen];
|
||||||
p.buflen = 0;
|
p.buflen = 0;
|
||||||
|
|
||||||
|
p.write(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -254,7 +301,7 @@ func (p *printer) writeWhitespace() {
|
|||||||
// Whitespace is accumulated until a non-whitespace token appears. Any
|
// Whitespace is accumulated until a non-whitespace token appears. Any
|
||||||
// comments that need to appear before that token are printed first,
|
// comments that need to appear before that token are printed first,
|
||||||
// taking into account the amount and structure of any pending white-
|
// taking into account the amount and structure of any pending white-
|
||||||
// space for best commemnt placement. Then, any leftover whitespace is
|
// space for best comment placement. Then, any leftover whitespace is
|
||||||
// printed, followed by the actual token.
|
// printed, followed by the actual token.
|
||||||
//
|
//
|
||||||
func (p *printer) print(args ...) {
|
func (p *printer) print(args ...) {
|
||||||
@ -930,8 +977,8 @@ func (p *printer) spec(spec ast.Spec) (comment *ast.CommentGroup, optSemi bool)
|
|||||||
if s.Name != nil {
|
if s.Name != nil {
|
||||||
p.expr(s.Name);
|
p.expr(s.Name);
|
||||||
}
|
}
|
||||||
// TODO fix for longer package names
|
p.print(tab);
|
||||||
p.print(tab, s.Path[0].Pos(), s.Path[0].Value);
|
p.expr(&ast.StringList{s.Path});
|
||||||
comment = s.Comment;
|
comment = s.Comment;
|
||||||
|
|
||||||
case *ast.ValueSpec:
|
case *ast.ValueSpec:
|
||||||
@ -1057,14 +1104,28 @@ func (p *printer) file(src *ast.File) {
|
|||||||
|
|
||||||
// Fprint "pretty-prints" an AST node to output and returns the number of
|
// Fprint "pretty-prints" an AST node to output and returns the number of
|
||||||
// bytes written, and an error, if any. The node type must be *ast.File,
|
// bytes written, and an error, if any. The node type must be *ast.File,
|
||||||
// or assignment-compatible to ast.Expr, ast.Decl, or ast.Stmt. Printing is
|
// or assignment-compatible to ast.Expr, ast.Decl, or ast.Stmt. Printing
|
||||||
// controlled by the mode parameter. For best results, the output should be
|
// is controlled by the mode and tabwidth parameters.
|
||||||
// a tabwriter.Writer.
|
|
||||||
//
|
//
|
||||||
func Fprint(output io.Writer, node interface{}, mode uint) (int, os.Error) {
|
func Fprint(output io.Writer, node interface{}, mode uint, tabwidth int) (int, os.Error) {
|
||||||
|
// setup tabwriter if needed and redirect output
|
||||||
|
var tw *tabwriter.Writer;
|
||||||
|
if mode & RawFormat == 0 {
|
||||||
|
padchar := byte('\t');
|
||||||
|
if mode & UseSpaces != 0 {
|
||||||
|
padchar = ' ';
|
||||||
|
}
|
||||||
|
var twmode uint;
|
||||||
|
if mode & GenHTML != 0 {
|
||||||
|
twmode = tabwriter.FilterHTML;
|
||||||
|
}
|
||||||
|
tw = tabwriter.NewWriter(output, tabwidth, 1, padchar, twmode);
|
||||||
|
output = tw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup printer and print node
|
||||||
var p printer;
|
var p printer;
|
||||||
p.init(output, mode);
|
p.init(output, mode);
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
case ast.Expr:
|
case ast.Expr:
|
||||||
@ -1085,5 +1146,10 @@ func Fprint(output io.Writer, node interface{}, mode uint) (int, os.Error) {
|
|||||||
}();
|
}();
|
||||||
err := <-p.errors; // wait for completion of goroutine
|
err := <-p.errors; // wait for completion of goroutine
|
||||||
|
|
||||||
|
// flush tabwriter, if any
|
||||||
|
if tw != nil {
|
||||||
|
tw.Flush(); // ignore errors
|
||||||
|
}
|
||||||
|
|
||||||
return p.written, err;
|
return p.written, err;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"go/printer";
|
"go/printer";
|
||||||
"os";
|
"os";
|
||||||
"path";
|
"path";
|
||||||
"tabwriter";
|
|
||||||
"testing";
|
"testing";
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,8 +20,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
dataDir = "testdata";
|
dataDir = "testdata";
|
||||||
tabwidth = 4;
|
tabwidth = 4;
|
||||||
padding = 1;
|
|
||||||
tabchar = '\t';
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -54,9 +51,9 @@ func check(t *testing.T, source, golden string, exports bool) {
|
|||||||
|
|
||||||
// format source
|
// format source
|
||||||
var buf bytes.Buffer;
|
var buf bytes.Buffer;
|
||||||
w := tabwriter.NewWriter(&buf, tabwidth, padding, tabchar, 0);
|
if _, err := Fprint(&buf, prog, 0, tabwidth); err != nil {
|
||||||
Fprint(w, prog, 0);
|
t.Error(err);
|
||||||
w.Flush();
|
}
|
||||||
res := buf.Data();
|
res := buf.Data();
|
||||||
|
|
||||||
// update golden files if necessary
|
// update golden files if necessary
|
||||||
|
Loading…
Reference in New Issue
Block a user