summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2020-05-15 19:16:42 +0800
committer最萌小汐 <sumneko@hotmail.com>2020-05-15 19:16:42 +0800
commitb17a7ec335b2702dd3562ab2d3380effba08a51a (patch)
tree804485ea67d40e9b2270ba204ff0c3d54890b691
parentaeae9df8137820f1c64fe528b96dfbb9b1348eb5 (diff)
downloadlua-language-server-b17a7ec335b2702dd3562ab2d3380effba08a51a.zip
更新一波语义着色
-rw-r--r--script/capability/semantic.lua28
-rw-r--r--script/constant/TokenModifiers.lua8
-rw-r--r--script/constant/TokenTypes.lua21
-rw-r--r--script/method/init.lua1
-rw-r--r--script/method/textDocument/semanticTokens.lua179
-rw-r--r--script/service.lua2
6 files changed, 236 insertions, 3 deletions
diff --git a/script/capability/semantic.lua b/script/capability/semantic.lua
index a5c8746b..72c889e1 100644
--- a/script/capability/semantic.lua
+++ b/script/capability/semantic.lua
@@ -1,11 +1,27 @@
-local rpc = require 'rpc'
+local rpc = require 'rpc'
+local TokenTypes = require 'constant.TokenTypes'
+local TokenModifiers = require 'constant.TokenModifiers'
local isEnable = false
-local function enable()
+local function toArray(map)
+ local array = {}
+ for k in pairs(map) do
+ array[#array+1] = k
+ end
+ table.sort(array, function (a, b)
+ return map[a] < map[b]
+ end)
+ return array
+end
+
+local function enable(lsp)
if isEnable then
return
end
+ if not lsp.client.capabilities.textDocument.semanticTokens then
+ return
+ end
isEnable = true
log.debug('Enable semantic.')
rpc:request('client/registerCapability', {
@@ -13,6 +29,14 @@ local function enable()
{
id = 'semantic',
method = 'textDocument/semanticTokens',
+ registerOptions = {
+ legend = {
+ tokenTypes = toArray(TokenTypes),
+ tokenModifiers = toArray(TokenModifiers),
+ },
+ rangeProvider = false,
+ documentProvider = false,
+ },
},
}
})
diff --git a/script/constant/TokenModifiers.lua b/script/constant/TokenModifiers.lua
new file mode 100644
index 00000000..b77fd386
--- /dev/null
+++ b/script/constant/TokenModifiers.lua
@@ -0,0 +1,8 @@
+return {
+ ["declaration"] = 1 << 0,
+ ["documentation"] = 1 << 1,
+ ["static"] = 1 << 2,
+ ["abstract"] = 1 << 3,
+ ["deprecated"] = 1 << 4,
+ ["readonly"] = 1 << 5,
+}
diff --git a/script/constant/TokenTypes.lua b/script/constant/TokenTypes.lua
new file mode 100644
index 00000000..236a7805
--- /dev/null
+++ b/script/constant/TokenTypes.lua
@@ -0,0 +1,21 @@
+return {
+ ["comment"] = 0,
+ ["keyword"] = 1,
+ ["number"] = 2,
+ ["regexp"] = 3,
+ ["operator"] = 4,
+ ["namespace"] = 5,
+ ["type"] = 6,
+ ["struct"] = 7,
+ ["class"] = 8,
+ ["interface"] = 9,
+ ["enum"] = 10,
+ ["typeParameter"] = 11,
+ ["function"] = 12,
+ ["member"] = 13,
+ ["macro"] = 14,
+ ["variable"] = 15,
+ ["parameter"] = 16,
+ ["property"] = 17,
+ ["label"] = 18,
+}
diff --git a/script/method/init.lua b/script/method/init.lua
index 8827768b..dd662a2d 100644
--- a/script/method/init.lua
+++ b/script/method/init.lua
@@ -23,6 +23,7 @@ init 'textDocument/onTypeFormatting'
init 'textDocument/publishDiagnostics'
init 'textDocument/rename'
init 'textDocument/references'
+init 'textDocument/semanticTokens'
init 'textDocument/signatureHelp'
init 'workspace/didChangeConfiguration'
init 'workspace/didChangeWatchedFiles'
diff --git a/script/method/textDocument/semanticTokens.lua b/script/method/textDocument/semanticTokens.lua
new file mode 100644
index 00000000..6595459e
--- /dev/null
+++ b/script/method/textDocument/semanticTokens.lua
@@ -0,0 +1,179 @@
+local TokenTypes = require 'constant.TokenTypes'
+local TokenModifiers = require 'constant.TokenModifiers'
+local findLib = require 'core.find_lib'
+
+local timerCache = {}
+local constLib = {
+ ['_G'] = true,
+ ['_VERSION'] = true,
+ ['math.pi'] = true,
+ ['math.huge'] = true,
+ ['math.maxinteger'] = true,
+ ['math.mininteger'] = true,
+ ['utf8.charpattern'] = true,
+ ['io.stdin'] = true,
+ ['io.stdout'] = true,
+ ['io.stderr'] = true,
+ ['package.config'] = true,
+ ['package.cpath'] = true,
+ ['package.loaded'] = true,
+ ['package.loaders'] = true,
+ ['package.path'] = true,
+ ['package.preload'] = true,
+ ['package.searchers'] = true
+}
+
+local function buildLibToken(source, lib)
+ local modifieres
+ if constLib[lib.doc] then
+ modifieres = TokenModifiers.readonly
+ else
+ modifieres = TokenModifiers.static
+ end
+ return {
+ start = source.start,
+ finish = source.finish,
+ type = TokenTypes.namespace,
+ modifieres = modifieres,
+ }
+end
+
+local Care = {
+ ['name'] = function (source)
+ local lib = findLib(source)
+ if lib then
+ return buildLibToken(source, lib)
+ end
+ if source:get 'global' then
+ return {
+ start = source.start,
+ finish = source.finish,
+ type = TokenTypes.namespace,
+ modifieres = TokenModifiers.deprecated,
+ }
+ else
+ return {
+ start = source.start,
+ finish = source.finish,
+ type = TokenTypes.variable,
+ }
+ end
+ end,
+}
+
+local function buildTokens(sources, lines)
+ local tokens = {}
+ local lastLine = 0
+ local lastStartChar = 0
+ for i, source in ipairs(sources) do
+ local row, col = lines:rowcol(source.start)
+ local line = row - 1
+ local startChar = col - 1
+ local deltaLine = line - lastLine
+ local deltaStartChar
+ if deltaLine == 0 then
+ deltaStartChar = startChar - lastStartChar
+ else
+ deltaStartChar = startChar
+ end
+ lastLine = line
+ lastStartChar = startChar
+ local len = i * 5 - 5
+ tokens[len + 1] = deltaLine
+ tokens[len + 2] = deltaStartChar
+ tokens[len + 3] = source.finish - source.start + 1 -- length
+ tokens[len + 4] = source.type
+ tokens[len + 5] = source.modifieres or 0
+ end
+ return tokens
+end
+
+local function resolveTokens(vm, lines)
+ local sources = {}
+ for _, source in ipairs(vm.sources) do
+ if Care[source.type] then
+ sources[#sources+1] = Care[source.type](source)
+ end
+ end
+
+ -- 先进行排序
+ table.sort(sources, function (a, b)
+ return a.start < b.start
+ end)
+
+ log.debug(table.dump(sources))
+
+ local tokens = buildTokens(sources, lines)
+
+ return tokens
+end
+
+local function toArray(map)
+ local array = {}
+ for k in pairs(map) do
+ array[#array+1] = k
+ end
+ table.sort(array, function (a, b)
+ return map[a] < map[b]
+ end)
+ return array
+end
+
+local function testTokens(vm, lines)
+ local text = vm.text
+ local sources = {}
+ local init = 1
+ while true do
+ local start, finish = text:find('[%w_%.]+', init)
+ if not start then
+ break
+ end
+ init = finish + 1
+ local token = text:sub(start, finish)
+ local type = token:match '[%w_]+'
+ local mod = token:match '%.([%w_]+)'
+ sources[#sources+1] = {
+ start = start,
+ finish = finish,
+ type = TokenTypes[type],
+ modifieres = TokenModifiers[mod] or 0,
+ }
+ end
+ local tokens = buildTokens(sources, lines)
+ log.debug(table.dump(sources))
+ log.debug(table.dump(tokens))
+ return tokens
+end
+
+return function (lsp, params)
+ local uri = params.textDocument.uri
+
+ if timerCache[uri] then
+ timerCache[uri]:remove()
+ timerCache[uri] = nil
+ end
+
+ return function (response)
+ local clock = os.clock()
+ timerCache[uri] = ac.loop(0.1, function (t)
+ local vm, lines = lsp:getVM(uri)
+ if not vm then
+ if os.clock() - clock > 10 then
+ t:remove()
+ timerCache[uri] = nil
+ response(nil)
+ end
+ return
+ end
+
+ t:remove()
+ timerCache[uri] = nil
+
+ local tokens = resolveTokens(vm, lines)
+ --local tokens = testTokens(vm, lines)
+ response {
+ data = tokens,
+ }
+ end)
+ end
+end
diff --git a/script/service.lua b/script/service.lua
index 88e8448c..1e3f7108 100644
--- a/script/service.lua
+++ b/script/service.lua
@@ -774,7 +774,7 @@ function mt:onUpdateConfig(updated, other)
capability.completion.disable(self)
end
if newConfig.color.mode == 'Semantic' then
- capability.semantic.enable()
+ capability.semantic.enable(self)
else
capability.semantic.disable()
end