Create simple window management in neovim, you can swap buffers in
windows, resize windows and enter a resizing mode. Also add some utility functionality to support this and update the rest of the config to use these new utility functions
This commit is contained in:
parent
653e57198a
commit
697d0acf15
4 changed files with 296 additions and 118 deletions
|
|
@ -12,7 +12,6 @@ local function setup_yank_highlight()
|
|||
})
|
||||
end,
|
||||
group = yank_autocommand,
|
||||
pattern = "*",
|
||||
})
|
||||
end
|
||||
|
||||
|
|
@ -31,107 +30,8 @@ require("lazy").setup("plugs")
|
|||
-- Initialize the sticky terminal window at the bottom
|
||||
require("terminal").setup()
|
||||
|
||||
-- Initialize the custom window management functionality
|
||||
require("window_management").setup()
|
||||
|
||||
-- See ":help vim.highlight.on_yank()"
|
||||
setup_yank_highlight()
|
||||
|
||||
-- Extract to plugin later
|
||||
local function is_floating_window(window)
|
||||
return vim.api.nvim_win_get_config(window).relative ~= ""
|
||||
end
|
||||
|
||||
local function is_window_resizable(window)
|
||||
local config = vim.api.nvim_win_get_config(window)
|
||||
return not config.winfixwidth and not config.winfixheight
|
||||
end
|
||||
|
||||
local function get_total_num_windows_open()
|
||||
return #vim.api.nvim_tabpage_list_wins(0)
|
||||
end
|
||||
|
||||
local function get_adjacent_window(dir_char)
|
||||
assert(dir_char == "h" or dir_char == "j" or dir_char == "k" or dir_char == "l", "Invalid direction character")
|
||||
local current_window = vim.api.nvim_get_current_win()
|
||||
assert(current_window, "Current window is nil")
|
||||
|
||||
vim.cmd("wincmd " .. dir_char)
|
||||
local new_window = vim.api.nvim_get_current_win()
|
||||
vim.api.nvim_set_current_win(current_window)
|
||||
|
||||
assert(vim.api.nvim_get_current_win() == current_window, "Cursor moved to a different window")
|
||||
return new_window
|
||||
end
|
||||
|
||||
local function is_current_window_at_edge(dir_char)
|
||||
return vim.api.nvim_get_current_win() == get_adjacent_window(dir_char)
|
||||
end
|
||||
|
||||
local function swap_buffer_between_windows(window_a, window_b)
|
||||
assert(window_a and window_b, "Invalid window")
|
||||
|
||||
local buffer_a = vim.api.nvim_win_get_buf(window_a)
|
||||
local buffer_b = vim.api.nvim_win_get_buf(window_b)
|
||||
vim.api.nvim_win_set_buf(window_a, buffer_b)
|
||||
vim.api.nvim_win_set_buf(window_b, buffer_a)
|
||||
|
||||
assert(vim.api.nvim_win_get_buf(window_a) == buffer_b and vim.api.nvim_win_get_buf(window_b) == buffer_a,
|
||||
"Failed to swap buffers")
|
||||
end
|
||||
|
||||
local function swap_window(dir_char)
|
||||
assert(dir_char == "h" or dir_char == "j" or dir_char == "k" or dir_char == "l", "Invalid direction character")
|
||||
local current_window = vim.api.nvim_get_current_win()
|
||||
assert(current_window, "Current window is nil")
|
||||
|
||||
local required_num_windows = 2
|
||||
if get_total_num_windows_open() < required_num_windows then
|
||||
return
|
||||
end
|
||||
|
||||
if is_floating_window(current_window) then
|
||||
return
|
||||
end
|
||||
|
||||
if is_current_window_at_edge(dir_char) then
|
||||
return
|
||||
end
|
||||
|
||||
if not is_window_resizable(current_window) then
|
||||
return
|
||||
end
|
||||
|
||||
local adjacent_window = get_adjacent_window(dir_char)
|
||||
if not is_window_resizable(adjacent_window) then
|
||||
return
|
||||
end
|
||||
|
||||
swap_buffer_between_windows(current_window, adjacent_window)
|
||||
end
|
||||
|
||||
require("utils").add_keymaps({
|
||||
n = {
|
||||
-- ["<C-S>Left"] = {
|
||||
["h"] = {
|
||||
cmd = function()
|
||||
swap_window("h")
|
||||
end
|
||||
},
|
||||
-- ["<C-S>Down"] = {
|
||||
["j"] = {
|
||||
cmd = function()
|
||||
swap_window("j")
|
||||
end
|
||||
},
|
||||
-- ["<C-S>Up"] = {
|
||||
["k"] = {
|
||||
cmd = function()
|
||||
swap_window("k")
|
||||
end
|
||||
},
|
||||
-- ["<C-S>Right"] = {
|
||||
["l"] = {
|
||||
cmd = function()
|
||||
swap_window("l")
|
||||
end
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,15 +17,6 @@ local function get_open_buffers_with_inlay_hints()
|
|||
return buffers
|
||||
end
|
||||
|
||||
local function add_leap_autocmd(pattern, callback)
|
||||
vim.api.nvim_create_autocmd("User", {
|
||||
pattern = pattern,
|
||||
callback = function()
|
||||
callback()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return {
|
||||
"ggandor/leap.nvim",
|
||||
dependencies = {
|
||||
|
|
@ -37,7 +28,7 @@ return {
|
|||
|
||||
local autocmds = {
|
||||
{
|
||||
pattern = "LeapEnter",
|
||||
event_name = "LeapEnter",
|
||||
cb = function()
|
||||
local open_buffers = get_open_buffers_with_inlay_hints()
|
||||
set_inlay_hints_active(open_buffers, false)
|
||||
|
|
@ -45,15 +36,18 @@ return {
|
|||
end
|
||||
},
|
||||
{
|
||||
pattern = "LeapLeave",
|
||||
event_name = "LeapLeave",
|
||||
cb = function()
|
||||
set_inlay_hints_active(buffers_without_inlay_hints, true)
|
||||
end
|
||||
},
|
||||
}
|
||||
|
||||
local utils = require("utils")
|
||||
local leap_augroup_name = "LeapEvents"
|
||||
vim.api.nvim_create_augroup(leap_augroup_name, { clear = true })
|
||||
for _, cmd in ipairs(autocmds) do
|
||||
add_leap_autocmd(cmd.pattern, cmd.cb)
|
||||
utils.create_user_event_cb(cmd.event_name, cmd.cb, leap_augroup_name)
|
||||
end
|
||||
|
||||
require("utils").add_keymaps({
|
||||
|
|
|
|||
|
|
@ -1,9 +1,66 @@
|
|||
local M = {}
|
||||
|
||||
local function is_single_keymap_table(map_table)
|
||||
assert(map_table)
|
||||
return map_table.n or map_table.t or map_table.i or map_table.v
|
||||
end
|
||||
|
||||
function M.create_user_event_cb(event_name, function_callback, augroup)
|
||||
assert(event_name and event_name ~= "", "Event name must be provided")
|
||||
assert(function_callback and type(function_callback) == "function", "Callback must be a valid function")
|
||||
|
||||
local cmd = {
|
||||
callback = function_callback,
|
||||
pattern = event_name,
|
||||
}
|
||||
|
||||
if augroup then
|
||||
cmd.group = augroup
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd("User", cmd)
|
||||
end
|
||||
|
||||
function M.broadcast_event(event_name)
|
||||
vim.api.nvim_command("doautocmd <nomodeline> User " .. event_name)
|
||||
end
|
||||
|
||||
function M.add_keymaps(maps)
|
||||
for mode, entries in pairs(maps) do
|
||||
for code, info in pairs(entries) do
|
||||
vim.keymap.set(mode, code, info.cmd, info.opts)
|
||||
assert(maps)
|
||||
|
||||
local function set_keymaps(map_table)
|
||||
for mode, entries in pairs(map_table) do
|
||||
for code, info in pairs(entries) do
|
||||
vim.keymap.set(mode, code, info.cmd, info.opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if is_single_keymap_table(maps) then
|
||||
set_keymaps(maps)
|
||||
else
|
||||
for _, map_table in pairs(maps) do
|
||||
set_keymaps(map_table)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.remove_keymaps(maps)
|
||||
assert(maps)
|
||||
|
||||
local function del_keymaps(map_table)
|
||||
for mode, entries in pairs(map_table) do
|
||||
for code, _ in pairs(entries) do
|
||||
vim.keymap.del(mode, code)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if is_single_keymap_table(maps) then
|
||||
del_keymaps(maps)
|
||||
else
|
||||
for _, map_table in pairs(maps) do
|
||||
del_keymaps(map_table)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
227
home/.config/nvim/lua/window_management.lua
Normal file
227
home/.config/nvim/lua/window_management.lua
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
local utils = require("utils")
|
||||
|
||||
local M = {}
|
||||
|
||||
local is_in_resizing_mode = false
|
||||
local on_resize_mode_enter_event = "ResizeModeEnter"
|
||||
local on_resize_mode_exit_event = "ResizeModeExit"
|
||||
|
||||
local function is_floating_window(window)
|
||||
assert(window, "Invalid window")
|
||||
|
||||
return vim.api.nvim_win_get_config(window).relative ~= ""
|
||||
end
|
||||
|
||||
local function is_window_resizable(window)
|
||||
assert(window, "Invalid window")
|
||||
|
||||
local config = vim.api.nvim_win_get_config(window)
|
||||
return not config.winfixwidth and not config.winfixheight
|
||||
end
|
||||
|
||||
local function get_total_num_windows_open()
|
||||
return #vim.api.nvim_tabpage_list_wins(0)
|
||||
end
|
||||
|
||||
local function get_adjacent_window(dir_char)
|
||||
assert(dir_char == "h" or dir_char == "j" or dir_char == "k" or dir_char == "l", "Invalid direction character")
|
||||
|
||||
local current_window = vim.api.nvim_get_current_win()
|
||||
if not current_window then
|
||||
return
|
||||
end
|
||||
|
||||
vim.cmd("wincmd " .. dir_char)
|
||||
local new_window = vim.api.nvim_get_current_win()
|
||||
vim.api.nvim_set_current_win(current_window)
|
||||
|
||||
assert(vim.api.nvim_get_current_win() == current_window, "Cursor moved to a different window")
|
||||
return new_window
|
||||
end
|
||||
|
||||
local function is_current_window_at_edge(dir_char)
|
||||
return vim.api.nvim_get_current_win() == get_adjacent_window(dir_char)
|
||||
end
|
||||
|
||||
local function swap_buffer_between_windows(window_a, window_b)
|
||||
assert(window_a and window_b, "Invalid window")
|
||||
|
||||
local buffer_a = vim.api.nvim_win_get_buf(window_a)
|
||||
local buffer_b = vim.api.nvim_win_get_buf(window_b)
|
||||
vim.api.nvim_win_set_buf(window_a, buffer_b)
|
||||
vim.api.nvim_win_set_buf(window_b, buffer_a)
|
||||
|
||||
assert(vim.api.nvim_win_get_buf(window_a) == buffer_b and vim.api.nvim_win_get_buf(window_b) == buffer_a,
|
||||
"Failed to swap buffers")
|
||||
end
|
||||
|
||||
local function swap_window(dir_char)
|
||||
assert(dir_char == "h" or dir_char == "j" or dir_char == "k" or dir_char == "l", "Invalid direction character")
|
||||
|
||||
local required_num_windows = 2
|
||||
if get_total_num_windows_open() < required_num_windows then
|
||||
return
|
||||
end
|
||||
|
||||
local current_window = vim.api.nvim_get_current_win()
|
||||
if not current_window then
|
||||
return
|
||||
end
|
||||
|
||||
if is_floating_window(current_window) then
|
||||
return
|
||||
end
|
||||
|
||||
if is_current_window_at_edge(dir_char) then
|
||||
return
|
||||
end
|
||||
|
||||
if not is_window_resizable(current_window) then
|
||||
return
|
||||
end
|
||||
|
||||
local adjacent_window = get_adjacent_window(dir_char)
|
||||
if not is_window_resizable(adjacent_window) then
|
||||
return
|
||||
end
|
||||
|
||||
swap_buffer_between_windows(current_window, adjacent_window)
|
||||
vim.api.nvim_set_current_win(adjacent_window)
|
||||
|
||||
assert(vim.api.nvim_get_current_win() == adjacent_window, "Failed to swap windows")
|
||||
end
|
||||
|
||||
local function resize_window(window, dir_char)
|
||||
assert(is_in_resizing_mode, "Not in resizing mode")
|
||||
assert(window, "Invalid window")
|
||||
assert(dir_char == "h" or dir_char == "j" or dir_char == "k" or dir_char == "l", "Invalid direction character")
|
||||
|
||||
local default_resize_units = 5
|
||||
local tot_resize_units = default_resize_units * vim.v.count1
|
||||
if dir_char == "h" then
|
||||
vim.cmd("vertical resize -" .. tot_resize_units)
|
||||
elseif dir_char == "j" then
|
||||
vim.cmd("resize " .. tot_resize_units)
|
||||
elseif dir_char == "k" then
|
||||
vim.cmd("resize -" .. tot_resize_units)
|
||||
elseif dir_char == "l" then
|
||||
vim.cmd("vertical resize " .. tot_resize_units)
|
||||
end
|
||||
end
|
||||
|
||||
local function exit_resizing_mode()
|
||||
assert(is_in_resizing_mode, "Not in resizing mode")
|
||||
|
||||
is_in_resizing_mode = false
|
||||
utils.broadcast_event(on_resize_mode_exit_event)
|
||||
|
||||
assert(not is_in_resizing_mode, "Failed to exit resizing mode")
|
||||
end
|
||||
|
||||
local function enter_resizing_mode()
|
||||
assert(not is_in_resizing_mode, "Already in resizing mode")
|
||||
|
||||
local current_window = vim.api.nvim_get_current_win()
|
||||
if not current_window then
|
||||
return
|
||||
end
|
||||
|
||||
if is_floating_window(current_window) then
|
||||
return
|
||||
end
|
||||
|
||||
if not is_window_resizable(current_window) then
|
||||
return
|
||||
end
|
||||
|
||||
is_in_resizing_mode = true
|
||||
utils.broadcast_event(on_resize_mode_enter_event)
|
||||
|
||||
assert(is_in_resizing_mode, "Failed to enter resizing mode")
|
||||
end
|
||||
|
||||
function M.autosize_windows()
|
||||
vim.api.nvim_command("wincmd =")
|
||||
end
|
||||
|
||||
function M.is_in_resizing_mode()
|
||||
return is_in_resizing_mode
|
||||
end
|
||||
|
||||
function M.setup()
|
||||
local resizing_mode_keymaps = {
|
||||
n = {
|
||||
["<Left>"] = {
|
||||
cmd = function() resize_window(vim.api.nvim_get_current_win(), "h") end
|
||||
},
|
||||
["<Down>"] = {
|
||||
cmd = function() resize_window(vim.api.nvim_get_current_win(), "j") end
|
||||
},
|
||||
["<Up>"] = {
|
||||
cmd = function() resize_window(vim.api.nvim_get_current_win(), "k") end
|
||||
},
|
||||
["<Right>"] = {
|
||||
cmd = function() resize_window(vim.api.nvim_get_current_win(), "l") end
|
||||
},
|
||||
["<Esc>"] = {
|
||||
cmd = function() exit_resizing_mode() end
|
||||
},
|
||||
["<Enter>"] = {
|
||||
cmd = function() exit_resizing_mode() end
|
||||
},
|
||||
}
|
||||
}
|
||||
local enter_resizing_mode_keymaps = {
|
||||
n = {
|
||||
["<C- >"] = {
|
||||
cmd = function() enter_resizing_mode() end
|
||||
}
|
||||
},
|
||||
}
|
||||
local window_shifting_keymaps = {
|
||||
n = {
|
||||
["<C-S-Left>"] = {
|
||||
cmd = function()
|
||||
swap_window("h")
|
||||
end
|
||||
},
|
||||
["<C-S-Down>"] = {
|
||||
cmd = function()
|
||||
swap_window("j")
|
||||
end
|
||||
},
|
||||
["<C-S-Up>"] = {
|
||||
cmd = function()
|
||||
swap_window("k")
|
||||
end
|
||||
},
|
||||
["<C-S-Right>"] = {
|
||||
cmd = function()
|
||||
swap_window("l")
|
||||
end
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
utils.add_keymaps({
|
||||
window_shifting_keymaps,
|
||||
enter_resizing_mode_keymaps
|
||||
})
|
||||
|
||||
local function on_resize_mode_enter()
|
||||
utils.remove_keymaps(enter_resizing_mode_keymaps)
|
||||
utils.add_keymaps(resizing_mode_keymaps)
|
||||
end
|
||||
|
||||
local function on_resize_mode_exit()
|
||||
utils.remove_keymaps(resizing_mode_keymaps)
|
||||
utils.add_keymaps(enter_resizing_mode_keymaps)
|
||||
end
|
||||
|
||||
local window_management_augroup = "WindowManagementEvents"
|
||||
vim.api.nvim_create_augroup(window_management_augroup, { clear = true })
|
||||
utils.create_user_event_cb(on_resize_mode_enter_event, on_resize_mode_enter, window_management_augroup)
|
||||
utils.create_user_event_cb(on_resize_mode_exit_event, on_resize_mode_exit, window_management_augroup)
|
||||
end
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue