WinShift.nvim
Rearrange your windows with ease.
Introduction
Window moving in vim is rather limited. You can exchange a window with any other window in the same column or row, and you can rotate the order of windows within a column or row. This doesn't grant much flexibility, and yet there are limitations to when these operations work.
WinShift lets you freely rearrange your window layouts by letting you move any window in any direction. Further, it doesn't only let you move around windows, but also lets you form new columns and rows by moving into windows horizontally or vertically respectively.
Requirements
- Neovim ≥ 0.7.2
Installation
Install the plugin with your package manager of choice.
" Plug
Plug 'sindrets/winshift.nvim'
-- Packer
use 'sindrets/winshift.nvim'
Configuration
-- Lua
require("winshift").setup({
highlight_moving_win = true, -- Highlight the window being moved
focused_hl_group = "Visual", -- The highlight group used for the moving window
moving_win_options = {
-- These are local options applied to the moving window while it's
-- being moved. They are unset when you leave Win-Move mode.
wrap = false,
cursorline = false,
cursorcolumn = false,
colorcolumn = "",
},
keymaps = {
disable_defaults = false, -- Disable the default keymaps
win_move_mode = {
["h"] = "left",
["j"] = "down",
["k"] = "up",
["l"] = "right",
["H"] = "far_left",
["J"] = "far_down",
["K"] = "far_up",
["L"] = "far_right",
["<left>"] = "left",
["<down>"] = "down",
["<up>"] = "up",
["<right>"] = "right",
["<S-left>"] = "far_left",
["<S-down>"] = "far_down",
["<S-up>"] = "far_up",
["<S-right>"] = "far_right",
},
},
---A function that should prompt the user to select a window.
---
---The window picker is used to select a window while swapping windows with
---`:WinShift swap`.
---@return integer? winid # Either the selected window ID, or `nil` to
--- indicate that the user cancelled / gave an invalid selection.
window_picker = function()
return require("winshift.lib").pick_window({
-- A string of chars used as identifiers by the window picker.
picker_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
filter_rules = {
-- This table allows you to indicate to the window picker that a window
-- should be ignored if its buffer matches any of the following criteria.
cur_win = true, -- Filter out the current window
floats = true, -- Filter out floating windows
filetype = {}, -- List of ignored file types
buftype = {}, -- List of ignored buftypes
bufname = {}, -- List of vim regex patterns matching ignored buffer names
},
---A function used to filter the list of selectable windows.
---@param winids integer[] # The list of selectable window IDs.
---@return integer[] filtered # The filtered list of window IDs.
filter_func = nil,
})
end,
})
Optionally create some mappings for starting Win-Move mode:
" Start Win-Move mode:
nnoremap <C-W><C-M> <Cmd>WinShift<CR>
nnoremap <C-W>m <Cmd>WinShift<CR>
" Swap two windows:
nnoremap <C-W>X <Cmd>WinShift swap<CR>
" If you don't want to use Win-Move mode you can create mappings for calling the
" move commands directly:
nnoremap <C-M-H> <Cmd>WinShift left<CR>
nnoremap <C-M-J> <Cmd>WinShift down<CR>
nnoremap <C-M-K> <Cmd>WinShift up<CR>
nnoremap <C-M-L> <Cmd>WinShift right<CR>
Usage
:WinShift [direction]
When called without [direction]
: starts Win-Move mode targeting the current
window for moving. You can then move the window either by using hjkl
or the
arrow keys. You can move the window to any of the far ends of the viewport by
pressing one of HJKL
, or shift + any arrow key. Exit Win-Move mode
by pressing q
/ <esc>
/ <C-c>
.
With [direction]
: perform a one-shot move operation on the current window,
moving it in the given direction. [direction]
can be one of:
left
,right
,up
,down
,far_left
,far_right
,far_up
,far_down
The far_
variants will move the window to the far
end of the viewport in the given direction.
:WinShift swap
Swap the current window with another. When this command is called, you'll be prompted to select the window you want to swap with. A selection is made by pressing the character displayed in the statusline of the target window. The input is case-insensitive.
Caveats
Moving through windows with 'winfixwidth'
and / or 'winfixheight'
can be a
bit wonky. It will work, but it can be a bit hard to follow the movement, and
the fixed window might end up with different dimensions after. This is simply a
consequence of vim being forced to resize the window due to there not being
enough space to adhere to the fixed window's preferred dimensions.