Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/preview in floating window #403

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ You can open a directory with `:edit <path>` or `:Oil <path>`. 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
Expand Down Expand Up @@ -247,6 +247,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)
Expand Down
4 changes: 3 additions & 1 deletion doc/oil.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions lua/oil/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,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
Expand Down
4 changes: 3 additions & 1 deletion lua/oil/config.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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
Expand Down Expand Up @@ -121,6 +121,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)
Expand Down
107 changes: 64 additions & 43 deletions lua/oil/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,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
Expand All @@ -255,31 +256,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)
Expand Down Expand Up @@ -333,12 +310,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,
Expand Down Expand Up @@ -445,6 +423,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)
Expand All @@ -466,18 +446,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 = {
Expand All @@ -486,7 +507,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.
Expand All @@ -495,15 +515,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)
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
end

util.get_edit_path(bufnr, entry, function(normalized_url)
local filebufnr = vim.fn.bufadd(normalized_url)
local entry_is_file = not vim.endswith(normalized_url, "/")

Expand Down
83 changes: 83 additions & 0 deletions lua/oil/layout.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down