diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2021-09-27 17:18:38 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-27 17:18:38 +0800 |
commit | e462ad0bc5254487337daf285c0303b0eb93e607 (patch) | |
tree | ef11d0d548e23a18da5151321e614d3dca07f797 /script/core | |
parent | 98c74b1f9a04ed49e4c9186e9e01f7c5c15449c9 (diff) | |
parent | 4c51da51064bb825563827d0610a1e3db75299aa (diff) | |
download | lua-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.lua | 246 |
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) |