summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/src/matcher/diagnostics.lua49
-rw-r--r--server/src/matcher/init.lua1
-rw-r--r--server/src/service.lua88
3 files changed, 119 insertions, 19 deletions
diff --git a/server/src/matcher/diagnostics.lua b/server/src/matcher/diagnostics.lua
new file mode 100644
index 00000000..9cd4f6ee
--- /dev/null
+++ b/server/src/matcher/diagnostics.lua
@@ -0,0 +1,49 @@
+local DiagnosticSeverity = {
+ Error = 1,
+ Warning = 2,
+ Information = 3,
+ Hint = 4,
+}
+
+--[[
+/**
+ * Represents a related message and source code location for a diagnostic. This should be
+ * used to point to code locations that cause or related to a diagnostics, e.g when duplicating
+ * a symbol in a scope.
+ */
+export interface DiagnosticRelatedInformation {
+ /**
+ * The location of this related diagnostic information.
+ */
+ location: Location;
+
+ /**
+ * The message of this related diagnostic information.
+ */
+ message: string;
+}
+]]--
+
+return function (ast, results)
+ local diagnostics = {}
+
+ diagnostics[1] = {
+ range = {
+ start = {
+ line = 0,
+ character = 0,
+ },
+ ['end'] = {
+ line = 0,
+ character = 10,
+ },
+ },
+ severity = DiagnosticSeverity.Warning,
+ code = 'I am code',
+ source = 'I am source',
+ message = 'I am message',
+ relatedInformation = nil,
+ }
+
+ return diagnostics
+end
diff --git a/server/src/matcher/init.lua b/server/src/matcher/init.lua
index 99149582..cacef3e5 100644
--- a/server/src/matcher/init.lua
+++ b/server/src/matcher/init.lua
@@ -4,6 +4,7 @@ local api = {
references = require 'matcher.references',
rename = require 'matcher.rename',
hover = require 'matcher.hover',
+ diagnostics = require 'matcher.diagnostics',
compile = require 'matcher.compile',
}
diff --git a/server/src/service.lua b/server/src/service.lua
index e6515fa5..12ae140b 100644
--- a/server/src/service.lua
+++ b/server/src/service.lua
@@ -34,21 +34,27 @@ function mt:_callMethod(name, params)
local f = method[name]
if f then
local clock = os.clock()
- local suc, res, res2 = pcall(f, self, params)
+ local suc, res = xpcall(f, log.error, self, params)
local passed = os.clock() - clock
if passed > 0.01 then
log.debug(('Task [%s] takes [%.3f]sec.'):format(name, passed))
end
if suc then
- return res, res2
+ return res
else
- return nil, 'Runtime error: ' .. res
+ return nil, {
+ code = ErrorCodes.InternalError,
+ message = res,
+ }
end
end
if optional then
- return false
+ return nil
else
- return nil, 'Undefined method: ' .. name
+ return nil, {
+ code = ErrorCodes.MethodNotFound,
+ message = 'MethodNotFound',
+ }
end
end
@@ -64,18 +70,50 @@ function mt:_doProto(proto)
local method = proto.method
local params = proto.params
local response, err = self:_callMethod(method, params)
+ if not id then
+ return
+ end
local proto = json.table()
proto.id = id
- proto.result = response
+ if err then
+ proto.error = err
+ else
+ proto.result = response
+ end
self:_send(proto)
end
+function mt:_doDiagnostic()
+ if not next(self._needDiagnostics) then
+ return
+ end
+ local copy = {}
+ for uri, data in pairs(self._needDiagnostics) do
+ copy[uri] = data
+ self._needDiagnostics[uri] = nil
+ end
+ for uri, data in pairs(copy) do
+ local ast = data.ast
+ local results = data.results
+ local suc, res = xpcall(matcher.diagnostics, log.error, ast, results)
+ if suc then
+ self:_send {
+ method = 'textDocument/publishDiagnostics',
+ params = {
+ uri = uri,
+ diagnostics = res,
+ },
+ }
+ end
+ end
+end
+
function mt:_buildTextCache()
- if not next(self._need_compile) then
+ if not next(self._needCompile) then
return
end
local list = {}
- for uri in pairs(self._need_compile) do
+ for uri in pairs(self._needCompile) do
list[#list+1] = uri
end
@@ -123,13 +161,13 @@ function mt:saveText(uri, version, text)
end
obj.version = version
obj.text = text
- self._need_compile[uri] = true
+ self._needCompile[uri] = true
else
self._file[uri] = {
version = version,
text = text,
}
- self._need_compile[uri] = true
+ self._needCompile[uri] = true
end
end
@@ -147,30 +185,41 @@ function mt:compileText(uri)
if not obj then
return nil
end
- if not self._need_compile[uri] then
+ if not self._needCompile[uri] then
return nil
end
- self._need_compile[uri] = nil
- local ast = parser:ast(obj.text)
+ self._needCompile[uri] = nil
+ local ast = parser:ast(obj.text)
obj.results = matcher.compile(ast)
- obj.lines = parser:lines(obj.text)
+ if not obj.results then
+ return obj
+ end
+ obj.lines = parser:lines(obj.text)
+
+ self._needDiagnostics[uri] = {
+ ast = ast,
+ results = obj.results,
+ }
+
return obj
end
function mt:removeText(uri)
self._file[uri] = nil
- self._need_compile[uri] = nil
+ self._needCompile[uri] = nil
end
function mt:on_tick()
local proto = thread.proto()
if proto then
- self._idle_clock = os.clock()
+ self._idleClock = os.clock()
self:_doProto(proto)
return
end
- if os.clock() - self._idle_clock >= 1 then
+ if os.clock() - self._idleClock >= 0.2 then
+ self._idleClock = os.clock()
self:_buildTextCache()
+ self:_doDiagnostic()
end
end
@@ -192,8 +241,9 @@ end
return function ()
local session = setmetatable({
_file = {},
- _need_compile = {},
- _idle_clock = os.clock(),
+ _needCompile = {},
+ _needDiagnostics = {},
+ _idleClock = os.clock(),
}, mt)
return session
end