aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
diff options
context:
space:
mode:
authordundargoc <gocdundar@gmail.com>2024-06-03 19:04:28 +0200
committerdundargoc <33953936+dundargoc@users.noreply.github.com>2024-06-08 21:38:06 +0200
commit9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c (patch)
tree0a9d7b503db73886b848e4c653119a741d4bf113 /runtime/lua/vim
parent4881211097aba7f5d17700362ec0967e3024f074 (diff)
downloadrneovim-9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c.tar.gz
rneovim-9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c.tar.bz2
rneovim-9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c.zip
feat(lua): add `vim._with`
It's a function to perform operations in their own sealed context, similar to pythons `with`. This helps ease operations where you need to perform an operation in a specific context, and then restore the context. Marked as private for now as it's not ready for public use. The current plan is to start using this internally so we can discover and fix any problems. Once this is ready to be exposed it will be renamed to `vim.with`. Usage: ```lua local ret = vim._with({context = val}, function() return "hello" end) ``` , where `context` is any combination of: - `buf` - `emsg_silent` - `hide` - `horizontal` - `keepalt` - `keepjumps` - `keepmarks` - `keeppatterns` - `lockmarks` - `noautocmd` - `options` - `sandbox` - `silent` - `unsilent` - `win` (except for `win` and `buf` which can't be used at the same time). This list will most likely be expanded in the future. Work on https://github.com/neovim/neovim/issues/19832. Co-authored-by: Lewis Russell <lewis6991@gmail.com>
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r--runtime/lua/vim/_comment.lua11
-rw-r--r--runtime/lua/vim/shared.lua78
2 files changed, 81 insertions, 8 deletions
diff --git a/runtime/lua/vim/_comment.lua b/runtime/lua/vim/_comment.lua
index 044cd69716..efe289b3e1 100644
--- a/runtime/lua/vim/_comment.lua
+++ b/runtime/lua/vim/_comment.lua
@@ -194,14 +194,9 @@ local function toggle_lines(line_start, line_end, ref_position)
-- - Debatable for highlighting in text area (like LSP semantic tokens).
-- Mostly because it causes flicker as highlighting is preserved during
-- comment toggling.
- package.loaded['vim._comment']._lines = vim.tbl_map(f, lines)
- local lua_cmd = string.format(
- 'vim.api.nvim_buf_set_lines(0, %d, %d, false, package.loaded["vim._comment"]._lines)',
- line_start - 1,
- line_end
- )
- vim.cmd.lua({ lua_cmd, mods = { lockmarks = true } })
- package.loaded['vim._comment']._lines = nil
+ vim._with({ lockmarks = true }, function()
+ vim.api.nvim_buf_set_lines(0, line_start - 1, line_end, false, vim.tbl_map(f, lines))
+ end)
end
--- Operator which toggles user-supplied range of lines
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 9d54a80144..7fd29d5f7b 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -1139,4 +1139,82 @@ function vim._defer_require(root, mod)
})
end
+--- @nodoc
+--- @class vim.context.mods
+--- @field buf? integer
+--- @field emsg_silent? boolean
+--- @field hide? boolean
+--- @field horizontal? boolean
+--- @field keepalt? boolean
+--- @field keepjumps? boolean
+--- @field keepmarks? boolean
+--- @field keeppatterns? boolean
+--- @field lockmarks? boolean
+--- @field noautocmd? boolean
+--- @field options? table<string, any>
+--- @field sandbox? boolean
+--- @field silent? boolean
+--- @field unsilent? boolean
+--- @field win? integer
+
+--- Executes function `f` with the given context specification.
+---
+--- @param context vim.context.mods
+function vim._with(context, f)
+ vim.validate('context', context, 'table')
+ vim.validate('f', f, 'function')
+
+ vim.validate('context.buf', context.buf, 'number', true)
+ vim.validate('context.emsg_silent', context.emsg_silent, 'boolean', true)
+ vim.validate('context.hide', context.hide, 'boolean', true)
+ vim.validate('context.horizontal', context.horizontal, 'boolean', true)
+ vim.validate('context.keepalt', context.keepalt, 'boolean', true)
+ vim.validate('context.keepjumps', context.keepjumps, 'boolean', true)
+ vim.validate('context.keepmarks', context.keepmarks, 'boolean', true)
+ vim.validate('context.keeppatterns', context.keeppatterns, 'boolean', true)
+ vim.validate('context.lockmarks', context.lockmarks, 'boolean', true)
+ vim.validate('context.noautocmd', context.noautocmd, 'boolean', true)
+ vim.validate('context.options', context.options, 'table', true)
+ vim.validate('context.sandbox', context.sandbox, 'boolean', true)
+ vim.validate('context.silent', context.silent, 'boolean', true)
+ vim.validate('context.unsilent', context.unsilent, 'boolean', true)
+ vim.validate('context.win', context.win, 'number', true)
+
+ -- Check buffer exists
+ if context.buf then
+ if not vim.api.nvim_buf_is_valid(context.buf) then
+ error('Invalid buffer id: ' .. context.buf)
+ end
+ end
+
+ -- Check window exists
+ if context.win then
+ if not vim.api.nvim_win_is_valid(context.win) then
+ error('Invalid window id: ' .. context.win)
+ end
+ end
+
+ -- Store original options
+ local previous_options ---@type table<string, any>
+ if context.options then
+ previous_options = {}
+ for k, v in pairs(context.options) do
+ previous_options[k] =
+ vim.api.nvim_get_option_value(k, { win = context.win, buf = context.buf })
+ vim.api.nvim_set_option_value(k, v, { win = context.win, buf = context.buf })
+ end
+ end
+
+ local retval = { vim._with_c(context, f) }
+
+ -- Restore original options
+ if previous_options then
+ for k, v in pairs(previous_options) do
+ vim.api.nvim_set_option_value(k, v, { win = context.win, buf = context.buf })
+ end
+ end
+
+ return unpack(retval)
+end
+
return vim