summaryrefslogtreecommitdiff
path: root/script/core
diff options
context:
space:
mode:
Diffstat (limited to 'script/core')
-rw-r--r--script/core/code-action.lua144
-rw-r--r--script/core/command/autoRequire.lua24
-rw-r--r--script/core/command/jsonToLua.lua15
-rw-r--r--script/core/command/removeSpace.lua51
-rw-r--r--script/core/command/solve.lua14
-rw-r--r--script/core/completion.lua484
-rw-r--r--script/core/diagnostics/count-down-loop.lua25
-rw-r--r--script/core/diagnostics/different-requires.lua2
-rw-r--r--script/core/diagnostics/init.lua2
-rw-r--r--script/core/diagnostics/newfield-call.lua5
-rw-r--r--script/core/diagnostics/newline-call.lua17
-rw-r--r--script/core/diagnostics/redundant-value.lua32
-rw-r--r--script/core/diagnostics/trailing-space.lua35
-rw-r--r--script/core/diagnostics/undefined-global.lua2
-rw-r--r--script/core/document-symbol.lua14
-rw-r--r--script/core/find-source.lua6
-rw-r--r--script/core/highlight.lua40
-rw-r--r--script/core/hover/label.lua3
-rw-r--r--script/core/infer.lua5
-rw-r--r--script/core/keyword.lua36
-rw-r--r--script/core/look-backward.lua2
-rw-r--r--script/core/noder.lua75
-rw-r--r--script/core/reference.lua4
-rw-r--r--script/core/rename.lua25
-rw-r--r--script/core/semantic-tokens.lua6
-rw-r--r--script/core/signature.lua36
-rw-r--r--script/core/type-formatting.lua72
27 files changed, 648 insertions, 528 deletions
diff --git a/script/core/code-action.lua b/script/core/code-action.lua
index 64f862f9..8256107e 100644
--- a/script/core/code-action.lua
+++ b/script/core/code-action.lua
@@ -1,63 +1,49 @@
-local files = require 'files'
-local lang = require 'language'
-local util = require 'utility'
-local sp = require 'bee.subprocess'
-local guide = require "parser.guide"
+local files = require 'files'
+local lang = require 'language'
+local util = require 'utility'
+local sp = require 'bee.subprocess'
+local guide = require "parser.guide"
+local converter = require 'proto.converter'
local function checkDisableByLuaDocExits(uri, row, mode, code)
- local lines = files.getLines(uri)
- local ast = files.getState(uri)
- local text = files.getOriginText(uri)
- local line = lines[row]
- if ast.ast.docs and line then
- for _, doc in ipairs(ast.ast.docs) do
- if doc.start >= line.start
- and doc.finish <= line.finish then
- if doc.type == 'doc.diagnostic' then
- if doc.mode == mode then
- if doc.names then
- return {
- start = doc.finish,
- finish = doc.finish,
- newText = text:sub(doc.finish, doc.finish)
- .. ', '
- .. code
- }
- else
- return {
- start = doc.finish,
- finish = doc.finish,
- newText = text:sub(doc.finish, doc.finish)
- .. ': '
- .. code
- }
- end
- end
+ if row < 0 then
+ return nil
+ end
+ local state = files.getState(uri)
+ local lines = state.lines
+ if state.ast.docs and lines then
+ return guide.eachSourceBetween(state.ast.docs, guide.positionOf(row, 0), guide.positionOf(row + 1, 0), function (doc)
+ if doc.type == 'doc.diagnostic'
+ and doc.mode == mode then
+ if doc.names then
+ return {
+ start = doc.finish,
+ finish = doc.finish,
+ newText = ', ' .. code,
+ }
+ else
+ return {
+ start = doc.finish,
+ finish = doc.finish,
+ newText = ': ' .. code,
+ }
end
end
- end
+ end)
end
return nil
end
local function checkDisableByLuaDocInsert(uri, row, mode, code)
- local lines = files.getLines(uri)
- local ast = files.getState(uri)
- local text = files.getOriginText(uri)
- -- 先看看上一行是不是已经有了
- -- 没有的话就插入一行
- local line = lines[row]
return {
- start = line.start,
- finish = line.start,
- newText = '---@diagnostic ' .. mode .. ': ' .. code .. '\n'
- .. text:sub(line.start, line.start)
+ start = guide.positionOf(row, 0),
+ finish = guide.positionOf(row, 0),
+ newText = '---@diagnostic ' .. mode .. ': ' .. code .. '\n',
}
end
local function disableDiagnostic(uri, code, start, results)
- local lines = files.getLines(uri)
- local row = guide.positionOf(lines, start)
+ local row = guide.rowColOf(start)
results[#results+1] = {
title = lang.script('ACTION_DISABLE_DIAG', code),
kind = 'quickfix',
@@ -90,8 +76,8 @@ local function disableDiagnostic(uri, code, start, results)
checkDisableByLuaDocExits (uri, row - 1, 'disable-next-line', code)
or checkDisableByLuaDocInsert(uri, row, 'disable-next-line', code))
pushEdit(lang.script('ACTION_DISABLE_DIAG_FILE', code),
- checkDisableByLuaDocExits (uri, 1, 'disable', code)
- or checkDisableByLuaDocInsert(uri, 1, 'disable', code))
+ checkDisableByLuaDocExits (uri, 0, 'disable', code)
+ or checkDisableByLuaDocInsert(uri, 0, 'disable', code))
end
local function markGlobal(uri, name, results)
@@ -134,8 +120,8 @@ end
local function solveUndefinedGlobal(uri, diag, results)
local ast = files.getState(uri)
- local offset = files.offsetOfWord(uri, diag.range.start)
- guide.eachSourceContain(ast.ast, offset, function (source)
+ local start = converter.unpackRange(uri, diag.range)
+ guide.eachSourceContain(ast.ast, start, function (source)
if source.type ~= 'getglobal' then
return
end
@@ -153,8 +139,8 @@ end
local function solveLowercaseGlobal(uri, diag, results)
local ast = files.getState(uri)
- local offset = files.offsetOfWord(uri, diag.range.start)
- guide.eachSourceContain(ast.ast, offset, function (source)
+ local start = converter.unpackRange(uri, diag.range)
+ guide.eachSourceContain(ast.ast, start, function (source)
if source.type ~= 'setglobal' then
return
end
@@ -168,7 +154,7 @@ local function findSyntax(uri, diag)
local ast = files.getState(uri)
for _, err in ipairs(ast.errs) do
if err.type:lower():gsub('_', '-') == diag.code then
- local range = files.range(uri, err.start, err.finish)
+ local range = converter.packRange(uri, err.start, err.finish)
if util.equal(range, diag.range) then
return err
end
@@ -197,8 +183,13 @@ local function solveSyntaxByAddDoEnd(uri, err, results)
[uri] = {
{
start = err.start,
+ finish = err.start,
+ newText = 'do ',
+ },
+ {
+ start = err.finish,
finish = err.finish,
- newText = ('do %s end'):format(text:sub(err.start, err.finish)),
+ newText = ' end',
},
}
}
@@ -265,7 +256,7 @@ local function solveSyntax(uri, diag, results)
end
local function solveNewlineCall(uri, diag, results)
- local start = files.unrange(uri, diag.range)
+ local start = converter.unpackRange(uri, diag.range)
results[#results+1] = {
title = lang.script.ACTION_ADD_SEMICOLON,
kind = 'quickfix',
@@ -349,18 +340,18 @@ local function checkQuickFix(results, uri, start, diagnostics)
end
local function checkSwapParams(results, uri, start, finish)
- local ast = files.getState(uri)
- local text = files.getText(uri)
- if not ast then
+ local state = files.getState(uri)
+ local text = files.getText(uri)
+ if not state then
return
end
local args = {}
- guide.eachSourceBetween(ast.ast, start, finish, function (source)
+ guide.eachSourceBetween(state.ast, start, finish, function (source)
if source.type == 'callargs'
or source.type == 'funcargs' then
local targetIndex
for index, arg in ipairs(source) do
- if arg.start - 1 <= finish and arg.finish >= start then
+ if arg.start <= finish and arg.finish >= start then
-- should select only one param
if targetIndex then
return
@@ -373,11 +364,17 @@ local function checkSwapParams(results, uri, start, finish)
end
local node
if source.type == 'callargs' then
- node = text:sub(source.parent.node.start, source.parent.node.finish)
+ node = text:sub(
+ guide.positionToOffset(state, source.parent.node.start) + 1,
+ guide.positionToOffset(state, source.parent.node.finish)
+ )
elseif source.type == 'funcargs' then
local var = source.parent.parent
if guide.isSet(var) then
- node = text:sub(var.start, var.finish)
+ node = text:sub(
+ guide.positionToOffset(state, var.start) + 1,
+ guide.positionToOffset(state, var.finish)
+ )
else
node = lang.script.SYMBOL_ANONYMOUS
end
@@ -411,12 +408,18 @@ local function checkSwapParams(results, uri, start, finish)
{
start = myArg.start,
finish = myArg.finish,
- newText = text:sub(targetArg.start, targetArg.finish),
+ newText = text:sub(
+ guide.positionToOffset(state, targetArg.start) + 1,
+ guide.positionToOffset(state, targetArg.finish)
+ ),
},
{
start = targetArg.start,
finish = targetArg.finish,
- newText = text:sub(myArg.start, myArg.finish),
+ newText = text:sub(
+ guide.positionToOffset(state, myArg.start) + 1,
+ guide.positionToOffset(state, myArg.finish)
+ ),
},
}
}
@@ -499,13 +502,16 @@ end
--end
local function checkJsonToLua(results, uri, start, finish)
- local text = files.getText(uri)
- local jsonStart = text:match ('()[%{%[]', start)
+ local text = files.getText(uri)
+ local state = files.getState(uri)
+ local startOffset = guide.positionToOffset(state, start)
+ local finishOffset = guide.positionToOffset(state, finish)
+ local jsonStart = text:match ('()[%{%[]', startOffset + 1)
if not jsonStart then
return
end
local jsonFinish
- for i = math.min(finish, #text), jsonStart + 1, -1 do
+ for i = math.min(finishOffset, #text), jsonStart + 1, -1 do
local char = text:sub(i, i)
if char == ']'
or char == '}' then
@@ -528,8 +534,8 @@ local function checkJsonToLua(results, uri, start, finish)
arguments = {
{
uri = uri,
- start = jsonStart,
- finish = jsonFinish,
+ start = guide.offsetToPosition(state, jsonStart) - 1,
+ finish = guide.offsetToPosition(state, jsonFinish),
}
}
},
diff --git a/script/core/command/autoRequire.lua b/script/core/command/autoRequire.lua
index 2cb6a8f8..d711fb16 100644
--- a/script/core/command/autoRequire.lua
+++ b/script/core/command/autoRequire.lua
@@ -4,20 +4,22 @@ local config = require 'config'
local rpath = require 'workspace.require-path'
local client = require 'client'
local lang = require 'language'
+local guide = require 'parser.guide'
-local function findInsertOffset(uri)
- local lines = files.getLines(uri)
+local function findInsertRow(uri)
local text = files.getText(uri)
+ local state = files.getState(uri)
+ local lines = state.lines
local fmt = {
pair = false,
quot = '"',
col = nil,
}
- for i = 1, #lines do
+ for i = 0, #lines do
local ln = lines[i]
- local lnText = text:sub(ln.start, ln.finish)
+ local lnText = text:match('[^\r\n]*', ln)
if not lnText:find('require', 1, true) then
- return ln.start, fmt
+ return i, fmt
else
local lpPos = lnText:find '%('
if lpPos then
@@ -33,7 +35,7 @@ local function findInsertOffset(uri)
end
end
end
- return 1, fmt
+ return 0, fmt
end
local function askAutoRequire(visiblePaths)
@@ -70,7 +72,7 @@ local function askAutoRequire(visiblePaths)
return nameMap[result]
end
-local function applyAutoRequire(uri, offset, name, result, fmt)
+local function applyAutoRequire(uri, row, name, result, fmt)
local quotedResult = ('%q'):format(result)
if fmt.quot == "'" then
quotedResult = ([['%s']]):format(quotedResult:sub(2, -2)
@@ -88,11 +90,11 @@ local function applyAutoRequire(uri, offset, name, result, fmt)
if fmt.col and fmt.col > #text then
sp = (' '):rep(fmt.col - #text - 1)
end
- text = ('\nlocal %s%s= require%s\n'):format(name, sp, quotedResult)
+ text = ('local %s%s= require%s\n'):format(name, sp, quotedResult)
client.editText(uri, {
{
- start = offset,
- finish = offset - 1,
+ start = guide.positionOf(row, 0),
+ finish = guide.positionOf(row, 0),
text = text,
}
})
@@ -121,6 +123,6 @@ return function (data)
return
end
- local offset, fmt = findInsertOffset(uri)
+ local offset, fmt = findInsertRow(uri)
applyAutoRequire(uri, offset, name, result, fmt)
end
diff --git a/script/core/command/jsonToLua.lua b/script/core/command/jsonToLua.lua
index c4f001ff..8a493b5e 100644
--- a/script/core/command/jsonToLua.lua
+++ b/script/core/command/jsonToLua.lua
@@ -1,9 +1,10 @@
-local files = require 'files'
-local json = require 'json'
-local util = require 'utility'
-local proto = require 'proto'
-local define = require 'proto.define'
-local lang = require 'language'
+local files = require 'files'
+local json = require 'json'
+local util = require 'utility'
+local proto = require 'proto'
+local define = require 'proto.define'
+local lang = require 'language'
+local converter = require 'proto.converter'
return function (data)
local text = files.getText(data.uri)
@@ -26,7 +27,7 @@ return function (data)
changes = {
[data.uri] = {
{
- range = files.range(data.uri, data.start, data.finish),
+ range = converter.packRange(data.uri, data.start, data.finish),
newText = luaStr,
}
}
diff --git a/script/core/command/removeSpace.lua b/script/core/command/removeSpace.lua
index b94f9788..3021d4a4 100644
--- a/script/core/command/removeSpace.lua
+++ b/script/core/command/removeSpace.lua
@@ -1,7 +1,8 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local proto = require 'proto'
-local lang = require 'language'
+local files = require 'files'
+local guide = require 'parser.guide'
+local proto = require 'proto'
+local lang = require 'language'
+local converter = require 'proto.converter'
local function isInString(ast, offset)
return guide.eachSourceContain(ast.ast, offset, function (source)
@@ -13,29 +14,39 @@ end
return function (data)
local uri = data.uri
- local lines = files.getLines(uri)
local text = files.getText(uri)
- local ast = files.getState(uri)
- if not lines then
+ local state = files.getState(uri)
+ if not state then
return
end
+ local lines = state.lines
local textEdit = {}
- for i = 1, #lines do
- local line = guide.lineContent(lines, text, i, true)
- local pos = line:find '[ \t]+$'
- if pos then
- local start, finish = guide.lineRange(lines, i, true)
- start = start + pos
- if isInString(ast, start) then
- goto NEXT_LINE
- end
- textEdit[#textEdit+1] = {
- range = files.range(uri, start, finish),
- newText = '',
- }
+ for i = 0, #lines do
+ local startOffset = lines[i]
+ local finishOffset = text:find('[\r\n]', startOffset) or (#text + 1)
+ local lastOffset = finishOffset - 1
+ local lastChar = text:sub(lastOffset, lastOffset)
+ if lastChar ~= ' ' and lastChar ~= '\t' then
+ goto NEXT_LINE
+ end
+ local lastPos = guide.offsetToPosition(state, lastOffset)
+ if isInString(state.ast, lastPos) then
goto NEXT_LINE
end
+ local firstOffset = startOffset
+ for n = lastOffset - 1, startOffset, -1 do
+ local char = text:sub(n, n)
+ if char ~= ' ' and char ~= '\t' then
+ firstOffset = n + 1
+ break
+ end
+ end
+ local firstPos = guide.offsetToPosition(state, firstOffset) - 1
+ textEdit[#textEdit+1] = {
+ range = converter.packRange(uri, firstPos, lastPos),
+ newText = '',
+ }
::NEXT_LINE::
end
diff --git a/script/core/command/solve.lua b/script/core/command/solve.lua
index a493de24..9428d065 100644
--- a/script/core/command/solve.lua
+++ b/script/core/command/solve.lua
@@ -1,7 +1,8 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local proto = require 'proto'
-local lang = require 'language'
+local files = require 'files'
+local guide = require 'parser.guide'
+local proto = require 'proto'
+local lang = require 'language'
+local converter = require 'proto.converter'
local opMap = {
['+'] = true,
@@ -34,8 +35,7 @@ return function (data)
return
end
- local start = files.offsetOfWord(uri, data.range.start)
- local finish = files.offsetOfWord(uri, data.range['end'])
+ local start, finish = converter.unpackRange(uri, data.range)
local result = guide.eachSourceContain(ast.ast, start, function (source)
if source.start ~= start
@@ -85,7 +85,7 @@ return function (data)
changes = {
[uri] = {
{
- range = files.range(uri, result.start, result.finish),
+ range = converter.packRange(uri, result.start, result.finish),
newText = ('(%s)'):format(text:sub(result.start, result.finish)),
}
},
diff --git a/script/core/completion.lua b/script/core/completion.lua
index fb7b2eb4..bb55506a 100644
--- a/script/core/completion.lua
+++ b/script/core/completion.lua
@@ -53,17 +53,17 @@ local function trim(str)
return str:match '^%s*(%S+)%s*$'
end
-local function findNearestSource(ast, offset)
+local function findNearestSource(state, position)
local source
- guide.eachSourceContain(ast.ast, offset, function (src)
+ guide.eachSourceContain(state.ast, position, function (src)
source = src
end)
return source
end
-local function findNearestTableField(ast, offset)
+local function findNearestTableField(state, position)
local source
- guide.eachSourceContain(ast.ast, offset, function (src)
+ guide.eachSourceContain(state.ast, position, function (src)
if src.type == 'table'
or src.type == 'tablefield'
or src.type == 'tableindex'
@@ -74,7 +74,8 @@ local function findNearestTableField(ast, offset)
return source
end
-local function findParent(ast, text, offset)
+local function findParent(state, text, position)
+ local offset = guide.positionToOffset(state, position)
for i = offset, 1, -1 do
local char = text:sub(i, i)
if lookBackward.isSpace(char) then
@@ -92,11 +93,12 @@ local function findParent(ast, text, offset)
else
return nil, nil
end
- local anyPos = lookBackward.findAnyPos(text, i-1)
- if not anyPos then
+ local anyOffset = lookBackward.findAnyOffset(text, i-1)
+ if not anyOffset then
return nil, nil
end
- local parent = guide.eachSourceContain(ast.ast, anyPos, function (source)
+ local anyPos = guide.offsetToPosition(state, anyOffset)
+ local parent = guide.eachSourceContain(state.ast, anyPos, function (source)
if source.finish == anyPos then
return source
end
@@ -109,9 +111,9 @@ local function findParent(ast, text, offset)
return nil, nil
end
-local function findParentInStringIndex(ast, text, offset)
+local function findParentInStringIndex(state, text, position)
local near, nearStart
- guide.eachSourceContain(ast.ast, offset, function (source)
+ guide.eachSourceContain(state.ast, position, function (source)
local start = guide.getStartFinish(source)
if not start then
return
@@ -169,17 +171,18 @@ local function getSnip(source)
if def ~= source and def.type == 'function' then
local uri = guide.getUri(def)
local text = files.getText(uri)
- local lines = files.getLines(uri)
+ local state = files.getState(uri)
+ local lines = state.lines
if not text then
goto CONTINUE
end
if vm.isMetaFile(uri) then
goto CONTINUE
end
- local row = guide.positionOf(lines, def.start)
- local firstRow = lines[row]
- local lastRow = lines[math.min(row + context - 1, #lines)]
- local snip = text:sub(firstRow.start, lastRow.finish)
+ local firstRow = guide.rowColOf(def.start)
+ local lastRow = firstRow + context
+ local lastOffset = lines[lastRow] and (lines[lastRow] - 1) or #text
+ local snip = text:sub(lines[firstRow], lastOffset)
return snip
end
::CONTINUE::
@@ -222,38 +225,8 @@ local function buildFunction(results, source, value, oop, data)
end
end
-local function buildInsertRequire(ast, targetUri, stemName)
- local uri = guide.getUri(ast.ast)
- local lines = files.getLines(uri)
- local text = files.getText(uri)
- local start = 1
- for i = 1, #lines do
- local ln = lines[i]
- local lnText = text:sub(ln.start, ln.finish)
- if not lnText:find('require', 1, true) then
- start = ln.start
- break
- end
- end
- local path = furi.decode(targetUri)
- local visiblePaths = rpath.getVisiblePath(path, config.get 'Lua.runtime.path', true)
- if not visiblePaths or #visiblePaths == 0 then
- return nil
- end
- table.sort(visiblePaths, function (a, b)
- return #a.expect < #b.expect
- end)
- return {
- {
- start = start,
- finish = start - 1,
- newText = ('local %s = require %q\n'):format(stemName, visiblePaths[1].expect)
- }
- }
-end
-
-local function isSameSource(ast, source, pos)
- if guide.getUri(source) ~= guide.getUri(ast.ast) then
+local function isSameSource(state, source, pos)
+ if guide.getUri(source) ~= guide.getUri(state.ast) then
return false
end
if source.type == 'field'
@@ -283,10 +256,10 @@ local function getParams(func, oop)
return '(' .. table.concat(args, ', ') .. ')'
end
-local function checkLocal(ast, word, offset, results)
- local locals = guide.getVisibleLocals(ast.ast, offset)
+local function checkLocal(state, word, position, results)
+ local locals = guide.getVisibleLocals(state.ast, position)
for name, source in util.sortPairs(locals) do
- if isSameSource(ast, source, offset) then
+ if isSameSource(state, source, position) then
goto CONTINUE
end
if not matchKey(word, name) then
@@ -330,13 +303,13 @@ local function checkLocal(ast, word, offset, results)
end
end
-local function checkModule(ast, word, offset, results)
+local function checkModule(state, word, position, results)
if not config.get 'Lua.completion.autoRequire' then
return
end
- local locals = guide.getVisibleLocals(ast.ast, offset)
+ local locals = guide.getVisibleLocals(state.ast, position)
for uri in files.eachFile() do
- if uri == guide.getUri(ast.ast) then
+ if uri == guide.getUri(state.ast) then
goto CONTINUE
end
local path = furi.decode(uri)
@@ -347,11 +320,11 @@ local function checkModule(ast, word, offset, results)
and not config.get 'Lua.diagnostics.globals'[stemName]
and stemName:match '^[%a_][%w_]*$'
and matchKey(word, stemName) then
- local targetAst = files.getState(uri)
- if not targetAst then
+ local targetState = files.getState(uri)
+ if not targetState then
goto CONTINUE
end
- local targetReturns = targetAst.ast.returns
+ local targetReturns = targetState.ast.returns
if not targetReturns then
goto CONTINUE
end
@@ -377,7 +350,7 @@ local function checkModule(ast, word, offset, results)
command = 'lua.autoRequire:' .. sp:get_id(),
arguments = {
{
- uri = guide.getUri(ast.ast),
+ uri = guide.getUri(state.ast),
target = uri,
name = stemName,
},
@@ -393,7 +366,7 @@ local function checkModule(ast, word, offset, results)
return {
detail = buildDetail(targetSource),
description = md,
- --additionalTextEdits = buildInsertRequire(ast, originUri, stemName),
+ --additionalTextEdits = buildInsertRequire(state, originUri, stemName),
}
end)
}
@@ -402,19 +375,28 @@ local function checkModule(ast, word, offset, results)
end
end
-local function checkFieldFromFieldToIndex(name, src, parent, word, start, offset)
+local function checkFieldFromFieldToIndex(name, src, parent, word, startPos, position)
if name:match '^[%a_][%w_]*$' then
return nil
end
local textEdit, additionalTextEdits
- local uri = guide.getUri(parent)
- local text = files.getText(uri)
- local wordStart
+ local uri = guide.getUri(parent)
+ local text = files.getText(uri)
+ local state = files.getState(uri)
+ local startOffset = guide.positionToOffset(state, startPos)
+ local offset = guide.positionToOffset(state, position)
+ local wordStartOffset
if word == '' then
- wordStart = text:match('()%S', start + 1) or (offset + 1)
+ wordStartOffset = text:match('()%S', startOffset + 1)
+ if wordStartOffset then
+ wordStartOffset = wordStartOffset - 1
+ else
+ wordStartOffset = offset
+ end
else
- wordStart = offset - #word + 1
+ wordStartOffset = offset - #word
end
+ local wordStartPos = guide.offsetToPosition(state, wordStartOffset)
local newText
if vm.getKeyType(src) == 'string' then
newText = ('[%q]'):format(name)
@@ -422,26 +404,28 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, start, offset
newText = ('[%s]'):format(name)
end
textEdit = {
- start = wordStart,
- finish = offset,
+ start = wordStartPos,
+ finish = position,
newText = newText,
}
local nxt = parent.next
if nxt then
- local dotStart
+ local dotStart, dotFinish
if nxt.type == 'setfield'
or nxt.type == 'getfield'
or nxt.type == 'tablefield' then
dotStart = nxt.dot.start
+ dotFinish = nxt.dot.finish
elseif nxt.type == 'setmethod'
or nxt.type == 'getmethod' then
dotStart = nxt.colon.start
+ dotFinish = nxt.colon.finish
end
if dotStart then
additionalTextEdits = {
{
start = dotStart,
- finish = dotStart,
+ finish = dotFinish,
newText = '',
}
}
@@ -457,7 +441,7 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, start, offset
return textEdit, additionalTextEdits
end
-local function checkFieldThen(name, src, word, start, offset, parent, oop, results)
+local function checkFieldThen(name, src, word, startPos, position, parent, oop, results)
local value = searcher.getObjectValue(src) or src
local kind = define.CompletionItemKind.Field
if value.type == 'function'
@@ -494,11 +478,11 @@ local function checkFieldThen(name, src, word, start, offset, parent, oop, resul
local str = parent.next.index
textEdit = {
start = str.start + #str[2],
- finish = offset,
+ finish = position,
newText = name,
}
else
- textEdit, additionalTextEdits = checkFieldFromFieldToIndex(name, src, parent, word, start, offset)
+ textEdit, additionalTextEdits = checkFieldFromFieldToIndex(name, src, parent, word, startPos, position)
end
results[#results+1] = {
label = name,
@@ -515,7 +499,7 @@ local function checkFieldThen(name, src, word, start, offset, parent, oop, resul
}
end
-local function checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, results, locals, isGlobal)
+local function checkFieldOfRefs(refs, state, word, startPos, position, parent, oop, results, locals, isGlobal)
local fields = {}
local funcs = {}
local count = 0
@@ -524,7 +508,7 @@ local function checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, res
if not name then
goto CONTINUE
end
- if isSameSource(ast, src, start) then
+ if isSameSource(state, src, startPos) then
goto CONTINUE
end
if isGlobal and locals and locals[name] then
@@ -573,29 +557,29 @@ local function checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, res
end
for name, src in util.sortPairs(fields) do
if src then
- checkFieldThen(name, src, word, start, offset, parent, oop, results)
+ checkFieldThen(name, src, word, startPos, position, parent, oop, results)
end
end
end
-local function checkGlobal(ast, word, start, offset, parent, oop, results)
- local locals = guide.getVisibleLocals(ast.ast, offset)
+local function checkGlobal(state, word, startPos, position, parent, oop, results)
+ local locals = guide.getVisibleLocals(state.ast, position)
local globals = vm.getGlobalSets '*'
- checkFieldOfRefs(globals, ast, word, start, offset, parent, oop, results, locals, 'global')
+ checkFieldOfRefs(globals, state, word, startPos, position, parent, oop, results, locals, 'global')
end
-local function checkField(ast, word, start, offset, parent, oop, results)
+local function checkField(state, word, start, position, parent, oop, results)
if parent.tag == '_ENV' or parent.special == '_G' then
local globals = vm.getGlobalSets '*'
- checkFieldOfRefs(globals, ast, word, start, offset, parent, oop, results)
+ checkFieldOfRefs(globals, state, word, start, position, parent, oop, results)
else
local refs = vm.getRefs(parent, '*')
- checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, results)
+ checkFieldOfRefs(refs, state, word, start, position, parent, oop, results)
end
end
-local function checkTableField(ast, word, start, results)
- local source = guide.eachSourceContain(ast.ast, start, function (source)
+local function checkTableField(state, word, start, results)
+ local source = guide.eachSourceContain(state.ast, start, function (source)
if source.start == start
and source.parent
and source.parent.type == 'table' then
@@ -606,7 +590,7 @@ local function checkTableField(ast, word, start, results)
return
end
local used = {}
- guide.eachSourceType(ast.ast, 'tablefield', function (src)
+ guide.eachSourceType(state.ast, 'tablefield', function (src)
if not src.field then
return
end
@@ -623,7 +607,7 @@ local function checkTableField(ast, word, start, results)
end)
end
-local function checkCommon(myUri, word, text, offset, results)
+local function checkCommon(myUri, word, text, position, results)
local showWord = config.get 'Lua.completion.showWord'
if showWord == 'Disable' then
return
@@ -691,11 +675,14 @@ local function checkCommon(myUri, word, text, offset, results)
end
end
end
- for str, pos in text:gmatch '([%a_][%w_]+)()' do
+ local state = files.getState(myUri)
+ for str, offset in text:gmatch '([%a_][%w_]+)()' do
if #results >= 100 then
break
end
- if #str >= 3 and not used[str] and pos - 1 ~= offset then
+ if #str >= 3
+ and not used[str]
+ and guide.offsetToPosition(state, offset - 1) ~= position then
used[str] = true
if matchKey(word, str) then
results[#results+1] = {
@@ -710,26 +697,26 @@ local function checkCommon(myUri, word, text, offset, results)
end
end
-local function isInString(ast, offset)
- return guide.eachSourceContain(ast.ast, offset, function (source)
+local function isInString(state, position)
+ return guide.eachSourceContain(state.ast, position, function (source)
if source.type == 'string' then
return true
end
end)
end
-local function checkKeyWord(ast, text, start, offset, word, hasSpace, afterLocal, results)
+local function checkKeyWord(state, text, start, position, word, hasSpace, afterLocal, results)
local snipType = config.get 'Lua.completion.keywordSnippet'
- local symbol = lookBackward.findSymbol(text, start - 1)
+ local symbol = lookBackward.findSymbol(text, guide.positionToOffset(state, start))
local isExp = symbol == '(' or symbol == ',' or symbol == '='
local info = {
hasSpace = hasSpace,
isExp = isExp,
text = text,
start = start,
- uri = guide.getUri(ast.ast),
- offset = offset,
- ast = ast,
+ uri = guide.getUri(state.ast),
+ position = position,
+ state = state,
}
for _, data in ipairs(keyWordMap) do
local key = data[1]
@@ -789,9 +776,9 @@ local function checkKeyWord(ast, text, start, offset, word, hasSpace, afterLocal
end
end
-local function checkProvideLocal(ast, word, start, results)
+local function checkProvideLocal(state, word, start, results)
local block
- guide.eachSourceContain(ast.ast, start, function (source)
+ guide.eachSourceContain(state.ast, start, function (source)
if source.type == 'function'
or source.type == 'main' then
block = source
@@ -825,8 +812,8 @@ local function checkProvideLocal(ast, word, start, results)
end)
end
-local function checkFunctionArgByDocParam(ast, word, start, results)
- local func = guide.eachSourceContain(ast.ast, start, function (source)
+local function checkFunctionArgByDocParam(state, word, startPos, results)
+ local func = guide.eachSourceContain(state.ast, startPos, function (source)
if source.type == 'function' then
return source
end
@@ -846,7 +833,7 @@ local function checkFunctionArgByDocParam(ast, word, start, results)
end
local firstArg = func.args and func.args[1]
if not firstArg
- or firstArg.start <= start and firstArg.finish >= start then
+ or firstArg.start <= startPos and firstArg.finish >= startPos then
local firstParam = params[1]
if firstParam and matchKey(word, firstParam.param[1]) then
local label = {}
@@ -870,16 +857,17 @@ local function checkFunctionArgByDocParam(ast, word, start, results)
end
end
-local function isAfterLocal(text, start)
- local pos = lookBackward.skipSpace(text, start-1)
- local word = lookBackward.findWord(text, pos)
+local function isAfterLocal(state, text, startPos)
+ local offset = guide.positionToOffset(state, startPos)
+ local pos = lookBackward.skipSpace(text, offset)
+ local word = lookBackward.findWord(text, pos)
return word == 'local'
end
-local function checkUri(ast, text, offset, results)
+local function checkUri(state, text, position, results)
local collect = {}
- local myUri = guide.getUri(ast.ast)
- guide.eachSourceContain(ast.ast, offset, function (source)
+ local myUri = guide.getUri(state.ast)
+ guide.eachSourceContain(state.ast, position, function (source)
if source.type ~= 'string' then
return
end
@@ -910,7 +898,7 @@ local function checkUri(ast, text, offset, results)
collect[info.expect] = {
textEdit = {
start = source.start + #source[2],
- finish = offset,
+ finish = position,
newText = info.expect,
}
}
@@ -996,23 +984,27 @@ local function checkUri(ast, text, offset, results)
end
end
-local function checkLenPlusOne(ast, text, offset, results)
- guide.eachSourceContain(ast.ast, offset, function (source)
+local function checkLenPlusOne(state, text, position, results)
+ guide.eachSourceContain(state.ast, position, function (source)
if source.type == 'getindex'
or source.type == 'setindex' then
- local _, pos = text:find('%s*%[%s*%#', source.node.finish)
- if not pos then
+ local finish = guide.positionToOffset(state, source.node.finish)
+ local _, offset = text:find('%s*%[%s*%#', finish)
+ if not offset then
return
end
- local nodeText = text:sub(source.node.start, source.node.finish)
- local writingText = trim(text:sub(pos + 1, offset - 1)) or ''
+ local start = guide.positionToOffset(state, source.node.start) + 1
+ local nodeText = text:sub(start, finish)
+ local writingText = trim(text:sub(offset + 1, guide.positionToOffset(state, position))) or ''
if not matchKey(writingText, nodeText) then
return
end
+ local offsetPos = guide.offsetToPosition(state, offset) - 1
if source.parent == guide.getParentBlock(source) then
+ local sourceFinish = guide.positionToOffset(state, source.finish)
-- state
- local label = text:match('%#[ \t]*', pos) .. nodeText .. '+1'
- local eq = text:find('^%s*%]?%s*%=', source.finish)
+ local label = text:match('%#[ \t]*', offset) .. nodeText .. '+1'
+ local eq = text:find('^%s*%]?%s*%=', sourceFinish)
local newText = label .. ']'
if not eq then
newText = newText .. ' = '
@@ -1022,20 +1014,20 @@ local function checkLenPlusOne(ast, text, offset, results)
match = nodeText,
kind = define.CompletionItemKind.Snippet,
textEdit = {
- start = pos,
+ start = offsetPos,
finish = source.finish,
newText = newText,
},
}
else
-- exp
- local label = text:match('%#[ \t]*', pos) .. nodeText
+ local label = text:match('%#[ \t]*', offset) .. nodeText
local newText = label .. ']'
results[#results+1] = {
label = label,
kind = define.CompletionItemKind.Snippet,
textEdit = {
- start = pos,
+ start = offsetPos,
finish = source.finish,
newText = newText,
},
@@ -1049,7 +1041,7 @@ local function tryLabelInString(label, source)
if not source or source.type ~= 'string' then
return label
end
- local str = parser:grammar(label, 'String')
+ local str = parser.grammar(label, 'String')
if not str then
return label
end
@@ -1084,7 +1076,7 @@ local function mergeEnums(a, b, source)
end
end
-local function checkTypingEnum(ast, text, offset, defs, str, results)
+local function checkTypingEnum(state, text, position, defs, str, results)
local enums = {}
for _, def in ipairs(defs) do
if def.type == 'doc.type.enum'
@@ -1106,21 +1098,21 @@ local function checkTypingEnum(ast, text, offset, defs, str, results)
end
end
-local function checkEqualEnumLeft(ast, text, offset, source, results)
+local function checkEqualEnumLeft(state, text, position, source, results)
if not source then
return
end
- local str = guide.eachSourceContain(ast.ast, offset, function (src)
+ local str = guide.eachSourceContain(state.ast, position, function (src)
if src.type == 'string' then
return src
end
end)
local defs = vm.getDefs(source)
- checkTypingEnum(ast, text, offset, defs, str, results)
+ checkTypingEnum(state, text, position, defs, str, results)
end
-local function checkEqualEnum(ast, text, offset, results)
- local start = lookBackward.findTargetSymbol(text, offset, '=')
+local function checkEqualEnum(state, text, position, results)
+ local start = lookBackward.findTargetSymbol(text, guide.positionToOffset(state, position), '=')
if not start then
return
end
@@ -1131,7 +1123,7 @@ local function checkEqualEnum(ast, text, offset, results)
eqOrNeq = true
end
start = lookBackward.skipSpace(text, start - 1)
- local source = findNearestSource(ast, start)
+ local source = findNearestSource(state, guide.offsetToPosition(state, start))
if not source then
return
end
@@ -1141,11 +1133,11 @@ local function checkEqualEnum(ast, text, offset, results)
if source.type == 'call' and not eqOrNeq then
return
end
- checkEqualEnumLeft(ast, text, offset, source, results)
+ checkEqualEnumLeft(state, text, position, source, results)
end
-local function checkEqualEnumInString(ast, text, offset, results)
- local source = findNearestSource(ast, offset)
+local function checkEqualEnumInString(state, text, position, results)
+ local source = findNearestSource(state, position)
local parent = source.parent
if parent.type == 'binary' then
if source ~= parent[2] then
@@ -1157,118 +1149,123 @@ local function checkEqualEnumInString(ast, text, offset, results)
if parent.op.type ~= '==' and parent.op.type ~= '~=' then
return
end
- checkEqualEnumLeft(ast, text, offset, parent[1], results)
+ checkEqualEnumLeft(state, text, position, parent[1], results)
end
if parent.type == 'local' then
- checkEqualEnumLeft(ast, text, offset, parent, results)
+ checkEqualEnumLeft(state, text, position, parent, results)
end
if parent.type == 'setlocal'
or parent.type == 'setglobal'
or parent.type == 'setfield'
or parent.type == 'setindex' then
- checkEqualEnumLeft(ast, text, offset, parent.node, results)
+ checkEqualEnumLeft(state, text, position, parent.node, results)
end
end
-local function isFuncArg(ast, offset)
- return guide.eachSourceContain(ast.ast, offset, function (source)
+local function isFuncArg(state, position)
+ return guide.eachSourceContain(state.ast, position, function (source)
if source.type == 'funcargs' then
return true
end
end)
end
-local function trySpecial(ast, text, offset, results)
- if isInString(ast, offset) then
- checkUri(ast, text, offset, results)
- checkEqualEnumInString(ast, text, offset, results)
+local function trySpecial(state, text, position, results)
+ if isInString(state, position) then
+ checkUri(state, text, position, results)
+ checkEqualEnumInString(state, text, position, results)
return
end
-- x[#x+1]
- checkLenPlusOne(ast, text, offset, results)
+ checkLenPlusOne(state, text, position, results)
-- type(o) ==
- checkEqualEnum(ast, text, offset, results)
+ checkEqualEnum(state, text, position, results)
end
-local function tryIndex(ast, text, offset, results)
- local parent, oop = findParentInStringIndex(ast, text, offset)
+local function tryIndex(state, text, position, results)
+ local parent, oop = findParentInStringIndex(state, text, position)
if not parent then
return
end
local word = parent.next.index[1]
- checkField(ast, word, offset, offset, parent, oop, results)
+ checkField(state, word, position, position, parent, oop, results)
end
-local function tryWord(ast, text, offset, triggerCharacter, results)
+local function tryWord(state, text, position, triggerCharacter, results)
+ local offset = guide.positionToOffset(state, position)
local finish = lookBackward.skipSpace(text, offset)
local word, start = lookBackward.findWord(text, offset)
+ local startPos
if not word then
if triggerCharacter == nil then
word = ''
- start = offset + 1
+ startPos = position + 1
else
return nil
end
+ else
+ startPos = guide.offsetToPosition(state, start - 1)
end
local hasSpace = triggerCharacter ~= nil and finish ~= offset
- if isInString(ast, offset) then
+ if isInString(state, position) then
if not hasSpace then
if #results == 0 then
- checkCommon(ast.uri, word, text, offset, results)
+ checkCommon(state.uri, word, text, position, results)
end
end
else
- local parent, oop = findParent(ast, text, start - 1)
+ local parent, oop = findParent(state, text, startPos)
if parent then
if not hasSpace then
- checkField(ast, word, start, offset, parent, oop, results)
+ checkField(state, word, startPos, position, parent, oop, results)
end
- elseif isFuncArg(ast, offset) then
- checkProvideLocal(ast, word, start, results)
- checkFunctionArgByDocParam(ast, word, start, results)
+ elseif isFuncArg(state, position) then
+ checkProvideLocal(state, word, startPos, results)
+ checkFunctionArgByDocParam(state, word, startPos, results)
else
- local afterLocal = isAfterLocal(text, start)
- local stop = checkKeyWord(ast, text, start, offset, word, hasSpace, afterLocal, results)
+ local afterLocal = isAfterLocal(state, text, startPos)
+ local stop = checkKeyWord(state, text, startPos, position, word, hasSpace, afterLocal, results)
if stop then
return
end
if not hasSpace then
if afterLocal then
- checkProvideLocal(ast, word, start, results)
+ checkProvideLocal(state, word, startPos, results)
else
- checkLocal(ast, word, start, results)
- checkTableField(ast, word, start, results)
- local env = guide.getENV(ast.ast, start)
- checkGlobal(ast, word, start, offset, env, false, results)
- checkModule(ast, word, start, results)
+ checkLocal(state, word, startPos, results)
+ checkTableField(state, word, startPos, results)
+ local env = guide.getENV(state.ast, startPos)
+ checkGlobal(state, word, startPos, position, env, false, results)
+ checkModule(state, word, startPos, results)
end
end
end
if not hasSpace then
- checkCommon(ast.uri, word, text, offset, results)
+ checkCommon(state.uri, word, text, position, results)
end
end
end
-local function trySymbol(ast, text, offset, results)
- local symbol, start = lookBackward.findSymbol(text, offset)
+local function trySymbol(state, text, position, results)
+ local symbol, start = lookBackward.findSymbol(text, guide.positionToOffset(state, position))
if not symbol then
return nil
end
- if isInString(ast, offset) then
+ if isInString(state, position) then
return nil
end
+ local startPos = guide.offsetToPosition(state, start)
if symbol == '.'
or symbol == ':' then
- local parent, oop = findParent(ast, text, start)
+ local parent, oop = findParent(state, text, startPos)
if parent then
tracy.ZoneBeginN 'completion.trySymbol'
- checkField(ast, '', start, offset, parent, oop, results)
+ checkField(state, '', startPos, position, parent, oop, results)
tracy.ZoneEnd()
end
end
if symbol == '(' then
- checkFunctionArgByDocParam(ast, '', start, results)
+ checkFunctionArgByDocParam(state, '', startPos, results)
end
end
@@ -1354,9 +1351,9 @@ local function getCallEnumsAndFuncs(source, index, oop)
end
end
-local function findCall(ast, text, offset)
+local function findCall(state, text, position)
local call
- guide.eachSourceContain(ast.ast, offset, function (src)
+ guide.eachSourceContain(state.ast, position, function (src)
if src.type == 'call' then
if not call or call.start < src.start then
call = src
@@ -1366,13 +1363,13 @@ local function findCall(ast, text, offset)
return call
end
-local function getCallArgInfo(call, text, offset)
+local function getCallArgInfo(call, text, position)
if not call.args then
return 1, nil, nil
end
local oop = call.node.type == 'getmethod'
for index, arg in ipairs(call.args) do
- if arg.start <= offset and arg.finish >= offset then
+ if arg.start <= position and arg.finish >= position then
return index, arg, oop
end
end
@@ -1391,7 +1388,7 @@ local function getFuncParamByCallIndex(func, index)
return func.args[index]
end
-local function checkTableLiteralField(ast, text, offset, tbl, fields, results)
+local function checkTableLiteralField(state, text, position, tbl, fields, results)
local mark = {}
for _, field in ipairs(tbl) do
if field.type == 'tablefield'
@@ -1407,9 +1404,9 @@ local function checkTableLiteralField(ast, text, offset, tbl, fields, results)
return guide.getKeyName(a) < guide.getKeyName(b)
end)
-- {$}
- local left = lookBackward.findWord(text, offset)
+ local left = lookBackward.findWord(text, guide.positionToOffset(state, position))
if not left then
- local pos = lookBackward.findAnyPos(text, offset)
+ local pos = lookBackward.findAnyOffset(text, guide.positionToOffset(state, position))
local char = text:sub(pos, pos)
if char == '{' or char == ',' or char == ';' then
left = ''
@@ -1435,8 +1432,8 @@ local function checkTableLiteralField(ast, text, offset, tbl, fields, results)
end
end
-local function checkTableLiteralFieldByCall(ast, text, offset, call, defs, index, results)
- local source = findNearestTableField(ast, offset)
+local function checkTableLiteralFieldByCall(state, text, position, call, defs, index, results)
+ local source = findNearestTableField(state, position)
if not source then
return
end
@@ -1469,16 +1466,16 @@ local function checkTableLiteralFieldByCall(ast, text, offset, call, defs, index
end
::CONTINUE::
end
- checkTableLiteralField(ast, text, offset, tbl, fields, results)
+ checkTableLiteralField(state, text, position, tbl, fields, results)
end
-local function tryCallArg(ast, text, offset, results)
- local call = findCall(ast, text, offset)
+local function tryCallArg(state, text, position, results)
+ local call = findCall(state, text, position)
if not call then
return
end
local myResults = {}
- local argIndex, arg, oop = getCallArgInfo(call, text, offset)
+ local argIndex, arg, oop = getCallArgInfo(call, text, position)
if arg and arg.type == 'function' then
return
end
@@ -1493,12 +1490,11 @@ local function tryCallArg(ast, text, offset, results)
for _, enum in ipairs(myResults) do
results[#results+1] = enum
end
- checkTableLiteralFieldByCall(ast, text, offset, call, defs, argIndex, results)
+ checkTableLiteralFieldByCall(state, text, position, call, defs, argIndex, results)
end
-local function tryTable(ast, text, offset, results)
- offset = lookBackward.skipSpace(text, offset)
- local source = findNearestTableField(ast, offset)
+local function tryTable(state, text, position, results)
+ local source = findNearestTableField(state, position)
if not source then
return
end
@@ -1521,21 +1517,21 @@ local function tryTable(ast, text, offset, results)
fields[#fields+1] = field
end
end
- checkTableLiteralField(ast, text, offset, tbl, fields, results)
+ checkTableLiteralField(state, text, position, tbl, fields, results)
end
-local function getComment(ast, offset)
- for _, comm in ipairs(ast.comms) do
- if offset >= comm.start - 2 and offset <= comm.finish then
+local function getComment(state, position)
+ for _, comm in ipairs(state.comms) do
+ if position > comm.start and position <= comm.finish then
return comm
end
end
return nil
end
-local function getLuaDoc(ast, offset)
- for _, doc in ipairs(ast.ast.docs) do
- if offset >= doc.start and offset <= doc.range then
+local function getLuaDoc(state, position)
+ for _, doc in ipairs(state.ast.docs) do
+ if position >= doc.start and position <= doc.range then
return doc
end
end
@@ -1568,28 +1564,28 @@ local function tryLuaDocCate(word, results)
end
end
-local function getLuaDocByContain(ast, offset)
+local function getLuaDocByContain(state, position)
local result
local range = math.huge
- guide.eachSourceContain(ast.ast.docs, offset, function (src)
+ guide.eachSourceContain(state.ast.docs, position, function (src)
if not src.start then
return
end
- if range >= offset - src.start
- and offset <= src.finish then
- range = offset - src.start
+ if range >= position - src.start
+ and position <= src.finish then
+ range = position - src.start
result = src
end
end)
return result
end
-local function getLuaDocByErr(ast, text, start, offset)
+local function getLuaDocByErr(state, text, start, position)
local targetError
- for _, err in ipairs(ast.errs) do
- if err.finish <= offset
+ for _, err in ipairs(state.errs) do
+ if err.finish <= position
and err.start >= start then
- if not text:sub(err.finish + 1, offset):find '%S' then
+ if not text:sub(err.finish + 1, position):find '%S' then
targetError = err
break
end
@@ -1599,8 +1595,8 @@ local function getLuaDocByErr(ast, text, start, offset)
return nil
end
local targetDoc
- for i = #ast.ast.docs, 1, -1 do
- local doc = ast.ast.docs[i]
+ for i = #state.ast.docs, 1, -1 do
+ local doc = state.ast.docs[i]
if doc.finish <= targetError.start then
targetDoc = doc
break
@@ -1609,7 +1605,7 @@ local function getLuaDocByErr(ast, text, start, offset)
return targetError, targetDoc
end
-local function tryLuaDocBySource(ast, offset, source, results)
+local function tryLuaDocBySource(state, position, source, results)
if source.type == 'doc.extends.name' then
if source.parent.type == 'doc.class' then
for _, doc in ipairs(vm.getDocDefines '*') do
@@ -1621,7 +1617,7 @@ local function tryLuaDocBySource(ast, offset, source, results)
kind = define.CompletionItemKind.Class,
textEdit = doc[1]:find '[^%w_]' and {
start = source.start,
- finish = offset,
+ finish = position,
newText = doc[1],
},
}
@@ -1639,7 +1635,7 @@ local function tryLuaDocBySource(ast, offset, source, results)
kind = define.CompletionItemKind.Class,
textEdit = doc[1]:find '[^%w_]' and {
start = source.start,
- finish = offset,
+ finish = position,
newText = doc[1],
},
}
@@ -1648,8 +1644,8 @@ local function tryLuaDocBySource(ast, offset, source, results)
return true
elseif source.type == 'doc.param.name' then
local funcs = {}
- guide.eachSourceBetween(ast.ast, offset, math.huge, function (src)
- if src.type == 'function' and src.start > offset then
+ guide.eachSourceBetween(state.ast, position, math.huge, function (src)
+ if src.type == 'function' and src.start > position then
funcs[#funcs+1] = src
end
end)
@@ -1702,7 +1698,7 @@ local function tryLuaDocBySource(ast, offset, source, results)
return false
end
-local function tryLuaDocByErr(ast, offset, err, docState, results)
+local function tryLuaDocByErr(state, position, err, docState, results)
if err.type == 'LUADOC_MISS_CLASS_EXTENDS_NAME' then
for _, doc in ipairs(vm.getDocDefines '*') do
if doc.type == 'doc.class.name'
@@ -1724,8 +1720,8 @@ local function tryLuaDocByErr(ast, offset, err, docState, results)
end
elseif err.type == 'LUADOC_MISS_PARAM_NAME' then
local funcs = {}
- guide.eachSourceBetween(ast.ast, offset, math.huge, function (src)
- if src.type == 'function' and src.start > offset then
+ guide.eachSourceBetween(state.ast, position, math.huge, function (src)
+ if src.type == 'function' and src.start > position then
funcs[#funcs+1] = src
end
end)
@@ -1851,49 +1847,49 @@ local function tryLuaDocOfFunction(doc, results)
}
end
-local function tryLuaDoc(ast, text, offset, results)
- local doc = getLuaDoc(ast, offset)
+local function tryLuaDoc(state, text, position, results)
+ local doc = getLuaDoc(state, position)
if not doc then
return
end
if doc.type == 'doc.comment' then
- local line = text:sub(doc.start, doc.range)
+ local line = doc.originalComment.text
-- 尝试 ---$
if line == '-' then
tryLuaDocOfFunction(doc, results)
return
end
-- 尝试 ---@$
- local cate = line:match('^-%s*@(%a*)$')
+ local cate = line:match('^-+%s*@(%a*)$')
if cate then
tryLuaDocCate(cate, results)
return
end
end
-- 根据输入中的source来补全
- local source = getLuaDocByContain(ast, offset)
+ local source = getLuaDocByContain(state, position)
if source then
- local suc = tryLuaDocBySource(ast, offset, source, results)
+ local suc = tryLuaDocBySource(state, position, source, results)
if suc then
return
end
end
-- 根据附近的错误消息来补全
- local err, expectDoc = getLuaDocByErr(ast, text, doc.start, offset)
+ local err, expectDoc = getLuaDocByErr(state, text, doc.start, position)
if err then
- tryLuaDocByErr(ast, offset, err, expectDoc, results)
+ tryLuaDocByErr(state, position, err, expectDoc, results)
return
end
end
-local function tryComment(ast, text, offset, results)
+local function tryComment(state, text, position, results)
if #results > 0 then
return
end
- local word = lookBackward.findWord(text, offset)
- local doc = getLuaDoc(ast, offset)
+ local word = lookBackward.findWord(text, guide.positionToOffset(state, position))
+ local doc = getLuaDoc(state, position)
if not word then
- local comment = getComment(ast, offset)
+ local comment = getComment(state, position)
if comment.type == 'comment.short'
or comment.type == 'comment.cshort' then
if comment.text == '' then
@@ -1912,23 +1908,24 @@ local function tryComment(ast, text, offset, results)
if doc and doc.type ~= 'doc.comment' then
return
end
- checkCommon(ast.uri, word, text, offset, results)
+ checkCommon(state.uri, word, text, position, results)
end
-local function makeCache(uri, offset, results)
+local function makeCache(uri, position, results)
local cache = workspace.getCache 'completion'
if not uri then
cache.results = nil
return
end
local text = files.getText(uri)
- local word = lookBackward.findWord(text, offset)
+ local state = files.getState(uri)
+ local word = lookBackward.findWord(text, guide.positionToOffset(state, position))
if not word or #word < 2 then
cache.results = nil
return
end
cache.results = results
- cache.offset = offset
+ cache.position= position
cache.word = word:lower()
cache.length = #word
end
@@ -1950,13 +1947,14 @@ local function isValidCache(word, result)
return false
end
-local function getCache(uri, offset)
+local function getCache(uri, position)
local cache = workspace.getCache 'completion'
if not cache.results then
return nil
end
local text = files.getText(uri)
- local word = lookBackward.findWord(text, offset)
+ local state = files.getState(uri)
+ local word = lookBackward.findWord(text, guide.positionToOffset(state, position))
if not word then
return nil
end
@@ -1980,7 +1978,7 @@ local function getCache(uri, offset)
end
if results.enableCommon then
- checkCommon(uri, word, text, offset, results)
+ checkCommon(uri, word, text, position, results)
end
return cache.results
@@ -1991,36 +1989,36 @@ local function clearCache()
cache.results = nil
end
-local function completion(uri, offset, triggerCharacter)
+local function completion(uri, position, triggerCharacter)
tracy.ZoneBeginN 'completion cache'
- local results = getCache(uri, offset)
+ local results = getCache(uri, position)
tracy.ZoneEnd()
if results then
return results
end
tracy.ZoneBeginN 'completion #1'
- local ast = files.getState(uri)
+ local state = files.getState(uri)
local text = files.getText(uri)
results = {}
clearStack()
tracy.ZoneEnd()
tracy.ZoneBeginN 'completion #2'
- if ast then
- if getComment(ast, offset) then
- tryLuaDoc(ast, text, offset, results)
- tryComment(ast, text, offset, results)
+ if state then
+ if getComment(state, position) then
+ tryLuaDoc(state, text, position, results)
+ tryComment(state, text, position, results)
else
- trySpecial(ast, text, offset, results)
- tryCallArg(ast, text, offset, results)
- tryTable(ast, text, offset, results)
- tryWord(ast, text, offset, triggerCharacter, results)
- tryIndex(ast, text, offset, results)
- trySymbol(ast, text, offset, results)
+ trySpecial(state, text, position, results)
+ tryCallArg(state, text, position, results)
+ tryTable(state, text, position, results)
+ tryWord(state, text, position, triggerCharacter, results)
+ tryIndex(state, text, position, results)
+ trySymbol(state, text, position, results)
end
else
- local word = lookBackward.findWord(text, offset)
+ local word = lookBackward.findWord(text, guide.positionToOffset(state, position))
if word then
- checkCommon(nil, word, text, offset, results)
+ checkCommon(nil, word, text, position, results)
end
end
tracy.ZoneEnd()
@@ -2031,7 +2029,7 @@ local function completion(uri, offset, triggerCharacter)
end
tracy.ZoneBeginN 'completion #3'
- makeCache(uri, offset, results)
+ makeCache(uri, position, results)
tracy.ZoneEnd()
return results
end
diff --git a/script/core/diagnostics/count-down-loop.lua b/script/core/diagnostics/count-down-loop.lua
index 1a7dcf7d..49c48880 100644
--- a/script/core/diagnostics/count-down-loop.lua
+++ b/script/core/diagnostics/count-down-loop.lua
@@ -10,30 +10,39 @@ return function (uri, callback)
end
guide.eachSourceType(state.ast, 'loop', function (source)
- if not source.loc or not source.loc.value then
- return
- end
local maxNumer = source.max and tonumber(source.max[1])
if maxNumer ~= 1 then
return
end
- local minNumber = source.loc and source.loc.value and tonumber(source.loc.value[1])
+ local minNumber = source.init and tonumber(source.init[1])
if minNumber and minNumber <= 1 then
return
end
if not source.step then
callback {
- start = source.loc.value.start,
+ start = source.init.start,
finish = source.max.finish,
- message = lang.script('DIAG_COUNT_DOWN_LOOP', ('%s, %s'):format(text:sub(source.loc.value.start, source.max.finish), '-1'))
+ message = lang.script('DIAG_COUNT_DOWN_LOOP'
+ , ('%s, %s'):format(text:sub(
+ guide.positionToOffset(state, source.init.start),
+ guide.positionToOffset(state, source.max.finish)
+ )
+ , '-1')
+ )
}
else
local stepNumber = tonumber(source.step[1])
if stepNumber and stepNumber > 0 then
callback {
- start = source.loc.value.start,
+ start = source.init.start,
finish = source.step.finish,
- message = lang.script('DIAG_COUNT_DOWN_LOOP', ('%s, -%s'):format(text:sub(source.loc.value.start, source.max.finish), source.step[1]))
+ message = lang.script('DIAG_COUNT_DOWN_LOOP'
+ , ('%s, -%s'):format(text:sub(
+ guide.positionToOffset(state, source.init.start),
+ guide.positionToOffset(state, source.max.finish)
+ )
+ , source.step[1])
+ )
}
end
end
diff --git a/script/core/diagnostics/different-requires.lua b/script/core/diagnostics/different-requires.lua
index 909342f4..fd7415b6 100644
--- a/script/core/diagnostics/different-requires.lua
+++ b/script/core/diagnostics/different-requires.lua
@@ -12,7 +12,7 @@ return function (uri, callback)
end
local cache = vm.getCache 'different-requires'
guide.eachSpecialOf(state.ast, 'require', function (source)
- local call = source.next
+ local call = source.parent
if not call or call.type ~= 'call' then
return
end
diff --git a/script/core/diagnostics/init.lua b/script/core/diagnostics/init.lua
index 09688f6e..63a1bcf0 100644
--- a/script/core/diagnostics/init.lua
+++ b/script/core/diagnostics/init.lua
@@ -44,7 +44,7 @@ local function check(uri, name, results)
if vm.isDiagDisabledAt(uri, result.start, name) then
return
end
- if result.start == 0 then
+ if result.start < 0 then
return
end
if mark[result.start] then
diff --git a/script/core/diagnostics/newfield-call.lua b/script/core/diagnostics/newfield-call.lua
index fe86ad66..669ed2bb 100644
--- a/script/core/diagnostics/newfield-call.lua
+++ b/script/core/diagnostics/newfield-call.lua
@@ -8,7 +8,6 @@ return function (uri, callback)
return
end
- local lines = files.getLines(uri)
local text = files.getText(uri)
guide.eachSourceType(ast.ast, 'table', function (source)
@@ -27,8 +26,8 @@ return function (uri, callback)
local func = call.node
local args = call.args
if args then
- local funcLine = guide.positionOf(lines, func.finish)
- local argsLine = guide.positionOf(lines, args.start)
+ local funcLine = guide.rowColOf(func.finish)
+ local argsLine = guide.rowColOf(args.start)
if argsLine > funcLine then
callback {
start = call.start,
diff --git a/script/core/diagnostics/newline-call.lua b/script/core/diagnostics/newline-call.lua
index 71dc33e2..dbb8c690 100644
--- a/script/core/diagnostics/newline-call.lua
+++ b/script/core/diagnostics/newline-call.lua
@@ -3,14 +3,13 @@ local guide = require 'parser.guide'
local lang = require 'language'
return function (uri, callback)
- local ast = files.getState(uri)
- local lines = files.getLines(uri)
+ local state = files.getState(uri)
local text = files.getText(uri)
- if not ast or not lines then
+ if not state then
return
end
- guide.eachSourceType(ast.ast, 'call', function (source)
+ guide.eachSourceType(state.ast, 'call', function (source)
local node = source.node
local args = source.args
if not args then
@@ -21,13 +20,15 @@ return function (uri, callback)
if not source.next then
return
end
- if text:sub(args.start, args.start) ~= '('
- or text:sub(args.finish, args.finish) ~= ')' then
+ local startOffset = guide.positionToOffset(state, args.start) + 1
+ local finishOffset = guide.positionToOffset(state, args.finish)
+ if text:sub(startOffset, startOffset) ~= '('
+ or text:sub(finishOffset, finishOffset) ~= ')' then
return
end
- local nodeRow = guide.positionOf(lines, node.finish)
- local argRow = guide.positionOf(lines, args.start)
+ local nodeRow = guide.rowColOf(node.finish)
+ local argRow = guide.rowColOf(args.start)
if nodeRow == argRow then
return
end
diff --git a/script/core/diagnostics/redundant-value.lua b/script/core/diagnostics/redundant-value.lua
index d6cd97a7..4c913330 100644
--- a/script/core/diagnostics/redundant-value.lua
+++ b/script/core/diagnostics/redundant-value.lua
@@ -1,24 +1,24 @@
local files = require 'files'
local define = require 'proto.define'
local lang = require 'language'
+local guide = require 'parser.guide'
+local await = require 'await'
-return function (uri, callback, code)
- local ast = files.getState(uri)
- if not ast then
+return function (uri, callback)
+ local state = files.getState(uri)
+ if not state then
return
end
- local diags = ast.diags[code]
- if not diags then
- return
- end
-
- for _, info in ipairs(diags) do
- callback {
- start = info.start,
- finish = info.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script('DIAG_OVER_MAX_VALUES', info.max, info.passed)
- }
- end
+ guide.eachSource(state.ast, function (src)
+ await.delay()
+ if src.redundant then
+ callback {
+ start = src.start,
+ finish = src.finish,
+ tags = { define.DiagnosticTag.Unnecessary },
+ message = lang.script('DIAG_OVER_MAX_VALUES', src.redundant.max, src.redundant.passed)
+ }
+ end
+ end)
end
diff --git a/script/core/diagnostics/trailing-space.lua b/script/core/diagnostics/trailing-space.lua
index 824eb83f..cc51cf77 100644
--- a/script/core/diagnostics/trailing-space.lua
+++ b/script/core/diagnostics/trailing-space.lua
@@ -13,40 +13,43 @@ local function isInString(ast, offset)
end
return function (uri, callback)
- local ast = files.getState(uri)
- if not ast then
+ local state = files.getState(uri)
+ if not state then
return
end
local text = files.getText(uri)
- local lines = files.getLines(uri)
- for i = 1, #lines do
- local start = lines[i].start
- local range = lines[i].range
- local lastChar = text:sub(range, range)
+ local lines = state.lines
+ for i = 0, #lines do
+ local startOffset = lines[i]
+ local finishOffset = text:find('[\r\n]', startOffset) or (#text + 1)
+ local lastOffset = finishOffset - 1
+ local lastChar = text:sub(lastOffset, lastOffset)
if lastChar ~= ' ' and lastChar ~= '\t' then
goto NEXT_LINE
end
- if isInString(ast.ast, range) then
+ local lastPos = guide.offsetToPosition(state, lastOffset)
+ if isInString(state.ast, lastPos) then
goto NEXT_LINE
end
- local first = start
- for n = range - 1, start, -1 do
+ local firstOffset = startOffset
+ for n = lastOffset - 1, startOffset, -1 do
local char = text:sub(n, n)
if char ~= ' ' and char ~= '\t' then
- first = n + 1
+ firstOffset = n + 1
break
end
end
- if first == start then
+ local firstPos = guide.offsetToPosition(state, firstOffset) - 1
+ if firstOffset == startOffset then
callback {
- start = first,
- finish = range,
+ start = firstPos,
+ finish = lastPos,
message = lang.script.DIAG_LINE_ONLY_SPACE,
}
else
callback {
- start = first,
- finish = range,
+ start = firstPos,
+ finish = lastPos,
message = lang.script.DIAG_LINE_POST_SPACE,
}
end
diff --git a/script/core/diagnostics/undefined-global.lua b/script/core/diagnostics/undefined-global.lua
index c7ddeac2..14754c16 100644
--- a/script/core/diagnostics/undefined-global.lua
+++ b/script/core/diagnostics/undefined-global.lua
@@ -5,6 +5,7 @@ local config = require 'config'
local guide = require 'parser.guide'
local noder = require 'core.noder'
local collector = require 'core.collector'
+local await = require 'await'
local requireLike = {
['include'] = true,
@@ -35,6 +36,7 @@ return function (uri, callback)
if node.tag ~= '_ENV' then
return
end
+ await.delay()
local id = 'def:' .. noder.getID(src)
if not collector.has(id) then
local message = lang.script('DIAG_UNDEF_GLOBAL', key)
diff --git a/script/core/document-symbol.lua b/script/core/document-symbol.lua
index 9f950d25..cfabedab 100644
--- a/script/core/document-symbol.lua
+++ b/script/core/document-symbol.lua
@@ -5,20 +5,26 @@ local define = require 'proto.define'
local util = require 'utility'
local function buildName(source, text)
+ local uri = guide.getUri(source)
+ local state = files.getState(uri)
+ local startOffset = guide.positionToOffset(state, source.start)
if source.type == 'setmethod'
or source.type == 'getmethod' then
if source.method then
- return text:sub(source.start, source.method.finish)
+ local finishOffset = guide.positionToOffset(state, source.method.finish)
+ return text:sub(startOffset + 1, finishOffset)
end
end
if source.type == 'setfield'
or source.type == 'tablefield'
or source.type == 'getfield' then
if source.field then
- return text:sub(source.start, source.field.finish)
+ local finishOffset = guide.positionToOffset(state, source.field.finish)
+ return text:sub(startOffset + 1, finishOffset)
end
end
- return text:sub(source.start, source.finish)
+ local finishOffset = guide.positionToOffset(state, source.finish)
+ return text:sub(startOffset + 1, finishOffset)
end
local function buildFunctionParams(func)
@@ -208,7 +214,7 @@ local function buildAnonymousFunction(source, text, used, symbols)
detail = ('%sfunction (%s)'):format(head, buildFunctionParams(source)),
kind = define.SymbolKind.Function,
range = { source.start, source.finish },
- selectionRange = { source.start, source.start },
+ selectionRange = { source.keyword[1], source.keyword[2] },
valueRange = { source.start, source.finish },
}
end
diff --git a/script/core/find-source.lua b/script/core/find-source.lua
index edbb1e2c..26a411e5 100644
--- a/script/core/find-source.lua
+++ b/script/core/find-source.lua
@@ -11,12 +11,12 @@ local function isValidFunctionPos(source, offset)
return false
end
-return function (ast, offset, accept)
+return function (ast, position, accept)
local len = math.huge
local result
- guide.eachSourceContain(ast.ast, offset, function (source)
+ guide.eachSourceContain(ast.ast, position, function (source)
if source.type == 'function' then
- if not isValidFunctionPos(source, offset) then
+ if not isValidFunctionPos(source, position) then
return
end
end
diff --git a/script/core/highlight.lua b/script/core/highlight.lua
index 47b482d5..02f3c07f 100644
--- a/script/core/highlight.lua
+++ b/script/core/highlight.lua
@@ -54,12 +54,12 @@ local function find(source, uri, callback)
end
end
-local function checkInIf(source, text, offset)
+local function checkInIf(state, source, text, position)
-- 检查 end
- local endA = source.finish - #'end' + 1
- local endB = source.finish
- if offset >= endA
- and offset <= endB
+ local endB = guide.positionToOffset(state, source.finish)
+ local endA = endB - #'end' + 1
+ if position >= source.finish - #'end'
+ and position <= source.finish
and text:sub(endA, endB) == 'end' then
return true
end
@@ -68,7 +68,7 @@ local function checkInIf(source, text, offset)
for i = 1, #block.keyword, 2 do
local start = block.keyword[i]
local finish = block.keyword[i+1]
- if offset >= start and offset <= finish then
+ if position >= start and position <= finish then
return true
end
end
@@ -76,12 +76,12 @@ local function checkInIf(source, text, offset)
return false
end
-local function makeIf(source, text, callback)
+local function makeIf(state, source, text, callback)
-- end
- local endA = source.finish - #'end' + 1
- local endB = source.finish
+ local endB = guide.positionToOffset(state, source.finish)
+ local endA = endB - #'end' + 1
if text:sub(endA, endB) == 'end' then
- callback(endA, endB)
+ callback(source.finish - #'end', source.finish)
end
-- 每个子模块
for _, block in ipairs(source) do
@@ -94,8 +94,8 @@ local function makeIf(source, text, callback)
return false
end
-local function findKeyWord(ast, text, offset, callback)
- guide.eachSourceContain(ast.ast, offset, function (source)
+local function findKeyWord(state, text, position, callback)
+ guide.eachSourceContain(state.ast, position, function (source)
if source.type == 'do'
or source.type == 'function'
or source.type == 'loop'
@@ -106,7 +106,7 @@ local function findKeyWord(ast, text, offset, callback)
for i = 1, #source.keyword, 2 do
local start = source.keyword[i]
local finish = source.keyword[i+1]
- if offset >= start and offset <= finish then
+ if position >= start and position <= finish then
ok = true
break
end
@@ -119,9 +119,9 @@ local function findKeyWord(ast, text, offset, callback)
end
end
elseif source.type == 'if' then
- local ok = checkInIf(source, text, offset)
+ local ok = checkInIf(state, source, text, position)
if ok then
- makeIf(source, text, callback)
+ makeIf(state, source, text, callback)
end
end
end)
@@ -238,15 +238,15 @@ local function isLiteralValue(source)
end
return function (uri, offset)
- local ast = files.getState(uri)
- if not ast then
+ local state = files.getState(uri)
+ if not state then
return nil
end
local text = files.getText(uri)
local results = {}
local mark = {}
- local source = findSource(ast, offset, accept)
+ local source = findSource(state, offset, accept)
if source then
local isGlobal = guide.isGlobal(source)
local isLiteral = isLiteralValue(source)
@@ -344,7 +344,7 @@ return function (uri, offset)
end)
end
- findKeyWord(ast, text, offset, function (start, finish)
+ findKeyWord(state, text, offset, function (start, finish)
results[#results+1] = {
start = start,
finish = finish,
@@ -352,7 +352,7 @@ return function (uri, offset)
}
end)
- checkRegion(ast, text, offset, function (start, finish)
+ checkRegion(state, text, offset, function (start, finish)
results[#results+1] = {
start = start,
finish = finish,
diff --git a/script/core/hover/label.lua b/script/core/hover/label.lua
index a29cf672..3322e0d3 100644
--- a/script/core/hover/label.lua
+++ b/script/core/hover/label.lua
@@ -50,8 +50,7 @@ local function asValue(source, title)
local literal = infer.searchAndViewLiterals(source)
local cont
if not infer.hasType(source, 'string')
- and not type:find('%[%]$')
- and not type:find('%w%<') then
+ and not type:find('%[%]$') then
if #vm.getRefs(source, '*') > 0
or infer.hasType(source, 'table') then
cont = buildTable(source)
diff --git a/script/core/infer.lua b/script/core/infer.lua
index d6784c67..2915f7f5 100644
--- a/script/core/infer.lua
+++ b/script/core/infer.lua
@@ -371,9 +371,10 @@ function m.getDocName(doc)
return nodeName .. '[]'
end
if doc.type == 'doc.type.table' then
- local key = m.viewDocName(doc.tkey) or '?'
+ local node = m.viewDocName(doc.node) or '?'
+ local key = m.viewDocName(doc.tkey) or '?'
local value = m.viewDocName(doc.tvalue) or '?'
- return ('table<%s, %s>'):format(key, value)
+ return ('%s<%s, %s>'):format(node, key, value)
end
if doc.type == 'doc.type.function' then
return m.viewDocFunction(doc)
diff --git a/script/core/keyword.lua b/script/core/keyword.lua
index b8e37605..295026d7 100644
--- a/script/core/keyword.lua
+++ b/script/core/keyword.lua
@@ -24,14 +24,12 @@ end",
end
return true
end, function (info)
- return guide.eachSourceContain(info.ast.ast, info.start, function (source)
+ return guide.eachSourceContain(info.state.ast, info.start, function (source)
if source.type == 'while'
or source.type == 'in'
or source.type == 'loop' then
- for i = 1, #source.keyword do
- if info.start == source.keyword[i] then
- return true
- end
+ if source.finish - info.start <= 2 then
+ return true
end
end
end)
@@ -40,8 +38,9 @@ end",
{'break'},
{'else'},
{'elseif', function (info, results)
- if info.text:find('^%s*then', info.offset + 1)
- or info.text:find('^%s*do', info.offset + 1) then
+ local offset = guide.positionToOffset(info.state, info.position)
+ if info.text:find('^%s*then', offset + 1)
+ or info.text:find('^%s*do', offset + 1) then
return false
end
if info.hasSpace then
@@ -155,8 +154,9 @@ end"
end},
{'goto'},
{'if', function (info, results)
- if info.text:find('^%s*then', info.offset + 1)
- or info.text:find('^%s*do', info.offset + 1) then
+ local offset = guide.positionToOffset(info.state, info.position)
+ if info.text:find('^%s*then', offset + 1)
+ or info.text:find('^%s*do', offset + 1) then
return false
end
if info.hasSpace then
@@ -183,8 +183,9 @@ end"
return true
end},
{'in', function (info, results)
- if info.text:find('^%s*then', info.offset + 1)
- or info.text:find('^%s*do', info.offset + 1) then
+ local offset = guide.positionToOffset(info.state, info.position)
+ if info.text:find('^%s*then', offset + 1)
+ or info.text:find('^%s*do', offset + 1) then
return false
end
if info.hasSpace then
@@ -270,15 +271,16 @@ until $1"
return false
end},
{'then', function (info, results)
- local lines = files.getLines(info.uri)
- local pos, first = info.text:match('%S+%s+()(%S+)', info.start)
+ local startOffset = guide.positionToOffset(info.state, info.start)
+ local pos, first = info.text:match('%S+%s+()(%S+)', startOffset + 1)
if first == 'end'
or first == 'else'
or first == 'elseif' then
- local startRow = guide.positionOf(lines, info.start)
- local finishRow = guide.positionOf(lines, pos)
- local startSp = info.text:match('^%s*', lines[startRow].start + 1)
- local finishSp = info.text:match('^%s*', lines[finishRow].start + 1)
+ local startRow = guide.rowColOf(info.start)
+ local finishPosition = guide.offsetToPosition(info.state, pos)
+ local finishRow = guide.rowColOf(finishPosition)
+ local startSp = info.text:match('^%s*', info.state.lines[startRow])
+ local finishSp = info.text:match('^%s*', info.state.lines[finishRow])
if startSp == finishSp then
return false
end
diff --git a/script/core/look-backward.lua b/script/core/look-backward.lua
index ee89078f..2f90b768 100644
--- a/script/core/look-backward.lua
+++ b/script/core/look-backward.lua
@@ -77,7 +77,7 @@ function m.findTargetSymbol(text, offset, symbol)
return nil
end
-function m.findAnyPos(text, offset)
+function m.findAnyOffset(text, offset)
for i = offset, 1, -1 do
if not m.isSpace(text:sub(i, i)) then
return i
diff --git a/script/core/noder.lua b/script/core/noder.lua
index 3fd316eb..f364f458 100644
--- a/script/core/noder.lua
+++ b/script/core/noder.lua
@@ -905,6 +905,9 @@ compileNodeMap = util.switch()
end)
: case 'doc.type.table'
: call(function (noders, id, source)
+ if source.node then
+ pushForward(noders, id, getID(source.node), INFO_CLASS_TO_EXNTENDS)
+ end
if source.tkey then
local keyID = id .. TABLE_KEY
pushForward(noders, keyID, getID(source.tkey))
@@ -1231,6 +1234,55 @@ compileNodeMap = util.switch()
end
end
end)
+ : case 'in'
+ : call(function (noders, id, source)
+ local keys = source.keys
+ local exps = source.exps
+ if not keys or not exps then
+ return
+ end
+ local node = exps[1]
+ local param1 = exps[2]
+ local param2 = exps[3]
+ if node.type == 'call' then
+ if not param1 then
+ param1 = {
+ type = 'select',
+ dummy = true,
+ sindex = 2,
+ start = node.start,
+ finish = node.finish,
+ vararg = node,
+ parent = source,
+ }
+ compileCallReturn(noders, node, getID(param1), 2)
+ if not param2 then
+ param2 = {
+ type = 'select',
+ dummy = true,
+ sindex = 3,
+ start = node.start,
+ finish = node.finish,
+ vararg = node,
+ parent = source,
+ }
+ compileCallReturn(noders, node, getID(param2), 3)
+ end
+ end
+ end
+ local call = {
+ type = 'call',
+ dummy = true,
+ start = source.keyword[3],
+ finish = exps[#exps].finish,
+ node = node,
+ args = { param1, param2 },
+ parent = source,
+ }
+ for i = 1, #keys do
+ compileCallReturn(noders, call, getID(keys[i]), i)
+ end
+ end)
: case 'main'
: call(function (noders, id, source)
if source.returns then
@@ -1288,7 +1340,7 @@ function m.compileNode(noders, source)
local id = getID(source)
bindValue(noders, source, id)
- if specialMap[source.special] then
+ if id and specialMap[source.special] then
noders.skip[id] = true
end
@@ -1534,11 +1586,6 @@ local partNodersMap = util.switch()
m.compilePartNodes(noders, ref)
end
end
-
- local nxt = source.next
- if nxt then
- m.compilePartNodes(noders, nxt)
- end
end)
: case 'setlocal'
: case 'getlocal'
@@ -1554,6 +1601,14 @@ local partNodersMap = util.switch()
if parent.value == source then
m.compilePartNodes(noders, parent)
end
+
+ if parent.type == 'call' then
+ local node = parent.node
+ if node.special == 'rawset'
+ or node.special == 'rawget' then
+ m.compilePartNodes(noders, parent)
+ end
+ end
end)
: case 'setfield'
: case 'getfield'
@@ -1585,6 +1640,14 @@ local partNodersMap = util.switch()
if parent.value == source then
m.compilePartNodes(noders, parent)
end
+
+ if parent.type == 'call' then
+ local node = parent.node
+ if node.special == 'rawset'
+ or node.special == 'rawget' then
+ m.compilePartNodes(noders, parent)
+ end
+ end
end)
: case 'label'
: call(function (noders, source)
diff --git a/script/core/reference.lua b/script/core/reference.lua
index 5f5831c6..067d2e23 100644
--- a/script/core/reference.lua
+++ b/script/core/reference.lua
@@ -52,13 +52,13 @@ local accept = {
['doc.alias.name'] = true,
}
-return function (uri, offset)
+return function (uri, position)
local ast = files.getState(uri)
if not ast then
return nil
end
- local source = findSource(ast, offset, accept)
+ local source = findSource(ast, position, accept)
if not source then
return nil
end
diff --git a/script/core/rename.lua b/script/core/rename.lua
index 0ab7a055..0c48dbc4 100644
--- a/script/core/rename.lua
+++ b/script/core/rename.lua
@@ -36,12 +36,12 @@ local function isValidFunctionName(str)
if isValidGlobal(str) then
return true
end
- local pos = str:find(':', 1, true)
- if not pos then
+ local offset = str:find(':', 1, true)
+ if not offset then
return false
end
- return isValidGlobal(trim(str:sub(1, pos-1)))
- and isValidName(trim(str:sub(pos+1)))
+ return isValidGlobal(trim(str:sub(1, offset-1)))
+ and isValidName(trim(str:sub(offset+1)))
end
local function isFunctionGlobalName(source)
@@ -81,21 +81,26 @@ local function renameField(source, newname, callback)
elseif parent.type == 'getmethod' then
callback(source, source.start, source.finish, newname)
elseif parent.type == 'setmethod' then
- local uri = guide.getUri(source)
- local text = files.getText(uri)
+ local uri = guide.getUri(source)
+ local text = files.getText(uri)
+ local state = files.getState(uri)
local func = parent.value
-- function mt:name () end --> mt['newname'] = function (self) end
+ local startOffset = guide.positionToOffset(state, parent.start) + 1
+ local finishOffset = guide.positionToOffset(state, parent.node.finish)
local newstr = string.format('%s[%s] = function '
- , text:sub(parent.start, parent.node.finish)
+ , text:sub(startOffset, finishOffset)
, util.viewString(newname)
)
callback(source, func.start, parent.finish, newstr)
- local pl = text:find('(', parent.finish, true)
+ local finishOffset = guide.positionToOffset(state, parent.finish)
+ local pl = text:find('(', finishOffset, true)
if pl then
+ local insertPos = guide.offsetToPosition(state, pl)
if text:find('^%s*%)', pl + 1) then
- callback(source, pl + 1, pl, 'self')
+ callback(source, insertPos, insertPos, 'self')
else
- callback(source, pl + 1, pl, 'self, ')
+ callback(source, insertPos, insertPos, 'self, ')
end
end
end
diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua
index 96cbc5e1..405f2735 100644
--- a/script/core/semantic-tokens.lua
+++ b/script/core/semantic-tokens.lua
@@ -5,6 +5,7 @@ local define = require 'proto.define'
local vm = require 'vm'
local util = require 'utility'
local guide = require 'parser.guide'
+local converter = require 'proto.converter'
local Care = {}
Care['setglobal'] = function (source, results)
@@ -188,8 +189,8 @@ local function buildTokens(uri, results)
local lastLine = 0
local lastStartChar = 0
for i, source in ipairs(results) do
- local startPos = files.position(uri, source.start, 'left')
- local finishPos = files.position(uri, source.finish, 'right')
+ local startPos = converter.packPosition(uri, source.start)
+ local finishPos = converter.packPosition(uri, source.finish)
local line = startPos.line
local startChar = startPos.character
local deltaLine = line - lastLine
@@ -214,7 +215,6 @@ end
return function (uri, start, finish)
local ast = files.getState(uri)
- local lines = files.getLines(uri)
local text = files.getText(uri)
if not ast then
return nil
diff --git a/script/core/signature.lua b/script/core/signature.lua
index 26d9867c..007a3787 100644
--- a/script/core/signature.lua
+++ b/script/core/signature.lua
@@ -7,20 +7,22 @@ local guide = require 'parser.guide'
local lookback = require 'core.look-backward'
local function findNearCall(uri, ast, pos)
- local text = files.getText(uri)
+ local text = files.getText(uri)
+ local state = files.getState(uri)
local nearCall
guide.eachSourceContain(ast.ast, pos, function (src)
if src.type == 'call'
or src.type == 'table'
or src.type == 'function' then
+ local finishOffset = guide.positionToOffset(state, src.finish)
-- call(),$
if src.finish <= pos
- and text:sub(src.finish, src.finish) == ')' then
+ and text:sub(finishOffset, finishOffset) == ')' then
return
end
-- {},$
if src.finish <= pos
- and text:sub(src.finish, src.finish) == '}' then
+ and text:sub(finishOffset, finishOffset) == '}' then
return
end
if not nearCall or nearCall.start <= src.start then
@@ -56,13 +58,13 @@ local function makeOneSignature(source, oop, index)
for start, finish in converted:gmatch '%s*()[^,]+()' do
i = i + 1
params[i] = {
- label = {start + argStart, finish - 1 + argStart},
+ label = {start + argStart - 1, finish - 1 + argStart},
}
end
-- 不定参数
if index > i and i > 0 then
local lastLabel = params[i].label
- local text = label:sub(lastLabel[1], lastLabel[2])
+ local text = label:sub(lastLabel[1] + 1, lastLabel[2])
if text == '...' then
index = i
end
@@ -88,11 +90,15 @@ local function makeSignatures(text, call, pos)
args[#args+1] = arg
end
end
+ local uri = guide.getUri(call)
+ local state = files.getState(uri)
for i, arg in ipairs(args) do
- local start = lookback.findTargetSymbol(text, arg.start - 1, '(')
- or lookback.findTargetSymbol(text, arg.start - 1, ',')
- or arg.start
- if start > pos then
+ local startOffset = guide.positionToOffset(state, arg.start)
+ startOffset = lookback.findTargetSymbol(text, startOffset, '(')
+ or lookback.findTargetSymbol(text, startOffset, ',')
+ or startOffset
+ local startPos = guide.offsetToPosition(state, startOffset)
+ if startPos > pos then
index = i - 1
break
end
@@ -102,7 +108,8 @@ local function makeSignatures(text, call, pos)
end
end
if not index then
- local backSymbol = lookback.findSymbol(text, pos)
+ local offset = guide.positionToOffset(state, pos)
+ local backSymbol = lookback.findSymbol(text, offset)
if backSymbol == ','
or backSymbol == '(' then
index = #args + 1
@@ -130,13 +137,14 @@ local function makeSignatures(text, call, pos)
end
return function (uri, pos)
- local ast = files.getState(uri)
- if not ast then
+ local state = files.getState(uri)
+ if not state then
return nil
end
local text = files.getText(uri)
- pos = lookback.skipSpace(text, pos)
- local call = findNearCall(uri, ast, pos)
+ local offset = guide.positionToOffset(state, pos)
+ pos = guide.offsetToPosition(state, lookback.skipSpace(text, offset))
+ local call = findNearCall(uri, state, pos)
if not call then
return nil
end
diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua
index a225d9d7..b946184b 100644
--- a/script/core/type-formatting.lua
+++ b/script/core/type-formatting.lua
@@ -2,85 +2,89 @@ local files = require 'files'
local lookBackward = require 'core.look-backward'
local guide = require "parser.guide"
-local function insertIndentation(uri, offset, edits)
- local lines = files.getLines(uri)
- local text = files.getOriginText(uri)
- local row = guide.positionOf(lines, offset)
- local line = lines[row]
- local indent = text:sub(line.start, line.finish):match '^%s*'
+local function insertIndentation(uri, position, edits)
+ local text = files.getText(uri)
+ local state = files.getState(uri)
+ local row = guide.rowColOf(position)
+ local offset = state.lines[row]
+ local indent = text:match('^%s*', offset)
for _, edit in ipairs(edits) do
edit.text = edit.text:gsub('\n', '\n' .. indent)
end
end
-local function findForward(text, offset, ...)
- local pos = text:match('^[ \t]*()', offset)
- if not pos then
+local function findForward(uri, position, ...)
+ local text = files.getText(uri)
+ local state = files.getState(uri)
+ local offset = guide.positionToOffset(state, position)
+ local firstOffset = text:match('^[ \t]*()', offset + 1)
+ if not firstOffset then
return nil
end
for _, symbol in ipairs { ... } do
- if text:sub(pos, pos + #symbol - 1) == symbol then
- return pos, symbol
+ if text:sub(firstOffset, firstOffset + #symbol - 1) == symbol then
+ return guide.offsetToPosition(state, firstOffset - 1), symbol
end
end
return nil
end
-local function findBackward(text, offset, ...)
- local pos = lookBackward.findAnyPos(text, offset)
+local function findBackward(uri, position, ...)
+ local text = files.getText(uri)
+ local state = files.getState(uri)
+ local offset = guide.positionToOffset(state, position)
+ local lastOffset = lookBackward.findAnyOffset(text, offset)
for _, symbol in ipairs { ... } do
- if text:sub(pos - #symbol + 1, pos) == symbol then
- return pos - #symbol + 1, symbol
+ if text:sub(lastOffset - #symbol + 1, lastOffset) == symbol then
+ return guide.offsetToPosition(state, lastOffset)
end
end
return nil
end
-local function checkSplitOneLine(results, uri, offset, ch)
+local function checkSplitOneLine(results, uri, position, ch)
if ch ~= '\n' then
return
end
- local text = files.getOriginText(uri)
- local fOffset, fSymbol = findForward(text, offset + 1, 'end', '}')
- if not fOffset then
+ local fPosition, fSymbol = findForward(uri, position, 'end', '}')
+ if not fPosition then
return
end
- local bOffset, bSymbol = findBackward(text, offset, 'then', 'do', ')', '{')
- if not bOffset then
+ local bPosition = findBackward(uri, position, 'then', 'do', ')', '{')
+ if not bPosition then
return
end
local edits = {}
edits[#edits+1] = {
- start = bOffset + #bSymbol,
- finish = offset,
+ start = bPosition,
+ finish = position,
text = '\n\t',
}
edits[#edits+1] = {
- start = offset + 1,
- finish = fOffset + #fSymbol - 1,
- text = ''
+ start = position,
+ finish = fPosition + 1,
+ text = '',
}
edits[#edits+1] = {
- start = fOffset + #fSymbol,
- finish = fOffset + #fSymbol - 1,
- text = '\n' .. fSymbol
+ start = fPosition + 1,
+ finish = fPosition + 1,
+ text = '\n' .. fSymbol:sub(1, 1)
}
- insertIndentation(uri, bOffset, edits)
+ insertIndentation(uri, bPosition, edits)
for _, edit in ipairs(edits) do
results[#results+1] = edit
end
end
-return function (uri, offset, ch)
+return function (uri, position, ch)
local ast = files.getState(uri)
- local text = files.getOriginText(uri)
- if not ast or not text then
+ if not ast then
return nil
end
local results = {}
-- split `function () $ end`
- checkSplitOneLine(results, uri, offset, ch)
+ checkSplitOneLine(results, uri, position, ch)
return results
end