feat: use scratch buffer for file previews (#467)
* Initial implementation of scratch based preview * Fix call to buf is valid in loop * Fixing call to be made only from the main event loop * Improve handling of large files from @pkazmier * Better error handling and simplifying the code * Default to old behavior * Add documentation * Fix readfile * Fix the configuration * refactor: single config enum and load real buffer on BufEnter * doc: regenerate documentation --------- Co-authored-by: Steven Arcangeli <stevearc@stevearc.com>
This commit is contained in:
parent
8ea40b5506
commit
21705a1deb
5 changed files with 79 additions and 21 deletions
|
|
@ -272,8 +272,8 @@ require("oil").setup({
|
||||||
preview_win = {
|
preview_win = {
|
||||||
-- Whether the preview window is automatically updated when the cursor is moved
|
-- Whether the preview window is automatically updated when the cursor is moved
|
||||||
update_on_cursor_moved = true,
|
update_on_cursor_moved = true,
|
||||||
-- Maximum file size in megabytes to preview
|
-- How to open the preview window "load"|"scratch"|"fast_scratch"
|
||||||
max_file_size_mb = 100,
|
preview_method = "fast_scratch",
|
||||||
-- Window-local options to use for preview window buffers
|
-- Window-local options to use for preview window buffers
|
||||||
win_options = {},
|
win_options = {},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -157,8 +157,8 @@ CONFIG *oil-confi
|
||||||
preview_win = {
|
preview_win = {
|
||||||
-- Whether the preview window is automatically updated when the cursor is moved
|
-- Whether the preview window is automatically updated when the cursor is moved
|
||||||
update_on_cursor_moved = true,
|
update_on_cursor_moved = true,
|
||||||
-- Maximum file size in megabytes to preview
|
-- How to open the preview window "load"|"scratch"|"fast_scratch"
|
||||||
max_file_size_mb = 100,
|
preview_method = "fast_scratch",
|
||||||
-- Window-local options to use for preview window buffers
|
-- Window-local options to use for preview window buffers
|
||||||
win_options = {},
|
win_options = {},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -142,8 +142,8 @@ local default_config = {
|
||||||
preview_win = {
|
preview_win = {
|
||||||
-- Whether the preview window is automatically updated when the cursor is moved
|
-- Whether the preview window is automatically updated when the cursor is moved
|
||||||
update_on_cursor_moved = true,
|
update_on_cursor_moved = true,
|
||||||
-- Maximum file size in megabytes to preview
|
-- How to open the preview window "load"|"scratch"|"fast_scratch"
|
||||||
max_file_size_mb = 100,
|
preview_method = "fast_scratch",
|
||||||
-- Window-local options to use for preview window buffers
|
-- Window-local options to use for preview window buffers
|
||||||
win_options = {},
|
win_options = {},
|
||||||
},
|
},
|
||||||
|
|
@ -326,16 +326,21 @@ local M = {}
|
||||||
---@field border? string|string[] Window border
|
---@field border? string|string[] Window border
|
||||||
---@field win_options? table<string, any>
|
---@field win_options? table<string, any>
|
||||||
|
|
||||||
|
---@alias oil.PreviewMethod
|
||||||
|
---| '"load"' # Load the previewed file into a buffer
|
||||||
|
---| '"scratch"' # Put the text into a scratch buffer to avoid LSP attaching
|
||||||
|
---| '"fast_scratch"' # Put only the visible text into a scratch buffer
|
||||||
|
|
||||||
---@class (exact) oil.PreviewWindowConfig
|
---@class (exact) oil.PreviewWindowConfig
|
||||||
---@field update_on_cursor_moved boolean
|
---@field update_on_cursor_moved boolean
|
||||||
---@field max_file_size_mb number
|
---@field preview_method oil.PreviewMethod
|
||||||
---@field win_options table<string, any>
|
---@field win_options table<string, any>
|
||||||
|
|
||||||
---@class (exact) oil.ConfirmationWindowConfig : oil.WindowConfig
|
---@class (exact) oil.ConfirmationWindowConfig : oil.WindowConfig
|
||||||
|
|
||||||
---@class (exact) oil.SetupPreviewWindowConfig
|
---@class (exact) oil.SetupPreviewWindowConfig
|
||||||
---@field update_on_cursor_moved? boolean Whether the preview window is automatically updated when the cursor is moved
|
---@field update_on_cursor_moved? boolean Whether the preview window is automatically updated when the cursor is moved
|
||||||
---@field max_file_size_mb? number Maximum file size in megabytes to preview
|
---@field preview_method? oil.PreviewMethod How to open the preview window
|
||||||
---@field win_options? table<string, any> Window-local options to use for preview window buffers
|
---@field win_options? table<string, any> Window-local options to use for preview window buffers
|
||||||
|
|
||||||
---@class (exact) oil.SetupConfirmationWindowConfig : oil.SetupWindowConfig
|
---@class (exact) oil.SetupConfirmationWindowConfig : oil.SetupWindowConfig
|
||||||
|
|
|
||||||
|
|
@ -452,13 +452,6 @@ M.open_preview = function(opts, callback)
|
||||||
if not entry then
|
if not entry then
|
||||||
return finish("Could not find entry under cursor")
|
return finish("Could not find entry under cursor")
|
||||||
end
|
end
|
||||||
if entry.meta ~= nil and entry.meta.stat ~= nil then
|
|
||||||
if entry.meta.stat.size >= config.preview_win.max_file_size_mb * 1e6 then
|
|
||||||
return finish(
|
|
||||||
"File over " .. config.preview_win.max_file_size_mb .. "MB is too large to preview"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local entry_title = entry.name
|
local entry_title = entry.name
|
||||||
if entry.type == "directory" then
|
if entry.type == "directory" then
|
||||||
entry_title = entry_title .. "/"
|
entry_title = entry_title .. "/"
|
||||||
|
|
@ -529,15 +522,20 @@ M.open_preview = function(opts, callback)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local filebufnr = vim.fn.bufadd(normalized_url)
|
|
||||||
local entry_is_file = not vim.endswith(normalized_url, "/")
|
local entry_is_file = not vim.endswith(normalized_url, "/")
|
||||||
|
local filebufnr
|
||||||
|
if entry_is_file and config.preview_win.preview_method ~= "load" then
|
||||||
|
filebufnr =
|
||||||
|
util.read_file_to_scratch_buffer(normalized_url, config.preview_win.preview_method)
|
||||||
|
end
|
||||||
|
|
||||||
-- If we're previewing a file that hasn't been opened yet, make sure it gets deleted after
|
if not filebufnr then
|
||||||
-- we close the window
|
filebufnr = vim.fn.bufadd(normalized_url)
|
||||||
if entry_is_file and vim.fn.bufloaded(filebufnr) == 0 then
|
if entry_is_file and vim.fn.bufloaded(filebufnr) == 0 then
|
||||||
vim.bo[filebufnr].bufhidden = "wipe"
|
vim.bo[filebufnr].bufhidden = "wipe"
|
||||||
vim.b[filebufnr].oil_preview_buffer = true
|
vim.b[filebufnr].oil_preview_buffer = true
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---@diagnostic disable-next-line: param-type-mismatch
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
local ok, err = pcall(vim.cmd, {
|
local ok, err = pcall(vim.cmd, {
|
||||||
|
|
|
||||||
|
|
@ -897,4 +897,59 @@ M.get_icon_provider = function()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Read a buffer into a scratch buffer and apply syntactic highlighting when possible
|
||||||
|
---@param path string The path to the file to read
|
||||||
|
---@param preview_method oil.PreviewMethod
|
||||||
|
---@return nil|integer
|
||||||
|
M.read_file_to_scratch_buffer = function(path, preview_method)
|
||||||
|
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||||
|
if bufnr == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.bo[bufnr].bufhidden = "wipe"
|
||||||
|
vim.bo[bufnr].buftype = "nofile"
|
||||||
|
|
||||||
|
local max_lines = preview_method == "fast_scratch" and vim.o.lines or nil
|
||||||
|
local has_lines, read_res = pcall(vim.fn.readfile, path, "", max_lines)
|
||||||
|
local lines = has_lines and vim.split(table.concat(read_res, "\n"), "\n") or {}
|
||||||
|
|
||||||
|
local ok = pcall(vim.api.nvim_buf_set_lines, bufnr, 0, -1, false, lines)
|
||||||
|
if not ok then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local ft = vim.filetype.match({ filename = path, buf = bufnr })
|
||||||
|
if ft and ft ~= "" then
|
||||||
|
local lang = vim.treesitter.language.get_lang(ft)
|
||||||
|
if not pcall(vim.treesitter.start, bufnr, lang) then
|
||||||
|
vim.bo[bufnr].syntax = ft
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Replace the scratch buffer with a real buffer if we enter it
|
||||||
|
vim.api.nvim_create_autocmd("BufEnter", {
|
||||||
|
desc = "oil.nvim replace scratch buffer with real buffer",
|
||||||
|
buffer = bufnr,
|
||||||
|
callback = function()
|
||||||
|
local winid = vim.api.nvim_get_current_win()
|
||||||
|
-- Have to schedule this so all the FileType, etc autocmds will fire
|
||||||
|
vim.schedule(function()
|
||||||
|
if vim.api.nvim_get_current_win() == winid then
|
||||||
|
vim.cmd.edit({ args = { path } })
|
||||||
|
|
||||||
|
-- If we're still in a preview window, make sure this buffer still gets treated as a
|
||||||
|
-- preview
|
||||||
|
if vim.wo.previewwindow then
|
||||||
|
vim.bo.bufhidden = "wipe"
|
||||||
|
vim.b.oil_preview_buffer = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
return bufnr
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue