summaryrefslogtreecommitdiff
path: root/script
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2024-08-15 15:16:03 +0800
committerGitHub <noreply@github.com>2024-08-15 15:16:03 +0800
commit2c798703ca854d670fb28f51adc85c2b41f08f37 (patch)
treeaa192cf6d6ed02d02dda8c8b7a4c240dded64efb /script
parentabd5daae1885cdf7a9e21a1cbdfea945385124fc (diff)
parentb71cb7aecd9337c9463a4dfbdb9d06cac7b825fd (diff)
downloadlua-language-server-2c798703ca854d670fb28f51adc85c2b41f08f37.zip
Merge branch 'master' into cast-table-to-class
Diffstat (limited to 'script')
-rw-r--r--script/cli/check.lua7
-rw-r--r--script/core/code-lens.lua36
-rw-r--r--script/core/completion/postfix.lua2
-rw-r--r--script/core/diagnostics/missing-fields.lua78
-rw-r--r--script/core/diagnostics/unused-function.lua6
-rw-r--r--script/core/fix-indent.lua211
-rw-r--r--script/core/hint.lua3
-rw-r--r--script/core/type-formatting.lua195
-rw-r--r--script/lclient.lua28
-rw-r--r--script/library.lua2
-rw-r--r--script/parser/guide.lua2
-rw-r--r--script/plugin.lua2
-rw-r--r--script/provider/language-configuration.lua86
-rw-r--r--script/provider/provider.lua21
-rw-r--r--script/service/service.lua10
-rw-r--r--script/vm/compiler.lua12
-rw-r--r--script/vm/def.lua2
-rw-r--r--script/vm/operator.lua9
-rw-r--r--script/vm/type.lua2
19 files changed, 473 insertions, 241 deletions
diff --git a/script/cli/check.lua b/script/cli/check.lua
index 8b314f24..c3aac0e3 100644
--- a/script/cli/check.lua
+++ b/script/cli/check.lua
@@ -8,7 +8,12 @@ local util = require 'utility'
local numThreads = tonumber(NUM_THREADS or 1)
-local exe = arg[-1]
+local exe
+local minIndex = -1
+while arg[minIndex] do
+ exe = arg[minIndex]
+ minIndex = minIndex - 1
+end
-- TODO: is this necessary? got it from the shell.lua helper in bee.lua tests
if platform.os == 'windows' and not exe:match('%.[eE][xX][eE]$') then
exe = exe..'.exe'
diff --git a/script/core/code-lens.lua b/script/core/code-lens.lua
index bc39ec86..bebfeedf 100644
--- a/script/core/code-lens.lua
+++ b/script/core/code-lens.lua
@@ -4,6 +4,7 @@ local await = require 'await'
local conv = require 'proto.converter'
local getRef = require 'core.reference'
local lang = require 'language'
+local client = require 'client'
---@class parser.state
---@field package _codeLens? codeLens
@@ -88,12 +89,35 @@ end
function mt:resolveReference(source)
local refs = getRef(self.uri, source.finish, false)
local count = refs and #refs or 0
- local command = conv.command(
- lang.script('COMMAND_REFERENCE_COUNT', count),
- '',
- {}
- )
- return command
+ if client.getOption('codeLensViewReferences') then
+ local locations = {}
+ for _, ref in ipairs(refs or {}) do
+ local state = files.getState(ref.uri)
+ if state then
+ locations[#locations+1] = conv.location(
+ ref.uri,
+ conv.packRange(state, ref.target.start, ref.target.finish)
+ )
+ end
+ end
+ local command = conv.command(
+ lang.script('COMMAND_REFERENCE_COUNT', count),
+ 'lua.showReferences',
+ {
+ self.uri,
+ conv.packPosition(self.state, source.start),
+ locations,
+ }
+ )
+ return command
+ else
+ local command = conv.command(
+ lang.script('COMMAND_REFERENCE_COUNT', count),
+ '',
+ {}
+ )
+ return command
+ end
end
---@async
diff --git a/script/core/completion/postfix.lua b/script/core/completion/postfix.lua
index b5f33315..46c24b8e 100644
--- a/script/core/completion/postfix.lua
+++ b/script/core/completion/postfix.lua
@@ -353,7 +353,7 @@ local function checkPostFix(state, word, wordPosition, position, symbol, results
end):gsub('%$%{?%d+%}?', '')
results[#results+1] = {
label = action.key,
- kind = define.CompletionItemKind.Event,
+ kind = define.CompletionItemKind.Snippet,
description = markdown()
: add('lua', descText)
: string(),
diff --git a/script/core/diagnostics/missing-fields.lua b/script/core/diagnostics/missing-fields.lua
index 210920fd..5ce650ec 100644
--- a/script/core/diagnostics/missing-fields.lua
+++ b/script/core/diagnostics/missing-fields.lua
@@ -15,61 +15,75 @@ return function (uri, callback)
guide.eachSourceType(state.ast, 'table', function (src)
await.delay()
+ vm.removeNode(src) -- the node is not updated correctly, reason still unknown
local defs = vm.getDefs(src)
+ local sortedDefs = {}
for _, def in ipairs(defs) do
- if def.type == 'doc.class' and def.bindSource then
- if guide.isInRange(def.bindSource, src.start) then
+ if def.type == 'doc.class' then
+ if def.bindSource and guide.isInRange(def.bindSource, src.start) then
return
end
+ local className = def.class[1]
+ if not sortedDefs[className] then
+ sortedDefs[className] = {}
+ end
+ local samedefs = sortedDefs[className]
+ samedefs[#samedefs+1] = def
end
if def.type == 'doc.type.array'
or def.type == 'doc.type.table' then
return
end
end
+
+ local myKeys
local warnings = {}
- for _, def in ipairs(defs) do
- if def.type == 'doc.class' then
- if not def.fields then
- return
+ for className, samedefs in pairs(sortedDefs) do
+ local missedKeys = {}
+ for _, def in ipairs(samedefs) do
+ if not def.fields or #def.fields == 0 then
+ goto continue
+ end
+
+ if not myKeys then
+ myKeys = {}
+ for _, field in ipairs(src) do
+ local key = vm.getKeyName(field) or field.tindex
+ if key then
+ myKeys[key] = true
+ end
+ end
end
- local requiresKeys = {}
for _, field in ipairs(def.fields) do
if not field.optional
and not vm.compileNode(field):isNullable() then
local key = vm.getKeyName(field)
- if key and not requiresKeys[key] then
- requiresKeys[key] = true
- requiresKeys[#requiresKeys+1] = key
+ if not key then
+ local fieldnode = vm.compileNode(field.field)[1]
+ if fieldnode and fieldnode.type == 'doc.type.integer' then
+ ---@cast fieldnode parser.object
+ key = vm.getKeyName(fieldnode)
+ end
end
- end
- end
- if #requiresKeys == 0 then
- return
- end
- local myKeys = {}
- for _, field in ipairs(src) do
- local key = vm.getKeyName(field)
- if key then
- myKeys[key] = true
- end
- end
-
- local missedKeys = {}
- for _, key in ipairs(requiresKeys) do
- if not myKeys[key] then
- missedKeys[#missedKeys+1] = ('`%s`'):format(key)
+ if key and not myKeys[key] then
+ if type(key) == "number" then
+ missedKeys[#missedKeys+1] = ('`[%s]`'):format(key)
+ else
+ missedKeys[#missedKeys+1] = ('`%s`'):format(key)
+ end
+ end
end
end
+ ::continue::
+ end
- if #missedKeys == 0 then
- return
- end
-
- warnings[#warnings+1] = lang.script('DIAG_MISSING_FIELDS', def.class[1], table.concat(missedKeys, ', '))
+ if #missedKeys == 0 then
+ return
end
+
+ warnings[#warnings+1] = lang.script('DIAG_MISSING_FIELDS', className, table.concat(missedKeys, ', '))
end
if #warnings == 0 then
diff --git a/script/core/diagnostics/unused-function.lua b/script/core/diagnostics/unused-function.lua
index a873375f..1145036d 100644
--- a/script/core/diagnostics/unused-function.lua
+++ b/script/core/diagnostics/unused-function.lua
@@ -5,6 +5,7 @@ local define = require 'proto.define'
local lang = require 'language'
local await = require 'await'
local client = require 'client'
+local util = require 'utility'
local function isToBeClosed(source)
if not source.attrs then
@@ -105,8 +106,11 @@ return function (uri, callback)
turnBlack(source, black, white, links)
end
+ local tagSupports = client.getAbility('textDocument.completion.completionItem.tagSupport.valueSet')
+ local supportUnnecessary = tagSupports and util.arrayHas(tagSupports, define.DiagnosticTag.Unnecessary)
+
for source in pairs(white) do
- if client.isVSCode() then
+ if supportUnnecessary then
callback {
start = source.start,
finish = source.finish,
diff --git a/script/core/fix-indent.lua b/script/core/fix-indent.lua
new file mode 100644
index 00000000..59adfb7b
--- /dev/null
+++ b/script/core/fix-indent.lua
@@ -0,0 +1,211 @@
+local files = require 'files'
+local guide = require 'parser.guide'
+local proto = require 'proto.proto'
+local lookBackward = require 'core.look-backward'
+local util = require 'utility'
+local client = require 'client'
+
+---@param state parser.state
+---@param change table
+local function removeSpacesAfterEnter(state, change)
+ if not change.text:match '^\r?\n[\t ]+\r?\n$' then
+ return false
+ end
+ local lines = state.originLines or state.lines
+ local text = state.originText or state.lua
+ ---@cast text -?
+
+ local edits = {}
+ -- 清除前置空格
+ local startPos = guide.positionOf(change.range.start.line, change.range.start.character)
+ local startOffset = guide.positionToOffsetByLines(lines, startPos)
+ local leftOffset
+ for offset = startOffset, lines[change.range.start.line], -1 do
+ leftOffset = offset
+ local char = text:sub(offset, offset)
+ if char ~= ' ' and char ~= '\t' then
+ break
+ end
+ end
+
+ if leftOffset and leftOffset < startOffset then
+ edits[#edits+1] = {
+ start = leftOffset,
+ finish = startOffset,
+ text = '',
+ }
+ end
+
+ -- 清除后置空格
+ local endOffset = startOffset + #change.text
+ local _, rightOffset = text:find('^[\t ]+', endOffset + 1)
+ if rightOffset then
+ edits[#edits+1] = {
+ start = endOffset,
+ finish = rightOffset,
+ text = '',
+ }
+ end
+
+ if #edits == 0 then
+ return nil
+ end
+
+ return edits
+end
+
+local function getIndent(state, row)
+ local offset = state.lines[row]
+ local indent = state.lua:match('^[\t ]*', offset)
+ return indent
+end
+
+local function isInBlock(state, position)
+ local block = guide.eachSourceContain(state.ast, position, function(source)
+ if source.type == 'ifblock'
+ or source.type == 'elseifblock' then
+ if source.keyword[4] and source.keyword[4] <= position then
+ return true
+ end
+ end
+ if source.type == 'else' then
+ if source.keyword[2] and source.keyword[2] <= position then
+ return true
+ end
+ end
+ if source.type == 'while' then
+ if source.keyword[4] and source.keyword[4] <= position then
+ return true
+ end
+ end
+ if source.type == 'repeat' then
+ if source.keyword[2] and source.keyword[2] <= position then
+ return true
+ end
+ end
+ if source.type == 'loop' then
+ if source.keyword[4] and source.keyword[4] <= position then
+ return true
+ end
+ end
+ if source.type == 'in' then
+ if source.keyword[6] and source.keyword[6] <= position then
+ return true
+ end
+ end
+ if source.type == 'do' then
+ if source.keyword[2] and source.keyword[2] <= position then
+ return true
+ end
+ end
+ if source.type == 'function' then
+ if source.args and source.args.finish <= position then
+ return true
+ end
+ if not source.keyword[3] or source.keyword[3] >= position then
+ return true
+ end
+ end
+ if source.type == 'table' then
+ if source.start + 1 == position then
+ return true
+ end
+ end
+ end)
+ return block ~= nil
+end
+
+local function fixWrongIndent(state, change)
+ if not change.text:match '^\r?\n[\t ]+$' then
+ return false
+ end
+ local position = guide.positionOf(change.range.start.line, change.range.start.character)
+ local row = guide.rowColOf(position)
+ local myIndent = getIndent(state, row + 1)
+ local lastOffset = lookBackward.findAnyOffset(state.lua, guide.positionToOffset(state, position))
+ if not lastOffset then
+ return
+ end
+ local lastPosition = guide.offsetToPosition(state, lastOffset)
+ local lastRow = guide.rowColOf(lastPosition)
+ local lastIndent = getIndent(state, lastRow)
+ if #myIndent <= #lastIndent then
+ return
+ end
+ if not util.stringStartWith(myIndent, lastIndent) then
+ return
+ end
+ if isInBlock(state, lastPosition) then
+ return
+ end
+
+ local endPosition = guide.positionOf(change.range.start.line + 1, #myIndent)
+ local endOffset = guide.positionToOffset(state, endPosition)
+
+ local edits = {}
+ edits[#edits+1] = {
+ start = endOffset - #myIndent + #lastIndent,
+ finish = endOffset,
+ text = '',
+ }
+
+ return edits
+end
+
+---@param state parser.state
+local function applyEdits(state, edits)
+ if #edits == 0 then
+ return
+ end
+
+ local lines = state.originLines or state.lines
+
+ local results = {}
+ for i, edit in ipairs(edits) do
+ local startPos = guide.offsetToPositionByLines(lines, edit.start)
+ local endPos = guide.offsetToPositionByLines(lines, edit.finish)
+ local startRow, startCol = guide.rowColOf(startPos)
+ local endRow, endCol = guide.rowColOf(endPos)
+ results[i] = {
+ range = {
+ start = {
+ line = startRow,
+ character = startCol,
+ },
+ ['end'] = {
+ line = endRow,
+ character = endCol,
+ }
+ },
+ newText = edit.text,
+ }
+ end
+
+ proto.request('workspace/applyEdit', {
+ label = 'Fix Indent',
+ edit = {
+ changes = {
+ [state.uri] = results
+ }
+ },
+ })
+end
+
+return function (uri, changes)
+ if not client.getOption('fixIndents') then
+ return
+ end
+ local state = files.compileState(uri)
+ if not state then
+ return
+ end
+
+ local firstChange = changes[1]
+ if firstChange.range then
+ local edits = removeSpacesAfterEnter(state, firstChange)
+ or fixWrongIndent(state, firstChange)
+ if edits then
+ applyEdits(state, edits)
+ end
+ end
+end
diff --git a/script/core/hint.lua b/script/core/hint.lua
index 9d098aa9..b0ff5aa7 100644
--- a/script/core/hint.lua
+++ b/script/core/hint.lua
@@ -287,6 +287,8 @@ local function semicolonHint(uri, results, start, finish)
---@async
guide.eachSourceTypes(state.ast, blockTypes, function (src)
await.delay()
+ if #src < 1 then return end
+
for i = 1, #src - 1 do
local current = src[i]
local next = src[i+1]
@@ -313,6 +315,7 @@ local function semicolonHint(uri, results, start, finish)
end
end
end
+
if mode == 'All' then
local last = src[#src]
results[#results+1] = {
diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua
index 419cb56b..f6080650 100644
--- a/script/core/type-formatting.lua
+++ b/script/core/type-formatting.lua
@@ -4,187 +4,6 @@ local guide = require 'parser.guide'
local config = require 'config'
local util = require 'utility'
-
-local function insertIndentation(uri, position, edits)
- local text = files.getText(uri)
- local state = files.getState(uri)
- local row = guide.rowColOf(position)
- if not state or not text then
- return
- end
- 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(uri, position, ...)
- local text = files.getText(uri)
- local state = files.getState(uri)
- if not state or not text then
- return nil
- end
- 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(firstOffset, firstOffset + #symbol - 1) == symbol then
- return guide.offsetToPosition(state, firstOffset - 1), symbol
- end
- end
- return nil
-end
-
-local function findBackward(uri, position, ...)
- local text = files.getText(uri)
- local state = files.getState(uri)
- if not state or not text then
- return nil
- end
- local offset = guide.positionToOffset(state, position)
- local lastOffset = lookBackward.findAnyOffset(text, offset)
- for _, symbol in ipairs { ... } do
- if text:sub(lastOffset - #symbol + 1, lastOffset) == symbol then
- return guide.offsetToPosition(state, lastOffset)
- end
- end
- return nil
-end
-
-local function checkSplitOneLine(results, uri, position, ch)
- if ch ~= '\n' then
- return
- end
-
- local fPosition, fSymbol = findForward(uri, position, 'end', '}')
- if not fPosition or not fSymbol then
- return
- end
- local bPosition = findBackward(uri, position, 'then', 'do', ')', '{')
- if not bPosition then
- return
- end
- local edits = {}
- edits[#edits+1] = {
- start = bPosition,
- finish = position,
- text = '\n\t',
- }
- edits[#edits+1] = {
- start = position,
- finish = fPosition + 1,
- text = '',
- }
- edits[#edits+1] = {
- start = fPosition + 1,
- finish = fPosition + 1,
- text = '\n' .. fSymbol:sub(1, 1)
- }
- insertIndentation(uri, bPosition, edits)
- for _, edit in ipairs(edits) do
- results[#results+1] = edit
- end
-end
-
-local function getIndent(state, row)
- local offset = state.lines[row]
- local indent = state.lua:match('^[\t ]*', offset)
- return indent
-end
-
-local function isInBlock(state, position)
- local block = guide.eachSourceContain(state.ast, position, function(source)
- if source.type == 'ifblock'
- or source.type == 'elseifblock' then
- if source.keyword[4] and source.keyword[4] <= position then
- return true
- end
- end
- if source.type == 'else' then
- if source.keyword[2] and source.keyword[2] <= position then
- return true
- end
- end
- if source.type == 'while' then
- if source.keyword[4] and source.keyword[4] <= position then
- return true
- end
- end
- if source.type == 'repeat' then
- if source.keyword[2] and source.keyword[2] <= position then
- return true
- end
- end
- if source.type == 'loop' then
- if source.keyword[4] and source.keyword[4] <= position then
- return true
- end
- end
- if source.type == 'in' then
- if source.keyword[6] and source.keyword[6] <= position then
- return true
- end
- end
- if source.type == 'do' then
- if source.keyword[2] and source.keyword[2] <= position then
- return true
- end
- end
- if source.type == 'function' then
- if source.args and source.args.finish <= position then
- return true
- end
- if not source.keyword[3] or source.keyword[3] >= position then
- return true
- end
- end
- if source.type == 'table' then
- if source.start + 1 == position then
- return true
- end
- end
- end)
- return block ~= nil
-end
-
-local function checkWrongIndentation(results, uri, position, ch)
- if ch ~= '\n' then
- return
- end
- local state = files.getState(uri)
- if not state then
- return
- end
- local row = guide.rowColOf(position)
- if row <= 0 then
- return
- end
- local myIndent = getIndent(state, row)
- local lastIndent = getIndent(state, row - 1)
- if #myIndent <= #lastIndent then
- return
- end
- if not util.stringStartWith(myIndent, lastIndent) then
- return
- end
- local lastOffset = lookBackward.findAnyOffset(state.lua, guide.positionToOffset(state, position) - 1)
- if not lastOffset then
- return
- end
- local lastPosition = guide.offsetToPosition(state, lastOffset)
- if isInBlock(state, lastPosition) then
- return
- end
- results[#results+1] = {
- start = position - #myIndent + #lastIndent,
- finish = position,
- text = '',
- }
-end
-
local function typeFormat(results, uri, position, ch, options)
if ch ~= '\n' then
return
@@ -218,22 +37,12 @@ return function (uri, position, ch, options)
return nil
end
- local results = {}
- -- split `function () $ end`
- checkSplitOneLine(results, uri, position, ch)
- if #results > 0 then
- return results
- end
-
- checkWrongIndentation(results, uri, position, ch)
- if #results > 0 then
- return results
- end
-
if TEST then
return nil
end
+ local results = {}
+
typeFormat(results, uri, position, ch, options)
if #results > 0 then
return results
diff --git a/script/lclient.lua b/script/lclient.lua
index 13b431b0..96a6c16f 100644
--- a/script/lclient.lua
+++ b/script/lclient.lua
@@ -5,6 +5,8 @@ local await = require 'await'
local timer = require 'timer'
local pub = require 'pub'
local json = require 'json'
+local client = require 'client'
+local define = require 'proto.define'
require 'provider'
@@ -61,9 +63,33 @@ function mt:_localLoadFile()
end)
end
+local defaultClientOptions = {
+ initializationOptions = {
+ changeConfiguration = true,
+ viewDocument = true,
+ trustByClient = true,
+ useSemanticByRange = true,
+ },
+ capabilities = {
+ textDocument = {
+ completion = {
+ completionItem = {
+ tagSupport = {
+ valueSet = {
+ define.DiagnosticTag.Unnecessary,
+ define.DiagnosticTag.Deprecated,
+ },
+ },
+ },
+ },
+ },
+ },
+}
+
---@async
function mt:initialize(params)
- self:awaitRequest('initialize', params or {})
+ local initParams = util.tableMerge(params or {}, defaultClientOptions)
+ self:awaitRequest('initialize', initParams)
self:notify('initialized')
end
diff --git a/script/library.lua b/script/library.lua
index cfc7e328..49e39470 100644
--- a/script/library.lua
+++ b/script/library.lua
@@ -22,7 +22,7 @@ m.metaPaths = {}
local function getDocFormater(uri)
local version = config.get(uri, 'Lua.runtime.version')
- if client.isVSCode() then
+ if client.getOption('viewDocument') then
if version == 'Lua 5.1' then
return 'HOVER_NATIVE_DOCUMENT_LUA51'
elseif version == 'Lua 5.2' then
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index e42f2acd..768d7dec 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -105,6 +105,8 @@ local blockTypes = {
['main'] = true,
}
+m.blockTypes = blockTypes
+
local topBlockTypes = {
['while'] = true,
['function'] = true,
diff --git a/script/plugin.lua b/script/plugin.lua
index b8ecfb6a..ec55875e 100644
--- a/script/plugin.lua
+++ b/script/plugin.lua
@@ -195,7 +195,7 @@ local function initPlugin(uri)
m.showError(scp, err)
return
end
- if not client.isVSCode() and not checkTrustLoad(scp) then
+ if not client.getOption('trustByClient') and not checkTrustLoad(scp) then
return
end
local suc, err = xpcall(f, log.error, f, uri, myArgs)
diff --git a/script/provider/language-configuration.lua b/script/provider/language-configuration.lua
new file mode 100644
index 00000000..1d34f765
--- /dev/null
+++ b/script/provider/language-configuration.lua
@@ -0,0 +1,86 @@
+-- Enumeration of commonly encountered syntax token types.
+local SyntaxTokenType = {
+ Other = 0, -- Everything except tokens that are part of comments, string literals and regular expressions.
+ Comment = 1, -- A comment.
+ String = 2, -- A string literal.
+ RegEx = 3 -- A regular expression.
+}
+
+-- Describes what to do with the indentation when pressing Enter.
+local IndentAction = {
+ None = 0, -- Insert new line and copy the previous line's indentation.
+ Indent = 1, -- Insert new line and indent once (relative to the previous line's indentation).
+ IndentOutdent = 2, -- Insert two new lines: the first one indented which will hold the cursor, and the second one at the same indentation level.
+ Outdent = 3 -- Insert new line and outdent once (relative to the previous line's indentation).
+}
+
+local languageConfiguration = {
+ id = 'lua',
+ configuration = {
+ autoClosingPairs = {
+ { open = "{", close = "}" },
+ { open = "[", close = "]" },
+ { open = "(", close = ")" },
+ { open = "'", close = "'", notIn = { SyntaxTokenType.String } },
+ { open = '"', close = '"', notIn = { SyntaxTokenType.String } },
+ { open = "[=", close = "=]" },
+ { open = "[==", close = "==]" },
+ { open = "[===", close = "===]" },
+ { open = "[====", close = "====]" },
+ { open = "[=====", close = "=====]" },
+ },
+ onEnterRules = {
+ {
+ beforeText = [[\)\s*$]],
+ afterText = [[^\s*end\b]],
+ action = {
+ indentAction = IndentAction.IndentOutdent,
+ }
+ },
+ {
+ beforeText = [[\b()\s*$]],
+ afterText = [[^\s*end\b]],
+ action = {
+ indentAction = IndentAction.IndentOutdent,
+ }
+ },
+ {
+ beforeText = [[\b(repeat)\s*$]],
+ afterText = [[^\s*until\b]],
+ action = {
+ indentAction = IndentAction.IndentOutdent,
+ }
+ },
+ {
+ beforeText = [[^\s*---@]],
+ action = {
+ indentAction = IndentAction.None,
+ appendText = "---@"
+ }
+ },
+ {
+ beforeText = [[^\s*--- @]],
+ action = {
+ indentAction = IndentAction.None,
+ appendText = "--- @"
+ }
+ },
+ {
+ beforeText = [[^\s*--- ]],
+ action = {
+ indentAction = IndentAction.None,
+ appendText = "--- "
+ }
+ },
+ {
+ beforeText = [[^\s*---]],
+ action = {
+ indentAction = IndentAction.None,
+ appendText = "---"
+ }
+ },
+ },
+ },
+}
+
+return languageConfiguration
diff --git a/script/provider/provider.lua b/script/provider/provider.lua
index 2e2fb5eb..6a4b2406 100644
--- a/script/provider/provider.lua
+++ b/script/provider/provider.lua
@@ -292,6 +292,7 @@ m.register 'textDocument/didClose' {
m.register 'textDocument/didChange' {
---@async
function (params)
+ local fixIndent = require 'core.fix-indent'
local doc = params.textDocument
local changes = params.contentChanges
local uri = files.getRealUri(doc.uri)
@@ -299,6 +300,7 @@ m.register 'textDocument/didChange' {
if not text then
text = util.loadFile(furi.decode(uri))
files.setText(uri, text, false)
+ fixIndent(uri, changes)
return
end
local rows = files.getCachedRows(uri)
@@ -307,6 +309,8 @@ m.register 'textDocument/didChange' {
file.version = doc.version
end)
files.setCachedRows(uri, rows)
+
+ fixIndent(uri, changes)
end
}
@@ -1059,7 +1063,7 @@ end
client.event(function (ev)
if ev == 'init' then
- if not client.isVSCode() then
+ if not client.getOption('useSemanticByRange') then
m.register 'textDocument/semanticTokens/full' {
capability = {
semanticTokensProvider = {
@@ -1593,8 +1597,23 @@ m.register '$/psi/select' {
end
}
+local function refreshLanguageConfiguration()
+ if not client.getOption('languageConfiguration') then
+ return
+ end
+ proto.notify('$/languageConfiguration', require 'provider.language-configuration')
+end
+
+config.watch(function (uri, key, value)
+ if key == '' then
+ refreshLanguageConfiguration()
+ end
+end)
local function refreshStatusBar()
+ if not client.getOption('statusBar') then
+ return
+ end
local valid = config.get(nil, 'Lua.window.statusBar')
for _, scp in ipairs(workspace.folders) do
if not config.get(scp.uri, 'Lua.window.statusBar') then
diff --git a/script/service/service.lua b/script/service/service.lua
index c3afd4cf..c7675f1b 100644
--- a/script/service/service.lua
+++ b/script/service/service.lua
@@ -13,6 +13,7 @@ local time = require 'bee.time'
local fw = require 'filewatch'
local furi = require 'file-uri'
local net = require 'service.net'
+local client = require 'client'
require 'jsonc'
require 'json-beautify'
@@ -202,6 +203,9 @@ end
local showStatusTip = math.random(100) == 1
function m.reportStatus()
+ if not client.getOption('statusBar') then
+ return
+ end
local info = {}
if m.workingClock and time.monotonic() - m.workingClock > 100 then
info.text = '$(loading~spin)Lua'
@@ -245,6 +249,10 @@ function m.testVersion()
end
end
+function m.sayHello()
+ proto.notify('$/hello', {'world'})
+end
+
function m.lockCache()
local fs = require 'bee.filesystem'
local sp = require 'bee.subprocess'
@@ -280,6 +288,8 @@ function m.start()
require 'provider'
+ m.sayHello()
+
m.eventLoop()
end
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua
index f3655123..54390450 100644
--- a/script/vm/compiler.lua
+++ b/script/vm/compiler.lua
@@ -578,7 +578,17 @@ local function matchCall(source)
if call.args then
-- clear node caches of args to allow recomputation with the type narrowed call
for _, arg in ipairs(call.args) do
- vm.removeNode(arg)
+ vm.setNode(arg, vm.createNode(), true)
+ end
+ for n in newNode:eachObject() do
+ if n.type == 'function'
+ or n.type == 'doc.type.function' then
+ for i, arg in ipairs(call.args) do
+ if n.args[i] then
+ vm.setNode(arg, vm.compileNode(n.args[i]))
+ end
+ end
+ end
end
end
end
diff --git a/script/vm/def.lua b/script/vm/def.lua
index 669d39c2..41f735b2 100644
--- a/script/vm/def.lua
+++ b/script/vm/def.lua
@@ -93,7 +93,7 @@ function vm.getDefs(source)
return results
end
-local HAS_DEF_ERR = {} -- the error object for comparing
+local HAS_DEF_ERR = false -- the error object for comparing
local function checkHasDef(checkFunc, source, pushResult)
local _, err = pcall(checkFunc, source, pushResult)
return err == HAS_DEF_ERR
diff --git a/script/vm/operator.lua b/script/vm/operator.lua
index 7ce2b30d..07ce19eb 100644
--- a/script/vm/operator.lua
+++ b/script/vm/operator.lua
@@ -261,6 +261,9 @@ vm.binarySwitch = util.switch()
})
else
local node = vm.runOperator(binaryMap[op], source[1], source[2])
+ if not node then
+ node = vm.runOperator(binaryMap[op], source[2], source[1])
+ end
if node then
vm.setNode(source, node)
end
@@ -300,6 +303,9 @@ vm.binarySwitch = util.switch()
})
else
local node = vm.runOperator(binaryMap[op], source[1], source[2])
+ if not node then
+ node = vm.runOperator(binaryMap[op], source[2], source[1])
+ end
if node then
vm.setNode(source, node)
return
@@ -396,6 +402,9 @@ vm.binarySwitch = util.switch()
return
end
local node = vm.runOperator(binaryMap[source.op.type], source[1], source[2])
+ if not node then
+ node = vm.runOperator(binaryMap[source.op.type], source[2], source[1])
+ end
if node then
vm.setNode(source, node)
end
diff --git a/script/vm/type.lua b/script/vm/type.lua
index afc19984..4835065a 100644
--- a/script/vm/type.lua
+++ b/script/vm/type.lua
@@ -70,7 +70,7 @@ local function checkParentEnum(parentName, child, uri, mark, errs)
if enums then
enums = util.arrayMerge(enums, denums)
else
- enums = denums
+ enums = util.arrayMerge({}, denums)
end
end
end