Skip to content

Commit

Permalink
feat: Show parent directory in a split next to oil buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
DriesOlbrechts committed Sep 26, 2024
1 parent 1360be5 commit 44408f4
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
1 change: 1 addition & 0 deletions lua/oil/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ local default_config = {
},
-- preview_split: Split direction: "auto", "left", "right", "above", "below".
preview_split = "auto",
parent_dir_split = "left",
-- This is the config that will be passed to nvim_open_win.
-- Change values here to customize the layout
override = function(conf)
Expand Down
142 changes: 142 additions & 0 deletions lua/oil/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,18 @@ local function update_preview_window(oil_bufnr)
end)
end

---@param oil_bufnr? integer
local function update_parent_dir_window(oil_bufnr)
oil_bufnr = oil_bufnr or 0
local util = require("oil.util")
util.run_after_load(oil_bufnr, function()
local parent_dir_win_id = util.get_parent_dir_win()
if parent_dir_win_id then
M.open_parent_dir()
end
end)
end

---Open oil browser for a directory
---@param dir nil|string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file
M.open = function(dir)
Expand All @@ -390,6 +402,7 @@ M.open = function(dir)

-- If preview window exists, update its content
update_preview_window()
update_parent_dir_window()
end

---Restore the buffer that was present when oil was opened
Expand Down Expand Up @@ -500,6 +513,7 @@ M.open_preview = function(opts, callback)
end

preview_win = vim.api.nvim_open_win(bufnr, true, win_opts)

vim.api.nvim_set_option_value("previewwindow", true, { scope = "local", win = preview_win })
vim.api.nvim_set_current_win(prev_win)
elseif vim.fn.has("nvim-0.9") == 1 then
Expand Down Expand Up @@ -567,6 +581,113 @@ M.open_preview = function(opts, callback)
end)
end

---View the parent directory of the current directory in a split
---@param opts nil|table
--- vertical boolean Open the buffer in a vertical split
--- horizontal boolean Open the buffer in a horizontal split
--- split "aboveleft"|"belowright"|"topleft"|"botright" Split modifier
M.open_parent_dir = function(opts, callback)
opts = opts or {}
local config = require("oil.config")
local layout = require("oil.layout")
local util = require("oil.util")

local function finish(err)
if err then
vim.notify(err, vim.log.levels.ERROR)
end
if callback then
callback(err)
end
end

if not opts.horizontal and opts.vertical == nil then
opts.vertical = true
end
if not opts.split then
if opts.horizontal then
opts.split = vim.o.splitbelow and "belowright" or "aboveleft"
else
opts.split = vim.o.splitright and "belowright" or "aboveleft"
end
end

local parent_dir_win = util.get_parent_dir_win()
local prev_win = vim.api.nvim_get_current_win()
local bufnr = vim.api.nvim_get_current_buf()

local current_path = M.get_current_dir(bufnr)
local parent_path = vim.fn.fnamemodify(current_path, ":h:h")

if util.is_floating_win() then
if parent_dir_win == nil then
local root_win_opts, parent_dir_win_opts =
layout.split_window(0, config.float.parent_dir_split, config.float.padding)

local win_opts_oil = {
relative = "editor",
width = root_win_opts.width,
height = root_win_opts.height,
row = root_win_opts.row,
col = root_win_opts.col,
border = config.float.border,
zindex = 45,
}
vim.api.nvim_win_set_config(0, win_opts_oil)
local win_opts = {
relative = "editor",
width = parent_dir_win_opts.width,
height = parent_dir_win_opts.height,
row = parent_dir_win_opts.row,
col = parent_dir_win_opts.col,
border = config.float.border,
zindex = 45,
focusable = false,
noautocmd = true,
style = "minimal",
}

if vim.fn.has("nvim-0.9") == 1 then
win_opts.title = parent_path
end

parent_dir_win = vim.api.nvim_open_win(bufnr, true, win_opts)

