Public Access
oil is king
This commit is contained in:
@@ -54,19 +54,10 @@ Git shortcuts:
|
|||||||
- `[h`, `]h`, `[H`, `]H` jump to hunks
|
- `[h`, `]h`, `[H`, `]H` jump to hunks
|
||||||
- `<leader>th` — toggle the expanded hunk view
|
- `<leader>th` — toggle the expanded hunk view
|
||||||
|
|
||||||
Refresh shortcuts (oil and buffers):
|
|
||||||
|
|
||||||
- `gR` refresh the current buffer
|
|
||||||
- `<F5>` refresh the current buffer
|
|
||||||
|
|
||||||
Oil usage:
|
Oil usage:
|
||||||
|
|
||||||
- `<leader>dl` opens the file browser
|
|
||||||
- `-`, `<BS>` goes to the parent directory
|
- `-`, `<BS>` goes to the parent directory
|
||||||
- `<A-h>` also goes to the parent directory
|
|
||||||
- `<A-l>` opens the selected file or enters the selected directory
|
|
||||||
- `<C-p>` previews the selected entry
|
- `<C-p>` previews the selected entry
|
||||||
- `gx` opens the file in external viewer
|
|
||||||
|
|
||||||
Toggle shortcuts:
|
Toggle shortcuts:
|
||||||
|
|
||||||
@@ -115,7 +106,10 @@ Diagnostics:
|
|||||||
- `]g`, `[g` jump to warning or error
|
- `]g`, `[g` jump to warning or error
|
||||||
- `<leader>ti` toggle inline diagnostics
|
- `<leader>ti` toggle inline diagnostics
|
||||||
- `<leader>tv` toggle virtual diagnostics
|
- `<leader>tv` toggle virtual diagnostics
|
||||||
- `<leader>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.
|
- `<leader>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
|
## Tree-sitter
|
||||||
|
|
||||||
|
|||||||
@@ -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", "<F5>" }) 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", "<CR>", "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
|
|
||||||
@@ -18,15 +18,6 @@ local function telescope_picker(picker)
|
|||||||
end
|
end
|
||||||
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", "<leader><leader>r", ":source ~/.config/nvim/init.lua<CR>", { desc = "reload init.lua" })
|
map("n", "<leader><leader>r", ":source ~/.config/nvim/init.lua<CR>", { desc = "reload init.lua" })
|
||||||
map("n", "<leader><leader>h", telescope_picker("keymaps"), { desc = "show keymaps" })
|
map("n", "<leader><leader>h", telescope_picker("keymaps"), { desc = "show keymaps" })
|
||||||
map("n", "<leader>dl", "<Cmd>Oil<CR>", { desc = "open oil" })
|
map("n", "<leader>dl", "<Cmd>Oil<CR>", { desc = "open oil" })
|
||||||
|
|||||||
Reference in New Issue
Block a user