diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2024-08-15 15:16:03 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-15 15:16:03 +0800 |
commit | 2c798703ca854d670fb28f51adc85c2b41f08f37 (patch) | |
tree | aa192cf6d6ed02d02dda8c8b7a4c240dded64efb /script | |
parent | abd5daae1885cdf7a9e21a1cbdfea945385124fc (diff) | |
parent | b71cb7aecd9337c9463a4dfbdb9d06cac7b825fd (diff) | |
download | lua-language-server-2c798703ca854d670fb28f51adc85c2b41f08f37.zip |
Merge branch 'master' into cast-table-to-class
Diffstat (limited to 'script')
-rw-r--r-- | script/cli/check.lua | 7 | ||||
-rw-r--r-- | script/core/code-lens.lua | 36 | ||||
-rw-r--r-- | script/core/completion/postfix.lua | 2 | ||||
-rw-r--r-- | script/core/diagnostics/missing-fields.lua | 78 | ||||
-rw-r--r-- | script/core/diagnostics/unused-function.lua | 6 | ||||
-rw-r--r-- | script/core/fix-indent.lua | 211 | ||||
-rw-r--r-- | script/core/hint.lua | 3 | ||||
-rw-r--r-- | script/core/type-formatting.lua | 195 | ||||
-rw-r--r-- | script/lclient.lua | 28 | ||||
-rw-r--r-- | script/library.lua | 2 | ||||
-rw-r--r-- | script/parser/guide.lua | 2 | ||||
-rw-r--r-- | script/plugin.lua | 2 | ||||
-rw-r--r-- | script/provider/language-configuration.lua | 86 | ||||
-rw-r--r-- | script/provider/provider.lua | 21 | ||||
-rw-r--r-- | script/service/service.lua | 10 | ||||
-rw-r--r-- | script/vm/compiler.lua | 12 | ||||
-rw-r--r-- | script/vm/def.lua | 2 | ||||
-rw-r--r-- | script/vm/operator.lua | 9 | ||||
-rw-r--r-- | script/vm/type.lua | 2 |
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 |