From 357e62b68d67c4218d95f6bee937e6d5e206d752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Mon, 18 Mar 2019 16:23:16 +0800 Subject: =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=96=87=E4=BB=B6=E7=AC=A6=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/core/document_symbol.lua | 288 +++++++++++++++++++----------------- server/src/core/hover/hover.lua | 6 + server/src/core/hover/name.lua | 69 +-------- server/src/core/name.lua | 70 +++++++++ 4 files changed, 231 insertions(+), 202 deletions(-) create mode 100644 server/src/core/name.lua (limited to 'server/src/core') diff --git a/server/src/core/document_symbol.lua b/server/src/core/document_symbol.lua index e22fd4db..ac81277c 100644 --- a/server/src/core/document_symbol.lua +++ b/server/src/core/document_symbol.lua @@ -1,5 +1,5 @@ local hoverFunction = require 'core.hover.function' -local hoverName = require 'core.hover.name' +local getName = require 'core.name' local hover = require 'core.hover' local SymbolKind = { @@ -31,171 +31,183 @@ local SymbolKind = { TypeParameter = 26, } -local function isFirstSet(source, value) - if source:action() ~= 'set' then - return false +local function buildLocal(vm, source, used, callback) + local vars = source[1] + local exps = source[2] + if vars.type ~= 'list' then + vars = {vars} end - local firstSrc = value:eachInfo(function (info, src) - if info.type == 'set' then - return src - end - end) - if not firstSrc then - return false + if not exps or exps.type ~= 'list' then + exps = {exps} end - if firstSrc ~= source then - return false + for i, var in ipairs(vars) do + local exp = exps[i] + local data = {} + local loc = var:bindLocal() + data.name = loc:getName() + data.range = { var.start, var.finish } + data.selectionRange = { var.start, var.finish } + if exp then + local hvr = hover(var) + if exp.type == 'function' then + data.kind = SymbolKind.Function + else + data.kind = SymbolKind.Variable + end + data.detail = hvr.label:gsub('[\r\n]', '') + data.valueRange = { exp.start, exp.finish } + used[exp] = true + else + data.kind = SymbolKind.Variable + data.detail = '' + data.valueRange = { var.start, var.finish } + end + callback(data) end - return true end -local function buildLocal(vm, source, callback) - local loc = source:bindLocal() - local value = loc:getInitValue() - local hvr = hover(source) - if not hvr then - return +local function buildSet(vm, source, used, callback) + local vars = source[1] + local exps = source[2] + if vars.type ~= 'list' then + vars = {vars} end - local kind - if value:getType() == 'function' then - kind = SymbolKind.Function - elseif source:get 'table index' then - kind = SymbolKind.Class - else - kind = SymbolKind.Variable - end - local valueSource = value:getSource() - if not valueSource or valueSource.start == 0 or value.uri ~= vm.uri then - valueSource = source - end - local name = hvr.name - if name == '' then - name = tostring(source[1] or '') - end - -- 由于范围不允许交叉,为了支持 local x, y, z = 1, 2, 3 的形式 - -- 范围只能限定在变量上 - -- 而 local function xx() 的形式范围会包含整个 function - if source.start > valueSource.start and source.finish < valueSource.finish then - callback { - name = name, - detail = hvr.label:gsub('[\r\n]', ''), - kind = kind, - range = { valueSource.start, valueSource.finish }, - selectionRange = { source.start, source.finish }, - valueRange = { valueSource.start, valueSource.finish }, - } - else - callback { - name = name, - detail = hvr.label:gsub('[\r\n]', ''), - kind = kind, - range = { source.start, source.finish }, - selectionRange = { source.start, source.finish }, - valueRange = { valueSource.start, valueSource.finish }, - } + if not exps or exps.type ~= 'list' then + exps = {exps} + end + for i, var in ipairs(vars) do + if var:bindLocal() then + goto CONTINUE + end + local exp = exps[i] + local data = {} + data.name = getName(var) + data.range = { var.start, var.finish } + data.selectionRange = { var.start, var.finish } + if exp then + local hvr = hover(var) + if not hvr then + goto CONTINUE + end + if exp.type == 'function' then + data.kind = SymbolKind.Function + else + data.kind = SymbolKind.Property + end + data.detail = hvr.label:gsub('[\r\n]', '') + data.valueRange = { exp.start, exp.finish } + used[exp] = true + else + data.kind = SymbolKind.Property + data.detail = '' + data.valueRange = { var.start, var.finish } + end + callback(data) + :: CONTINUE :: end end -local function buildSet(vm, source, callback) - if source:bindLocal() then - return - end - local value = source:bindValue() - local hvr = hover(source) - if not hvr then - return - end - local kind - if value:getFunction() then - local func = value:getFunction() - if func:getObject() then - kind = SymbolKind.Field +local function buildPair(vm, source, used, callback) + local var = source[1] + local exp = source[2] + local data = {} + data.name = getName(var) + data.range = { var.start, var.finish } + data.selectionRange = { var.start, var.finish } + if exp then + local hvr = hover(var) + if not hvr then + return + end + if exp.type == 'function' then + data.kind = SymbolKind.Function else - kind = SymbolKind.Function + data.kind = SymbolKind.Class end - elseif source:get 'table index' then - kind = SymbolKind.Class + data.detail = hvr.label:gsub('[\r\n]', '') + data.valueRange = { exp.start, exp.finish } + used[exp] = true else - kind = SymbolKind.Property - end - local valueSource = value:getSource() - if not valueSource or valueSource.start == 0 or value.uri ~= vm.uri then - valueSource = source - end - local name = hvr.name - if name == '' then - name = tostring(source[1] or '') - end - -- 由于范围不允许交叉,为了支持 x, y, z = 1, 2, 3 的形式 - -- 范围只能限定在变量上 - -- 而 function xx() 的形式范围会包含整个 function - if source.start > valueSource.start and source.finish < valueSource.finish then - callback { - name = name, - -- 前端不支持多行 - detail = hvr.label:gsub('[\r\n]', ''), - kind = kind, - range = { valueSource.start, valueSource.finish }, - selectionRange = { source.start, source.finish }, - valueRange = { valueSource.start, valueSource.finish }, - } - elseif isFirstSet(source, value) then - callback { - name = name, - -- 前端不支持多行 - detail = hvr.label:gsub('[\r\n]', ''), - kind = kind, - range = { source.start, source.finish }, - selectionRange = { source.start, source.finish }, - valueRange = { valueSource.start, valueSource.finish }, - } - else - callback { - name = name, - -- 前端不支持多行 - detail = hvr.label:gsub('[\r\n]', ''), - kind = kind, - range = { source.start, source.finish }, - selectionRange = { source.start, source.finish }, - valueRange = { source.start, source.finish }, - } + data.kind = SymbolKind.Class + data.detail = '' + data.valueRange = { var.start, var.finish } end + callback(data) end -local function buildReturn(vm, source, callback) +local function buildLocalFunction(vm, source, used, callback) local value = source:bindFunction() if not value then return end - local hvr = hoverFunction('', value:getFunction()) + local name = getName(source.name) + local hvr = hoverFunction(name, value:getFunction()) if not hvr then return end local kind = SymbolKind.Function callback { - name = '', - -- 前端不支持多行 + name = name, detail = hvr.label:gsub('[\r\n]', ''), kind = kind, range = { source.start, source.finish }, - selectionRange = { source.start, source.start }, + selectionRange = { source.name.start, source.name.finish }, valueRange = { source.start, source.finish }, } end -local function buildSource(vm, source, callback) - if source:action() == 'local' then - buildLocal(vm, source, callback) + +local function buildFunction(vm, source, used, callback) + if used[source] then return end - if source:action() == 'set' then - buildSet(vm, source, callback) + local value = source:bindFunction() + if not value then return end - if source.type == 'return' then - for _, src in ipairs(source) do - buildReturn(vm, src, callback) - end + local name = getName(source.name) + local func = value:getFunction() + local hvr = hoverFunction(name, func, func:getObject()) + if not hvr then + return + end + local data = {} + data.name = name + data.detail = hvr.label:gsub('[\r\n]', '') + data.range = { source.start, source.finish } + data.valueRange = { source.start, source.finish } + if source.name then + data.selectionRange = { source.name.start, source.name.finish } + else + data.selectionRange = { source.start, source.start } + end + if func:getObject() then + data.kind = SymbolKind.Field + else + data.kind = SymbolKind.Function + end + callback(data) +end + +local function buildSource(vm, source, used, callback) + if source.type == 'local' then + buildLocal(vm, source, used, callback) + return + end + if source.type == 'set' then + buildSet(vm, source, used, callback) + return + end + if source.type == 'pair' then + buildPair(vm, source, used, callback) + return + end + if source.type == 'localfunction' then + buildLocalFunction(vm, source, used, callback) + return + end + if source.type == 'function' then + buildFunction(vm, source, used, callback) return end end @@ -212,13 +224,10 @@ local function packChild(symbols, finish, kind) end symbols[#symbols] = nil symbol.children = packChild(symbols, symbol.valueRange[2], symbol.kind) - if symbol.kind == SymbolKind.Class and kind == SymbolKind.Function then - else - if not t then - t = {} - end - t[#t+1] = symbol + if not t then + t = {} end + t[#t+1] = symbol end return t end @@ -226,7 +235,7 @@ end local function packSymbols(symbols) -- 按照start位置反向排序 table.sort(symbols, function (a, b) - return a.valueRange[1] > b.valueRange[1] + return a.range[1] > b.range[1] end) -- 处理嵌套 return packChild(symbols, math.maxinteger, SymbolKind.Function) @@ -234,9 +243,10 @@ end return function (vm) local symbols = {} + local used = {} for _, source in ipairs(vm.sources) do - buildSource(vm, source, function (data) + buildSource(vm, source, used, function (data) symbols[#symbols+1] = data end) end diff --git a/server/src/core/hover/hover.lua b/server/src/core/hover/hover.lua index c7aba17e..f09bfce4 100644 --- a/server/src/core/hover/hover.lua +++ b/server/src/core/hover/hover.lua @@ -220,5 +220,11 @@ return function (source, lsp, select) if source.type == 'name' and source:bindValue() then return hoverAsValue(source, lsp, select) end + if source.type == 'simple' then + source = source[#source] + if source.type == 'name' and source:bindValue() then + return hoverAsValue(source, lsp, select) + end + end return nil end diff --git a/server/src/core/hover/name.lua b/server/src/core/hover/name.lua index 52bcfef4..e5880884 100644 --- a/server/src/core/hover/name.lua +++ b/server/src/core/hover/name.lua @@ -1,4 +1,9 @@ +local getName = require 'core.name' + return function (source) + if not source then + return '' + end local value = source:bindValue() if not value then return '' @@ -22,67 +27,5 @@ return function (source) return name or '' end - local key - if declarat:get 'simple' then - local simple = declarat:get 'simple' - local chars = {} - for i, obj in ipairs(simple) do - if obj.type == 'name' then - chars[i] = obj[1] - elseif obj.type == 'index' then - chars[i] = '[?]' - elseif obj.type == 'call' then - chars[i] = '(?)' - elseif obj.type == ':' then - chars[i] = ':' - elseif obj.type == '.' then - chars[i] = '.' - else - chars[i] = '*' .. obj.type - end - if obj == declarat then - break - end - end - key = table.concat(chars) - elseif declarat.type == 'name' then - key = declarat[1] - elseif declarat.type == 'string' then - key = ('%q'):format(declarat[1]) - elseif declarat.type == 'number' or declarat.type == 'boolean' then - key = tostring(declarat[1]) - elseif declarat.type == 'simple' then - local chars = {} - for i, obj in ipairs(declarat) do - if obj.type == 'name' then - chars[i] = obj[1] - elseif obj.type == 'index' then - chars[i] = '[?]' - elseif obj.type == 'call' then - chars[i] = '(?)' - elseif obj.type == ':' then - chars[i] = ':' - elseif obj.type == '.' then - chars[i] = '.' - else - chars[i] = '*' .. obj.type - end - end - -- 这里有个特殊处理 - -- function mt:func() 以 mt.func 的形式调用时 - -- hover 显示为 mt.func(self) - if chars[#chars-1] == ':' then - if not source:get 'object' then - chars[#chars-1] = '.' - end - elseif chars[#chars-1] == '.' then - if source:get 'object' then - chars[#chars-1] = ':' - end - end - key = table.concat(chars) - else - key = '' - end - return key + return getName(declarat, source) end diff --git a/server/src/core/name.lua b/server/src/core/name.lua new file mode 100644 index 00000000..54947974 --- /dev/null +++ b/server/src/core/name.lua @@ -0,0 +1,70 @@ +return function (source, caller) + if not source then + return '' + end + local key + if source:get 'simple' then + local simple = source:get 'simple' + local chars = {} + for i, obj in ipairs(simple) do + if obj.type == 'name' then + chars[i] = obj[1] + elseif obj.type == 'index' then + chars[i] = '[?]' + elseif obj.type == 'call' then + chars[i] = '(?)' + elseif obj.type == ':' then + chars[i] = ':' + elseif obj.type == '.' then + chars[i] = '.' + else + chars[i] = '*' .. obj.type + end + if obj == source then + break + end + end + key = table.concat(chars) + elseif source.type == 'name' then + key = source[1] + elseif source.type == 'string' then + key = ('%q'):format(source[1]) + elseif source.type == 'number' or source.type == 'boolean' then + key = tostring(source[1]) + elseif source.type == 'simple' then + local chars = {} + for i, obj in ipairs(source) do + if obj.type == 'name' then + chars[i] = obj[1] + elseif obj.type == 'index' then + chars[i] = '[?]' + elseif obj.type == 'call' then + chars[i] = '(?)' + elseif obj.type == ':' then + chars[i] = ':' + elseif obj.type == '.' then + chars[i] = '.' + else + chars[i] = '*' .. obj.type + end + end + -- 这里有个特殊处理 + -- function mt:func() 以 mt.func 的形式调用时 + -- hover 显示为 mt.func(self) + if caller then + if chars[#chars-1] == ':' then + if not caller:get 'object' then + chars[#chars-1] = '.' + end + elseif chars[#chars-1] == '.' then + if caller:get 'object' then + chars[#chars-1] = ':' + end + end + end + key = table.concat(chars) + else + key = '' + end + return key +end -- cgit v1.2.3