diff --git a/README.md b/README.md index 1929c38..524657d 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ You can open a directory with `:edit ` or `:Oil `. To open oil in a ```lua require("oil").setup({ -- Oil will take over directory buffers (e.g. `vim .` or `:e src/`) - -- Set to false if you still want to use netrw. + -- Set to false if you want some other plugin (e.g. netrw) to open when you edit directories. default_file_explorer = true, -- Id is automatically added at the beginning, and name at the end -- See :help oil-columns @@ -248,6 +248,8 @@ require("oil").setup({ win_options = { winblend = 0, }, + -- preview_split: Split direction: "auto", "left", "right", "above", "below". + preview_split = "auto", -- This is the config that will be passed to nvim_open_win. -- Change values here to customize the layout override = function(conf) diff --git a/doc/oil.txt b/doc/oil.txt index 8e55183..a10cd9f 100644 --- a/doc/oil.txt +++ b/doc/oil.txt @@ -17,7 +17,7 @@ CONFIG *oil-confi >lua require("oil").setup({ -- Oil will take over directory buffers (e.g. `vim .` or `:e src/`) - -- Set to false if you still want to use netrw. + -- Set to false if you want some other plugin (e.g. netrw) to open when you edit directories. default_file_explorer = true, -- Id is automatically added at the beginning, and name at the end -- See :help oil-columns @@ -138,6 +138,8 @@ CONFIG *oil-confi win_options = { winblend = 0, }, + -- preview_split: Split direction: "auto", "left", "right", "above", "below". + preview_split = "auto", -- This is the config that will be passed to nvim_open_win. -- Change values here to customize the layout override = function(conf) diff --git a/lua/oil/actions.lua b/lua/oil/actions.lua index 7fc27ce..6a2a5ff 100644 --- a/lua/oil/actions.lua +++ b/lua/oil/actions.lua @@ -80,6 +80,11 @@ M.preview = { local cur_id = vim.w[winid].oil_entry_id if entry.id == cur_id then vim.api.nvim_win_close(winid, true) + if util.is_floating_win() then + local layout = require("oil.layout") + local win_opts = layout.get_fullscreen_win_opts() + vim.api.nvim_win_set_config(0, win_opts) + end return end end diff --git a/lua/oil/config.lua b/lua/oil/config.lua index 1b6f085..e1dd950 100644 --- a/lua/oil/config.lua +++ b/lua/oil/config.lua @@ -2,7 +2,7 @@ local default_config = { -- Oil will take over directory buffers (e.g. `vim .` or `:e src/`) - -- Set to false if you still want to use netrw. + -- Set to false if you want some other plugin (e.g. netrw) to open when you edit directories. default_file_explorer = true, -- Id is automatically added at the beginning, and name at the end -- See :help oil-columns @@ -123,6 +123,8 @@ local default_config = { win_options = { winblend = 0, }, + -- preview_split: Split direction: "auto", "left", "right", "above", "below". + preview_split = "auto", -- This is the config that will be passed to nvim_open_win. -- Change values here to customize the layout override = function(conf) diff --git a/lua/oil/init.lua b/lua/oil/init.lua index f025085..7bcb3bb 100644 --- a/lua/oil/init.lua +++ b/lua/oil/init.lua @@ -244,6 +244,7 @@ M.open_float = function(dir) local layout = require("oil.layout") local util = require("oil.util") local view = require("oil.view") + local parent_url, basename = M.get_url_for_path(dir) if not parent_url then return @@ -254,31 +255,7 @@ M.open_float = function(dir) local bufnr = vim.api.nvim_create_buf(false, true) vim.bo[bufnr].bufhidden = "wipe" - local total_width = vim.o.columns - local total_height = layout.get_editor_height() - local width = total_width - 2 * config.float.padding - if config.float.border ~= "none" then - width = width - 2 -- The border consumes 1 col on each side - end - if config.float.max_width > 0 then - width = math.min(width, config.float.max_width) - end - local height = total_height - 2 * config.float.padding - if config.float.max_height > 0 then - height = math.min(height, config.float.max_height) - end - local row = math.floor((total_height - height) / 2) - local col = math.floor((total_width - width) / 2) - 1 -- adjust for border width - local win_opts = { - relative = "editor", - width = width, - height = height, - row = row, - col = col, - border = config.float.border, - zindex = 45, - } - win_opts = config.float.override(win_opts) or win_opts + local win_opts = layout.get_fullscreen_win_opts() local original_winid = vim.api.nvim_get_current_win() local winid = vim.api.nvim_open_win(bufnr, true, win_opts) @@ -332,12 +309,13 @@ M.open_float = function(dir) if not vim.api.nvim_win_is_valid(winid) or vim.api.nvim_win_get_buf(winid) ~= winbuf then return end + local cur_win_opts = vim.api.nvim_win_get_config(winid) vim.api.nvim_win_set_config(winid, { relative = "editor", - row = win_opts.row, - col = win_opts.col, - width = win_opts.width, - height = win_opts.height, + row = cur_win_opts.row, + col = cur_win_opts.col, + width = cur_win_opts.width, + height = cur_win_opts.height, title = get_title(), }) end, @@ -444,6 +422,8 @@ end --- split "aboveleft"|"belowright"|"topleft"|"botright" Split modifier M.open_preview = 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) @@ -465,18 +445,59 @@ M.open_preview = function(opts, callback) opts.split = vim.o.splitright and "belowright" or "aboveleft" end end - if util.is_floating_win() then - return finish("oil preview doesn't work in a floating window") - end + + local preview_win = util.get_preview_win() + local prev_win = vim.api.nvim_get_current_win() + local bufnr = vim.api.nvim_get_current_buf() local entry = M.get_cursor_entry() if not entry then return finish("Could not find entry under cursor") end + local entry_title = entry.name + if entry.type == "directory" then + entry_title = entry_title .. "/" + end - local preview_win = util.get_preview_win() - local prev_win = vim.api.nvim_get_current_win() - local bufnr = vim.api.nvim_get_current_buf() + if util.is_floating_win() then + if preview_win == nil then + local root_win_opts, preview_win_opts = + layout.split_window(0, config.float.preview_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 = preview_win_opts.width, + height = preview_win_opts.height, + row = preview_win_opts.row, + col = preview_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 = entry_title + 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 + vim.api.nvim_win_set_config(preview_win, { title = entry_title }) + end + end local cmd = preview_win and "buffer" or "sbuffer" local mods = { @@ -485,7 +506,6 @@ M.open_preview = function(opts, callback) split = opts.split, } - local is_visual_mode = util.is_visual_mode() -- HACK Switching windows takes us out of visual mode. -- Switching with nvim_set_current_win causes the previous visual selection (as used by `gv`) to -- not get set properly. So we have to switch windows this way instead. @@ -494,15 +514,16 @@ M.open_preview = function(opts, callback) vim.cmd.wincmd({ args = { "w" }, count = winnr }) end - if preview_win then - if is_visual_mode then - hack_set_win(preview_win) - else - vim.api.nvim_set_current_win(preview_win) - end - end - util.get_edit_path(bufnr, entry, function(normalized_url) + local is_visual_mode = util.is_visual_mode() + if preview_win then + if is_visual_mode then + hack_set_win(preview_win) + else + vim.api.nvim_set_current_win(preview_win) + end + end + local filebufnr = vim.fn.bufadd(normalized_url) local entry_is_file = not vim.endswith(normalized_url, "/") diff --git a/lua/oil/layout.lua b/lua/oil/layout.lua index b4e3fed..1ed257a 100644 --- a/lua/oil/layout.lua +++ b/lua/oil/layout.lua @@ -93,6 +93,89 @@ M.calculate_height = function(desired_height, opts) ) end +---@class (exact) conform.WinLayout +---@field width integer +---@field height integer +---@field row integer +---@field col integer + +---@return vim.api.keyset.win_config +M.get_fullscreen_win_opts = function() + local config = require("oil.config") + + local total_width = M.get_editor_width() + local total_height = M.get_editor_height() + local width = total_width - 2 * config.float.padding + if config.float.border ~= "none" then + width = width - 2 -- The border consumes 1 col on each side + end + if config.float.max_width > 0 then + width = math.min(width, config.float.max_width) + end + local height = total_height - 2 * config.float.padding + if config.float.max_height > 0 then + height = math.min(height, config.float.max_height) + end + local row = math.floor((total_height - height) / 2) + local col = math.floor((total_width - width) / 2) - 1 -- adjust for border width + + local win_opts = { + relative = "editor", + width = width, + height = height, + row = row, + col = col, + border = config.float.border, + zindex = 45, + } + return config.float.override(win_opts) or win_opts +end + +---@param winid integer +---@param direction "above"|"below"|"left"|"right"|"auto" +---@param gap integer +---@return conform.WinLayout root_dim New dimensions of the original window +---@return conform.WinLayout new_dim New dimensions of the new window +M.split_window = function(winid, direction, gap) + if direction == "auto" then + direction = vim.o.splitright and "right" or "left" + end + + local float_config = vim.api.nvim_win_get_config(winid) + local dim_root = { + width = float_config.width, + height = float_config.height, + col = float_config.col, + row = float_config.row, + } + if vim.fn.has("nvim-0.10") == 0 then + -- read https://github.com/neovim/neovim/issues/24430 for more infos. + dim_root.col = float_config.col[vim.val_idx] + dim_root.row = float_config.row[vim.val_idx] + end + local dim_new = vim.deepcopy(dim_root) + + if direction == "left" or direction == "right" then + dim_new.width = math.floor(float_config.width / 2) - math.ceil(gap / 2) + dim_root.width = dim_new.width + else + dim_new.height = math.floor(float_config.height / 2) - math.ceil(gap / 2) + dim_root.height = dim_new.height + end + + if direction == "left" then + dim_root.col = dim_root.col + dim_root.width + gap + elseif direction == "right" then + dim_new.col = dim_new.col + dim_new.width + gap + elseif direction == "above" then + dim_root.row = dim_root.row + dim_root.height + gap + elseif direction == "below" then + dim_new.row = dim_new.row + dim_new.height + gap + end + + return dim_root, dim_new +end + M.calculate_dims = function(desired_width, desired_height, opts) local width = M.calculate_width(desired_width, opts) local height = M.calculate_height(desired_height, opts)