diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2020-09-27 21:19:08 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2020-09-27 21:19:08 +0800 |
commit | 599fa474f0abe30a7086b5321fe52bd2e078666a (patch) | |
tree | d76e259b45b35f7263d62511978e90dbf06718c4 /script-beta/core/document-symbol.lua | |
parent | afc09241d9075d73cb76661a02613a6e114df686 (diff) | |
download | lua-language-server-599fa474f0abe30a7086b5321fe52bd2e078666a.zip |
优化 workspace/symbol 的性能
Diffstat (limited to 'script-beta/core/document-symbol.lua')
-rw-r--r-- | script-beta/core/document-symbol.lua | 201 |
1 files changed, 199 insertions, 2 deletions
diff --git a/script-beta/core/document-symbol.lua b/script-beta/core/document-symbol.lua index efa54f57..7426b4e3 100644 --- a/script-beta/core/document-symbol.lua +++ b/script-beta/core/document-symbol.lua @@ -1,5 +1,202 @@ local await = require 'await' -local symbol = require 'core.symbol' +local files = require 'files' +local guide = require 'parser.guide' +local skind = require 'define.SymbolKind' +local lname = require 'core.hover.name' +local util = require 'utility' + +local function buildFunctionParams(func) + if not func.args then + return '' + end + local params = {} + for i, arg in ipairs(func.args) do + if arg.type == '...' then + params[i] = '...' + else + params[i] = arg[1] or '' + end + end + return table.concat(params, ', ') +end + +local function buildFunction(source, symbols) + local name = lname(source) + local func = source.value + if source.type == 'tablefield' + or source.type == 'setfield' then + source = source.field + end + local range, kind + if func.start > source.finish then + -- a = function() + range = { source.start, func.finish } + else + -- function f() + range = { func.start, func.finish } + end + if source.type == 'setmethod' then + kind = skind.Method + else + kind = skind.Function + end + symbols[#symbols+1] = { + name = name, + detail = ('function (%s)'):format(buildFunctionParams(func)), + kind = kind, + range = range, + selectionRange = { source.start, source.finish }, + valueRange = { func.start, func.finish }, + } +end + +local function buildTable(tbl) + local buf = {} + for i = 1, 3 do + local field = tbl[i] + if not field then + break + end + if field.type == 'tablefield' then + buf[i] = ('%s'):format(field.field[1]) + end + end + return table.concat(buf, ', ') +end + +local function buildValue(source, symbols) + local name = lname(source) + local range, sRange, valueRange, kind + local details = {} + if source.type == 'local' then + if source.parent.type == 'funcargs' then + details[1] = 'param' + range = { source.start, source.finish } + sRange = { source.start, source.finish } + kind = skind.Constant + else + details[1] = 'local' + range = { source.start, source.finish } + sRange = { source.start, source.finish } + kind = skind.Variable + end + elseif source.type == 'setlocal' then + details[1] = 'setlocal' + range = { source.start, source.finish } + sRange = { source.start, source.finish } + kind = skind.Variable + elseif source.type == 'setglobal' then + details[1] = 'global' + range = { source.start, source.finish } + sRange = { source.start, source.finish } + kind = skind.Class + elseif source.type == 'tablefield' then + details[1] = 'field' + range = { source.field.start, source.field.finish } + sRange = { source.field.start, source.field.finish } + kind = skind.Property + else + details[1] = 'field' + range = { source.field.start, source.field.finish } + sRange = { source.field.start, source.field.finish } + kind = skind.Field + end + if source.value then + local literal = source.value[1] + if source.value.type == 'boolean' then + details[2] = ' boolean' + if literal ~= nil then + details[3] = ' = ' + details[4] = util.viewLiteral(source.value[1]) + end + elseif source.value.type == 'string' then + details[2] = ' string' + if literal ~= nil then + details[3] = ' = ' + details[4] = util.viewLiteral(source.value[1]) + end + elseif source.value.type == 'number' then + details[2] = ' number' + if literal ~= nil then + details[3] = ' = ' + details[4] = util.viewLiteral(source.value[1]) + end + elseif source.value.type == 'table' then + details[2] = ' {' + details[3] = buildTable(source.value) + details[4] = '}' + valueRange = { source.value.start, source.value.finish } + elseif source.value.type == 'select' then + if source.value.vararg and source.value.vararg.type == 'call' then + valueRange = { source.value.start, source.value.finish } + end + end + range = { range[1], source.value.finish } + end + symbols[#symbols+1] = { + name = name, + detail = table.concat(details), + kind = kind, + range = range, + selectionRange = sRange, + valueRange = valueRange, + } +end + +local function buildSet(source, used, symbols) + local value = source.value + if value and value.type == 'function' then + used[value] = true + buildFunction(source, symbols) + else + buildValue(source, symbols) + end +end + +local function buildAnonymousFunction(source, used, symbols) + if used[source] then + return + end + used[source] = true + symbols[#symbols+1] = { + name = '', + detail = 'function ()', + kind = skind.Function, + range = { source.start, source.finish }, + selectionRange = { source.start, source.start }, + valueRange = { source.start, source.finish }, + } +end + +local function buildSource(source, used, symbols) + if source.type == 'local' + or source.type == 'setlocal' + or source.type == 'setglobal' + or source.type == 'setfield' + or source.type == 'setmethod' + or source.type == 'tablefield' then + await.delay() + buildSet(source, used, symbols) + elseif source.type == 'function' then + await.delay() + buildAnonymousFunction(source, used, symbols) + end +end + +local function makeSymbol(uri) + local ast = files.getAst(uri) + if not ast then + return nil + end + + local symbols = {} + local used = {} + guide.eachSource(ast.ast, function (source) + buildSource(source, used, symbols) + end) + + return symbols +end local function packChild(ranges, symbols) await.delay() @@ -62,7 +259,7 @@ local function packSymbols(symbols) end return function (uri) - local symbols = symbol(uri) + local symbols = makeSymbol(uri) if not symbols then return nil end |