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