Add dumbindent.Options (tabs vs spaces)
diff --git a/cmd/dumbindent/main.go b/cmd/dumbindent/main.go
index b171d5c..3aa985f 100644
--- a/cmd/dumbindent/main.go
+++ b/cmd/dumbindent/main.go
@@ -42,8 +42,6 @@
// user 0m0.005s
// sys 0m0.005s
// ----
-//
-// There are no configuration options (e.g. tabs versus spaces).
package main
import (
@@ -64,6 +62,9 @@
var (
lFlag = flag.Bool("l", false, "list files whose formatting differs from dumbindent's")
wFlag = flag.Bool("w", false, "write result to (source) file instead of stdout")
+
+ spacesFlag = flag.Int("spaces", 2, "the number of spaces per indent")
+ tabsFlag = flag.Bool("tabs", false, "indent with a tab instead of spaces")
)
func usage() {
@@ -142,7 +143,10 @@
return err
}
- dst := dumbindent.FormatBytes(nil, src)
+ dst := dumbindent.FormatBytes(nil, src, &dumbindent.Options{
+ Spaces: *spacesFlag,
+ Tabs: *tabsFlag,
+ })
if r != nil {
if _, err := os.Stdout.Write(dst); err != nil {
diff --git a/internal/cgen/cgen.go b/internal/cgen/cgen.go
index b06f000..c5204ba 100644
--- a/internal/cgen/cgen.go
+++ b/internal/cgen/cgen.go
@@ -181,7 +181,7 @@
return unformatted, nil
}
- return dumbindent.FormatBytes(nil, unformatted), nil
+ return dumbindent.FormatBytes(nil, unformatted, nil), nil
})
}
diff --git a/lib/dumbindent/dumbindent.go b/lib/dumbindent/dumbindent.go
index 5b3fd36..647dbb2 100644
--- a/lib/dumbindent/dumbindent.go
+++ b/lib/dumbindent/dumbindent.go
@@ -25,8 +25,6 @@
//
// See `cmd/dumbindent/main.go` in this repository for an example where
// `dumbindent` was 80 times faster than `clang-format`.
-//
-// There are no configuration options (e.g. tabs versus spaces).
package dumbindent
import (
@@ -37,8 +35,10 @@
var (
backTick = []byte("`")
externC = []byte("extern \"C\"")
- spaces = []byte(" ")
starSlash = []byte("*/")
+
+ spaces = []byte(" ")
+ tabs = []byte("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")
)
// hangingBytes is a look-up table for updating the hanging variable.
@@ -47,13 +47,28 @@
'\\': true,
}
+// Options are formatting options.
+type Options struct {
+ // Spaces, if positive, is the number of spaces per indentation level. A
+ // non-positive value means to use the default: 2 spaces per indent.
+ //
+ // This field is ignored when Tabs is true.
+ Spaces int
+
+ // Tabs is whether to indent with tabs instead of spaces. If true, it's one
+ // '\t' tab character per indent and the Spaces field is ignored.
+ Tabs bool
+}
+
// FormatBytes formats the C (or C-like) program in src, appending the result
// to dst, and returns that longer slice.
//
// It is valid to pass a dst slice (such as nil) whose unused capacity
// (cap(dst) - len(dst)) is too short to hold the formatted program. In this
// case, a new slice will be allocated and returned.
-func FormatBytes(dst []byte, src []byte) []byte {
+//
+// Passing a nil opts means to use the default options.
+func FormatBytes(dst []byte, src []byte, opts *Options) []byte {
src = trimLeadingWhiteSpaceAndNewLines(src)
if len(src) == 0 {
return dst
@@ -61,6 +76,17 @@
dst = make([]byte, 0, len(src)+(len(src)/2))
}
+ indentBytes := spaces
+ indentCount := 2
+ if opts != nil {
+ if opts.Tabs {
+ indentBytes = tabs
+ indentCount = 1
+ } else if opts.Spaces > 0 {
+ indentCount = opts.Spaces
+ }
+ }
+
nBraces := 0 // The number of unbalanced '{'s.
nParens := 0 // The number of unbalanced '('s.
openBrace := false // Whether the previous non-blank line ends with '{'.
@@ -118,17 +144,17 @@
// "clang-format -style=Chromium" indentation style.
indent := 0
if nBraces > 0 {
- indent += 2 * nBraces
+ indent += indentCount * nBraces
}
if (nParens > 0) || hanging {
- indent += 4
+ indent += indentCount * 2
}
for indent > 0 {
n := indent
- if n > len(spaces) {
- n = len(spaces)
+ if n > len(indentBytes) {
+ n = len(indentBytes)
}
- dst = append(dst, spaces[:n]...)
+ dst = append(dst, indentBytes[:n]...)
indent -= n
}
diff --git a/lib/dumbindent/dumbindent_test.go b/lib/dumbindent/dumbindent_test.go
index b54a64c..df75128 100644
--- a/lib/dumbindent/dumbindent_test.go
+++ b/lib/dumbindent/dumbindent_test.go
@@ -78,12 +78,21 @@
}}
for i, tc := range testCases {
- if got := string(FormatBytes(nil, []byte(tc.src))); got != tc.want {
+ if got := string(FormatBytes(nil, []byte(tc.src), nil)); got != tc.want {
tt.Fatalf("i=%d, src=%q:\ngot %q\nwant %q", i, tc.src, got, tc.want)
}
}
}
+func TestTabs(tt *testing.T) {
+ const src = "a {\nb\n}\n"
+ got := string(FormatBytes(nil, []byte(src), &Options{Tabs: true}))
+ want := "a {\n\tb\n}\n"
+ if got != want {
+ tt.Fatalf("\ngot %q\nwant %q", got, want)
+ }
+}
+
func ExampleFormatBytes() {
const src = `
// Blah blah blah.
@@ -95,7 +104,7 @@
}
`
- os.Stdout.Write(FormatBytes(nil, []byte(src)))
+ os.Stdout.Write(FormatBytes(nil, []byte(src), nil))
// Output:
// // Blah blah blah.