Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to warn before opening certain filetypes in vim?

Tags:

bash

vim

It is easy to accidentally open a large binary or data file with vim when relying on command line autocomplete.

Is it possible to add an interactive warning when opening certain file types in vim?

For example, I'd like to add a warning when opening files without an extension:

> vim someBinary
Edit someBinary? [y/N]

Or maybe:

> vim someBinary
# vim buffer opens and displays warning about filetype, 
# giving user a chance to quit before loading the file

This could be applied to a range of extensions, such as .pdf, .so, .o, .a, no extension, etc.

There is a related question on preventing vim from opening binary files, but it is primarily about modifying autocomplete to prevent accidentally opening the files in the first place.

like image 383
ben-albrecht Avatar asked Dec 06 '25 20:12

ben-albrecht


1 Answers

Below is the solution I came up with, using vim autocommands with the BufReadCmd event. It's a lot of vimscript, but it's pretty robust. It issues a warning if the file being opened is a non-ascii file or has a blacklisted extension (.csv and .tsv for this example):

augroup bigfiles
   " Clear the bigfiles group in case defined elsewhere
   autocmd!
   " Set autocommand to run before reading buffer
   autocmd BufReadCmd * silent call PromptFileEdit()
augroup end



" Prompt user input if editing an existing file before reading
function! PromptFileEdit()
    " Current file
    let file = expand("%")
    " Whether or not we should continue to open the file
    let continue = 1

    " Skip if file has an extension or is not readable
    if filereadable(file) && (IsNonAsciiFile(file) || IsBlacklistedFile())
        " Get response from user
        let response = input('Are you sure you want to open "' . file . '"? [y/n]')

        " Bail if response is a 'n' or contains a 'q'
        if response ==? "n" || response =~ "q"
            let continue = 0
            if (winnr("$") == 1)
                " Quit if it was the only buffer open
                quit
            else
                " Close buffer if other buffers open
                bdelete
            endif
        endif
    endif

    if continue == 1
        " Edit the file
        execute "e" file
        " Run the remaining autocommands for the file
        execute "doautocmd BufReadPost" file
    endif

endfunction

" Return 1 if file is a non-ascii file, otherwise 0
function! IsNonAsciiFile(file)
    let ret = 1
    let fileResult = system('file ' . a:file)
    " Check if file contains ascii or is empty
    if fileResult =~ "ASCII" || fileResult =~ "empty" || fileResult =~ "UTF"
        let ret = 0
    endif
    return ret
endfunction

" Return 1 if file is blacklisted, otherwise 0
function! IsBlacklistedFile()
    let ret = 0
    let extension = expand('%:e')

    " List contains ASCII files that we don't want to open by accident
    let blacklistExtensions = ['csv', 'tsv']

    " Check if we even have an extension
    if strlen(extension) == 0
        let ret = 0
    " Check if our extension is in the blacklisted extensions
    elseif index(blacklistExtensions, extension) >= 0
        let ret = 1
    endif

    return ret
endfunction

To read with syntax highlighting enabled, see this gist.

Maybe not super elegant, but I enjoyed learning some vimscript along the way.

I am not too experienced with vimscript so I'm sure there is room for improvements -- suggestions and alternative solutions welcome.

Note: This is not expected to work on Windows systems outside of WSL or Cygwin, due to calling file.

like image 177
ben-albrecht Avatar answered Dec 09 '25 15:12

ben-albrecht