Neovim: WIP on navigation workflow

This commit is contained in:
Riyyi
2025-01-18 13:54:36 +01:00
parent 98cf182406
commit f0835c1a06
10 changed files with 897 additions and 29 deletions
+23 -12
View File
@@ -1,3 +1,5 @@
local F = require("core.functions")
--------------------------------------------
--- Commands ---
@@ -13,10 +15,9 @@ vim.cmd [[
--- Autocommands ---
-- Cut off trailing whitespace and trailing blank lines
local core = require("core.functions")
vim.api.nvim_create_autocmd({ "BufWritePre" }, {
pattern = "*",
callback = core.trim_buffer,
callback = F.trim_buffer,
})
-- Highlight on yank
@@ -29,14 +30,24 @@ vim.api.nvim_create_autocmd("TextYankPost", {
})
-- Show message when autosaving
local group = vim.api.nvim_create_augroup('autosave', {})
vim.api.nvim_create_autocmd('User', {
pattern = 'AutoSaveWritePost',
group = group,
callback = function(opts)
if opts.data.saved_buffer ~= nil then
local filename = vim.api.nvim_buf_get_name(opts.data.saved_buffer)
vim.notify("Wrote " .. filename, vim.log.levels.INFO)
end
end,
local autosave_group = vim.api.nvim_create_augroup("autosave", {})
vim.api.nvim_create_autocmd("User", {
pattern = "AutoSaveWritePost",
group = autosave_group,
callback = function(opts)
if opts.data.saved_buffer ~= nil then
local filename = vim.api.nvim_buf_get_name(opts.data.saved_buffer)
vim.notify("Wrote " .. filename, vim.log.levels.INFO)
end
end,
})
-- Create an autocommand for full window buffers
vim.api.nvim_create_autocmd("BufWinEnter", {
-- callback = require("core.buffers").add_buffer
callback = function()
require("core.buffers").add_buffer()
LOG(require("core.buffers").buffers)
end,
desc = "Track all full window buffers visited",
})
+213
View File
@@ -0,0 +1,213 @@
local F = require("core.functions")
-- Module for managing buffers, these are used for navigation
local M = {}
-- Buffer table structure:
-- {
-- "Group" = { "buffer1", "buffer2", active_index = 1 }
-- }
M.buffers = {}
M.buffer_default_group = "Other"
M.buffer_matcher = {
-- match = truthy, function() -> thruthy, or string matching buffer filename
-- group = string, function() -> string
{ match = F.find_project_root, group = F.find_project_root },
{ match = true, group = "Other" }, -- default
}
--------------------------------------------
local get_buffer_name = function()
local buf = vim.api.nvim_get_current_buf()
local buffer_name = vim.api.nvim_buf_get_name(buf)
if not buffer_name or buffer_name == "" then return nil end
return buffer_name
end
M.add_buffer = function()
local buffer_name = get_buffer_name()
if not buffer_name then return end
-- Evaluate group
local eval_group = function(config_group)
if not config_group then return M.buffer_default_group end
if type(config_group) == "function" then return config_group() end
return config_group
end
-- 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
if buffer == buffer_name then
M.buffers[group]["active_index"] = i
return group, i
end
end
table.insert(M.buffers[group], buffer_name)
local count = #M.buffers[group]
M.buffers[group]["active_index"] = count
return group, count
end
-- Walk matcher configuration
local matcher = M.buffer_matcher or {}
if matcher and type(matcher) == "function" then
matcher = matcher()
end
if #matcher == 0 then add(M.buffer_default_group) end
for _, config in ipairs(M.buffer_matcher) do
if type(config.match) == "function" and config.match() then
return add(config.group)
end
-- Match path's filename
if type(config.match) == "string" and config.match == buffer_name:match("([^/]+)$") then
return add(config.group)
end
if type(config.match) == "boolean" and config.match then
return add(config.group)
end
end
return add(M.buffer_default_group)
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
end
end
return nil
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
local buffers = M.buffers[group]
if #buffers < 2 then return end
-- Determine the other index
local other_index = index + direction
if index == 1 and direction == -1 then
other_index = #buffers
elseif index == #buffers and direction == 1 then
other_index = 1
end
if action == "move" then
for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
-- Remove inactive buffers
if not vim.api.nvim_buf_is_loaded(buffer) then
for i, group_buffer in ipairs(buffers) do
if buffer == group_buffer then
table.remove(buffers, i)
if i > 1 and i <= other_index then
other_index = other_index - 1
end
end
end
goto continue
end
-- 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
break
end
::continue::
end
elseif action == "swap" then
local tmp = buffers[other_index]
buffers[other_index] = buffers[index]
buffers[index] = tmp
end
M.buffers[group] = buffers
end
M.buffer_move_left = function()
buffer_action_in_active_group("move", -1)
end
M.buffer_move_right = function()
buffer_action_in_active_group("move", 1)
end
M.buffer_swap_left = function()
buffer_action_in_active_group("swap", -1)
end
M.buffer_swap_right = function()
buffer_action_in_active_group("swap", 1)
end
--------------------------------------------
-- Group move
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
-- Check groups bounds
-- Change active group
end
M.buffer_group_move_up = function()
buffer_group_move(-1)
end
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)
return M
-- (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")))))
+7 -4
View File
@@ -32,11 +32,14 @@ M.find_project_root = function()
local directory = current_directory
while directory ~= "/" do
local git_directory = directory .. "/.git"
local project_file = directory .. "/.project"
local git_path = vim.loop.fs_stat(directory .. "/.git")
if git_path then
return directory:gsub("/$", "") -- remove trailing slash
end
if vim.fn.isdirectory(git_directory) == 1 or vim.fn.filereadable(project_file) == 1 then
return directory
local project_file = vim.loop.fs_stat(directory .. "/.project")
if project_file and project_file.type == "file" then
return directory:gsub("/$", "") -- remove trailing slash
end
directory = vim.fn.fnamemodify(directory, ":h")