diff options
-rw-r--r-- | changelog.md | 5 | ||||
-rw-r--r-- | script/core/definition.lua | 2 | ||||
-rw-r--r-- | script/core/jump-source.lua | 33 | ||||
-rw-r--r-- | script/core/reference.lua | 2 | ||||
-rw-r--r-- | script/core/type-definition.lua | 2 | ||||
-rw-r--r-- | script/parser/luadoc.lua | 52 | ||||
-rw-r--r-- | script/provider/provider.lua | 45 | ||||
-rw-r--r-- | test/tclient/init.lua | 1 | ||||
-rw-r--r-- | test/tclient/tests/jump-source.lua | 76 |
9 files changed, 189 insertions, 29 deletions
diff --git a/changelog.md b/changelog.md index 6ecdef04..4e9adbe3 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,11 @@ local fileName = root / 'script' / 'main.lua' -- `fileName` is `fspath` here ``` +* `NEW` `LuaDoc`: `---@source`: + ```lua + ---@source file:///xxx.c:50:20 + XXX = 1 -- when finding definitions of `XXX`, returns `file:///xxx.c:50:20` instead here + ``` * `NEW` diagnostics: * `unknown-operator` * `unreachable-code` diff --git a/script/core/definition.lua b/script/core/definition.lua index e4868532..ac2513e9 100644 --- a/script/core/definition.lua +++ b/script/core/definition.lua @@ -4,6 +4,7 @@ local vm = require 'vm' local findSource = require 'core.find-source' local guide = require 'parser.guide' local rpath = require 'workspace.require-path' +local jumpSource = require 'core.jump-source' local function sortResults(results) -- 先按照顺序排序 @@ -197,6 +198,7 @@ return function (uri, offset) end sortResults(results) + jumpSource(results) return results end diff --git a/script/core/jump-source.lua b/script/core/jump-source.lua new file mode 100644 index 00000000..76d7324b --- /dev/null +++ b/script/core/jump-source.lua @@ -0,0 +1,33 @@ +local guide = require 'parser.guide' + +---@param results table +return function (results) + for _, result in ipairs(results) do + if result.target.type == 'doc.field.name' then + local doc = result.target.parent.source + if doc then + result.uri = doc.source + result.target.uri = doc.source + result.target.start = guide.positionOf(doc.line - 1, 0) + result.target.finish = guide.positionOf(doc.line - 1, 0) + end + else + local target = result.target + if target.type == 'method' + or target.type == 'field' then + target = target.parent + end + if target.bindDocs then + for _, doc in ipairs(target.bindDocs) do + if doc.type == 'doc.source' + and doc.bindSource == target then + result.uri = doc.source + result.target.uri = doc.source + result.target.start = guide.positionOf(doc.line - 1, 0) + result.target.finish = guide.positionOf(doc.line - 1, 0) + end + end + end + end + end +end diff --git a/script/core/reference.lua b/script/core/reference.lua index 4c9c193d..a468afde 100644 --- a/script/core/reference.lua +++ b/script/core/reference.lua @@ -2,6 +2,7 @@ local guide = require 'parser.guide' local files = require 'files' local vm = require 'vm' local findSource = require 'core.find-source' +local jumpSource = require 'core.jump-source' local function sortResults(results) -- 先按照顺序排序 @@ -132,6 +133,7 @@ return function (uri, position) end sortResults(results) + jumpSource(results) return results end diff --git a/script/core/type-definition.lua b/script/core/type-definition.lua index d8434c8c..2140090b 100644 --- a/script/core/type-definition.lua +++ b/script/core/type-definition.lua @@ -4,6 +4,7 @@ local vm = require 'vm' local findSource = require 'core.find-source' local guide = require 'parser.guide' local rpath = require 'workspace.require-path' +local jumpSource = require 'core.jump-source' local function sortResults(results) -- 先按照顺序排序 @@ -164,6 +165,7 @@ return function (uri, offset) end sortResults(results) + jumpSource(results) return results end diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 37a1843d..91ed44c0 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -3,6 +3,7 @@ local re = require 'parser.relabel' local guide = require 'parser.guide' local compile = require 'parser.compile' local util = require 'utility' +local furi = require 'file-uri' local TokenTypes, TokenStarts, TokenFinishs, TokenContents, TokenMarks ---@type integer @@ -147,6 +148,7 @@ Symbol <- ({} { ---@field async? boolean ---@field versions? table[] ---@field names? parser.object[] +---@field source? parser.object local function parseTokens(text, offset) Ci = 0 @@ -1403,8 +1405,36 @@ local docSwitch = util.switch() return result end) + : case 'source' + : call(function (doc) + local fullSource = doc:sub(#'source' + 1) + if not fullSource or fullSource == '' then + return + end + fullSource = util.trim(fullSource) + if fullSource == '' then + return + end + local source, line = fullSource:match('^(.-):(%d+)$') + source = source or fullSource + line = tonumber(line) or 1 + local uri + if furi.split(source) then + uri = source + else + uri = furi.decode(source) + end + local result = { + type = 'doc.source', + start = getFinish(), + finish = getFinish(), + source = uri, + line = line, + } + return result + end) -local function convertTokens() +local function convertTokens(doc) local tp, text = nextToken() if not tp then return @@ -1417,7 +1447,7 @@ local function convertTokens() } return nil end - return docSwitch(text) + return docSwitch(text, doc) end local function trimTailComment(text) @@ -1457,7 +1487,7 @@ local function buildLuaDoc(comment) local doc = text:sub(startPos) parseTokens(doc, comment.start + startPos) - local result, rests = convertTokens() + local result, rests = convertTokens(doc) if result then result.range = comment.finish local finish = result.firstFinish or result.finish @@ -1527,7 +1557,8 @@ local function isContinuedDoc(lastDoc, nextDoc) if nextDoc.type ~= 'doc.field' and nextDoc.type ~= 'doc.operator' and nextDoc.type ~= 'doc.comment' - and nextDoc.type ~= 'doc.overload' then + and nextDoc.type ~= 'doc.overload' + and nextDoc.type ~= 'doc.source' then return false end end @@ -1603,7 +1634,8 @@ local function bindDoc(source, binded) if doc.type == 'doc.class' or doc.type == 'doc.deprecated' or doc.type == 'doc.version' - or doc.type == 'doc.module' then + or doc.type == 'doc.module' + or doc.type == 'doc.source' then if source.type == 'function' or isParam then goto CONTINUE @@ -1746,6 +1778,7 @@ end local function bindCommentsAndFields(binded) local class local comments = {} + local source for _, doc in ipairs(binded) do if doc.type == 'doc.class' then -- 多个class连续写在一起,只有最后一个class可以绑定source @@ -1760,6 +1793,10 @@ local function bindCommentsAndFields(binded) class.fields[#class.fields+1] = doc doc.class = class end + if source then + doc.source = source + source.bindSource = doc + end bindCommentsToDoc(doc, comments) comments = {} elseif doc.type == 'doc.operator' then @@ -1774,7 +1811,12 @@ local function bindCommentsAndFields(binded) comments = {} elseif doc.type == 'doc.comment' then comments[#comments+1] = doc + elseif doc.type == 'doc.source' then + source = doc + goto CONTINUE end + source = nil + ::CONTINUE:: end end diff --git a/script/provider/provider.lua b/script/provider/provider.lua index eb1362eb..18147e80 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -22,6 +22,7 @@ local inspect = require 'inspect' local markdown = require 'provider.markdown' local guide = require 'parser.guide' local fs = require 'bee.filesystem' +local jumpSource = require 'core.jump-source' ---@async local function updateConfig(uri) @@ -376,18 +377,16 @@ m.register 'textDocument/definition' { for i, info in ipairs(result) do local targetUri = info.uri if targetUri then - if files.exists(targetUri) then - if client.getAbility 'textDocument.definition.linkSupport' then - response[i] = converter.locationLink(targetUri - , converter.packRange(targetUri, info.target.start, info.target.finish) - , converter.packRange(targetUri, info.target.start, info.target.finish) - , converter.packRange(uri, info.source.start, info.source.finish) - ) - else - response[i] = converter.location(targetUri - , converter.packRange(targetUri, info.target.start, info.target.finish) - ) - end + if client.getAbility 'textDocument.definition.linkSupport' then + response[i] = converter.locationLink(targetUri + , converter.packRange(targetUri, info.target.start, info.target.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) + , converter.packRange(uri, info.source.start, info.source.finish) + ) + else + response[i] = converter.location(targetUri + , converter.packRange(targetUri, info.target.start, info.target.finish) + ) end end end @@ -418,18 +417,16 @@ m.register 'textDocument/typeDefinition' { for i, info in ipairs(result) do local targetUri = info.uri if targetUri then - if files.exists(targetUri) then - if client.getAbility 'textDocument.typeDefinition.linkSupport' then - response[i] = converter.locationLink(targetUri - , converter.packRange(targetUri, info.target.start, info.target.finish) - , converter.packRange(targetUri, info.target.start, info.target.finish) - , converter.packRange(uri, info.source.start, info.source.finish) - ) - else - response[i] = converter.location(targetUri - , converter.packRange(targetUri, info.target.start, info.target.finish) - ) - end + if client.getAbility 'textDocument.typeDefinition.linkSupport' then + response[i] = converter.locationLink(targetUri + , converter.packRange(targetUri, info.target.start, info.target.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) + , converter.packRange(uri, info.source.start, info.source.finish) + ) + else + response[i] = converter.location(targetUri + , converter.packRange(targetUri, info.target.start, info.target.finish) + ) end end end diff --git a/test/tclient/init.lua b/test/tclient/init.lua index 070cf337..80aae53a 100644 --- a/test/tclient/init.lua +++ b/test/tclient/init.lua @@ -8,4 +8,5 @@ require 'tclient.tests.resolve-completion' require 'tclient.tests.performance-jass-common' require 'tclient.tests.hover-pairs' require 'tclient.tests.change-workspace-folder' +require 'tclient.tests.jump-source' require 'tclient.tests.build-meta' diff --git a/test/tclient/tests/jump-source.lua b/test/tclient/tests/jump-source.lua new file mode 100644 index 00000000..ff679826 --- /dev/null +++ b/test/tclient/tests/jump-source.lua @@ -0,0 +1,76 @@ +local lclient = require 'lclient' +local util = require 'utility' +local ws = require 'workspace' +local files = require 'files' +local furi = require 'file-uri' +local fs = require 'bee.filesystem' + +---@async +lclient():start(function (client) + client:registerFakers() + client:initialize() + + ws.awaitReady() + + client:notify('textDocument/didOpen', { + textDocument = { + uri = furi.encode('1.lua'), + languageId = 'lua', + version = 0, + text = [[ +---@class AAA +---@source file:///xxx.lua:50 +---@field x number +local mt = {} + +---@source file:///yyy.lua:30 +function mt:ff() end +]] + } + }) + + client:notify('textDocument/didOpen', { + textDocument = { + uri = furi.encode('main.lua'), + languageId = 'lua', + version = 0, + text = [[ +---@type AAA +local a + +print(a.x) +print(a.ff) +]] + } + }) + + local locations = client:awaitRequest('textDocument/definition', { + textDocument = { uri = furi.encode('main.lua') }, + position = { line = 3, character = 9 }, + }) + + assert(util.equal(locations, { + { + uri = 'file:///xxx.lua', + range = { + start = { line = 49, character = 0 }, + ['end'] = { line = 49, character = 0 }, + } + } + })) + + local locations = client:awaitRequest('textDocument/definition', { + textDocument = { uri = furi.encode('main.lua') }, + position = { line = 4, character = 9 }, + }) + + assert(util.equal(locations, { + { + uri = 'file:///yyy.lua', + range = { + start = { line = 29, character = 0 }, + ['end'] = { line = 29, character = 0 }, + } + } + })) +end) |