Skip to content

Commit

Permalink
feat: use scratch buffer for file previews (#467)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
jelmansouri and stevearc authored Nov 20, 2024
1 parent 8ea40b5 commit 21705a1
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 21 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ require("oil").setup({
preview_win = {
-- Whether the preview window is automatically updated when the cursor is moved
update_on_cursor_moved = true,
-- Maximum file size in megabytes to preview
max_file_size_mb = 100,
-- How to open the preview window "load"|"scratch"|"fast_scratch"
preview_method = "fast_scratch",
-- Window-local options to use for preview window buffers
win_options = {},
},
Expand Down
4 changes: 2 additions & 2 deletions doc/oil.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ CONFIG *oil-confi
preview_win = {
-- Whether the preview window is automatically updated when the cursor is moved
update_on_cursor_moved = true,
-- Maximum file size in megabytes to preview
max_file_size_mb = 100,
-- How to open the preview window "load"|"scratch"|"fast_scratch"
preview_method = "fast_scratch",
-- Window-local options to use for preview window buffers
win_options = {},
},
Expand Down
13 changes: 9 additions & 4 deletions lua/oil/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ local default_config = {
preview_win = {
-- Whether the preview window is automatically updated when the cursor is moved
update_on_cursor_moved = true,
-- Maximum file size in megabytes to preview
max_file_size_mb = 100,
-- How to open the preview window "load"|"scratch"|"fast_scratch"
preview_method = "fast_scratch",
-- Window-local options to use for preview window buffers
win_options = {},
},
Expand Down Expand Up @@ -326,16 +326,21 @@ local M = {}
---@field border? string|string[] Window border
---@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
---@field update_on_cursor_moved boolean
---@field max_file_size_mb number
---@field preview_method oil.PreviewMethod
---@field win_options table<string, any>

---@class (exact) oil.ConfirmationWindowConfig : oil.WindowConfig

---@class (exact) oil.SetupPreviewWindowConfig
---@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

---@class (exact) oil.SetupConfirmationWindowConfig : oil.SetupWindowConfig
Expand Down
24 changes: 11 additions & 13 deletions lua/oil/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -452,13 +452,6 @@ M.open_preview = function(opts, callback)
if not entry then
return finish("Could not find entry under cursor")
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
if entry.type == "directory" then
entry_title = entry_title .. "/"
Expand Down Expand Up @@ -529,14 +522,19 @@ M.open_preview = function(opts, callback)
end
end

local filebufnr = vim.fn.bufadd(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
-- we close the window
if entry_is_file and vim.fn.bufloaded(filebufnr) == 0 then
vim.bo[filebufnr].bufhidden = "wipe"
vim.b[filebufnr].oil_preview_buffer = true
if not filebufnr then
filebufnr = vim.fn.bufadd(normalized_url)
if entry_is_file and vim.fn.bufloaded(filebufnr) == 0 then
vim.bo[filebufnr].bufhidden = "wipe"
vim.b[filebufnr].oil_preview_buffer = true
end
end

---@diagnostic disable-next-line: param-type-mismatch
Expand Down
55 changes: 55 additions & 0 deletions lua/oil/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -897,4 +897,59 @@ M.get_icon_provider = function()
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

5 comments on commit 21705a1

@forestchen1224
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems after this commit,the preview of image that use image.nvim does not work anymore

@pkazmier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps try changing the value of preview_method in your config to load or scratch? The default of fast_scratch does not load the whole file for efficiency purposes.

@forestchen1224
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right,changing the preview_method to load fix the problem.

@stevearc
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed the image.nvim preview issue when preview_method="scratch", but this now means that a large image can freeze the UI again even when preview_method="scratch". To combat this, I've added another config option that will allow you to define a function to determine if previews should be enabled for a specific file. If you find that images are lagging, you can disable previews on them or you can check their size and disable previews for large images.

@forestchen1224
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works well.

Please sign in to comment.