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  }