github.com/tiagovtristao/plz@v13.4.0+incompatible/tools/build_langserver/langserver_main.go (about) 1 package main 2 3 import ( 4 "context" 5 "github.com/thought-machine/please/src/cli" 6 "github.com/thought-machine/please/tools/build_langserver/langserver" 7 "net" 8 "os" 9 10 "github.com/sourcegraph/jsonrpc2" 11 "gopkg.in/op/go-logging.v1" 12 ) 13 14 // TODO(bnmetrics): also think about how we can implement this with .build_defs as well 15 // TODO(bnmetrics): Make the Usage part better 16 var log = logging.MustGetLogger("build_langserver") 17 18 var opts = struct { 19 Usage string 20 Verbosity cli.Verbosity `short:"v" long:"verbosity" default:"notice" description:"Verbosity of output (higher number = more output)"` 21 LogFile cli.Filepath `long:"log_file" description:"File to echo full logging output to"` 22 23 Mode string `short:"m" long:"mode" default:"stdio" choice:"stdio" choice:"tcp" description:"Mode of the language server communication"` 24 Host string `short:"h" long:"host" default:"127.0.0.1" description:"TCP host to communicate with"` 25 Port string `short:"p" long:"port" default:"4040" description:"TCP port to communicate with"` 26 }{ 27 Usage: ` 28 build_langserver is a binary shipped with Please that you can use as a language server for build files. 29 30 It speaks language server protocol from vscode, you can plugin this binary in your IDE to start the language server. 31 Currently, it supports autocompletion, goto definition for build_defs, and signature help 32 `, 33 } 34 35 func main() { 36 cli.ParseFlagsOrDie("build_langserver", &opts) 37 cli.InitLogging(opts.Verbosity) 38 if opts.LogFile != "" { 39 cli.InitFileLogging(string(opts.LogFile), opts.Verbosity) 40 } 41 42 handler := langserver.NewHandler() 43 44 if err := serve(handler); err != nil { 45 log.Fatalf("fail to start server: %s", err) 46 os.Exit(1) 47 } 48 } 49 50 func serve(handler jsonrpc2.Handler) error { 51 if opts.Mode == "tcp" { 52 lis, err := net.Listen("tcp", opts.Host+":"+opts.Port) 53 if err != nil { 54 return err 55 } 56 defer lis.Close() 57 58 log.Notice("build_langserver: listening on", opts.Host+":"+opts.Port) 59 for { 60 conn, err := lis.Accept() 61 if err != nil { 62 return err 63 } 64 jsonrpc2.NewConn(context.Background(), jsonrpc2.NewBufferedStream(conn, jsonrpc2.VSCodeObjectCodec{}), handler) 65 } 66 } else { 67 log.Notice("build_langserver: reading on stdin, writing on stdout") 68 69 <-jsonrpc2.NewConn(context.Background(), jsonrpc2.NewBufferedStream(stdrwc{}, jsonrpc2.VSCodeObjectCodec{}), 70 handler).DisconnectNotify() 71 72 log.Notice("connection closed") 73 } 74 75 return nil 76 } 77 78 type stdrwc struct{} 79 80 func (stdrwc) Read(p []byte) (int, error) { 81 return os.Stdin.Read(p) 82 } 83 84 func (stdrwc) Write(p []byte) (int, error) { 85 return os.Stdout.Write(p) 86 } 87 88 func (stdrwc) Close() error { 89 if err := os.Stdin.Close(); err != nil { 90 return err 91 } 92 return os.Stdout.Close() 93 }