1

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 eg. a command from trash-cli or simply moving file/directory to a different folder?

thanks in advance!

  • 1
    Is it acceptable to remap delete keys/redefine delete commands? – D. Ben Knoble Jan 7 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. – Adrian Pirela Jan 8 at 19:04
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
endfunction

" 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()]
        else
            " remove selection as files will be deleted soon
            call netrw#Call('NetrwUnmarkAll')
        endif
        " do delete and refresh view
        call g:MyNetrw_DoDelete(l:flist)
        return 'refresh'
    endif

    " 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)
 endfunction

" 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())
        endfor
        " do delete and then refresh view
        call g:MyNetrw_DoDelete(l:flist)
        call netrw#Call('NetrwRefresh', 1, b:netrw_curdir)
        return
    endif

    " 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
endfunction
| improve this answer | |
  • 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. – Adrian Pirela Jan 8 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 Jan 8 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. – Adrian Pirela Jan 9 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 Jan 9 at 7:15
1

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
endfunction

" 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
endfunction
| improve this answer | |
  • 1
    Just, whoa... i can decide if that’s impressive or insane :P – D. Ben Knoble Jan 7 at 22:04
  • @D.BenKnoble Insane... Definitely insane! :-D Has my +1. – filbranden Jan 7 at 22:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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