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