Skip to content

Commit

Permalink
feat!(previewer): replace plenary.filetype with vim.filetype.match
Browse files Browse the repository at this point in the history
  • Loading branch information
Conni2461 committed Jun 7, 2023
1 parent 9e3922f commit abe3027
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 84 deletions.
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,13 +390,15 @@ Built-in functions. Ready to be bound to any key you like.
The default previewers are from now on `vim_buffer_` previewers. They use vim
buffers for displaying files and use tree-sitter or regex for file highlighting.

These previewers are guessing the filetype of the selected file, so there might
be cases where they miss, leading to wrong highlights. This is because we can't
determine the filetype in the traditional way: We don't do `bufload` and instead
read the file asynchronously with `vim.loop.fs_` and attach only a highlighter;
otherwise the speed of the previewer would slow down considerably. If you want
to configure more filetypes, take a look at
[plenary wiki](https://github.com/nvim-lua/plenary.nvim#plenaryfiletype).
These previewers are using `vim.filetype` to guess the filetype for the
selected file. The guessing is done by inspecting the filename, the head of the
file(shebang) and the tail of the file (modeline). If you have trouble with
filetype detection you should read `:help vim.filetype`.

We need to do it manually because we can't determine the filetype in the
traditional way: We don't do `bufload` and instead read the file asynchronously
with `vim.loop.fs_` and attach only a highlighter; otherwise the speed of the
previewer would slow down considerably.

If you want to configure the `vim_buffer_` previewer (e.g. you want the line to wrap), do this:

Expand Down
13 changes: 6 additions & 7 deletions doc/telescope.txt
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,8 @@ telescope.setup({opts}) *telescope.setup()*

Fields:
- check_mime_type: Use `file` if available to try to infer whether the
file to preview is a binary if plenary's
filetype detection fails.
file to preview is a binary if filetype
detection fails.
Windows users get `file` from:
https://github.com/julian-r/file-windows
Set to false to attempt to preview any mime type.
Expand Down Expand Up @@ -496,11 +496,10 @@ telescope.setup({opts}) *telescope.setup()*
end,
}
The configuration recipes for relevant examples.
Note: if plenary does not recognize your filetype yet --
1) Please consider contributing to:
$PLENARY_REPO/data/plenary/filetypes/builtin.lua
2) Register your filetype locally as per link
https://github.com/nvim-lua/plenary.nvim#plenaryfiletype
Note: we use vim.filetype filetype detection,
so if you have troubles with files not
highlighting correctly, please read
|vim.filetype|
Default: nil
- treesitter: Determines whether the previewer performs treesitter
highlighting, which falls back to regex-based highlighting.
Expand Down
13 changes: 6 additions & 7 deletions lua/telescope/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,8 @@ append(
Fields:
- check_mime_type: Use `file` if available to try to infer whether the
file to preview is a binary if plenary's
filetype detection fails.
file to preview is a binary if filetype
detection fails.
Windows users get `file` from:
https://github.com/julian-r/file-windows
Set to false to attempt to preview any mime type.
Expand Down Expand Up @@ -594,11 +594,10 @@ append(
end,
}
The configuration recipes for relevant examples.
Note: if plenary does not recognize your filetype yet --
1) Please consider contributing to:
$PLENARY_REPO/data/plenary/filetypes/builtin.lua
2) Register your filetype locally as per link
https://github.com/nvim-lua/plenary.nvim#plenaryfiletype
Note: we use vim.filetype filetype detection,
so if you have troubles with files not
highlighting correctly, please read
|vim.filetype|
Default: nil
- treesitter: Determines whether the previewer performs treesitter
highlighting, which falls back to regex-based highlighting.
Expand Down
122 changes: 59 additions & 63 deletions lua/telescope/previewers/buffer_previewer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ local putils = require "telescope.previewers.utils"
local Previewer = require "telescope.previewers.previewer"
local conf = require("telescope.config").values

local pfiletype = require "plenary.filetype"
local pscan = require "plenary.scandir"

