diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2020-09-27 17:51:13 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2020-09-27 17:51:13 +0800 |
commit | afc09241d9075d73cb76661a02613a6e114df686 (patch) | |
tree | a71006af6318a9c445185c6495fe4e8d67d085fa | |
parent | 6c34663ba8d3392136f0c0cedb0c402810e442da (diff) | |
download | lua-language-server-afc09241d9075d73cb76661a02613a6e114df686.zip |
工作区符号
-rw-r--r-- | .vscode/launch.json | 2 | ||||
-rw-r--r-- | script-beta/core/document-symbol.lua | 196 | ||||
-rw-r--r-- | script-beta/core/hover/return.lua | 6 | ||||
-rw-r--r-- | script-beta/core/symbol.lua | 199 | ||||
-rw-r--r-- | script-beta/core/workspace-symbol.lua | 29 | ||||
-rw-r--r-- | script-beta/provider/provider.lua | 35 |
6 files changed, 266 insertions, 201 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index 5095cfb2..838f6b24 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -48,7 +48,7 @@ "type": "lua", "request": "attach", "stopOnEntry": true, - "address": "127.0.0.1:11414", + "address": "127.0.0.1:11413", "outputCapture": [ ] }, diff --git a/script-beta/core/document-symbol.lua b/script-beta/core/document-symbol.lua index dabb8a25..efa54f57 100644 --- a/script-beta/core/document-symbol.lua +++ b/script-beta/core/document-symbol.lua @@ -1,187 +1,5 @@ -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 await = require 'await' - -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.Field - 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 await = require 'await' +local symbol = require 'core.symbol' local function packChild(ranges, symbols) await.delay() @@ -244,17 +62,11 @@ local function packSymbols(symbols) end return function (uri) - local ast = files.getAst(uri) - if not ast then + local symbols = symbol(uri) + if not symbols then return nil end - local symbols = {} - local used = {} - guide.eachSource(ast.ast, function (source) - buildSource(source, used, symbols) - end) - local packedSymbols = packSymbols(symbols) return packedSymbols diff --git a/script-beta/core/hover/return.lua b/script-beta/core/hover/return.lua index 3e340b5b..0fd11c57 100644 --- a/script-beta/core/hover/return.lua +++ b/script-beta/core/hover/return.lua @@ -68,8 +68,10 @@ local function asFunction(source) for n = 1, #rtn do local values = vm.getInfers(rtn[n]) for _, value in ipairs(values) do - for tp in value.type:gmatch '[^|]+' do - types[#types+1] = tp + if value.type then + for tp in value.type:gmatch '[^|]+' do + types[#types+1] = tp + end end end end diff --git a/script-beta/core/symbol.lua b/script-beta/core/symbol.lua new file mode 100644 index 00000000..eeed234d --- /dev/null +++ b/script-beta/core/symbol.lua @@ -0,0 +1,199 @@ +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 await = require 'await' + +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.Field + 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 + +return function (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 diff --git a/script-beta/core/workspace-symbol.lua b/script-beta/core/workspace-symbol.lua index a2d1d8dd..6b2c309e 100644 --- a/script-beta/core/workspace-symbol.lua +++ b/script-beta/core/workspace-symbol.lua @@ -1,7 +1,28 @@ -local files = require 'files' -local define = require 'proto.define' -local skind = require 'define.symbolkind' +local files = require 'files' +local symbol = require 'core.symbol' +local guide = require 'parser.guide' +local matchKey = require 'core.matchkey' + +local function searchFile(uri, key, results) + local symbols = symbol(uri) + if not symbols then + return + end + + for _, res in ipairs(symbols) do + if res.name ~= '' and matchKey(key, res.name) then + res.uri = uri + results[#results+1] = res + end + end +end return function (key) - + local results = {} + + for uri in files.eachFile() do + searchFile(files.getOriginUri(uri), key, results) + end + + return results end diff --git a/script-beta/provider/provider.lua b/script-beta/provider/provider.lua index 7c61db14..68c498c6 100644 --- a/script-beta/provider/provider.lua +++ b/script-beta/provider/provider.lua @@ -511,6 +511,7 @@ proto.on('textDocument/documentSymbol', function (params) if symbol.name == '' then symbol.name = lang.script.SYMBOL_ANONYMOUS end + symbol.valueRange = nil if symbol.children then for _, child in ipairs(symbol.children) do convert(child) @@ -549,6 +550,36 @@ proto.on('workspace/executeCommand', function (params) end end) -proto.on('workspaceSymbolProvider', function (params) - +proto.on('workspace/symbol', function (params) + local core = require 'core.workspace-symbol' + + await.close('workspace/symbol') + await.setID('workspace/symbol') + + local symbols = core(params.query) + if not symbols or #symbols == 0 then + return nil + end + + local function convert(symbol) + symbol.location = define.location( + symbol.uri, + define.range( + files.getLines(symbol.uri), + files.getText(symbol.uri), + symbol.range[1], + symbol.range[2] + ) + ) + symbol.uri = nil + symbol.detail = nil + symbol.selectionRange = nil + symbol.valueRange = nil + end + + for _, symbol in ipairs(symbols) do + convert(symbol) + end + + return symbols end) |