Skip to content

Commit 2a8e50d

Browse files
authored
feat!: Make the window picker function configurable. (#11)
BREAKING CHANGE: The configuration for the window picker has changed as a result of the function now being fully configurable. If you have previously configured the window picker, see `:h winshift.changelog-11` for more information about how to update your config.
1 parent 7014fda commit 2a8e50d

File tree

5 files changed

+187
-46
lines changed

5 files changed

+187
-46
lines changed

README.md

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,24 +70,31 @@ require("winshift").setup({
7070
["<S-right>"] = "far_right",
7171
},
7272
},
73-
-- The window picker is used to select a window while swapping windows with
74-
-- ':WinShift swap'.
75-
-- A string of chars used as identifiers by the window picker.
76-
window_picker_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
77-
window_picker_ignore = {
78-
-- This table allows you to indicate to the window picker that a window
79-
-- should be ignored if its buffer matches any of the following criteria.
80-
filetype = { -- List of ignored file types
81-
"NvimTree",
82-
},
83-
buftype = { -- List of ignored buftypes
84-
"terminal",
85-
"quickfix",
86-
},
87-
bufname = { -- List of regex patterns matching ignored buffer names
88-
[[.*foo/bar/baz\.qux]]
89-
},
90-
},
73+
---A function that should prompt the user to select a window.
74+
---
75+
---The window picker is used to select a window while swapping windows with
76+
---`:WinShift swap`.
77+
---@return integer? winid # Either the selected window ID, or `nil` to
78+
--- indicate that the user cancelled / gave an invalid selection.
79+
window_picker = function()
80+
return require("winshift.lib").pick_window({
81+
-- A string of chars used as identifiers by the window picker.
82+
picker_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
83+
filter_rules = {
84+
-- This table allows you to indicate to the window picker that a window
85+
-- should be ignored if its buffer matches any of the following criteria.
86+
cur_win = true, -- Filter out the current window
87+
floats = true, -- Filter out floating windows
88+
filetype = {}, -- List of ignored file types
89+
buftype = {}, -- List of ignored buftypes
90+
bufname = {}, -- List of vim regex patterns matching ignored buffer names
91+
},
92+
---A function used to filter the list of selectable windows.
93+
---@param winids integer[] # The list of selectable window IDs.
94+
---@return integer[] filtered # The filtered list of window IDs.
95+
filter_func = nil,
96+
})
97+
end,
9198
})
9299
```
93100

doc/winshift.txt

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
*winshift.nvim* WinShift.nvim
1+
*winshift.txt* WinShift.nvim
22

33
Rearrange your windows with ease.
44

55
Author: Sindre T. Strøm
66

77
==============================================================================
88

9-
INTRODUCTION *winshift-introduction*
9+
INTRODUCTION *winshift.nvim* *winshift*
1010

1111
WinShift lets you move windows, not only around each other, but also in and
1212
out of rows and columns.
1313

14-
USAGE *Win-Move-mode* *winshift-usage*
14+
USAGE *Win-Move-mode* *winshift-usage*
1515

1616
Enter Win-Move mode by calling `:WinShift`. This will target your current
1717
window for moving. You can move the window either by using |hjkl| or the arrow
1818
keys. You can move the window to any of the far ends of the viewport by
1919
pressing one of `HJKL`, or shift + any arrow key. Exit Win-Move mode by
2020
pressing `q` / `<esc>` / `<C-c>`.
2121

22-
CONFIGURATION *winshift-config*
22+
CONFIGURATION *winshift-config*
2323

2424
Example configuration with default settings:
2525
>
@@ -56,12 +56,37 @@ Example configuration with default settings:
5656
["<S-right>"] = "far_right",
5757
},
5858
},
59+
---A function that should prompt the user to select a window.
60+
---
61+
---The window picker is used to select a window while swapping windows with
62+
---`:WinShift swap`.
63+
---@return integer? winid # Either the selected window ID, or `nil` to
64+
--- indicate that the user cancelled / gave an invalid selection.
65+
window_picker = function()
66+
return require("winshift.lib").pick_window({
67+
-- A string of chars used as identifiers by the window picker.
68+
picker_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
69+
filter_rules = {
70+
-- This table allows you to indicate to the window picker that a window
71+
-- should be ignored if its buffer matches any of the following criteria.
72+
cur_win = true, -- Filter out the current window
73+
floats = true, -- Filter out floating windows
74+
filetype = {}, -- List of ignored file types
75+
buftype = {}, -- List of ignored buftypes
76+
bufname = {}, -- List of vim regex patterns matching ignored buffer names
77+
},
78+
---A function used to filter the list of selectable windows.
79+
---@param winids integer[] # The list of selectable window IDs.
80+
---@return integer[] filtered # The filtered list of window IDs.
81+
filter_func = nil,
82+
})
83+
end,
5984
})
6085
<
6186

62-
COMMANDS *winshift-commands*
87+
COMMANDS *winshift-commands*
6388

64-
*:WinShift*
89+
*:WinShift*
6590
:WinShift [direction]
6691
When called without [direction]: starts Win-Move mode
6792
targeting the current window for moving. For how to
@@ -82,7 +107,7 @@ COMMANDS *winshift-commands*
82107
pressing the character displayed in the statusline of
83108
the target window. The input is case-insensitive.
84109

85-
CAVEATS *winshift-caveats*
110+
CAVEATS *winshift-caveats*
86111

87112
Moving through windows with 'winfixwidth' and / or 'winfixheight' can be a bit
88113
wonky. It will work, but it can be a bit hard to follow the movement, and the

doc/winshift_changelog.txt

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
================================================================================
2+
*winshift.changelog*
3+
4+
CHANGELOG
5+
6+
*winshift.changelog-11*
7+
8+
PR: https://github.com/sindrets/winshift.nvim/pull/11
9+
10+
The configuration for the window picker has changed as a result of the
11+
function now being fully configurable. If you have previously configured
12+
options for the window picker, move them into the options passed to the
13+
`pick_window` function:
14+
15+
Before: ~
16+
>
17+
require("winshift").setup({
18+
-- ...
19+
window_picker_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
20+
window_picker_ignore = {
21+
filetype = {
22+
"NvimTree",
23+
},
24+
buftype = {
25+
"terminal",
26+
"quickfix",
27+
},
28+
bufname = {
29+
[[.*foo/bar/baz\.qux]]
30+
},
31+
},
32+
})
33+
<
34+
After: ~
35+
>
36+
require("winshift").setup({
37+
-- ...
38+
window_picker = function()
39+
return require("winshift.lib").pick_window({
40+
picker_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
41+
filter_rules = {
42+
cur_win = true,
43+
floats = true,
44+
filetype = {
45+
"NvimTree",
46+
},
47+
buftype = {
48+
"terminal",
49+
"quickfix",
50+
},
51+
bufname = {
52+
[[.*foo/bar/baz\.qux]]
53+
},
54+
},
55+
})
56+
end,
57+
})
58+
<
59+
60+
See |winshift-config| more information about how to configure the window
61+
picker.
62+
63+
vim:tw=78:ts=8:ft=help:norl:

lua/winshift/config.lua

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,28 @@ M.defaults = {
3232
["<S-right>"] = "far_right",
3333
},
3434
},
35-
window_picker_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
36-
window_picker_ignore = {
37-
filetype = {},
38-
buftype = {},
39-
bufname = {},
40-
},
35+
---A function that should prompt the user to select a window.
36+
---
37+
---The window picker is used to select a window while swapping windows with
38+
---`:WinShift swap`.
39+
---@return integer? winid # Either the selected window ID, or `nil` to
40+
--- indicate that the user cancelled / gave an invalid selection.
41+
window_picker = function()
42+
return require("winshift.lib").pick_window({
43+
picker_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
44+
filter_rules = {
45+
cur_win = true,
46+
floats = true,
47+
filetype = {},
48+
buftype = {},
49+
bufname = {},
50+
},
51+
---A function used to filter the list of selectable windows.
52+
---@param winids integer[] # The list of selectable window IDs.
53+
---@return integer[] filtered # The filtered list of window IDs.
54+
filter_func = nil,
55+
})
56+
end,
4157
}
4258
-- stylua: ignore end
4359

@@ -65,6 +81,17 @@ function M.setup(user_config)
6581

6682
M._config.moving_win_options = user_config.moving_win_options or M._config.moving_win_options
6783

84+
--#region DEPRECATION NOTICES
85+
86+
if M._config.window_picker_chars or M._config.window_picker_ignore then
87+
utils.warn(table.concat({
88+
"'window_picker_chars' and 'window_picker_ignore' has been deprecated!",
89+
" See ':h winshift.changelog-11' for more information.",
90+
}, ""))
91+
end
92+
93+
--#endregion
94+
6895
if M._config.keymaps.disable_defaults then
6996
for name, _ in pairs(M._config.keymaps) do
7097
if name ~= "disable_defaults" then

lua/winshift/lib.lua

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -277,47 +277,66 @@ function M.next_node_vertical(leaf, dir)
277277
end
278278
end
279279

280+
---@class WindowPickerFilterRules
281+
---@field cur_win boolean
282+
---@field floats boolean
283+
---@field filetype string[]
284+
---@field buftype string[]
285+
---@field bufname string[]
286+
287+
---@class WindowPickerSpec
288+
---@field picker_chars string
289+
---@field filter_rules WindowPickerFilterRules
290+
---@field filter_func fun(winids: integer[]): integer[]
291+
280292
---Get user to pick a window. Selectable windows are all windows in the current
281293
---tabpage.
282-
---@param ignore table<integer, boolean>
294+
---@param opt? WindowPickerSpec
283295
---@return integer|nil -- If a valid window was picked, return its id. If an
284296
--- invalid window was picked / user canceled, return nil. If there are
285297
--- no selectable windows, return -1.
286-
function M.pick_window(ignore)
298+
function M.pick_window(opt)
299+
opt = opt or {}
287300
local tabpage = api.nvim_get_current_tabpage()
288301
local win_ids = api.nvim_tabpage_list_wins(tabpage)
289-
local exclude = config.get_config().window_picker_ignore
302+
local curwin = api.nvim_get_current_win()
303+
local filter_rules = opt.filter_rules or {}
290304

291305
local selectable = vim.tbl_filter(function (id)
292-
local bufid = api.nvim_win_get_buf(id)
293-
local bufname = api.nvim_buf_get_name(bufid)
294-
295-
if ignore[id] then
306+
if filter_rules.cur_win and curwin == id then
307+
return false
308+
elseif filter_rules.floats and api.nvim_win_get_config(id).relative ~= "" then
296309
return false
297310
end
298311

312+
local bufid = api.nvim_win_get_buf(id)
313+
local bufname = api.nvim_buf_get_name(bufid)
314+
299315
for _, option in ipairs({ "filetype", "buftype" }) do
300-
if vim.tbl_contains(exclude[option], vim.bo[bufid][option]) then
316+
if vim.tbl_contains(filter_rules[option] or {}, vim.bo[bufid][option]) then
301317
return false
302318
end
303319
end
304320

305-
for _, pattern in ipairs(exclude.bufname) do
321+
for _, pattern in ipairs(filter_rules.bufname or {}) do
306322
local regex = vim.regex(pattern)
307323
if regex:match_str(bufname) ~= nil then
308324
return false
309325
end
310326
end
311327

312-
local win_config = api.nvim_win_get_config(id)
313-
return win_config.focusable and not win_config.external
328+
return true
314329
end, win_ids)
315330

331+
if opt.filter_func then
332+
selectable = opt.filter_func(selectable)
333+
end
334+
316335
-- If there are no selectable windows: return. If there's only 1, return it without picking.
317336
if #selectable == 0 then return -1 end
318337
if #selectable == 1 then return selectable[1] end
319338

320-
local chars = config.get_config().window_picker_chars:upper()
339+
local chars = (opt.picker_chars or "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"):upper()
321340
local i = 1
322341
local win_opts = {}
323342
local win_map = {}
@@ -360,8 +379,8 @@ function M.pick_window(ignore)
360379

361380
-- Restore window options
362381
for _, id in ipairs(selectable) do
363-
for opt, value in pairs(win_opts[id]) do
364-
api.nvim_win_set_option(id, opt, value)
382+
for option, value in pairs(win_opts[id]) do
383+
api.nvim_win_set_option(id, option, value)
365384
end
366385
end
367386

@@ -568,7 +587,7 @@ function M.start_swap_mode()
568587
vim.cmd("redraw")
569588

570589
local ok, err = pcall(function()
571-
local target = M.pick_window({ [cur_win] = true })
590+
local target = conf.window_picker()
572591

573592
if target == -1 or target == nil then
574593
return

0 commit comments

Comments
 (0)