diff options
-rw-r--r-- | .luarc.json | 5 | ||||
-rw-r--r-- | changelog.md | 1 | ||||
-rw-r--r-- | script/core/document-symbol.lua | 113 | ||||
-rw-r--r-- | script/parser/compile.lua | 6 | ||||
-rw-r--r-- | test/document_symbol/init.lua | 95 |
5 files changed, 181 insertions, 39 deletions
diff --git a/.luarc.json b/.luarc.json index 64e09c46..b441d426 100644 --- a/.luarc.json +++ b/.luarc.json @@ -41,6 +41,11 @@ ], "checkThirdParty": false }, + "typeFormat": { + "config": { + "format_line": "false" + } + }, "type": { "castNumberToInteger": false } diff --git a/changelog.md b/changelog.md index f342fa69..9ef80713 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ # changelog ## 3.5.4 +* `CHG` `document-symbol`: redesigned to better support for `Sticky Scroll` feature of VSCode * `FIX` `diagnostics.workspaceDelay` can not prevent first workspace diagnostic * `FIX` [#1476](https://github.com/sumneko/lua-language-server/issues/1476) diff --git a/script/core/document-symbol.lua b/script/core/document-symbol.lua index 2c9caafb..6fbd63f3 100644 --- a/script/core/document-symbol.lua +++ b/script/core/document-symbol.lua @@ -3,38 +3,31 @@ local files = require 'files' local guide = require 'parser.guide' local define = require 'proto.define' local util = require 'utility' -local vm = require 'vm' +local subber = require 'core.substring' -local function buildName(source, text) - local uri = guide.getUri(source) - local state = files.getState(uri) - local startOffset = guide.positionToOffset(state, source.start) +local function buildName(source, sub) if source.type == 'setmethod' or source.type == 'getmethod' then if source.method then - local finishOffset = guide.positionToOffset(state, source.method.finish) - return text:sub(startOffset + 1, finishOffset) + return sub(source.start + 1, source.method.finish) end end if source.type == 'setfield' or source.type == 'tablefield' or source.type == 'getfield' then if source.field then - local finishOffset = guide.positionToOffset(state, source.field.finish) - return text:sub(startOffset + 1, finishOffset) + return sub(source.start + 1, source.field.finish) end end if source.type == 'tableindex' then if source.index then - local finishOffset = guide.positionToOffset(state, source.finish) - return text:sub(startOffset + 1, finishOffset) + return sub(source.start + 1, source.finish) end end if source.type == 'tableexp' then return ('[%d]'):format(source.tindex) end - local finishOffset = guide.positionToOffset(state, source.finish) - return text:sub(startOffset + 1, finishOffset) + return sub(source.start + 1, source.finish) end local function buildFunctionParams(func) @@ -56,8 +49,7 @@ local function buildFunctionParams(func) return table.concat(params, ', ') end -local function buildTable(tbl) - local uri = guide.getUri(tbl) +local function buildTable(tbl, sub) local buf = {} for i = 1, 5 do local field = tbl[i] @@ -69,9 +61,7 @@ local function buildTable(tbl) buf[#buf+1] = ('%s'):format(field.field[1]) elseif field.type == 'tableindex' and field.index then - local view = vm.getInfer(field.index):viewLiterals() - or vm.getInfer(field.index):view(uri) - buf[#buf+1] = ('[%s]'):format(view) + buf[#buf+1] = ('[%s]'):format(sub(field.index.start + 1, field.index.finish)) elseif field.type == 'tableexp' then buf[#buf+1] = ('[%s]'):format(field.tindex) end @@ -82,16 +72,14 @@ local function buildTable(tbl) return table.concat(buf, ', ') end -local function buildArray(tbl) - local uri = guide.getUri(tbl) +local function buildArray(tbl, sub) local buf = {} for i = 1, 5 do local field = tbl[i] if not field then break end - buf[#buf+1] = vm.getInfer(field):viewLiterals() - or vm.getInfer(field):view(uri) + buf[#buf+1] = sub(field.start + 1, field.finish) end if #tbl > 5 then buf[#buf+1] = ('...(+%d)'):format(#tbl - 5) @@ -99,8 +87,8 @@ local function buildArray(tbl) return table.concat(buf, ', ') end -local function buildValue(source, text, used, symbols) - local name = buildName(source, text) +local function buildValue(source, sub, used, symbols) + local name = buildName(source, sub) local range, sRange, valueRange, kind local details = {} if source.type == 'local' then @@ -175,12 +163,12 @@ local function buildValue(source, text, used, symbols) -- Array kind = define.SymbolKind.Array details[#details+1] = '[' - details[#details+1] = buildArray(source.value) + details[#details+1] = buildArray(source.value, sub) details[#details+1] = ']' else -- Object details[#details+1] = '{' - details[#details+1] = buildTable(source.value) + details[#details+1] = buildTable(source.value, sub) details[#details+1] = '}' end end @@ -211,7 +199,7 @@ local function buildValue(source, text, used, symbols) } end -local function buildAnonymousFunction(source, text, used, symbols) +local function buildAnonymousFunction(source, sub, used, symbols) if used[source] then return end @@ -223,7 +211,7 @@ local function buildAnonymousFunction(source, text, used, symbols) elseif parent.type == 'callargs' then local call = parent.parent local node = call.node - head = buildName(node, text) .. ' -> ' + head = buildName(node, sub) .. ' -> ' end symbols[#symbols+1] = { name = '', @@ -235,7 +223,54 @@ local function buildAnonymousFunction(source, text, used, symbols) } end -local function buildSource(source, text, used, symbols) +local function buildBlock(source, sub, used, symbols) + if used[source] then + return + end + used[source] = true + if source.type == 'if' then + for _, block in ipairs(source) do + symbols[#symbols+1] = { + name = block.type:gsub('block$', ''), + detail = sub(block.start + 1, block.keyword[4] or block.keyword[2]), + kind = define.SymbolKind.Package, + range = { block.start, block.finish }, + valueRange = { block.start, block.finish }, + selectionRange = { block.keyword[1], block.keyword[2] }, + } + end + elseif source.type == 'while' then + symbols[#symbols+1] = { + name = 'while', + detail = sub(source.start + 1, source.keyword[4] or source.keyword[2]), + kind = define.SymbolKind.Package, + range = { source.start, source.finish }, + valueRange = { source.start, source.finish }, + selectionRange = { source.keyword[1], source.keyword[2] }, + } + elseif source.type == 'repeat' then + symbols[#symbols+1] = { + name = 'repeat', + detail = source.filter and sub(source.keyword[3] + 1, source.filter.finish) or '', + kind = define.SymbolKind.Package, + range = { source.start, source.finish }, + valueRange = { source.start, source.finish }, + selectionRange = { source.keyword[1], source.keyword[2] }, + } + elseif source.type == 'loop' + or source.type == 'in' then + symbols[#symbols+1] = { + name = 'for', + detail = sub(source.start, source.keyword[4] or source.keyword[2]), + kind = define.SymbolKind.Package, + range = { source.start, source.finish }, + valueRange = { source.start, source.finish }, + selectionRange = { source.keyword[1], source.keyword[2] }, + } + end +end + +local function buildSource(source, sub, used, symbols) if source.type == 'local' or source.type == 'setlocal' or source.type == 'setglobal' @@ -244,26 +279,32 @@ local function buildSource(source, text, used, symbols) or source.type == 'tablefield' or source.type == 'tableexp' or source.type == 'tableindex' then - buildValue(source, text, used, symbols) + buildValue(source, sub, used, symbols) elseif source.type == 'function' then - buildAnonymousFunction(source, text, used, symbols) + buildAnonymousFunction(source, sub, used, symbols) + elseif source.type == 'if' + or source.type == 'while' + or source.type == 'in' + or source.type == 'loop' + or source.type == 'repeat' then + buildBlock(source, sub, used, symbols) end end ---@async local function makeSymbol(uri) - local ast = files.getState(uri) - local text = files.getText(uri) - if not ast or not text then + local state = files.getState(uri) + if not state then return nil end + local sub = subber(state) local symbols = {} local used = {} local i = 0 ---@async - guide.eachSource(ast.ast, function (source) - buildSource(source, text, used, symbols) + guide.eachSource(state.ast, function (source) + buildSource(source, sub, used, symbols) i = i + 1 if i % 1000 == 0 then await.delay() diff --git a/script/parser/compile.lua b/script/parser/compile.lua index 915a2764..33ac4d69 100644 --- a/script/parser/compile.lua +++ b/script/parser/compile.lua @@ -3191,7 +3191,7 @@ local function parseIfBlock(parent) pushChunk(ifblock) parseActions() popChunk() - ifblock.finish = lastRightPosition() + ifblock.finish = getPosition(Tokens[Index], 'left') if ifblock.locals then LocalCount = LocalCount - #ifblock.locals end @@ -3250,7 +3250,7 @@ local function parseElseIfBlock(parent) pushChunk(elseifblock) parseActions() popChunk() - elseifblock.finish = lastRightPosition() + elseifblock.finish = getPosition(Tokens[Index], 'left') if elseifblock.locals then LocalCount = LocalCount - #elseifblock.locals end @@ -3275,7 +3275,7 @@ local function parseElseBlock(parent) pushChunk(elseblock) parseActions() popChunk() - elseblock.finish = lastRightPosition() + elseblock.finish = getPosition(Tokens[Index], 'left') if elseblock.locals then LocalCount = LocalCount - #elseblock.locals end diff --git a/test/document_symbol/init.lua b/test/document_symbol/init.lua index 6f80287f..17728efc 100644 --- a/test/document_symbol/init.lua +++ b/test/document_symbol/init.lua @@ -743,3 +743,98 @@ local t = { 1, 2, [5] = 3, [true] = 4, x = 5 } children = EXISTS } } + +TEST [[ +if 1 then + +elseif 2 then + +elseif 3 then + +else + +end +]] +{ + { + name = 'if', + detail = 'if 1 then', + kind = define.SymbolKind.Package, + range = {0, 20000}, + selectionRange = {0, 2}, + valueRange = {0, 20000}, + }, + { + name = 'elseif', + detail = 'elseif 2 then', + kind = define.SymbolKind.Package, + range = {20000, 40000}, + selectionRange = {20000, 20006}, + valueRange = {20000, 40000}, + }, + { + name = 'elseif', + detail = 'elseif 3 then', + kind = define.SymbolKind.Package, + range = {40000, 60000}, + selectionRange = {40000, 40006}, + valueRange = {40000, 60000}, + }, + { + name = 'else', + detail = 'else', + kind = define.SymbolKind.Package, + range = {60000, 80000}, + selectionRange = {60000, 60004}, + valueRange = {60000, 80000}, + }, +} + +TEST [[ +while true do + +end +]] +{ + { + name = 'while', + detail = 'while true do', + kind = define.SymbolKind.Package, + range = {0, 20003}, + selectionRange = {0, 5}, + valueRange = {0, 20003}, + }, +} + +TEST [[ +repeat + +until true +]] +{ + { + name = 'repeat', + detail = 'until true', + kind = define.SymbolKind.Package, + range = {0, 20010}, + selectionRange = {0, 6}, + valueRange = {0, 20010}, + }, +} + +TEST [[ +for i = 1, 10 do + +end +]] +{ + { + name = 'for', + detail = 'for i = 1, 10 do', + kind = define.SymbolKind.Package, + range = {0, 20003}, + selectionRange = {0, 3}, + valueRange = {0, 20003}, + children = EXISTS, + }, +} |