Skip to content

Commit

Permalink
feat: config for floating preview window (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevearc committed Mar 19, 2023
1 parent 6d9b1e5 commit 3e1affa
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 17 deletions.
23 changes: 23 additions & 0 deletions lua/oil/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,29 @@ local default_config = {
winblend = 10,
},
},
-- Configuration for the actions floating preview window
preview = {
-- Width dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%)
-- min_width and max_width can be a single value or a list of mixed integer/float types.
-- max_width = {100, 0.8} means "the lesser of 100 columns or 80% of total"
max_width = 0.9,
-- min_width = {40, 0.4} means "the greater of 40 columns or 40% of total"
min_width = { 40, 0.4 },
-- optionally define an integer/float for the exact width of the preview window
width = nil,
-- Height dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%)
-- min_height and max_height can be a single value or a list of mixed integer/float types.
-- max_height = {80, 0.9} means "the lesser of 80 columns or 90% of total"
max_height = 0.9,
-- min_height = {5, 0.1} means "the greater of 5 columns or 10% of total"
min_height = { 5, 0.1 },
-- optionally define an integer/float for the exact height of the preview window
height = nil,
border = "rounded",
win_options = {
winblend = 0,
},
},
}

-- The adapter API hasn't really stabilized yet. We're not ready to advertise or encourage people to
Expand Down
100 changes: 100 additions & 0 deletions lua/oil/layout.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
local M = {}

local function is_float(value)
local _, p = math.modf(value)
return p ~= 0
end

local function calc_float(value, max_value)
if value and is_float(value) then
return math.min(max_value, value * max_value)
else
return value
end
end

M.get_editor_width = function()
return vim.o.columns
end

M.get_editor_height = function()
local editor_height = vim.o.lines - vim.o.cmdheight
-- Subtract 1 if tabline is visible
if vim.o.showtabline == 2 or (vim.o.showtabline == 1 and #vim.api.nvim_list_tabpages() > 1) then
editor_height = editor_height - 1
end
-- Subtract 1 if statusline is visible
if
vim.o.laststatus >= 2 or (vim.o.laststatus == 1 and #vim.api.nvim_tabpage_list_wins(0) > 1)
then
editor_height = editor_height - 1
end
return editor_height
end

local function calc_list(values, max_value, aggregator, limit)
local ret = limit
if not max_value or not values then
return nil
elseif type(values) == "table" then
for _, v in ipairs(values) do
ret = aggregator(ret, calc_float(v, max_value))
end
return ret
else
ret = aggregator(ret, calc_float(values, max_value))
end
return ret
end

local function calculate_dim(desired_size, exact_size, min_size, max_size, total_size)
local ret = calc_float(exact_size, total_size)
local min_val = calc_list(min_size, total_size, math.max, 1)
local max_val = calc_list(max_size, total_size, math.min, total_size)
if not ret then
if not desired_size then
if min_val and max_val then
ret = (min_val + max_val) / 2
else
ret = 80
end
else
ret = calc_float(desired_size, total_size)
end
end
if max_val then
ret = math.min(ret, max_val)
end
if min_val then
ret = math.max(ret, min_val)
end
return math.floor(ret)
end

M.calculate_width = function(desired_width, opts)
return calculate_dim(
desired_width,
opts.width,
opts.min_width,
opts.max_width,
M.get_editor_width()
)
end

M.calculate_height = function(desired_height, opts)
return calculate_dim(
desired_height,
opts.height,
opts.min_height,
opts.max_height,
M.get_editor_height()
)
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)
return width, height
end

return M
54 changes: 37 additions & 17 deletions lua/oil/mutator/preview.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local columns = require("oil.columns")
local config = require("oil.config")
local layout = require("oil.layout")
local util = require("oil.util")
local M = {}

Expand Down Expand Up @@ -44,6 +45,8 @@ end
---@param should_confirm nil|boolean
---@param cb fun(proceed: boolean)
M.show = vim.schedule_wrap(function(actions, should_confirm, cb)
-- The schedule wrap ensures that we actually enter the floating window.
-- Not sure why it doesn't work without that
if should_confirm == false or #actions == 0 then
cb(true)
return
Expand All @@ -52,36 +55,52 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb)
cb(true)
return
end
-- The schedule wrap ensures that we actually enter the floating window.
-- Not sure why it doesn't work without that

-- Create the buffer
local bufnr = vim.api.nvim_create_buf(false, true)
vim.bo[bufnr].bufhidden = "wipe"
local width = 120
local height = 40
local lines = {}
local max_line_width = 0
for _, action in ipairs(actions) do
local adapter = util.get_adapter_for_action(action)
local line
if action.type == "change" then
line = columns.render_change_action(adapter, action)
else
line = adapter.render_action(action)
end
table.insert(lines, line)
local line_width = vim.api.nvim_strwidth(line)
if line_width > max_line_width then
max_line_width = line_width
end
end
table.insert(lines, "")

-- Create the floating window
local width, height = layout.calculate_dims(max_line_width, #lines + 1, config.preview)
local winid = vim.api.nvim_open_win(bufnr, true, {
relative = "editor",
width = width,
height = height,
row = math.floor((vim.o.lines - vim.o.cmdheight - height) / 2),
col = math.floor((vim.o.columns - width) / 2),
row = math.floor((layout.get_editor_height() - height) / 2),
col = math.floor((layout.get_editor_width() - width) / 2),
zindex = 152, -- render on top of the floating window title
style = "minimal",
border = "rounded",
border = config.preview.border,
})
vim.bo[bufnr].filetype = "oil_preview"
vim.bo[bufnr].syntax = "oil_preview"

local lines = {}
for _, action in ipairs(actions) do
local adapter = util.get_adapter_for_action(action)
if action.type == "change" then
table.insert(lines, columns.render_change_action(adapter, action))
else
table.insert(lines, adapter.render_action(action))
end
for k, v in pairs(config.preview.win_options) do
vim.api.nvim_win_set_option(winid, k, v)
end
table.insert(lines, "")

-- Finish setting the last line and highlights on the buffer
width = vim.api.nvim_win_get_width(0)
height = vim.api.nvim_win_get_height(0)
while #lines < height - 1 do
table.insert(lines, "")
end
local last_line = "[O]k [C]ancel"
local highlights = {}
local padding = string.rep(" ", math.floor((width - last_line:len()) / 2))
Expand All @@ -97,6 +116,7 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb)
vim.api.nvim_buf_add_highlight(bufnr, ns, unpack(hl))
end

-- Attach autocmds and keymaps
local cancel
local confirm
local function make_callback(value)
Expand Down

0 comments on commit 3e1affa

Please sign in to comment.