From 855732f3c166392f392a989d08b753f82a3e629e Mon Sep 17 00:00:00 2001 From: Riyyi Date: Fri, 11 Apr 2025 22:57:42 +0200 Subject: [PATCH] Neovim: Finish buffer navigation, add keybinds --- .config/nvim/lazy-lock.json | 54 +++--- .config/nvim/lua/core.lua | 2 + .config/nvim/lua/core/autocommands.lua | 12 +- .config/nvim/lua/core/buffers.lua | 238 +++++++++++++++++++------ .config/nvim/lua/core/commands.lua | 18 ++ .config/nvim/lua/core/filetypes.lua | 5 + .config/nvim/lua/core/functions.lua | 16 ++ .config/nvim/lua/keybinds.lua | 14 ++ 8 files changed, 277 insertions(+), 82 deletions(-) create mode 100644 .config/nvim/lua/core/commands.lua create mode 100644 .config/nvim/lua/core/filetypes.lua diff --git a/.config/nvim/lazy-lock.json b/.config/nvim/lazy-lock.json index c58aeed..4a20e3a 100644 --- a/.config/nvim/lazy-lock.json +++ b/.config/nvim/lazy-lock.json @@ -1,42 +1,42 @@ { "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, - "LuaSnip": { "branch": "master", "commit": "33b06d72d220aa56a7ce80a0dd6f06c70cd82b9d" }, - "auto-save.nvim": { "branch": "main", "commit": "b58948445c43e6903987a9bb97c82e66fdcc0786" }, - "cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" }, - "cmp-nvim-lsp": { "branch": "main", "commit": "99290b3ec1322070bcfb9e846450a46f6efa50f0" }, + "LuaSnip": { "branch": "master", "commit": "c9b9a22904c97d0eb69ccb9bab76037838326817" }, + "auto-save.nvim": { "branch": "main", "commit": "29f793a3a7f98129387590269ffe3ad61ab5e509" }, + "cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" }, + "cmp-nvim-lsp": { "branch": "main", "commit": "a8912b88ce488f411177fc8aed358b04dc246d7b" }, "cmp-nvim-lua": { "branch": "main", "commit": "f12408bdb54c39c23e67cab726264c10db33ada8" }, - "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, + "cmp-path": { "branch": "main", "commit": "c6635aae33a50d6010bf1aa756ac2398a2d54c32" }, "cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" }, - "dashboard-nvim": { "branch": "master", "commit": "ae309606940d26d8c9df8b048a6e136b6bbec478" }, + "dashboard-nvim": { "branch": "master", "commit": "000448d837f6e7a47f8f342f29526c4d7e49e9ce" }, "diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" }, "friendly-snippets": { "branch": "main", "commit": "efff286dd74c22f731cdec26a70b46e5b203c619" }, - "gitsigns.nvim": { "branch": "main", "commit": "5f808b5e4fef30bd8aca1b803b4e555da07fc412" }, - "lazy.nvim": { "branch": "main", "commit": "7e6c863bc7563efbdd757a310d17ebc95166cef3" }, + "gitsigns.nvim": { "branch": "main", "commit": "17ab794b6fce6fce768430ebc925347e349e1d60" }, + "lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" }, "lspkind.nvim": { "branch": "master", "commit": "d79a1c3299ad0ef94e255d045bed9fa26025dab6" }, - "lspsaga.nvim": { "branch": "main", "commit": "2710a0ad97b5aaff404cd4756c296df454b3f726" }, - "lualine.nvim": { "branch": "master", "commit": "2a5bae925481f999263d6f5ed8361baef8df4f83" }, + "lspsaga.nvim": { "branch": "main", "commit": "778d56ff9b387dacd14ae648ed5604394b486f51" }, + "lualine.nvim": { "branch": "master", "commit": "0ea56f91b7f51a37b749c050a5e5dfdd56b302b3" }, "neodev.nvim": { "branch": "main", "commit": "46aa467dca16cf3dfe27098042402066d2ae242d" }, - "neogit": { "branch": "master", "commit": "40038473707c54a846bd11ecaf5933dd45858972" }, - "nvim-base16": { "branch": "master", "commit": "6ac181b5733518040a33017dde654059cd771b7c" }, - "nvim-cmp": { "branch": "main", "commit": "3403e2e9391ed0a28c3afddd8612701b647c8e26" }, + "neogit": { "branch": "master", "commit": "97f83f1dc51dee41e08e3c7a8adf00e1083e3178" }, + "nvim-base16": { "branch": "master", "commit": "3f13e15c53ea2aaf79c24ceab725309d87f0619c" }, + "nvim-cmp": { "branch": "main", "commit": "059e89495b3ec09395262f16b1ad441a38081d04" }, "nvim-colorizer.lua": { "branch": "master", "commit": "a065833f35a3a7cc3ef137ac88b5381da2ba302e" }, - "nvim-lspconfig": { "branch": "master", "commit": "5a812abc65d529ea7673059a348814c21d7f87ff" }, - "nvim-treesitter": { "branch": "master", "commit": "337b503688eccb3046547661e4c738e674548fcf" }, - "nvim-treesitter-textobjects": { "branch": "master", "commit": "ad8f0a472148c3e0ae9851e26a722ee4e29b1595" }, - "nvim-web-devicons": { "branch": "master", "commit": "e73d2774d12d0ecf9e05578d692ba1ea50508cf2" }, - "omnisharp-extended-lsp.nvim": { "branch": "main", "commit": "4916fa12e5b28d21a1f031f0bdd10aa15a75d85d" }, - "plenary.nvim": { "branch": "master", "commit": "2d9b06177a975543726ce5c73fca176cedbffe9d" }, + "nvim-lspconfig": { "branch": "master", "commit": "4ea9083b6d3dff4ddc6da17c51334c3255b7eba5" }, + "nvim-treesitter": { "branch": "master", "commit": "0e21ee8df6235511c02bab4a5b391d18e165a58d" }, + "nvim-treesitter-textobjects": { "branch": "master", "commit": "698b5f805722254bca3c509591c1806d268b6c2f" }, + "nvim-web-devicons": { "branch": "master", "commit": "c90dee4e930ab9f49fa6d77f289bff335b49e972" }, + "omnisharp-extended-lsp.nvim": { "branch": "main", "commit": "ec1a2431f8872f650a85ed71c24f0715df2e49c2" }, + "plenary.nvim": { "branch": "master", "commit": "857c5ac632080dba10aae49dba902ce3abf91b35" }, "project.nvim": { "branch": "main", "commit": "8c6bad7d22eef1b71144b401c9f74ed01526a4fb" }, "rainbow-delimiters.nvim": { "branch": "master", "commit": "c7e489756b5455f922ce79ac374a4ede594f4a20" }, - "sqlite.lua": { "branch": "master", "commit": "d0ffd703b56d090d213b497ed4eb840495f14a11" }, - "telescope-all-recent.nvim": { "branch": "main", "commit": "267e9e5fd13a6e9a4cc6ffe00452d446d040401d" }, + "sqlite.lua": { "branch": "master", "commit": "50092d60feb242602d7578398c6eb53b4a8ffe7b" }, + "telescope-all-recent.nvim": { "branch": "main", "commit": "e437f60ea468268e49ffdc0c9ed7c5ba384e63cf" }, "telescope-file-browser.nvim": { "branch": "master", "commit": "626998e5c1b71c130d8bc6cf7abb6709b98287bb" }, - "telescope-fzf-native.nvim": { "branch": "main", "commit": "cf48d4dfce44e0b9a2e19a008d6ec6ea6f01a83b" }, - "telescope-recent-files": { "branch": "main", "commit": "3a7a1b9c6b52b6ff7938c59f64c87a05e013dff8" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "1f08ed60cafc8f6168b72b80be2b2ea149813e55" }, + "telescope-recent-files": { "branch": "main", "commit": "eb190c0baded1cbfa9d8767c817b054377683163" }, "telescope.nvim": { "branch": "0.1.x", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" }, - "todo-comments.nvim": { "branch": "main", "commit": "ae0a2afb47cf7395dc400e5dc4e05274bf4fb9e0" }, - "trouble.nvim": { "branch": "main", "commit": "46cf952fc115f4c2b98d4e208ed1e2dce08c9bf6" }, - "ultimate-autopair.nvim": { "branch": "development", "commit": "9e3209190c22953566ae4e6436ad2b4ff4dabb95" }, + "todo-comments.nvim": { "branch": "main", "commit": "304a8d204ee787d2544d8bc23cd38d2f929e7cc5" }, + "trouble.nvim": { "branch": "main", "commit": "85bedb7eb7fa331a2ccbecb9202d8abba64d37b3" }, + "ultimate-autopair.nvim": { "branch": "development", "commit": "5835876b57901d81ebbeb3cd6ad71aaed66f82d7" }, "vim-sleuth": { "branch": "master", "commit": "be69bff86754b1aa5adcbb527d7fcd1635a84080" }, - "which-key.nvim": { "branch": "main", "commit": "9b365a6428a9633e3eeb34dbef1b791511c54f70" } + "which-key.nvim": { "branch": "main", "commit": "370ec46f710e058c9c1646273e6b225acf47cbed" } } diff --git a/.config/nvim/lua/core.lua b/.config/nvim/lua/core.lua index 30d926d..93abe07 100644 --- a/.config/nvim/lua/core.lua +++ b/.config/nvim/lua/core.lua @@ -3,3 +3,5 @@ require("core.config") require("core.buffers") require("core.autocommands") require("core.globals") +require("core.commands") +require("core.filetypes") diff --git a/.config/nvim/lua/core/autocommands.lua b/.config/nvim/lua/core/autocommands.lua index a2b8d1f..2df9edf 100644 --- a/.config/nvim/lua/core/autocommands.lua +++ b/.config/nvim/lua/core/autocommands.lua @@ -42,12 +42,18 @@ vim.api.nvim_create_autocmd("User", { end, }) --- Create an autocommand for full window buffers vim.api.nvim_create_autocmd("BufWinEnter", { - -- callback = require("core.buffers").add_buffer callback = function() + -- Buffer tracking require("core.buffers").add_buffer() - LOG(require("core.buffers").buffers) end, desc = "Track all full window buffers visited", }) + +vim.api.nvim_create_autocmd({ "BufDelete", "BufWipeout" }, { + callback = function(opts) + -- Buffer tracking + require("core.buffers").remove_buffer(opts.match) + end, + desc = "Track all full window buffers killed", +}) diff --git a/.config/nvim/lua/core/buffers.lua b/.config/nvim/lua/core/buffers.lua index e4c1d91..b9908ff 100644 --- a/.config/nvim/lua/core/buffers.lua +++ b/.config/nvim/lua/core/buffers.lua @@ -4,9 +4,10 @@ local F = require("core.functions") local M = {} --- Buffer table structure: +-- Buffers, categorized into groups -- { --- "Group" = { "buffer1", "buffer2", active_index = 1 } +-- { group = "Project", buffers = { "buffer1", "buffer2" }, active_index = 1 }, +-- { group = "Other", buffers = { "buffer3", "buffer4" }, active_index = 1 }, -- } M.buffers = {} @@ -42,19 +43,32 @@ M.add_buffer = function() -- Add if buffer does not exist yet local add = function(config_group) local group = eval_group(config_group) - if not M.buffers[group] then M.buffers[group] = {} end - for i, buffer in ipairs(M.buffers[group]) do + + local index + for i, buffer_group in ipairs(M.buffers) do + if buffer_group.group == group then index = i end + end + + -- Group is new entirely, so we only have 1 buffer + if not index then + table.insert(M.buffers, { group = group, buffers = { buffer_name }, active_index = 1 }) + return #M.buffers, 1 -- group index, buffer index + end + + -- Buffer previously added, set active + for i, buffer in ipairs(M.buffers[index].buffers) do if buffer == buffer_name then - M.buffers[group]["active_index"] = i - return group, i + M.buffers[index].active_index = i + return index, i -- group index, buffer index end end - table.insert(M.buffers[group], buffer_name) - local count = #M.buffers[group] - M.buffers[group]["active_index"] = count + -- Buffer is new, add it to the list + table.insert(M.buffers[index].buffers, buffer_name) + local count = #M.buffers[index].buffers + M.buffers[index].active_index = count - return group, count + return index, count -- group index, buffer index end -- Walk matcher configuration @@ -82,34 +96,74 @@ M.add_buffer = function() end local get_group_from_buffer = function(buffer_name) - for group, buffers in pairs(M.buffers) do - for i, buffer in ipairs(buffers) do - if buffer == buffer_name then return group, i end + for i, buffer_group in ipairs(M.buffers) do + for j, buffer in ipairs(buffer_group.buffers) do + if buffer == buffer_name then + return i, j -- group index, buffer index + end end end + return nil end +local focus_buffer = function(new_buffer_name) + for _, buffer in ipairs(vim.api.nvim_list_bufs()) do + if vim.api.nvim_buf_get_name(buffer) == new_buffer_name then + vim.api.nvim_set_current_buf(buffer) + break + end + end +end + +M.remove_buffer = function(buffer_name) + if not buffer_name or buffer_name == "" then return end + + local group_index, buffer_index = get_group_from_buffer(buffer_name) + if not group_index or not buffer_index then return end + + local buffer_group = M.buffers[group_index] + + -- Remove the buffer and decrease active index + table.remove(buffer_group.buffers, buffer_index) + buffer_group.active_index = math.max(buffer_group.active_index - 1, 1) + local new_buffer_name = buffer_group.buffers[buffer_group.active_index] + + -- If there are now no buffers in the group, delete the group + if #buffer_group.buffers == 0 then + table.remove(M.buffers, group_index) + if #M.buffers == 0 then return end + if #M.buffers < group_index then group_index = group_index - 1 end + new_buffer_name = M.buffers[group_index].buffers[M.buffers[group_index].active_index] + end + + -- Make the new index the active buffer + focus_buffer(new_buffer_name) +end + local buffer_action_in_active_group = function(action, direction) local buffer_name = get_buffer_name() if not buffer_name then return end - local group, index = get_group_from_buffer(buffer_name) - if not group then group, index = M.add_buffer() end + -- Get active group from the current buffer + local group_index, buffer_index = get_group_from_buffer(buffer_name) + if not group_index then group_index, buffer_index = M.add_buffer() end - local buffers = M.buffers[group] + -- Get buffer set + local buffers = M.buffers[group_index].buffers if #buffers < 2 then return end -- Determine the other index - local other_index = index + direction - if index == 1 and direction == -1 then + local other_index = buffer_index + direction + if buffer_index == 1 and direction == -1 then other_index = #buffers - elseif index == #buffers and direction == 1 then + elseif buffer_index == #buffers and direction == 1 then other_index = 1 end if action == "move" then for _, buffer in ipairs(vim.api.nvim_list_bufs()) do + -- TODO: Probably not needed if the other autocommands are implemented -- Remove inactive buffers if not vim.api.nvim_buf_is_loaded(buffer) then for i, group_buffer in ipairs(buffers) do @@ -127,7 +181,7 @@ local buffer_action_in_active_group = function(action, direction) -- Make buffer active if vim.api.nvim_buf_get_name(buffer) == buffers[other_index] then vim.api.nvim_set_current_buf(buffer) - buffers.active_index = other_index + M.buffers[group_index].active_index = other_index break end @@ -135,11 +189,11 @@ local buffer_action_in_active_group = function(action, direction) end elseif action == "swap" then local tmp = buffers[other_index] - buffers[other_index] = buffers[index] - buffers[index] = tmp + buffers[other_index] = buffers[buffer_index] + buffers[buffer_index] = tmp end - M.buffers[group] = buffers + M.buffers[group_index].buffers = buffers end M.buffer_move_left = function() @@ -165,13 +219,28 @@ local buffer_group_move = function(direction) local buffer_name = get_buffer_name() if not buffer_name then return end - -- TODO: How to get groups deterministically? - -- Get active group from the current buffer + local group_index, _ = get_group_from_buffer(buffer_name) + if not group_index then group_index, _ = M.add_buffer() end -- Check groups bounds + if #M.buffers < 2 then return end + + -- Determine the other index + local other_index = group_index + direction + if group_index == 1 and direction == -1 then + other_index = #M.buffers + elseif group_index == #M.buffers and direction == 1 then + other_index = 1 + end + + -- Get active index from other group + local other_active_index = M.buffers[other_index].active_index - -- Change active group + -- Make buffer active + -- TODO: What do if this buffer no longer exists? + local other_buffer = M.buffers[other_index].buffers[other_active_index] + focus_buffer(other_buffer) end M.buffer_group_move_up = function() @@ -182,32 +251,97 @@ M.buffer_group_move_down = function() buffer_group_move(1) end --- TODO: functions that can --- v Navigate buffer left --- v Navigate buffer right --- - Navigate group up (use active_index when swapping) --- - Navigate group down --- v Move buffer left --- v Move buffer right --- - Remove buffer from currently active group (decrease active_index) +-------------------------------------------- +-- Telescope functionss + +local pick = function(title, items, entry_maker, action) + local actions = require("telescope.actions") + local action_state = require("telescope.actions.state") + local conf = require("telescope.config").values + local finders = require("telescope.finders") + local pickers = require("telescope.pickers") + + pickers.new({}, { + prompt_title = title, + finder = finders.new_table { + results = items, + entry_maker = entry_maker, + }, + previewer = false, + sorter = conf.generic_sorter({}), + attach_mappings = function(prompt_bufnr) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + + local selection = action_state.get_selected_entry() + action(selection) + end) + + return true + end, + }):find() +end -return M +M.buffer_pick_buffer = function() + local buffer_name = get_buffer_name() + if not buffer_name then return end + -- Get active group from the current buffer + local group_index, _ = get_group_from_buffer(buffer_name) + if not group_index then group_index, _ = M.add_buffer() end + + -- Get all buffers from the active group + local buffers = {} + for i, buffer in ipairs(M.buffers[group_index].buffers) do + table.insert(buffers, { key = buffer, value = tostring(i) }) + end + + pick("Group buffers", + buffers, + function(buffer) + -- Only show last part of the path + local display = buffer.key:match("^.+/(.+)$") or buffer.key + return { + display = display, -- shown in the picker + ordinal = buffer.value, -- used for sorting/filtering + value = buffer.value, -- actual value + } + end, + function(selection) + local new_buffer_name = M.buffers[group_index].buffers[tonumber(selection.value)] + + -- Make new buffer active + focus_buffer(new_buffer_name) + end + ) +end --- (cond --- ((string-equal "*" (substring (buffer-name) 0 1)) "Emacs") --- ((or (memq major-mode '(magit-process-mode --- magit-status-mode --- magit-diff-mode --- magit-log-mode --- magit-file-mode --- magit-blob-mode --- magit-blame-mode)) --- (string= (buffer-name) "COMMIT_EDITMSG")) "Magit") --- ((project-current) (dot/project-project-name)) --- ((memq major-mode '(org-mode --- emacs-lisp-mode)) "Org Mode") --- ((derived-mode-p 'dired-mode) "Dired") --- ((derived-mode-p 'prog-mode --- 'text-mode) "Editing") --- (t "Other"))))) +M.buffer_pick_group = function() + -- Get all groups + local groups = {} + for i, buffer_group in ipairs(M.buffers) do + table.insert(groups, { key = buffer_group.group, value = tostring(i) }) + end + + pick("Groups", + groups, + function(group) + -- Only show last part of the path + local display = group.key:match("^.+/(.+)$") or group.key + return { + display = display, -- shown in the picker + ordinal = group.value, -- used for sorting/filtering + value = group.value, -- actual value + } + end, + function(selection) + local buffer_group = M.buffers[tonumber(selection.value)] + local new_buffer_name = buffer_group.buffers[buffer_group.active_index] + + -- Make new buffer active + focus_buffer(new_buffer_name) + end + ) +end + +return M diff --git a/.config/nvim/lua/core/commands.lua b/.config/nvim/lua/core/commands.lua new file mode 100644 index 0000000..de7ce49 --- /dev/null +++ b/.config/nvim/lua/core/commands.lua @@ -0,0 +1,18 @@ +local F = require("core.functions") + +local create_command = function(name, command) + if not name or type(name) ~= "string" then return end + + vim.api.nvim_create_user_command(name, function() + local cmd = type(command) == "function" and command() or command + F.execute_command(cmd) + end, {}) +end + +create_command("RunScript", "ls") +create_command("ScanScript", function() + local file_path = vim.fn.expand("%:p") + LOG(file_path) + + return "ls" +end) diff --git a/.config/nvim/lua/core/filetypes.lua b/.config/nvim/lua/core/filetypes.lua new file mode 100644 index 0000000..6006266 --- /dev/null +++ b/.config/nvim/lua/core/filetypes.lua @@ -0,0 +1,5 @@ +vim.filetype.add({ + extension = { + flw = "lua", + }, +}) diff --git a/.config/nvim/lua/core/functions.lua b/.config/nvim/lua/core/functions.lua index be6f69f..70a443e 100644 --- a/.config/nvim/lua/core/functions.lua +++ b/.config/nvim/lua/core/functions.lua @@ -1,5 +1,21 @@ local M = {} +M.execute_command = function(command) + if not command then return end + + local job = require("plenary.job") + job:new({ + command = command, + on_exit = function(j, _) + vim.schedule(function() + vim.api.nvim_echo({ + { table.concat(j:result(), "\n"), "Normal" } + }, false, {}) + end) + end, + }):start() +end + M.is_buffer_a_file = function() local buffer_name = vim.fn.bufname() diff --git a/.config/nvim/lua/keybinds.lua b/.config/nvim/lua/keybinds.lua index 1939fa7..7e86dc7 100644 --- a/.config/nvim/lua/keybinds.lua +++ b/.config/nvim/lua/keybinds.lua @@ -1,6 +1,7 @@ local K = vim.keymap.set local builtin +local bs = require("core.buffers") local wk = require("which-key") local F = require("keybind-functions") @@ -57,6 +58,14 @@ M.setup = function() K("i", "", F.hungry_delete_backspace()) K("i", "", F.hungry_delete()) + -- Navigation + K("n", "", bs.buffer_move_left) + K("n", "", bs.buffer_group_move_down) + K("n", "", bs.buffer_group_move_up) + K("n", "", bs.buffer_move_right) + K("n", "", bs.buffer_swap_left) + K("n", "", bs.buffer_swap_right) + ---------------------------------------- --- Leader keys --- @@ -66,6 +75,7 @@ M.setup = function() F.wk("b", "buffer/bookmark") K("n", "bb", builtin.buffers, { desc = "Switch buffer" }) + K("n", "bB", bs.buffer_pick_buffer, { desc = "Switch tab group buffer" }) K("n", "bd", F.buffer_dashboard, { desc = "Dashboard" }) @@ -112,6 +122,10 @@ M.setup = function() K("n", "sq", ":nohlsearch", { desc = "Stop search", silent = true }) + F.wk("t", "tabs/toggle") + K("n", "tg", bs.buffer_pick_group, { desc = "Switch tab group" }) + + F.wk("v", "git") -- version control K("n", "vr", F.vc_select_repo, { desc = "Select repo" }) K("n", "vv", F.vc_status, { desc = "Neogit status" })