├── README.md └── note ├── augroup.md ├── autoload.md ├── execute.md ├── expand.md ├── fnamemodify.md ├── leaders.md └── runtimepath.md /README.md: -------------------------------------------------------------------------------- 1 | # thinkvim-study 2 | 3 | # 一、整体预览学习 4 | 5 | `ThinkVim`是一个很好的`Vim`配置文件项目,用来拆分`vim`的配置。 6 | 7 | 原作者github项目: 8 | 9 | 这个工程来记录学习这个项目笔记。 10 | 11 | 自己由于不懂`Vim Script`这个也是记录学习`Vim Script`的笔记。 12 | 13 | ## 1、`init.vim` 14 | 15 | 这个文件是`neovim`的配置文件,是整个项目的入口 16 | 17 | `init.vim` 18 | 19 | ```css 20 | " 执行加载当前目录下core/vimrc配置文件 21 | execute 'source' fnamemodify(expand(''), ':h').'/core/vimrc' 22 | ``` 23 | 24 | - [execute](./note/execute.md):执行字符串命令 25 | 26 | - [fnamemodify](./note/fnamemodify.md):获取路径内置函数 27 | - [expand](./note/expand.md):获取路径内置函数 28 | 29 | 所以这里是加载`./core/vimrc`配置文件 30 | 31 | - ``:表示当前载入的配置文件 32 | - `expand('')`:扩展当前配置文件 33 | - `:h`:当前文件的路径,去掉文件名部分,相对路径 34 | - `fnamemodify(expand(''),':h')`返回当前配置文件的相对路径 35 | 36 | ## 2、`core/vimrc` 37 | 38 | ```bash 39 | if &compatible 40 | " vint: -ProhibitSetNoCompatible 41 | set nocompatible 42 | " vint: +ProhibitSetNoCompatible 43 | endif 44 | 45 | " Set main configuration directory as parent directory 46 | let $VIM_PATH = fnamemodify(resolve(expand(':p')), ':h:h') 47 | let s:user_settings_path = expand('~/.thinkvim.d/local_settings.vim') 48 | 49 | " Regular Vim doesn't add custom configuration directories, if you use one 50 | if &runtimepath !~# $VIM_PATH 51 | set runtimepath^=$VIM_PATH 52 | endif 53 | 54 | let $DATA_PATH = g:etc#cache_path 55 | 56 | " Set augroup 57 | augroup MyAutoCmd 58 | autocmd! 59 | augroup END 60 | 61 | " Disable vim distribution plugins 62 | let g:loaded_getscript = 1 63 | let g:loaded_getscriptPlugin = 1 64 | let g:loaded_gzip = 1 65 | let g:loaded_logiPat = 1 66 | let g:loaded_matchit = 1 67 | let g:loaded_matchparen = 1 68 | let g:netrw_nogx = 1 " disable netrw's gx mapping. 69 | let g:loaded_rrhelper = 1 70 | let g:loaded_shada_plugin = 1 71 | let g:loaded_tar = 1 72 | let g:loaded_tarPlugin = 1 73 | let g:loaded_tutor_mode_plugin = 1 74 | let g:loaded_2html_plugin = 1 75 | let g:loaded_vimball = 1 76 | let g:loaded_vimballPlugin = 1 77 | let g:loaded_zip = 1 78 | let g:loaded_zipPlugin = 1 79 | 80 | " Initialize base requirements 81 | if has('vim_starting') 82 | " Global Mappings "{{{ 83 | " Use spacebar as leader and ; as secondary-leader 84 | " Required before loading plugins! 85 | let g:mapleader="\" 86 | let g:maplocalleader=';' 87 | 88 | " Release keymappings prefixes, evict entirely for use of plug-ins. 89 | nnoremap 90 | xnoremap 91 | nnoremap , 92 | xnoremap , 93 | nnoremap ; 94 | xnoremap ; 95 | nnoremap m 96 | xnoremap m 97 | if ! has('nvim') && has('pythonx') 98 | if has('python3') 99 | set pyxversion=3 100 | elseif has('python') 101 | set pyxversion=2 102 | endif 103 | endif 104 | 105 | 106 | " Ensure data directories 107 | call etc#util#ensure_directory([ 108 | \ g:etc#cache_path . '/undo', 109 | \ g:etc#cache_path . '/backup', 110 | \ g:etc#cache_path . '/session', 111 | \ g:etc#vim_path . '/spell' 112 | \ ]) 113 | 114 | endif 115 | 116 | call etc#init() 117 | call etc#util#source_file('core/plugins/allkey.vim') 118 | call etc#util#source_file('core/general.vim') 119 | call etc#util#source_file('core/filetype.vim') 120 | call etc#util#source_file('core/mappings.vim') 121 | 122 | " Initialize user favorite colorscheme 123 | call theme#init() 124 | call etc#util#source_file('core/color.vim') 125 | 126 | function! s:check_custom_settings(filename)abort 127 | let content = readfile(a:filename) 128 | if empty(content) 129 | return 0 130 | endif 131 | return 1 132 | endfunction 133 | 134 | function! s:source_custom(path, ...) abort 135 | let use_global = get(a:000, 0, !has('vim_starting')) 136 | let abspath = resolve(expand('~/.thinkvim.d' . a:path)) 137 | if !use_global 138 | execute 'source' fnameescape(abspath) 139 | return 140 | endif 141 | 142 | " substitute all 'set' to 'setglobal' 143 | let content = map(readfile(abspath), 144 | \ 'substitute(v:val, "^\\W*\\zsset\\ze\\W", "setglobal", "")') 145 | " create tempfile and source the tempfile 146 | let tempfile = tempname() 147 | try 148 | call writefile(content, tempfile) 149 | execute 'source' fnameescape(tempfile) 150 | finally 151 | if filereadable(tempfile) 152 | call delete(tempfile) 153 | endif 154 | endtry 155 | endfunction 156 | " Load user custom local settings 157 | if filereadable(s:user_settings_path) 158 | if s:check_custom_settings(s:user_settings_path) 159 | call s:source_custom('/local_settings.vim') 160 | endif 161 | endif 162 | 163 | 164 | set secure 165 | 166 | " vim: set ts=2 sw=2 tw=80 noet : 167 | 168 | ``` 169 | 170 | - 不与`vi`兼容 171 | 172 | ```bash 173 | if &compatible 174 | " vint: -ProhibitSetNoCompatible 175 | set nocompatible 176 | " vint: +ProhibitSetNoCompatible 177 | endif 178 | ``` 179 | 180 | - 设置配置文件目录 181 | 182 | ```shell 183 | " Set main configuration directory as parent directory 184 | let $VIM_PATH = fnamemodify(resolve(expand(':p')), ':h:h') 185 | let s:user_settings_path = expand('~/.thinkvim.d/local_settings.vim') 186 | ``` 187 | 188 | - 设置runtime路径 189 | 190 | 参考: 191 | 192 | 参考:[runtime](./note/runtimepath.md) 193 | 194 | ```shell 195 | " Regular Vim doesn't add custom configuration directories, if you use one 196 | if &runtimepath !~# $VIM_PATH 197 | set runtimepath^=$VIM_PATH 198 | endif 199 | ``` 200 | 201 | - 设置数据目录 202 | 203 | ```shell 204 | let $DATA_PATH = g:etc#cache_path 205 | ``` 206 | 207 | 不知道这个用来做什么 208 | 209 | 关于`#`参考[自动加载](./note/autoload.md) 210 | 211 | - [创建自动命令组](./note/augroup.md) 212 | 213 | 清楚命令组MyAutoCmd 214 | 215 | ```shell 216 | " Set augroup 217 | augroup MyAutoCmd 218 | autocmd! 219 | augroup END 220 | ``` 221 | 222 | 对于这个问题,Vim有一个解决方案。这个解决方案的第一步是将相关的自动命令收集起来放到一个已命名的组(groups)中。 223 | 224 | 新开一个Vim实例,这样可以清除之前所创建的自动命令。 225 | 226 | - 禁用分发插件 227 | 228 | ```shell 229 | " Disable vim distribution plugins 230 | let g:loaded_getscript = 1 231 | let g:loaded_getscriptPlugin = 1 232 | let g:loaded_gzip = 1 233 | let g:loaded_logiPat = 1 234 | let g:loaded_matchit = 1 235 | let g:loaded_matchparen = 1 236 | let g:netrw_nogx = 1 " disable netrw's gx mapping. 237 | let g:loaded_rrhelper = 1 238 | let g:loaded_shada_plugin = 1 239 | let g:loaded_tar = 1 240 | let g:loaded_tarPlugin = 1 241 | let g:loaded_tutor_mode_plugin = 1 242 | let g:loaded_2html_plugin = 1 243 | let g:loaded_vimball = 1 244 | let g:loaded_vimballPlugin = 1 245 | let g:loaded_zip = 1 246 | let g:loaded_zipPlugin = 1 247 | ``` 248 | 249 | 从注释上来下,是做这个的,以后回头再来看这些变量的作用 250 | 251 | - 开始时初始化设置 252 | 253 | ```css 254 | " Initialize base requirements 255 | if has('vim_starting') 256 | " Global Mappings "{{{ 257 | " Use spacebar as leader and ; as secondary-leader 258 | " Required before loading plugins! 259 | let g:mapleader="\" 260 | let g:maplocalleader=';' 261 | 262 | " Release keymappings prefixes, evict entirely for use of plug-ins. 263 | nnoremap 264 | xnoremap 265 | nnoremap , 266 | xnoremap , 267 | nnoremap ; 268 | xnoremap ; 269 | nnoremap m 270 | xnoremap m 271 | if ! has('nvim') && has('pythonx') 272 | if has('python3') 273 | set pyxversion=3 274 | elseif has('python') 275 | set pyxversion=2 276 | endif 277 | endif 278 | 279 | 280 | " Ensure data directories 281 | call etc#util#ensure_directory([ 282 | \ g:etc#cache_path . '/undo', 283 | \ g:etc#cache_path . '/backup', 284 | \ g:etc#cache_path . '/session', 285 | \ g:etc#vim_path . '/spell' 286 | \ ]) 287 | 288 | endif 289 | ``` 290 | 291 | 设置`leader` 292 | 293 | 参考:[Leader](./note/leaders.md) 294 | 295 | ```css 296 | let g:mapleader="\" 297 | let g:maplocalleader=';' 298 | ``` 299 | 300 | 301 | 302 | 303 | 304 | 305 | # 二、主题学习 306 | 307 | 这一章来总结整个架构每个知识点的学习。 308 | 309 | ## 1、插件配置 310 | 311 | 这里插件使用的是`dein`插件管理器来管理插件插件。 312 | 313 | 这里分析是在`thinkvim`中是如何使用`dein`的 314 | 315 | - 初始脚本`init.vim`加载`core/vimrc` 316 | - `core/vimrc`调用`etc#init()` 317 | - `etc#init()`调用`etc#providers#dein#_init()`来完成`dein`脚本的初始化 318 | 319 | 重点来看下这个文件`autoload/etc/providers/dein.vim` 320 | 321 | ```css 322 | function! etc#providers#dein#_init(config_paths) abort 323 | let l:cache_path = $DATA_PATH . '/dein' 324 | 325 | if has('vim_starting') 326 | " Use dein as a plugin manager 327 | let g:dein#auto_recache = 1 328 | let g:dein#install_max_processes = 16 329 | let g:dein#install_progress_type = 'echo' 330 | let g:dein#enable_notification = 1 331 | let g:dein#install_log_filename = $DATA_PATH . '/dein.log' 332 | 333 | " Add dein to vim's runtimepath 334 | if &runtimepath !~# '/dein.vim' 335 | let s:dein_dir = l:cache_path . '/repos/github.com/Shougo/dein.vim' 336 | " Clone dein if first-time setup 337 | if ! isdirectory(s:dein_dir) 338 | execute '!git clone https://github.com/Shougo/dein.vim' s:dein_dir 339 | if v:shell_error 340 | call s:error('dein installation has failed! is git installed?') 341 | finish 342 | endif 343 | endif 344 | 345 | execute 'set runtimepath+='.substitute( 346 | \ fnamemodify(s:dein_dir, ':p') , '/$', '', '') 347 | endif 348 | endif 349 | 350 | " Initialize dein.vim (package manager) 351 | if dein#load_state(l:cache_path) 352 | let l:rc = etc#_parse_config_files(a:config_paths) 353 | if empty(l:rc) 354 | call etc#util#error('Empty plugin list') 355 | return 356 | endif 357 | " Start propagating file paths and plugin presets 358 | call dein#begin(l:cache_path, extend([expand('')], a:config_paths)) 359 | for plugin in l:rc 360 | call dein#add(plugin['repo'], extend(plugin, {}, 'keep')) 361 | endfor 362 | 363 | " Add any local ./dev plugins 364 | if isdirectory(g:etc#vim_path.'/dev') 365 | call dein#local(g:etc#vim_path.'/dev', {'frozen': 1, 'merged': 0}) 366 | endif 367 | call dein#end() 368 | call dein#save_state() 369 | 370 | " Update or install plugins if a change detected 371 | if dein#check_install() 372 | if ! has('nvim') 373 | set nomore 374 | endif 375 | call dein#install() 376 | endif 377 | endif 378 | 379 | filetype plugin indent on 380 | 381 | " Trigger source events, only when vim is starting 382 | if has('vim_starting') 383 | syntax enable 384 | else 385 | call dein#call_hook('source') 386 | call dein#call_hook('post_source') 387 | endif 388 | endfunction 389 | ``` 390 | 391 | `nvim`启动时将开始判断路径 392 | 393 | ```css 394 | let s:dein_dir = l:cache_path . '/repos/github.com/Shougo/dein.vim' 395 | ``` 396 | 397 | 判断这个路径是否存在 398 | 399 | 在我的电脑上是:`/home/pix/.cache/vim/dein/repos/github.com/Shougo/dein.vim` 400 | 401 | 就是`dein`的路径 402 | 403 | 接下来: 404 | 405 | ```css 406 | if ! isdirectory(s:dein_dir) 407 | execute '!git clone https://github.com/Shougo/dein.vim' s:dein_dir 408 | if v:shell_error 409 | call s:error('dein installation has failed! is git installed?') 410 | finish 411 | endif 412 | endif 413 | ``` 414 | 415 | 如果路径不存在`clone dein仓库代码`到`s:dein_dir`目录 416 | 417 | 将`dein`安装目录加到`runtimepath` 418 | 419 | ```css 420 | execute 'set runtimepath+='.substitute( 421 | \ fnamemodify(s:dein_dir, ':p') , '/$', '', '') 422 | ``` 423 | 424 | - 然后加载插件配置文件 425 | 426 | - 执行dein加载插件流程 427 | 428 | - 安装插件 429 | 430 | - 其他操作: 431 | 432 | ```css 433 | " Trigger source events, only when vim is starting 434 | if has('vim_starting') 435 | syntax enable 436 | else 437 | call dein#call_hook('source') 438 | call dein#call_hook('post_source') 439 | endif 440 | ``` 441 | 442 | 参考:使用`YAML`管理插件:http://genkisugimoto.com/blog/manage-vim-plugins-via-yaml/ 443 | 444 | - 插件的配置文件:`core/dein/plugins.yaml` 445 | 446 | - 插件的快捷键配置文件:`layers/+thinkvim/config.vim` 447 | 448 | # 三、插件学习 449 | 450 | 插件的大概加载流程和配置文件目录已经知道了,接下来学习配置每个插件和学习每个插件的作用。 451 | 452 | ## 1、插件`denite.nvim` 453 | 454 | `github:https://github.com/Shougo/denite.nvim ` 455 | 456 | 看了下,这个插件是扩展用的,看作者的配置是用来处理`GoLang`的,暂时略过,先看别的 457 | 458 | 参考: 459 | 460 | plugins.yaml 461 | 462 | ```yaml 463 | - repo: Shougo/denite.nvim 464 | on_cmd: Denite 465 | depends: vim-devicons 466 | hook_source: | 467 | source $VIM_PATH/layers/+completion/denite/config.vim 468 | source $VIM_PATH/layers/+completion/denite/+denite_menu.vim 469 | ``` 470 | 471 | - `$VIM_PATH/layers/+completion/denite/config.vim` 472 | 473 | ```css 474 | call denite#custom#option('_', { 475 | \ 'cached_filter': v:true, 476 | \ 'cursor_shape': v:true, 477 | \ 'cursor_wrap': v:true, 478 | \ 'highlight_filter_background': 'DeniteFilter', 479 | \ 'highlight_matched_char': 'Underlined', 480 | \ 'matchers': 'matcher/fuzzy', 481 | \ 'prompt': 'λ ', 482 | \ 'split': 'floating', 483 | \ 'start_filter': v:false, 484 | \ 'statusline': v:false, 485 | \ }) 486 | function! s:denite_detect_size() abort 487 | let s:denite_winheight = 20 488 | let s:denite_winrow = &lines > s:denite_winheight ? (&lines - s:denite_winheight) / 2 : 0 489 | let s:denite_winwidth = &columns > 240 ? &columns / 2 : 120 490 | let s:denite_wincol = &columns > s:denite_winwidth ? (&columns - s:denite_winwidth) / 2 : 0 491 | call denite#custom#option('_', { 492 | \ 'wincol': s:denite_wincol, 493 | \ 'winheight': s:denite_winheight, 494 | \ 'winrow': s:denite_winrow, 495 | \ 'winwidth': s:denite_winwidth, 496 | \ }) 497 | endfunction 498 | augroup denite-detect-size 499 | autocmd! 500 | autocmd VimResized * call denite_detect_size() 501 | augroup END 502 | call s:denite_detect_size() 503 | 504 | 505 | call denite#custom#option('search', { 'start_filter': 0, 'no_empty': 1 }) 506 | call denite#custom#option('list', { 'start_filter': 0 }) 507 | call denite#custom#option('jump', { 'start_filter': 0 }) 508 | call denite#custom#option('git', { 'start_filter': 0 }) 509 | call denite#custom#option('mpc', { 'winheight': 20 }) 510 | 511 | 512 | " MATCHERS 513 | " Default is 'matcher/fuzzy' 514 | call denite#custom#source('tag', 'matchers', ['matcher/substring']) 515 | call denite#custom#source('file/rec', 'matchers', ['matcher/fuzzy']) 516 | 517 | if has('nvim') && &runtimepath =~# '\/cpsm' 518 | call denite#custom#source( 519 | \ 'buffer,file_mru,file/old,file/rec,grep,mpc,line,neoyank', 520 | \ 'matchers', ['matcher/cpsm', 'matcher/fuzzy']) 521 | endif 522 | 523 | 524 | " CONVERTERS 525 | " Default is none 526 | call denite#custom#source( 527 | \ 'buffer,file_mru,file/old,file/rec,directory/rec,directory_mru', 528 | \ 'converters', ['devicons_denite_converter','converter_relative_word']) 529 | 530 | " FIND and GREP COMMANDS 531 | if executable('ag') 532 | " The Silver Searcher 533 | call denite#custom#var('file/rec', 'command', 534 | \ ['ag', '-U', '--hidden', '--follow', '--nocolor', '--nogroup', '-g', '']) 535 | 536 | " Setup ignore patterns in your .agignore file! 537 | " https://github.com/ggreer/the_silver_searcher/wiki/Advanced-Usage 538 | 539 | call denite#custom#var('grep', 'command', ['ag']) 540 | call denite#custom#var('grep', 'recursive_opts', []) 541 | call denite#custom#var('grep', 'pattern_opt', []) 542 | call denite#custom#var('grep', 'separator', ['--']) 543 | call denite#custom#var('grep', 'final_opts', []) 544 | call denite#custom#var('grep', 'default_opts', 545 | \ [ '--skip-vcs-ignores', '--vimgrep', '--smart-case', '--hidden' ]) 546 | 547 | elseif executable('ack') 548 | " Ack command 549 | call denite#custom#var('grep', 'command', ['ack']) 550 | call denite#custom#var('grep', 'recursive_opts', []) 551 | call denite#custom#var('grep', 'pattern_opt', ['--match']) 552 | call denite#custom#var('grep', 'separator', ['--']) 553 | call denite#custom#var('grep', 'final_opts', []) 554 | call denite#custom#var('grep', 'default_opts', 555 | \ ['--ackrc', $HOME.'/.config/ackrc', '-H', 556 | \ '--nopager', '--nocolor', '--nogroup', '--column']) 557 | 558 | elseif executable('rg') 559 | " Ripgrep 560 | call denite#custom#var('file/rec', 'command', 561 | \ ['rg', '--files', '--glob', '!.git']) 562 | call denite#custom#var('grep', 'command', ['rg', '--threads', '1']) 563 | call denite#custom#var('grep', 'recursive_opts', []) 564 | call denite#custom#var('grep', 'final_opts', []) 565 | call denite#custom#var('grep', 'separator', ['--']) 566 | call denite#custom#var('grep', 'default_opts', 567 | \ ['-i', '--vimgrep', '--no-heading']) 568 | endif 569 | 570 | 571 | " KEY MAPPINGS 572 | autocmd FileType denite call s:denite_settings() 573 | function! s:denite_settings() abort 574 | highlight! link CursorLine Visual 575 | nnoremap denite#do_map('do_action') 576 | nnoremap i denite#do_map('open_filter_buffer') 577 | nnoremap d denite#do_map('do_action', 'delete') 578 | nnoremap p denite#do_map('do_action', 'preview') 579 | nnoremap st denite#do_map('do_action', 'tabopen') 580 | nnoremap sv denite#do_map('do_action', 'vsplit') 581 | nnoremap si denite#do_map('do_action', 'split') 582 | nnoremap ' denite#do_map('quick_move') 583 | nnoremap q denite#do_map('quit') 584 | nnoremap r denite#do_map('redraw') 585 | nnoremap yy denite#do_map('do_action', 'yank') 586 | nnoremap denite#do_map('quit') 587 | nnoremap denite#do_map('restore_sources') 588 | nnoremap denite#do_map('do_action', 'defx') 589 | nnoremap denite#do_map('choose_action') 590 | nnoremap denite#do_map('toggle_select').'j' 591 | endfunction 592 | 593 | autocmd FileType denite-filter call s:denite_filter_settings() 594 | function! s:denite_filter_settings() abort 595 | nnoremap denite#do_map('quit') 596 | " inoremap denite#do_map('quit') 597 | nnoremap q denite#do_map('quit') 598 | imap (denite_filter_quit) 599 | "inoremap denite#do_map('quit') 600 | nnoremap denite#do_map('quit') 601 | inoremap kk p 602 | nnoremap kk p 603 | inoremap jj p 604 | nnoremap jj p 605 | endfunction 606 | 607 | " vim: set ts=3 sw=2 tw=80 noet : 608 | ``` 609 | 610 | - `$VIM_PATH/layers/+completion/denite/+denite_menu.vim` 611 | 612 | ```yaml 613 | let s:menus = {} 614 | 615 | let s:menus.dein = { 'description': '⚔️ Plugin management' } 616 | let s:menus.dein.command_candidates = [ 617 | \ ['🐬 Dein: Plugins update 🔸', 'call dein#update()'], 618 | \ ['🐬 Dein: Plugins List 🔸', 'Denite dein'], 619 | \ ['🐬 Dein: RecacheRuntimePath 🔸', 'call dein#recache_runtimepath()'], 620 | \ ['🐬 Dein: Update log 🔸', 'echo dein#get_updates_log()'], 621 | \ ['🐬 Dein: Log 🔸', 'echo dein#get_log()'], 622 | \ ] 623 | 624 | let s:menus.project = { 'description': '🛠 Project & Structure' } 625 | let s:menus.project.command_candidates = [ 626 | \ ['🐳 File Explorer 🔸e', 'Defx -resume -toggle -buffer-name=tab`tabpagenr()`'], 627 | \ ['🐳 Outline 🔸t', 'TagbarToggle'], 628 | \ ['🐳 Git Status 🔸gs', 'Denite gitstatus'], 629 | \ ['🐳 Mundo Tree 🔸m', 'MundoToggle'], 630 | \ ] 631 | 632 | let s:menus.files = { 'description': '📁 File tools' } 633 | let s:menus.files.command_candidates = [ 634 | \ ['📂 Denite: Find in files… 🔹 ', 'Denite grep:.'], 635 | \ ['📂 Denite: Find files 🔹 ', 'Denite file/rec'], 636 | \ ['📂 Denite: Buffers 🔹 ', 'Denite buffer'], 637 | \ ['📂 Denite: MRU 🔹 ', 'Denite file/old'], 638 | \ ['📂 Denite: Line 🔹 ', 'Denite line'], 639 | \ ] 640 | 641 | let s:menus.tools = { 'description': '⚙️ Dev Tools' } 642 | let s:menus.tools.command_candidates = [ 643 | \ ['🐠 Git commands 🔹', 'Git'], 644 | \ ['🐠 Git log 🔹', 'Denite gitlog:all'], 645 | \ ['🐠 Goyo 🔹', 'Goyo'], 646 | \ ['🐠 Tagbar 🔹', 'TagbarToggle'], 647 | \ ['🐠 File explorer 🔹', 'Defx -resume -toggle -buffer-name=tab`tabpagenr()`'], 648 | \ ] 649 | 650 | let s:menus.config = { 'description': '🔧 Zsh Tmux Configuration' } 651 | let s:menus.config.file_candidates = [ 652 | \ ['🐠 Zsh Configurationfile 🔸', '~/.zshrc'], 653 | \ ['🐠 Tmux Configurationfile 🔸', '~/.tmux.conf'], 654 | \ ] 655 | 656 | let s:menus.thinkvim = {'description': '💎 ThinkVim Configuration files'} 657 | let s:menus.thinkvim.file_candidates = [ 658 | \ ['🐠 MainVimrc settings: vimrc 🔹', $VIMPATH.'/core/vimrc'], 659 | \ ['🐠 Initial settings: init.vim 🔹', $VIMPATH.'/core/init.vim'], 660 | \ ['🐠 General settings: general.vim 🔹', $VIMPATH.'/core/general.vim'], 661 | \ ['🐠 DeinConfig settings: deinrc.vim 🔹', $VIMPATH.'/core/deinrc.vim'], 662 | \ ['🐠 FileTypes settings: filetype.vim 🔹', $VIMPATH.'/core/filetype.vim'], 663 | \ ['🐠 Installed LoadPlugins: plugins.yaml 🔹', $VIMPATH.'/core/dein/plugins.yaml'], 664 | \ ['🐠 Installed LocalPlugins: local_plugins.yaml 🔹', $VIMPATH.'/core/dein/local_plugins.yaml'], 665 | \ ['🐠 Global Key Vimmappings: mappings.vim 🔹', $VIMPATH.'/core/mappings.vim'], 666 | \ ['🐠 Global Key Pluginmappings: Pluginmappings 🔹', $VIMPATH.'/core/plugins/allkey.vim'], 667 | \ ] 668 | 669 | call denite#custom#var('menu', 'menus', s:menus) 670 | 671 | "let s:menus.sessions = { 'description': 'Sessions' } 672 | "let s:menus.sessions.command_candidates = [ 673 | "\ ['▶ Restore session │ ;s', 'Denite session'], 674 | "\ ['▶ Save session… │', 'Denite session/new'], 675 | "\ ] 676 | ``` 677 | 678 | 679 | 680 | ## 2、插件fzf.vim 681 | 682 | 插件的github:https://github.com/junegunn/fzf.vim 683 | 684 | 首先是`core/dein/plugins.yaml`中的配置 685 | 686 | ```yaml 687 | - repo: junegunn/fzf 688 | build: './install --all' 689 | merged: 0 690 | 691 | - repo: junegunn/fzf.vim 692 | depends: fzf 693 | on_cmd: [Colors,Rg,Buffers] 694 | on_func: Fzf_dev 695 | hook_source: source $VIM_PATH/layers/+completion/fzf/config.vim 696 | ``` 697 | 698 | 这里hook_source:`hook_source: source $VIM_PATH/layers/+completion/fzf/config.vim` 699 | 700 | ```css 701 | "autocmd! FileType fzf 702 | "autocmd FileType fzf set laststatus=0 noshowmode noruler 703 | "\| autocmd BufLeave set laststatus=0 showmode ruler 704 | " 705 | let g:fzf_action = { 706 | \ 'ctrl-t': 'tab split', 707 | \ 'ctrl-x': 'split', 708 | \ 'ctrl-v': 'vsplit' } 709 | 710 | " Customize fzf colors to match your color scheme 711 | let g:fzf_colors = 712 | \ { 'fg': ['fg', 'Normal'], 713 | \ 'bg': ['bg', '#5f5f87'], 714 | \ 'hl': ['fg', 'Comment'], 715 | \ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'], 716 | \ 'bg+': ['bg', 'CursorLine', 'CursorColumn'], 717 | \ 'hl+': ['fg', 'Statement'], 718 | \ 'info': ['fg', 'PreProc'], 719 | \ 'border': ['fg', 'Ignore'], 720 | \ 'prompt': ['fg', 'Conditional'], 721 | \ 'pointer': ['fg', 'Exception'], 722 | \ 'marker': ['fg', 'Keyword'], 723 | \ 'spinner': ['fg', 'Label'], 724 | \ 'header': ['fg', 'Comment'] } 725 | 726 | let g:fzf_commits_log_options = '--graph --color=always 727 | \ --format="%C(yellow)%h%C(red)%d%C(reset) 728 | \ - %C(bold green)(%ar)%C(reset) %s %C(blue)<%an>%C(reset)"' 729 | 730 | "let $FZF_DEFAULT_COMMAND = 'ag --hidden -l -g ""' 731 | " ripgrep 732 | if executable('rg') 733 | let $FZF_DEFAULT_COMMAND = 'rg --files --hidden --follow --glob "!.git/*"' 734 | set grepprg=rg\ --vimgrep 735 | command! -bang -nargs=* Find call fzf#vim#grep('rg --column --line-number --no-heading --fixed-strings --ignore-case --hidden --follow --glob "!.git/*" --color "always" '.shellescape().'| tr -d "\017"', 1, 0) 736 | endif 737 | 738 | let $FZF_DEFAULT_OPTS='--layout=reverse' 739 | let g:fzf_layout = { 'window': 'call FloatingFZF()' } 740 | 741 | function! FloatingFZF() 742 | let buf = nvim_create_buf(v:false, v:true) 743 | call setbufvar(buf, 'number', 'no') 744 | 745 | let height = float2nr(&lines/2) 746 | let width = float2nr(&columns - (&columns * 2 / 10)) 747 | "let width = &columns 748 | let row = float2nr(&lines / 3) 749 | let col = float2nr((&columns - width) / 3) 750 | 751 | let opts = { 752 | \ 'relative': 'editor', 753 | \ 'row': row, 754 | \ 'col': col, 755 | \ 'width': width, 756 | \ 'height':height, 757 | \ } 758 | let win = nvim_open_win(buf, v:true, opts) 759 | call setwinvar(win, '&number', 0) 760 | call setwinvar(win, '&relativenumber', 0) 761 | endfunction 762 | 763 | " Files + devicons 764 | function! Fzf_dev() 765 | 766 | let l:fzf_files_options = ' -m --bind ctrl-d:preview-page-down,ctrl-u:preview-page-up --preview "bat --color always --style numbers {2..}"' 767 | 768 | function! s:files() 769 | let l:files = split(system($FZF_DEFAULT_COMMAND), '\n') 770 | return s:prepend_icon(l:files) 771 | endfunction 772 | 773 | function! s:prepend_icon(candidates) 774 | let result = [] 775 | for candidate in a:candidates 776 | let filename = fnamemodify(candidate, ':p:t') 777 | let icon = WebDevIconsGetFileTypeSymbol(filename, isdirectory(filename)) 778 | call add(result, printf("%s %s", icon, candidate)) 779 | endfor 780 | 781 | return result 782 | endfunction 783 | 784 | function! s:edit_file(items) 785 | let items = a:items 786 | let i = 1 787 | let ln = len(items) 788 | while i < ln 789 | let item = items[i] 790 | let parts = split(item, ' ') 791 | let file_path = get(parts, 1, '') 792 | let items[i] = file_path 793 | let i += 1 794 | endwhile 795 | call s:Sink(items) 796 | endfunction 797 | 798 | let opts = fzf#wrap({}) 799 | let opts.source = files() 800 | let s:Sink = opts['sink*'] 801 | let opts['sink*'] = function('s:edit_file') 802 | let opts.options .= l:fzf_files_options 803 | call fzf#run(opts) 804 | endfunction 805 | 806 | ``` 807 | 808 | 809 | 810 | ## 3、插件which-key 811 | 812 | Github:https://github.com/liuchengxu/vim-which-key 813 | 原作者博客:https://www.jianshu.com/p/e47f7ec27cea 814 | 815 | 首先是`core/dein/plugins.yaml`中的配置 816 | 817 | ```yaml 818 | - repo: liuchengxu/vim-which-key 819 | on_cmd: [Whichkey, Whichkey!] 820 | hook_source: source $VIM_PATH/layers/+tools/whichkey/config.vim 821 | hook_post_source: | 822 | call which_key#register('', 'g:which_key_map') 823 | call which_key#register(';', 'g:which_key_localmap') 824 | call which_key#register(']', 'g:which_key_rsbgmap') 825 | call which_key#register('[', 'g:which_key_lsbgmap') 826 | ``` 827 | 828 | 插件配置文件:` $VIM_PATH/layers/+tools/whichkey/config.vim` 829 | 830 | ```css 831 | let g:which_key_map = {} 832 | let g:which_key_map = { 833 | \ 'name' : '+ThinkVim root ' , 834 | \ '1' : 'select window-1' , 835 | \ '2' : 'select window-2' , 836 | \ '3' : 'select window-3' , 837 | \ '4' : 'select window-4' , 838 | \ '5' : 'select window-5' , 839 | \ '6' : 'select window-6' , 840 | \ '7' : 'select window-7' , 841 | \ '8' : 'select window-8' , 842 | \ '9' : 'select window-9' , 843 | \ '0' : 'select window-10' , 844 | \ 'a' : { 845 | \ 'name' : '+coc-code-action', 846 | \ 'c' : 'code action', 847 | \ }, 848 | \ 'b' : { 849 | \ 'name' : '+buffer', 850 | \ 'b' : 'buffer list', 851 | \ 'c' : 'keep current buffer', 852 | \ 'o' : 'keep input buffer', 853 | \ }, 854 | \ 'e' : 'open file explorer' , 855 | \ '-' : 'choose window by {prompt char}' , 856 | \ 'd' : 'search cursor word on Dash.app' , 857 | \ 'G' : 'distraction free writing' , 858 | \ 'F' : 'find current file' , 859 | \ 'f' : { 860 | \ 'name' : '+search {files cursorword word outline}', 861 | \ 'f' : 'find file', 862 | \ 'r' : 'search {word}', 863 | \ 'c' : 'change colorscheme', 864 | \ 'w' : 'search cursorword', 865 | \ 'v' : 'search outline', 866 | \ }, 867 | \ 'm' : 'open mundotree' , 868 | \ 'w' : 'save file', 869 | \ 'j' : 'open coc-explorer', 870 | \ 's' : 'open startify screen', 871 | \ 'p' : 'edit pluginsconfig {filename}', 872 | \ 'x' : 'coc cursors operate', 873 | \ 'g' :{ 874 | \'name':'+git-operate', 875 | \ 'd' : 'Gdiff', 876 | \ 'c' : 'Gcommit', 877 | \ 'b' : 'Gblame', 878 | \ 'B' : 'Gbrowse', 879 | \ 'S' : 'Gstatus', 880 | \ 'p' : 'git push', 881 | \ 'l' : 'GitLogAll', 882 | \ 'h' : 'GitBranch', 883 | \}, 884 | \ 'c' : { 885 | \ 'name' : '+coc list' , 886 | \ 'a' : 'coc CodeActionSelected', 887 | \ 'd' : 'coc Diagnostics', 888 | \ 'c' : 'coc Commands', 889 | \ 'e' : 'coc Extensions', 890 | \ 'j' : 'coc Next', 891 | \ 'k' : 'coc Prev', 892 | \ 'o' : 'coc OutLine', 893 | \ 'r' : 'coc Resume', 894 | \ 'n' : 'coc Rename', 895 | \ 's' : 'coc Isymbols', 896 | \ 'g' : 'coc Gitstatus', 897 | \ 'f' : 'coc Format', 898 | \ 'm' : 'coc search word to multiple cursors', 899 | \ }, 900 | \ 'q' : { 901 | \ 'name' : '+coc-quickfix', 902 | \ 'f' : 'coc fixcurrent', 903 | \ }, 904 | \ 't' : { 905 | \ 'name' : '+tab-operate', 906 | \ 'n' : 'new tab', 907 | \ 'e' : 'edit tab', 908 | \ 'm' : 'move tab', 909 | \ }, 910 | \ } 911 | let g:which_key_map[' '] = { 912 | \ 'name' : '+easymotion-jumpto-word ' , 913 | \ 'b' : ['(easymotion-b)' , 'beginning of word backward'], 914 | \ 'f' : ['(easymotion-f)' , 'find {char} to the left'], 915 | \ 'w' : ['(easymotion-w)' , 'beginning of word forward'], 916 | \ } 917 | 918 | let g:which_key_localmap ={ 919 | \ 'name' : '+LocalLeaderKey' , 920 | \ 'v' : 'open vista show outline', 921 | \ 'r' : 'quick run', 922 | \ 'm' : 'toolkit Menu', 923 | \ 'g' : { 924 | \ 'name' : '+golang-toolkit', 925 | \ 'i' : 'go impl', 926 | \ 'd' : 'go describe', 927 | \ 'c' : 'go callees', 928 | \ 'C' : 'go callers', 929 | \ 's' : 'go callstack', 930 | \ }, 931 | \ } 932 | 933 | let g:which_key_rsbgmap = { 934 | \ 'name' : '+RightSquarebrackets', 935 | \ 'a' : 'ale nextwarp', 936 | \ 'c' : 'coc nextdiagnostics', 937 | \ 'b' : 'next buffer', 938 | \ 'g' : 'coc gitnextchunk', 939 | \ ']' : 'jump prefunction-golang', 940 | \ } 941 | 942 | 943 | let g:which_key_lsbgmap = { 944 | \ 'name' : '+LeftSquarebrackets', 945 | \ 'a' : 'ale prewarp', 946 | \ 'c' : 'coc prediagnostics', 947 | \ 'b' : 'pre buffer', 948 | \ 'g' : 'coc gitprevchunk', 949 | \ '[' : 'jump nextfunction-golang', 950 | \ } 951 | 952 | let s:current_colorscheme = get(g:,"colors_name","") 953 | if s:current_colorscheme == "base16-default-dark" 954 | highlight WhichKeySeperator guibg=NONE ctermbg=NONE guifg=#a1b56c ctermfg=02 955 | endif 956 | 957 | ``` 958 | 959 | ## 4、vim-gutentags 960 | 961 | 这个是用来自动生成tags的插件 962 | 963 | Github:https://github.com/ludovicchabant/vim-gutentags 964 | 965 | 参考阅读:https://www.cnblogs.com/pengdonglin137/articles/10202606.html 966 | 967 | 首先是core/dein/plugins.yaml中的配置 968 | 969 | ```yaml 970 | - repo: ludovicchabant/vim-gutentags 971 | if: executable('ctags') 972 | on_path: .* 973 | hook_source: source $VIM_PATH/layers/+tools/vim-gutentags/config.vim 974 | ``` 975 | 976 | 配置文件` $VIM_PATH/layers/+tools/vim-gutentags/config.vim` 977 | 978 | ```css 979 | let g:gutentags_cache_dir = $DATA_PATH . '/tags' 980 | let g:gutentags_project_root = ['.root', '.git', '.svn', '.hg', '.project','go.mod','/usr/local'] 981 | let g:gutentags_generate_on_write = 1 982 | let g:gutentags_generate_on_missing = 1 983 | let g:gutentags_generate_on_new = 0 984 | let g:gutentags_exclude_filetypes = [ 'defx', 'denite', 'vista', 'magit' ] 985 | let g:gutentags_ctags_extra_args = ['--output-format=e-ctags'] 986 | let g:gutentags_ctags_exclude = ['*.json', '*.js', '*.ts', '*.jsx', '*.css', '*.less', '*.sass', '*.go', '*.dart', 'node_modules', 'dist', 'vendor'] 987 | ``` 988 | 989 | ## 5、defx.nvim 990 | 991 | github:https://github.com/Shougo/defx.nvim 992 | 993 | 这个插件是用来浏览文件目录的,取代NERDTree 994 | 995 | 首先是core/dein/plugins.yaml中的配置 996 | 997 | ```yaml 998 | - repo: Shougo/defx.nvim 999 | on_cmd: Defx 1000 | hook_source: source $VIM_PATH/layers/+ui/defx/config.vim 1001 | ``` 1002 | 1003 | 配置文件:`$VIM_PATH/layers/+ui/defx/config.vim` 1004 | 1005 | ```css 1006 | " Defx 1007 | call defx#custom#option('_', { 1008 | \ 'columns': 'indent:git:icons:filename', 1009 | \ 'winwidth': 30, 1010 | \ 'split': 'vertical', 1011 | \ 'direction': 'topleft', 1012 | \ 'show_ignored_files': 0, 1013 | \ }) 1014 | 1015 | 1016 | " Events 1017 | " --- 1018 | 1019 | augroup user_plugin_defx 1020 | autocmd! 1021 | 1022 | " autocmd DirChanged * call s:defx_refresh_cwd(v:event) 1023 | 1024 | " Delete defx if it's the only buffer left in the window 1025 | " autocmd WinEnter * if &filetype == 'defx' && winnr('$') == 1 | bd | endif 1026 | 1027 | " Move focus to the next window if current buffer is defx 1028 | autocmd TabLeave * if &filetype == 'defx' | wincmd w | endif 1029 | 1030 | autocmd TabClosed * call s:defx_close_tab(expand('')) 1031 | 1032 | " Define defx window mappings 1033 | autocmd FileType defx call s:defx_mappings() 1034 | 1035 | augroup END 1036 | 1037 | " Internal functions 1038 | " --- 1039 | 1040 | function! s:defx_close_tab(tabnr) 1041 | " When a tab is closed, find and delete any associated defx buffers 1042 | for l:nr in range(1, bufnr('$')) 1043 | let l:defx = getbufvar(l:nr, 'defx') 1044 | if empty(l:defx) 1045 | continue 1046 | endif 1047 | let l:context = get(l:defx, 'context', {}) 1048 | if get(l:context, 'buffer_name', '') ==# 'tab' . a:tabnr 1049 | silent! execute 'bdelete '.l:nr 1050 | break 1051 | endif 1052 | endfor 1053 | endfunction 1054 | 1055 | function! s:defx_toggle_tree() abort 1056 | " Open current file, or toggle directory expand/collapse 1057 | if defx#is_directory() 1058 | return defx#do_action('open_or_close_tree') 1059 | endif 1060 | return defx#do_action('multi', ['drop']) 1061 | endfunction 1062 | 1063 | function! s:defx_refresh_cwd(event) 1064 | " Automatically refresh opened Defx windows when changing working-directory 1065 | let l:cwd = get(a:event, 'cwd', '') 1066 | let l:scope = get(a:event, 'scope', '') " global, tab, window 1067 | let l:is_opened = bufwinnr('defx') > -1 1068 | if ! l:is_opened || empty(l:cwd) || empty(l:scope) 1069 | return 1070 | endif 1071 | 1072 | " Abort if Defx is already on the cwd triggered (new files trigger this) 1073 | let l:paths = get(getbufvar('defx', 'defx', {}), 'paths', []) 1074 | if index(l:paths, l:cwd) >= 0 1075 | return 1076 | endif 1077 | 1078 | let l:tab = tabpagenr() 1079 | call execute(printf('Defx -buffer-name=tab%s %s', l:tab, l:cwd)) 1080 | wincmd p 1081 | endfunction 1082 | 1083 | function! s:jump_dirty(dir) abort 1084 | " Jump to the next position with defx-git dirty symbols 1085 | let l:icons = get(g:, 'defx_git_indicators', {}) 1086 | let l:icons_pattern = join(values(l:icons), '\|') 1087 | 1088 | if ! empty(l:icons_pattern) 1089 | let l:direction = a:dir > 0 ? 'w' : 'bw' 1090 | return search(printf('\(%s\)', l:icons_pattern), l:direction) 1091 | endif 1092 | endfunction 1093 | 1094 | function! s:defx_mappings() abort 1095 | " Defx window keyboard mappings 1096 | setlocal signcolumn=no 1097 | 1098 | nnoremap defx#do_action('drop') 1099 | nnoremap l defx_toggle_tree() 1100 | nnoremap h defx#async_action('cd', ['..']) 1101 | nnoremap st defx#do_action('multi', [['drop', 'tabnew'], 'quit']) 1102 | nnoremap s defx#do_action('open', 'botright vsplit') 1103 | nnoremap i defx#do_action('open', 'botright split') 1104 | nnoremap P defx#do_action('open', 'pedit') 1105 | nnoremap K defx#do_action('new_directory') 1106 | nnoremap N defx#do_action('new_multiple_files') 1107 | nnoremap dd defx#do_action('remove_trash') 1108 | nnoremap r defx#do_action('rename') 1109 | nnoremap x defx#do_action('execute_system') 1110 | nnoremap . defx#do_action('toggle_ignored_files') 1111 | nnoremap yy defx#do_action('yank_path') 1112 | nnoremap ~ defx#async_action('cd') 1113 | nnoremap q defx#do_action('quit') 1114 | nnoremap winnr('$') != 1 ? 1115 | \ ':wincmd w' : 1116 | \ ':Defx -buffer-name=temp -split=vertical' 1117 | 1118 | nnoremap [g :call jump_dirty(-1) 1119 | nnoremap ]g :call jump_dirty(1) 1120 | 1121 | nnoremap \ defx#do_action('cd', getcwd()) 1122 | nnoremap & defx#do_action('cd', getcwd()) 1123 | nnoremap c defx#do_action('copy') 1124 | nnoremap m defx#do_action('move') 1125 | nnoremap p defx#do_action('paste') 1126 | 1127 | nnoremap 1128 | \ defx#do_action('toggle_select') . 'j' 1129 | 1130 | nnoremap ' defx#do_action('toggle_select') . 'j' 1131 | nnoremap * defx#do_action('toggle_select_all') 1132 | nnoremap defx#do_action('redraw') 1133 | nnoremap defx#do_action('print') 1134 | 1135 | nnoremap S defx#do_action('toggle_sort', 'Time') 1136 | nnoremap C 1137 | \ defx#do_action('toggle_columns', 'indent:mark:filename:type:size:time') 1138 | 1139 | " Tools 1140 | nnoremap gx defx#async_action('execute_system') 1141 | nnoremap gd defx#async_action('multi', ['drop', ['call', 'git_diff']]) 1142 | nnoremap gl defx#async_action('call', 'explorer') 1143 | nnoremap gr defx#do_action('call', 'grep') 1144 | nnoremap gf defx#do_action('call', 'find_files') 1145 | nnoremap w defx#async_action('call', 'toggle_width') 1146 | endfunction 1147 | 1148 | " TOOLS 1149 | " --- 1150 | 1151 | function! s:git_diff(context) abort 1152 | execute 'GdiffThis' 1153 | endfunction 1154 | 1155 | function! s:find_files(context) abort 1156 | " Find files in parent directory with Denite 1157 | let l:target = a:context['targets'][0] 1158 | let l:parent = fnamemodify(l:target, ':h') 1159 | silent execute 'wincmd w' 1160 | silent execute 'Denite file/rec:'.l:parent 1161 | endfunction 1162 | 1163 | function! s:grep(context) abort 1164 | " Grep in parent directory with Denite 1165 | let l:target = a:context['targets'][0] 1166 | let l:parent = fnamemodify(l:target, ':h') 1167 | silent execute 'wincmd w' 1168 | silent execute 'Denite grep:'.l:parent 1169 | endfunction 1170 | 1171 | function! s:toggle_width(context) abort 1172 | " Toggle between defx window width and longest line 1173 | let l:max = 0 1174 | let l:original = a:context['winwidth'] 1175 | for l:line in range(1, line('$')) 1176 | let l:len = len(getline(l:line)) 1177 | if l:len > l:max 1178 | let l:max = l:len 1179 | endif 1180 | endfor 1181 | execute 'vertical resize ' . (l:max == winwidth('.') ? l:original : l:max) 1182 | endfunction 1183 | 1184 | function! s:explorer(context) abort 1185 | " Open file-explorer split with tmux 1186 | let l:explorer = s:find_file_explorer() 1187 | if empty('$TMUX') || empty(l:explorer) 1188 | return 1189 | endif 1190 | let l:target = a:context['targets'][0] 1191 | let l:parent = fnamemodify(l:target, ':h') 1192 | let l:cmd = 'split-window -p 30 -c ' . l:parent . ' ' . l:explorer 1193 | silent execute '!tmux ' . l:cmd 1194 | endfunction 1195 | 1196 | function! s:find_file_explorer() abort 1197 | " Detect terminal file-explorer 1198 | let s:file_explorer = get(g:, 'terminal_file_explorer', '') 1199 | if empty(s:file_explorer) 1200 | for l:explorer in ['lf', 'hunter', 'ranger', 'vifm'] 1201 | if executable(l:explorer) 1202 | let s:file_explorer = l:explorer 1203 | break 1204 | endif 1205 | endfor 1206 | endif 1207 | return s:file_explorer 1208 | endfunction 1209 | ``` 1210 | 1211 | ## 6、vim-easygit 1212 | 1213 | Github:https://github.com/neoclide/vim-easygit 1214 | 1215 | 用来vim支持git的插件。 1216 | 1217 | 首先是core/dein/plugins.yaml中的配置 1218 | 1219 | ```yaml 1220 | - repo: chemzqm/vim-easygit 1221 | on_cmd: [Gcd, Glcd, Gcommit, Gblame, Gstatus, Gdiff, Gbrowse, Gstatus, Gpush] 1222 | hook_source: let g:easygit_enable_command = 1 1223 | ``` 1224 | 1225 | ## 7、defx-git 1226 | 1227 | Github:https://github.com/kristijanhusak/defx-git 1228 | 1229 | 这个插件是用来给`defx`来提供git状态支持的 1230 | 1231 | 首先是core/dein/plugins.yaml中的配置 1232 | 1233 | ```yaml 1234 | - repo: kristijanhusak/defx-git 1235 | on_source: defx.nvim 1236 | hook_source: source $VIM_PATH/layers/+ui/defx/+defx-git.vim 1237 | ``` 1238 | 1239 | 配置文件:`$VIM_PATH/layers/+ui/defx/+defx-git.vim` 1240 | 1241 | ```yaml 1242 | 1243 | let g:defx_git#indicators = { 1244 | \ 'Modified' : '•', 1245 | \ 'Staged' : '✚', 1246 | \ 'Untracked' : 'ᵁ', 1247 | \ 'Renamed' : '≫', 1248 | \ 'Unmerged' : '≠', 1249 | \ 'Ignored' : 'ⁱ', 1250 | \ 'Deleted' : '✖', 1251 | \ 'Unknown' : '⁇' 1252 | \ } 1253 | 1254 | ``` 1255 | 1256 | ## 8、defx-icons 1257 | 1258 | Github:https://github.com/kristijanhusak/defx-icons 1259 | 1260 | plugins.yaml 1261 | 1262 | ```yaml 1263 | - repo: kristijanhusak/defx-icons 1264 | on_source: defx.nvim 1265 | ``` 1266 | 1267 | ## 9、magit.vim 1268 | 1269 | 更好的查看提交记录 1270 | 1271 | github:https://github.com/taigacute/magit.vim 1272 | 1273 | plugins.yaml 1274 | 1275 | ```yaml 1276 | - { repo: taigacute/magit.vim, on_cmd: Magit } 1277 | ``` 1278 | 1279 | ## 10、gina.vim 1280 | 1281 | 另一个git工具 1282 | 1283 | github:https://github.com/lambdalisue/gina.vim 1284 | 1285 | plugins.yaml 1286 | 1287 | ```yaml 1288 | - { repo: lambdalisue/gina.vim, on_cmd: Gina } 1289 | ``` 1290 | 1291 | ## 11、vim-easymotion 1292 | 1293 | 快速移动工具 1294 | 1295 | github:https://github.com/easymotion/vim-easymotion 1296 | 1297 | plugins.yaml 1298 | 1299 | ```yaml 1300 | - repo: easymotion/vim-easymotion 1301 | on_map: { n: } 1302 | hook_source: | 1303 | let g:EasyMotion_do_mapping = 0 1304 | let g:EasyMotion_prompt = 'Jump to → ' 1305 | let g:EasyMotion_keys = 'fjdkswbeoavn' 1306 | let g:EasyMotion_smartcase = 1 1307 | let g:EasyMotion_use_smartsign_us = 1 1308 | ``` 1309 | 1310 | ## 12、vim-repeat 1311 | 1312 | 重复操作插件,使用.即可重复操作 1313 | 1314 | github:https://github.com/tpope/vim-repeat 1315 | 1316 | plugins.yaml 1317 | 1318 | ```yaml 1319 | - {repo: tpope/vim-repeat , on_map: .* } 1320 | ``` 1321 | 1322 | ## 13、vim-mundo 1323 | 1324 | 访问vim的undo树的插件 1325 | 1326 | github:https://github.com/simnalamburt/vim-mundo 1327 | 1328 | plugins.yaml 1329 | 1330 | ```yaml 1331 | - {repo: simnalamburt/vim-mundo , on_map: { n: } } 1332 | ``` 1333 | 1334 | 按说这个插件,命令模式`:GundoToggle`能够唤起,但是不起作用。稍后调试一下 1335 | 1336 | ## 14、vim-quickrun 1337 | 1338 | 快速运行插件 1339 | 1340 | github:https://github.com/thinca/vim-quickrun 1341 | 1342 | plugins.yaml 1343 | 1344 | ```yaml 1345 | - repo: thinca/vim-quickrun 1346 | on_cmd: QuickRun 1347 | hook_add: | 1348 | let g:quickrun_config = { 1349 | \ "_" : { 1350 | \ "outputter" : "message", 1351 | \ }, 1352 | \} 1353 | let g:quickrun_no_default_key_mappings = 1 1354 | 1355 | ``` 1356 | 1357 | ## 15、dash.vim 1358 | 1359 | 这个插件是用在Mac上的,因为只有mac才有`Dash.app`,在其他操作系统上,将不起作用 1360 | 1361 | github:https://github.com/rizzatti/dash.vim 1362 | 1363 | plugins.yaml 1364 | 1365 | ```yaml 1366 | - repo: rizzatti/dash.vim 1367 | on_map: { n: } 1368 | hook_add: | 1369 | let g:dash_map = { 1370 | \ 'javascript': ['javascript', 'NodeJS'], 1371 | \ 'javascript.jsx': ['react'], 1372 | \ 'html': ['html', 'svg'], 1373 | \ 'go' : 'Go', 1374 | \} 1375 | 1376 | ``` 1377 | 1378 | ## 16、comfortable-motion.vim 1379 | 1380 | 光标位置不变的上下滚动 1381 | 1382 | github:https://github.com/yuttie/comfortable-motion.vim 1383 | 1384 | plugins.yaml 1385 | 1386 | ```yaml 1387 | - repo: yuttie/comfortable-motion.vim 1388 | on_func: comfortable_motion#flick 1389 | hook_add: | 1390 | let g:comfortable_motion_no_default_key_mappings = 1 1391 | let g:comfortable_motion_impulse_multiplier = 1 1392 | 1393 | ``` 1394 | 1395 | ## 17、 vim-easy-align 1396 | 1397 | 快速格式化对其,例如编程语言中的赋值多行对其 1398 | 1399 | github:https://github.com/junegunn/vim-easy-align 1400 | 1401 | plugins.yaml 1402 | 1403 | ```yaml 1404 | - repo: junegunn/vim-easy-align 1405 | on_ft: [vim,json,go,html,js,jsx,py,css,less,tmpl,toml,xml,sql,Dockerfile] 1406 | 1407 | ``` 1408 | 1409 | ## 18、vim-startify 1410 | 1411 | 这个用来选择编辑过的文件菜单的插件 1412 | 1413 | github:https://github.com/mhinz/vim-startify 1414 | 1415 | plugins.yaml 1416 | 1417 | ```yaml 1418 | - repo: mhinz/vim-startify 1419 | on_cmd: Startify 1420 | depends: vim-devicons 1421 | hook_source: source $VIM_PATH/layers/+ui/startify/config.vim 1422 | hook_post_source: | 1423 | function! StartifyEntryFormat() 1424 | return 'WebDevIconsGetFileTypeSymbol(absolute_path) ." ". entry_path' 1425 | endfunction 1426 | ``` 1427 | 1428 | $VIM_PATH/layers/+ui/startify/config.vim 1429 | 1430 | ```css 1431 | 1432 | " For startify 1433 | let g:startify_padding_left = 30 1434 | let s:header = [ 1435 | \ '', 1436 | \ ' __ _ _ _ _ _ _ ', 1437 | \ ' / / ___ | |_ ( ) ___ | |_ | |__ (_) _ __ | | __', 1438 | \ ' / / / _ \| __||/ / __| | __|| |_ \ | || |_ \ | |/ /', 1439 | \ '/ /___ | __/| |_ \__ \ | |_ | | | || || | | || < ', 1440 | \ '\____/ \___| \__| |___/ \__||_| |_||_||_| |_||_|\_\', 1441 | \ ' ', 1442 | \ ' [ ThinkVim Author:taigacute ] ', 1443 | \ '', 1444 | \ ] 1445 | 1446 | let s:footer = [ 1447 | \ '+-------------------------------------------+', 1448 | \ '| ThinkVim ^_^ |', 1449 | \ '| Talk is cheap Show me the code |', 1450 | \ '| |', 1451 | \ '| GitHub:taigacute |', 1452 | \ '+-------------------------------------------+', 1453 | \ ] 1454 | 1455 | function! s:center(lines) abort 1456 | let longest_line = max(map(copy(a:lines), 'strwidth(v:val)')) 1457 | let centered_lines = map(copy(a:lines), 1458 | \ 'repeat(" ", (&columns / 2) - (longest_line / 2)) . v:val') 1459 | return centered_lines 1460 | endfunction 1461 | 1462 | let g:startify_custom_header = s:center(s:header) 1463 | let g:startify_custom_footer = s:center(s:footer) 1464 | 1465 | ``` 1466 | 1467 | ## 19、vim-choosewin 1468 | 1469 | 选择窗口插件,类似于tmux的`q` 1470 | 1471 | github:https://github.com/t9md/vim-choosewin 1472 | 1473 | plugins.yaml 1474 | 1475 | ```css 1476 | - repo: t9md/vim-choosewin 1477 | on_map: { n: } 1478 | hook_source: source $VIM_PATH/layers/+tools/choosewin/config.vim 1479 | ``` 1480 | 1481 | $VIM_PATH/layers/+tools/choosewin/config.vim 1482 | 1483 | ```css 1484 | 1485 | " Plugin: vim-choosewin 1486 | " --------------------------------------------------------- 1487 | let g:choosewin_label = 'SDFJKLZXCV' 1488 | let g:choosewin_overlay_enable = 1 1489 | let g:choosewin_statusline_replace = 1 1490 | let g:choosewin_overlay_clear_multibyte = 0 1491 | let g:choosewin_blink_on_land = 0 1492 | 1493 | let g:choosewin_color_label = { 1494 | \ 'cterm': [ 236, 2 ], 'gui': [ '#555555', '#000000' ] } 1495 | let g:choosewin_color_label_current = { 1496 | \ 'cterm': [ 234, 220 ], 'gui': [ '#333333', '#000000' ] } 1497 | let g:choosewin_color_other = { 1498 | \ 'cterm': [ 235, 235 ], 'gui': [ '#333333' ] } 1499 | let g:choosewin_color_overlay = { 1500 | \ 'cterm': [ 2, 10 ], 'gui': [ '#88A2A4' ] } 1501 | let g:choosewin_color_overlay_current = { 1502 | \ 'cterm': [ 72, 64 ], 'gui': [ '#7BB292' ] } 1503 | ``` 1504 | 1505 | ## 20、**accelerated-jk** 1506 | 1507 | 让`j``k`键,上下翻动时,增加速度,拥有滚动效果 1508 | 1509 | github: 1510 | 1511 | plugins.yaml 1512 | 1513 | ```yaml 1514 | - { repo: rhysd/accelerated-jk, on_map: { n: } } 1515 | ``` 1516 | 1517 | ## 21、vim-devicons 1518 | 1519 | 增加`icon`图标的插件 1520 | 1521 | github: 1522 | 1523 | plugins.yaml 1524 | 1525 | ```yaml 1526 | # Interface{{{ 1527 | - repo: ryanoasis/vim-devicons 1528 | hook_add: let g:webdevicons_enable_denite = 1 1529 | ``` 1530 | 1531 | ## 22、vim-snippets 1532 | 1533 | 模板插件,增加写代码速度 1534 | 1535 | github: 1536 | 1537 | plugins.yaml 1538 | 1539 | ```yaml 1540 | - repo: honza/vim-snippets 1541 | depends : coc.nvim 1542 | ``` 1543 | 1544 | ## 23、coc.nvim 1545 | 1546 | 一个提供插件的插件 1547 | 1548 | github:https://github.com/neoclide/coc.nvim 1549 | 1550 | plugins.yaml 1551 | 1552 | ```yaml 1553 | - repo: neoclide/coc.nvim 1554 | merge: 0 1555 | rev: release 1556 | hook_add: source $VIM_PATH/layers/+completion/coc/config.vim 1557 | 1558 | ``` 1559 | 1560 | - ` $VIM_PATH/layers/+completion/coc/config.vim` 1561 | 1562 | ```css 1563 | "CoC configlet 1564 | let g:coc_snippet_next = '' 1565 | let g:coc_snippet_prev = '' 1566 | let g:coc_status_error_sign = '•' 1567 | let g:coc_status_warning_sign = '•' 1568 | let g:coc_global_extensions =['coc-html','coc-css','coc-snippets','coc-prettier','coc-eslint','coc-emmet','coc-tsserver','coc-pairs','coc-json','coc-python','coc-imselect','coc-highlight','coc-git','coc-emoji','coc-lists','coc-post','coc-stylelint','coc-yaml','coc-template','coc-tabnine','coc-marketplace','coc-gitignore','coc-yank','coc-explorer','coc-go'] 1569 | 1570 | augroup MyAutoCmd 1571 | autocmd! 1572 | " Setup formatexpr specified filetype(s). 1573 | autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected') 1574 | " Update signature help on jump placeholder 1575 | autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp') 1576 | augroup end 1577 | 1578 | " Highlight symbol under cursor on CursorHold 1579 | autocmd CursorHold * silent call CocActionAsync('highlight') 1580 | 1581 | "Use tab for trigger completion with characters ahead and navigate 1582 | inoremap 1583 | \ pumvisible() ? "\" : 1584 | \ check_back_space() ? "\" : 1585 | \ coc#refresh() 1586 | 1587 | inoremap pumvisible() ? "\" : "\" 1588 | "inoremap pumvisible() ? "\" : "\u\" 1589 | inoremap pumvisible() ? coc#_select_confirm() : "\u\\=coc#on_enter()\" 1590 | 1591 | function! s:check_back_space() abort 1592 | let col = col('.') - 1 1593 | return !col || getline('.')[col - 1] =~# '\s' 1594 | endfunction 1595 | 1596 | 1597 | ``` 1598 | 1599 | ## 24、vim-buffet 1600 | 1601 | 快速切换`buffer`的插件 1602 | 1603 | github:https://github.com/bagrat/vim-buffet 1604 | 1605 | plugins.yaml 1606 | 1607 | ```yaml 1608 | - repo: bagrat/vim-buffet 1609 | hook_add: source $VIM_PATH/layers/+ui/buffet/config.vim 1610 | 1611 | ``` 1612 | 1613 | - `$VIM_PATH/layers/+ui/buffet/config.vim` 1614 | 1615 | ```css 1616 | 1617 | let g:buffet_tab_icon = "\uf00a" 1618 | function! g:BuffetSetCustomColors() 1619 | hi! BuffetCurrentBuffer cterm=NONE ctermbg=106 ctermfg=8 guibg=#b8bb26 guifg=#000000 1620 | hi! BuffetTrunc cterm=bold ctermbg=66 ctermfg=8 guibg=#458588 guifg=#000000 1621 | hi! BuffetBuffer cterm=NONE ctermbg=239 ctermfg=8 guibg=#504945 guifg=#000000 1622 | hi! BuffetTab cterm=NONE ctermbg=66 ctermfg=8 guibg=#458588 guifg=#000000 1623 | hi! BuffetActiveBuffer cterm=NONE ctermbg=10 ctermfg=239 guibg=#999999 guifg=#504945 1624 | endfunction 1625 | 1626 | ``` 1627 | 1628 | ## 25、spaceline.vim 1629 | 1630 | 状态条插件 1631 | 1632 | github:https://github.com/hardcoreplayers/spaceline.vim 1633 | 1634 | plugins.yaml 1635 | 1636 | ```yaml 1637 | - repo: taigacute/spaceline.vim 1638 | ``` 1639 | 1640 | ## 26、dein.vim 1641 | 1642 | 插件管理 1643 | 1644 | github:https://github.com/Shougo/dein.vim 1645 | 1646 | plugins.yaml 1647 | 1648 | ```yaml 1649 | - repo: Shougo/dein.vim 1650 | ``` 1651 | 1652 | ## 27、dockerfile.vim 1653 | 1654 | 高亮dockerfiles语法插件 1655 | 1656 | github:https://github.com/honza/dockerfile.vim 1657 | 1658 | plugins.yaml 1659 | 1660 | ```yaml 1661 | - { repo: honza/dockerfile.vim, on_ft: Dockerfile } 1662 | ``` 1663 | 1664 | ## 28、vim-emoji 1665 | 1666 | 使vim支持emoji的插件 1667 | 1668 | github:https://github.com/junegunn/vim-emoji 1669 | 1670 | plugins.yaml 1671 | 1672 | ```yaml 1673 | - { repo: junegunn/vim-emoji, on_ft: [markdown,vim] } 1674 | 1675 | ``` 1676 | 1677 | ## 29、typescript-vim 1678 | 1679 | TypeScrpit语法高亮 1680 | 1681 | github:https://github.com/leafgarland/typescript-vim 1682 | 1683 | plugins.yaml 1684 | 1685 | ```yaml 1686 | - { repo: leafgarland/typescript-vim, on_ft: [typescript.tsx,typescript] } 1687 | 1688 | ``` 1689 | 1690 | ## 29、peitalin/vim-jsx-typescript 1691 | 1692 | Syntax highlighting for JSX in Typescript. 1693 | 1694 | github:https://github.com/peitalin/vim-jsx-typescript 1695 | 1696 | plugins.yaml 1697 | 1698 | ```yaml 1699 | - { repo: peitalin/vim-jsx-typescript, on_ft: [typescript.tsx]} 1700 | 1701 | ``` 1702 | 1703 | ## 30、vim-python-pep8-indent 1704 | 1705 | python的PEP8缩进 1706 | 1707 | github:https://github.com/Vimjas/vim-python-pep8-indent 1708 | 1709 | plugins.yaml 1710 | 1711 | ```yaml 1712 | - { repo: Vimjas/vim-python-pep8-indent, on_ft: python } 1713 | 1714 | ``` 1715 | 1716 | ## 31、SimpylFold 1717 | 1718 | python的正确折叠插件 1719 | 1720 | github:https://github.com/tmhedberg/SimpylFold 1721 | 1722 | plugins.yaml 1723 | 1724 | ```yaml 1725 | - { repo: tmhedberg/SimpylFold, on_ft: python } 1726 | 1727 | ``` 1728 | 1729 | ## 32、**python_match.vim** 1730 | 1731 | python`%`匹配跳转 1732 | 1733 | github:https://github.com/vim-scripts/python_match.vim 1734 | 1735 | plugins.yaml 1736 | 1737 | ```yaml 1738 | - { repo: vim-scripts/python_match.vim, on_ft: python } 1739 | 1740 | ``` 1741 | 1742 | ## 33、vim-python/python-syntax 1743 | 1744 | 增强高亮python语法 1745 | 1746 | github:https://github.com/vim-python/python-syntax 1747 | 1748 | plugins.yaml 1749 | 1750 | ```yaml 1751 | - repo: vim-python/python-syntax 1752 | on_ft: python 1753 | hook_add: let g:python_highlight_all = 1 1754 | 1755 | ``` 1756 | 1757 | ## 34、vim-jsx-improve 1758 | 1759 | Makes your javascript files support React jsx correctly. 1760 | 1761 | github:https://github.com/neoclide/vim-jsx-improve 1762 | 1763 | plugins.yaml 1764 | 1765 | ```yaml 1766 | - { repo: neoclide/vim-jsx-improve, on_ft: [javascript,jsx,javascript.jsx]} 1767 | 1768 | ``` 1769 | 1770 | ## 35、vim-toml 1771 | 1772 | TOML语法高亮 1773 | 1774 | github:https://github.com/cespare/vim-toml 1775 | 1776 | plugins.yaml 1777 | 1778 | ```yaml 1779 | - { repo: cespare/vim-toml, on_ft: toml } 1780 | 1781 | ``` 1782 | 1783 | ## 36、**xml.vim** 1784 | 1785 | xml编辑插件,自动补齐 1786 | 1787 | github:https://github.com/vim-scripts/xml.vim 1788 | 1789 | plugins.yaml 1790 | 1791 | ```yaml 1792 | - { repo: vim-scripts/xml.vim, on_ft: xml} 1793 | 1794 | ``` 1795 | 1796 | ## 37、**ansible-vim** 1797 | 1798 | 配置自动化脚本高亮插件 1799 | 1800 | This is a vim syntax plugin for Ansible 2.x, it supports YAML playbooks, Jinja2 templates, and Ansible's `hosts` files. 1801 | 1802 | github:https://github.com/pearofducks/ansible-vim 1803 | 1804 | plugins.yaml 1805 | 1806 | ```yaml 1807 | - { repo: pearofducks/ansible-vim, on_ft: [ yaml.ansible, ansible_hosts ]} 1808 | 1809 | ``` 1810 | 1811 | ## 38、**vim-json** 1812 | 1813 | json高亮插件 1814 | 1815 | github:https://github.com/elzr/vim-json 1816 | 1817 | plugins.yaml 1818 | 1819 | ```yaml 1820 | - repo: elzr/vim-json 1821 | on_ft: json 1822 | hook_add: let g:vim_json_syntax_conceal = 0 1823 | 1824 | ``` 1825 | 1826 | ## 39、vim-go 1827 | 1828 | Go语言对Vim支持 1829 | 1830 | github:https://github.com/fatih/vim-go 1831 | 1832 | plugins.yaml 1833 | 1834 | ```yaml 1835 | - repo: fatih/vim-go 1836 | on_ft: go 1837 | hook_source: source $VIM_PATH/layers/+lang/go/config.vim 1838 | 1839 | ``` 1840 | 1841 | - `$VIM_PATH/layers/+lang/go/config.vim` 1842 | 1843 | ```css 1844 | "vim-go 1845 | let g:go_fmt_command = "goimports" 1846 | let g:go_highlight_types = 1 1847 | let g:go_highlight_fields = 1 1848 | let g:go_highlight_functions = 1 1849 | let g:go_highlight_function_calls = 1 1850 | let g:go_highlight_methods = 1 1851 | let g:go_highlight_structs = 1 1852 | let g:go_highlight_operators = 1 1853 | let g:go_highlight_extra_types = 1 1854 | let g:go_highlight_build_constraints = 1 1855 | let g:go_highlight_generate_tags = 1 1856 | "disable use K to run godoc 1857 | let g:go_doc_keywordprg_enabled = 0 1858 | let g:go_def_mapping_enabled = 0 1859 | ``` 1860 | 1861 | ## 40、vim-markdown 1862 | 1863 | Vim对Markdown的支持 1864 | 1865 | github:https://github.com/tpope/vim-markdown 1866 | 1867 | plugins.yaml 1868 | 1869 | ```yaml 1870 | - repo: tpope/vim-markdown 1871 | on_ft: markdown 1872 | hook_add: | 1873 | let g:markdown_fenced_languages = [ 1874 | \ 'html', 1875 | \ 'bash=sh', 1876 | \ 'css', 1877 | \ 'javascript', 1878 | \ 'js=javascript', 1879 | \ 'go', 1880 | \] 1881 | 1882 | ``` 1883 | 1884 | ## 41、**caw.vim** 1885 | 1886 | Vim注释插件 1887 | 1888 | github:https://github.com/tyru/caw.vim 1889 | 1890 | plugins.yaml 1891 | 1892 | ```yaml 1893 | - repo: tyru/caw.vim 1894 | on_map: { nx: } 1895 | 1896 | ``` 1897 | 1898 | ## 42、neoformat 1899 | 1900 | 格式化插件 1901 | 1902 | github:https://github.com/sbdchd/neoformat 1903 | 1904 | plugins.yaml 1905 | 1906 | ```yaml 1907 | - repo: sbdchd/neoformat 1908 | on_cmd: [Neoformat,Neoformat!] 1909 | hook_source: source $VIM_PATH/layers/+tools/neoformat/config.vim 1910 | 1911 | ``` 1912 | 1913 | - `$VIM_PATH/layers/+tools/neoformat/config.vim` 1914 | 1915 | ```css 1916 | 1917 | let g:neoformat_try_formatprg = 1 1918 | let g:jsx_ext_required = 0 1919 | let g:neoformat_enabled_javascript=['prettier'] 1920 | let g:neoformat_enabled_html=['js-beautify'] 1921 | 1922 | ``` 1923 | 1924 | ## 43、**indentLine** 1925 | 1926 | 缩进线 1927 | 1928 | github:https://github.com/Yggdroot/indentLine 1929 | 1930 | plugins.yaml 1931 | 1932 | ```yaml 1933 | - repo: Yggdroot/indentLine 1934 | on_ft: [python,html,css,vim,javascript,jsx,javascript.jsx,vue] 1935 | hook_source: source $VIM_PATH/layers/+ui/indentline/config.vim 1936 | 1937 | ``` 1938 | 1939 | - `$VIM_PATH/layers/+ui/indentline/config.vim` 1940 | 1941 | ```css 1942 | 1943 | let g:indentline_enabled = 1 1944 | let g:indentline_char='┆' 1945 | let g:indentLine_fileTypeExclude = ['defx', 'denite','startify','tagbar','vista_kind','vista'] 1946 | let g:indentLine_concealcursor = 'niv' 1947 | let g:indentLine_color_term = 96 1948 | let g:indentLine_color_gui= '#725972' 1949 | let g:indentLine_showFirstIndentLevel =1 1950 | 1951 | ``` 1952 | 1953 | ## 44、vista.vim 1954 | 1955 | new tagbar 1956 | 1957 | 参考:https://www.zhihu.com/question/31934850 1958 | 1959 | github:https://github.com/liuchengxu/vista.vim 1960 | 1961 | plugins.yaml 1962 | 1963 | ```yaml 1964 | - repo: liuchengxu/vista.vim 1965 | on_cmd: [Vista,Vista!,Vista!!] 1966 | hook_source: source $VIM_PATH/layers/+tools/vista/config.vim 1967 | 1968 | ``` 1969 | 1970 | - `$VIM_PATH/layers/+tools/vista/config.vim` 1971 | 1972 | ```yaml 1973 | let g:vista#renderer#enable_icon = 1 1974 | let g:vista_default_executive = 'ctags' 1975 | let g:vista_fzf_preview = ['right:50%'] 1976 | 1977 | let g:vista_executive_for = { 1978 | \ 'go': 'ctags', 1979 | \ 'javascript': 'coc', 1980 | \ 'javascript.jsx': 'coc', 1981 | \ 'python': 'ctags', 1982 | \ } 1983 | 1984 | ``` 1985 | 1986 | ## 45、Emmet-vim 1987 | 1988 | 快速生成`HTML`的插件 1989 | 1990 | 参考:https://www.jianshu.com/p/ad8a6a786054 1991 | 1992 | github:https://github.com/mattn/emmet-vim 1993 | 1994 | plugins.yaml 1995 | 1996 | ```css 1997 | - repo: mattn/emmet-vim 1998 | on_ft: [html,css,jsx,javascript,javascript.jsx] 1999 | on_event: InsertEnter 2000 | hook_add: | 2001 | let g:use_emmet_complete_tag = 0 2002 | let g:user_emmet_install_global = 0 2003 | let g:user_emmet_install_command = 0 2004 | let g:user_emmet_mode = 'i' 2005 | let g:user_emmet_leader_key='' 2006 | let g:user_emmet_settings = { 2007 | \ 'javascript.jsx' : { 2008 | \ 'extends' : 'jsx', 2009 | \ }, 2010 | \} 2011 | 2012 | ``` 2013 | 2014 | ## 46、**rainbow** 2015 | 2016 | 彩虹括号增强版,提高复杂代码的阅读性 2017 | 2018 | github:https://github.com/luochen1990/rainbow 2019 | 2020 | plugins.yaml 2021 | 2022 | ```yaml 2023 | - repo: luochen1990/rainbow 2024 | on_ft: [python,javascript,jsx,javascript.jsx,html,css,go,vim,toml] 2025 | hook_source: let g:rainbow_active = 1 2026 | 2027 | ``` 2028 | 2029 | ## 47、echodoc.vim 2030 | 2031 | 显示函数文档到command line中 2032 | 2033 | github:https://github.com/Shougo/echodoc.vim 2034 | 2035 | plugins.yaml 2036 | 2037 | ```css 2038 | - repo: Shougo/echodoc.vim 2039 | on_event: CompleteDone 2040 | hook_source: | 2041 | call echodoc#enable() 2042 | let g:echodoc#type = "virtual" 2043 | 2044 | ``` 2045 | 2046 | ## 48、markdown-preview.nvim 2047 | 2048 | 预览Markdown的插件 2049 | 2050 | github:https://github.com/iamcco/markdown-preview.nvim 2051 | 2052 | plugins.yam 2053 | 2054 | ```css 2055 | - repo: iamcco/markdown-preview.nvim 2056 | on_ft: [markdown,pandoc.markdown,rmd] 2057 | hook_post_source: 'call mkdp#util#install()' 2058 | hook_source: | 2059 | let g:mkdp_auto_start = 1 2060 | 2061 | ``` 2062 | 2063 | ## 49、goyo.vim 2064 | 2065 | 清爽模式,不被其他元素打扰的写作插件 2066 | 2067 | 参考:https://github.com/junegunn/goyo.vim 2068 | 2069 | plugins.yaml 2070 | 2071 | ```css 2072 | - repo: junegunn/goyo.vim 2073 | on_cmd: Goyo 2074 | hook_source: source $VIM_PATH/layers/+tools/goyo/config.vim 2075 | 2076 | ``` 2077 | 2078 | - `$VIM_PATH/layers/+tools/goyo/config.vim` 2079 | 2080 | ```css 2081 | " Goyo 2082 | 2083 | " s:goyo_enter() "{{{ 2084 | " Disable visual candy in Goyo mode 2085 | function! s:goyo_enter() 2086 | if has('gui_running') 2087 | " Gui fullscreen 2088 | set fullscreen 2089 | set background=light 2090 | set linespace=7 2091 | elseif exists('$TMUX') 2092 | " Hide tmux status 2093 | silent !tmux set status off 2094 | endif 2095 | 2096 | " Activate Limelight 2097 | Limelight 2098 | endfunction 2099 | 2100 | " }}} 2101 | " s:goyo_leave() "{{{ 2102 | " Enable visuals when leaving Goyo mode 2103 | function! s:goyo_leave() 2104 | if has('gui_running') 2105 | " Gui exit fullscreen 2106 | set nofullscreen 2107 | set background=dark 2108 | set linespace=0 2109 | elseif exists('$TMUX') 2110 | " Show tmux status 2111 | silent !tmux set status on 2112 | endif 2113 | 2114 | " De-activate Limelight 2115 | Limelight! 2116 | endfunction 2117 | " }}} 2118 | 2119 | " Goyo Commands {{{ 2120 | autocmd! User GoyoEnter 2121 | autocmd! User GoyoLeave 2122 | autocmd User GoyoEnter nested call goyo_enter() 2123 | autocmd User GoyoLeave nested call goyo_leave() 2124 | " }}} 2125 | 2126 | " vim: set foldmethod=marker ts=2 sw=2 tw=80 noet : 2127 | 2128 | ``` 2129 | 2130 | ## 50、limelight.vim 2131 | 2132 | 在使用goyo.vim的清爽模式时,块高亮插件 2133 | 2134 | github:https://github.com/junegunn/Limelight.vim 2135 | 2136 | plugins.yaml 2137 | 2138 | ```css 2139 | - repo: junegunn/Limelight.vim 2140 | on_cmd: Limelight 2141 | 2142 | ``` 2143 | 2144 | ## 51、splitjoin.vim 2145 | 2146 | 多行和单行之间快速切换的插件 2147 | 2148 | github:https://github.com/AndrewRadev/splitjoin.vim 2149 | 2150 | plugins.yaml 2151 | 2152 | ```yaml 2153 | - { repo: AndrewRadev/splitjoin.vim, on_map: { n: Splitjoin }} 2154 | 2155 | ``` 2156 | 2157 | ## 52、vim-expand-region 2158 | 2159 | 扩展选择插件,让你快速选择 2160 | 2161 | github:https://github.com/terryma/vim-expand-region 2162 | 2163 | plugins.yaml 2164 | 2165 | ```yaml 2166 | - { repo: terryma/vim-expand-region, on_map: { x: }} 2167 | 2168 | ``` 2169 | 2170 | ## 53、vim-textobj-user 2171 | 2172 | 用户可以自定文本块的插件 2173 | 2174 | github:https://github.com/kana/vim-textobj-user 2175 | 2176 | plugins.yaml 2177 | 2178 | ```yaml 2179 | - { repo: kana/vim-textobj-user, on_func: textobj#user# } 2180 | 2181 | ``` 2182 | 2183 | ## 54、vim-operator-user 2184 | 2185 | 用户定义自己的操作符的插件 2186 | 2187 | github:https://github.com/kana/vim-operator-user 2188 | 2189 | plugins.yaml 2190 | 2191 | ```yaml 2192 | - { repo: kana/vim-operator-user, lazy: 1 } 2193 | 2194 | ``` 2195 | 2196 | ## 55、vim-niceblock 2197 | 2198 | 更好的块选择插件 2199 | 2200 | github:https://github.com/kana/vim-niceblock 2201 | 2202 | plugins.yaml 2203 | 2204 | ```yaml 2205 | - { repo: kana/vim-niceblock, on_map: { x: }} 2206 | 2207 | ``` 2208 | 2209 | ## 56、**vim-smartchr** 2210 | 2211 | 一键插入多个候选的插件 2212 | 2213 | github:https://github.com/kana/vim-smartchr 2214 | 2215 | plugins.yaml 2216 | 2217 | ```yaml 2218 | - repo: kana/vim-smartchr 2219 | on_event: InsertCharPre 2220 | 2221 | ``` 2222 | 2223 | ## 57、vim-operator-replace 2224 | 2225 | 操作符替换插件 2226 | 2227 | github:https://github.com/kana/vim-operator-replace 2228 | 2229 | plugins.yaml 2230 | 2231 | ```yaml 2232 | - repo: kana/vim-operator-replace 2233 | depends: vim-operator-user 2234 | on_map: { vnx: } 2235 | 2236 | ``` 2237 | 2238 | ## 58、vim-sandwich 2239 | 2240 | 改变括号的插件 2241 | 2242 | github:https://github.com/machakann/vim-sandwich 2243 | 2244 | plugins.yaml 2245 | 2246 | ```yaml 2247 | - repo: machakann/vim-sandwich 2248 | on_map: { vnx: [(operator-sandwich-,(textobj-sandwich-]} 2249 | 2250 | ``` 2251 | 2252 | ## 59、vim-textobj-multiblock 2253 | 2254 | 过个括号一起使用的文本快 2255 | 2256 | github:https://github.com/osyo-manga/vim-textobj-multiblock/ 2257 | 2258 | plugins.yaml 2259 | 2260 | ```yaml 2261 | - repo: osyo-manga/vim-textobj-multiblock 2262 | depends: vim-textobj-user 2263 | on_map: { ox: } 2264 | hook_add: let g:textobj_multiblock_no_default_key_mappings = 1 2265 | 2266 | ``` 2267 | 2268 | 2269 | 2270 | 2271 | 2272 | 2273 | 2274 | 2275 | 2276 | 2277 | 2278 | 2279 | 2280 | 2281 | 2282 | 2283 | 2284 | # 四、快捷键 2285 | 2286 | ## 1、fzf 2287 | 2288 | | 按键 | 映射 | 功能 | 2289 | | -------------------------------------------- | -------------------------------------------------- | ---------------- | 2290 | | LEADER + fc | `nnoremap fc :Colors` | 选择颜色主题 | 2291 | | LEADER + bb | `nnoremap bb :Buffers` | 选择buffer | 2292 | | LEADER + ff | `nnoremap ff :call Fzf_dev()` | 搜索项目中的文件 | 2293 | | LEADER + fr | `nnoremap fr :Rg` | 执行Rg搜索 | 2294 | | LEADER + fw | `nnoremap fw :Rg ` | 搜索光标所在词 | 2295 | 2296 | ## 2、which-key 2297 | 2298 | 这个插件定义了很多快捷键,有时间逐个试下,总结一下,这个插件本身的作用就是引导用户来使用快捷键。 2299 | 2300 | 四个引导键: 2301 | 2302 | - `` 2303 | - `` 2304 | - `[` 2305 | - `]` 2306 | 2307 | ## 3、defx 2308 | 2309 | 文件浏览器defx的快捷键 2310 | 2311 | | 按键 | 映射 | 功能 | 2312 | | ------------------------------ | ------------------------------------------------------------ | -------------------------- | 2313 | | Enter | `nnoremap defx#do_action('drop')` | 进入目录/打开文件 | 2314 | | l | `nnoremap l defx_toggle_tree()` | 展开目录 | 2315 | | h | `nnoremap h defx#async_action('cd', ['..'])` | 回到上级目录 | 2316 | | st | `nnoremap st defx#do_action('multi', [['drop', 'tabnew'], 'quit'])` | 新标签打开文件,关闭defx | 2317 | | s | `nnoremap s defx#do_action('open', 'botright vsplit')` | 垂直分屏打开文件,关闭defx | 2318 | | i | `nnoremap i defx#do_action('open', 'botright split')` | 纵向分屏打开文件,关闭defx | 2319 | | P | `nnoremap P defx#do_action('open', 'pedit')` | 在左上角打开,不知道有啥用 | 2320 | | K | `nnoremap K defx#do_action('new_directory')` | 创建一个目录 | 2321 | | N | `nnoremap N defx#do_action('new_multiple_files')` | 复制黏贴文件 | 2322 | | dd | `nnoremap dd defx#do_action('remove_trash')` | 删除文件 | 2323 | | r | `nnoremap r defx#do_action('rename')` | 重命名 | 2324 | | x | `nnoremap x defx#do_action('execute_system')` | 执行文件 | 2325 | | . | `nnoremap . defx#do_action('toggle_ignored_files')` | 显示隐藏文件 | 2326 | | yy | `nnoremap yy defx#do_action('yank_path')` | 复制 | 2327 | | | `nnoremap ~ defx#async_action('cd')` | 回到宿主目录 | 2328 | | q | `nnoremap q defx#do_action('quit')` | 退出defx | 2329 | | TAB | `nnoremap winnr('$') != 1 ?
\ ':wincmd w' :
\ ':Defx -buffer-name=temp -split=vertical'` | 切换窗口 | 2330 | | [g | `nnoremap [g :call jump_dirty(-1)` | 未知 | 2331 | | ]g | `nnoremap ]g :call jump_dirty(1)` | 未知 | 2332 | | \\ | `nnoremap \ defx#do_action('cd', getcwd())` | 切换到工作目录 | 2333 | | & | `nnoremap & defx#do_action('cd', getcwd())` | 同\\ | 2334 | | c | `nnoremap c defx#do_action('copy')` | 拷贝 | 2335 | | m | `nnoremap m defx#do_action('move')` | 剪切\移动 | 2336 | | p | `nnoremap p defx#do_action('paste')` | 粘贴 | 2337 | | SPACE | `nnoremap
\ defx#do_action('toggle_select') . 'j'` | 选择 | 2338 | | ' | `nnoremap ' defx#do_action('toggle_select') . 'j'` | 选择 | 2339 | | * | `nnoremap * defx#do_action('toggle_select_all')` | 全选 | 2340 | | Ctrl + r | `nnoremap defx#do_action('redraw')` | 重绘 | 2341 | | Ctrl + g | `nnoremap defx#do_action('print')` | 打印当前文件全路径 | 2342 | | S | `nnoremap S defx#do_action('toggle_sort', 'Time')` | 按时间排序 | 2343 | | C | `nnoremap C
\ defx#do_action('toggle_columns', 'indent:mark:filename:type:size:time')` | 显示样式 | 2344 | | gx | `nnoremap gx defx#async_action('execute_system')` | 异步执行 | 2345 | | gd | `nnoremap gd defx#async_action('multi', ['drop', ['call', 'git_diff']])` | git diff | 2346 | | gl | `nnoremap gl defx#async_action('call', 'explorer')` | 类似于ranger的方式浏览 | 2347 | | gr | `nnoremap gr defx#do_action('call', 'grep')` | 过滤搜索 | 2348 | | gf | `nnoremap gf defx#do_action('call', 'find_files')` | 列出所有文件 | 2349 | | w | `nnoremap w defx#async_action('call', 'toggle_width')` | 文件浏览器defx变宽显示 | 2350 | 2351 | ## 4、easymotion 2352 | 2353 | | 快捷键 | 功能 | 2354 | | ------------------------------------------------- | ---------------------- | 2355 | | LEADERLEADER + b | 上一个单词的快速移动 | 2356 | | LEADERLEADER + w | 下一个单词的快速移动 | 2357 | | LEADERLEADER + f | 查找一个字母的快速移动 | 2358 | 2359 | ## 5、quickrun 2360 | 2361 | LOCALLEADER + r 2362 | 2363 | 或:`:QuickRun` 2364 | 2365 | ## 6、comfortable-motion.vim 2366 | 2367 | | 快捷键 | 功能 | 2368 | | ------------------------------ | ------------------------ | 2369 | | Ctrl + d | 光标所在行不变,向下滚动 | 2370 | | Ctrl + u | 光标位置不变,向上滚动 | 2371 | | | | 2372 | 2373 | ## 7、vim-easy-align 2374 | 2375 | 引导键:ga 2376 | 2377 | 常用快捷键: 2378 | 2379 | - `vipga=` 2380 | - `v`isual-select `i`nner `p`aragraph 2381 | - Start EasyAlign command (`ga`) 2382 | - Align around `=` 2383 | - `gaip=` 2384 | - Start EasyAlign command (`ga`) for `i`nner `p`aragraph 2385 | - Align around `=` 2386 | 2387 | ## 8、vim-startify 2388 | 2389 | 打开:LEADER + s 2390 | 2391 | ## 9、vim-choosewin 2392 | 2393 | 打开:LEADER + - 2394 | 2395 | 2396 | 2397 | # 未知的设置 2398 | 2399 | ## 1、get() 2400 | 2401 | ```css 2402 | let g:etc#vim_path = 2403 | \ get(g:, 'etc#vimpath', 2404 | \ exists('*stdpath') ? stdpath('config') : 2405 | \ ! empty($MYVIMRC) ? fnamemodify(expand($MYVIMRC), ':h') : 2406 | \ ! empty($VIMCONFIG) ? expand($VIMCONFIG) : 2407 | \ ! empty($VIMCONFIG) ? expand($VIMCONFIG) : 2408 | \ ! empty($VIM_PATH) ? expand($VIM_PATH) : 2409 | \ expand('$HOME/.vim') 2410 | \ ) 2411 | ``` 2412 | 2413 | # 一些问题 2414 | 2415 | ## 1、BufOnly映射 2416 | 2417 | mapping.vim 2418 | 2419 | ```css 2420 | "buffer 2421 | nnoremap bc :BufOnly 2422 | nnoremap bo :BufOnly 2423 | ``` 2424 | 2425 | 这个映射是如何生效的? 2426 | 2427 | ## 2、EditPluginSetting 2428 | 2429 | mapping.vim 2430 | 2431 | ```css 2432 | " a command which edit PLugin config easy 2433 | nnoremap p :EditPluginSetting 2434 | ``` 2435 | 2436 | 这个映射如何使用? 2437 | 2438 | ## 3、buffer select mapping 2439 | 2440 | mapping.vim 2441 | 2442 | ```css 2443 | nmap 1 BuffetSwitch(1) 2444 | nmap 2 BuffetSwitch(2) 2445 | nmap 3 BuffetSwitch(3) 2446 | nmap 4 BuffetSwitch(4) 2447 | nmap 5 BuffetSwitch(5) 2448 | nmap 6 BuffetSwitch(6) 2449 | nmap 7 BuffetSwitch(7) 2450 | nmap 8 BuffetSwitch(8) 2451 | nmap 9 BuffetSwitch(9) 2452 | nmap 0 BuffetSwitch(10) 2453 | ``` 2454 | 2455 | 这个映射如何生效? 2456 | 2457 | 2458 | 2459 | ## 参考 2460 | 2461 | - 2462 | - 2463 | - 2464 | - -------------------------------------------------------------------------------- /note/augroup.md: -------------------------------------------------------------------------------- 1 | # 自动命令组 2 | 3 | 前面几章我们学习了自动命令。执行下面命令: 4 | 5 | ``` 6 | :autocmd BufWrite * :echom "Writing buffer!" 7 | ``` 8 | 9 | 现在使用`:write`命令将当前缓冲区写入文件,然后执行`:messages`命令查看消息日志。你会看到`Writing buffer!`在消息列表中。 10 | 11 | 然后将当前缓冲区写入文件,执行`:messages`查看消息日志。你会看到`Writing buffer!`在消息列表中出现了两次。 12 | 13 | 现在再次执行上面的自动命令: 14 | 15 | ``` 16 | :autocmd BufWrite * :echom "Writing buffer!" 17 | ``` 18 | 19 | 再次将当前缓冲区写入文件并执行`:messages`命令。你会看到`Writing buffer!`在消息列表中出现了*4*次,这是怎么回事? 20 | 21 | 这是因为当你以上面的方式创建第二个自动命令的时候,Vim没办法知道你是想替换第一个自动命令。在上面的示例中,Vim创建了两个*不同*的自动命令,并且这两个命令刚好做同样的事情。 22 | 23 | ## 这会有什么问题? 24 | 25 | 既然你现在知道了Vim可能创建两个完全一样的自动命令,你可能会想:“有什么大不了?只要别这么干就可以!”。 26 | 27 | 问题是当你加载你的`~/.vimrc`文件的时候,Vim会重新读取整个文件,包括你所定义的任何自动命令!这就意味着每次你加载你的`~/.vimrc`文件的时候,Vim都会复制之前的自动命令,这会降低Vim的运行速度,因为它会一次又一次地执行相同的命令。 28 | 29 | 你可以执行下面的命令模拟这种情况: 30 | 31 | ``` 32 | :autocmd BufWrite * :sleep 200m 33 | ``` 34 | 35 | 现在将当前缓冲区写入文件。你可能注意到Vim在写入文件的时候有点缓慢,当然也你可能注意不到。现在执行上面的自动命令三次: 36 | 37 | ``` 38 | :autocmd BufWrite * :sleep 200m 39 | :autocmd BufWrite * :sleep 200m 40 | :autocmd BufWrite * :sleep 200m 41 | ``` 42 | 43 | 再次写文件。这次会更明显。 44 | 45 | 当然你不会创建任何只是进行sleep而不做任何事情的自动命令,不过一个使用Vim的老鸟的`~/.vimrc`文件可以轻易达到1000行,其中会有很多自动命令。再加上安装的插件中的自动命令,这肯定会影响Vim的速度。 46 | 47 | ## 把自动命令放到组中(Grouping Autocommands) 48 | 49 | 对于这个问题,Vim有一个解决方案。这个解决方案的第一步是将相关的自动命令收集起来放到一个已命名的组(groups)中。 50 | 51 | 新开一个Vim实例,这样可以清除之前所创建的自动命令。然后运行下面的命令: 52 | 53 | ``` 54 | :augroup testgroup 55 | : autocmd BufWrite * :echom "Foo" 56 | : autocmd BufWrite * :echom "Bar" 57 | :augroup END 58 | ``` 59 | 60 | 中间两行的缩进没有什么含义,如果你不想输入的话可以不输。 61 | 62 | 将一个缓冲区写入文件然后执行`:messages`。你应该可以在消息日志列表中看到`Foo`和`Bar`。现在执行下面的命令: 63 | 64 | ``` 65 | :augroup testgroup 66 | : autocmd BufWrite * :echom "Baz" 67 | :augroup END 68 | ``` 69 | 70 | 当你再次将缓冲区写入文件的时候猜猜会发生什么。ok,你也许已经有结果了,重新写入缓冲区,然后执行`:messages`命令,看看你猜对了没。 71 | 72 | ## 清除自动命令组 73 | 74 | 当你写入文件的时候发生什么了?猜对了么? 75 | 76 | 如果你认为Vim会替换那个组,那么你猜错了。不要紧,很多人刚开始的时候都会这么想(我也是)。 77 | 78 | 当你多次使用`augroup`的时候,Vim每次都会组合那些组。 79 | 80 | 如果你想清除一个组,你可以把`autocmd!`这个命令包含在组里面。执行下面的命令: 81 | 82 | ``` 83 | :augroup testgroup 84 | : autocmd! 85 | : autocmd BufWrite * :echom "Cats" 86 | :augroup END 87 | ``` 88 | 89 | 现在试试写入文件然后执行`:messages`查看消息日志。这次Vim只会输出`Cats`在消息列表中。 90 | 91 | ## 在Vimrc中使用自动命令 92 | 93 | 既然我们现在知道了怎么把自动命令放到一个组里面以及怎么清除这些组,我们可以使用这种方式将自动命令添加到`~/.vimrc`中,这样每次加载它的时候就不会复制自动命令了。 94 | 95 | 添加下面的命令到你的`~/.vimrc`文件中: 96 | 97 | ``` 98 | augroup filetype_html 99 | autocmd! 100 | autocmd FileType html nnoremap f Vatzf 101 | augroup END 102 | ``` 103 | 104 | 当进入`filetype_html`这个组的时候,我们会立即清除这个组,然后定义一个自动命令,然后退出这个组。当我们再次加载`~/.vimrc`文件的时候,清除组命令会阻止Vim添加一个一模一样的自动命令。 105 | 106 | ## 练习 107 | 108 | 查看你的`~/.vimrc`文件,然后把所有的自动命令用上面组的方式包裹起来。如果你觉得有必要,可以把多个自动命令放到一个组里面。 109 | 110 | 想想上一节的示例中的自动命令是干啥的。 111 | 112 | 阅读`:help autocmd-groups`。 113 | 114 | 115 | 116 | # 负责任的编码 117 | 118 | 到目前为止我们已经介绍了一堆Vim命令,这可以让你可以快速自定义Vim。除了自动命令组外其他的命令都是单行的命令,你可以不费吹灰之力就把它们添加到你的`~/.vimrc`文件中。 119 | 120 | 这本书的下一部分我们会开始专注于Vim脚本编程,将其当作一个真正的编程语言对待,不过在此之前,我会先讲一些在编写大量的Vim脚本时需要注意的东西。 121 | 122 | ## 注释 123 | 124 | Vim脚本非常强大,但对于那些想进入这个领域的程序员而言,在最近几年它似乎逐渐变得像一个弯弯曲曲的迷宫,让进入的人找不到归路。 125 | 126 | Vim的选项和命令经常会比较简短生硬,并且难于阅读,另外处理兼容性问题也会增加代码的复杂度。编写一个插件并且允许用户自定义又会让复杂度更进一级。 127 | 128 | 在编写大量Vim脚本时要保持防御意识。要养成习惯添加注释说明某段代码是干什么的,如果有一个相关的帮助主题(help topic),最好在注释中说明! 129 | 130 | 这不仅会给你以后的维护带来方便,而且如果你将你的`~/.vimrc`文件分享到Bitbucket或者GitHub(强烈推荐你这么做),这些注释也会帮助其他的人理解你的脚本。 131 | 132 | ## 分组 133 | 134 | 之前创建的映射可以让我们在使用Vim的同时方便快捷地编辑和加载`~/.vimrc`。不幸的是这会导致`~/.vimrc`中的代码快速增长以至失去控制,并且变得难于阅读浏览。 135 | 136 | 我们用于对付这种情况的方法是使用Vim的代码折叠功能,将多行代码组织起来的作为一个部分然后对这部分的代码进行折叠。如果你从来没有用过Vim的折叠功能,那么你现在应该尽快去瞄一瞄。很多人(包括我自己)都认为在日常编码工作中代码折叠是不可或缺的。 137 | 138 | 首先我们需要为Vim脚本文件设置折叠。在你的`~/.vimrc`文件中添加下面几行: 139 | 140 | ``` 141 | augroup filetype_vim 142 | autocmd! 143 | autocmd FileType vim setlocal foldmethod=marker 144 | augroup END 145 | ``` 146 | 147 | 这会告诉Vim对任何Vim脚本文件使用`marker`折叠方法。 148 | 149 | 现在在显示`~/.vimrc`文件的窗口中执行`:setlocal foldmethod=marker`。如果你不执行这个命令,你会发现加载`~/.vimrc`文件后没什么效果,这是因为Vim已经为这个文件设置了文件类型(FileType),而自动命令只会在设置文件类型的时候执行。这让你以后不需要手动来做这个事情。 150 | 151 | 现在在自动命令组开始和结束的地方添加两行,像下面这样: 152 | 153 | ``` 154 | " Vimscript file settings ---------------------- {{{ 155 | augroup filetype_vim 156 | autocmd! 157 | autocmd FileType vim setlocal foldmethod=marker 158 | augroup END 159 | " }}} 160 | ``` 161 | 162 | 切换到常用模式,将光标放到这些文字中的任意一行,然后敲击`za`。Vim会折叠从包含`{{{`的行到包含`}}}`的行之间的所有行。再敲击`za`会展开所有这些行。 163 | 164 | 刚开始你可能会觉得为了代码折叠而对源代码进行注释会有些不合理,我刚开始也这么想。对于大多数文件我现在仍然觉得这种做法并并不合适。因为不是所有人都使用相同的编辑器,所以在代码中添加的折叠注释对于那些不用Vim的人而言就像是噪音。 165 | 166 | 不过Vim脚本文件比较特殊,因为一个不用Vim的人不太可能会读你的代码,并且最重要的是如果不对代码进行分组处理,写着写着你就不知道写到哪里了,严重点可能会经脉尽断,吐血而亡。 167 | 168 | 先自己尝试尝试吧,说不定你会逐渐喜欢上它。 169 | 170 | ## 简短的名称(Short Names) 171 | 172 | 对于大多数命令和选项,Vim支持使用它们的缩写。例如,下面的两个命令做的事情完全一样: 173 | 174 | ``` 175 | :setlocal wrap 176 | :setl wrap 177 | ``` 178 | 179 | 我*强烈*提醒你不要在你的`~/.vimrc`或者是你编写的插件中使用这些缩写。Vim脚本对于初学者而言本来就已经够晦涩难懂了;从长远来看使用缩写只会使得它更难于阅读。即使*你*知道某个缩写的意思,其他人未必读得懂。 180 | 181 | 换句话说,缩写只在编码的过程中手动执行命令的时候会*很有用*。在你按了回车键以后,就没人会看到你输入什么了,这样你也没必要输入更多的字符。 182 | 183 | ## 练习 184 | 185 | 检查你的`~/.vimrc`文件,将所有相关的行组织起来。你可以这么开头:“基本设置(Basic Settings)“,”文件类型相关设置(FileType-specific settings)”,“映射(Mappings)”,和“状态条(Status Line)”。然后在每个部分添加折叠标记和标题。 186 | 187 | 想想怎么让Vim在第一次打开`~/.vimrc`文件的时候自动折叠所有设置了折叠注释的行。阅读`:help foldlevelstart`你会知道怎么搞。 188 | 189 | 检查你的`~/.vimrc`文件,把所有的命令和选项的缩写改成全称。 190 | 191 | 检查你的`~/.vimrc`文件,确保里面没有什么敏感信息。然后创建一个git或者Mercurial仓库,再将`~/.vimrc`文件放到里面,然后将这个文件链接到`~/.vimrc`。 192 | 193 | 提交你刚才创建的仓库,并把它放到Bitbucket或者GitHub上,这样其他的人都可以看到和学习它。记住要经常提交和推送到仓库中,这样你所做的修改也会被记录下来。 194 | 195 | 如果你不只在一个机器上使用Vim,那你就可以克隆那个仓库,然后像之前一样将这个文件链接到`~/.vimrc`文件。这样你就可以在所有的机器上都使用同样的Vim配置了。 196 | 197 | # 条件语句 198 | 199 | 每种编程语言都有产生分支流程的方法,在Vimscript中,这是用`if`语句实现的。 `if`语句是Vimscript中产生分支的基本方法。这里没有类似Ruby中的`unless`语句, 所以代码中所有的判断都需要用`if`实现。 200 | 201 | 在谈论Vim的`if`语句之前,我们需要花费额外的时间讲讲语法,这样可以在同一页里讲完它。 202 | 203 | ## 多行语句 204 | 205 | 有时你在一行里写不下所需的Vimscript。在讲到自动命令组时,我们已经遇到过这样的例子了。 这里是我们之前写过的代码: 206 | 207 | ``` 208 | :augroup testgroup 209 | : autocmd BufWrite * :echom "Baz" 210 | :augroup END 211 | ``` 212 | 213 | 在理想的情况下,你可以分开成三行来写。但在手工执行命令的时候,这样写就太冗长了。 其实,你可以用管道符(`|`)来隔开每一行。执行下面的命令: 214 | 215 | ``` 216 | :echom "foo" | echom "bar" 217 | ``` 218 | 219 | Vim会把它当作两个独立的命令。如果你看不到两行输出,执行`:messages`查看消息日志。 220 | 221 | 在本书的剩余部分,当你想手工执行一个命令,却对输入新行和冒号感到心烦时,试试用管道隔开, 在一行里写完。 222 | 223 | ## If的基本用法 224 | 225 | 现在让我们回到正题上来,执行下面的命令: 226 | 227 | ``` 228 | :if 1 229 | : echom "ONE" 230 | :endif 231 | ``` 232 | 233 | Vim将显示`ONE`,因为整数`1`是"truthy"。现在执行下面命令: 234 | 235 | ``` 236 | :if 0 237 | : echom "ZERO" 238 | :endif 239 | ``` 240 | 241 | Vim将*不*显示`ZERO`,因为整数`0`是"falsy"。让我们看看对字符串是怎么处理的。执行下面命令: 242 | 243 | ``` 244 | :if "something" 245 | : echom "INDEED" 246 | :endif 247 | ``` 248 | 249 | 结果可能让你吃惊。Vim*不会*把非空字符串当作"truthy",所以什么也没有显示。 250 | 251 | 让我们打破沙锅问到底。执行下面的命令: 252 | 253 | ``` 254 | :if "9024" 255 | : echom "WHAT?!" 256 | :endif 257 | ``` 258 | 259 | 这次Vim*会*显示了!为什么会这样? 260 | 261 | 为了搞懂发生了什么,执行下面三个命令: 262 | 263 | ``` 264 | :echom "hello" + 10 265 | :echom "10hello" + 10 266 | :echom "hello10" + 10 267 | ``` 268 | 269 | 第一个命令使得Vim输出`10`,第二个命令输出`20`,第三个则又一次输出`10`! 270 | 271 | 在探究了所有的命令后,对于Vimscript我们可以得出结论: 272 | 273 | - 如有必要,Vim将强制转换变量(和字面量)的类型。在解析`10 + "20foo"`时,Vim将把`"20foo"`转换成一个整数(`20`)然后加到`10`上去。 274 | - 以一个数字开头的字符串会被强制转换成数字,否则会转换成`0` 275 | - 在所有的强制转换完成*后*,当`if`的判断条件等于非零整数时,Vim会执行`if`语句体。 276 | 277 | ## Else 和 Elseif 278 | 279 | Vim,像Python一样,支持"else"和"else if"分句。执行下面的命令: 280 | 281 | ``` 282 | :if 0 283 | : echom "if" 284 | :elseif "nope!" 285 | : echom "elseif" 286 | :else 287 | : echom "finally!" 288 | :endif 289 | ``` 290 | 291 | Vim输出`finally!`,因为前面的判断条件都等于0,而0代表falsy。 292 | 293 | ## 练习 294 | 295 | 来一杯啤酒,安抚自己因Vim中的字符串强制转换而受伤的心。 -------------------------------------------------------------------------------- /note/autoload.md: -------------------------------------------------------------------------------- 1 | # 自动加载 2 | 3 | 我们已经为我们的Potion插件写了大量的功能,覆盖了本书所要讲的内容。 在结束之前,我们将讲到一些非常重要的方法,可以给我们的插件锦上添花。 4 | 5 | 第一项是使用自动加载让我们的插件更有效率。 6 | 7 | ## 如何自动加载 8 | 9 | 目前,当用户加载我们的插件时(比如打开了一个Potion文件),所有的功能都会被加载。 我们的插件还很小,所以这大概不是什么大问题,但对于较大的插件,加载全部代码将会导致可被察觉的卡顿。 10 | 11 | Vim使用称为"自动加载(autoload)"来解决这个问题。自动加载让你直到需要时才加载某一部分代码。 会有一些性能上的损失,但如果用户不总是需要你的插件的每一行代码,自动加载将带来速度上的飞跃。 12 | 13 | 示范一下它是怎么工作的。看看下面的命令: 14 | 15 | ``` 16 | :call somefile#Hello() 17 | ``` 18 | 19 | 当你执行这个命令,Vim的行为与平常的函数调用有些许不同。 20 | 21 | 如果这个函数已经加载了,Vim简单地像平常一样调用它。 22 | 23 | 否则Vim将在你的`~/.vim`(或`~/.vim/bundles/对应的插件/autoload`)下查找一个叫做`autoload/somefile.vim`的文件。 24 | 25 | 如果文件存在,Vim将加载/source文件。接着Vim就会像平常一样调用它。 26 | 27 | 在这个文件内,函数应该这样定义: 28 | 29 | ``` 30 | function somefile#Hello() 31 | " ... 32 | endfunction 33 | ``` 34 | 35 | 你可以在函数名中使用多个`#`来表示子目录。举个例子: 36 | 37 | ``` 38 | :call myplugin#somefile#Hello() 39 | ``` 40 | 41 | 这将在`autoload/myplugin/somefile.vim`查找自动加载文件。 里面的函数需要使用自动加载的绝对路径进行定义: 42 | 43 | ``` 44 | function myplugin#somefile#Hello() 45 | " ... 46 | endfunction 47 | ``` 48 | 49 | ## 实验一下 50 | 51 | 为了更好地理解自动加载,让我们实验一下。 创建一个`~/.vim/autoload/example.vim`文件并加入下面的内容: 52 | 53 | ``` 54 | echom "Loading..." 55 | 56 | function! example#Hello() 57 | echom "Hello, world!" 58 | endfunction 59 | 60 | echom "Done loading." 61 | ``` 62 | 63 | 保存文件并执行`:call example#Hello()`。Vim将输出下面内容: 64 | 65 | ``` 66 | Loading... 67 | Done loading. 68 | Hello, world! 69 | ``` 70 | 71 | 这个小演示证明了几件事: 72 | 73 | 1. Vim的确是在半途加载了`example.vim`文件。当我们打开Vim的时候它并不存在,所以不可能是在启动时加载的。 74 | 2. 当Vim找到它需要自动加载的文件后,它在调用对应函数之前就加载了整个文件。 75 | 76 | **先不要关闭Vim**,修改函数的定义成这样: 77 | 78 | ``` 79 | echom "Loading..." 80 | 81 | function! example#Hello() 82 | echom "Hello AGAIN, world!" 83 | endfunction 84 | 85 | echom "Done loading." 86 | ``` 87 | 88 | 保存文件并**不要关闭Vim**,执行`:call example#Hello()`。Vim将简单地输出: 89 | 90 | ``` 91 | Hello, world! 92 | ``` 93 | 94 | Vim已经有了`example#Hello`的一个定义,所以它不再需要重新加载文件,这意味着: 95 | 96 | 1. 函数以外的代码将不再执行。 97 | 2. 它不会反映函数本身的变化。 98 | 99 | 现在执行`:call example#BadFunction()`。你将再一次看到加载信息,伴随着一个函数不存在的错误。 但现在尝试再次执行`:call example#Hello()`。这次你将看到更新后的信息! 100 | 101 | 目前为止你应该清晰地了解到Vim会怎么处理一个自动加载类型的函数调用吧: 102 | 103 | 1. 它首先是否已经存在同名的函数了。如果是,就调用它。 104 | 2. 否则,查找名字对应的文件,并source它。 105 | 3. 然后试图调用那个函数。如果成功,太棒了。如果失败,就输出一个错误。 106 | 107 | 如果你还是没有完成弄懂,回到前面重新过一遍演示,注意观察每条规则生效的地方。 108 | 109 | ## 自动加载什么 110 | 111 | 自动加载不是没有缺陷的。 设置了自动加载后,会有一些(小的)运行开销,更别说你不得不在你的代码里容忍丑陋的函数名了。 112 | 113 | 正因为如此,如果你不是写一个用户会在*每次*打开Vim对话时都用到的插件,最好尽量把功能代码都挪到autoload文件中去。 这将减少你的插件在用户启动Vim时的影响,尤其是在人们安装了越来越多的插件的今天。 114 | 115 | 所以有什么是可以安全地自动加载?那些不由你的用户直接调用的部分。 映射和自定义命令不能自动加载(因为它们需要由用户调用),但别的许多东西都可以。 116 | 117 | 让我们看看Potion插件里有什么可以自动加载的。 118 | 119 | ## 在Potion插件里添加自动加载 120 | 121 | 我们将从编译和执行功能开始下手。 在前一章的最后,我们的`ftplugin/potion/running.vim`文件大概是这样: 122 | 123 | ``` 124 | if !exists("g:potion_command") 125 | let g:potion_command = "/Users/sjl/src/potion/potion" 126 | endif 127 | 128 | function! PotionCompileAndRunFile() 129 | silent !clear 130 | execute "!" . g:potion_command . " " . bufname("%") 131 | endfunction 132 | 133 | function! PotionShowBytecode() 134 | " Get the bytecode. 135 | let bytecode = system(g:potion_command . " -c -V " . bufname("%")) 136 | 137 | " Open a new split and set it up. 138 | vsplit __Potion_Bytecode__ 139 | normal! ggdG 140 | setlocal filetype=potionbytecode 141 | setlocal buftype=nofile 142 | 143 | " Insert the bytecode. 144 | call append(0, split(bytecode, '\v\n')) 145 | endfunction 146 | 147 | nnoremap r :call PotionCompileAndRunFile() 148 | nnoremap b :call PotionShowBytecode() 149 | ``` 150 | 151 | 这个文件仅仅当Potion文件加载时才会调用,所以它通常不会影响Vim的启动时间。 但可能会有一些用户就是不想要这些功能,所以如果我们可以自动加载某些部分, 每次打开Potion文件时可以省下他们以毫秒记的时间。 152 | 153 | 是的,这种情况下我们不会节省多少。 但你可以想象到可能有那么一个插件包括了数千行可以通过自动加载来减少每次的加载时间的代码。 154 | 155 | 让我们开始吧。在你的插件repo中创建一个`autoload/potion/running.vim`文件。 然后移动两个函数进去,并修改它们的名字,让它们看上去像: 156 | 157 | ``` 158 | echom "Autoloading..." 159 | 160 | function! potion#running#PotionCompileAndRunFile() 161 | silent !clear 162 | execute "!" . g:potion_command . " " . bufname("%") 163 | endfunction 164 | 165 | function! potion#running#PotionShowBytecode() 166 | " Get the bytecode. 167 | let bytecode = system(g:potion_command . " -c -V " . bufname("%")) 168 | 169 | " Open a new split and set it up. 170 | vsplit __Potion_Bytecode__ 171 | normal! ggdG 172 | setlocal filetype=potionbytecode 173 | setlocal buftype=nofile 174 | 175 | " Insert the bytecode. 176 | call append(0, split(bytecode, '\v\n')) 177 | endfunction 178 | ``` 179 | 180 | 注意`potion#running`部分的函数名怎么匹配它们所在的路径。 现在修改`ftplugin/potion/running.vim`文件成这样: 181 | 182 | ``` 183 | if !exists("g:potion_command") 184 | let g:potion_command = "/Users/sjl/src/potion/potion" 185 | endif 186 | 187 | nnoremap r 188 | \ :call potion#running#PotionCompileAndRunFile() 189 | 190 | nnoremap b 191 | \ :call potion#running#PotionShowBytecode() 192 | ``` 193 | 194 | 保存文件,关闭Vim,然后打开你的`factorial.pn`文件。尝试这些映射,确保它们依然正常工作。 195 | 196 | 确保你仅仅在第一次执行其中一个映射的时候才看到诊断信息`Autoloading...`(你可能需要使用`:message`来看到)。 一旦认为自动加载正常工作,你可以移除那些信息。 197 | 198 | 正如你看到的,我们保留`nnoremap`映射部分不变。 我们不能自动加载它们,不然用户就没办法引发自动加载了! 199 | 200 | 你将在Vim插件中普遍看到:大多数的功能将位于自动加载函数中,仅有`nnoremap`和`command`命令每次都被Vim加载。 每次你写一个有用的Vim插件时,不要忘了这一点。 201 | 202 | ## 练习 203 | 204 | 阅读`:help autoload` 205 | 206 | 稍微测试一下并弄懂自动加载变量是怎么一回事。 207 | 208 | 假设你想要强制加载一个Vim已经加载的自动加载文件,并不会惊扰到用户。 你会怎么做?你可能想要阅读`:help silent!`(译注:此处应该是`:help :silent`)。不过在现实生活中请不要那么做。 -------------------------------------------------------------------------------- /note/execute.md: -------------------------------------------------------------------------------- 1 | # Execute命令 2 | 3 | `execute`命令用来把一个字符串当作Vimscript命令执行。在前面的章节我们曾经跟它打过交道, 不过随着对Vimscript中的字符串有更深入的了解,现在我们将再次认识它。 4 | 5 | ## `execute`基本用法 6 | 7 | 执行下面的命令: 8 | 9 | ``` 10 | :execute "echom 'Hello, world!'" 11 | ``` 12 | 13 | Vim把`echom 'Hello, world!'`当作一个命令,而且尽职地在把它输出的同时将消息记录下来。 Execute是一个非常强大的工具,因为它允许你用任意字符串来创造命令。 14 | 15 | 让我们试试一个更实用的例子。先在Vim里打开一个文件作为准备工作,接着使用`:edit foo.txt`在同一个窗口创建新的缓冲区。 现在执行下面的命令: 16 | 17 | ``` 18 | :execute "rightbelow vsplit " . bufname("#") 19 | ``` 20 | 21 | Vim将在第二个文件的右边打开第一个文件的竖直分割窗口(vertical split)。为什么会这样? 22 | 23 | 首先,Vim将`"rightbelow vsplit"`和`bufname('#')`调用的结果连接在一起,创建一个字符串作为命令。 24 | 25 | 我们过一段时间才会讲到相应的函数,现在姑且认为它返回前一个缓冲区的路径名。 你可以用`echom`来确认这一点。 26 | 27 | 待`bufname`执行完毕,Vim将结果连接成`"rightbelow vsplit bar.txt"`。 `execute`命令将此作为Vimscript命令执行,在新的分割里打开该文件。 28 | 29 | ## Execute危险吗? 30 | 31 | 在大多数编程语言中使用诸如"eval"来构造可执行的字符串是会受到谴责的(如果不会是更严重的后果)。 因为两个原因,Vimscript中的`execute`命令能免于操这份心。 32 | 33 | 首先,大多数Vimscript代码仅仅接受唯一的来源——用户的输入。 假设有用户想输入一个古怪的字符串来执行邪恶的命令,无所谓,反正这是他们自己的计算机! 然而在其他语言里,程序通常得接受来自不可信的用户的输入。Vim是一个特殊的环境, 在此无需担心一般的安全性问题。 34 | 35 | 第二个原因是因为Vimscript有时候处理问题的方式过于晦涩难懂且稀奇古怪。 这时`execute`会是完成任务的最简单,最直白的方法。 在大多数其他语言中,使用"eval"不会省下你多少击键的生命,但在Vimscript里这样做可以化繁为简。 36 | 37 | ## 练习 38 | 39 | 浏览`:help execute`来明了哪些命令你可以用`execute`实现而哪些不可以。 但当涉猎,因为我们很快将重新审视这个问题。 40 | 41 | 阅读`:help leftabove`,`:help rightbelow`,`:help :split`和`:help :vsplit`(注意最后两个条目中额外的分号)。 42 | 43 | 在你的`~/.vimrc`中加入能在选定的分割(竖直或水平,上/下/左/右方位)中打开前一个缓冲区的映射。 -------------------------------------------------------------------------------- /note/expand.md: -------------------------------------------------------------------------------- 1 | 参考: 2 | 3 | vim提供很多内置函数,expand就是其中之一 4 | 5 | 不多说,先上文档介绍 6 | 7 | `expand({expr} [,{nosuf} [, {list}]])`  8 | 9 | expand() 10 | 11 | 扩展{expr}里的通配符和下列关键字。 12 | 13 |  'wildgnorecase' 此处适用。 14 | 15 |     如果给出{list}且为TRUE,返回列表。否则返回的是字符串,且如果返回多个匹配,以字符分隔[备注:5.0版本适用空格。但是文件名如果也包含空格就会有问题]。 16 | 17 |     如果扩展失败,返回空字符串。如果{expr}以'%','#'或'<'开始,不返回不存在的文件名。详见下。 18 | 19 |     如果{expr}以'%'、‘#’、或‘<’开始,类似于cmdline-special变量的方式扩展,扩宝相关的修饰符。这里是一个简短的小结: 20 | 21 | - %                   当前文件名 22 | - n                  交换文件名n 23 | - ``           光标所在的文件名(其实就是光标所在的一个字符串的名) 24 | - ``           自动命令文件名(当expand在自动命令中执行的时候,扩展为自动命令所在的文件的文件名) 25 | - ``          自动命令的缓冲区号(当expand在指定命令中执行的时候,扩展为自动命令的缓冲区号) 26 | - ``     自动命令匹配的名字(绝对路径下的文件名) 27 | - ``           脚本文件名或者函数名(在脚本中扩展为脚本文件名,在函数中,扩展为函数名) 28 | - ``       脚本文件的行号(当expand(‘``’)在某一行,就扩展为那一行的行号) 29 | - ``       扩展为光标所在的单词 30 | - ``    扩展为光标所在的字符串(比cword扩展的更多) 31 | - ``        最近收到的消息的值 32 | 33 | 修饰符: 34 | 35 |     :p                扩展为完整的路径 36 | 37 |     :h                去掉最后一个部分 38 | 39 |     :t                 只保留最后一个部分 40 | 41 |     :r                 根部(去掉扩展名) 42 | 43 |     :e                只有扩展名 44 | 我们看到对于`<>`这种扩展,通常只会返回被引用的文件名,而不会进一步扩展。 45 | 46 | 对于%和#,如果文件名不存在,则返回空字符串。 47 | 48 | 对于不以%、#和<开头,则以命令行文件名那样扩展。使用'suffixes'和'wildignore'。除非给出可选的{nosuf}参数而且为TRUE. 49 | 50 | 可以有不存在的文件的名字。 51 | 52 | 例如:`echo expand("/README")`  扩展当前目录及子目录下所有的“README”(用于匹配所有目录,通配符) 53 | 54 | expand()还可以用来扩展变量和只有shell知道的环境变量。 55 | 56 | 例如:`echo expand('$FOOBAR')`  如果FOOBAR这个环境变量存在,则扩展为其值;如果不存在就直接扩展为FOOBAR。 57 | 58 | 这里的`#`目前还不知道具体能做什么,应该是用于扩展交换文件用,不常用。 -------------------------------------------------------------------------------- /note/fnamemodify.md: -------------------------------------------------------------------------------- 1 | # 路径 2 | 3 | Vim是一个文本编辑器,而文本编辑器(经常)处理文本文件。文本文件储存在文件系统中, 而我们使用路径来描述文件。Vimscript有一些内置的方法会在你需要处理路径时帮上大忙。 4 | 5 | ## 绝对路径 6 | 7 | 有时外部脚本也需要获取特定文件的绝对路径名。执行下面的命令: 8 | 9 | ``` 10 | :echom expand('%') 11 | :echom expand('%:p') 12 | :echom fnamemodify('foo.txt', ':p') 13 | ``` 14 | 15 | 第一个命令显示我们正在编辑的文件的相对路径。`%`表示"当前文件"。 Vim也支持其他一些字符串作为`expand()`的参数。 16 | 17 | 第二个命令显示当前文件的完整的绝对路径名。字符串中的`:p`告诉Vim你需要绝对路径。 这里也有许多别的修饰符可以用到。 18 | 19 | 第三个命令显示了当前文件夹下的文件`foo.txt`的绝对路径,无论文件是否存在。(译注:试一下看看文件不存在的情况?) `fnamemodify()`是一个比`expand()`灵活多了的Vim函数, 你可以指定任意文件名作为`fnamemodify()`的参数,而不仅仅是`expand()`所需要的那种特殊字符串。 20 | 21 | ## 列出文件 22 | 23 | 你可能想要得到一个特定文件夹下的文件列表。执行下面的命令: 24 | 25 | ``` 26 | :echo globpath('.', '*') 27 | ``` 28 | 29 | Vim将输出当前目录下所有的文件和文件夹。`globpath()`函数返回一个字符串, 其中每一项都用换行符隔开。为了得到一个列表,你需要自己去`split()`。执行这个命令: 30 | 31 | ``` 32 | :echo split(globpath('.', '*'), '\n') 33 | ``` 34 | 35 | 这次Vim显示一个包括各个文件路径的Vimscript列表。 如果你的文件名里包括了换行符,那就只能由你自己想办法了。 36 | 37 | `globpath()`的通配符(wildcards)的工作方式就像你所想的一样。执行下面的命令: 38 | 39 | ``` 40 | :echo split(globpath('.', '*.txt'), '\n') 41 | ``` 42 | 43 | Vim显示一个当前文件夹下的所有`.txt`文件组成的列表。 44 | 45 | 你可以用`**`递归地列出文件。执行这个命令: 46 | 47 | ``` 48 | :echo split(globpath('.', '**'), '\n') 49 | ``` 50 | 51 | Vim将列出当前文件夹下的所有文件及文件夹。 52 | 53 | `globpath()`*非常地*强大。在你完成本章练习后,你将学到更多内容。 54 | 55 | ## 练习 56 | 57 | 阅读`:help expand()`. 58 | 59 | 阅读`:help fnamemodify()`. 60 | 61 | 阅读`:help filename-modifiers`. 62 | 63 | 阅读`:help simplify()`. 64 | 65 | 阅读`:help resolve()`. 66 | 67 | 阅读`:help globpath()`. 68 | 69 | 阅读`:help wildcards`. -------------------------------------------------------------------------------- /note/leaders.md: -------------------------------------------------------------------------------- 1 | # Leaders 2 | 3 | 我们已经学了一种不会让我们发狂的键盘映射方法,但是你可以注意到另外一个问题。 4 | 5 | 每次我们像`:nnoremap dd`这样映射一个按键都会覆盖掉``的原有功能。 如果哪天我们想用``了,怎么办? 6 | 7 | 有些按键你平常使用并不需要用到。你几乎永远不会用到`-`、 `H`、`L`、``、`` 和``这些按键的功能(当然,是在normal模式下)。依据你的工作方式,可能还有其他你 不会用到的按键。 8 | 9 | 这些按键都可以随意映射,但是只有这6个按键貌似不够吧。难道为Vim称道的可定制传说 有问题? 10 | 11 | ## 映射按键序列 12 | 13 | 不像Emacs,Vim可以映射多个按键。运行下面命令: 14 | 15 | ``` 16 | :nnoremap -d dd 17 | :nnoremap -c ddO 18 | ``` 19 | 20 | norma模式下快读敲入 `-d`或`-c`查看效果。第一个映射作用是删除一行,第二个是 删除一行并进入insert模式。 21 | 22 | 这就意味着你可以用一个你不常用的按键(如`-`)作为“前缀”,后接其它字符作为一个整体 进行映射。你需要多敲一个按键以执行这些映射,多一个按键而已,很容易就记住了。 23 | 24 | 如果你也认为这是个好方法,我可以告诉你,Vim已经支持这种机制。 25 | 26 | ## Leader 27 | 28 | 我们称这个“前缀”为“leader”。你可以按你的喜好设置你的leader键。运行命令: 29 | 30 | ``` 31 | :let mapleader = "-" 32 | ``` 33 | 34 | 你可以替换`-`为你喜欢的按键。尽管会屏蔽一个有用的功能,但我个人使用的是`,`,因为这个键比较 比较容易按到。 35 | 36 | 当你创建新的映射时,你可以使用``表示“我设置的leader按键”。运行命令: 37 | 38 | ``` 39 | :nnoremap d dd 40 | ``` 41 | 42 | 现在试试按下你的leader按键和`d`。Vim会删除当前行。 43 | 44 | 然而为何每次都要繁琐的设置``?为什么创建映射时不直接敲入你的“前缀”按键? 原因主要有三个。 45 | 46 | 首先,你某天可能会想要更换你的“leader”。在一个地方定义它使得更方便更换它。 47 | 48 | 第二,其他人看你的`~/.vimrc`文件时,一旦看到``就能够立即知道你的用意。如果他们 喜欢你的`~/.vimrc`配置,即使他们使用不同的leader也可以简单的复制你的映射配置。 49 | 50 | 最后,许多Vim插件都会创建以``开头的映射。如果你已经设置了leader,你会更容易上手 使用那些插件。 51 | 52 | ## Local Leader 53 | 54 | Vim有另外一个“leader”成为“local leader“。这个leader用于那些只对某类文件 (如Python文件、HTML文件)而设置的映射。 55 | 56 | 本书将在后续章节讲述如何为特定类型的文件创建映射,但你可以现在创建一个“localleader”: 57 | 58 | ``` 59 | :let maplocalleader = "\\" 60 | ``` 61 | 62 | 注意我们使用`\\`而不是`\`,因为`\`在Vimscript中是转义字符。我们将在后续章节 讲到这个。 63 | 64 | 现在你就可以在映射中使用``了,使用方法和``一样(当然, 你要使用另外一个前缀)。 65 | 66 | 如果你不喜欢反斜线,请随意更改它。 67 | 68 | ## 练习 69 | 70 | 阅读`:help mapleader`。 71 | 72 | 阅读`:help maplocalleader`。 73 | 74 | 在你的`~/.vimrc`文件中设置`mapleader`和`maplocalleader`。 75 | 76 | 增加``前缀到之前章节中你添加到`~/.vimrc`文件中的映射命令, 防止那些映射覆盖了默认的按键作用。 -------------------------------------------------------------------------------- /note/runtimepath.md: -------------------------------------------------------------------------------- 1 | 公司的 10.61.33.10 自从上次重装系统后,vim 就一直无法语法高亮,用得很不爽。经过网上大搜索和实验研究,发现启动 vim 后依次输入以下命令 2 | 3 | `:let $VIMRUNTIME = "/usr/share/vim/vim61"` 4 | 5 | ` :set runtimepath=/usr/share/vim/vim61` 6 | 7 | `:syntax on` 8 | 9 | 就 OK 了。原因是默认的环境变量对应的路径是错误的,路径中多了一层“local”: `$VIMRUNTIME="/usr/local/share/vim"`,可用 `:echo $VIMRUNTIME` 命令查看。 `runtimepath=~/.vim,/usr/local/share/vim/vimfiles,/usr/local/share/vim, /usr/local/share/vim/vimfiles/after,~/.vim/after`,可用 `:set rtp` 或 `:set runtimepath` 命令查看。 但每次进入 vim 都要输入这几条命令,相当麻烦,解决方法是把这三条命令写入 /root/.vimrc,每次 vim 启动时都会先执行这里面的脚本。相比之下,10.61.102.11 的语法高亮可用,因为它的环境变量的路径已经设对了,但它在 /root/ 下并没有 .vimrc 这个文件。这么看来,两台机必然至少有一个保存着这些环境变量文件有所不同,是哪些文件呢? 在 10.61.33.10 下输入命令 `grep -r "/usr/local/share/vim"` /etc/ 搜不到任何结果。 grep -r "/usr/local/share/vim" / 搜了几个小时还没有任何结果,放弃了。 看来是以非明文的方式放在某个文件里,也就是说是编译 Linux 内核或安装 vim 时决定的。 --------------------------------------------------------------------------------