From d0ba7f74b12b6b54be8f7ff59f1bf703299e90b9 Mon Sep 17 00:00:00 2001 From: James Bulman Date: Wed, 24 Sep 2025 18:59:41 +0100 Subject: [PATCH] Added window handling functions Added scratch buffer on startup Attempt to wrangle windows so that at most only 3 are open via splitting Project wide (file only) search Properly layout "help" windows so they are at the bottom --- config/nvim/init.lua | 102 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/config/nvim/init.lua b/config/nvim/init.lua index a666e7d..96724b1 100644 --- a/config/nvim/init.lua +++ b/config/nvim/init.lua @@ -75,7 +75,99 @@ local function TrimBuffer() vim.fn.winrestview(view) end +local function MakeScratch() + local bufnr = vim.api.nvim_create_buf(true, true) + + vim.api.nvim_buf_set_option(bufnr, "buftype", "nofile") + vim.api.nvim_buf_set_option(bufnr, "bufhidden", "hide") + vim.api.nvim_buf_set_option(bufnr, "swapfile", false) + vim.api.nvim_buf_set_option(bufnr, "modified", false) + + vim.api.nvim_buf_set_name(bufnr, "scratch") + + vim.api.nvim_buf_set_text(bufnr, 0, 0, 0, -1, { "-*- Scratch Buffer -*-" }) + + -- @Hack: There isn't really any way to get the fullscreen size, 150 greater than the + -- half-screen width on all of my devices as we don't want to split in that case + if vim.o.columns > 150 then + vim.cmd(string.format("vsplit #%d", bufnr)) + vim.cmd("wincmd p") + end +end + +-- Windowing + +local _is_help = { help = true, man = true, qf = true } + +function ManageSplit() + local windows = vim.api.nvim_tabpage_list_wins(0) + local bufnr = vim.api.nvim_win_get_buf(windows[#windows]) + local filetype = vim.bo[bufnr].filetype + + local target_count = _is_help[filetype] and 3 or 2 + + if #windows == target_count then + -- We already have the target number of windows open so we should close our split window, + -- always close 2 because that is the right-most split. The third window if it exists is + -- the bottom most window and is a "help" window + vim.api.nvim_win_close(windows[2], false) + else + -- We have less than the required windows open so split the first window, we open the + -- "scratch" buffer in this new window, if it is still open. Otherwise the same buffer in + -- the first window is opened. + local scratch = vim.fn.bufnr("scratch") + local first = vim.api.nvim_win_get_buf(windows[1]) + + bufnr = vim.api.nvim_buf_is_loaded(scratch) and scratch or first + vim.api.nvim_open_win(bufnr, true, { split = "right", win = windows[1] }) + end +end + +local function ProjectSearch() + local input = vim.fn.input("Search: ") + + if input and input ~= "" then + vim.cmd("silent lgrep! \"" .. input .. "\" **") + vim.cmd("lopen | lfirst | wincmd p") + end +end + +local function ExpandHelp(a) + local winid = vim.api.nvim_get_current_win() + local filetype = vim.bo[vim.api.nvim_win_get_buf(winid)].filetype + local height = a.event == "WinEnter" and math.floor(0.8 * vim.o.lines) or 5 + + if _is_help[filetype] then + vim.api.nvim_win_set_height(winid, height) + end +end + +local function LayoutHelp(a) + if _is_help[vim.bo.filetype] then + local winid = vim.api.nvim_get_current_win() + local windows = vim.api.nvim_tabpage_list_wins(0) + + -- We need to close other "help" windows that may be open so search through the open + -- windows. There *should* only ever be 3 windows open if my window handling is working + -- correctly + for _, w in ipairs(windows) do + if w ~= winid then + local bufnr = vim.api.nvim_win_get_buf(w) + if _is_help[vim.bo[bufnr].filetype] then + vim.api.nvim_win_close(wi.winid, true) + end + end + end + + -- Force the new window to the bottom and expand it to be 80% of the height + vim.cmd("wincmd J") + vim.cmd(string.format("resize %d", math.floor(0.8 * vim.o.lines))) + end +end + +-------------------------------------------------------------------------------- -- Input mappings +-------------------------------------------------------------------------------- vim.g.mapleader = " " @@ -91,10 +183,18 @@ MAP("v", "K", "{") MAP("n", "k", ":Man") MAP("i", "", "<<") MAP("i", "", BufferComplete, { expr = true }) +MAP("n", "s", ManageSplit) +MAP("n", "f", ProjectSearch) +-------------------------------------------------------------------------------- -- Autocommands +-------------------------------------------------------------------------------- AUTOCMD('BufEnter', { command = "let b:man_default_sects=\"2,3\"", pattern = "*.c" }) AUTOCMD('BufReadPost', { command = "setlocal nornu", pattern = "quickfix" }) -AUTOCMD('BufWritePre', { callback = TrimBuffer, pattern = "*" }) +AUTOCMD('BufWritePre', { callback = TrimBuffer, pattern = "*" }) +AUTOCMD('VimEnter', { callback = MakeScratch, pattern = "*" }) +AUTOCMD('BufWinEnter', { callback = LayoutHelp, pattern = "*" }) +AUTOCMD('WinEnter', { callback = ExpandHelp, pattern = "*" }) +AUTOCMD('WinLeave', { callback = ExpandHelp, pattern = "*" })