VIM - 文件浏览插件 defx 配置

安装

vim8要求安装pynvim
pip install  pynvim  msgpack-python
用 vim 包管理工具安装 defx
call plug#begin('~/.vim/plugged')
    Plug 'git://github.com/Shougo/defx.nvim.git'
    Plug 'git://github.com/roxma/nvim-yarp.git'
    Plug 'git://github.com/roxma/vim-hug-neovim-rpc.git'
    Plug 'git://github.com/kristijanhusak/defx-icons.git'
call plug#end()
安装些字体美化 defx 树图标,不知道要哪个,把有的 nerd 字体都装了
$ sudo pacman -S nerd-fonts-roboto-mono  nerd-fonts-terminus ttf-nerd-fonts-symbols-mono nerd-fonts-terminus

配置

安装以后,defx 默认是没有多少快捷键配置的, 所以根据defx的帮助文档,把默认的快捷键设置代码写到 .vimrc 里,经过一些修改,目前我的配置文件是这样的:
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
""""" Defx配置
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    let g:defx_icons_enable_syntax_highlight = 1
    " 开关快捷键,【-search=`expand('%:p')`】表示打开defx树后,光标自动放在当前buffer上
    nmap <silent> ff :Defx  -search=`expand('%:p')` -toggle <cr>


    "打开vim自动打开defx
    func! ArgFunc() abort
        let s:arg = argv(0)
        if isdirectory(s:arg)
            return s:arg
        else
            return fnamemodify(s:arg, ':h')
        endif
    endfunc
    "autocmd VimEnter * Defx `ArgFunc()` -no-focus -search=`expand('%:p')`

    " 设置defx树的一些格式
    call defx#custom#option('_', {
          \ 'columns': 'icons:indent:filename:size',
          \ 'winwidth': 30,
          \ 'split': 'vertical',
          \ 'direction': 'botright',
          \ 'show_ignored_files': 0,
          \ 'resume': 1,
          \ })

    " Exit Vim if defxTree is the only window left.
    autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:defx') |
    \ quit | endif

    " 在打开多个tab的情况下,当前tab里只有一个buffer和nerd树,当关闭buffer时,自动关闭当前标签页的nerd树
    autocmd BufEnter * if tabpagenr('$') > 1 && winnr('$') == 1 && exists('b:defx') |
    \ tabclose | endif

    " 在新tab页打开文件
    func! MyT(context) abort
        if isdirectory(get(a:context.targets, 0)) == 0
            call defx#call_action('drop', 'tabe')
        endif
    endfunc


    " 给cd快捷键写的
    func! MyCD(context) abort
        if isdirectory(get(a:context.targets, 0))
            execute 'cd' . get(a:context.targets, 0)
        else
            execute 'cd' . fnamemodify(defx#get_candidate().action__path, ':h')
        endif
    endfunc

    " 给 ter 快捷键写的
    func! MyTER(context) abort
        call MyCD(a:context)
        shell
    endfunc

    " 给复制或剪切选中的文件或目录写的
    func! Mycopy_cut(mode) abort
        let s:Path = defx#get_selected_candidates()
        let s:Len = len(s:Path)
        let s:Path_list = []
        let s:counter = 0
        while s:counter < s:Len
            let s:P = s:Path[s:counter].action__path
            call add(s:Path_list, s:P)
            let s:counter = s:counter + 1
        endwhile
        let s:MyCMD = ['!~/.vim/cut_copy.py'] + s:Path_list + [a:mode]
        execute join(s:MyCMD)
        endfunc

    " 给粘贴文件写的
    func! Mypaste() abort
        execute join(['!~/.vim/paste.py', defx#get_candidate().action__path])
    endfunc

    " 所有快捷键在这里设置
    autocmd FileType defx call s:defx_my_settings()
    function! s:defx_my_settings() abort
        nnoremap <silent><buffer><expr> <CR>     defx#do_action('drop')
        nnoremap <silent><buffer><expr> t        defx#do_action('call', 'MyT')
        nnoremap <silent><buffer><expr> yy       defx#do_action('yank_path')
        nnoremap <silent><buffer><expr> dd       defx#do_action('remove_trash')
        nnoremap <silent><buffer><expr> cc        defx#do_action('copy')
        nnoremap <silent><buffer><expr> mm        defx#do_action('move')
        nnoremap <silent><buffer><expr> pp        defx#do_action('paste')
        nnoremap <silent><buffer><expr> CC       Mycopy_cut('copy') . defx#do_action('clear_select_all')
        nnoremap <silent><buffer><expr> MM       Mycopy_cut('cut') . defx#do_action('clear_select_all')
        nnoremap <silent><buffer><expr> PP       Mypaste()
        nnoremap <silent><buffer><expr> N        defx#do_action('new_file')
        nnoremap <silent><buffer><expr> M        defx#do_action('new_multiple_files')
        nnoremap <silent><buffer><expr> R        defx#do_action('rename')
        nnoremap <silent><buffer><expr> j        line('.') == line('$') ? 'gg' : 'j'
        nnoremap <silent><buffer><expr> k        line('.') == 1 ? 'G' : 'k'
        nnoremap <silent><buffer><expr> h    
                    \ defx#is_opened_tree() ? 
                    \ defx#do_action('close_tree', defx#get_candidate().action__path) : 
                    \ defx#do_action('search',  fnamemodify(defx#get_candidate().action__path, ':h'))
        nnoremap <silent><buffer><expr> l        defx#do_action('open_tree')
       nnoremap <silent><buffer><expr> o        defx#do_action('open_directory')
        nnoremap <silent><buffer><expr> u        defx#do_action('cd', ['..'])
        nnoremap <silent><buffer><expr> E        defx#do_action('open', 'vsplit')
        nnoremap <silent><buffer><expr> P        defx#do_action('preview')
        "nnoremap <silent><buffer><expr> d        defx#do_action('new_directory')
        nnoremap <silent><buffer><expr> C        defx#do_action('toggle_columns',  'mark:indent:icon:filename:type:size:time')
        nnoremap <silent><buffer><expr> S        defx#do_action('toggle_sort', 'time')
        nnoremap <silent><buffer><expr> !        defx#do_action('execute_command')
        nnoremap <silent><buffer><expr> x        defx#do_action('execute_system')
        nnoremap <silent><buffer><expr> cd       defx#do_action('call', 'MyCD')
        nnoremap <silent><buffer><expr> ~        defx#do_action('cd')
        nnoremap <silent><buffer><expr> ter      defx#do_action('call', 'MyTER')
        nnoremap <silent><buffer><expr> .        defx#do_action('toggle_ignored_files')
        nnoremap <silent><buffer><expr> q        defx#do_action('quit')
        nnoremap <silent><buffer><expr> <Space>  defx#do_action('toggle_select') . 'j'
        nnoremap <silent><buffer><expr> *        defx#do_action('toggle_select_all')
        nnoremap <silent><buffer><expr> m        defx#do_action('clear_select_all')
        nnoremap <silent><buffer><expr> r        defx#do_action('redraw')
        nnoremap <silent><buffer><expr> pr       defx#do_action('print')
        nnoremap <silent><buffer><expr> >        defx#do_action('resize',  defx#get_context().winwidth - 10)
        nnoremap <silent><buffer><expr> <        defx#do_action('resize',  defx#get_context().winwidth + 10)
    nnoremap <silent><buffer><expr> <2-LeftMouse>
    endfunction
修改了几处默认快捷键:
h键:改为当光标在某个文件上时,按键后光标移动到其父目录;当光标在目录上时,若目录在打开状态,则关闭目录,否则光标移动到其父目录,一直到 defxtree的根目录
u键:改为进入到defxtree根目录的父目录l键:改为只能打开或关闭目录
o键:改为只能进入目录,有点跟u键相反,按u键后,按o键可以恢复
cd键:把vim的工作目录切换到光标所在的目录,如果光标在文件上则切换到其父目录
增加ter键:当光标在目录上时,按ter 可以在此目录上打开一个shell外壳,当光标在文件则在其父目录打开
t键:在新标签页打开光标处的文件,这里打开总是很慢,原因是有快捷键ter,这里在等待确认是否还会输入er,可以改名解决,下面的space键也类似,可改为<space><space>
dd键:改成删除文件至系统回收站,需要安装send2trash默认有文件移动mm,复制cc,粘贴pp,因为有时用到不同的终端窗口之间移动文件,所以就新增加了以下几个键:
CC键:复制选中的文件和目录
MM键:剪切选中的文件和目录
PP键:粘贴上述的文件和目录到光标所在的位置,光标在目录上则粘贴到此目录内,光标在文件上,则粘贴到文件所在的目录
其实,复制和粘贴就是调用用 ~/.vim/cut_copy.py把选中的文件和目录的路径写到 ~/.vim/tmp_clipboard.txt 里,并标明要复制还是粘贴。
按PP键的时候才用 调用~/.vim/paste.py ,把文件和目录移动到相应的位置。
这三个键要用到下面的两个文件,要放到~/.vim 目录下。
要增加权限
chmod +x  cut_copy.py   paste.py 
 
至此,defx就配置成比较顺手的了,附上用到的两个文件cut_copy.py
#!/usr/bin/python3

"""
调用方式: ~/.vim/cut_copy.py  f1 f2 d1/ d2/ cut or copy
把相关的文件/目录的绝对路径写到文件里保存
最后一个参数代表粘贴的时候是复制copy还是移动mv
"""

import sys


argv = sys.argv
with open('~/.vim/tmp_clipboard.txt', 'w') as f:
    f.write('\n'.join(argv[1:]))
paste.py
#!/usr/bin/python3

"""
需要粘贴的文件路径已经存放在文件~/.vim/tmp_clipboard.txt
文件最后一行表示要cut还是copy, 。
调用方法: ~/.vim/paste.py dst
"""
import os
import sys
import shutil
def clean_dst(one_path, dst):
    """
    当dst是一个目录时,要把剪贴板上的文件和目录都放到dst下面;
    当dst是一个文件时,要把剪贴板上的文件和目录都放到其父目录下。
    函数的功能就是清理dst,使得粘贴的时候不会发生文件存在异常。
    """
    dst = os.path.dirname(dst) if os.path.isfile(dst) else dst
    path = os.path.join(dst, os.path.basename(one_path))
    if path == one_path:
        return None

    if os.path.exists(path):
        try:
            os.remove(path)
        except:
            shutil.rmtree(path)
    return path


def paste():
    """
    完成粘贴任务,如果同名目标已经存在,就覆盖
    """
    dst = sys.argv[1].strip()
    FILE = "~/.vim/tmp_clipboard.txt"
    if os.path.exists(FILE):
        with open(FILE) as f:
            files = f.readlines()

    # 查看复制还是剪切
    CUT = True if files[-1].strip() == 'cut' else False
    for f in files[: -1]:
        f = f.strip()
        if not f:
            continue
        dst_f = clean_dst(f, dst)
        if dst_f is None:  # 粘贴到原位置
            continue
        if CUT:
            shutil.move(f, dst_f)
        else:
            try:
                shutil.copy(f, dst_f)
            except:
                shutil.copytree(f, dst_f)


assert len(sys.argv) == 2, '输入dst'
paste()
 
参考:
https://zhuanlan.zhihu.com/p/358828723
posted @ 2021-04-16 15:39  7bGWFm  阅读(1482)  评论(0编辑  收藏  举报