summaryrefslogtreecommitdiff
path: root/src/cmd/gofmt/gofmt.go
diff options
context:
space:
mode:
authorSebastien Binet <seb.binet@gmail.com>2015-03-04 14:20:32 +0100
committerRobert Griesemer <gri@golang.org>2015-04-01 17:35:26 +0000
commit9a3ee2d217ef573426b57da1e4309900db140e76 (patch)
tree74979144af3736720725cf7e17537731c8e5335a /src/cmd/gofmt/gofmt.go
parentb09925b31d3012345b1926e6f8133551fa050fe2 (diff)
downloadgo-git-9a3ee2d217ef573426b57da1e4309900db140e76.tar.gz
cmd/gofmt, go/format: refactor common pieces into internal/format
cmd/gofmt and go/format had 3 functions (parse, format and isSpace) that had to be kept in-sync. This CL extracts these 3 functions and refactors them into a new internal/format package. This CL is just code reorganization with no behavior nor semantic change. Change-Id: I593f24e9d3cadbbd9559a67e3b1d2ff190b4fd90 Reviewed-on: https://go-review.googlesource.com/6760 Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/cmd/gofmt/gofmt.go')
-rw-r--r--src/cmd/gofmt/gofmt.go156
1 files changed, 3 insertions, 153 deletions
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 81da21ff10..b2805ac05f 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -13,6 +13,7 @@ import (
"go/printer"
"go/scanner"
"go/token"
+ "internal/format"
"io"
"io/ioutil"
"os"
@@ -87,7 +88,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
return err
}
- file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
+ file, sourceAdj, indentAdj, err := format.Parse(fileSet, filename, src, stdin)
if err != nil {
return err
}
@@ -106,7 +107,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
simplify(file)
}
- res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
+ res, err := format.Format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
if err != nil {
return err
}
@@ -234,154 +235,3 @@ func diff(b1, b2 []byte) (data []byte, err error) {
return
}
-
-// ----------------------------------------------------------------------------
-// Support functions
-//
-// The functions parse, format, and isSpace below are identical to the
-// respective functions in src/go/format/format.go - keep them in sync!
-//
-// TODO(gri) Factor out this functionality, eventually.
-
-// parse parses src, which was read from the named file,
-// as a Go source file, declaration, or statement list.
-func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
- file *ast.File,
- sourceAdj func(src []byte, indent int) []byte,
- indentAdj int,
- err error,
-) {
- // Try as whole source file.
- file, err = parser.ParseFile(fset, filename, src, parserMode)
- // If there's no error, return. If the error is that the source file didn't begin with a
- // package line and source fragments are ok, fall through to
- // try as a source fragment. Stop and return on any other error.
- if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
- return
- }
-
- // If this is a declaration list, make it a source file
- // by inserting a package clause.
- // Insert using a ;, not a newline, so that the line numbers
- // in psrc match the ones in src.
- psrc := append([]byte("package p;"), src...)
- file, err = parser.ParseFile(fset, filename, psrc, parserMode)
- if err == nil {
- sourceAdj = func(src []byte, indent int) []byte {
- // Remove the package clause.
- // Gofmt has turned the ; into a \n.
- src = src[indent+len("package p\n"):]
- return bytes.TrimSpace(src)
- }
- return
- }
- // If the error is that the source file didn't begin with a
- // declaration, fall through to try as a statement list.
- // Stop and return on any other error.
- if !strings.Contains(err.Error(), "expected declaration") {
- return
- }
-
- // If this is a statement list, make it a source file
- // by inserting a package clause and turning the list
- // into a function body. This handles expressions too.
- // Insert using a ;, not a newline, so that the line numbers
- // in fsrc match the ones in src.
- fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
- file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
- if err == nil {
- sourceAdj = func(src []byte, indent int) []byte {
- // Cap adjusted indent to zero.
- if indent < 0 {
- indent = 0
- }
- // Remove the wrapping.
- // Gofmt has turned the ; into a \n\n.
- // There will be two non-blank lines with indent, hence 2*indent.
- src = src[2*indent+len("package p\n\nfunc _() {"):]
- src = src[:len(src)-(indent+len("\n}\n"))]
- return bytes.TrimSpace(src)
- }
- // Gofmt has also indented the function body one level.
- // Adjust that with indentAdj.
- indentAdj = -1
- }
-
- // Succeeded, or out of options.
- return
-}
-
-// format formats the given package file originally obtained from src
-// and adjusts the result based on the original source via sourceAdj
-// and indentAdj.
-func format(
- fset *token.FileSet,
- file *ast.File,
- sourceAdj func(src []byte, indent int) []byte,
- indentAdj int,
- src []byte,
- cfg printer.Config,
-) ([]byte, error) {
- if sourceAdj == nil {
- // Complete source file.
- var buf bytes.Buffer
- err := cfg.Fprint(&buf, fset, file)
- if err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
- }
-
- // Partial source file.
- // Determine and prepend leading space.
- i, j := 0, 0
- for j < len(src) && isSpace(src[j]) {
- if src[j] == '\n' {
- i = j + 1 // byte offset of last line in leading space
- }
- j++
- }
- var res []byte
- res = append(res, src[:i]...)
-
- // Determine and prepend indentation of first code line.
- // Spaces are ignored unless there are no tabs,
- // in which case spaces count as one tab.
- indent := 0
- hasSpace := false
- for _, b := range src[i:j] {
- switch b {
- case ' ':
- hasSpace = true
- case '\t':
- indent++
- }
- }
- if indent == 0 && hasSpace {
- indent = 1
- }
- for i := 0; i < indent; i++ {
- res = append(res, '\t')
- }
-
- // Format the source.
- // Write it without any leading and trailing space.
- cfg.Indent = indent + indentAdj
- var buf bytes.Buffer
- err := cfg.Fprint(&buf, fset, file)
- if err != nil {
- return nil, err
- }
- res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
-
- // Determine and append trailing space.
- i = len(src)
- for i > 0 && isSpace(src[i-1]) {
- i--
- }
- return append(res, src[i:]...), nil
-}
-
-func isSpace(b byte) bool {
- return b == ' ' || b == '\t' || b == '\n' || b == '\r'
-}