diff --git a/nvim/.config/nvim/README.md b/nvim/.config/nvim/README.md index 0e17a18..dfb2607 100644 --- a/nvim/.config/nvim/README.md +++ b/nvim/.config/nvim/README.md @@ -54,19 +54,10 @@ Git shortcuts: - `[h`, `]h`, `[H`, `]H` jump to hunks - `th` — toggle the expanded hunk view -Refresh shortcuts (oil and buffers): - -- `gR` refresh the current buffer -- `` refresh the current buffer - Oil usage: -- `dl` opens the file browser - `-`, `` goes to the parent directory -- `` also goes to the parent directory -- `` opens the selected file or enters the selected directory - `` previews the selected entry -- `gx` opens the file in external viewer Toggle shortcuts: @@ -115,7 +106,10 @@ Diagnostics: - `]g`, `[g` jump to warning or error - `ti` toggle inline diagnostics - `tv` toggle virtual diagnostics -- `xx`, `:ProjectDiagnostics` check the current Dart or TypeScript package and show warnings and errors in Trouble. Save modified package files first. Other languages show available LSP diagnostics; project coverage depends on the language server. +- `xx`, `:ProjectDiagnostics` check the current Dart or TypeScript + package and show warnings and errors in Trouble. Save modified package files + first. Other languages show available LSP diagnostics; project coverage + depends on the language server. ## Tree-sitter diff --git a/nvim/.config/nvim/lua/romanzy/custom/mini_files.lua b/nvim/.config/nvim/lua/romanzy/custom/mini_files.lua deleted file mode 100644 index 8f0e850..0000000 --- a/nvim/.config/nvim/lua/romanzy/custom/mini_files.lua +++ /dev/null @@ -1,426 +0,0 @@ --- Custom module to config a few things for the mini.files: --- - git highlighting --- - refresh --- - file open in external programs - -local M = {} - -local uv = vim.uv or vim.loop -local cache_ttl_ms = 1000 - -local status_cache = {} -local git_root_cache = {} -local known_git_roots = {} - -local function is_path_inside(path, root) - return path == root or vim.startswith(path, root .. "/") -end - -local function new_status_node() - return { - children = {}, - status = nil, - priority = 0, - is_dir_ignored = false, - is_dir_untracked = false, - } -end - -local function is_conflict(status) - if #status < 2 then - return false - end - - local index_status = status:sub(1, 1) - local worktree_status = status:sub(2, 2) - return index_status == "U" - or worktree_status == "U" - or status == "AA" - or status == "DD" -end - -local function status_priority(status) - -- Folder aggregation follows the Zed-inspired order create < edit < - -- delete. `subtree_status()` uses the greatest priority, so deletion - -- must outrank every create or edit status. - if #status < 2 then - return 0 - end - - if is_conflict(status) then - return 8 - end - if status == "!!" then - return 1 - end - if status == "??" then - return 2 - end - - local index_status = status:sub(1, 1) - local worktree_status = status:sub(2, 2) - - if index_status == "D" or worktree_status == "D" then - return 4 - end - if index_status == "A" then - return 2 - end - if index_status == "R" or index_status == "C" then - return 3 - end - if index_status == "M" or worktree_status == "M" then - return 3 - end - - return 0 -end - -local function status_highlight(status) - if not status then - return nil - end - if status == "!!" then - return "Comment" - end - if is_conflict(status) then - return "MiniDiffSignDelete" - end - if status == "??" or status:sub(1, 1) == "A" then - return "MiniDiffSignAdd" - end - if status:sub(1, 1) == "D" or status:sub(2, 2) == "D" then - return "MiniDiffSignDelete" - end - if status:sub(1, 1) == "M" - or status:sub(1, 1) == "R" - or status:sub(1, 1) == "C" - or status:sub(2, 2) == "M" - then - return "MiniDiffSignChange" - end - - return nil -end - -local function insert_status(root, relative_path, status, is_directory) - local priority = status_priority(status) - if priority == 0 then - return - end - - local node = root - local segments = vim.split(relative_path, "/", { plain = true, trimempty = true }) - for index, segment in ipairs(segments) do - node.children[segment] = node.children[segment] or new_status_node() - node = node.children[segment] - - if index == #segments then - if priority > node.priority then - node.status = status - node.priority = priority - end - if is_directory and status == "!!" then - node.is_dir_ignored = true - end - if is_directory and status == "??" then - node.is_dir_untracked = true - end - end - end -end - -local function subtree_status(node) - local best_status = node.status - local best_priority = node.priority - - for _, child in pairs(node.children) do - local child_status, child_priority = subtree_status(child) - if child_priority > best_priority then - best_status = child_status - best_priority = child_priority - end - end - - return best_status, best_priority -end - -local function parse_status(output, root) - local data = { - root = root, - statuses = {}, - trie = new_status_node(), - timestamp = uv.now(), - } - - local records = vim.split(output, "\0", { plain = true, trimempty = true }) - local record_index = 1 - while record_index <= #records do - local record = records[record_index] - if #record >= 4 then - local status = record:sub(1, 2) - local relative_path = record:sub(4) - - -- With -z, rename/copy output contains the new path followed by - -- the old path. Oil highlights the new path only. - if status:sub(1, 1) == "R" or status:sub(1, 1) == "C" then - record_index = record_index + 1 - end - - local is_directory = relative_path:sub(-1) == "/" - relative_path = relative_path:gsub("^%./", ""):gsub("/$", "") - if relative_path ~= "" then - local absolute_path = vim.fs.normalize(vim.fs.joinpath(root, relative_path)) - data.statuses[absolute_path] = status - insert_status(data.trie, relative_path, status, is_directory) - end - end - record_index = record_index + 1 - end - - return data -end - -local function find_cached_root(path) - local result - for root in pairs(known_git_roots) do - if is_path_inside(path, root) and (result == nil or #root > #result) then - result = root - end - end - return result -end - -local function find_git_root(path) - local cached_root = find_cached_root(path) - if cached_root ~= nil then - return cached_root - end - - local cached = git_root_cache[path] - if cached ~= nil then - return cached or nil - end - - local result = vim.system({ "git", "-C", path, "rev-parse", "--show-toplevel" }, { text = true }):wait() - if result.code ~= 0 then - git_root_cache[path] = false - return nil - end - - local root = vim.trim(result.stdout) - if root == "" then - git_root_cache[path] = false - return nil - end - - root = vim.fs.normalize(root) - git_root_cache[path] = root - known_git_roots[root] = true - return root -end - -local function get_status_data(fs_entry) - local path = fs_entry.path - if fs_entry.fs_type ~= "directory" then - path = vim.fs.dirname(path) - end - path = vim.fs.normalize(path) - - local root = find_git_root(path) - if root == nil then - return nil - end - - local cached = status_cache[root] - if cached ~= nil and uv.now() - cached.timestamp < cache_ttl_ms then - return cached - end - - local result = vim.system({ - "git", - "-C", - root, - "--no-optional-locks", - "status", - "--porcelain", - "--ignored", - "-z", - }, { text = true }):wait() - if result.code ~= 0 then - status_cache[root] = parse_status("", root) - return status_cache[root] - end - - local data = parse_status(result.stdout, root) - status_cache[root] = data - return data -end - -local function lookup_status(data, fs_entry) - local path = vim.fs.normalize(fs_entry.path) - local direct_status = data.statuses[path] - if fs_entry.fs_type ~= "directory" and direct_status ~= nil then - return direct_status - end - - if not is_path_inside(path, data.root) then - return nil - end - - local relative_path = path:sub(#data.root + 2) - local node = data.trie - for _, segment in ipairs(vim.split(relative_path, "/", { plain = true, trimempty = true })) do - if node.is_dir_ignored then - return "!!" - end - if node.is_dir_untracked then - return "??" - end - - node = node.children[segment] - if node == nil then - return nil - end - end - - if node.is_dir_ignored then - return "!!" - end - if node.is_dir_untracked then - return "??" - end - if next(node.children) == nil then - return node.status - end - - local status = subtree_status(node) - -- Match the Oil configuration: an ignored descendant does not grey its - -- parent directory unless Git reported that directory as ignored. - if fs_entry.fs_type == "directory" and status == "!!" then - return nil - end - return status -end - -function M.filter(fs_entry) - return fs_entry.name ~= ".git" -end - -local function get_entry_status(fs_entry) - local data = get_status_data(fs_entry) - if data == nil then - return nil - end - - return lookup_status(data, fs_entry) -end - -function M.highlight(fs_entry) - local status = get_entry_status(fs_entry) - return status_highlight(status) - or (fs_entry.fs_type == "directory" and "MiniFilesDirectory" or "MiniFilesFile") -end - -function M.invalidate() - status_cache = {} - git_root_cache = {} - known_git_roots = {} -end - -local function refresh() - M.invalidate() - if _G.MiniFiles == nil or MiniFiles.get_explorer_state() == nil then - return - end - - vim.schedule(function() - if MiniFiles.get_explorer_state() ~= nil then - MiniFiles.refresh() - end - end) -end - -local function refresh_filetree() - M.invalidate() - if _G.MiniFiles == nil or MiniFiles.get_explorer_state() == nil then - return - end - - vim.schedule(function() - if MiniFiles.get_explorer_state() ~= nil then - MiniFiles.refresh({ - content = { - filter = M.filter, - highlight = M.highlight, - }, - }) - end - end) -end - -local function open_external() - local fs_entry = MiniFiles.get_fs_entry() - if fs_entry == nil then - vim.notify("No file system entry under the cursor", vim.log.levels.WARN) - return - end - - vim.ui.open(fs_entry.path) -end - -function M.setup() - local group = vim.api.nvim_create_augroup("romanzy_mini_files_git", { clear = true }) - - vim.api.nvim_create_autocmd("User", { - group = group, - pattern = "MiniFilesBufferCreate", - callback = function(args) - if args.data == nil then - return - end - - for _, lhs in ipairs({ "gR", "" }) do - vim.keymap.set("n", lhs, refresh_filetree, { - buffer = args.data.buf_id, - desc = "refresh mini.files filetree", - }) - end - vim.keymap.set("n", "gx", open_external, { - buffer = args.data.buf_id, - desc = "open mini.files entry externally", - }) - vim.keymap.set("n", "", "L", { - buffer = args.data.buf_id, - remap = true, - desc = "go in entry plus (extra)", - }) - end, - }) - vim.api.nvim_create_autocmd({ "BufWritePost", "FocusGained", "TermClose" }, { - group = group, - callback = refresh, - }) - vim.api.nvim_create_autocmd("User", { - group = group, - pattern = { - "GitSignsUpdate", - "LazyGitClosed", - "MiniFilesActionCreate", - "MiniFilesActionDelete", - "MiniFilesActionRename", - "MiniFilesActionCopy", - "MiniFilesActionMove", - }, - callback = refresh, - }) - - return { - content = { - filter = M.filter, - highlight = M.highlight, - }, - } -end - -return M diff --git a/nvim/.config/nvim/lua/romanzy/keymaps.lua b/nvim/.config/nvim/lua/romanzy/keymaps.lua index 3acf0c5..303aafc 100644 --- a/nvim/.config/nvim/lua/romanzy/keymaps.lua +++ b/nvim/.config/nvim/lua/romanzy/keymaps.lua @@ -18,15 +18,6 @@ local function telescope_picker(picker) end end -local function open_mini_files_at_current_buffer() - local current_path = vim.api.nvim_buf_get_name(0) - if vim.bo.buftype ~= "" or current_path == "" then - current_path = nil - end - - MiniFiles.open(current_path) -end - map("n", "r", ":source ~/.config/nvim/init.lua", { desc = "reload init.lua" }) map("n", "h", telescope_picker("keymaps"), { desc = "show keymaps" }) map("n", "dl", "Oil", { desc = "open oil" })