This repository was archived by the owner on Mar 27, 2019. It is now read-only.
Repository navigation
Expand file tree
/
Copy pathserver.go
More file actions
122 lines (106 loc) · 3.08 KB
/
Copy pathserver.go
File metadata and controls
122 lines (106 loc) · 3.08 KB
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package python
import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"os/exec"
"runtime"
"strings"
"sync"
"time"
"sourcegraph.com/sourcegraph/sourcegraph/pkg/cmdutil"
"sourcegraph.com/sourcegraph/sourcegraph/pkg/jsonrpc2"
"sourcegraph.com/sourcegraph/sourcegraph/pkg/lsp"
)
// cmdOutput is a helper around c.Output which logs the command, how long it
// took to run, and a nice error in the event of failure.
//
// The specified env is set as cmd.Env (because we do this at ALL callsites
// today anyway).
func cmdOutput(env []string, c *exec.Cmd) ([]byte, error) {
c.Env = env
start := time.Now()
stdout, err := cmdutil.Output(c)
log.Printf("TIME: %v '%s'\n", time.Since(start), strings.Join(c.Args, " "))
if err != nil {
log.Println(err)
return nil, err
}
return stdout, nil
}
// Handler represents an LSP handler for one user.
type Handler struct {
mu sync.Mutex
init *lsp.InitializeParams // set by "initialize" req
}
// reset clears all internal state in h.
func (h *Handler) reset(init *lsp.InitializeParams) {
h.init = init
}
func (h *Handler) Handle(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request) (_ interface{}, err error) {
// Coarse lock (for now) to protect h's internal state.
h.mu.Lock()
defer h.mu.Unlock()
// Prevent any uncaught panics from taking the entire server down.
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("unexpected panic: %v", r)
// Same as net/http
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
log.Printf("panic serving %v: %v\n%s", req.Method, r, buf)
return
}
}()
if req.Method != "initialize" && h.init == nil {
return nil, errors.New("server must be initialized")
}
switch req.Method {
case "initialize":
var params lsp.InitializeParams
if err = json.Unmarshal(*req.Params, ¶ms); err != nil {
return
}
if params.RootPath == "" {
params.RootPath = "/"
}
if !strings.HasSuffix(params.RootPath, "/") {
params.RootPath = params.RootPath + "/"
}
h.reset(¶ms)
return lsp.InitializeResult{
Capabilities: lsp.ServerCapabilities{
HoverProvider: true,
DefinitionProvider: true,
ReferencesProvider: true,
// WorkspaceSymbolProvider: true,
},
}, nil
case "shutdown":
// Result is undefined, per
// https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#shutdown-request.
return nil, nil
case "textDocument/hover":
var params lsp.TextDocumentPositionParams
if err = json.Unmarshal(*req.Params, ¶ms); err != nil {
return
}
return h.handleHover(req, params)
case "textDocument/definition":
var params lsp.TextDocumentPositionParams
if err = json.Unmarshal(*req.Params, ¶ms); err != nil {
return
}
return h.handleDefinition(req, params)
case "textDocument/references":
var params lsp.ReferenceParams
if err = json.Unmarshal(*req.Params, ¶ms); err != nil {
break
}
return h.handleReferences(req, params)
}
return nil, &jsonrpc2.Error{Code: jsonrpc2.CodeMethodNotFound, Message: fmt.Sprintf("method not supported: %s", req.Method)}
}