From 27200eee8bee798e11deb062f32c52ab0bef90d1 Mon Sep 17 00:00:00 2001 From: Wang Shidong Date: Wed, 3 Oct 2018 21:47:43 +0800 Subject: [PATCH] Add: A better way to use find with vim (#1777) --- autoload/SpaceVim/layers/core.vim | 1 + autoload/SpaceVim/plugins/find.vim | 256 +++++++++++++++++++++++++++++ docs/cn/documentation.md | 17 +- docs/documentation.md | 1 + syntax/SpaceVimFindArgv.vim | 14 ++ 5 files changed, 281 insertions(+), 8 deletions(-) create mode 100644 autoload/SpaceVim/plugins/find.vim create mode 100644 syntax/SpaceVimFindArgv.vim diff --git a/autoload/SpaceVim/layers/core.vim b/autoload/SpaceVim/layers/core.vim index cbf4bf672..9b1e40c41 100644 --- a/autoload/SpaceVim/layers/core.vim +++ b/autoload/SpaceVim/layers/core.vim @@ -167,6 +167,7 @@ function! SpaceVim#layers#core#config() abort \ . string(s:_function('s:delete_current_buffer_file')) . ', [])', \ 'delete-current-buffer-file', 1) call SpaceVim#mapping#space#def('nnoremap', ['f', 'F'], 'normal! gf', 'open-cursor-file', 1) + call SpaceVim#mapping#space#def('nnoremap', ['f', '/'], 'call SpaceVim#plugins#find#open()', 'find-files', 1) if g:spacevim_filemanager ==# 'vimfiler' call SpaceVim#mapping#space#def('nnoremap', ['f', 't'], 'VimFiler', 'toggle_file_tree', 1) call SpaceVim#mapping#space#def('nnoremap', ['f', 'T'], 'VimFiler -no-toggle', 'show_file_tree', 1) diff --git a/autoload/SpaceVim/plugins/find.vim b/autoload/SpaceVim/plugins/find.vim new file mode 100644 index 000000000..c33a04702 --- /dev/null +++ b/autoload/SpaceVim/plugins/find.vim @@ -0,0 +1,256 @@ +"============================================================================= +" find.vim --- vim plugin for find +" Copyright (c) 2016-2017 Wang Shidong & Contributors +" Author: Wang Shidong +" URL: https://spacevim.org +" License: GPLv3 +"============================================================================= + +" Loadding SpaceVim api {{{ +scriptencoding utf-8 +let s:MPT = SpaceVim#api#import('prompt') +let s:JOB = SpaceVim#api#import('job') +" let s:SYS = SpaceVim#api#import('system') +" let s:BUFFER = SpaceVim#api#import('vim#buffer') +" let s:LIST = SpaceVim#api#import('data#list') +"}}} + +let s:MPT._prompt.mpt = ' find ' + +let s:options_en = { + \ '-amin' : 'File was last accessed n minutes ago.', + \ '-anewer' : 'File was last accessed more recently than file was modified.', + \ '-atime' : 'File was last accessed n*24 hours ago.', + \ '-cmin' : "File's status was last changed n minutes ago.", + \ '-cnewer' : "File's status was last changed more recently than file was modified.", + \ '-ctime' : "File's status was last changed n*24 hours ago.", + \ '-daystart' : 'Measure times from the beginning of today rather than from 24 hours ago.', + \ '-depth' : "Process each directory's contents before the directory itself.", + \ '-exec' : 'Execute command', + \ '-false' : 'make find command return false', + \ '-fls' : 'True; like -ls but write to file like -fprint.', + \ '-follow' : 'a diagnostic message is issued when find encounters a loop of symbolic links.', + \ '-fprint' : 'True; print the full file name into file file.', + \ '-fprintf' : 'True; like -printf but write to file like -fprint.', + \ '-fstype' : 'Only list files or directorys with specific filesysten type', + \ '-gid' : 'Only list files with specific group ID.', + \ '-group' : 'Only list files with specific group name.', + \ '-help' : 'show help info', + \ '-ilname' : '此参数的效果和指定“-lname”参数类似,但忽略字符大小写的差别', + \ '-iname' : '指定字符串作为寻找符号连接的范本样式', + \ '-inum' : '查找符合指定的inode编号的文件或目录', + \ '-ipath' : '此参数的效果和指定“-path”参数类似,但忽略字符大小写的差别', + \ '-iregex' : '此参数的效果和指定“-regexe”参数类似,但忽略字符大小写的差别', + \ '-links' : '查找符合指定的硬连接数目的文件或目录', + \ '-ls' : 'If find command return True, then send all files names to stdout', + \ '-maxdepth' : 'specific the max path depath', + \ '-mindepth' : 'specific the min path depath', + \ '-mmin' : '查找在指定时间曾被更改过的文件或目录,单位以分钟计算', + \ '-mount' : '此参数的效果和指定“-xdev”相同', + \ '-mtime' : '查找在指定时间曾被更改过的文件或目录,单位以24小时计算', + \ '-name' : '指定字符串作为寻找文件或目录的范本样式', + \ '-newer' : '查找其更改时间较指定文件或目录的更改时间更接近现在的文件或目录', + \ '-nogroup' : '找出不属于本地主机群组识别码的文件或目录', + \ '-noleaf' : '不去考虑目录至少需拥有两个硬连接存在', + \ '-nouser' : '找出不属于本地主机用户识别码的文件或目录', + \ '-ok' : '此参数的效果和指定“-exec”类似,但在执行指令之前会先询问用户,若回答“y”或“Y”,则放弃执行命令', + \ '-path' : '指定字符串作为寻找目录的范本样式', + \ '-perm' : '查找符合指定的权限数值的文件或目录', + \ '-print' : '假设find指令的回传值为Ture,就将文件或目录名称列出到标准输出。格式为每列一个名称,每个名称前皆有“./”字符串', + \ '-print0' : '假设find指令的回传值为Ture,就将文件或目录名称列出到标准输出。格式为全部的名称皆在同一行', + \ '-printf' : '假设find指令的回传值为Ture,就将文件或目录名称列出到标准输出。格式可以自行指定', + \ '-prune' : '不寻找字符串作为寻找文件或目录的范本样式', + \ '-regex' : '指定字符串作为寻找文件或目录的范本样式', + \ '-size' : '查找符合指定的文件大小的文件', + \ '-true' : '将find指令的回传值皆设为True', + \ '-type' : '只寻找符合指定的文件类型的文件', + \ '-uid' : '查找符合指定的用户识别码的文件或目录', + \ '-used' : '查找文件或目录被更改之后在指定时间曾被存取过的文件或目录,单位以日计算', + \ '-user' : '查找符和指定的拥有者名称的文件或目录', + \ '-version' : 'Show version', + \ '-xdev' : '将范围局限在先行的文件系统中', + \ '-xtype' : '此参数的效果和指定“-type”参数类似,差别在于它针对符号连接检查' + \ } + +let s:options = { + \ '-amin' : '查找在指定时间曾被存取过的文件或目录,单位以分钟计算', + \ '-anewer' : '查找其存取时间较指定文件或目录的存取时间更接近现在的文件或目录', + \ '-atime' : '查找在指定时间曾被存取过的文件或目录,单位以24小时计算', + \ '-cmin' : '查找在指定时间之时被更改过的文件或目录', + \ '-cnewer' : '查找其更改时间较指定文件或目录的更改时间更接近现在的文件或目录', + \ '-ctime' : '查找在指定时间之时被更改的文件或目录,单位以24小时计算', + \ '-daystart' : '从本日开始计算时间', + \ '-depth' : '从指定目录下最深层的子目录开始查找', + \ '-exec' : '假设find指令的回传值为True,就执行该指令', + \ '-false' : '将find指令的回传值皆设为False', + \ '-fls' : '此参数的效果和指定“-ls”参数类似,但会把结果保存为指定的列表文件', + \ '-follow' : '排除符号连接', + \ '-fprint' : '此参数的效果和指定“-print”参数类似,但会把结果保存成指定的列表文件', + \ '-fprintf' : '此参数的效果和指定“-printf”参数类似,但会把结果保存成指定的列表文件', + \ '-fstype' : '只寻找该文件系统类型下的文件或目录', + \ '-gid' : '查找符合指定之群组识别码的文件或目录', + \ '-group' : '查找符合指定之群组名称的文件或目录', + \ '-help' : '——help:在线帮助', + \ '-ilname' : '此参数的效果和指定“-lname”参数类似,但忽略字符大小写的差别', + \ '-iname' : '指定字符串作为寻找符号连接的范本样式', + \ '-inum' : '查找符合指定的inode编号的文件或目录', + \ '-ipath' : '此参数的效果和指定“-path”参数类似,但忽略字符大小写的差别', + \ '-iregex' : '此参数的效果和指定“-regexe”参数类似,但忽略字符大小写的差别', + \ '-links' : '查找符合指定的硬连接数目的文件或目录', + \ '-ls' : '假设find指令的回传值为Ture,就将文件或目录名称列出到标准输出', + \ '-maxdepth' : '设置最大目录层级', + \ '-mindepth' : 'Do not apply any tests or actions at levels less than n.', + \ '-mmin' : '查找在指定时间曾被更改过的文件或目录,单位以分钟计算', + \ '-mount' : '此参数的效果和指定“-xdev”相同', + \ '-mtime' : '查找在指定时间曾被更改过的文件或目录,单位以24小时计算', + \ '-name' : '指定字符串作为寻找文件或目录的范本样式', + \ '-newer' : '查找其更改时间较指定文件或目录的更改时间更接近现在的文件或目录', + \ '-nogroup' : '找出不属于本地主机群组识别码的文件或目录', + \ '-noleaf' : '不去考虑目录至少需拥有两个硬连接存在', + \ '-nouser' : '找出不属于本地主机用户识别码的文件或目录', + \ '-ok' : '此参数的效果和指定“-exec”类似,但在执行指令之前会先询问用户,若回答“y”或“Y”,则放弃执行命令', + \ '-path' : '指定字符串作为寻找目录的范本样式', + \ '-perm' : '查找符合指定的权限数值的文件或目录', + \ '-print' : '假设find指令的回传值为Ture,就将文件或目录名称列出到标准输出。格式为每列一个名称,每个名称前皆有“./”字符串', + \ '-print0' : '假设find指令的回传值为Ture,就将文件或目录名称列出到标准输出。格式为全部的名称皆在同一行', + \ '-printf' : '假设find指令的回传值为Ture,就将文件或目录名称列出到标准输出。格式可以自行指定', + \ '-prune' : '不寻找字符串作为寻找文件或目录的范本样式', + \ '-regex' : '指定字符串作为寻找文件或目录的范本样式', + \ '-size' : '查找符合指定的文件大小的文件', + \ '-true' : '将find指令的回传值皆设为True', + \ '-type' : '只寻找符合指定的文件类型的文件', + \ '-uid' : '查找符合指定的用户识别码的文件或目录', + \ '-used' : '查找文件或目录被更改之后在指定时间曾被存取过的文件或目录,单位以日计算', + \ '-user' : '查找符和指定的拥有者名称的文件或目录', + \ '-version' : '显示版本信息', + \ '-xdev' : '将范围局限在先行的文件系统中', + \ '-xtype' : '此参数的效果和指定“-type”参数类似,差别在于它针对符号连接检查' + \ } + +let s:second_option_en = { + \ '-type' : + \ { + \ 'f' : 'regular file', + \ 'l' : 'symbolic link', + \ 'd' : 'directory', + \ 'c' : 'character (unbuffered) special', + \ 'b' : 'block (buffered) special', + \ 's' : 'socket', + \ 'p' : 'named pipe (FIFO)', + \ }, + \ } + +let s:second_option = { + \ '-type' : + \ { + \ 'f' : '普通文件', + \ 'l' : '符号连接', + \ 'd' : '目录', + \ 'c' : '字符设备', + \ 'b' : '块设备', + \ 's' : '套接字', + \ 'p' : 'Fifo', + \ }, + \ } + +let s:finded_files = [] +function! s:start_find() abort + let cmd = 'find -not -iwholename "*.git*" ' . s:MPT._prompt.begin . s:MPT._prompt.cursor . s:MPT._prompt.end + call s:MPT._clear_prompt() + let s:MPT._quit = 1 + let line = getline('.') + noautocmd q + redraw! + call s:JOB.start(cmd, + \ { + \ 'on_stdout' : function('s:find_on_stdout'), + \ 'on_exit' : function('s:find_on_exit'), + \ } + \ ) +endfunction + +function! s:find_on_stdout(id, data, event) abort + let s:finded_files += a:data +endfunction + +function! s:find_on_exit(id, data, event) abort + let files = map(filter(s:finded_files, '!empty(v:val)'), "{'filename' : v:val}") + if !empty(files) + call setqflist(files) + copen + else + echo 'Can not find anything' + endif +endfunction + +function! s:close_buffer() abort + noautocmd pclose + noautocmd q +endfunction +let s:MPT._onclose = function('s:close_buffer') + +function! s:next_item() abort + if line('.') == line('$') + normal! gg + else + normal! j + endif + let argv = matchstr(getline('.'), '^-[a-zA-Z0-9]') + let s:MPT._prompt.begin = substitute(s:MPT._prompt.begin, '-[a-zA-Z]*$', argv, 'g') + redraw + call s:MPT._build_prompt() +endfunction + +function! s:previous_item() abort + if line('.') == 1 + normal! G + else + normal! k + endif + let argv = matchstr(getline('.'), '^-[a-zA-Z0-9]') + let s:MPT._prompt.begin = substitute(s:MPT._prompt.begin, '-[a-zA-Z]*$', argv, 'g') + redraw + call s:MPT._build_prompt() +endfunction + +function! SpaceVim#plugins#find#open() abort + let s:MPT._handle_fly = function('s:handle_command_line') + let s:MPT._function_key = { + \ "\" : function('s:start_find'), + \ "\" : function('s:next_item'), + \ "\" : function('s:next_item'), + \ "\" : function('s:previous_item'), + \ "\" : function('s:previous_item'), + \ } + noautocmd rightbelow split __spacevim_find_argv__ + let s:find_argvs_buffer_id = bufnr('%') + setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline nospell nonu norelativenumber + setf SpaceVimFindArgv + call s:MPT.open() +endfunction + +function! s:handle_command_line(cmd) abort + normal! "_dG + if empty(a:cmd) + redraw + call s:MPT._build_prompt() + return + endif + let argv = split(a:cmd)[-1] + if a:cmd[-1:] ==# ' ' && argv ==# '-type' + let line = [] + for item in items(s:second_option_en['-type']) + call add(line, ' ' . item[0] . repeat(' ', 8 - len(item[0])) . item[1]) + endfor + call setline(1, line) + elseif argv =~# '^-[a-zA-Z0-1]*' + let argvs = filter(deepcopy(s:options_en), 'v:key =~ argv') + let line = [] + for item in items(argvs) + call add(line, item[0] . repeat(' ', 15 - len(item[0])) . item[1]) + endfor + call setline(1, line) + endif + redraw + call s:MPT._build_prompt() +endfunction diff --git a/docs/cn/documentation.md b/docs/cn/documentation.md index ca4d05543..520c2d0da 100644 --- a/docs/cn/documentation.md +++ b/docs/cn/documentation.md @@ -829,12 +829,12 @@ call SpaceVim#custom#SPC('nnoremap', ['f', 't'], 'echom "hello world"', 'test cu Denite/Unite 是一个强大的信息筛选浏览器,这类似于 emacs 中的 [Helm](https://github.com/emacs-helm/helm)。以下这些快捷键将帮助你快速获取需要的帮助信息: -| 快捷键 | 描述 | -| ----------- | -------------------------------------------- | -| `SPC h SPC` | 使用 fuzzy find 模块展示 SpaceVim 帮助文档章节目录 | -| `SPC h i` | 获取光标下单词的帮助信息 | -| `SPC h k` | 使用快捷键导航,展示 SpaceVim 所支持的前缀键 | -| `SPC h m` | 使用 Unite 浏览所有 man 文档 | +| 快捷键 | 描述 | +| ----------- | -------------------------------------------------- | +| `SPC h SPC` | 使用 fuzzy find 模块展示 SpaceVim 帮助文档章节目录 | +| `SPC h i` | 获取光标下单词的帮助信息 | +| `SPC h k` | 使用快捷键导航,展示 SpaceVim 所支持的前缀键 | +| `SPC h m` | 使用 Unite 浏览所有 man 文档 | 报告一个问题: @@ -979,8 +979,8 @@ merged = 0 | `SPC w TAB`/`` | 在统一标签内进行窗口切换 | | `SPC w =` | 对齐分离的窗口 | | `SPC w b` | force the focus back to the minibuffer (TODO) | -| `SPC w c` | 进入阅读模式,浏览当前窗口 (需要 tools 模块) | -| `SPC w C` | 选择某一个窗口,并且进入阅读模式 (需要 tools 模块) | +| `SPC w c` | 进入阅读模式,浏览当前窗口 (需要 tools 模块) | +| `SPC w C` | 选择某一个窗口,并且进入阅读模式 (需要 tools 模块) | | `SPC w d` | 删除一个窗口 | | `SPC u SPC w d` | delete a window and its current buffer (does not delete the file) (TODO) | | `SPC w D` | 选择一个窗口,并且关闭 | @@ -1062,6 +1062,7 @@ Buffer 操作相关快捷键都是已 `SPC b` 为前缀的: | 快捷键 | 描述 | | ----------- | ------------------------------------------------------ | +| `SPC f /` | 使用 `find` 命令查找文件,支持参数提示 | | `SPC f b` | 跳至文件书签 | | `SPC f c` | copy current file to a different location(TODO) | | `SPC f C d` | 修改文件编码 unix -> dos | diff --git a/docs/documentation.md b/docs/documentation.md index 35730a98e..c464cada5 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -1103,6 +1103,7 @@ Files manipulation commands (start with f): | Key Binding | Description | | ----------- | -------------------------------------------------------------- | +| `SPC f /` | Find files with `find` command | | `SPC f b` | go to file bookmarks | | `SPC f c` | copy current file to a different location(TODO) | | `SPC f C d` | convert file from unix to dos encoding | diff --git a/syntax/SpaceVimFindArgv.vim b/syntax/SpaceVimFindArgv.vim new file mode 100644 index 000000000..69fab3799 --- /dev/null +++ b/syntax/SpaceVimFindArgv.vim @@ -0,0 +1,14 @@ +if exists("b:current_syntax") + finish +endif +let b:current_syntax = "SpaceVimFindArgv" +syntax case ignore + +syn match CMDFindArgvOpt /-[a-zA-Z]*\ / +syn match CMDFindSecArgvOpt /^\s\+[a-z]\s\+/ +syn match CMDFindArgvDesc /\(-[a-zA-Z0-1]*\ \)\@<=.*/ +syn match CMDFindSecArgvDesc /\(^\s\+[a-z]\s\+\)\@<=.*/ +hi def link CMDFindArgvOpt Number +hi def link CMDFindSecArgvOpt Number +hi def link CMDFindArgvDesc Comment +hi def link CMDFindSecArgvDesc Comment