vim.api.nvim_win_set_var(parent_dir_win, "parentdirwindow", true)
vim.w.oil_source_win = prev_win
vim.api.nvim_set_current_win(prev_win)
elseif vim.fn.has("nvim-0.9") == 1 then
vim.api.nvim_win_set_config(parent_dir_win, { title = parent_path })
end
end

local cmd = parent_dir_win and "buffer" or "sbuffer"
local mods = {
vertical = opts.vertical,
horizontal = opts.horizontal,
split = opts.split,
}
if parent_dir_win then
vim.api.nvim_set_current_win(parent_dir_win)
end

local parent_url = M.get_url_for_path(parent_path)
local filebufnr = vim.fn.bufadd(parent_url)

local ok, err = pcall(vim.cmd, {
cmd = cmd,
args = { filebufnr },
mods = mods,
})
-- Ignore swapfile errors
if not ok and err and not err:match("^Vim:E325:") then
vim.api.nvim_echo({ { err, "Error" } }, true, {})
end

vim.api.nvim_set_current_win(prev_win)
finish()
end

---@class (exact) oil.SelectOpts
---@field vertical? boolean Open the buffer in a vertical split
---@field horizontal? boolean Open the buffer in a horizontal split
Expand Down Expand Up @@ -748,6 +869,7 @@ M.select = function(opts, callback)
end

update_preview_window()
update_parent_dir_window()

finish()
end)
Expand Down Expand Up @@ -1014,6 +1136,25 @@ local function close_preview_window_if_not_in_oil()
pcall(vim.api.nvim_win_close, preview_win_id, true)
end

local function close_parent_dir_window_if_not_in_oil()
local util = require("oil.util")
local parent_dir_win_id = util.get_parent_dir_win()
if not parent_dir_win_id then
return
end

local oil_source_win = vim.w[parent_dir_win_id].oil_source_win
if oil_source_win and vim.api.nvim_win_is_valid(oil_source_win) then
local src_buf = vim.api.nvim_win_get_buf(oil_source_win)
if util.is_oil_bufnr(src_buf) then
return
end
end

-- This can fail if it's the last window open
pcall(vim.api.nvim_win_close, parent_dir_win_id, true)
end

local _on_key_ns = 0
---Initialize oil
---@param opts oil.setupOpts|nil
Expand Down Expand Up @@ -1196,6 +1337,7 @@ M.setup = function(opts)
end

close_preview_window_if_not_in_oil()
close_parent_dir_window_if_not_in_oil()
end,
})

Expand Down
12 changes: 12 additions & 0 deletions lua/oil/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,18 @@ M.get_preview_win = function()
end
end

---@return nil|integer
M.get_parent_dir_win = function()
for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
if vim.api.nvim_win_is_valid(winid) then
local success, value = pcall(vim.api.nvim_win_get_var, winid, "parentdirwindow")
if success and value then
return winid
end
end
end
end

---@return fun() restore Function that restores the cursor
M.hide_cursor = function()
vim.api.nvim_set_hl(0, "OilPreviewCursor", { nocombine = true, blend = 100 })
Expand Down
6 changes: 6 additions & 0 deletions lua/oil/view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@ M.initialize = function(bufnr)
end

constrain_cursor()
-- update parent dir window
local parent_dir_win_id = util.get_parent_dir_win()
if parent_dir_win_id then
oil.open_parent_dir()
end

if config.preview.update_on_cursor_moved then
-- Debounce and update the preview window
Expand Down Expand Up @@ -695,6 +700,7 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter)
local chunk = columns.render_col(adapter, column, entry)
local text = type(chunk) == "table" and chunk[1] or chunk
---@cast text string
---
col_width[i + 1] = math.max(col_width[i + 1], vim.api.nvim_strwidth(text))
table.insert(cols, chunk)
end
Expand Down

0 comments on commit 44408f4

Please sign in to comment.