From d01ca2effcd81d084822fc6360b5f11213e9fffe Mon Sep 17 00:00:00 2001 From: "David R. Jenni" Date: Tue, 26 Sep 2017 08:45:55 +0200 Subject: [PATCH] cmd/fillstruct: add option to select by line number. Fixes #3. --- cmd/fillstruct/Readme.md | 1 + cmd/fillstruct/main.go | 59 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/cmd/fillstruct/Readme.md b/cmd/fillstruct/Readme.md index 464fb14..bdc7f52 100644 --- a/cmd/fillstruct/Readme.md +++ b/cmd/fillstruct/Readme.md @@ -56,3 +56,4 @@ Flags: -file: filename -modified: read an archive of modified files from stdin -offset: byte offset of the struct literal + -line: line number of the struct literal, can be used instead of -offset diff --git a/cmd/fillstruct/main.go b/cmd/fillstruct/main.go index bdc38b3..1c8e735 100644 --- a/cmd/fillstruct/main.go +++ b/cmd/fillstruct/main.go @@ -51,6 +51,8 @@ // // -offset: byte offset of the struct literal // +// -line: line number of the struct literal, can be used instead of -offset +// package main import ( @@ -302,10 +304,11 @@ func main() { filename = flag.String("file", "", "filename") modified = flag.Bool("modified", false, "read an archive of modified files from stdin") offset = flag.Int("offset", 0, "byte offset of the struct literal") + line = flag.Int("line", 0, "line number of the struct literal, can be used instead of -offset") ) flag.Parse() - if *offset == 0 || *filename == "" { + if (*offset == 0 && *line == 0) || *filename == "" { flag.PrintDefaults() os.Exit(1) } @@ -321,6 +324,18 @@ func main() { } pkg := lprog.InitialPackages()[0] + // --- selection by line + + if *line > 0 { + err = byLine(lprog, *filename, pkg, *line) + if err != nil { + log.Fatal(err) + } + return + } + + // --- selection by offset + f, pos, err := findPos(lprog, path, *offset) if err != nil { log.Fatal(err) @@ -390,6 +405,48 @@ func findPos(lprog *loader.Program, filename string, off int) (*ast.File, token. return nil, 0, fmt.Errorf("could not find file %q", filename) } +func byLine(lprog *loader.Program, filename string, pkg *loader.PackageInfo, line int) (err error) { + var f *ast.File + for _, af := range lprog.InitialPackages()[0].Files { + if file := lprog.Fset.File(af.Pos()); file.Name() == filename { + f = af + } + } + if f == nil { + return fmt.Errorf("could not find file %q", filename) + } + + ast.Inspect(f, func(n ast.Node) bool { + lit, ok := n.(*ast.CompositeLit) + if !ok { + return true + } + startLine := lprog.Fset.Position(lit.Pos()).Line + endLine := lprog.Fset.Position(lit.End()).Line + if !(startLine <= line && line <= endLine) { + return true + } + + name, _ := pkg.Types[lit].Type.(*types.Named) + typ, ok := pkg.Types[lit].Type.Underlying().(*types.Struct) + if !ok { + err = errors.New("no struct literal found at selection") + return false + } + + startOff := lprog.Fset.Position(lit.Pos()).Offset + endOff := lprog.Fset.Position(lit.End()).Offset + + newlit, lines := zeroValue(pkg.Pkg, lit, typ, name) + if err = print(newlit, lines, startOff, endOff); err != nil { + return false + } + + return false + }) + return err +} + func findCompositeLit(f *ast.File, info types.Info, pos token.Pos) (*ast.CompositeLit, *types.Struct, *types.Named, error) { path, _ := astutil.PathEnclosingInterval(f, pos, pos) for _, n := range path {