I'm currently using Vim 8.1 on Ubuntu 18.04, and I would like to override the default behavior of deleting local files/directories 'forever' when using netrw.

The doc says that this plugin uses a function called delete() on latest versions of vim. My guess is that this function simple uses rm to delete files, how could I override this behavior to use e.g. a command from trash-cli or simply moving file/directory to a different folder?

  • 1
    Is it acceptable to remap delete keys/redefine delete commands?
    – D. Ben Knoble
    Commented Jan 7, 2020 at 22:05
  • Yeah totally!, I should've mentioned that, I just want to override the default behavior of pressing 'D' in netrw, ideally by just adding a few lines to my vimrc. Commented Jan 8, 2020 at 19:04

2 Answers 2


Let us be not too insane :-) and provide a different solution using mappings and netrw public API.

Beware that the code is neither complete nor was tested properly!

" our custom delete routine
function! g:MyNetrw_DoDelete(flist)
    echom 'Deleting ' a:flist

" setup netrw mappings (:h g:Netrw_UserMaps)
let g:Netrw_UserMaps = [['D', 'g:MyNetrw_D'], ["\<Del>", 'g:MyNetrw_D']]

" unfortunately, the visual mode is not supported by Netrw_UserMaps,
" so implement it with the help of augroup/autocmd
" (although netrw is very peculiar about its mappings,
" it seems to work okay too)
augroup MyNetrw | au!
    autocmd FileType netrw vnoremap <buffer>D :call g:MyNetrw_vD()<CR>
augroup end

" implement normal mode deletion
function! g:MyNetrw_D(islocal)
    if a:islocal
        " get selected file list (:h netrw-mf)
        let l:flist = netrw#Expose('netrwmarkfilelist')
        if l:flist is# 'n/a'
            " no selection -- get name under cursor
            let l:flist = [b:netrw_curdir . '/' . netrw#GX()]
            " remove selection as files will be deleted soon
            call netrw#Call('NetrwUnmarkAll')
        " do delete and refresh view
        call g:MyNetrw_DoDelete(l:flist)
        return 'refresh'

    " this is to handle remote deletion
    " hope it works...
    call netrw#Call('RemotePathAnalysis', b:netrw_curdir)
    let l:usermach = netrw#Expose('user') . '@' . netrw#Expose('machine')
    let l:path = netrw#Expose('path')
    call netrw#Call('NetrwRemoteRm', l:usermach, l:path)

" implement delete over Visual range
function! g:MyNetrw_vD() range
    if isdirectory(b:netrw_curdir)
        " assume it's local dir
        " get all file names over selected lines
        let l:flist = []
        for l:lnum in range(a:firstline, a:lastline)
            execute l:lnum
            call add(l:flist, b:netrw_curdir . '/' . netrw#GX())
        " do delete and then refresh view
        call g:MyNetrw_DoDelete(l:flist)
        call netrw#Call('NetrwRefresh', 1, b:netrw_curdir)

    " remote delete over visual range -- NOT IMPLEMENTED
    " Note: call() cannot supply non-trivial range,
    " so we have to process line range manually (sigh),
    " and then call `s:NetrwRemoteRmFile()` in a loop
  • I like this answer, it changes the behavior of 'D' when attempting to delete a file with netrw, but it's still not working, it doesn't delete (or move to trash) anything yet, it just displays a message saying 'Deleting ['/home/path/to/file']. I'll try to play around with this code tho, it seems to be the way to go. Commented Jan 8, 2020 at 19:13
  • @AdrianPirela Sure, it's just an example. You asked "how to override that thing" without exactly saying what it should do instead. So I won't take a guess, you know.
    – Matt
    Commented Jan 8, 2020 at 19:25
  • My apologies for being unclear, I just want to delete a file or directory using netrw in a safer way, do you have any suggestions for this?, Something like invoking a command to move a file to the trash folder. I might update this question again if needed. Commented Jan 9, 2020 at 4:51
  • @AdrianPirela This is OS/Desktop dependent, so there can't be a truly general recommendation. Perhaps, in your case (Ubuntu?) you can simply !mv files to $XDG_DATA_HOME/Trash.
    – Matt
    Commented Jan 9, 2020 at 7:15

Well, it's not supposed to be user-modifiable. But we can "hack" it:

" helper function to find Script Number (aka SNR)
function! GetSNR(sfile)
    " slash <-> bslash translation
    let l:sfile = exists('+shellslash') && !&shellslash ?
        \ tr(a:sfile, '/', '\') : tr(a:sfile, '\', '/')
    " get 'number:', 'scriptfile' pairs
    let l:scripts = split(execute('scriptnames'))
    " find script file of interest
    let l:pos = index(l:scripts, l:sfile)
    " return SNR or zero
    return l:pos > 0 ? str2nr(l:scripts[l:pos - 1]) : 0

" force autoloaded script to load
call netrw#GX()

" replace script-local function s:NetrwDelete()
" bug or feature, however this works!
execute printf('function! <SNR>%d_NetrwDelete(path)',
    \ GetSNR($VIMRUNTIME . '/autoload/netrw.vim'))
    " ***** Do something instead of delete() *****
    echom 'Attempt to delete ' . a:path
  • 1
    Just, whoa... i can decide if that’s impressive or insane :P
    – D. Ben Knoble
    Commented Jan 7, 2020 at 22:04
  • @D.BenKnoble Insane... Definitely insane! :-D Has my +1.
    – filbranden
    Commented Jan 7, 2020 at 22:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.