summaryrefslogtreecommitdiff
path: root/script/core
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2021-09-27 17:18:38 +0800
committerGitHub <noreply@github.com>2021-09-27 17:18:38 +0800
commite462ad0bc5254487337daf285c0303b0eb93e607 (patch)
treeef11d0d548e23a18da5151321e614d3dca07f797 /script/core
parent98c74b1f9a04ed49e4c9186e9e01f7c5c15449c9 (diff)
parent4c51da51064bb825563827d0610a1e3db75299aa (diff)
downloadlua-language-server-e462ad0bc5254487337daf285c0303b0eb93e607.zip
Merge pull request #689 from ArcanoxDragon/improve-semantic-highlighting
Improve diversity and granularity of semantic token highlighting
Diffstat (limited to 'script/core')
-rw-r--r--script/core/semantic-tokens.lua246
1 files changed, 199 insertions, 47 deletions
diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua
index 38b75227..517eb25b 100644
--- a/script/core/semantic-tokens.lua
+++ b/script/core/semantic-tokens.lua
@@ -6,76 +6,109 @@ local vm = require 'vm'
local util = require 'utility'
local guide = require 'parser.guide'
local converter = require 'proto.converter'
+local infer = require 'core.infer'
+local config = require 'config'
+
+local isEnhanced = config.get 'Lua.color.mode' == 'SemanticEnhanced'
local Care = {}
-Care['setglobal'] = function (source, results)
+Care['getglobal'] = function (source, results)
local isLib = vm.isGlobalLibraryName(source[1])
- if not isLib then
+ local isFunc = false
+ local value = source.value
+ local next = source.next
+
+ if value and value.type == 'function' then
+ isFunc = true
+ elseif next and next.type == 'call' then
+ isFunc = true
+ elseif isEnhanced then
+ isFunc = infer.hasType(source, 'function')
+ end
+
+ local type = isFunc and define.TokenTypes['function'] or define.TokenTypes.variable
+ local modifier = isLib and define.TokenModifiers.defaultLibrary or define.TokenModifiers.static
+
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = type,
+ modifieres = modifier,
+ }
+end
+Care['setglobal'] = Care['getglobal']
+Care['getmethod'] = function (source, results)
+ local method = source.method
+ if method and method.type == 'method' then
results[#results+1] = {
- start = source.start,
- finish = source.finish,
- type = define.TokenTypes.namespace,
- modifieres = define.TokenModifiers.deprecated,
+ start = method.start,
+ finish = method.finish,
+ type = define.TokenTypes.method,
+ modifieres = source.type == 'setmethod' and define.TokenModifiers.declaration or nil,
}
end
end
-Care['getglobal'] = function (source, results)
- local isLib = vm.isGlobalLibraryName(source[1])
- if not isLib then
- results[#results+1] = {
+Care['setmethod'] = Care['getmethod']
+Care['field'] = function (source, results)
+ local modifiers = 0
+ if source.parent and source.parent.type == 'tablefield' then
+ modifiers = define.TokenModifiers.declaration
+ end
+ if source.parent then
+ local value = source.parent.value
+ if value and value.type == 'function' then
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes.method,
+ modifieres = modifiers,
+ }
+ return
+ end
+ end
+ if isEnhanced and infer.hasType(source, 'function') then
+ results[#results+1] = {
start = source.start,
finish = source.finish,
- type = define.TokenTypes.namespace,
- modifieres = define.TokenModifiers.deprecated,
+ type = define.TokenTypes.method,
+ modifieres = modifiers,
}
- end
-end
-Care['tablefield'] = function (source, results)
- local field = source.field
- if not field then
return
end
results[#results+1] = {
- start = field.start,
- finish = field.finish,
+ start = source.start,
+ finish = source.finish,
type = define.TokenTypes.property,
- modifieres = define.TokenModifiers.declaration,
+ modifieres = modifiers,
}
end
Care['getlocal'] = function (source, results)
local loc = source.node
- -- 1. 值为函数的局部变量
- local hasFunc
- local node = loc.node
- if node then
- for _, ref in ipairs(node.ref) do
- local def = ref.value
- if def.type == 'function' then
- hasFunc = true
- break
+ -- 1. 值为函数的局部变量 | Local variable whose value is a function
+ if loc.refs then
+ for _, ref in ipairs(loc.refs) do
+ if ref.value and ref.value.type == 'function' then
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes['function'],
+ }
+ return
end
end
end
- if hasFunc then
- results[#results+1] = {
- start = source.start,
- finish = source.finish,
- type = define.TokenTypes.interface,
- modifieres = define.TokenModifiers.declaration,
- }
- return
- end
- -- 2. 对象
+ -- 2. 对象 | Object
if source.parent.type == 'getmethod'
+ or source.parent.type == 'setmethod'
and source.parent.node == source then
return
end
- -- 3. 特殊变量
+ -- 3. 特殊变量 | Special variable
if source[1] == '_ENV'
or source[1] == 'self' then
return
end
- -- 4. 函数的参数
+ -- 4. 函数的参数 | Function parameters
if loc.parent and loc.parent.type == 'funcargs' then
results[#results+1] = {
start = source.start,
@@ -85,7 +118,57 @@ Care['getlocal'] = function (source, results)
}
return
end
- -- 5. const 变量
+ -- 5. References to other functions
+ if isEnhanced and infer.hasType(loc, 'function') then
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes['function'],
+ modifieres = source.type == 'setlocal' and define.TokenModifiers.declaration or nil,
+ }
+ return
+ end
+ -- 6. Class declaration
+ if isEnhanced then
+ -- search all defs
+ for _, def in ipairs(vm.getDefs(source)) do
+ if def.bindDocs then
+ for _, doc in ipairs(def.bindDocs) do
+ if doc.type == "doc.class" and doc.bindSources then
+ for _, src in ipairs(doc.bindSources) do
+ if src == def then
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes.class,
+ }
+ return
+ end
+ end
+ end
+ end
+ end
+ end
+ else
+ -- only search this local
+ if loc.bindDocs then
+ for i, doc in ipairs(loc.bindDocs) do
+ if doc.type == "doc.class" and doc.bindSources then
+ for _, src in ipairs(doc.bindSources) do
+ if src == loc then
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes.class,
+ }
+ return
+ end
+ end
+ end
+ end
+ end
+ end
+ -- 6. const 变量 | Const variable
if loc.attrs then
for _, attr in ipairs(loc.attrs) do
local name = attr[1]
@@ -108,20 +191,69 @@ Care['getlocal'] = function (source, results)
end
end
end
- -- 6. 函数调用
+ -- 7. 函数调用 | Function call
if source.parent.type == 'call'
and source.parent.node == source then
return
end
- -- 7. 其他
+ local isLocal = loc.parent ~= guide.getRoot(loc)
+ -- 8. 其他 | Other
results[#results+1] = {
start = source.start,
finish = source.finish,
type = define.TokenTypes.variable,
+ modifieres = isLocal and define.TokenModifiers['local'] or nil,
}
end
Care['setlocal'] = Care['getlocal']
-Care['local'] = function (source, results)
+Care['local'] = function (source, results) -- Local declaration, i.e. "local x", "local y = z", or "local function() end"
+ if source[1] == '_ENV'
+ or source[1] == 'self' then
+ return
+ end
+ if source.parent and source.parent.type == 'funcargs' then
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes.parameter,
+ modifieres = define.TokenModifiers.declaration,
+ }
+ return
+ end
+ if source.value then
+ local isFunction = false
+
+ if isEnhanced then
+ isFunction = source.value.type == 'function' or infer.hasType(source.value, 'function')
+ else
+ isFunction = source.value.type == 'function'
+ end
+
+ if isFunction then
+ -- Function declaration, either a new one or an alias for another one
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes['function'],
+ modifieres = define.TokenModifiers.declaration,
+ }
+ return
+ end
+ end
+ if source.value and source.value.type == 'table' and source.bindDocs then
+ for _, doc in ipairs(source.bindDocs) do
+ if doc.type == "doc.class" then
+ -- Class declaration (explicit)
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes.class,
+ modifieres = define.TokenModifiers.declaration,
+ }
+ return
+ end
+ end
+ end
if source.attrs then
for _, attr in ipairs(source.attrs) do
local name = attr[1]
@@ -130,7 +262,7 @@ Care['local'] = function (source, results)
start = source.start,
finish = source.finish,
type = define.TokenTypes.variable,
- modifieres = define.TokenModifiers.static,
+ modifieres = define.TokenModifiers.declaration | define.TokenModifiers.static,
}
return
elseif name == 'close' then
@@ -138,12 +270,26 @@ Care['local'] = function (source, results)
start = source.start,
finish = source.finish,
type = define.TokenTypes.variable,
- modifieres = define.TokenModifiers.abstract,
+ modifieres = define.TokenModifiers.declaration | define.TokenModifiers.abstract,
}
return
end
end
end
+
+ local isLocal = source.parent ~= guide.getRoot(source)
+ local modifiers = define.TokenModifiers.declaration
+
+ if isLocal then
+ modifiers = modifiers | define.TokenModifiers['local']
+ end
+
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes.variable,
+ modifieres = modifiers,
+ }
end
Care['doc.return.name'] = function (source, results)
results[#results+1] = {
@@ -213,6 +359,12 @@ local function buildTokens(uri, results)
return tokens
end
+config.watch(function (key, value)
+ if key == 'Lua.color.mode' then
+ isEnhanced = value == 'SemanticEnhanced'
+ end
+end)
+
return function (uri, start, finish)
local state = files.getState(uri)
local text = files.getText(uri)