mirror of
https://github.com/hexedtech/codemp-nvim.git
synced 2024-11-22 15:34:53 +01:00
chore: updated to codemp 0.8
This commit is contained in:
parent
9e22411df8
commit
c92b1799b6
9 changed files with 49 additions and 47 deletions
|
@ -8,6 +8,8 @@
|
||||||
-- `native.(so|dll|dylib)` file in this plugin folder, next to
|
-- `native.(so|dll|dylib)` file in this plugin folder, next to
|
||||||
-- the `loader.lua` file.
|
-- the `loader.lua` file.
|
||||||
|
|
||||||
|
local version = "v0.8.0"
|
||||||
|
|
||||||
|
|
||||||
local plugin_dir = vim.fn.fnamemodify(debug.getinfo(1, "S").source:sub(2), ":p:h") -- got this from https://lazy.folke.io/developers#building
|
local plugin_dir = vim.fn.fnamemodify(debug.getinfo(1, "S").source:sub(2), ":p:h") -- got this from https://lazy.folke.io/developers#building
|
||||||
|
|
||||||
|
@ -43,8 +45,6 @@ if os_uname.sysname == "Windows_NT" then sep = '\\' end
|
||||||
local new_ext = ext
|
local new_ext = ext
|
||||||
if os_uname.sysname == "Darwin" then new_ext = "so" end
|
if os_uname.sysname == "Darwin" then new_ext = "so" end
|
||||||
|
|
||||||
local version = "v0.7.3"
|
|
||||||
|
|
||||||
local native_path = plugin_dir..sep.."lua"..sep.."codemp"..sep.."new-native."..new_ext
|
local native_path = plugin_dir..sep.."lua"..sep.."codemp"..sep.."new-native."..new_ext
|
||||||
local replace_native_path = plugin_dir..sep.."lua"..sep.."codemp"..sep.."native."..new_ext
|
local replace_native_path = plugin_dir..sep.."lua"..sep.."codemp"..sep.."native."..new_ext
|
||||||
local download_url_native = string.format("https://codemp.dev/releases/lua/codemp-lua-%s-%s-%s.%s", version, arch, platform, ext)
|
local download_url_native = string.format("https://codemp.dev/releases/lua/codemp-lua-%s-%s-%s.%s", version, arch, platform, ext)
|
||||||
|
|
|
@ -15,7 +15,7 @@ local function detach(name)
|
||||||
id_buffer_map[buffer] = nil
|
id_buffer_map[buffer] = nil
|
||||||
buffer_id_map[name] = nil
|
buffer_id_map[name] = nil
|
||||||
CODEMP.workspace:get_buffer(name):clear_callback()
|
CODEMP.workspace:get_buffer(name):clear_callback()
|
||||||
if not CODEMP.workspace:detach(name) then
|
if not CODEMP.workspace:detach_buffer(name) then
|
||||||
collectgarbage("collect") -- clear dangling references
|
collectgarbage("collect") -- clear dangling references
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ local function attach(name, opts)
|
||||||
|
|
||||||
vim.api.nvim_buf_set_name(buffer, name)
|
vim.api.nvim_buf_set_name(buffer, name)
|
||||||
|
|
||||||
CODEMP.workspace:attach(name):and_then(function (controller)
|
CODEMP.workspace:attach_buffer(name):and_then(function (controller)
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
-- TODO disgusting! but poll blocks forever on empty buffers...
|
-- TODO disgusting! but poll blocks forever on empty buffers...
|
||||||
if not opts.nowait then
|
if not opts.nowait then
|
||||||
|
@ -124,7 +124,7 @@ local function attach(name, opts)
|
||||||
print(string.format("sending: %s..%s '%s'", start_offset, start_offset + old_end_byte_len, change_content))
|
print(string.format("sending: %s..%s '%s'", start_offset, start_offset + old_end_byte_len, change_content))
|
||||||
end
|
end
|
||||||
controller:send({
|
controller:send({
|
||||||
start = start_offset, finish = end_offset, content = change_content
|
start_idx = start_offset, end_idx = end_offset, content = change_content
|
||||||
}):await()
|
}):await()
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
@ -139,9 +139,9 @@ local function attach(name, opts)
|
||||||
ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer)
|
ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer)
|
||||||
CODEMP.ignore_following_action = true
|
CODEMP.ignore_following_action = true
|
||||||
if CODEMP.config.debug then
|
if CODEMP.config.debug then
|
||||||
print(" ~~ applying change ~~ " .. event.change.start .. ".." .. event.change.finish .. "::[" .. event.change.content .. "]")
|
print(" ~~ applying change ~~ " .. event.change.start_idx .. ".." .. event.change.end_idx .. "::[" .. event.change.content .. "]")
|
||||||
end
|
end
|
||||||
utils.buffer.set_content(buffer, event.change.content, event.change.start, event.change.finish)
|
utils.buffer.set_content(buffer, event.change.content, event.change.start_idx, event.change.end_idx)
|
||||||
if event.hash ~= nil then
|
if event.hash ~= nil then
|
||||||
if CODEMP.native.hash(utils.buffer.get_content(buffer)) ~= event.hash then
|
if CODEMP.native.hash(utils.buffer.get_content(buffer)) ~= event.hash then
|
||||||
if CODEMP.config.auto_sync then
|
if CODEMP.config.auto_sync then
|
||||||
|
@ -173,7 +173,7 @@ local function attach(name, opts)
|
||||||
if opts.content ~= nil then
|
if opts.content ~= nil then
|
||||||
-- TODO this may happen too soon!!
|
-- TODO this may happen too soon!!
|
||||||
local _ = controller:send({
|
local _ = controller:send({
|
||||||
start = 0, finish = #remote_content, content = opts.content
|
start_idx = 0, end_idx = #remote_content, content = opts.content
|
||||||
}) -- no need to await
|
}) -- no need to await
|
||||||
else
|
else
|
||||||
local current_content = utils.buffer.get_content(buffer)
|
local current_content = utils.buffer.get_content(buffer)
|
||||||
|
@ -227,7 +227,7 @@ local function create(buffer)
|
||||||
if CODEMP.workspace == nil then
|
if CODEMP.workspace == nil then
|
||||||
error("join a workspace first")
|
error("join a workspace first")
|
||||||
end
|
end
|
||||||
CODEMP.workspace:create(buffer):and_then(function ()
|
CODEMP.workspace:create_buffer(buffer):and_then(function ()
|
||||||
print(" ++ created buffer " .. buffer)
|
print(" ++ created buffer " .. buffer)
|
||||||
require('codemp.window').update()
|
require('codemp.window').update()
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -31,7 +31,7 @@ local base_actions = {
|
||||||
-- only available if state.client is not nil
|
-- only available if state.client is not nil
|
||||||
local connected_actions = {
|
local connected_actions = {
|
||||||
id = function()
|
id = function()
|
||||||
print("> codemp::" .. CODEMP.client.id)
|
print("> codemp::" .. CODEMP.client:current_user().id)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
join = function(ws)
|
join = function(ws)
|
||||||
|
@ -56,11 +56,11 @@ local connected_actions = {
|
||||||
|
|
||||||
available = function()
|
available = function()
|
||||||
CODEMP.available = {}
|
CODEMP.available = {}
|
||||||
for _, ws in ipairs(CODEMP.client:list_workspaces(true, false):await()) do
|
for _, ws in ipairs(CODEMP.client:fetch_owned_workspaces():await()) do
|
||||||
print(" ++ " .. ws)
|
print(" ++ " .. ws)
|
||||||
table.insert(CODEMP.available, ws)
|
table.insert(CODEMP.available, ws)
|
||||||
end
|
end
|
||||||
for _, ws in ipairs(CODEMP.client:list_workspaces(false, true):await()) do
|
for _, ws in ipairs(CODEMP.client:fetch_joined_workspaces():await()) do
|
||||||
print(" -- " .. ws)
|
print(" -- " .. ws)
|
||||||
table.insert(CODEMP.available, ws)
|
table.insert(CODEMP.available, ws)
|
||||||
end
|
end
|
||||||
|
@ -70,7 +70,7 @@ local connected_actions = {
|
||||||
invite = function(user)
|
invite = function(user)
|
||||||
local ws
|
local ws
|
||||||
if CODEMP.workspace ~= nil then
|
if CODEMP.workspace ~= nil then
|
||||||
ws = CODEMP.workspace.name
|
ws = CODEMP.workspace:id()
|
||||||
else
|
else
|
||||||
ws = vim.fn.input("workspace > ", "")
|
ws = vim.fn.input("workspace > ", "")
|
||||||
end
|
end
|
||||||
|
@ -81,10 +81,10 @@ local connected_actions = {
|
||||||
|
|
||||||
disconnect = function()
|
disconnect = function()
|
||||||
if CODEMP.workspace ~= nil then
|
if CODEMP.workspace ~= nil then
|
||||||
print(" xx leaving workspace " .. CODEMP.workspace.name)
|
print(" xx leaving workspace " .. CODEMP.workspace:id())
|
||||||
workspace.leave()
|
workspace.leave()
|
||||||
end
|
end
|
||||||
print(" xx disconnecting client " .. CODEMP.client.id)
|
print(" xx disconnecting client " .. CODEMP.client:current_user().id)
|
||||||
CODEMP.client = nil -- should drop and thus close everything
|
CODEMP.client = nil -- should drop and thus close everything
|
||||||
collectgarbage("collect") -- make sure we drop
|
collectgarbage("collect") -- make sure we drop
|
||||||
require('codemp.window').update()
|
require('codemp.window').update()
|
||||||
|
@ -118,13 +118,13 @@ local joined_actions = {
|
||||||
|
|
||||||
delete = function(path)
|
delete = function(path)
|
||||||
if path == nil then error("missing buffer name") end
|
if path == nil then error("missing buffer name") end
|
||||||
CODEMP.workspace:delete(path):and_then(function()
|
CODEMP.workspace:delete_buffer(path):and_then(function()
|
||||||
print(" xx deleted buffer " .. path)
|
print(" xx deleted buffer " .. path)
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
buffers = function()
|
buffers = function()
|
||||||
for _, buf in ipairs(CODEMP.workspace:filetree()) do
|
for _, buf in ipairs(CODEMP.workspace:search_buffers()) do
|
||||||
if buffers.map_rev[buf] ~= nil then
|
if buffers.map_rev[buf] ~= nil then
|
||||||
print(" +- " .. buf)
|
print(" +- " .. buf)
|
||||||
else
|
else
|
||||||
|
@ -149,7 +149,7 @@ local joined_actions = {
|
||||||
buffers.attach(p, { buffer = buffer })
|
buffers.attach(p, { buffer = buffer })
|
||||||
end
|
end
|
||||||
if path == nil then
|
if path == nil then
|
||||||
local filetree = CODEMP.workspace:filetree(nil, false)
|
local filetree = CODEMP.workspace:search_buffers()
|
||||||
return vim.ui.select(filetree, { prompt = "Select buffer to attach to:" }, function (choice)
|
return vim.ui.select(filetree, { prompt = "Select buffer to attach to:" }, function (choice)
|
||||||
if choice == nil then return end -- action canceled by user
|
if choice == nil then return end -- action canceled by user
|
||||||
doit(filetree[choice])
|
doit(filetree[choice])
|
||||||
|
@ -233,7 +233,7 @@ vim.api.nvim_create_user_command(
|
||||||
if CODEMP.client ~= nil and CODEMP.workspace ~= nil then
|
if CODEMP.client ~= nil and CODEMP.workspace ~= nil then
|
||||||
local choices
|
local choices
|
||||||
if last_arg == "attach" then
|
if last_arg == "attach" then
|
||||||
choices = CODEMP.workspace:filetree()
|
choices = CODEMP.workspace:search_buffers()
|
||||||
elseif last_arg == "detach" then
|
elseif last_arg == "detach" then
|
||||||
choices = CODEMP.workspace.active_buffers
|
choices = CODEMP.workspace.active_buffers
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,7 +38,7 @@ if CODEMP == nil then
|
||||||
{
|
{
|
||||||
callback = function (_ev)
|
callback = function (_ev)
|
||||||
if CODEMP.workspace ~= nil then
|
if CODEMP.workspace ~= nil then
|
||||||
print(" xx leaving workspace " .. CODEMP.workspace.name)
|
print(" xx leaving workspace " .. CODEMP.workspace:id())
|
||||||
require('codemp.workspace').leave()
|
require('codemp.workspace').leave()
|
||||||
end
|
end
|
||||||
if CODEMP.client ~= nil then
|
if CODEMP.client ~= nil then
|
||||||
|
|
|
@ -130,16 +130,16 @@ M.update_state = function(state)
|
||||||
state.default_expanded_nodes = {}
|
state.default_expanded_nodes = {}
|
||||||
|
|
||||||
if CODEMP.workspace ~= nil then
|
if CODEMP.workspace ~= nil then
|
||||||
local ws_section = new_root("#" .. CODEMP.workspace.name)
|
local ws_section = new_root("#" .. CODEMP.workspace:id())
|
||||||
table.insert(state.default_expanded_nodes, ws_section.id)
|
table.insert(state.default_expanded_nodes, ws_section.id)
|
||||||
for i, path in ipairs(CODEMP.workspace:filetree()) do
|
for i, path in ipairs(CODEMP.workspace:search_buffers()) do
|
||||||
table.insert(ws_section.children, new_item(CODEMP.workspace.name, path))
|
table.insert(ws_section.children, new_item(CODEMP.workspace:id(), path))
|
||||||
end
|
end
|
||||||
|
|
||||||
local usr_section = new_root("users")
|
local usr_section = new_root("users")
|
||||||
table.insert(state.default_expanded_nodes, usr_section.id)
|
table.insert(state.default_expanded_nodes, usr_section.id)
|
||||||
for user, buffer in pairs(buf_manager.users) do
|
for user, buffer in pairs(buf_manager.users) do
|
||||||
table.insert(usr_section.children, new_user(CODEMP.workspace.name, user))
|
table.insert(usr_section.children, new_user(CODEMP.workspace:id(), user))
|
||||||
end
|
end
|
||||||
table.insert(ws_section.children, spacer())
|
table.insert(ws_section.children, spacer())
|
||||||
table.insert(ws_section.children, usr_section)
|
table.insert(ws_section.children, usr_section)
|
||||||
|
@ -159,8 +159,8 @@ M.update_state = function(state)
|
||||||
|
|
||||||
local status_section = new_root("client")
|
local status_section = new_root("client")
|
||||||
table.insert(state.default_expanded_nodes, status_section.id)
|
table.insert(state.default_expanded_nodes, status_section.id)
|
||||||
table.insert(status_section.children, new_entry("id", CODEMP.client.id))
|
table.insert(status_section.children, new_entry("id", CODEMP.client:current_user().id))
|
||||||
table.insert(status_section.children, new_entry("name", CODEMP.client.username))
|
table.insert(status_section.children, new_entry("name", CODEMP.client:current_user().name))
|
||||||
|
|
||||||
table.insert(root, spacer())
|
table.insert(root, spacer())
|
||||||
table.insert(root, status_section)
|
table.insert(root, status_section)
|
||||||
|
|
|
@ -38,7 +38,7 @@ M.open = function(state, path, extra)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if selected.type == "workspace" then
|
if selected.type == "workspace" then
|
||||||
if CODEMP.workspace ~= nil and CODEMP.workspace.name ~= selected.name then
|
if CODEMP.workspace ~= nil and CODEMP.workspace:id() ~= selected.name then
|
||||||
error("must leave current workspace first")
|
error("must leave current workspace first")
|
||||||
end
|
end
|
||||||
if CODEMP.workspace == nil then
|
if CODEMP.workspace == nil then
|
||||||
|
@ -62,10 +62,12 @@ M.open = function(state, path, extra)
|
||||||
local usr = ws_manager.map[selected.name]
|
local usr = ws_manager.map[selected.name]
|
||||||
print(" /\\/ following " .. selected.name)
|
print(" /\\/ following " .. selected.name)
|
||||||
CODEMP.following = selected.name
|
CODEMP.following = selected.name
|
||||||
local _ = CODEMP.workspace.cursor:send({
|
local _ = CODEMP.workspace:cursor():send({
|
||||||
buffer = "",
|
buffer = "",
|
||||||
start = { 0, 0 },
|
start_row = 0,
|
||||||
finish = { 0, 0 },
|
start_col = 0,
|
||||||
|
end_row = 0,
|
||||||
|
end_col = 0,
|
||||||
}) -- clear current cursor
|
}) -- clear current cursor
|
||||||
if usr ~= nil then
|
if usr ~= nil then
|
||||||
local buf_name = buf_manager.users[selected.name]
|
local buf_name = buf_manager.users[selected.name]
|
||||||
|
@ -133,7 +135,7 @@ M.delete = function(state, path, extra)
|
||||||
if buf_manager.map_rev[selected.name] ~= nil then
|
if buf_manager.map_rev[selected.name] ~= nil then
|
||||||
buf_manager.detach(selected.name)
|
buf_manager.detach(selected.name)
|
||||||
end
|
end
|
||||||
CODEMP.workspace:delete(selected.name):and_then(function ()
|
CODEMP.workspace:delete_buffer(selected.name):and_then(function ()
|
||||||
print("deleted buffer " .. selected.name)
|
print("deleted buffer " .. selected.name)
|
||||||
manager.refresh("codemp")
|
manager.refresh("codemp")
|
||||||
end)
|
end)
|
||||||
|
@ -156,7 +158,7 @@ M.add = function(state, path, extra)
|
||||||
if vim.startswith(selected.name, "#") then
|
if vim.startswith(selected.name, "#") then
|
||||||
vim.ui.input({ prompt = "new buffer path" }, function(input)
|
vim.ui.input({ prompt = "new buffer path" }, function(input)
|
||||||
if input == nil or input == "" then return end
|
if input == nil or input == "" then return end
|
||||||
CODEMP.workspace:create(input):and_then(function ()
|
CODEMP.workspace:create_buffer(input):and_then(function ()
|
||||||
manager.refresh("codemp")
|
manager.refresh("codemp")
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -225,7 +225,7 @@ return {
|
||||||
get_content = buffer_get_content,
|
get_content = buffer_get_content,
|
||||||
set_content = buffer_set_content,
|
set_content = buffer_set_content,
|
||||||
},
|
},
|
||||||
available_colors = available_colors,
|
available_colors = colors,
|
||||||
color = color,
|
color = color,
|
||||||
poller = async_poller,
|
poller = async_poller,
|
||||||
sep = separator,
|
sep = separator,
|
||||||
|
|
|
@ -40,10 +40,10 @@ local function update_window()
|
||||||
local buffer_to_row = {}
|
local buffer_to_row = {}
|
||||||
local user_to_row = {}
|
local user_to_row = {}
|
||||||
local off = {}
|
local off = {}
|
||||||
local tree = CODEMP.workspace:filetree()
|
local tree = CODEMP.workspace:search_buffers()
|
||||||
vim.api.nvim_set_option_value('modifiable', true, { buf = buffer_id })
|
vim.api.nvim_set_option_value('modifiable', true, { buf = buffer_id })
|
||||||
local tmp = ">| codemp\n"
|
local tmp = ">| codemp\n"
|
||||||
tmp = tmp .. " |: " .. CODEMP.workspace.name .. "\n"
|
tmp = tmp .. " |: " .. CODEMP.workspace:id() .. "\n"
|
||||||
tmp = tmp .. " |\n"
|
tmp = tmp .. " |\n"
|
||||||
local base_row = 3
|
local base_row = 3
|
||||||
for n, path in pairs(tree) do
|
for n, path in pairs(tree) do
|
||||||
|
|
|
@ -12,14 +12,14 @@ local user_hl = {}
|
||||||
|
|
||||||
local function fetch_workspaces_list()
|
local function fetch_workspaces_list()
|
||||||
local new_list = {}
|
local new_list = {}
|
||||||
CODEMP.client:list_workspaces(true, false):and_then(function (owned)
|
CODEMP.client:fetch_owned_workspaces():and_then(function (owned)
|
||||||
for _, ws in pairs(owned) do
|
for _, ws in pairs(owned) do
|
||||||
table.insert(new_list, {
|
table.insert(new_list, {
|
||||||
name = ws,
|
name = ws,
|
||||||
owned = true,
|
owned = true,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
CODEMP.client:list_workspaces(false, true):and_then(function (invited)
|
CODEMP.client:fetch_joined_workspaces():and_then(function (invited)
|
||||||
for _, ws in pairs(invited) do
|
for _, ws in pairs(invited) do
|
||||||
table.insert(new_list, {
|
table.insert(new_list, {
|
||||||
name = ws,
|
name = ws,
|
||||||
|
@ -77,8 +77,8 @@ local function register_cursor_callback(controller, name)
|
||||||
end
|
end
|
||||||
once = false
|
once = false
|
||||||
end
|
end
|
||||||
local oldbuf = buffers.users[CODEMP.client.username]
|
local oldbuf = buffers.users[CODEMP.client:current_user().name]
|
||||||
buffers.users[CODEMP.client.username] = bufname
|
buffers.users[CODEMP.client:current_user().name] = bufname
|
||||||
if oldbuf ~= bufname then
|
if oldbuf ~= bufname then
|
||||||
require('codemp.window').update()
|
require('codemp.window').update()
|
||||||
end
|
end
|
||||||
|
@ -175,22 +175,22 @@ local events_poller = nil
|
||||||
---join a workspace and register event handlers
|
---join a workspace and register event handlers
|
||||||
local function join(workspace)
|
local function join(workspace)
|
||||||
print(" <> joining workspace " .. workspace .. " ...")
|
print(" <> joining workspace " .. workspace .. " ...")
|
||||||
CODEMP.client:join_workspace(workspace):and_then(function (ws)
|
CODEMP.client:attach_workspace(workspace):and_then(function (ws)
|
||||||
print(" >< joined workspace " .. ws.name)
|
print(" >< joined workspace " .. ws:id())
|
||||||
register_cursor_callback(ws.cursor, ws.name)
|
register_cursor_callback(ws:cursor(), ws:id())
|
||||||
register_cursor_handler(ws.cursor)
|
register_cursor_handler(ws:cursor())
|
||||||
CODEMP.workspace = ws
|
CODEMP.workspace = ws
|
||||||
for _, user in pairs(CODEMP.workspace:user_list()) do
|
for _, user in pairs(CODEMP.workspace:user_list()) do
|
||||||
buffers.users[user] = ""
|
buffers.users[user] = ""
|
||||||
user_hl[user] = {
|
user_hl[user] = {
|
||||||
ns = vim.api.nvim_create_namespace("codemp-cursor-" .. user),
|
ns = vim.api.nvim_create_namespace("codemp-cursor-" .. user),
|
||||||
hi = utils.color(user),
|
hi = utils.color(user.name),
|
||||||
pos = { 0, 0 },
|
pos = { 0, 0 },
|
||||||
mark = nil,
|
mark = nil,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
require('codemp.window').update()
|
require('codemp.window').update()
|
||||||
local ws_name = ws.name
|
local ws_name = ws:id()
|
||||||
events_poller = utils.poller(
|
events_poller = utils.poller(
|
||||||
function()
|
function()
|
||||||
if CODEMP.client == nil then return nil end
|
if CODEMP.client == nil then return nil end
|
||||||
|
@ -225,8 +225,8 @@ local function join(workspace)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function leave()
|
local function leave()
|
||||||
local ws_name = CODEMP.workspace.name
|
local ws_name = CODEMP.workspace:id()
|
||||||
CODEMP.workspace.cursor:clear_callback()
|
CODEMP.workspace:cursor():clear_callback()
|
||||||
vim.api.nvim_clear_autocmds({ group = workspace_callback_group })
|
vim.api.nvim_clear_autocmds({ group = workspace_callback_group })
|
||||||
for id, name in pairs(buffers.map) do
|
for id, name in pairs(buffers.map) do
|
||||||
CODEMP.workspace:get_buffer(name):clear_callback()
|
CODEMP.workspace:get_buffer(name):clear_callback()
|
||||||
|
|
Loading…
Reference in a new issue