12
func indent(s, with string) (r string) {
14
for i := 0; i != len(s); i++ {
17
case eol && c == '\n' || c == '\r':
18
case c == '\n' || c == '\r':
22
s = s[:i] + with + s[i:]
29
func printLine(filename string, line int) (string, error) {
30
fset := token.NewFileSet()
31
file, err := os.Open(filename)
35
fnode, err := parser.ParseFile(fset, filename, file, parser.ParseComments)
39
config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}
40
lp := &linePrinter{fset: fset, fnode: fnode, line: line, config: config}
42
result := lp.output.Bytes()
43
// Comments leave \n at the end.
45
for n > 0 && result[n-1] == '\n' {
48
return string(result[:n]), nil
51
type linePrinter struct {
52
config *printer.Config
60
func (lp *linePrinter) emit() bool {
63
lp.printWithComments(lp.stmt)
70
func (lp *linePrinter) printWithComments(n ast.Node) {
71
nfirst := lp.fset.Position(n.Pos()).Line
72
nlast := lp.fset.Position(n.End()).Line
73
for _, g := range lp.fnode.Comments {
74
cfirst := lp.fset.Position(g.Pos()).Line
75
clast := lp.fset.Position(g.End()).Line
76
if clast == nfirst-1 && lp.fset.Position(n.Pos()).Column == lp.fset.Position(g.Pos()).Column {
77
for _, c := range g.List {
78
lp.output.WriteString(c.Text)
79
lp.output.WriteByte('\n')
82
if cfirst >= nfirst && cfirst <= nlast && n.End() <= g.List[0].Slash {
83
// The printer will not include the comment if it starts past
84
// the node itself. Trick it into printing by overlapping the
85
// slash with the end of the statement.
86
g.List[0].Slash = n.End() - 1
89
node := &printer.CommentedNode{n, lp.fnode.Comments}
90
lp.config.Fprint(&lp.output, lp.fset, node)
93
func (lp *linePrinter) Visit(n ast.Node) (w ast.Visitor) {
95
if lp.output.Len() == 0 {
100
first := lp.fset.Position(n.Pos()).Line
101
last := lp.fset.Position(n.End()).Line
102
if first <= lp.line && last >= lp.line {
103
// Print the innermost statement containing the line.
104
if stmt, ok := n.(ast.Stmt); ok {
105
if _, ok := n.(*ast.BlockStmt); !ok {
109
if first == lp.line && lp.emit() {
117
func (lp *linePrinter) trim(n ast.Node) bool {
118
stmt, ok := n.(ast.Stmt)
122
line := lp.fset.Position(n.Pos()).Line
126
switch stmt := stmt.(type) {
128
stmt.Body = lp.trimBlock(stmt.Body)
129
case *ast.SwitchStmt:
130
stmt.Body = lp.trimBlock(stmt.Body)
131
case *ast.TypeSwitchStmt:
132
stmt.Body = lp.trimBlock(stmt.Body)
133
case *ast.CaseClause:
134
stmt.Body = lp.trimList(stmt.Body)
135
case *ast.CommClause:
136
stmt.Body = lp.trimList(stmt.Body)
138
stmt.List = lp.trimList(stmt.List)
143
func (lp *linePrinter) trimBlock(stmt *ast.BlockStmt) *ast.BlockStmt {
145
return lp.emptyBlock(stmt)
147
stmt.Rbrace = stmt.Lbrace
151
func (lp *linePrinter) trimList(stmts []ast.Stmt) []ast.Stmt {
152
for i := 0; i != len(stmts); i++ {
153
if !lp.trim(stmts[i]) {
154
stmts[i] = lp.emptyStmt(stmts[i])
161
func (lp *linePrinter) emptyStmt(n ast.Node) *ast.ExprStmt {
162
return &ast.ExprStmt{&ast.Ellipsis{n.Pos(), nil}}
165
func (lp *linePrinter) emptyBlock(n ast.Node) *ast.BlockStmt {
167
return &ast.BlockStmt{p, []ast.Stmt{lp.emptyStmt(n)}, p}