diff --git a/config/nvim/init.lua b/config/nvim/init.lua index d287b21..445ebf7 100644 --- a/config/nvim/init.lua +++ b/config/nvim/init.lua @@ -1,2 +1,13 @@ -require 'fschauen' +vim.g.mapleader = ' ' +vim.g.maplocalleader = ',' + +require 'fschauen.setup.globals' +require 'fschauen.setup.options' +require('fschauen.keymap').setup() +require 'fschauen.setup.autocmd' +require 'fschauen.setup.filetype' +require 'fschauen.setup.diagnostic' +require 'fschauen.setup.lazy' + +require('fschauen').colorscheme('gruvbox') diff --git a/config/nvim/lua/fschauen/diagnostic.lua b/config/nvim/lua/fschauen/diagnostic.lua new file mode 100644 index 0000000..2f03ceb --- /dev/null +++ b/config/nvim/lua/fschauen/diagnostic.lua @@ -0,0 +1,45 @@ +M = {} + +local diag_opts = { + wrap = false, -- don't wrap around the begin/end of file +} + +---Move to the next diagnostic. +---@param opts table\nil: options passed along to `vim.diagnostic.goto_next`. +M.goto_next= function(opts) + vim.diagnostic.goto_next(vim.tbl_extend('keep', opts or {}, diag_opts)) + vim.cmd 'normal zz' +end + +---Move to the previous diagnostic. +---@param opts table|nil: options passed along to `vim.diagnostic.goto_prev`. +M.goto_prev= function(opts) + vim.diagnostic.goto_prev(vim.tbl_extend('keep', opts or {}, diag_opts)) + vim.cmd 'normal zz' +end + +---Show diagnostics in a floating window. +---@param opts table|nil: options passed along to `vim.diagnostic.open_float`. +M.open_float= function(opts) + vim.diagnostic.open_float(opts) +end + +---Toggle diagnostics in the given buffer. +---@param bufnr integer|nil: Buffer number (0 for current buffer, nil for all buffers. +M.toggle = function(bufnr) + bufnr = bufnr or 0 + if vim.diagnostic.is_disabled(bufnr) then + vim.diagnostic.enable(bufnr) + else + vim.diagnostic.disable(bufnr) + end +end + +---Hide currently displayed diagnostics. +---@param bufnr integer|nil: Buffer number (0 for current buffer, nil for all buffers. +M.hide = function(bufnr) + vim.diagnostic.hide(nil, bufnr or 0) +end + +return M + diff --git a/config/nvim/lua/fschauen/disable_builtin.lua b/config/nvim/lua/fschauen/disable_builtin.lua deleted file mode 100644 index 133eb3f..0000000 --- a/config/nvim/lua/fschauen/disable_builtin.lua +++ /dev/null @@ -1,17 +0,0 @@ -vim.g.loaded_gzip = 1 -vim.g.loaded_zip = 1 -vim.g.loaded_zipPlugin = 1 -vim.g.loaded_tar = 1 -vim.g.loaded_tarPlugin = 1 -vim.g.loaded_getscript = 1 -vim.g.loaded_getscriptPlugin = 1 -vim.g.loaded_vimball = 1 -vim.g.loaded_vimballPlugin = 1 -vim.g.loaded_2html_plugin = 1 --- vim.g.loaded_matchit = 1 -vim.g.loaded_matchparen = 1 -vim.g.loaded_logiPat = 1 -vim.g.loaded_rrhelper = 1 -vim.g.loaded_netrw = 1 -vim.g.loaded_netrwPlugin = 1 -vim.g.loaded_netrwSettings = 1 diff --git a/config/nvim/lua/fschauen/init.lua b/config/nvim/lua/fschauen/init.lua index a353fe5..5b05146 100644 --- a/config/nvim/lua/fschauen/init.lua +++ b/config/nvim/lua/fschauen/init.lua @@ -1,14 +1,55 @@ -vim.g.mapleader = ' ' -vim.g.maplocalleader = ',' +local M = {} -require 'fschauen.disable_builtin' -require 'fschauen.globals' -require 'fschauen.options' -require 'fschauen.keymap' -require 'fschauen.autocmds' -require 'fschauen.filetypes' -require 'fschauen.diagnostics' -require 'fschauen.lazy' +--- Flip function arguments. +--- +--- flip(f)(a, b) == f(b, a) +--- +---@param f function: function to flip. +---@return function: function that takes `f`'s arguments flipped. +M.flip = function(f) + return function(a, b) + return f(b, a) + end +end -require('fschauen.util').set_colorscheme('gruvbox') +--- Concatenate lists. +--- +--- extend({'a', 'b'}, {'c', 'd'}) == {'a', 'b', 'c', 'd'} +--- extend({1, 2}, {3, 4}, {5, 6}) == {1, 2, 3, 4, 5, 6} +--- +---@param ... table: lists to concatenate. +---@return table: concatenation of arguments. +M.concat = function(...) + local result = {} + for _, tbl in ipairs {...} do + for _, v in pairs(tbl) do + result[#result+1] = v + end + end + return result +end + +--- Partial function application. +--- +--- partial(f, x)(...) == f(x, ...) +--- partial(f, x, y)(...) == f(x, y, ...) +--- +---@param f function: function to partially apply. +---@param ... any: arguments to bind. +---@return function: partially applied function. +M.partial = function(f, ...) + local argv = {...} + return function(...) + return f(unpack(M.concat(argv, {...}))) + end +end + +M.colorscheme = function(name) + vim.cmd('silent! colorscheme ' .. name) + if vim.v.errmsg ~= '' then + vim.notify(string.format('Colorscheme %s not found!', name), vim.log.levels.WARN) + end +end + +return M diff --git a/config/nvim/lua/fschauen/keymap.lua b/config/nvim/lua/fschauen/keymap.lua index 7950c5c..3e0b33d 100644 --- a/config/nvim/lua/fschauen/keymap.lua +++ b/config/nvim/lua/fschauen/keymap.lua @@ -1,84 +1,6 @@ -local util = require('fschauen.util') -local partial = util.partial -local nmap = partial(vim.keymap.set, 'n') -local imap = partial(vim.keymap.set, 'i') -local vmap = partial(vim.keymap.set, 'v') -local cmap = partial(vim.keymap.set, 'c') -local tmap = partial(vim.keymap.set, 't') +local diagnostic = require 'fschauen.diagnostic' +local window = require 'fschauen.window' --- better navigation for wrapped lines -nmap('j', 'gj') -nmap('k', 'gk') - --- maintain cursor position when joining lines -nmap('J', 'mzJ`z') - --- retain selection when making changes in visual mode -vmap( '', 'gv') -vmap( '', 'gv') -vmap('g', 'ggv') -vmap('g', 'ggv') -vmap('>', '>gv') -vmap('<', '<gv') - --- place destination of important movements in the center of the screen -nmap('n', 'nzzzv') -nmap('N', 'Nzzzv') -nmap('', 'zzzv') -nmap('', 'zzzv') - --- easier window navigation -nmap('', 'j') -nmap('', 'k') -nmap('', 'h') -nmap('', 'l') - --- window resizing -nmap('', util.win_resize_up(2), { desc = 'Resize window upward' }) -nmap('', util.win_resize_down(2), { desc = 'Resize window downward' }) -nmap('', util.win_resize_left(2), { desc = 'Resize window leftward' }) -nmap('', util.win_resize_right(2), { desc = 'Resize window rightward' }) - --- easy tab navigation -nmap('', 'tabnext', { silent = true }) -nmap('', 'tabprevious', { silent = true }) - --- move lines up and down -nmap('', [[:move .+1==]], { silent = true }) -nmap('', [[:move .-2==]], { silent = true }) -vmap('', [[:move '>+1gv=gv]], { silent = true }) -vmap('', [[:move '<-2gv=gv]], { silent = true }) -imap('', [[:move .+1==gi]], { silent = true }) -imap('', [[:move .-2==gi]], { silent = true }) - --- move to begin/end of line in insert mode -imap('', '^') -imap('', '$') - --- move to begin of line in command mode ( moves to end by default) -cmap('', '') - --- navigate items in quickfix and location lists -nmap('j', 'cnextzz', { silent = true }) -nmap('k', 'cpreviouszz', { silent = true }) -nmap('j', 'lnextzz', { silent = true }) -nmap('k', 'lpreviouszz', { silent = true }) - --- navigate diagnostics -nmap('dj', require('fschauen.util').goto_next_diagnostic) -nmap('dk', require('fschauen.util').goto_prev_diagnostic) -nmap('dd', require('fschauen.util').toggle_diagnostics) -nmap('do', require('fschauen.util').open_float_diagnostic) -nmap('dh', require('fschauen.util').hide_diagnostics) - --- toggle quickfix and loclist -nmap('ll', util.toggle_quickfix, { desc = 'Toggle quickfix' } ) -nmap('ll', util.toggle_loclist, { desc = 'Toggle loclist' } ) - --- quickly open lazy.nvim plugin manager -nmap('L', 'Lazy') - --- toggle options local toggle_number = function() vim.wo.number = not vim.wo.number vim.wo.relativenumber = false @@ -89,23 +11,113 @@ local toggle_relativenumber = function() vim.wo.number = vim.wo.relativenumber or vim.wo.number end -nmap('sn', toggle_number) -nmap('sr', toggle_relativenumber) -nmap('sl', 'set list! | set list?', { silent = true }) -nmap('sw', 'set wrap! | set wrap?', { silent = true }) -nmap('ss', 'set spell! | set spell?', { silent = true }) +M = {} --- quickly change background -nmap('bg', [[let &background = &background ==? 'light' ? 'dark' : 'light']]) +local base = { + -- better navigation for wrapped lines + { 'j', 'gj' }, + { 'k', 'gk' }, --- disable highlight until next search -nmap('', 'nohlsearch') -imap('', 'nohlsearch') + -- maintain cursor position when joining lines + { 'J', 'mzJ`z' }, --- more convenient way of entering normal mode from terminal mode -tmap([[]], [[]]) + -- retain selection when making changes in visual mode + { '', 'gv', 'v' }, + { '', 'gv', 'v' }, + { 'g', 'ggv', 'v' }, + { 'g', 'ggv', 'v' }, + { '>', '>gv', 'v' }, + { '<', '<gv', 'v' }, --- recall older/recent command-line from history -cmap('', '') -cmap('', '') + -- place destination of important movements in the center of the screen + { 'n', 'nzzzv' }, + { 'N', 'Nzzzv' }, + { '', 'zzzv' }, + { '', 'zzzv' }, + + -- easier window navigation + { '', 'j' }, + { '', 'k' }, + { '', 'h' }, + { '', 'l' }, + + -- window resizing + { '', window.resize_up(2), desc = 'Resize window upward' }, + { '', window.resize_down(2), desc = 'Resize window downward' }, + { '', window.resize_left(2), desc = 'Resize window leftward' }, + { '', window.resize_right(2), desc = 'Resize window rightward' }, + + -- easy tab navigation + { '', 'tabnext' }, + { '', 'tabprevious' }, + + -- move lines up and down + { '', [[:move .+1==]] }, + { '', [[:move .-2==]] }, + { '', [[:move '>+1gv=gv]], 'v' }, + { '', [[:move '<-2gv=gv]], 'v' }, + { '', [[:move .+1==gi]], 'i' }, + { '', [[:move .-2==gi]], 'i' }, + + -- move to begin/end of line in insert mode + { '', '^', 'i' }, + { '', '$', 'i' }, + + -- move to begin of line in command mode ( moves to end by default) + { '', '', 'c' }, + + -- navigate items in quickfix and location lists + { 'j', 'cnextzz' }, + { 'k', 'cpreviouszz' }, + { 'j', 'lnextzz' }, + { 'k', 'lpreviouszz' }, + + -- navigate diagnostics + { 'dj', diagnostic.goto_next }, + { 'dk', diagnostic.goto_prev }, + { 'dd', diagnostic.toggle }, + { 'do', diagnostic.open_float }, + { 'dh', diagnostic.hide }, + + -- toggle quickfix and loclist + { 'll', window.toggle_quickfix, desc = 'Toggle quickfix' }, + { 'll', window.toggle_loclist, desc = 'Toggle loclist' }, + + -- quickly open lazy.nvim plugin manager + { 'L', 'Lazy' }, + + -- toggle options + { 'sn', toggle_number }, + { 'sr', toggle_relativenumber }, + { 'sl', 'set list! | set list?' }, + { 'sw', 'set wrap! | set wrap?' }, + { 'ss', 'set spell! | set spell?' }, + + -- quickly change background + { 'bg', [[let &background = &background ==? 'light' ? 'dark' : 'light']] }, + + -- disable highlight until next search + { 'h', 'nohlsearch' }, + + -- more convenient way of entering normal mode from terminal mode + { [[]], [[]], 't' }, + + -- recall older/recent command-line from history + { '', '', 'c' }, + { '', '', 'c' }, +} + +local keymap_set = vim.keymap.set +local map = function(opts) + local lhs, rhs, mode = opts[1], opts[2], opts[3] or 'n' + opts[1], opts[2], opts[3], opts.mode = nil, nil, nil, nil + opts.silent = opts.silent ~= false + keymap_set(mode, lhs, rhs, opts) +end + +M.setup = function() + vim.tbl_map(map, base) +end + +return M diff --git a/config/nvim/lua/fschauen/plugins/completion.lua b/config/nvim/lua/fschauen/plugins/completion.lua index 34dd6cd..5efa4a9 100644 --- a/config/nvim/lua/fschauen/plugins/completion.lua +++ b/config/nvim/lua/fschauen/plugins/completion.lua @@ -1,9 +1,9 @@ local config = function() - local cmp = require('cmp') + local cmp = require 'cmp' local map = cmp.mapping - local flip = require('fschauen.util').flip - local partial = require('fschauen.util').partial + local fs = require 'fschauen' + local flip, partial = fs.flip, fs.partial -- assign('i', { key = func, ... }) == { key = { i = func }, ... } -- assign({'i', 'c'}, { key = func, ... }) == { key = { i = func, c = func }, ...} diff --git a/config/nvim/lua/fschauen/plugins/lualine.lua b/config/nvim/lua/fschauen/plugins/lualine.lua index d494305..3c76d5f 100644 --- a/config/nvim/lua/fschauen/plugins/lualine.lua +++ b/config/nvim/lua/fschauen/plugins/lualine.lua @@ -56,8 +56,7 @@ local config = function() local window_is_wide = window_is_at_least(80) local window_is_medium = window_is_at_least(50) - local concat = require('fschauen.util').concat - + local fs = require 'fschauen' local my = { paste = { function() return '' end, @@ -93,7 +92,7 @@ local config = function() status = { function() - local flags = concat( + local flags = fs.concat( vim.bo.modified and {'+'} or {}, (vim.bo.readonly or not vim.bo.modifiable) and {'RO'} or {}) return vim.fn.join(flags, ' ') @@ -142,8 +141,8 @@ local config = function() local active_sections = vim.tbl_extend('force', inactive_sections, { - lualine_a = concat({ my.paste, my.mode }, inactive_sections.lualine_a), - lualine_x = concat({ 'diagnostics' }, inactive_sections.lualine_x), + lualine_a = fs.concat({ my.paste, my.mode }, inactive_sections.lualine_a), + lualine_x = fs.concat({ 'diagnostics' }, inactive_sections.lualine_x), }) require('lualine').setup { diff --git a/config/nvim/lua/fschauen/autocmds.lua b/config/nvim/lua/fschauen/setup/autocmd.lua similarity index 100% rename from config/nvim/lua/fschauen/autocmds.lua rename to config/nvim/lua/fschauen/setup/autocmd.lua diff --git a/config/nvim/lua/fschauen/diagnostics.lua b/config/nvim/lua/fschauen/setup/diagnostic.lua similarity index 100% rename from config/nvim/lua/fschauen/diagnostics.lua rename to config/nvim/lua/fschauen/setup/diagnostic.lua diff --git a/config/nvim/lua/fschauen/filetypes.lua b/config/nvim/lua/fschauen/setup/filetype.lua similarity index 100% rename from config/nvim/lua/fschauen/filetypes.lua rename to config/nvim/lua/fschauen/setup/filetype.lua diff --git a/config/nvim/lua/fschauen/globals.lua b/config/nvim/lua/fschauen/setup/globals.lua similarity index 100% rename from config/nvim/lua/fschauen/globals.lua rename to config/nvim/lua/fschauen/setup/globals.lua diff --git a/config/nvim/lua/fschauen/lazy.lua b/config/nvim/lua/fschauen/setup/lazy.lua similarity index 71% rename from config/nvim/lua/fschauen/lazy.lua rename to config/nvim/lua/fschauen/setup/lazy.lua index 4f45010..40049a7 100644 --- a/config/nvim/lua/fschauen/lazy.lua +++ b/config/nvim/lua/fschauen/setup/lazy.lua @@ -23,6 +23,19 @@ if lazy then }, ui = { border = 'rounded', + performance = { + rtp = { + disabled_plugins = { + 'gzip', + 'matchit', + 'matchparen', + 'netrwPlugin', + 'tarPlugin', + 'tohtml', + 'tutor', + 'zipPlugin', + }, + }, }, } else diff --git a/config/nvim/lua/fschauen/options.lua b/config/nvim/lua/fschauen/setup/options.lua similarity index 100% rename from config/nvim/lua/fschauen/options.lua rename to config/nvim/lua/fschauen/setup/options.lua diff --git a/config/nvim/lua/fschauen/telescope.lua b/config/nvim/lua/fschauen/telescope.lua index 23a1724..b57ff3f 100644 --- a/config/nvim/lua/fschauen/telescope.lua +++ b/config/nvim/lua/fschauen/telescope.lua @@ -55,6 +55,28 @@ local config_builtin = function(picker, opts) end end +---Preserve register contents over function call. +---@param reg string: register to save, must be a valid register name. +---@param func function: function that may freely clobber the register. +---@return any: return value of calling `func`. +local with_saved_register = function(reg, func) + local saved = vim.fn.getreg(reg) + local result = func() + vim.fn.setreg(reg, saved) + return result +end + +---Get selected text. +---@return string: selected text, or work under cursor if not in visual mode. +local get_selected_text = function() + if vim.fn.mode() ~= 'v' then return vim.fn.expand '' end + + return with_saved_register('v', function() + vim.cmd [[noautocmd sil norm "vy]] + return vim.fn.getreg 'v' + end) +end + M.pickers = setmetatable({ all_files = config_builtin('find_files', { hidden = true, @@ -73,7 +95,7 @@ M.pickers = setmetatable({ }), selection = function(_) return function() - local text = require('fschauen.util').get_selected_text() + local text = get_selected_text() builtin().grep_string { prompt_title = string.format('  Grep: %s ', text), search = text, diff --git a/config/nvim/lua/fschauen/util.lua b/config/nvim/lua/fschauen/util.lua deleted file mode 100644 index a9e0c5f..0000000 --- a/config/nvim/lua/fschauen/util.lua +++ /dev/null @@ -1,197 +0,0 @@ -local M = {} - ---- Flip function arguments. ---- ---- flip(f)(a, b) == f(b, a) ---- ----@param f function: function to flip. ----@return function: function that takes `f`'s arguments flipped. -M.flip = function(f) - return function(a, b) - return f(b, a) - end -end - ---- Concatenate lists. ---- ---- extend({'a', 'b'}, {'c', 'd'}) == {'a', 'b', 'c', 'd'} ---- extend({1, 2}, {3, 4}, {5, 6}) == {1, 2, 3, 4, 5, 6} ---- ----@param ... table: lists to concatenate. ----@return table: concatenation of arguments. -M.concat = function(...) - local result = {} - for _, tbl in ipairs {...} do - for _, v in pairs(tbl) do - result[#result+1] = v - end - end - return result -end - ---- Partial function application. ---- ---- partial(f, x)(...) == f(x, ...) ---- partial(f, x, y)(...) == f(x, y, ...) ---- ----@param f function: function to partially apply. ----@param ... any: arguments to bind. ----@return function: partially applied function. -M.partial = function(f, ...) - local argv = {...} - return function(...) - return f(unpack(M.concat(argv, {...}))) - end -end - ---- Delayed function evaluation. ----@param f function: function whose evaluation will be delayed. ----@param ... any: arguments to `f`. ----@return function: a new function that calls f with provided arguments. -M.thunk = function(f, ...) - local args = {...} - return function() - return f(unpack(args)) - end -end - ---- Preserve register contents over function call. ----@param reg string: register to save, must be a valid register name. ----@param func function: function that may freely clobber the register. ----@return any: return value of calling `func`. -M.with_saved_register = function(reg, func) - local saved = vim.fn.getreg(reg) - local result = func() - vim.fn.setreg(reg, saved) - return result -end - ---- Get selected text. ----@return string: selected text, or work under cursor if not in visual mode. -M.get_selected_text = function() - if vim.fn.mode() ~= 'v' then return vim.fn.expand '' end - - return M.with_saved_register('v', function() - vim.cmd [[noautocmd sil norm "vy]] - return vim.fn.getreg 'v' - end) -end - -local diag_opts = { - wrap = false, -- don't wrap around the begin/end of file - -- float = { - -- border = 'rounded' -- enable border for the floating window - -- }, -} - ---- Move to the next diagnostic. ----@param opts table: options passed along to `vim.diagnostic.goto_next`. -M.goto_next_diagnostic = function(opts) - vim.diagnostic.goto_next(vim.tbl_extend('keep', opts or {}, diag_opts)) - vim.cmd 'normal zz' -end - ---- Move to the previous diagnostic. ----@param opts table: options passed along to `vim.diagnostic.goto_prev`. -M.goto_prev_diagnostic = function(opts) - vim.diagnostic.goto_prev(vim.tbl_extend('keep', opts or {}, diag_opts)) - vim.cmd 'normal zz' -end - -M.open_float_diagnostic = function(opts) - vim.diagnostic.open_float(opts) -end - -M.toggle_diagnostics = function(bufnr) - bufnr = bufnr or 0 - if vim.diagnostic.is_disabled(bufnr) then - vim.diagnostic.enable(bufnr) - else - vim.diagnostic.disable(bufnr) - end -end - -M.hide_diagnostics = function(bufnr) - vim.diagnostic.hide(nil, bufnr or 0) -end - ---- Whether the current window is the last in a given direction. ----@param direction string: one of 'h', 'j', 'k', or 'l' -local win_is_last = function(direction) - local current = vim.api.nvim_get_current_win() - vim.cmd('wincmd ' .. direction) - local next = vim.api.nvim_get_current_win() - - local is_last = current == next - if not is_last then vim.cmd('wincmd p') end - - return is_last -end - ---- Resize current window in a given direction. ----@param dir string: one of 'h', 'j', 'k', or 'l' ----@param size integer: how much to resize -local win_resize = function(dir, size) - if dir ~= 'h' and dir ~= 'j' and dir ~= 'k' and dir ~= 'l' then return end - - size = math.abs(size) - local is_height = dir == 'j' or dir == 'k' - local is_positive = dir == 'j' or dir == 'l' - - if win_is_last(is_height and 'j' or 'l') then - is_positive = not is_positive - end - - local delta = string.format('%s%d', is_positive and '+' or '-', size) - local prefix = is_height and '' or 'vertical ' - vim.cmd(prefix .. 'resize ' .. delta .. '') -end - ---- Resize current window upwards. ----@param size integer: how much to resize -M.win_resize_up = function(size) return M.thunk(win_resize, 'k', size) end - ---- Resize current window downwards. ----@param size integer: how much to resize -M.win_resize_down = function(size) return M.thunk(win_resize, 'j', size) end - ---- Resize current window leftwards. ----@param size integer: how much to resize -M.win_resize_left = function(size) return M.thunk(win_resize, 'h', size) end - ---- Resize current window rightwards. ----@param size integer: how much to resize -M.win_resize_right = function(size) return M.thunk(win_resize, 'l', size) end - ---- Toggle quickfix (or location) list. ----@param qf string: 'c' for quickfix, 'l' for location list -local toggle_qf_list = function(qf) - local l = qf == 'l' and 1 or 0 - local is_qf = function(win) return win.quickfix == 1 and win.loclist == l end - local is_open = not vim.tbl_isempty(vim.tbl_filter(is_qf, vim.fn.getwininfo())) - if is_open then - vim.cmd(qf .. 'close') - else - local ok = pcall(function(c) vim.cmd(c) end, qf .. 'open') - if not ok and qf == 'l' then - vim.notify('No location list', vim.log.levels.WARN) - end - end -end - ---- Toggle quickfix list. -M.toggle_quickfix = function() toggle_qf_list('c') end - ---- Toggle location list. -M.toggle_loclist = function() toggle_qf_list('l') end - - -M.set_colorscheme = function(name) - vim.cmd('silent! colorscheme ' .. name) - if vim.v.errmsg ~= '' then - vim.notify(string.format('Colorscheme %s not found!', name), vim.log.levels.WARN) - end -end - -return M - diff --git a/config/nvim/lua/fschauen/window.lua b/config/nvim/lua/fschauen/window.lua new file mode 100644 index 0000000..8313ff3 --- /dev/null +++ b/config/nvim/lua/fschauen/window.lua @@ -0,0 +1,94 @@ +M = {} + +---Whether the current window is the last in a given direction. +---@param direction string: one of 'h', 'j', 'k', or 'l' +local is_last = function(direction) + local current = vim.api.nvim_get_current_win() + vim.cmd('wincmd ' .. direction) + local next = vim.api.nvim_get_current_win() + + local is_last = current == next + if not is_last then vim.cmd('wincmd p') end + + return is_last +end + +---Resize current window in a given direction. +---@param dir string: one of 'h', 'j', 'k', or 'l' +---@param size integer: how much to resize +local resize = function(dir, size) + if dir ~= 'h' and dir ~= 'j' and dir ~= 'k' and dir ~= 'l' then return end + + size = math.abs(size) + local is_height = dir == 'j' or dir == 'k' + local is_positive = dir == 'j' or dir == 'l' + + if is_last(is_height and 'j' or 'l') then + is_positive = not is_positive + end + + local delta = string.format('%s%d', is_positive and '+' or '-', size) + local prefix = is_height and '' or 'vertical ' + vim.cmd(prefix .. 'resize ' .. delta .. '') +end + +---Resize current window upwards. +---@param size integer: how much to resize +M.resize_up = function(size) + return function() + resize('k', size) + end +end + +---Resize current window downwards. +---@param size integer: how much to resize +M.resize_down = function(size) + return function() + resize('j', size) + end +end + +---Resize current window leftwards. +---@param size integer: how much to resize +M.resize_left = function(size) + return function() + resize('h', size) + end +end + +---Resize current window rightwards. +---@param size integer: how much to resize +M.resize_right = function(size) + return function() + resize('l', size) + end +end + +---Toggle quickfix (or location) list. +---@param qf string: 'c' for quickfix, 'l' for location list +local toggle_list = function(qf) + local l = qf == 'l' and 1 or 0 + local is_qf = function(win) return win.quickfix == 1 and win.loclist == l end + local is_open = not vim.tbl_isempty(vim.tbl_filter(is_qf, vim.fn.getwininfo())) + if is_open then + vim.cmd(qf .. 'close') + else + local ok = pcall(function(c) vim.cmd(c) end, qf .. 'open') + if not ok and qf == 'l' then + vim.notify('No location list', vim.log.levels.WARN) + end + end +end + +---Toggle quickfix list. +M.toggle_quickfix = function() + toggle_list('c') +end + +---Toggle location list. +M.toggle_loclist = function() + toggle_list('l') +end + +return M +