-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.lua
179 lines (165 loc) · 5.92 KB
/
main.lua
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
167
168
169
170
171
172
173
174
175
176
177
178
179
-- TODO: If workspace folder is provided, use that instead of the git root path
-- TODO: Figure out what is causing the lsp to be so slow on larger files
local rpc = require("utils.rpc")
local switch = require("libs.switch")
local server = require("utils.server")
local methods = require("methods")
local logger = require("utils.logger")
local profile = require("libs.profile")
local function send_diagnostics(current_uri, diagnostics)
server.send_notification("textDocument/publishDiagnostics", {
uri = current_uri,
diagnostics = diagnostics,
})
end
logger.init()
---@type table<string, string>
local documents = {}
---@type table<string, table>
local ast_cache = {}
local current_uri = ""
local current_file_content = ""
local current_file_path = ""
---@type string
local root_path = io.popen("git rev-parse --show-toplevel 2>&1"):read("l")
-- TODO: Abstract later
if arg[1] == "DEBUG" then
profile.start()
local profile_file, err = io.open("/tmp/nelua-lsp-profile.log", "w")
if not profile_file then
logger.log(err)
end
end
while true do
---@type string
local header = io.read("L")
local content_length = tonumber(header:match("(%d+)\r\n"))
_ = io.read("L")
---@type string
local content = io.read(content_length)
local request, err = rpc.decode(content)
if request then
if request.params and request.params.textDocument then
current_uri = request.params.textDocument.uri
current_file_path = current_uri:sub(#"file://" + 1)
end
logger.log("Method: " .. request.method .. " ID: " .. (request.id or "N/A"))
switch(request.method, {
["initialize"] = function()
methods.initialize(request.id)
end,
["textDocument/didOpen"] = function()
local root_path_not_found =
root_path:match("fatal: not a git repository %(or any of the parent directories%): %.git")
if root_path_not_found then
root_path = current_uri:sub(#"file:///"):gsub("/[^/]+%.nelua", "")
end
current_file_content = request.params.textDocument.text
documents[current_uri] = current_file_content
local ast, diagnostics = methods.diagnostic(current_file_content, current_file_path, current_uri)
send_diagnostics(current_uri, diagnostics)
if ast then
ast_cache[current_uri] = ast
end
end,
["textDocument/didChange"] = function()
current_file_content = methods.did_change(request.params, current_file_content)
documents[current_uri] = current_file_content
local ast, diagnostics = methods.diagnostic(current_file_content, current_file_path, current_uri)
send_diagnostics(current_uri, diagnostics)
if ast then
ast_cache[current_uri] = ast
end
end,
["textDocument/didSave"] = function()
local current_file_prog <close> = io.open(current_file_path)
if current_file_prog then
current_file_content = current_file_prog:read("a")
documents[current_uri] = current_file_content
end
local ast, diagnostics = methods.diagnostic(current_file_content, current_file_path, current_uri)
send_diagnostics(current_uri, diagnostics)
if ast then
ast_cache[current_uri] = ast
end
end,
["textDocument/completion"] = function()
local ast, items =
methods.completion(request.params, documents, current_uri, current_file_path, current_file_content, ast_cache)
if ast then
ast_cache[current_uri] = ast
end
if next(items) then
server.send_response(request.id, items)
else
server.send_error(request.id, server.LspErrorCode.RequestFailed, "Failed to provide any completions")
end
end,
["completionItem/resolve"] = function() end,
["textDocument/hover"] = function()
current_file_content = documents[current_uri]
local ast = ast_cache[current_uri]
local hover_content = methods.hover(request.params, current_file_content, current_file_path, ast)
if hover_content then
local result = {
contents = hover_content,
}
server.send_response(request.id, result)
else
server.send_error(request.id, server.LspErrorCode.RequestFailed, "Failed to provide any hover information")
end
end,
["textDocument/definition"] = function()
local current_line = request.params.position.line
local current_char = request.params.position.character
current_file_content = documents[current_uri]
local ast = ast_cache[current_uri]
local locs = methods.definition(
root_path,
documents,
current_file_content,
current_file_path,
current_line,
current_char,
ast
)
if locs then
server.send_response(request.id, locs)
else
server.send_error(request.id, server.LspErrorCode.RequestFailed, "Failed to find definition")
end
end,
["textDocument/rename"] = function()
local changes = methods.rename(request.params, current_file_content, ast_cache[current_uri])
local result = {
changes = changes,
}
server.send_response(request.id, result)
end,
["textDocument/didClose"] = function()
documents[current_uri] = nil
ast_cache[current_uri] = nil
end,
["shutdown"] = function()
methods.shutdown()
end,
["exit"] = function()
os.exit()
end,
})
-- TODO: Abstract later
if arg[1] == "DEBUG" then
local profile_text = profile.report(20)
local profile_file, err = io.open("/tmp/nelua-lsp-profile.log", "a")
if profile_file then
profile_file:write(table.concat({ "\nMethod: ", request.method, "\n" }))
profile_file:write(profile_text)
else
logger.log(err)
end
profile.reset()
end
else
logger.log(err)
end
end