Skip to content

Commit c1c55fe

Browse files
committed
fix!: Remove workaround for setting local options. (fixes #12)
BREAKING CHANGE: Minimum required version has been bumped to 0.7.2.
1 parent 9e88474 commit c1c55fe

File tree

3 files changed

+71
-35
lines changed

3 files changed

+71
-35
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ or vertically respectively.
1818

1919
## Requirements
2020

21-
- Neovim ≥ 0.5.0
21+
- Neovim ≥ 0.7.2
2222

2323
## Installation
2424

lua/winshift/lib.lua

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,10 +547,13 @@ function M.start_move_mode()
547547
api.nvim_echo({ { "-- WIN MOVE MODE -- press 'q' to exit", "ModeMsg" } }, false, {})
548548
char, raw = utils.input_char(nil, { clear_prompt = false, allow_non_ascii = true })
549549
local dir = key_dir_map[char or raw]
550-
if dir then
551-
M.move_win(cur_win, dir)
552-
end
550+
551+
if dir then M.move_win(cur_win, dir) end
552+
553553
vim.cmd("redraw")
554+
555+
api.nvim_exec_autocmds({ "WinScrolled" }, { modeline = false })
556+
vim.schedule(function() vim.cmd("redraw") end)
554557
end
555558
end)
556559

lua/winshift/utils.lua

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
local api = vim.api
22
local M = {}
33

4-
---@alias vector any[]
5-
6-
local setlocal_opr_templates = {
7-
set = [[setl ${option}=${value}]],
8-
remove = [[exe 'setl ${option}-=${value}']],
9-
append = [[exe 'setl ${option}=' . (&${option} == "" ? "" : &${option} . ",") . '${value}']],
10-
prepend = [[exe 'setl ${option}=${value}' . (&${option} == "" ? "" : "," . &${option})]],
11-
}
4+
---@alias vector<T> T[]
125

136
function M._echo_multiline(msg, hl, schedule)
147
if schedule then
@@ -50,6 +43,7 @@ end
5043
---@return any result Return value
5144
function M.no_win_event_call(f)
5245
local last = vim.o.eventignore
46+
---@diagnostic disable-next-line: undefined-field
5347
vim.opt.eventignore:prepend(
5448
"WinEnter,WinLeave,WinNew,WinClosed,BufWinEnter,BufWinLeave,BufEnter,BufLeave"
5549
)
@@ -237,6 +231,8 @@ function M.input_char(prompt, opt)
237231

238232
local s = type(c) == "number" and vim.fn.nr2char(c) or nil
239233
local raw = type(c) == "number" and s or c
234+
235+
---@diagnostic disable-next-line: return-type-mismatch
240236
return s, raw
241237
end
242238

@@ -263,45 +259,82 @@ function M.pause(msg)
263259
)
264260
end
265261

266-
---@class SetLocalSpec
262+
---Map of options that accept comma separated, list-like values, but don't work
263+
---correctly with Option:set(), Option:append(), Option:prepend(), and
264+
---Option:remove() (seemingly for legacy reasons).
265+
---WARN: This map is incomplete!
266+
local list_like_options = {
267+
winhighlight = true,
268+
listchars = true,
269+
fillchars = true,
270+
}
271+
272+
---@class utils.set_local.Opt
267273
---@field method '"set"'|'"remove"'|'"append"'|'"prepend"' Assignment method. (default: "set")
268274

269-
---@class SetLocalListSpec : string[]
270-
---@field opt SetLocalSpec
275+
---@class utils.set_local.ListSpec : string[]
276+
---@field opt utils.set_local.Opt
277+
278+
---@alias WindowOptions table<string, boolean|integer|string|utils.set_local.ListSpec>
271279

272-
---HACK: workaround for inconsistent behavior from `vim.opt_local`.
273-
---@see [Neovim issue](https://github.com/neovim/neovim/issues/14670)
274280
---@param winids number[]|number Either a list of winids, or a single winid (0 for current window).
275-
---@param option_map table<string, SetLocalListSpec|string|boolean>
276-
---@param opt? SetLocalSpec
281+
---@param option_map WindowOptions
282+
---@param opt? utils.set_local.Opt
277283
function M.set_local(winids, option_map, opt)
278284
if type(winids) ~= "table" then
279285
winids = { winids }
280286
end
281287

282-
opt = vim.tbl_extend("keep", opt or {}, { method = "set" })
288+
opt = vim.tbl_extend("keep", opt or {}, { method = "set" }) --[[@as table ]]
283289

284-
local cmd
285290
for _, id in ipairs(winids) do
286291
api.nvim_win_call(id, function()
287292
for option, value in pairs(option_map) do
288-
if type(value) == "boolean" then
289-
cmd = string.format("setl %s%s", value and "" or "no", option)
290-
else
291-
---@type SetLocalSpec
292-
local o = opt
293-
if type(value) == "table" then
294-
o = vim.tbl_extend("force", opt, value.opt or {})
295-
value = table.concat(value, ",")
293+
local o = opt
294+
local fullname = api.nvim_get_option_info(option).name
295+
local is_list_like = list_like_options[fullname]
296+
local cur_value = vim.o[fullname]
297+
298+
if type(value) == "table" then
299+
if value.opt then
300+
o = vim.tbl_extend("force", opt, value.opt) --[[@as table ]]
296301
end
297302

298-
cmd = M.str_template(
299-
setlocal_opr_templates[o.method],
300-
{ option = option, value = tostring(value):gsub("'", "''") }
301-
)
303+
if is_list_like then
304+
value = table.concat(value, ",")
305+
end
302306
end
303307

304-
vim.cmd(cmd)
308+
if o.method == "set" then
309+
vim.opt_local[option] = value
310+
311+
else
312+
if o.method == "remove" then
313+
if is_list_like then
314+
vim.opt_local[fullname] = cur_value:gsub(",?" .. vim.pesc(value), "")
315+
else
316+
vim.opt_local[fullname]:remove(value)
317+
end
318+
319+
elseif o.method == "append" then
320+
if is_list_like then
321+
vim.opt_local[fullname] = ("%s%s"):format(cur_value ~= "" and cur_value .. ",", value)
322+
else
323+
vim.opt_local[fullname]:append(value)
324+
end
325+
326+
elseif o.method == "prepend" then
327+
if is_list_like then
328+
vim.opt_local[fullname] = ("%s%s%s"):format(
329+
value,
330+
cur_value ~= "" and "," or "",
331+
cur_value
332+
)
333+
else
334+
vim.opt_local[fullname]:prepend(value)
335+
end
336+
end
337+
end
305338
end
306339
end)
307340
end
@@ -316,7 +349,7 @@ function M.unset_local(winids, option)
316349

317350
for _, id in ipairs(winids) do
318351
api.nvim_win_call(id, function()
319-
vim.cmd(string.format("set %s<", option))
352+
vim.opt_local[option] = nil
320353
end)
321354
end
322355
end

0 commit comments

Comments
 (0)