summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/src/core/completion.lua121
-rw-r--r--server/src/core/document_symbol.lua4
-rw-r--r--server/src/core/hover/function.lua (renamed from server/src/core/hover_function.lua)0
-rw-r--r--server/src/core/hover/hover.lua (renamed from server/src/core/hover.lua)199
-rw-r--r--server/src/core/hover/init.lua1
-rw-r--r--server/src/core/hover/lib_function.lua194
-rw-r--r--server/src/core/hover/name.lua (renamed from server/src/core/hover_name.lua)0
-rw-r--r--server/test/completion/init.lua26
8 files changed, 326 insertions, 219 deletions
diff --git a/server/src/core/completion.lua b/server/src/core/completion.lua
index a4913ad8..a04ffc52 100644
--- a/server/src/core/completion.lua
+++ b/server/src/core/completion.lua
@@ -1,5 +1,6 @@
local findSource = require 'core.find_source'
-local hover = require 'core.hover'
+local getFunctionHover = require 'core.hover.function'
+local getFunctionHoverAsLib = require 'core.hover.lib_function'
local CompletionItemKind = {
Text = 1,
@@ -98,6 +99,86 @@ local function matchKey(me, other)
return true
end
+local function getDucumentation(name, value)
+ if value:getType() == 'function' then
+ local lib = value:getLib()
+ local hover
+ if lib then
+ hover = getFunctionHoverAsLib(name, lib)
+ else
+ hover = getFunctionHover(name, value:getFunction())
+ end
+ if not hover then
+ return nil
+ end
+ local text = ([[
+```lua
+%s
+```
+%s
+```lua
+%s
+```
+]]):format(hover.label or '', hover.description or '', hover.enum or '')
+ return {
+ kind = 'markdown',
+ value = text,
+ }
+ end
+ return nil
+end
+
+local function getDetail(value)
+ local literal = value:getLiteral()
+ local tp = type(literal)
+ if tp == 'boolean' then
+ return ('= %q'):format(literal)
+ elseif tp == 'string' then
+ return ('= %q'):format(literal)
+ elseif tp == 'number' then
+ if math.type(literal) == 'integer' then
+ return ('= %q'):format(literal)
+ else
+ local str = ('= %.16f'):format(literal)
+ local dot = str:find('.', 1, true)
+ local suffix = str:find('[0]+$', dot + 2)
+ if suffix then
+ return str:sub(1, suffix - 1)
+ else
+ return str
+ end
+ end
+ end
+ return nil
+end
+
+local function getKind(cata, value)
+ if value:getType() == 'function' then
+ local func = value:getFunction()
+ if func:getObject() then
+ return CompletionItemKind.Method
+ else
+ return CompletionItemKind.Function
+ end
+ end
+ if cata == 'field' then
+ local literal = value:getLiteral()
+ local tp = type(literal)
+ if tp == 'number' or tp == 'integer' or tp == 'string' then
+ return CompletionItemKind.Enum
+ end
+ end
+ return nil
+end
+
+local function getValueData(cata, name, value)
+ return {
+ documentation = getDucumentation(name, value),
+ detail = getDetail(value),
+ kind = getKind(cata, value),
+ }
+end
+
local function searchLocals(vm, source, word, callback)
for _, src in ipairs(vm.sources) do
local loc = src:bindLocal()
@@ -109,12 +190,26 @@ local function searchLocals(vm, source, word, callback)
and loc:close() >= source.finish
and matchKey(word, loc:getName())
then
- callback(loc:getName(), src, CompletionItemKind.Variable)
+ callback(loc:getName(), src, CompletionItemKind.Variable, getValueData('local', loc:getName(), loc:getValue()))
end
:: CONTINUE ::
end
end
+local function sortPairs(t)
+ local keys = {}
+ for k in pairs(t) do
+ keys[#keys+1] = k
+ end
+ table.sort(keys)
+ local i = 0
+ return function ()
+ i = i + 1
+ local k = keys[i]
+ return k, t[k]
+ end
+end
+
local function searchFields(vm, source, word, callback)
local parent = source:get 'parent'
if not parent then
@@ -129,13 +224,12 @@ local function searchFields(vm, source, word, callback)
goto CONTINUE
end
if matchKey(word, k) then
- map[#map+1] = k
+ map[k] = v
end
:: CONTINUE ::
end)
- table.sort(map)
- for _, k in ipairs(map) do
- callback(k, nil, CompletionItemKind.Field)
+ for k, v in sortPairs(map) do
+ callback(k, nil, CompletionItemKind.Field, getValueData('field', k, v))
end
end
@@ -147,6 +241,10 @@ local function searchAsGlobal(vm, source, word, callback)
searchFields(vm, source, word, callback)
end
+local function searchAsSuffix(vm, source, word, callback)
+ searchFields(vm, source, word, callback)
+end
+
local function searchSource(vm, source, word, callback)
if source:get 'global' then
searchAsGlobal(vm, source, word, callback)
@@ -156,6 +254,9 @@ local function searchSource(vm, source, word, callback)
searchAsGlobal(vm, source, word, callback)
return
end
+ if source:get 'simple' then
+ searchAsSuffix(vm, source, word, callback)
+ end
end
local function searchAllWords(vm, source, word, callback)
@@ -188,8 +289,12 @@ local function makeList(source, word)
if not data then
data = {}
end
- data.label = name
- data.kind = kind
+ if not data.label then
+ data.label = name
+ end
+ if not data.kind then
+ data.kind = kind
+ end
list[#list+1] = data
end, list
end
diff --git a/server/src/core/document_symbol.lua b/server/src/core/document_symbol.lua
index 199aab7b..8ca39bdd 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 hoverFunction = require 'core.hover.function'
+local hoverName = require 'core.hover.name'
local hover = require 'core.hover'
local SymbolKind = {
diff --git a/server/src/core/hover_function.lua b/server/src/core/hover/function.lua
index 6be90b06..6be90b06 100644
--- a/server/src/core/hover_function.lua
+++ b/server/src/core/hover/function.lua
diff --git a/server/src/core/hover.lua b/server/src/core/hover/hover.lua
index e99becdc..e07acf4a 100644
--- a/server/src/core/hover.lua
+++ b/server/src/core/hover/hover.lua
@@ -1,6 +1,7 @@
local findLib = require 'core.find_lib'
-local getFunctionHover = require 'core.hover_function'
-local buildValueName = require 'core.hover_name'
+local getFunctionHover = require 'core.hover.function'
+local getFunctionHoverAsLib = require 'core.hover.lib_function'
+local buildValueName = require 'core.hover.name'
local OriginTypes = {
['any'] = true,
@@ -15,200 +16,6 @@ local OriginTypes = {
['function'] = true,
}
-local function buildLibArgs(lib, object, select)
- if not lib.args then
- return ''
- end
- local start
- if object then
- start = 2
- if select then
- select = select + 1
- end
- else
- start = 1
- end
- local strs = {}
- for i = start, #lib.args do
- local arg = lib.args[i]
- if arg.optional then
- if i > start then
- strs[#strs+1] = ' ['
- else
- strs[#strs+1] = '['
- end
- end
- if i > start then
- strs[#strs+1] = ', '
- end
-
- local argStr = {}
- if i == select then
- argStr[#argStr+1] = '@ARG'
- end
- if arg.name then
- argStr[#argStr+1] = ('%s: '):format(arg.name)
- end
- if type(arg.type) == 'table' then
- argStr[#argStr+1] = table.concat(arg.type, '/')
- else
- argStr[#argStr+1] = arg.type or 'any'
- end
- if arg.default then
- argStr[#argStr+1] = ('(%q)'):format(arg.default)
- end
- if i == select then
- argStr[#argStr+1] = '@ARG'
- end
-
- for _, str in ipairs(argStr) do
- strs[#strs+1] = str
- end
- if arg.optional == 'self' then
- strs[#strs+1] = ']'
- end
- end
- for _, arg in ipairs(lib.args) do
- if arg.optional == 'after' then
- strs[#strs+1] = ']'
- end
- end
- local text = table.concat(strs)
- local argLabel = {}
- for i = 1, 2 do
- local pos = text:find('@ARG', 1, true)
- if pos then
- if i == 1 then
- argLabel[i] = pos
- else
- argLabel[i] = pos - 1
- end
- text = text:sub(1, pos-1) .. text:sub(pos+4)
- end
- end
- if #argLabel == 0 then
- argLabel = nil
- end
- return text, argLabel
-end
-
-local function buildLibReturns(lib)
- if not lib.returns then
- return ''
- end
- local strs = {}
- for i, rtn in ipairs(lib.returns) do
- if rtn.optional then
- if i > 1 then
- strs[#strs+1] = ' ['
- else
- strs[#strs+1] = '['
- end
- end
- if i > 1 then
- strs[#strs+1] = ', '
- end
- if rtn.name then
- strs[#strs+1] = ('%s: '):format(rtn.name)
- end
- if type(rtn.type) == 'table' then
- strs[#strs+1] = table.concat(rtn.type, '/')
- else
- strs[#strs+1] = rtn.type or 'any'
- end
- if rtn.default then
- strs[#strs+1] = ('(%q)'):format(rtn.default)
- end
- if rtn.optional == 'self' then
- strs[#strs+1] = ']'
- end
- end
- for _, rtn in ipairs(lib.returns) do
- if rtn.optional == 'after' then
- strs[#strs+1] = ']'
- end
- end
- return '\n -> ' .. table.concat(strs)
-end
-
-local function buildEnum(lib)
- if not lib.enums then
- return ''
- end
- local container = table.container()
- for _, enum in ipairs(lib.enums) do
- if not enum.name or (not enum.enum and not enum.code) then
- goto NEXT_ENUM
- end
- if not container[enum.name] then
- container[enum.name] = {}
- if lib.args then
- for _, arg in ipairs(lib.args) do
- if arg.name == enum.name then
- container[enum.name].type = arg.type
- break
- end
- end
- end
- if lib.returns then
- for _, rtn in ipairs(lib.returns) do
- if rtn.name == enum.name then
- container[enum.name].type = rtn.type
- break
- end
- end
- end
- end
- table.insert(container[enum.name], enum)
- ::NEXT_ENUM::
- end
- local strs = {}
- for name, enums in pairs(container) do
- local tp
- if type(enums.type) == 'table' then
- tp = table.concat(enums.type, '/')
- else
- tp = enums.type
- end
- strs[#strs+1] = ('\n%s: %s'):format(name, tp or 'any')
- for _, enum in ipairs(enums) do
- if enum.default then
- strs[#strs+1] = '\n -> '
- else
- strs[#strs+1] = '\n | '
- end
- if enum.code then
- strs[#strs+1] = tostring(enum.code)
- else
- strs[#strs+1] = ('%q'):format(enum.enum)
- end
- if enum.description then
- strs[#strs+1] = ' -- ' .. enum.description
- end
- end
- end
- return table.concat(strs)
-end
-
-local function getFunctionHoverAsLib(name, lib, object, select)
- local args, argLabel = buildLibArgs(lib, object, select)
- local returns = buildLibReturns(lib)
- local enum = buildEnum(lib)
- local tip = lib.description
- local headLen = #('function %s('):format(name)
- local title = ('function %s(%s)%s'):format(name, args, returns)
- if argLabel then
- argLabel[1] = argLabel[1] + headLen
- argLabel[2] = argLabel[2] + headLen
- end
- return {
- label = title,
- description = tip,
- enum = enum,
- argLabel = argLabel,
- }
-end
-
local function findClass(value)
-- 检查对象元表
local metaValue = value:getMetaTable()
diff --git a/server/src/core/hover/init.lua b/server/src/core/hover/init.lua
new file mode 100644
index 00000000..be5b5632
--- /dev/null
+++ b/server/src/core/hover/init.lua
@@ -0,0 +1 @@
+return require 'core.hover.hover'
diff --git a/server/src/core/hover/lib_function.lua b/server/src/core/hover/lib_function.lua
new file mode 100644
index 00000000..cb67c7f9
--- /dev/null
+++ b/server/src/core/hover/lib_function.lua
@@ -0,0 +1,194 @@
+
+local function buildLibArgs(lib, object, select)
+ if not lib.args then
+ return ''
+ end
+ local start
+ if object then
+ start = 2
+ if select then
+ select = select + 1
+ end
+ else
+ start = 1
+ end
+ local strs = {}
+ for i = start, #lib.args do
+ local arg = lib.args[i]
+ if arg.optional then
+ if i > start then
+ strs[#strs+1] = ' ['
+ else
+ strs[#strs+1] = '['
+ end
+ end
+ if i > start then
+ strs[#strs+1] = ', '
+ end
+
+ local argStr = {}
+ if i == select then
+ argStr[#argStr+1] = '@ARG'
+ end
+ if arg.name then
+ argStr[#argStr+1] = ('%s: '):format(arg.name)
+ end
+ if type(arg.type) == 'table' then
+ argStr[#argStr+1] = table.concat(arg.type, '/')
+ else
+ argStr[#argStr+1] = arg.type or 'any'
+ end
+ if arg.default then
+ argStr[#argStr+1] = ('(%q)'):format(arg.default)
+ end
+ if i == select then
+ argStr[#argStr+1] = '@ARG'
+ end
+
+ for _, str in ipairs(argStr) do
+ strs[#strs+1] = str
+ end
+ if arg.optional == 'self' then
+ strs[#strs+1] = ']'
+ end
+ end
+ for _, arg in ipairs(lib.args) do
+ if arg.optional == 'after' then
+ strs[#strs+1] = ']'
+ end
+ end
+ local text = table.concat(strs)
+ local argLabel = {}
+ for i = 1, 2 do
+ local pos = text:find('@ARG', 1, true)
+ if pos then
+ if i == 1 then
+ argLabel[i] = pos
+ else
+ argLabel[i] = pos - 1
+ end
+ text = text:sub(1, pos-1) .. text:sub(pos+4)
+ end
+ end
+ if #argLabel == 0 then
+ argLabel = nil
+ end
+ return text, argLabel
+end
+
+local function buildLibReturns(lib)
+ if not lib.returns then
+ return ''
+ end
+ local strs = {}
+ for i, rtn in ipairs(lib.returns) do
+ if rtn.optional then
+ if i > 1 then
+ strs[#strs+1] = ' ['
+ else
+ strs[#strs+1] = '['
+ end
+ end
+ if i > 1 then
+ strs[#strs+1] = ', '
+ end
+ if rtn.name then
+ strs[#strs+1] = ('%s: '):format(rtn.name)
+ end
+ if type(rtn.type) == 'table' then
+ strs[#strs+1] = table.concat(rtn.type, '/')
+ else
+ strs[#strs+1] = rtn.type or 'any'
+ end
+ if rtn.default then
+ strs[#strs+1] = ('(%q)'):format(rtn.default)
+ end
+ if rtn.optional == 'self' then
+ strs[#strs+1] = ']'
+ end
+ end
+ for _, rtn in ipairs(lib.returns) do
+ if rtn.optional == 'after' then
+ strs[#strs+1] = ']'
+ end
+ end
+ return '\n -> ' .. table.concat(strs)
+end
+
+local function buildEnum(lib)
+ if not lib.enums then
+ return ''
+ end
+ local container = table.container()
+ for _, enum in ipairs(lib.enums) do
+ if not enum.name or (not enum.enum and not enum.code) then
+ goto NEXT_ENUM
+ end
+ if not container[enum.name] then
+ container[enum.name] = {}
+ if lib.args then
+ for _, arg in ipairs(lib.args) do
+ if arg.name == enum.name then
+ container[enum.name].type = arg.type
+ break
+ end
+ end
+ end
+ if lib.returns then
+ for _, rtn in ipairs(lib.returns) do
+ if rtn.name == enum.name then
+ container[enum.name].type = rtn.type
+ break
+ end
+ end
+ end
+ end
+ table.insert(container[enum.name], enum)
+ ::NEXT_ENUM::
+ end
+ local strs = {}
+ for name, enums in pairs(container) do
+ local tp
+ if type(enums.type) == 'table' then
+ tp = table.concat(enums.type, '/')
+ else
+ tp = enums.type
+ end
+ strs[#strs+1] = ('\n%s: %s'):format(name, tp or 'any')
+ for _, enum in ipairs(enums) do
+ if enum.default then
+ strs[#strs+1] = '\n -> '
+ else
+ strs[#strs+1] = '\n | '
+ end
+ if enum.code then
+ strs[#strs+1] = tostring(enum.code)
+ else
+ strs[#strs+1] = ('%q'):format(enum.enum)
+ end
+ if enum.description then
+ strs[#strs+1] = ' -- ' .. enum.description
+ end
+ end
+ end
+ return table.concat(strs)
+end
+
+return function (name, lib, object, select)
+ local args, argLabel = buildLibArgs(lib, object, select)
+ local returns = buildLibReturns(lib)
+ local enum = buildEnum(lib)
+ local tip = lib.description
+ local headLen = #('function %s('):format(name)
+ local title = ('function %s(%s)%s'):format(name, args, returns)
+ if argLabel then
+ argLabel[1] = argLabel[1] + headLen
+ argLabel[2] = argLabel[2] + headLen
+ end
+ return {
+ label = title,
+ description = tip,
+ enum = enum,
+ argLabel = argLabel,
+ }
+end
diff --git a/server/src/core/hover_name.lua b/server/src/core/hover/name.lua
index 4faab3f1..4faab3f1 100644
--- a/server/src/core/hover_name.lua
+++ b/server/src/core/hover/name.lua
diff --git a/server/test/completion/init.lua b/server/test/completion/init.lua
index 3e7f9792..874b0948 100644
--- a/server/test/completion/init.lua
+++ b/server/test/completion/init.lua
@@ -182,40 +182,40 @@ ass@
}
TEST [[
-local t = {
- abc = 1,
-}
-t.a@
+local zabc = 1
+z@
]]
{
{
- label = 'abc',
- kind = CompletionItemKind.Enum,
+ label = 'zabc',
+ kind = CompletionItemKind.Variable,
detail = '= 1',
}
}
TEST [[
-local zabc = 1
+local zabc = 1.0
z@
]]
{
{
label = 'zabc',
kind = CompletionItemKind.Variable,
- detail = '= 1',
+ detail = '= 1.0',
}
}
TEST [[
-local zabc = 1.0
-z@
+local t = {
+ abc = 1,
+}
+t.a@
]]
{
{
- label = 'zabc',
- kind = CompletionItemKind.Variable,
- detail = '= 1.0',
+ label = 'abc',
+ kind = CompletionItemKind.Enum,
+ detail = '= 1',
}
}