diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2019-11-22 23:26:32 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2019-11-22 23:26:32 +0800 |
commit | d0ff66c9abe9d6abbca12fd811e0c3cb69c1033a (patch) | |
tree | bb34518d70b85de7656dbdbe958dfa221a3ff3b3 /script/src/method/textDocument | |
parent | 0a2c2ad15e1ec359171fb0dd4c72e57c5b66e9ba (diff) | |
download | lua-language-server-d0ff66c9abe9d6abbca12fd811e0c3cb69c1033a.zip |
整理一下目录结构
Diffstat (limited to 'script/src/method/textDocument')
-rw-r--r-- | script/src/method/textDocument/codeAction.lua | 23 | ||||
-rw-r--r-- | script/src/method/textDocument/completion.lua | 104 | ||||
-rw-r--r-- | script/src/method/textDocument/definition.lua | 88 | ||||
-rw-r--r-- | script/src/method/textDocument/didChange.lua | 16 | ||||
-rw-r--r-- | script/src/method/textDocument/didClose.lua | 5 | ||||
-rw-r--r-- | script/src/method/textDocument/didOpen.lua | 5 | ||||
-rw-r--r-- | script/src/method/textDocument/documentHighlight.lua | 37 | ||||
-rw-r--r-- | script/src/method/textDocument/documentSymbol.lua | 72 | ||||
-rw-r--r-- | script/src/method/textDocument/foldingRange.lua | 57 | ||||
-rw-r--r-- | script/src/method/textDocument/hover.lua | 44 | ||||
-rw-r--r-- | script/src/method/textDocument/implementation.lua | 108 | ||||
-rw-r--r-- | script/src/method/textDocument/onTypeFormatting.lua | 14 | ||||
-rw-r--r-- | script/src/method/textDocument/publishDiagnostics.lua | 163 | ||||
-rw-r--r-- | script/src/method/textDocument/references.lua | 86 | ||||
-rw-r--r-- | script/src/method/textDocument/rename.lua | 50 | ||||
-rw-r--r-- | script/src/method/textDocument/signatureHelp.lua | 50 |
16 files changed, 922 insertions, 0 deletions
diff --git a/script/src/method/textDocument/codeAction.lua b/script/src/method/textDocument/codeAction.lua new file mode 100644 index 00000000..3c6e8d49 --- /dev/null +++ b/script/src/method/textDocument/codeAction.lua @@ -0,0 +1,23 @@ +local core = require 'core' + +return function (lsp, params) + local uri = params.textDocument.uri + local vm, lines = lsp:getVM(uri) + if not vm then + return + end + local diagnostics = params.context.diagnostics + local range = params.range + + local results = core.codeAction(lsp + , uri + , diagnostics + , range + ) + + if #results == 0 then + return nil + end + + return results +end diff --git a/script/src/method/textDocument/completion.lua b/script/src/method/textDocument/completion.lua new file mode 100644 index 00000000..4c7581df --- /dev/null +++ b/script/src/method/textDocument/completion.lua @@ -0,0 +1,104 @@ +local core = require 'core' +local parser = require 'parser' + +local function posToRange(lines, start, finish) + local start_row, start_col = lines:rowcol(start) + local finish_row, finish_col = lines:rowcol(finish) + return { + start = { + line = start_row - 1, + character = start_col - 1, + }, + ['end'] = { + line = finish_row - 1, + character = finish_col, + }, + } +end + +local function fastCompletion(lsp, params, lines) + local uri = params.textDocument.uri + local text, oldText = lsp:getText(uri) + -- lua是从1开始的,因此都要+1 + local position = lines:positionAsChar(params.position.line + 1, params.position.character) + + local vm = lsp:getVM(uri) + if not vm then + vm = lsp:loadVM(uri) + if not vm then + return nil + end + end + + local items = core.completion(vm, text, position, oldText) + if not items or #items == 0 then + vm = lsp:loadVM(uri) + if not vm then + return nil + end + items = core.completion(vm, text, position) + if not items or #items == 0 then + return nil + end + end + + return items +end + +local function finishCompletion(lsp, params, lines) + local uri = params.textDocument.uri + local text = lsp:getText(uri) + -- lua是从1开始的,因此都要+1 + local position = lines:positionAsChar(params.position.line + 1, params.position.character) + + local vm = lsp:loadVM(uri) + if not vm then + return nil + end + + local items = core.completion(vm, text, position) + if not items or #items == 0 then + return nil + end + + return items +end + +return function (lsp, params) + local uri = params.textDocument.uri + local text, oldText = lsp:getText(uri) + if not text then + return nil + end + + local lines = parser:lines(text, 'utf8') + local items = fastCompletion(lsp, params, lines) + --local items = finishCompletion(lsp, params, lines) + if not items then + return nil + end + + for i, item in ipairs(items) do + item.sortText = ('%04d'):format(i) + item.insertTextFormat = 2 + item.insertText = item.insertText or item.label + if item.textEdit then + item.textEdit.range = posToRange(lines, item.textEdit.start, item.textEdit.finish) + item.textEdit.start = nil + item.textEdit.finish = nil + end + if item.additionalTextEdits then + for _, textEdit in ipairs(item.additionalTextEdits) do + textEdit.range = posToRange(lines, textEdit.start, textEdit.finish) + textEdit.start = nil + textEdit.finish = nil + end + end + end + + local response = { + isIncomplete = true, + items = items, + } + return response +end diff --git a/script/src/method/textDocument/definition.lua b/script/src/method/textDocument/definition.lua new file mode 100644 index 00000000..dbf9e41c --- /dev/null +++ b/script/src/method/textDocument/definition.lua @@ -0,0 +1,88 @@ +local core = require 'core' + +local function findResult(lsp, uri, position) + local vm = lsp:getVM(uri) + + local positions, isGlobal = core.definition(vm, position, 'definition') + if not positions then + return nil, isGlobal + end + + local locations = {} + for i, position in ipairs(positions) do + local start, finish, valueUri = position[1], position[2], (position[3] or uri) + local vm, valueLines = lsp:getVM(valueUri) + if valueLines then + local start_row, start_col = valueLines:rowcol(start) + local finish_row, finish_col = valueLines:rowcol(finish) + locations[#locations+1] = { + uri = valueUri, + range = { + start = { + line = start_row - 1, + character = start_col - 1, + }, + ['end'] = { + line = finish_row - 1, + -- 这里不用-1,因为前端期待的是匹配完成后的位置 + character = finish_col, + }, + } + } + elseif vm then + locations[#locations+1] = { + uri = valueUri, + range = { + start = { + line = 0, + character = 0, + }, + ['end'] = { + line = 0, + character = 0, + }, + } + } + end + end + + if #locations == 0 then + return nil, isGlobal + end + + return locations, isGlobal +end + +local LastTask + +---@param lsp LSP +---@param params table +return function (lsp, params) + local uri = params.textDocument.uri + local vm, lines = lsp:loadVM(uri) + if not vm then + return nil + end + + if LastTask then + LastTask:remove() + LastTask = nil + end + + -- lua是从1开始的,因此都要+1 + local position = lines:positionAsChar(params.position.line + 1, params.position.character) + + return function (response) + local clock = os.clock() + LastTask = ac.loop(0.1, function () + local result, isGlobal = findResult(lsp, uri, position) + if isGlobal and lsp:isWaitingCompile() and os.clock() - clock < 1 then + return + end + response(result) + LastTask:remove() + LastTask = nil + end) + LastTask:onTimer() + end +end diff --git a/script/src/method/textDocument/didChange.lua b/script/src/method/textDocument/didChange.lua new file mode 100644 index 00000000..82e6c096 --- /dev/null +++ b/script/src/method/textDocument/didChange.lua @@ -0,0 +1,16 @@ +return function (lsp, params) + local doc = params.textDocument + local change = params.contentChanges + if lsp.workspace then + local path = lsp.workspace:relativePathByUri(doc.uri) + if not path or not lsp.workspace:isLuaFile(path) then + return + end + if not lsp:isOpen(doc.uri) and lsp.workspace.gitignore(path:string()) then + return + end + end + -- TODO 支持差量更新 + lsp:saveText(doc.uri, doc.version, change[1].text) + return true +end diff --git a/script/src/method/textDocument/didClose.lua b/script/src/method/textDocument/didClose.lua new file mode 100644 index 00000000..589b212f --- /dev/null +++ b/script/src/method/textDocument/didClose.lua @@ -0,0 +1,5 @@ +return function (lsp, params) + local doc = params.textDocument + lsp:close(doc.uri) + return true +end diff --git a/script/src/method/textDocument/didOpen.lua b/script/src/method/textDocument/didOpen.lua new file mode 100644 index 00000000..e2a67fd2 --- /dev/null +++ b/script/src/method/textDocument/didOpen.lua @@ -0,0 +1,5 @@ +return function (lsp, params) + local doc = params.textDocument + lsp:open(doc.uri, doc.version, doc.text) + return true +end diff --git a/script/src/method/textDocument/documentHighlight.lua b/script/src/method/textDocument/documentHighlight.lua new file mode 100644 index 00000000..377ffcdf --- /dev/null +++ b/script/src/method/textDocument/documentHighlight.lua @@ -0,0 +1,37 @@ +local core = require 'core' + +return function (lsp, params) + local uri = params.textDocument.uri + local vm, lines = lsp:loadVM(uri) + if not vm then + return nil + end + local position = lines:positionAsChar(params.position.line + 1, params.position.character) + local positions = core.highlight(vm, position) + if not positions then + return nil + end + + local result = {} + for i, position in ipairs(positions) do + local start, finish = position[1], position[2] + local start_row, start_col = lines:rowcol(start) + local finish_row, finish_col = lines:rowcol(finish) + result[i] = { + range = { + start = { + line = start_row - 1, + character = start_col - 1, + }, + ['end'] = { + line = finish_row - 1, + -- 这里不用-1,因为前端期待的是匹配完成后的位置 + character = finish_col, + }, + }, + kind = position[3], + } + end + + return result +end diff --git a/script/src/method/textDocument/documentSymbol.lua b/script/src/method/textDocument/documentSymbol.lua new file mode 100644 index 00000000..a4b0c3b7 --- /dev/null +++ b/script/src/method/textDocument/documentSymbol.lua @@ -0,0 +1,72 @@ +local core = require 'core' +local lang = require 'language' + +local timerCache = {} + +local function posToRange(lines, start, finish) + local start_row, start_col = lines:rowcol(start) + local finish_row, finish_col = lines:rowcol(finish) + return { + start = { + line = start_row - 1, + character = start_col - 1, + }, + ['end'] = { + line = finish_row - 1, + character = finish_col, + }, + } +end + +local function convertRange(lines, symbol) + symbol.range = posToRange(lines, symbol.range[1], symbol.range[2]) + symbol.selectionRange = posToRange(lines, symbol.selectionRange[1], symbol.selectionRange[2]) + if symbol.name == '' then + symbol.name = lang.script.SYMBOL_ANONYMOUS + end + + if symbol.children then + for _, child in ipairs(symbol.children) do + convertRange(lines, child) + end + end +end + +return function (lsp, params) + local uri = params.textDocument.uri + + if timerCache[uri] then + timerCache[uri]:remove() + timerCache[uri] = nil + end + + return function (response) + local clock = os.clock() + timerCache[uri] = ac.loop(0.1, function (t) + local vm, lines = lsp:getVM(uri) + if not vm then + if os.clock() - clock > 10 then + t:remove() + timerCache[uri] = nil + response(nil) + end + return + end + + t:remove() + timerCache[uri] = nil + + local symbols = core.documentSymbol(vm) + if not symbols then + response(nil) + return + end + + for _, symbol in ipairs(symbols) do + convertRange(lines, symbol) + end + + response(symbols) + end) + end +end diff --git a/script/src/method/textDocument/foldingRange.lua b/script/src/method/textDocument/foldingRange.lua new file mode 100644 index 00000000..0320b422 --- /dev/null +++ b/script/src/method/textDocument/foldingRange.lua @@ -0,0 +1,57 @@ +local core = require 'core' + +local timerCache = {} + +local function convertRange(lines, range) + local start_row, start_col = lines:rowcol(range.start) + local finish_row, finish_col = lines:rowcol(range.finish) + local result = { + startLine = start_row - 1, + endLine = finish_row - 2, + kind = range.kind, + } + if result.startLine >= result.endLine then + return nil + end + return result +end + +return function (lsp, params) + local uri = params.textDocument.uri + if timerCache[uri] then + timerCache[uri]:remove() + timerCache[uri] = nil + end + + return function (response) + local clock = os.clock() + timerCache[uri] = ac.loop(0.1, function (t) + local vm, lines = lsp:getVM(uri) + if not vm then + if os.clock() - clock > 10 then + t:remove() + timerCache[uri] = nil + response(nil) + end + return + end + + t:remove() + timerCache[uri] = nil + + local comments = lsp:getComments(uri) + local ranges = core.foldingRange(vm, comments) + if not ranges then + response(nil) + return + end + + local results = {} + for _, range in ipairs(ranges) do + results[#results+1] = convertRange(lines, range) + end + + response(results) + end) + end +end diff --git a/script/src/method/textDocument/hover.lua b/script/src/method/textDocument/hover.lua new file mode 100644 index 00000000..f8dba27c --- /dev/null +++ b/script/src/method/textDocument/hover.lua @@ -0,0 +1,44 @@ +local core = require 'core' + +return function (lsp, params) + local uri = params.textDocument.uri + local vm, lines = lsp:loadVM(uri) + if not vm then + return nil + end + -- lua是从1开始的,因此都要+1 + local position = lines:positionAsChar(params.position.line + 1, params.position.character) + + local source = core.findSource(vm, position) + if not source then + return nil + end + + local hover = core.hover(source, lsp) + if not hover then + return nil + end + + local text = ([[ +```lua +%s +``` +```lua +%s +``` +%s +```lua +%s +``` +%s +]]):format(hover.label or '', hover.overloads or '', hover.description or '', hover.enum or '', hover.doc or '') + + local response = { + contents = { + value = text:gsub("```lua\n\n```", ""), + kind = 'markdown', + } + } + + return response +end diff --git a/script/src/method/textDocument/implementation.lua b/script/src/method/textDocument/implementation.lua new file mode 100644 index 00000000..14e2f24c --- /dev/null +++ b/script/src/method/textDocument/implementation.lua @@ -0,0 +1,108 @@ +local core = require 'core' + +local function checkWorkSpaceComplete(lsp, source) + if not source:bindValue() then + return + end + if not source:bindValue():get 'cross file' then + return + end + lsp:checkWorkSpaceComplete() +end + +local function findResult(lsp, params) + local uri = params.textDocument.uri + local vm, lines = lsp:loadVM(uri) + if not vm then + return nil + end + -- lua是从1开始的,因此都要+1 + local position = lines:positionAsChar(params.position.line + 1, params.position.character) + local source = core.findSource(vm, position) + if not source then + return nil + end + + checkWorkSpaceComplete(lsp, source) + + local positions = core.implementation(vm, source, lsp) + if not positions then + return nil + end + + local locations = {} + for i, position in ipairs(positions) do + local start, finish, valueUri = position[1], position[2], (position[3] or uri) + local _, valueLines = lsp:loadVM(valueUri) + if valueLines then + local start_row, start_col = valueLines:rowcol(start) + local finish_row, finish_col = valueLines:rowcol(finish) + locations[#locations+1] = { + uri = valueUri, + range = { + start = { + line = start_row - 1, + character = start_col - 1, + }, + ['end'] = { + line = finish_row - 1, + -- 这里不用-1,因为前端期待的是匹配完成后的位置 + character = finish_col, + }, + } + } + else + locations[#locations+1] = { + uri = valueUri, + range = { + start = { + line = 0, + character = 0, + }, + ['end'] = { + line = 0, + character = 0, + }, + } + } + end + end + + if #locations == 0 then + return nil + end + + return locations +end + +local LastTask + +return function (lsp, params) + if LastTask then + LastTask:remove() + LastTask = nil + end + local result = findResult(lsp, params) + if result then + return result + end + return function (response) + local count = 0 + LastTask = ac.loop(0.1, function () + local result = findResult(lsp, params) + if result then + LastTask:remove() + LastTask = nil + response(result) + return + end + count = count + 1 + if lsp:isWaitingCompile() and count < 10 then + return + end + LastTask:remove() + LastTask = nil + response(nil) + end) + end +end diff --git a/script/src/method/textDocument/onTypeFormatting.lua b/script/src/method/textDocument/onTypeFormatting.lua new file mode 100644 index 00000000..fc9cbdc9 --- /dev/null +++ b/script/src/method/textDocument/onTypeFormatting.lua @@ -0,0 +1,14 @@ +return function (lsp, params) + local uri = params.textDocument.uri + local vm, lines = lsp:loadVM(uri) + --log.debug(table.dump(params)) + if not vm then + return nil + end + local position = lines:position(params.position.line + 1, params.position.character) + local ch = params.ch + local options = params.options + local tabSize = options.tabSize + local insertSpaces = options.insertSpaces + return nil +end diff --git a/script/src/method/textDocument/publishDiagnostics.lua b/script/src/method/textDocument/publishDiagnostics.lua new file mode 100644 index 00000000..c767e934 --- /dev/null +++ b/script/src/method/textDocument/publishDiagnostics.lua @@ -0,0 +1,163 @@ +local core = require 'core' +local lang = require 'language' +local config = require 'config' + +local DiagnosticSeverity = { + Error = 1, + Warning = 2, + Information = 3, + Hint = 4, +} + +--[[ +/** + * Represents a related message and source code location for a diagnostic. This should be + * used to point to code locations that cause or related to a diagnostics, e.g when duplicating + * a symbol in a scope. + */ +export interface DiagnosticRelatedInformation { + /** + * The location of this related diagnostic information. + */ + location: Location; + + /** + * The message of this related diagnostic information. + */ + message: string; +} +]]-- + +local function getRange(start, finish, lines) + local start_row, start_col = lines:rowcol(start) + local finish_row, finish_col = lines:rowcol(finish) + return { + start = { + line = start_row - 1, + character = start_col - 1, + }, + ['end'] = { + line = finish_row - 1, + -- 这里不用-1,因为前端期待的是匹配完成后的位置 + character = finish_col, + }, + } +end + +local function createInfo(lsp, data, lines) + local diagnostic = { + source = lang.script.DIAG_DIAGNOSTICS, + range = getRange(data.start, data.finish, lines), + severity = data.level, + message = data.message, + code = data.code, + tags = data.tags, + } + if data.related then + local related = {} + for _, info in ipairs(data.related) do + local _, lines = lsp:getVM(info.uri) + if lines then + local message = info.message + if not message then + local start_line = lines:rowcol(info.start) + local finish_line = lines:rowcol(info.finish) + local chars = {} + for n = start_line, finish_line do + chars[#chars+1] = lines:line(n) + end + message = table.concat(chars, '\n') + end + related[#related+1] = { + message = message, + location = { + uri = info.uri, + range = getRange(info.start, info.finish, lines), + } + } + end + end + diagnostic.relatedInformation = related + end + return diagnostic +end + +local function buildError(err, lines, uri) + local diagnostic = { + source = lang.script.DIAG_SYNTAX_CHECK, + message = lang.script('PARSER_'..err.type, err.info) + } + if err.version then + local currentVersion = err.info and err.info.version or config.config.runtime.version + if type(err.version) == 'table' then + diagnostic.message = ('%s(%s)'):format(diagnostic.message, lang.script('DIAG_NEED_VERSION', table.concat(err.version, '/'), currentVersion)) + else + diagnostic.message = ('%s(%s)'):format(diagnostic.message, lang.script('DIAG_NEED_VERSION', err.version, currentVersion)) + end + end + if err.level == 'error' then + diagnostic.severity = DiagnosticSeverity.Error + else + diagnostic.severity = DiagnosticSeverity.Warning + end + local startrow, startcol = lines:rowcol(err.start) + local endrow, endcol = lines:rowcol(err.finish) + if err.type == 'UNKNOWN' then + local _, max = lines:range(endrow) + endcol = max + end + local range = { + start = { + line = startrow - 1, + character = startcol - 1, + }, + ['end'] = { + line = endrow - 1, + character = endcol, + }, + } + diagnostic.range = range + + local related = err.info and err.info.related + if related then + local start_line = lines:rowcol(related[1]) + local finish_line = lines:rowcol(related[2]) + local chars = {} + for n = start_line, finish_line do + chars[#chars+1] = lines:line(n) + end + local message = table.concat(chars, '\n') + diagnostic.relatedInformation = { + { + message = message, + location = { + uri = uri, + range = getRange(related[1], related[2], lines), + } + } + } + end + return diagnostic +end + +return function (lsp, params) + local vm = params.vm + local lines = params.lines + local uri = params.uri + local errs = lsp:getAstErrors(uri) + + local diagnostics = {} + if vm then + local datas = core.diagnostics(vm, lines, uri) + for _, data in ipairs(datas) do + diagnostics[#diagnostics+1] = createInfo(lsp, data, lines) + end + end + if errs then + for _, err in ipairs(errs) do + diagnostics[#diagnostics+1] = buildError(err, lines, uri) + end + end + + return diagnostics +end diff --git a/script/src/method/textDocument/references.lua b/script/src/method/textDocument/references.lua new file mode 100644 index 00000000..0a198323 --- /dev/null +++ b/script/src/method/textDocument/references.lua @@ -0,0 +1,86 @@ +local core = require 'core' +local LastTask + +local function findReferences(lsp, uri, position) + local vm = lsp:getVM(uri) + + local positions, isGlobal = core.definition(vm, position, 'reference') + if not positions then + return nil, isGlobal + end + + local locations = {} + for i, position in ipairs(positions) do + local start, finish, valueUri = position[1], position[2], (position[3] or uri) + local vm, valueLines = lsp:getVM(valueUri) + if valueLines then + local start_row, start_col = valueLines:rowcol(start) + local finish_row, finish_col = valueLines:rowcol(finish) + locations[#locations+1] = { + uri = valueUri, + range = { + start = { + line = start_row - 1, + character = start_col - 1, + }, + ['end'] = { + line = finish_row - 1, + -- 这里不用-1,因为前端期待的是匹配完成后的位置 + character = finish_col, + }, + } + } + elseif vm then + locations[#locations+1] = { + uri = valueUri, + range = { + start = { + line = 0, + character = 0, + }, + ['end'] = { + line = 0, + character = 0, + }, + } + } + end + end + + if #locations == 0 then + return nil, isGlobal + end + + return locations, isGlobal +end + +return function (lsp, params) + local uri = params.textDocument.uri + local declarat = params.context.includeDeclaration + local vm, lines = lsp:loadVM(uri) + if not vm then + return nil + end + + if LastTask then + LastTask:remove() + LastTask = nil + end + + -- lua是从1开始的,因此都要+1 + local position = lines:positionAsChar(params.position.line + 1, params.position.character) + + return function (response) + local clock = os.clock() + LastTask = ac.loop(0.1, function () + local positions, isGlobal = findReferences(lsp, uri, position) + if isGlobal and lsp:isWaitingCompile() and os.clock() - clock < 5 then + return + end + response(positions) + LastTask:remove() + LastTask = nil + end) + LastTask:onTimer() + end +end diff --git a/script/src/method/textDocument/rename.lua b/script/src/method/textDocument/rename.lua new file mode 100644 index 00000000..6da9c721 --- /dev/null +++ b/script/src/method/textDocument/rename.lua @@ -0,0 +1,50 @@ +local core = require 'core' + +return function (lsp, params) + local uri = params.textDocument.uri + local newName = params.newName + local vm, lines = lsp:loadVM(uri) + if not vm then + return {} + end + local position = lines:positionAsChar(params.position.line + 1, params.position.character) + local positions = core.rename(vm, position, newName) + if not positions then + return {} + end + + local changes = {} + for _, position in ipairs(positions) do + local start, finish, uri = position[1], position[2], position[3] + local _, lines = lsp:getVM(uri) + if not lines then + goto CONTINUE + end + local start_row, start_col = lines:rowcol(start) + local finish_row, finish_col = lines:rowcol(finish) + if not changes[uri] then + changes[uri] = {} + end + changes[uri][#changes[uri]+1] = { + newText = newName, + range = { + start = { + line = start_row - 1, + character = start_col - 1, + }, + ['end'] = { + line = finish_row - 1, + -- 这里不用-1,因为前端期待的是匹配完成后的位置 + character = finish_col, + }, + } + } + ::CONTINUE:: + end + + local response = { + changes = changes, + } + + return response +end diff --git a/script/src/method/textDocument/signatureHelp.lua b/script/src/method/textDocument/signatureHelp.lua new file mode 100644 index 00000000..01d6289d --- /dev/null +++ b/script/src/method/textDocument/signatureHelp.lua @@ -0,0 +1,50 @@ +local core = require 'core' + +return function (lsp, params) + local uri = params.textDocument.uri + local vm, lines = lsp:loadVM(uri) + if not vm then + return + end + local position = lines:position(params.position.line + 1, params.position.character + 1) + local hovers = core.signature(vm, position) + if not hovers then + return + end + + local hover = hovers[1] + local desc = {} + desc[#desc+1] = hover.description + local active + local signatures = {} + for i, hover in ipairs(hovers) do + local signature = { + label = hover.label, + documentation = { + kind = 'markdown', + value = table.concat(desc, '\n'), + }, + } + if hover.argLabel then + if not active then + active = i + end + signature.parameters = { + { + label = { + hover.argLabel[1] - 1, + hover.argLabel[2], + } + } + } + end + signatures[i] = signature + end + + local response = { + signatures = signatures, + activeSignature = active and active - 1 or 0, + } + + return response +end |