local buf_delete = utils.buf_delete
Expand Down Expand Up @@ -201,7 +200,6 @@ previewers.file_maker = function(filepath, bufnr, opts)
if opts.use_ft_detect == nil then
opts.use_ft_detect = true
end
opts.ft = opts.use_ft_detect and pfiletype.detect(filepath)
if opts.bufname ~= filepath then
if not vim.in_fast_event() then
filepath = vim.fn.expand(filepath)
Expand All @@ -218,76 +216,74 @@ previewers.file_maker = function(filepath, bufnr, opts)
if stat.type == "directory" then
handle_directory_preview(filepath, bufnr, opts)
else
if opts.preview.check_mime_type == true and has_file and 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
vim.schedule_wrap(opts.preview.mime_hook)(filepath, bufnr, opts)
else
vim.schedule_wrap(putils.set_preview_message)(
bufnr,
opts.winid,
"Binary cannot be previewed",
opts.preview.msg_bg_fillchar
)
vim.schedule(function()
opts.ft = opts.use_ft_detect and putils.filetype_detect(filepath)
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)
else
putils.set_preview_message(
bufnr,
opts.winid,
"Binary cannot be previewed",
opts.preview.msg_bg_fillchar
)
end
return
end
return
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
vim.schedule_wrap(opts.preview.filesize_hook)(filepath, bufnr, opts)
else
vim.schedule_wrap(putils.set_preview_message)(
bufnr,
opts.winid,
"File exceeds preview size limit",
opts.preview.msg_bg_fillchar
)
if mime_type[2] == "json" then
opts.ft = "json"
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
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
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
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 opts.callback then
opts.callback(bufnr)
end
putils.highlighter(bufnr, opts.ft, opts)
else
if type(opts.preview.timeout_hook) == "function" then
vim.schedule_wrap(opts.preview.timeout_hook)(filepath, bufnr, 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

if opts.callback then
opts.callback(bufnr)
end
putils.highlighter(bufnr, opts.ft, opts)
else
vim.schedule_wrap(putils.set_preview_message)(
bufnr,
opts.winid,
"Previewer timed out",
opts.preview.msg_bg_fillchar
)
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
return
end
end))
end))
end)
end
end)
else
Expand Down Expand Up @@ -431,7 +427,7 @@ previewers.new_buffer_previewer = function(opts)
data = {
title = entry.preview_title,
bufname = self.state.bufname,
filetype = pfiletype.detect(self.state.bufname or ""),
filetype = putils.filetype_detect(self.state.bufname or ""),
},
})
end)
Expand Down Expand Up @@ -851,7 +847,7 @@ previewers.git_commit_diff_as_was = defaulter(function(opts)
local cmd = { "git", "--no-pager", "show" }
local cf = opts.current_file and Path:new(opts.current_file):make_relative(opts.cwd)
local value = cf and (entry.value .. ":" .. cf) or entry.value
local ft = cf and pfiletype.detect(value) or "diff"
local ft = cf and putils.filetype_detect(value) or "diff"
table.insert(cmd, value)

putils.job_maker(cmd, self.state.bufnr, {
Expand Down
46 changes: 46 additions & 0 deletions lua/telescope/previewers/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,55 @@ local strings = require "plenary.strings"
local conf = require("telescope.config").values

local Job = require "plenary.job"
local Path = require "plenary.path"

local utils = {}

local detect_from_shebang = function(p)
local s = p:readbyterange(0, 256)
if not s then
local lines = vim.split(s, "\n")
return vim.filetype.match { contents = lines }
end
end

local parse_modeline = function(tail)
if tail:find "vim:" then
return tail:match ".*:ft=([^: ]*):.*$" or ""
end
end

local detect_from_modeline = function(p)
local s = p:readbyterange(-256, 256)
if s then
local lines = vim.split(s, "\n")
local idx = lines[#lines] ~= "" and #lines or #lines - 1
if idx >= 1 then
return parse_modeline(lines[idx])
end
end
end

utils.filetype_detect = function(filepath)
local match = vim.filetype.match { filename = filepath }
if match and match ~= "" then
return match
end

local p = Path:new(filepath)
if p and p:exists() then
match = detect_from_shebang(p)
if match and match ~= "" then
return match
end

match = detect_from_modeline(p)
if match and match ~= "" then
return match
end
end
end

utils.with_preview_window = function(status, bufnr, callable)
if bufnr and vim.api.nvim_buf_call and false then
vim.api.nvim_buf_call(bufnr, callable)
Expand Down

0 comments on commit abe3027

Please sign in to comment.