From b14de80d1cdf66f988f6550ca8577c43bb3797cd Mon Sep 17 00:00:00 2001 From: James Trew <66286082+jamestrew@users.noreply.github.com> Date: Sat, 1 Jul 2023 13:57:00 -0400 Subject: [PATCH] refactor(previewer): clean up file_maker (#2585) - split apart functions - replace magic numbers with named constants - reorganize functions for better grouping --- lua/telescope/previewers/buffer_previewer.lua | 254 +++++++++--------- 1 file changed, 125 insertions(+), 129 deletions(-) diff --git a/lua/telescope/previewers/buffer_previewer.lua b/lua/telescope/previewers/buffer_previewer.lua index 37cd994..5f92ac9 100644 --- a/lua/telescope/previewers/buffer_previewer.lua +++ b/lua/telescope/previewers/buffer_previewer.lua @@ -155,6 +155,131 @@ local handle_directory_preview = function(filepath, bufnr, opts) }) end +local handle_file_preview = function(filepath, bufnr, stat, opts) + vim.schedule(function() + opts.ft = opts.use_ft_detect and putils.filetype_detect(filepath) + local possible_binary = false + if type(opts.preview.filetype_hook) == "function" and opts.ft ~= nil and opts.ft ~= "" then + if not opts.preview.filetype_hook(filepath, bufnr, opts) then + return + end + end + if opts.preview.check_mime_type == true and has_file and (opts.ft == nil or opts.ft == "") then + -- avoid SIGABRT in buffer previewer happening with utils.get_os_command_output + local output = capture(string.format([[file --mime-type -b "%s"]], filepath)) + local mime_type = vim.split(output, "/") + if mime_type[1] ~= "text" and mime_type[1] ~= "inode" and mime_type[2] ~= "json" then + if type(opts.preview.mime_hook) == "function" then + opts.preview.mime_hook(filepath, bufnr, opts) + return + else + possible_binary = true + end + end + if mime_type[2] == "json" then + opts.ft = "json" + end + end + + if opts.preview.filesize_limit then + local mb_filesize = math.floor(stat.size / bytes_to_megabytes) + if mb_filesize > opts.preview.filesize_limit then + if type(opts.preview.filesize_hook) == "function" then + opts.preview.filesize_hook(filepath, bufnr, opts) + else + putils.set_preview_message(bufnr, opts.winid, "File exceeds preview size limit", opts.preview.msg_bg_fillchar) + end + return + end + end + + opts.start_time = vim.loop.hrtime() + Path:new(filepath):_read_async(vim.schedule_wrap(function(data) + if not vim.api.nvim_buf_is_valid(bufnr) then + return + end + local processed_data = split(data, "[\r]?\n", nil, opts) + + if processed_data then + local ok = pcall(vim.api.nvim_buf_set_lines, bufnr, 0, -1, false, processed_data) + if not ok then + return + end + -- last resort, if ft is still empty at this point in time, + -- we need to determine the filetype using the buffer contents + if opts.ft == nil or opts.ft == "" then + opts.ft = vim.filetype.match { filename = filepath, buf = bufnr } + end + -- we need to attempt to call filetype hook at this point "again" + -- previously only if we had a valid filetype, now every time + -- also if there will never be a filetype + if type(opts.preview.filetype_hook) == "function" then + if not opts.preview.filetype_hook(filepath, bufnr, opts) then + return + end + end + -- if we still dont have a ft we need to display the binary message + if (opts.ft == nil or opts.ft == "") and possible_binary then + putils.set_preview_message(bufnr, opts.winid, "Binary cannot be previewed", opts.preview.msg_bg_fillchar) + return + end + + if opts.callback then + opts.callback(bufnr) + end + putils.highlighter(bufnr, opts.ft, opts) + else + if type(opts.preview.timeout_hook) == "function" then + opts.preview.timeout_hook(filepath, bufnr, opts) + else + putils.set_preview_message(bufnr, opts.winid, "Previewer timed out", opts.preview.msg_bg_fillchar) + end + return + end + end)) + end) +end + +local PREVIEW_TIMEOUT_MS = 250 +local PREVIEW_FILESIZE_MB = 25 + +previewers.file_maker = function(filepath, bufnr, opts) + opts = vim.F.if_nil(opts, {}) + opts.preview = vim.F.if_nil(opts.preview, {}) + opts.preview.timeout = vim.F.if_nil(opts.preview.timeout, PREVIEW_TIMEOUT_MS) + opts.preview.filesize_limit = vim.F.if_nil(opts.preview.filesize_limit, PREVIEW_FILESIZE_MB) + opts.preview.msg_bg_fillchar = vim.F.if_nil(opts.preview.msg_bg_fillchar, "╱") + opts.preview.treesitter = vim.F.if_nil(opts.preview.treesitter, true) + if opts.use_ft_detect == nil then + opts.use_ft_detect = true + end + if opts.bufname ~= filepath then + if not vim.in_fast_event() then + filepath = vim.fn.expand(filepath) + end + vim.loop.fs_stat(filepath, function(_, stat) + if not stat then + return + end + if stat.type == "directory" then + handle_directory_preview(filepath, bufnr, opts) + else + handle_file_preview(filepath, bufnr, stat, opts) + end + end) + else + if opts.callback then + if vim.in_fast_event() then + vim.schedule(function() + opts.callback(bufnr) + end) + else + opts.callback(bufnr) + end + end + end +end + local search_cb_jump = function(self, bufnr, query) if not query then return @@ -202,135 +327,6 @@ local scroll_horizontal_fn = function(self, direction) end) end -previewers.file_maker = function(filepath, bufnr, opts) - opts = vim.F.if_nil(opts, {}) - -- TODO(conni2461): here shouldn't be any hardcoded magic numbers ... - opts.preview = vim.F.if_nil(opts.preview, {}) - opts.preview.timeout = vim.F.if_nil(opts.preview.timeout, 250) -- in ms - opts.preview.filesize_limit = vim.F.if_nil(opts.preview.filesize_limit, 25) -- in mb - opts.preview.msg_bg_fillchar = vim.F.if_nil(opts.preview.msg_bg_fillchar, "╱") -- in mb - opts.preview.treesitter = vim.F.if_nil(opts.preview.treesitter, true) - if opts.use_ft_detect == nil then - opts.use_ft_detect = true - end - if opts.bufname ~= filepath then - if not vim.in_fast_event() then - filepath = vim.fn.expand(filepath) - end - vim.loop.fs_stat(filepath, function(_, stat) - if not stat then - return - end - if stat.type == "directory" then - handle_directory_preview(filepath, bufnr, opts) - else - vim.schedule(function() - opts.ft = opts.use_ft_detect and putils.filetype_detect(filepath) - local possible_binary = false - if type(opts.preview.filetype_hook) == "function" and opts.ft ~= nil and opts.ft ~= "" then - if not opts.preview.filetype_hook(filepath, bufnr, opts) then - return - end - end - if opts.preview.check_mime_type == true and has_file and (opts.ft == nil or opts.ft == "") then - -- avoid SIGABRT in buffer previewer happening with utils.get_os_command_output - local output = capture(string.format([[file --mime-type -b "%s"]], filepath)) - local mime_type = vim.split(output, "/") - if mime_type[1] ~= "text" and mime_type[1] ~= "inode" and mime_type[2] ~= "json" then - if type(opts.preview.mime_hook) == "function" then - opts.preview.mime_hook(filepath, bufnr, opts) - return - else - possible_binary = true - end - end - if mime_type[2] == "json" then - opts.ft = "json" - end - end - - if opts.preview.filesize_limit then - local mb_filesize = math.floor(stat.size / bytes_to_megabytes) - if mb_filesize > opts.preview.filesize_limit then - if type(opts.preview.filesize_hook) == "function" then - opts.preview.filesize_hook(filepath, bufnr, opts) - else - putils.set_preview_message( - bufnr, - opts.winid, - "File exceeds preview size limit", - opts.preview.msg_bg_fillchar - ) - end - return - end - end - - opts.start_time = vim.loop.hrtime() - Path:new(filepath):_read_async(vim.schedule_wrap(function(data) - if not vim.api.nvim_buf_is_valid(bufnr) then - return - end - local processed_data = split(data, "[\r]?\n", _, opts) - - if processed_data then - local ok = pcall(vim.api.nvim_buf_set_lines, bufnr, 0, -1, false, processed_data) - if not ok then - return - end - -- last resort, if ft is still empty at this point in time, - -- we need to determine the filetype using the buffer contents - if opts.ft == nil or opts.ft == "" then - opts.ft = vim.filetype.match { filename = filepath, buf = bufnr } - end - -- we need to attempt to call filetype hook at this point "again" - -- previously only if we had a valid filetype, now every time - -- also if there will never be a filetype - if type(opts.preview.filetype_hook) == "function" then - if not opts.preview.filetype_hook(filepath, bufnr, opts) then - return - end - end - -- if we still dont have a ft we need to display the binary message - if (opts.ft == nil or opts.ft == "") and possible_binary then - putils.set_preview_message( - bufnr, - opts.winid, - "Binary cannot be previewed", - opts.preview.msg_bg_fillchar - ) - return - end - - if opts.callback then - opts.callback(bufnr) - end - putils.highlighter(bufnr, opts.ft, opts) - else - if type(opts.preview.timeout_hook) == "function" then - opts.preview.timeout_hook(filepath, bufnr, opts) - else - putils.set_preview_message(bufnr, opts.winid, "Previewer timed out", opts.preview.msg_bg_fillchar) - end - return - end - end)) - end) - end - end) - else - if opts.callback then - if vim.in_fast_event() then - vim.schedule(function() - opts.callback(bufnr) - end) - else - opts.callback(bufnr) - end - end - end -end - previewers.new_buffer_previewer = function(opts) opts = opts or {}