Source file
src/cmd/gofmt/internal.go
1
2
3
4
5
6
7
8
9
10 package main
11
12 import (
13 "bytes"
14 "go/ast"
15 "go/parser"
16 "go/printer"
17 "go/token"
18 "strings"
19 )
20
21
22
23 func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
24 file *ast.File,
25 sourceAdj func(src []byte, indent int) []byte,
26 indentAdj int,
27 err error,
28 ) {
29
30 file, err = parser.ParseFile(fset, filename, src, parserMode)
31
32
33
34 if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
35 return
36 }
37
38
39
40
41
42 psrc := append([]byte("package p;"), src...)
43 file, err = parser.ParseFile(fset, filename, psrc, parserMode)
44 if err == nil {
45 sourceAdj = func(src []byte, indent int) []byte {
46
47
48 src = src[indent+len("package p\n"):]
49 return bytes.TrimSpace(src)
50 }
51 return
52 }
53
54
55
56 if !strings.Contains(err.Error(), "expected declaration") {
57 return
58 }
59
60
61
62
63
64
65
66 fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '\n', '}')
67 file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
68 if err == nil {
69 sourceAdj = func(src []byte, indent int) []byte {
70
71 if indent < 0 {
72 indent = 0
73 }
74
75
76
77 src = src[2*indent+len("package p\n\nfunc _() {"):]
78
79 src = src[:len(src)-len("}\n")]
80 return bytes.TrimSpace(src)
81 }
82
83
84 indentAdj = -1
85 }
86
87
88 return
89 }
90
91
92
93
94 func format(
95 fset *token.FileSet,
96 file *ast.File,
97 sourceAdj func(src []byte, indent int) []byte,
98 indentAdj int,
99 src []byte,
100 cfg printer.Config,
101 ) ([]byte, error) {
102 if sourceAdj == nil {
103
104 var buf bytes.Buffer
105 err := cfg.Fprint(&buf, fset, file)
106 if err != nil {
107 return nil, err
108 }
109 return buf.Bytes(), nil
110 }
111
112
113
114 i, j := 0, 0
115 for j < len(src) && isSpace(src[j]) {
116 if src[j] == '\n' {
117 i = j + 1
118 }
119 j++
120 }
121 var res []byte
122 res = append(res, src[:i]...)
123
124
125
126
127 indent := 0
128 hasSpace := false
129 for _, b := range src[i:j] {
130 switch b {
131 case ' ':
132 hasSpace = true
133 case '\t':
134 indent++
135 }
136 }
137 if indent == 0 && hasSpace {
138 indent = 1
139 }
140 for i := 0; i < indent; i++ {
141 res = append(res, '\t')
142 }
143
144
145
146 cfg.Indent = indent + indentAdj
147 var buf bytes.Buffer
148 err := cfg.Fprint(&buf, fset, file)
149 if err != nil {
150 return nil, err
151 }
152 out := sourceAdj(buf.Bytes(), cfg.Indent)
153
154
155
156
157 if len(out) == 0 {
158 return src, nil
159 }
160
161
162 res = append(res, out...)
163
164
165 i = len(src)
166 for i > 0 && isSpace(src[i-1]) {
167 i--
168 }
169 return append(res, src[i:]...), nil
170 }
171
172
173
174 func isSpace(b byte) bool {
175 return b == ' ' || b == '\t' || b == '\n' || b == '\r'
176 }
177
View as plain text