Commit dc7355a9 authored by Robert Griesemer's avatar Robert Griesemer

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
parent e89441ba
...@@ -31,12 +31,17 @@ var ( ...@@ -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() { ...@@ -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 *tabindent {
printerMode |= printer.TabIndent
}
if *usespaces { if *usespaces {
mode |= printer.UseSpaces printerMode |= printer.UseSpaces
} }
return mode;
} }
...@@ -85,7 +91,7 @@ func processFile(f *os.File) os.Error { ...@@ -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 { ...@@ -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() { ...@@ -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) { ...@@ -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) { ...@@ -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;
} }
......
This diff is collapsed.
...@@ -64,12 +64,12 @@ func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected s ...@@ -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();
...@@ -97,193 +97,193 @@ func check(t *testing.T, testname string, tabwidth, padding int, padchar byte, f ...@@ -97,193 +97,193 @@ 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;
} }
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&lt;o\t<b>bar</b>\t\n", "f) f&lt;o\t<b>bar</b>\t\n",
"f) f&lt;o..<b>bar</b>.....\n", "f) f&lt;o..<b>bar</b>.....\n",
}, },
entry{ entry{
"7g", "7g",
8, 1, '.', FilterHTML, 8, 0, 1, '.', FilterHTML,
"g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp", "g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
"g) f&lt;o..<b>bar</b>..... non-terminated entity &amp", "g) f&lt;o..<b>bar</b>..... non-terminated entity &amp",
}, },
entry{ entry{
"7g debug", "7g debug",
8, 1, '.', FilterHTML | Debug, 8, 0, 1, '.', FilterHTML | Debug,
"g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp", "g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
"g) f&lt;o..|<b>bar</b>.....| non-terminated entity &amp", "g) f&lt;o..|<b>bar</b>.....| non-terminated entity &amp",
}, },
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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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)
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment