From a73071596b66ea25a1bb3299653663239f379d62 Mon Sep 17 00:00:00 2001 From: Mark Woods Date: Sun, 19 Jan 2025 07:59:13 +0000 Subject: [PATCH] Skip preview for binary files Previewing binary files as text can mess up the screen, characters can get rendered outside of the preview window which are not later cleared when the popups are closed. It also looks pretty awful. This adds a simple check for a NUL byte in the first 128 bytes, which is fast and should be enough to detect a binary file. This is similar to how ripgrep and other programs typically detect a binary, though they may read the entire file. The 128 bytes might seem arbitrary, but it comes from Leaderf, added in September 2023 and unchanged since then, so presumably works well enough. Telescope.nvim does things differently, actually running the file program to detect a mime type, but I wanted to avoid that, at least until trying the simpler NUL byte check. Note: as this code reads the first 128 bytes in binary mode and does no encoding conversion, it will generate false positives for file encodings that allow NUL bytes, like UTF-16 and UTF-32. This is IMHO an acceptable trade-off to keep the code simple, Leaderf also detects encodings that allow NUL bytes as binary, Telescope.nvim renders them as UTF-8, so with a load of NUL byte marker garbage, git even considers them to be binary. Rendering them in the Fuzzyy preview window would also include NUL byte marker garbage as the file is read raw, without any encoding conversion. Also note that this does not currently apply to the grep preview because all the supported grep programs are configured to skip binaries anyway. --- autoload/fuzzyy/files.vim | 9 ++++++--- autoload/fuzzyy/grep.vim | 3 +-- autoload/fuzzyy/mru.vim | 9 ++++++--- autoload/fuzzyy/utils/selector.vim | 12 ++++++++++++ 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/autoload/fuzzyy/files.vim b/autoload/fuzzyy/files.vim index 4c6bd7ec..47af52e6 100644 --- a/autoload/fuzzyy/files.vim +++ b/autoload/fuzzyy/files.vim @@ -109,10 +109,13 @@ def Preview(wid: number, opts: dict) return endif var preview_bufnr = winbufnr(preview_wid) - var fileraw = readfile(path, '', 1000) - noautocmd call popup_settext(preview_wid, fileraw) + if selector.IsBinary(path) + noautocmd call popup_settext(preview_wid, 'Cannot preview binary file') + else + noautocmd call popup_settext(preview_wid, readfile(path, '', 1000)) + win_execute(preview_wid, 'silent! doautocmd filetypedetect BufNewFile ' .. path) + endif win_execute(preview_wid, 'norm gg') - win_execute(preview_wid, 'silent! doautocmd filetypedetect BufNewFile ' .. path) noautocmd win_execute(preview_wid, 'silent! setlocal nospell nolist') enddef diff --git a/autoload/fuzzyy/grep.vim b/autoload/fuzzyy/grep.vim index a6d8a1ed..12a046da 100644 --- a/autoload/fuzzyy/grep.vim +++ b/autoload/fuzzyy/grep.vim @@ -315,8 +315,7 @@ def Preview(wid: number, opts: dict) if path != last_path var preview_bufnr = winbufnr(preview_wid) - var fileraw = readfile(path) - noautocmd call popup_settext(preview_wid, fileraw) + noautocmd call popup_settext(preview_wid, readfile(path)) win_execute(preview_wid, 'silent! doautocmd filetypedetect BufNewFile ' .. path) noautocmd win_execute(preview_wid, 'silent! setlocal nospell nolist') endif diff --git a/autoload/fuzzyy/mru.vim b/autoload/fuzzyy/mru.vim index 92bd2cd0..ec2cdaed 100644 --- a/autoload/fuzzyy/mru.vim +++ b/autoload/fuzzyy/mru.vim @@ -41,10 +41,13 @@ def Preview(wid: number, opts: dict) return endif var preview_bufnr = winbufnr(preview_wid) - var fileraw = readfile(path) - noautocmd call popup_settext(preview_wid, fileraw) + if selector.IsBinary(path) + noautocmd call popup_settext(preview_wid, 'Cannot preview binary file') + else + noautocmd call popup_settext(preview_wid, readfile(path)) + win_execute(preview_wid, 'silent! doautocmd filetypedetect BufNewFile ' .. path) + endif win_execute(preview_wid, 'norm gg') - win_execute(preview_wid, 'silent! doautocmd filetypedetect BufNewFile ' .. path) noautocmd win_execute(preview_wid, 'silent! setlocal nospell nolist') enddef diff --git a/autoload/fuzzyy/utils/selector.vim b/autoload/fuzzyy/utils/selector.vim index 07f3b837..b5571c21 100644 --- a/autoload/fuzzyy/utils/selector.vim +++ b/autoload/fuzzyy/utils/selector.vim @@ -92,6 +92,18 @@ export def GetRootDir(): string return getcwd() enddef +export def IsBinary(path: string): bool + # NUL byte check for binary files, used to avoid showing preview + # Assumes a file encoding that does not allow NUL bytes, so will + # generate false positives for UTF-16 and UTF-32, but the preview + # window doesn't work for these encodings anyway, even with a BOM + var bytes = readblob(path, 0, 128) + for byte in bytes + if byte == 0 | return true | endif + endfor + return false +enddef + # Search pattern @pattern in a list of strings @li # if pattern is empty, return [li, []] # params: