github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/lsp/cmd/imports.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package cmd 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 "io/ioutil" 12 13 "github.com/powerman/golang-tools/internal/lsp/diff" 14 "github.com/powerman/golang-tools/internal/lsp/protocol" 15 "github.com/powerman/golang-tools/internal/lsp/source" 16 "github.com/powerman/golang-tools/internal/span" 17 "github.com/powerman/golang-tools/internal/tool" 18 errors "golang.org/x/xerrors" 19 ) 20 21 // imports implements the import verb for gopls. 22 type imports struct { 23 Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` 24 Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` 25 26 app *Application 27 } 28 29 func (t *imports) Name() string { return "imports" } 30 func (t *imports) Parent() string { return t.app.Name() } 31 func (t *imports) Usage() string { return "[imports-flags] <filename>" } 32 func (t *imports) ShortHelp() string { return "updates import statements" } 33 func (t *imports) DetailedHelp(f *flag.FlagSet) { 34 fmt.Fprintf(f.Output(), ` 35 Example: update imports statements in a file: 36 37 $ gopls imports -w internal/lsp/cmd/check.go 38 39 imports-flags: 40 `) 41 printFlagDefaults(f) 42 } 43 44 // Run performs diagnostic checks on the file specified and either; 45 // - if -w is specified, updates the file in place; 46 // - if -d is specified, prints out unified diffs of the changes; or 47 // - otherwise, prints the new versions to stdout. 48 func (t *imports) Run(ctx context.Context, args ...string) error { 49 if len(args) != 1 { 50 return tool.CommandLineErrorf("imports expects 1 argument") 51 } 52 conn, err := t.app.connect(ctx) 53 if err != nil { 54 return err 55 } 56 defer conn.terminate(ctx) 57 58 from := span.Parse(args[0]) 59 uri := from.URI() 60 file := conn.AddFile(ctx, uri) 61 if file.err != nil { 62 return file.err 63 } 64 actions, err := conn.CodeAction(ctx, &protocol.CodeActionParams{ 65 TextDocument: protocol.TextDocumentIdentifier{ 66 URI: protocol.URIFromSpanURI(uri), 67 }, 68 }) 69 if err != nil { 70 return errors.Errorf("%v: %v", from, err) 71 } 72 var edits []protocol.TextEdit 73 for _, a := range actions { 74 if a.Title != "Organize Imports" { 75 continue 76 } 77 for _, c := range a.Edit.DocumentChanges { 78 if fileURI(c.TextDocument.URI) == uri { 79 edits = append(edits, c.Edits...) 80 } 81 } 82 } 83 sedits, err := source.FromProtocolEdits(file.mapper, edits) 84 if err != nil { 85 return errors.Errorf("%v: %v", edits, err) 86 } 87 newContent := diff.ApplyEdits(string(file.mapper.Content), sedits) 88 89 filename := file.uri.Filename() 90 switch { 91 case t.Write: 92 if len(edits) > 0 { 93 ioutil.WriteFile(filename, []byte(newContent), 0644) 94 } 95 case t.Diff: 96 diffs := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits) 97 fmt.Print(diffs) 98 default: 99 fmt.Print(string(newContent)) 100 } 101 return nil 102 }