-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
166 lines (138 loc) · 6.58 KB
/
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
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package main
import (
"bufio"
"encoding/json"
"io"
"log"
"lsp-go/analysis"
"lsp-go/lsp"
"lsp-go/rpc"
"os"
)
func main() {
logger := getLogger("/Users/ayush/Desktop/learn/lsp-go/logs.txt")
logger.Printf("logger initiated bruv..")
logger.Printf("hiii");
bufferScanner := bufio.NewScanner(os.Stdin);
state := analysis.NewState();
// split using the custom defined splitter function
bufferScanner.Split(rpc.Split)
var idx int = 1
logger.Println("attached splitter")
for bufferScanner.Scan() {
logger.Printf("parsing buffer... %d", idx)
msg := bufferScanner.Bytes()
method, content, err := rpc.DecodeMessage(msg)
if (err != nil) {
logger.Printf("An error occurred %s", err)
}
// I previously erroneously used stderr as writing stream and hence wasn't able to receive further responses from the client
writer := os.Stdout
handleMessage(logger, writer, state, method, content);
logger.Printf("[progress] Buffer parsed for [%d]th time", idx)
idx += 1
}
logger.Println("finished scanning")
}
// handle the message received from client
// UNIMPLEMENTED yet
func handleMessage(logger *log.Logger, writer io.Writer, state analysis.State, method string, content []byte) {
logger.Printf("Received message with method %s", method)
switch method {
case "initialize":
var request lsp.InitializeRequest
if err := json.Unmarshal(content, &request); err != nil {
logger.Printf("received contents cannot be parsed : %s %s", content, err)
}
logger.Printf("[INITIALIZE] Connected to client %s with version %s", request.InitializeRequestParams.ClientInfo.Name, request.InitializeRequestParams.ClientInfo.Version)
response := lsp.NewInitializeResponse(request.ID)
writeResponse(logger, response, writer)
case "textDocument/didOpen":
var request lsp.DidOpenTextDocumentNotification
if err := json.Unmarshal(content, &request) ; err != nil {
logger.Printf("[textdoc/didOpen]received contents cannot be parsed : %s %s", content, err)
}
logger.Printf("[textdoc/didOpen] OPENED loaded file at: [ %s ]", request.DidOpenTextDocumentParams.TextDocumentItem.Uri)
diagnostics := state.OpenDocument(logger, request.DidOpenTextDocumentParams.TextDocumentItem.Uri, request.DidOpenTextDocumentParams.TextDocumentItem.Text)
writeResponse(logger, lsp.PublishDiagnosticsNotification{
Notification: lsp.Notification{
RPC: "2.0",
Method: "textDocument/publishDiagnostics",
},
Params: lsp.PublishDiagnosticParams{
URI: request.DidOpenTextDocumentParams.TextDocumentItem.Uri,
Diagnostics: diagnostics,
},
}, writer)
case "textDocument/didChange":
var request lsp.DidChangeTextDocumentNotification
if err := json.Unmarshal(content, &request) ; err != nil {
logger.Printf("[textdoc/didChange] received contents cannot be parsed : %s %s", content, err)
}
logger.Printf("[textdoc/didChange] UPDATED loaded file at: [ %s ]", request.Params.TextDocument.Uri)
for _, change := range request.Params.Changes {
diagnostics := state.UpdateDocument(logger, request.Params.TextDocument.Uri, change.Text)
writeResponse(logger, lsp.PublishDiagnosticsNotification{
Notification: lsp.Notification{
RPC: "2.0",
Method: "textDocument/publishDiagnostics",
},
Params: lsp.PublishDiagnosticParams {
URI: request.Params.TextDocument.Uri,
Diagnostics: diagnostics,
},
},
writer,
)
}
case "textDocument/hover":
var request lsp.HoverRequest
if err := json.Unmarshal(content, &request) ; err != nil {
logger.Printf("[textdoc/hover] received contents cannot be parsed : %s %s", content, err)
}
logger.Printf("[textdoc/hover] HOVER loaded file at: [ %s ]", request.Params.TextDocument.Uri)
// prepare resposne
response := state.Hover(request.ID, request.Params.TextDocument.Uri) // write it back to the stream
writeResponse(logger, response, writer)
case "textDocument/definition":
var request lsp.DefinitionRequest
if err := json.Unmarshal(content, &request) ; err != nil {
logger.Printf("[textdoc/defnition] received contents cannot be parsed : %s %s", content, err)
}
logger.Printf("[textdoc/definition] DEFINITION loaded file at: [ %s ]", request.Params.TextDocument.Uri)
// prepare resposne
response := state.Definition(request.ID, request.Params.TextDocument.Uri, request.Params.Position) // write it back to the stream
writeResponse(logger, response, writer)
case "textDocument/codeAction":
var request lsp.DefinitionRequest
if err := json.Unmarshal(content, &request) ; err != nil {
logger.Printf("[textdoc/codeAction] received contents cannot be parsed : %s %s", content, err)
}
logger.Printf("[textdoc/codeAction] CODE ACTION loaded file at: [ %s ]", request.Params.TextDocument.Uri)
// prepare resposne
response := state.CodeAction(request.ID, request.Params.TextDocument.Uri) // write it back to the stream
writeResponse(logger, response, writer)
case "textDocument/completion":
var request lsp.CompletionRequest
if err := json.Unmarshal(content, &request) ; err != nil {
logger.Printf("[textdoc/completion] received contents cannot be parsed : %s %s", content, err)
}
logger.Printf("[textdoc/completion] COMPLETION loaded file at: [ %s ]", request.Params.TextDocument.Uri)
// prepare resposne
response := state.Completion(logger, request.ID, request.Params.TextDocument.Uri) // write it back to the stream
writeResponse(logger, response, writer)
}
}
func writeResponse(logger *log.Logger, response any, writer io.Writer) {
encodedResponse := rpc.EncodeMessage(response);
writer.Write([]byte(encodedResponse))
logger.Printf("responded back to client with %s", encodedResponse)
}
// create a file to write logs to and return it
func getLogger(path string) *log.Logger {
logfile, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
if (err != nil) {
panic("Invalid file path provided")
}
return log.New(logfile, "[custom-lsp]", log.Ldate|log.Ltime|log.Lshortfile)
}