github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/internal/lsp/cmd/format.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/jhump/golang-x-tools/internal/lsp/diff" 14 "github.com/jhump/golang-x-tools/internal/lsp/protocol" 15 "github.com/jhump/golang-x-tools/internal/lsp/source" 16 "github.com/jhump/golang-x-tools/internal/span" 17 errors "golang.org/x/xerrors" 18 ) 19 20 // format implements the format verb for gopls. 21 type format struct { 22 Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` 23 Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` 24 List bool `flag:"l,list" help:"list files whose formatting differs from gofmt's"` 25 26 app *Application 27 } 28 29 func (c *format) Name() string { return "format" } 30 func (c *format) Parent() string { return c.app.Name() } 31 func (c *format) Usage() string { return "[format-flags] <filerange>" } 32 func (c *format) ShortHelp() string { return "format the code according to the go standard" } 33 func (c *format) DetailedHelp(f *flag.FlagSet) { 34 fmt.Fprint(f.Output(), ` 35 The arguments supplied may be simple file names, or ranges within files. 36 37 Example: reformat this file: 38 39 $ gopls format -w internal/lsp/cmd/check.go 40 41 format-flags: 42 `) 43 printFlagDefaults(f) 44 } 45 46 // Run performs the check on the files specified by args and prints the 47 // results to stdout. 48 func (c *format) Run(ctx context.Context, args ...string) error { 49 if len(args) == 0 { 50 // no files, so no results 51 return nil 52 } 53 // now we ready to kick things off 54 conn, err := c.app.connect(ctx) 55 if err != nil { 56 return err 57 } 58 defer conn.terminate(ctx) 59 for _, arg := range args { 60 spn := span.Parse(arg) 61 file := conn.AddFile(ctx, spn.URI()) 62 if file.err != nil { 63 return file.err 64 } 65 filename := spn.URI().Filename() 66 loc, err := file.mapper.Location(spn) 67 if err != nil { 68 return err 69 } 70 if loc.Range.Start != loc.Range.End { 71 return errors.Errorf("only full file formatting supported") 72 } 73 p := protocol.DocumentFormattingParams{ 74 TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, 75 } 76 edits, err := conn.Formatting(ctx, &p) 77 if err != nil { 78 return errors.Errorf("%v: %v", spn, err) 79 } 80 sedits, err := source.FromProtocolEdits(file.mapper, edits) 81 if err != nil { 82 return errors.Errorf("%v: %v", spn, err) 83 } 84 formatted := diff.ApplyEdits(string(file.mapper.Content), sedits) 85 printIt := true 86 if c.List { 87 printIt = false 88 if len(edits) > 0 { 89 fmt.Println(filename) 90 } 91 } 92 if c.Write { 93 printIt = false 94 if len(edits) > 0 { 95 ioutil.WriteFile(filename, []byte(formatted), 0644) 96 } 97 } 98 if c.Diff { 99 printIt = false 100 u := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits) 101 fmt.Print(u) 102 } 103 if printIt { 104 fmt.Print(formatted) 105 } 106 } 107 return nil 108 }