summaryrefslogtreecommitdiff
path: root/script/method/workspace
diff options
context:
space:
mode:
Diffstat (limited to 'script/method/workspace')
-rw-r--r--script/method/workspace/didChangeConfiguration.lua27
-rw-r--r--script/method/workspace/didChangeWatchedFiles.lua44
-rw-r--r--script/method/workspace/didChangeWorkspaceFolders.lua20
-rw-r--r--script/method/workspace/executeCommand.lua258
4 files changed, 349 insertions, 0 deletions
diff --git a/script/method/workspace/didChangeConfiguration.lua b/script/method/workspace/didChangeConfiguration.lua
new file mode 100644
index 00000000..ecaa9182
--- /dev/null
+++ b/script/method/workspace/didChangeConfiguration.lua
@@ -0,0 +1,27 @@
+local rpc = require 'rpc'
+
+return function (lsp)
+ local uri = lsp.workspace and lsp.workspace.uri
+ -- 请求配置
+ rpc:request('workspace/configuration', {
+ items = {
+ {
+ scopeUri = uri,
+ section = 'Lua',
+ },
+ {
+ scopeUri = uri,
+ section = 'files.associations',
+ },
+ {
+ scopeUri = uri,
+ section = 'files.exclude',
+ }
+ },
+ }, function (configs)
+ lsp:onUpdateConfig(configs[1], {
+ associations = configs[2],
+ exclude = configs[3],
+ })
+ end)
+end
diff --git a/script/method/workspace/didChangeWatchedFiles.lua b/script/method/workspace/didChangeWatchedFiles.lua
new file mode 100644
index 00000000..3ce68924
--- /dev/null
+++ b/script/method/workspace/didChangeWatchedFiles.lua
@@ -0,0 +1,44 @@
+local fs = require 'bee.filesystem'
+local uric = require 'uri'
+
+local FileChangeType = {
+ Created = 1,
+ Changed = 2,
+ Deleted = 3,
+}
+
+return function (lsp, params)
+ if not lsp.workspace then
+ return
+ end
+ local needReset
+ for _, change in ipairs(params.changes) do
+ local path = uric.decode(change.uri)
+ if not path then
+ goto CONTINUE
+ end
+ if change.type == FileChangeType.Created then
+ lsp.workspace:addFile(path)
+ if lsp:getVM(change.uri) then
+ needReset = true
+ end
+ elseif change.type == FileChangeType.Deleted then
+ lsp.workspace:removeFile(path)
+ if lsp:getVM(change.uri) then
+ needReset = true
+ end
+ end
+ -- 排除类文件发生更改需要重新扫描
+ local filename = path:filename():string()
+ if lsp.workspace:fileNameEq(filename, '.gitignore')
+ or lsp.workspace:fileNameEq(filename, '.gitmodules')
+ then
+ lsp:reScanFiles()
+ end
+ ::CONTINUE::
+ end
+ -- 缓存过的文件发生变化后,重新计算
+ if needReset then
+ lsp.workspace:reset()
+ end
+end
diff --git a/script/method/workspace/didChangeWorkspaceFolders.lua b/script/method/workspace/didChangeWorkspaceFolders.lua
new file mode 100644
index 00000000..01a28abd
--- /dev/null
+++ b/script/method/workspace/didChangeWorkspaceFolders.lua
@@ -0,0 +1,20 @@
+local rpc = require 'rpc'
+local lang = require 'language'
+
+return function ()
+ -- 暂不支持多个工作目录,因此当工作目录切换时,暴力结束服务,让前端重启服务
+ rpc:requestWait('window/showMessageRequest', {
+ type = 3,
+ message = lang.script('MWS_NOT_SUPPORT', '[Lua]'),
+ actions = {
+ {
+ title = lang.script.MWS_RESTART,
+ }
+ }
+ }, function ()
+ os.exit(true)
+ end)
+ ac.wait(5, function ()
+ os.exit(true)
+ end)
+end
diff --git a/script/method/workspace/executeCommand.lua b/script/method/workspace/executeCommand.lua
new file mode 100644
index 00000000..cfa4023e
--- /dev/null
+++ b/script/method/workspace/executeCommand.lua
@@ -0,0 +1,258 @@
+local fs = require 'bee.filesystem'
+local json = require 'json'
+local config = require 'config'
+local rpc = require 'rpc'
+local lang = require 'language'
+local platform = require 'bee.platform'
+
+local command = {}
+
+local function isContainPos(obj, start, finish)
+ if obj.start <= start and obj.finish >= finish then
+ return true
+ end
+ return false
+end
+
+local function isInString(vm, start, finish)
+ return vm:eachSource(function (source)
+ if source.type == 'string' and isContainPos(source, start, finish) then
+ return true
+ end
+ end)
+end
+
+local function posToRange(lines, start, finish)
+ local start_row, start_col = lines:rowcol(start)
+ local finish_row, finish_col = lines:rowcol(finish)
+ return {
+ start = {
+ line = start_row - 1,
+ character = start_col - 1,
+ },
+ ['end'] = {
+ line = finish_row - 1,
+ character = finish_col,
+ },
+ }
+end
+
+function command.config(lsp, data)
+ local def = config.config
+ for _, k in ipairs(data.key) do
+ def = def[k]
+ if not def then
+ return
+ end
+ end
+ if data.action == 'add' then
+ if type(def) ~= 'table' then
+ return
+ end
+ end
+
+ local vscodePath
+ local mode
+ if lsp.workspace then
+ vscodePath = lsp.workspace.root / '.vscode'
+ mode = 'workspace'
+ else
+ if platform.OS == 'Windows' then
+ vscodePath = fs.path(os.getenv 'USERPROFILE') / 'AppData' / 'Roaming' / 'Code' / 'User'
+ else
+ vscodePath = fs.path(os.getenv 'HOME') / '.vscode-server' / 'data' / 'Machine'
+ end
+ mode = 'user'
+ if not fs.exists(vscodePath) then
+ rpc:notify('window/showMessage', {
+ type = 3,
+ message = lang.script.MWS_UCONFIG_FAILED,
+ })
+ return
+ end
+ end
+
+ local settingBuf = io.load(vscodePath / 'settings.json')
+ if not settingBuf then
+ fs.create_directories(vscodePath)
+ end
+
+ local setting = json.decode(settingBuf or '', true) or {}
+ local key = 'Lua.' .. table.concat(data.key, '.')
+ local attr = setting[key]
+
+ if data.action == 'add' then
+ if attr == nil then
+ attr = {}
+ elseif type(attr) == 'string' then
+ attr = {}
+ for str in attr:gmatch '[^;]+' do
+ attr[#attr+1] = str
+ end
+ elseif type(attr) == 'table' then
+ else
+ return
+ end
+
+ attr[#attr+1] = data.value
+ setting[key] = attr
+ elseif data.action == 'set' then
+ setting[key] = data.value
+ end
+
+ io.save(vscodePath / 'settings.json', json.encode(setting) .. '\r\n')
+
+ if mode == 'workspace' then
+ rpc:notify('window/showMessage', {
+ type = 3,
+ message = lang.script.MWS_WCONFIG_UPDATED,
+ })
+ elseif mode == 'user' then
+ rpc:notify('window/showMessage', {
+ type = 3,
+ message = lang.script.MWS_UCONFIG_UPDATED,
+ })
+ end
+end
+
+function command.removeSpace(lsp, data)
+ local uri = data.uri
+ local vm, lines = lsp:getVM(uri)
+ if not vm then
+ return
+ end
+
+ local textEdit = {}
+ for i = 1, #lines do
+ local line = lines:line(i)
+ local pos = line:find '[ \t]+$'
+ if pos then
+ local start, finish = lines:range(i)
+ start = start + pos - 1
+ if isInString(vm, start, finish) then
+ goto NEXT_LINE
+ end
+ textEdit[#textEdit+1] = {
+ range = posToRange(lines, start, finish),
+ newText = '',
+ }
+ goto NEXT_LINE
+ end
+
+ ::NEXT_LINE::
+ end
+
+ if #textEdit == 0 then
+ return
+ end
+
+ rpc:request('workspace/applyEdit', {
+ label = lang.script.COMMAND_REMOVE_SPACE,
+ edit = {
+ changes = {
+ [uri] = textEdit,
+ }
+ },
+ })
+end
+
+local opMap = {
+ ['+'] = true,
+ ['-'] = true,
+ ['*'] = true,
+ ['/'] = true,
+ ['//'] = true,
+ ['^'] = true,
+ ['<<'] = true,
+ ['>>'] = true,
+ ['&'] = true,
+ ['|'] = true,
+ ['~'] = true,
+ ['..'] = true,
+}
+
+local literalMap = {
+ ['number'] = true,
+ ['boolean'] = true,
+ ['string'] = true,
+ ['table'] = true,
+}
+
+function command.solve(lsp, data)
+ local uri = data.uri
+ local vm, lines = lsp:getVM(uri)
+ if not vm then
+ return
+ end
+
+ local start = lines:position(data.range.start.line + 1, data.range.start.character + 1)
+ local finish = lines:position(data.range['end'].line + 1, data.range['end'].character)
+
+ local result = vm:eachSource(function (source)
+ if not isContainPos(source, start, finish) then
+ return
+ end
+ if source.op ~= 'or' then
+ return
+ end
+ local first = source[1]
+ local second = source[2]
+ -- (a + b) or 0 --> a + (b or 0)
+ do
+ if opMap[first.op]
+ and first.type ~= 'unary'
+ and not second.op
+ and literalMap[second.type]
+ then
+ return {
+ start = source[1][2].start,
+ finish = source[2].finish,
+ }
+ end
+ end
+ -- a or (b + c) --> (a or b) + c
+ do
+ if opMap[second.op]
+ and second.type ~= 'unary'
+ and not first.op
+ and literalMap[second[1].type]
+ then
+ return {
+ start = source[1].start,
+ finish = source[2][1].finish,
+ }
+ end
+ end
+ end)
+
+ if not result then
+ return
+ end
+
+ rpc:request('workspace/applyEdit', {
+ label = lang.script.COMMAND_ADD_BRACKETS,
+ edit = {
+ changes = {
+ [uri] = {
+ {
+ range = posToRange(lines, result.start, result.start - 1),
+ newText = '(',
+ },
+ {
+ range = posToRange(lines, result.finish + 1, result.finish),
+ newText = ')',
+ },
+ }
+ }
+ },
+ })
+end
+
+return function (lsp, params)
+ local name = params.command
+ if not command[name] then
+ return
+ end
+ local result = command[name](lsp, params.arguments[1])
+ return result
+end