diff --git a/.gitignore b/.gitignore index ad8956bc1..3974e19ab 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ doc/tags-cn wiki/.git *.class .floo +*.pyc .flooignore *.netrwhist *-rplugin~ diff --git a/README.md b/README.md index 445e3a644..b3ea244c4 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ For more features, please read [SpaceVim's Blog](https://spacevim.org/blog/) ├─ docs/ website(cn/en) ├─ wiki/ wiki(cn/en) ├─ bin/ executable +├─ bundle/ forked repos └─ test/ tests ``` diff --git a/autoload/SpaceVim/autocmds.vim b/autoload/SpaceVim/autocmds.vim index c4712f783..4a85a7006 100644 --- a/autoload/SpaceVim/autocmds.vim +++ b/autoload/SpaceVim/autocmds.vim @@ -70,6 +70,7 @@ function! SpaceVim#autocmds#init() abort augroup END endfunction +let g:_spacevim_cursorline_flag = -1 function! s:enable_cursorline() abort if g:_spacevim_cursorline_flag == -1 setl cursorline diff --git a/autoload/SpaceVim/layers/autocomplete.vim b/autoload/SpaceVim/layers/autocomplete.vim index 328f12929..9961edeeb 100644 --- a/autoload/SpaceVim/layers/autocomplete.vim +++ b/autoload/SpaceVim/layers/autocomplete.vim @@ -28,7 +28,7 @@ function! SpaceVim#layers#autocomplete#plugins() abort let plugins = [ - \ ['honza/vim-snippets', { 'on_event' : 'InsertEnter', 'loadconf_before' : 1}], + \ [g:_spacevim_root_dir . 'bundle/vim-snippets', { 'on_event' : 'InsertEnter', 'loadconf_before' : 1}], \ ['Shougo/neco-syntax', { 'on_event' : 'InsertEnter'}], \ ['Shougo/context_filetype.vim', { 'on_event' : 'InsertEnter'}], \ ['Shougo/neoinclude.vim', { 'on_event' : 'InsertEnter'}], diff --git a/autoload/SpaceVim/layers/checkers.vim b/autoload/SpaceVim/layers/checkers.vim index 73367fde4..6d77b9a13 100644 --- a/autoload/SpaceVim/layers/checkers.vim +++ b/autoload/SpaceVim/layers/checkers.vim @@ -18,7 +18,7 @@ function! SpaceVim#layers#checkers#plugins() abort let plugins = [] if g:spacevim_enable_neomake && g:spacevim_enable_ale == 0 - call add(plugins, ['neomake/neomake', {'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/neomake', {'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}]) elseif g:spacevim_enable_ale call add(plugins, ['dense-analysis/ale', {'merged' : 0, 'loadconf_before' : 1}]) else diff --git a/autoload/SpaceVim/layers/core.vim b/autoload/SpaceVim/layers/core.vim index d0afe0adb..7e1bf52a8 100644 --- a/autoload/SpaceVim/layers/core.vim +++ b/autoload/SpaceVim/layers/core.vim @@ -11,40 +11,40 @@ let s:SYS = SpaceVim#api#import('system') function! SpaceVim#layers#core#plugins() abort let plugins = [] if g:spacevim_filemanager ==# 'nerdtree' - call add(plugins, ['scrooloose/nerdtree', { 'merged' : 0, + call add(plugins, [g:_spacevim_root_dir . 'bundle/nerdtree', { 'merged' : 0, \ 'loadconf' : 1}]) elseif g:spacevim_filemanager ==# 'vimfiler' - call add(plugins, ['Shougo/vimfiler.vim',{ + call add(plugins, [g:_spacevim_root_dir . 'bundle/vimfiler.vim',{ \ 'merged' : 0, \ 'loadconf' : 1 , \ 'loadconf_before' : 1, \ 'on_cmd' : ['VimFiler', 'VimFilerBufferDir'] \ }]) - call add(plugins, ['Shougo/unite.vim',{ + call add(plugins, [g:_spacevim_root_dir . 'bundle/unite.vim',{ \ 'merged' : 0, \ 'loadconf' : 1 \ }]) call add(plugins, ['Shougo/vimproc.vim', {'build' : [(executable('gmake') ? 'gmake' : 'make')]}]) elseif g:spacevim_filemanager ==# 'defx' - call add(plugins, ['Shougo/defx.nvim',{'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}]) - call add(plugins, ['kristijanhusak/defx-git',{'merged' : 0, 'loadconf' : 1}]) - call add(plugins, ['kristijanhusak/defx-icons',{'merged' : 0}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/defx.nvim',{'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/defx-git',{'merged' : 0, 'loadconf' : 1}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/defx-icons',{'merged' : 0}]) endif if !g:spacevim_vimcompatible - call add(plugins, ['rhysd/clever-f.vim', {'merged' : 0}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/clever-f.vim', {'merged' : 0}]) endif - call add(plugins, ['scrooloose/nerdcommenter', { 'loadconf' : 1, 'merged' : 0}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/nerdcommenter', { 'loadconf' : 1, 'merged' : 0}]) if exists('*matchaddpos') - call add(plugins, ['andymass/vim-matchup', {'merged' : 0}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/vim-matchup', {'merged' : 0}]) endif - call add(plugins, ['gruvbox-community/gruvbox', {'loadconf' : 1, 'merged' : 0}]) - call add(plugins, ['tyru/open-browser.vim', { + call add(plugins, [g:_spacevim_root_dir . 'bundle/gruvbox', {'loadconf' : 1, 'merged' : 0}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/open-browser.vim', { \ 'merged' : 0, \ 'loadconf' : 1, \}]) - call add(plugins, ['mhinz/vim-grepper' , { 'on_cmd' : 'Grepper', + call add(plugins, [g:_spacevim_root_dir . 'bundle/vim-grepper' , { 'on_cmd' : 'Grepper', \ 'loadconf' : 1} ]) return plugins endfunction diff --git a/autoload/SpaceVim/layers/edit.vim b/autoload/SpaceVim/layers/edit.vim index d03073865..b95eb3b75 100644 --- a/autoload/SpaceVim/layers/edit.vim +++ b/autoload/SpaceVim/layers/edit.vim @@ -15,28 +15,28 @@ let s:VIM = SpaceVim#api#import('vim') function! SpaceVim#layers#edit#plugins() abort let plugins = [ - \ ['tpope/vim-surround'], - \ ['tpope/vim-repeat'], - \ ['junegunn/vim-emoji'], - \ ['terryma/vim-expand-region', { 'loadconf' : 1}], - \ ['kana/vim-textobj-user'], - \ ['kana/vim-textobj-indent'], - \ ['kana/vim-textobj-line'], - \ ['dhruvasagar/vim-table-mode'], - \ ['kana/vim-textobj-entire'], - \ ['gcmt/wildfire.vim',{'on_map' : '(wildfire-'}], - \ ['easymotion/vim-easymotion'], - \ ['haya14busa/vim-easyoperator-line'], - \ ['editorconfig/editorconfig-vim', { 'merged' : 0, 'if' : has('python') || has('python3')}], - \ ['osyo-manga/vim-jplus', { 'on_map' : '(jplus' }], - \ ['godlygeek/tabular', { 'merged' : 0}], - \ ['ntpeters/vim-better-whitespace', { 'on_cmd' : ['StripWhitespace', 'ToggleWhitespace', 'DisableWhitespace', 'EnableWhitespace']}], + \ [g:_spacevim_root_dir . 'bundle/vim-surround'], + \ [g:_spacevim_root_dir . 'bundle/vim-repeat'], + \ [g:_spacevim_root_dir . 'bundle/vim-emoji'], + \ [g:_spacevim_root_dir . 'bundle/vim-expand-region', { 'loadconf' : 1}], + \ [g:_spacevim_root_dir . 'bundle/vim-textobj-user'], + \ [g:_spacevim_root_dir . 'bundle/vim-textobj-indent'], + \ [g:_spacevim_root_dir . 'bundle/vim-textobj-line'], + \ [g:_spacevim_root_dir . 'bundle/vim-table-mode'], + \ [g:_spacevim_root_dir . 'bundle/vim-textobj-entire'], + \ [g:_spacevim_root_dir . 'bundle/wildfire.vim',{'on_map' : '(wildfire-'}], + \ [g:_spacevim_root_dir . 'bundle/vim-easymotion'], + \ [g:_spacevim_root_dir . 'bundle/vim-easyoperator-line'], + \ [g:_spacevim_root_dir . 'bundle/editorconfig-vim', { 'merged' : 0, 'if' : has('python') || has('python3')}], + \ [g:_spacevim_root_dir . 'bundle/evim-jplus', { 'on_map' : '(jplus' }], + \ [g:_spacevim_root_dir . 'bundle/tabular', { 'merged' : 0}], + \ [g:_spacevim_root_dir . 'bundle/vim-better-whitespace', { 'on_cmd' : ['StripWhitespace', 'ToggleWhitespace', 'DisableWhitespace', 'EnableWhitespace']}], \ ] if executable('fcitx') - call add(plugins,['lilydjwg/fcitx.vim', { 'on_event' : 'InsertEnter'}]) + call add(plugins,[g:_spacevim_root_dir . 'bundle/fcitx.vim', { 'on_event' : 'InsertEnter'}]) endif if g:spacevim_enable_bepo_layout - call add(plugins,['michamos/vim-bepo', { 'merged' : 0}]) + call add(plugins,[g:_spacevim_root_dir . 'bundle/vim-bepo', { 'merged' : 0}]) endif return plugins endfunction diff --git a/autoload/SpaceVim/layers/format.vim b/autoload/SpaceVim/layers/format.vim index f3d125c87..28b9b5f68 100644 --- a/autoload/SpaceVim/layers/format.vim +++ b/autoload/SpaceVim/layers/format.vim @@ -22,7 +22,7 @@ function! SpaceVim#layers#format#plugins() abort return [ - \ ['neoformat/neoformat', {'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}], + \ [g:_spacevim_root_dir . 'bundle/neoformat', {'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}], \ ] endfunction diff --git a/autoload/SpaceVim/layers/ui.vim b/autoload/SpaceVim/layers/ui.vim index 501ffbc0b..f8718fd40 100644 --- a/autoload/SpaceVim/layers/ui.vim +++ b/autoload/SpaceVim/layers/ui.vim @@ -9,17 +9,17 @@ scriptencoding utf-8 function! SpaceVim#layers#ui#plugins() abort let plugins = [ - \ ['Yggdroot/indentLine', {'merged' : 0}], - \ ['wsdjeg/tagbar', {'loadconf' : 1, 'merged' : 0}], - \ ['tenfyzhong/tagbar-makefile.vim', {'merged': 0}], - \ ['tenfyzhong/tagbar-proto.vim', {'merged': 0}], - \ ['t9md/vim-choosewin', {'merged' : 0}], - \ ['mhinz/vim-startify', {'loadconf' : 1, 'merged' : 0}], + \ [g:_spacevim_root_dir . 'bundle/indentLine', {'merged' : 0}], + \ [g:_spacevim_root_dir . 'bundle/tagbar', {'loadconf' : 1, 'merged' : 0}], + \ [g:_spacevim_root_dir . 'bundle/tagbar-makefile.vim', {'merged': 0}], + \ [g:_spacevim_root_dir . 'bundle/tagbar-proto.vim', {'merged': 0}], + \ [g:_spacevim_root_dir . 'bundle/vim-choosewin', {'merged' : 0}], + \ [g:_spacevim_root_dir . 'bundle/vim-startify', {'loadconf' : 1, 'merged' : 0}], \ ] if !SpaceVim#layers#isLoaded('core#statusline') - call add(plugins, ['vim-airline/vim-airline', { 'merged' : 0, + call add(plugins, [g:_spacevim_root_dir . 'bundle/vim-airline', { 'merged' : 0, \ 'loadconf' : 1}]) - call add(plugins, ['vim-airline/vim-airline-themes', { 'merged' : 0}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/vim-airline-themes', { 'merged' : 0}]) endif return plugins @@ -259,7 +259,6 @@ function! s:toggle_win_fringe() abort endif endfunction -let g:_spacevim_cursorline_flag = -1 function! s:toggle_cursorline() abort setl cursorline! let g:_spacevim_cursorline_flag = g:_spacevim_cursorline_flag * -1 diff --git a/autoload/SpaceVim/plugins.vim b/autoload/SpaceVim/plugins.vim index 020f5f4f7..433263561 100644 --- a/autoload/SpaceVim/plugins.vim +++ b/autoload/SpaceVim/plugins.vim @@ -140,28 +140,8 @@ function! s:install_manager() abort \ . fnameescape(g:spacevim_plugin_bundle_dir) \ . 'neobundle.vim' elseif g:spacevim_plugin_manager ==# 'dein' - "auto install dein - if filereadable(expand(g:spacevim_plugin_bundle_dir) - \ . join(['repos', 'github.com', - \ 'Shougo', 'dein.vim', 'README.md'], - \ s:Fsep)) - let g:_spacevim_dein_installed = 1 - else - if executable('git') - exec '!git clone https://github.com/Shougo/dein.vim "' - \ . expand(g:spacevim_plugin_bundle_dir) - \ . join(['repos', 'github.com', - \ 'Shougo', 'dein.vim"'], s:Fsep) - let g:_spacevim_dein_installed = 1 - else - echohl WarningMsg - echom 'You need install git!' - echohl None - endif - endif - exec 'set runtimepath+='. fnameescape(g:spacevim_plugin_bundle_dir) - \ . join(['repos', 'github.com', 'Shougo', - \ 'dein.vim'], s:Fsep) + let g:_spacevim_dein_installed = 1 + exec 'set runtimepath+=' . g:_spacevim_root_dir . 'bundle/dein.vim/' elseif g:spacevim_plugin_manager ==# 'vim-plug' "auto install vim-plug if filereadable(expand(g:spacevim_data_dir.'/vim-plug/autoload/plug.vim')) @@ -184,9 +164,8 @@ function! s:install_manager() abort endif endf -if get(g:,'spacevim_enable_plugins', 1) - call s:install_manager() -endif +call s:install_manager() + function! SpaceVim#plugins#begin(path) abort let g:unite_source_menu_menus.AddedPlugins = diff --git a/autoload/SpaceVim/plugins/manager.vim b/autoload/SpaceVim/plugins/manager.vim index 8b56de6bd..933d9c763 100644 --- a/autoload/SpaceVim/plugins/manager.vim +++ b/autoload/SpaceVim/plugins/manager.vim @@ -417,28 +417,32 @@ endfunction function! s:pull(repo) abort let s:pct += 1 let s:ui_buf[a:repo.name] = s:pct - let argv = ['git', 'pull', '--progress'] - if s:JOB.vim_job || s:JOB.nvim_job - let jobid = s:JOB.start(argv,{ - \ 'on_stderr' : function('s:on_install_stdout'), - \ 'cwd' : a:repo.path, - \ 'on_exit' : function('s:on_pull_exit') - \ }) - if jobid != 0 - let s:pulling_repos[jobid] = a:repo + if !get(a:repo, 'local', 0) + let argv = ['git', 'pull', '--progress'] + if s:JOB.vim_job || s:JOB.nvim_job + let jobid = s:JOB.start(argv,{ + \ 'on_stderr' : function('s:on_install_stdout'), + \ 'cwd' : a:repo.path, + \ 'on_exit' : function('s:on_pull_exit') + \ }) + if jobid != 0 + let s:pulling_repos[jobid] = a:repo + call s:msg_on_start(a:repo.name) + endif + else + let s:jobpid += 1 + let s:pulling_repos[s:jobpid] = a:repo call s:msg_on_start(a:repo.name) + redraw! + call s:JOB.start(argv,{ + \ 'on_stderr' : function('s:on_install_stdout'), + \ 'cwd' : a:repo.path, + \ 'on_exit' : function('s:on_pull_exit') + \ }) + endif else - let s:jobpid += 1 - let s:pulling_repos[s:jobpid] = a:repo - call s:msg_on_start(a:repo.name) - redraw! - call s:JOB.start(argv,{ - \ 'on_stderr' : function('s:on_install_stdout'), - \ 'cwd' : a:repo.path, - \ 'on_exit' : function('s:on_pull_exit') - \ }) - + call s:msg_on_local(a:repo.name) endif endfunction @@ -525,6 +529,9 @@ if has('nvim') function! s:msg_on_start(name) abort call s:set_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '+ ' . a:name . ': Updating...') endfunction + function! s:msg_on_local(name) abort + call s:set_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '- ' . a:name . ': Skip local') + endfunction function! s:msg_on_install_start(name) abort call s:set_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '+ ' . a:name . ': Installing...') endfunction @@ -532,6 +539,9 @@ elseif s:VIM_CO.has('python') function! s:msg_on_start(name) abort call s:append_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '+ ' . a:name . ': Updating...') endfunction + function! s:msg_on_local(name) abort + call s:append_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '- ' . a:name . ': Skip local') + endfunction function! s:msg_on_install_start(name) abort call s:append_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '+ ' . a:name . ': Installing...') endfunction @@ -539,6 +549,9 @@ else function! s:msg_on_start(name) abort call s:set_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '+ ' . a:name . ': Updating...') endfunction + function! s:msg_on_local(name) abort + call s:set_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '- ' . a:name . ': Skip local') + endfunction function! s:msg_on_install_start(name) abort call s:set_buf_line(s:plugin_manager_buffer, s:ui_buf[a:name] + 3, '+ ' . a:name . ': Installing...') endfunction diff --git a/bundle/README.md b/bundle/README.md new file mode 100644 index 000000000..0ee7c5ea8 --- /dev/null +++ b/bundle/README.md @@ -0,0 +1,11 @@ +## Forked repos + +### checkers layer + +- neomake +- vim-snippets +- neco-syntax +- context_filetype.vim +- neoinclude.vim +- neosnippet-snippets +- neopairs.vim diff --git a/bundle/clever-f.vim/.codecov.yml b/bundle/clever-f.vim/.codecov.yml new file mode 100644 index 000000000..53b2086e7 --- /dev/null +++ b/bundle/clever-f.vim/.codecov.yml @@ -0,0 +1,8 @@ +coverage: + status: + project: + default: + target: 0% + patch: + default: + target: 0% diff --git a/bundle/clever-f.vim/.github/workflows/ci.yml b/bundle/clever-f.vim/.github/workflows/ci.yml new file mode 100644 index 000000000..94f693551 --- /dev/null +++ b/bundle/clever-f.vim/.github/workflows/ci.yml @@ -0,0 +1,66 @@ +name: CI +on: [push, pull_request] + +jobs: + unit-tests: + name: Unit tests + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + neovim: [false, true] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - name: Checkout themis.vim + uses: actions/checkout@v2 + with: + repository: thinca/vim-themis + path: vim-themis + - name: Install Vim or Neovim + uses: rhysd/action-setup-vim@v1 + id: vim + with: + neovim: ${{ matrix.neovim }} + - name: Run unit tests + env: + THEMIS_VIM: ${{ steps.vim.outputs.executable }} + PROFILE_LOG: profile.txt + run: | + cd ./test + echo $THEMIS_VIM + ../vim-themis/bin/themis . + # covimerage seems not maintained for Windows. Skip taking code coverage on Windows + - name: Install Python + if: matrix.os != 'windows-latest' + uses: actions/setup-python@v1 + - name: Install covimerage + if: matrix.os != 'windows-latest' + run: | + pip install covimerage + covimerage --version + - name: Run covimerage + if: matrix.os != 'windows-latest' + run: | + cd ./test + covimerage write_coverage profile.txt + - name: Take coverage + if: matrix.os != 'windows-latest' + run: | + cd ./test + coverage report + coverage xml + - name: Upload coverage to codecov + if: matrix.os != 'windows-latest' + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./test/coverage.xml + + vint: + name: Run vint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v1 + - run: pip install vim-vint + - run: vint --warning --verbose --enable-neovim ./autoload ./plugin diff --git a/bundle/clever-f.vim/.gitignore b/bundle/clever-f.vim/.gitignore new file mode 100644 index 000000000..2fd1dcbdf --- /dev/null +++ b/bundle/clever-f.vim/.gitignore @@ -0,0 +1,4 @@ +/doc/tags +/test/profile.txt +/test/htmlcov +/test/.coverage_covimerage diff --git a/bundle/clever-f.vim/README.md b/bundle/clever-f.vim/README.md new file mode 100644 index 000000000..49eb720ef --- /dev/null +++ b/bundle/clever-f.vim/README.md @@ -0,0 +1,158 @@ +clever-[f][].vim +================ +[![Build Status][]][CI] +[![Coverage Status][]][Codecov] + +clever-f.vim extends `f`, `F`, `t` and `T` mappings for more convenience. Instead of `;`, `f` is available +to repeat after you type `f{char}` or `F{char}`. `F` after `f{char}` and `F{char}` is also available +to undo a jump. `t{char}` and `T{char}` are ditto. This extension makes a repeat easier and makes you +forget the existence of `;`. You can use `;` for other key mapping. In addition, this extension provides +many convenient features like target character highlighting, smart case matching and so on. + +If you want to reset the searching character without moving cursor, map `(clever-f-reset)` to your +favorite key. + +Lastly, you can customize the behavior of the mappings and features. + +### [Try Online Demo][] using [vim.js][] + + +## USAGE + +![Screen shot](https://raw.githubusercontent.com/rhysd/screenshots/master/clever-f.vim/cleverf_main.gif) + +I'll show some examples of usage. `_` is the place of cursor, `->` is a move of cursor, alphabets above +`->` is input by keyboard. Note that this is a part of clever-f.vim's features. + +### __`f`__ + + input: fh f f e fo f + move : _---------->_------>_---------->_->_---------------->_->_ + input: F F + move : _<-----------------------------_<-_ + text : hoge huga hoo hugu ponyo + +![f screencast](https://raw.githubusercontent.com/rhysd/screenshots/master/clever-f.vim/cleverf_1.gif) + + +### __`F`__ + + input: f Fh b f Fo + move : _<----------_<------_<-_<-----------------------------_<-_ + input: F F F + move : _---------->_------>_----------->_ + text : hoge huga huyo hugu ponyo + +![F screencast](https://raw.githubusercontent.com/rhysd/screenshots/master/clever-f.vim/cleverf_2.gif) + + +### __`t`__ + + input: th t t e to t + move : _--------->_------>_---------->_-->_--------------->_->_ + input: T T + move : _<-----------------------------__ + text : hoge huga hoo hugu ponyo + +![t screencast](https://raw.githubusercontent.com/rhysd/screenshots/master/clever-f.vim/cleverf_3.gif) + + +## CUSTOMIZE + +### Search a character only in current line + +`g:clever_f_across_no_line` controls to search a character across multi lines or not. Please set it +to `1` in your vimrc to search a character only in current line. + +### Ignore case + +`g:clever_f_ignore_case` controls whether or not searches are case-insensitive. If you want searches +to be case-insensitive, set it to `1` in your vimrc. + +### Smart case + +`g:clever_f_smart_case` controls whether searches are smart case or not. If you type a lower case character, the case will be ignored however if you type an upper case character it will only search for upper case characters. Please set it to `1` in your vimrc to enable searching by smart case. + +### Target character highlighting in current line + +clever-f.vim highlights the target character you input in current line. The highlight is cleared +automatically when the search ends. If you want to change the highlight group, set your favorite highlight +group to `g:clever_f_mark_char_color`. + +Below is an example using `ta` in description of clever-f.vim. + +![highlight example](https://raw.githubusercontent.com/rhysd/screenshots/master/clever-f.vim/cleverf_4.gif) + +Here, `ta` searches `a` forward then matches the character before `a` and `Ta` searches `a` backward +then matches the character after `a`. You can see the highlighted target is dynamically changed following +the cursor's direction. + +### Timeout + +You can specify the timeout for `f`, `F`, `t` and `T` mappings. If the interval of these mappings +is greater than the one you specified, clever-f.vim resets its state to make you input a new character. +This feature is disabled by default. If you want to use this feature, set `g:clever_f_timeout_ms` +to proper value. + +### Repeat last input + +`` is easy to type but usually it isn't input as the target character of search. So by default, +when you input `` as `{char}`, the previous input is used instead of ``. For example, when +you previously input `fa` and then input `f`, `a` will be used as input instead of ``. +You can specify characters to use previous input by setting `g:clever_f_repeat_last_char_inputs`. +Adding `` may be handy. + +### Migemo support + +In Japanese environment, it is convenient that `fa` matches `あ` in some cases. Originally, this +feature is provided by [migemo](http://0xcc.net/migemo/). clever-f can search multibyte Japanese +character with `f`, 'F', 't' and 'T' key mappings. A cmigemo package is **NOT** required because clever-f +includes regex patterns generated by migemo. Set `clever_f_use_migemo` to `1` to get migemo support. + +### Fix a direction of search + +If you always want to search forward with `f` and always want to search backward with `F`, +set `g:clever_f_fix_key_direction` to `1`. + + input: F Fh b F Fo + move : _<----------_<------_<-_<-----------------------------_<-_ + input: f f f + move : _---------->_------>_----------->_ + text : hoge huga huyo hugu ponyo + +### Show prompt + +If you want to show a prompt when you input a character for clever-f, set `g:clever_f_show_prompt` +to `1`. The prompt is disposed after a character is input. + +### Match all symbols with one char + +Many symbol (`{`, `(`, `"`, and so on) keys are hard to press. If you want to match `;` key to all symbols, +you can use `g:clever_f_chars_match_any_signs`. If you set it to `';'`, `f;` matches all symbols. + + input: f; f f f f f f + move : _-->_--->_--------->_>_>_------------>_>_ + text : hoge.huga( autoloads: %w{ aaa bbb ccc } ) + +### Keeping the functionality of `;` and `,` via mappings + +If you are used to using `;` and `,` for forward and backward searching, but still want these to work +the same way with clever-f, you can simply remap `;`and `,` to use this plugin: + +``` +map ; (clever-f-repeat-forward) +map , (clever-f-repeat-back) +``` + +## LICENSE + +Distributed under MIT License. See `doc/clever_f.txt` + + +[f]: https://github.com/vim/vim/blob/0d76683e094c6cac2e879601aff3acf1163cbe0b/runtime/doc/motion.txt#L254-L262 +[Build Status]: https://github.com/rhysd/clever-f.vim/workflows/CI/badge.svg?branch=master&event=push +[CI]: https://github.com/rhysd/clever-f.vim/actions?query=workflow%3ACI+branch%3Amaster +[Coverage Status]: https://codecov.io/gh/rhysd/clever-f.vim/branch/master/graph/badge.svg +[Codecov]: https://codecov.io/gh/rhysd/clever-f.vim +[Try Online Demo]: http://rhysd.github.io/clever-f.vim/ +[vim.js]: https://github.com/coolwanglu/vim.js/ diff --git a/bundle/clever-f.vim/autoload/clever_f.vim b/bundle/clever-f.vim/autoload/clever_f.vim new file mode 100644 index 000000000..7413576fa --- /dev/null +++ b/bundle/clever-f.vim/autoload/clever_f.vim @@ -0,0 +1,488 @@ +let s:save_cpo = &cpo +set cpo&vim + +" constants +let s:ON_NVIM = has('nvim') + +" configurations +let g:clever_f_across_no_line = get(g:, 'clever_f_across_no_line', 0) +let g:clever_f_ignore_case = get(g:, 'clever_f_ignore_case', 0) +let g:clever_f_use_migemo = get(g:, 'clever_f_use_migemo', 0) +let g:clever_f_fix_key_direction = get(g:, 'clever_f_fix_key_direction', 0) +let g:clever_f_show_prompt = get(g:, 'clever_f_show_prompt', 0) +let g:clever_f_smart_case = get(g:, 'clever_f_smart_case', 0) +let g:clever_f_chars_match_any_signs = get(g:, 'clever_f_chars_match_any_signs', '') +let g:clever_f_mark_cursor = get(g:, 'clever_f_mark_cursor', 1) +let g:clever_f_hide_cursor_on_cmdline = get(g:, 'clever_f_hide_cursor_on_cmdline', 1) +let g:clever_f_timeout_ms = get(g:, 'clever_f_timeout_ms', 0) +let g:clever_f_mark_char = get(g:, 'clever_f_mark_char', 1) +let g:clever_f_repeat_last_char_inputs = get(g:, 'clever_f_repeat_last_char_inputs', ["\"]) +let g:clever_f_mark_direct = get(g:, 'clever_f_mark_direct', 0) + +" below variable must be set before loading this script +let g:clever_f_clean_labels_eagerly = get(g:, 'clever_f_clean_labels_eagerly', 1) + +" highlight labels +augroup plugin-clever-f-highlight + autocmd! + autocmd ColorScheme * highlight default CleverFDefaultLabel ctermfg=red ctermbg=NONE cterm=bold,underline guifg=red guibg=NONE gui=bold,underline +augroup END +highlight default CleverFDefaultLabel ctermfg=red ctermbg=NONE cterm=bold,underline guifg=red guibg=NONE gui=bold,underline + +" Priority of highlight customization is: +" High: When g:clever_f_*_color +" Middle: :highlight in a colorscheme +" Low: Default highlights +" When the variable is defined, it should be linked with :hi! since :hi does +" not overwrite existing highlight group. (#50) +if g:clever_f_mark_cursor + if exists('g:clever_f_mark_cursor_color') + execute 'highlight! link CleverFCursor' g:clever_f_mark_cursor_color + else + highlight link CleverFCursor Cursor + endif +endif +if g:clever_f_mark_char + if exists('g:clever_f_mark_char_color') + execute 'highlight! link CleverFChar' g:clever_f_mark_char_color + else + highlight link CleverFChar CleverFDefaultLabel + endif +endif +if g:clever_f_mark_direct + if exists('g:clever_f_mark_direct_color') + execute 'highlight! link CleverFDirect' g:clever_f_mark_direct_color + else + highlight link CleverFDirect CleverFDefaultLabel + endif +endif + +if g:clever_f_clean_labels_eagerly + augroup plugin-clever-f-permanent-finalizer + autocmd! + autocmd WinEnter,WinLeave,CmdWinLeave * if g:clever_f_mark_char | call s:remove_highlight() | endif + augroup END +endif +augroup plugin-clever-f-finalizer + autocmd! +augroup END + +" initialize the internal state +let s:last_mode = '' +let s:previous_map = {} +let s:previous_pos = {} +let s:first_move = {} +let s:migemo_dicts = {} +let s:previous_char_num = {} +let s:timestamp = [0, 0] + +" keys are mode string returned from mode() +function! clever_f#reset() abort + let s:previous_map = {} + let s:previous_pos = {} + let s:first_move = {} + let s:migemo_dicts = {} + + " Note: + " [0, 0] may be invalid because the representation of return value of reltime() depends on implementation. + let s:timestamp = [0, 0] + + call s:remove_highlight() + + return '' +endfunction + +" hidden API for debug +function! clever_f#_reset_all() abort + call clever_f#reset() + let s:last_mode = '' + let s:previous_char_num = {} + autocmd! plugin-clever-f-finalizer + unlet! s:moved_forward + + return '' +endfunction + +function! s:remove_highlight() abort + for h in filter(getmatches(), 'v:val.group ==# "CleverFChar"') + call matchdelete(h.id) + endfor +endfunction + +function! s:is_timedout() abort + let cur = reltime() + let rel = reltimestr(reltime(s:timestamp, cur)) + let elapsed_ms = float2nr(str2float(rel) * 1000.0) + let s:timestamp = cur + return elapsed_ms > g:clever_f_timeout_ms +endfunction + +" highlight characters to which the cursor can be moved directly +function! s:mark_direct(forward, count) abort + let line = getline('.') + let [_, l, c, _] = getpos('.') + + if (a:forward && c == len(line)) || (!a:forward && c == 1) + " there is no matching characters + return [] + endif + + if g:clever_f_ignore_case + let line = tolower(line) + endif + + let char_count = {} + let matches = [] + let indices = a:forward ? range(c, len(line) - 1, 1) : range(c - 2, 0, -1) + for i in indices + let ch = line[i] + " only matches to ASCII + if ch !~# '^[\x00-\x7F]$' | continue | endif + let ch_lower = tolower(ch) + + let char_count[ch] = get(char_count, ch, 0) + 1 + if g:clever_f_smart_case && ch =~# '\u' + " uppercase characters are doubly counted + let char_count[ch_lower] = get(char_count, ch_lower, 0) + 1 + endif + + if char_count[ch] == a:count || + \ (g:clever_f_smart_case && char_count[ch_lower] == a:count) + " NOTE: should not use `matchaddpos(group, [...position])`, + " because the maximum number of position is 8 + let m = matchaddpos('CleverFDirect', [[l, i + 1]]) + call add(matches, m) + endif + endfor + return matches +endfunction + +" introduce public function for test +function! clever_f#_mark_direct(forward, count) abort + return s:mark_direct(a:forward, a:count) +endfunction + +function! s:mark_char_in_current_line(map, char) abort + let regex = '\%' . line('.') . 'l' . s:generate_pattern(a:map, a:char) + call matchadd('CleverFChar', regex , 999) +endfunction + +" Note: +" \x80\xfd` seems to be sent by a terminal. +" Below is a workaround for the sequence. +function! s:getchar() abort + while 1 + let cn = getchar() + if type(cn) != type('') || cn !=# "\x80\xfd`" + return cn + endif + endwhile +endfunction + +function! s:include_multibyte_char(str) abort + return strlen(a:str) != clever_f#compat#strchars(a:str) +endfunction + +function! clever_f#find_with(map) abort + if a:map !~# '^[fFtT]$' + throw "Error: Invalid mapping '" . a:map . "'" + endif + + if &foldopen =~# '\<\%(all\|hor\)\>' + while foldclosed(line('.')) >= 0 + foldopen + endwhile + endif + + let current_pos = getpos('.')[1 : 2] + + let mode = s:mode() + if current_pos != get(s:previous_pos, mode, [0, 0]) + let back = 0 + if g:clever_f_mark_cursor + let cursor_marker = matchadd('CleverFCursor', '\%#', 999) + redraw + endif + " block-NONE does not work on Neovim + if g:clever_f_hide_cursor_on_cmdline && !s:ON_NVIM + let guicursor_save = &guicursor + set guicursor=n-o:block-NONE + let t_ve_save = &t_ve + set t_ve= + endif + try + if g:clever_f_mark_direct + let direct_markers = s:mark_direct(a:map =~# '\l', v:count1) + redraw + endif + if g:clever_f_show_prompt | echon 'clever-f: ' | endif + let s:previous_map[mode] = a:map + let s:first_move[mode] = 1 + let cn = s:getchar() + if cn == char2nr("\") + return "\" + endif + if index(map(deepcopy(g:clever_f_repeat_last_char_inputs), 'char2nr(v:val)'), cn) == -1 + let s:previous_char_num[mode] = cn + else + if has_key(s:previous_char_num, s:last_mode) + let s:previous_char_num[mode] = s:previous_char_num[s:last_mode] + else + echohl ErrorMsg | echo 'Previous input not found.' | echohl None + return '' + endif + endif + let s:last_mode = mode + + if g:clever_f_timeout_ms > 0 + let s:timestamp = reltime() + endif + + if g:clever_f_mark_char + call s:remove_highlight() + if mode ==# 'n' || mode ==? 'v' || mode ==# "\" || + \ mode ==# 'ce' || mode ==? 's' || mode ==# "\" + augroup plugin-clever-f-finalizer + autocmd CursorMoved call s:maybe_finalize() + autocmd InsertEnter call s:finalize() + augroup END + call s:mark_char_in_current_line(s:previous_map[mode], s:previous_char_num[mode]) + endif + endif + + if g:clever_f_show_prompt | redraw! | endif + finally + if g:clever_f_mark_cursor | call matchdelete(cursor_marker) | endif + if g:clever_f_mark_direct + for m in direct_markers + call matchdelete(m) + endfor + endif + if g:clever_f_hide_cursor_on_cmdline && !s:ON_NVIM + " Set default value at first then restore (#49) + " For example, when the value is a:blinkon0, it does not affect cursor shape so cursor + " shape continues to disappear. + set guicursor& + + if &guicursor !=# guicursor_save + let &guicursor = guicursor_save + endif + let &t_ve = t_ve_save + endif + endtry + else + " when repeated + let back = a:map =~# '\u' + if g:clever_f_fix_key_direction + let back = s:previous_map[mode] =~# '\u' ? !back : back + endif + + " reset and retry if timed out + if g:clever_f_timeout_ms > 0 && s:is_timedout() + call clever_f#reset() + return clever_f#find_with(a:map) + endif + endif + + return clever_f#repeat(back) +endfunction + +function! clever_f#repeat(back) abort + let mode = s:mode() + let pmap = get(s:previous_map, mode, '') + let prev_char_num = get(s:previous_char_num, mode, 0) + + if pmap ==# '' + return '' + endif + + " ignore special characters like \ + if type(prev_char_num) == type('') && char2nr(prev_char_num) == 128 + return '' + endif + + if a:back + let pmap = s:swapcase(pmap) + endif + + if mode[0] ==? 'v' || mode[0] ==# "\" + let cmd = s:move_cmd_for_visualmode(pmap, prev_char_num) + else + let inclusive = mode ==# 'no' && pmap =~# '\l' + let cmd = printf("%s:\call clever_f#find(%s, %s)\", + \ inclusive ? 'v' : '', + \ string(pmap), prev_char_num) + endif + + return cmd +endfunction + +" absolutely moved forward? +function! s:moves_forward(p, n) abort + if a:p[0] != a:n[0] + return a:p[0] < a:n[0] + endif + + if a:p[1] != a:n[1] + return a:p[1] < a:n[1] + endif + + return 0 +endfunction + +function! clever_f#find(map, char_num) abort + let before_pos = getpos('.')[1 : 2] + let next_pos = s:next_pos(a:map, a:char_num, v:count1) + if next_pos == [0, 0] + return + endif + + let moves_forward = s:moves_forward(before_pos, next_pos) + + " update highlight when cursor moves across lines + let mode = s:mode() + if g:clever_f_mark_char + if next_pos[0] != before_pos[0] + \ || (a:map ==? 't' && !s:first_move[mode] && clever_f#compat#xor(s:moved_forward, moves_forward)) + call s:remove_highlight() + call s:mark_char_in_current_line(a:map, a:char_num) + endif + endif + + let s:moved_forward = moves_forward + let s:previous_pos[mode] = next_pos + let s:first_move[mode] = 0 +endfunction + +function! s:finalize() abort + autocmd! plugin-clever-f-finalizer + call s:remove_highlight() + let s:previous_pos = {} + let s:moved_forward = 0 +endfunction + +function! s:maybe_finalize() abort + let pp = get(s:previous_pos, s:last_mode, [0, 0]) + if getpos('.')[1 : 2] != pp + call s:finalize() + endif +endfunction + +function! s:move_cmd_for_visualmode(map, char_num) abort + let next_pos = s:next_pos(a:map, a:char_num, v:count1) + if next_pos == [0, 0] + return '' + endif + + let m = s:mode() + call setpos("''", [0] + next_pos + [0]) + let s:previous_pos[m] = next_pos + let s:first_move[m] = 0 + + return '``' +endfunction + +function! s:search(pat, flag) abort + if g:clever_f_across_no_line + return search(a:pat, a:flag, line('.')) + else + return search(a:pat, a:flag) + endif +endfunction + +function! s:should_use_migemo(char) abort + if !g:clever_f_use_migemo || a:char !~# '^\a$' + return 0 + endif + + if !g:clever_f_across_no_line + return 1 + endif + + return s:include_multibyte_char(getline('.')) +endfunction + +function! s:load_migemo_dict() abort + let enc = &l:encoding + if enc ==# 'utf-8' + return clever_f#migemo#utf8#load_dict() + elseif enc ==# 'cp932' + return clever_f#migemo#cp932#load_dict() + elseif enc ==# 'euc-jp' + return clever_f#migemo#eucjp#load_dict() + else + let g:clever_f_use_migemo = 0 + throw 'Error: ' . enc . ' is not supported. Migemo is disabled.' + endif +endfunction + +function! s:generate_pattern(map, char_num) abort + let char = type(a:char_num) == type(0) ? nr2char(a:char_num) : a:char_num + let regex = char + + let should_use_migemo = s:should_use_migemo(char) + if should_use_migemo + if !has_key(s:migemo_dicts, &l:encoding) + let s:migemo_dicts[&l:encoding] = s:load_migemo_dict() + endif + let regex = s:migemo_dicts[&l:encoding][regex] . '\&\%(' . char . '\|\A\)' + elseif stridx(g:clever_f_chars_match_any_signs, char) != -1 + let regex = '\[!"#$%&''()=~|\-^\\@`[\]{};:+*<>,.?_/]' + elseif char ==# '\' + let regex = '\\' + endif + + let is_exclusive_visual = &selection ==# 'exclusive' && s:mode()[0] ==? 'v' + if a:map ==# 't' && !is_exclusive_visual + let regex = '\_.\ze\%(' . regex . '\)' + elseif is_exclusive_visual && a:map ==# 'f' + let regex = '\%(' . regex . '\)\zs\_.' + elseif a:map ==# 'T' + let regex = '\%(' . regex . '\)\@<=\_.' + endif + + if !should_use_migemo + let regex = '\V'.regex + endif + + return ((g:clever_f_smart_case && char =~# '\l') || g:clever_f_ignore_case ? '\c' : '\C') . regex +endfunction + +function! s:next_pos(map, char_num, count) abort + let mode = s:mode() + let search_flag = a:map =~# '\l' ? 'W' : 'bW' + let cnt = a:count + let pattern = s:generate_pattern(a:map, a:char_num) + + if a:map ==? 't' && get(s:first_move, mode, 1) + if !s:search(pattern, search_flag . 'c') + return [0, 0] + endif + let cnt -= 1 + endif + + while 0 < cnt + if !s:search(pattern, search_flag) + return [0, 0] + endif + let cnt -= 1 + endwhile + + return getpos('.')[1 : 2] +endfunction + +function! s:swapcase(char) abort + return a:char =~# '\u' ? tolower(a:char) : toupper(a:char) +endfunction + +" Drop forced visual mode character ('nov' -> 'no') +function! s:mode() abort + let mode = mode(1) + if mode =~# '^no' + let mode = mode[0 : 1] + endif + return mode +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/bundle/clever-f.vim/autoload/clever_f/compat.vim b/bundle/clever-f.vim/autoload/clever_f/compat.vim new file mode 100644 index 000000000..5c0ba5924 --- /dev/null +++ b/bundle/clever-f.vim/autoload/clever_f/compat.vim @@ -0,0 +1,19 @@ +if exists('*strchars') + function! clever_f#compat#strchars(str) abort + return strchars(a:str) + endfunction +else + function! clever_f#compat#strchars(str) abort + return strlen(substitute(a:str, '.', 'x', 'g')) + endfunction +endif + +if exists('*xor') + function! clever_f#compat#xor(a, b) abort + return xor(a:a, a:b) + endfunction +else + function! clever_f#compat#xor(a, b) abort + return a:a && !a:b || !a:a && a:b + endfunction +endif diff --git a/bundle/clever-f.vim/autoload/clever_f/migemo/cp932.vim b/bundle/clever-f.vim/autoload/clever_f/migemo/cp932.vim new file mode 100644 index 000000000..82d2290e9 --- /dev/null +++ b/bundle/clever-f.vim/autoload/clever_f/migemo/cp932.vim @@ -0,0 +1,57 @@ +scriptencoding cp932 +function! clever_f#migemo#cp932#load_dict() abort + return { + \ 'a' : '\%([ݕNҊ{b]毛^w܏㦚@oC粕ӓJlVȌlˆ^Мۜ{Qz鸈WEB{MQ榓kw{\N}Ho{tVpA֔\HՓaڏS[矏NaWo㻓֏~ĔMؒg禈Ŋ[NΎҕae}yRXvI\॑ŐVaz\eX~dVEYэʊ늿ߎӕT瑀剕ՕP]JÓV쉐˖ԋY͈b般HꙌǖsNL[ӟ䈮NzPjEDɏ͏W쏺Hq蕚V襕B\͈ԑ~㪌ZQsň}Ĉǝƈ䒩툤@rb`~qgݝю鈩[脝ōCK暖\ؐԙzЕɈŒaS㈢ҌݕJ숫rG}Lj򈡈}[YޝKgOc&ȁ_ڋ͋́ˁ܌WāNLMOf`Ap@a]\|\_s*\|\_s*\|\_s*\|\_s*\|Z\_s*\%(n\|i\_s*n\_s*c\)\|\_s*q\|\_s*\|E\_s*n\|f\_s*\|\_s*\|M\_s*V\_s*\|\_s*T\|\_s*\|Z\_s*q\|\_s*\|l\_s*\|\_s*\|\_s*\|^\_s*\|\_s*\|\_s*w\|\_s*[]\|\_s*p\|\_s*\|\_s*\|L\_s*a\_s*r\_s*d\_s*i\_s*z\_s*a\_s*b\_s*a\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*{\|\_s*\%(\|\_s*q\)\|\_s*\%(\|\_s*\_s*\_s*\_s*\)\|H\_s*a\_s*b\|H\_s*a\_s*l\_s*o\_s*r\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|\_s*F\|\_s*\|\_s*`\|^\_s*\_s*\_s*\|\_s*\|\_s*\|D\_s*`\|\_s*[K]\|\_s*G\|\_s*[mF]\|\_s*x\|\_s*\|\_s*\|\_s*\|p\_s*\%([ۓc]\|\_s*p\|\_s*\)\|\_s*[ɁX]\|E\_s*\%(s\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\)\|I\_s*\%(r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(d\_s*b\|A\_s*h\_s*\_s*X\)\|D\_s*J\_s*[\_s*h\|C\_s*\%(^\_s*O\|J\_s*[\_s*h\)\)\|h\_s*\%(o\_s*d\_s*b\|b\_s*\%(^\_s*O\|J\_s*[\_s*h\)\)\|\_s*~\|\_s*\|c\_s*\|n\_s*\_s*\|C\_s*[^lm]\|R\_s*u\_s*b\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\_s*a\_s*\|\_s*\|\_s*n\|\_s*[ꆔn]\|M\_s*a\_s*l\_s*v\_s*a\_s*l\_s*e\_s*s\|g\_s*\_s*v\_s*\_s*A\|\_s*\| \_s*A\_s*N\_s*V\_s*A\_s*\|q\_s*f\|\_s*f\|\_s*s\_s*\_s*x\_s*Z\_s*p\_s*\_s*\_s*\|\_s*\|\_s*Y\|\_s*\|G\_s*o\_s*l\_s*d\|\_s*\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*@\|a\_s*\_s*\_s*@\)\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|Z\_s*\_s*g\_s*L\_s*b\_s*c\_s*l\|S\_s*\%(b\|i\_s*l\_s*v\_s*e\_s*r\)\|g\_s*p\_s*\_s*\\|\_s*p\_s*\_s*\\|Z\_s*@\|\_s*\_s*\_s*\|I\_s*\%(\|M\_s*\_s*X\_s*^\_s*\|h\_s*\_s*C\|\_s*O\_s*X\_s*g\_s*\_s*[\_s*\|\_s*\%(g\_s*L\_s*[\|^\_s*\%([[i]\|l\_s*\%([\_s*g\|C\_s*g\)\)\)\|[\_s*\%([NKTg]\|j\_s*\_s*O\|L\_s*V\_s*\|u\_s*\_s*[\|o\_s*[\_s*h\|x\_s*\_s*W\_s*\|M\_s*\_s*X\_s*\%(g\|^\_s*\)\|]\_s*\_s*k\|X\_s*\%(`\_s*\|e\_s*B\_s*\|^\_s*[\|g\_s*\%(\_s*A\|\_s*\_s*A\)\)\|h\_s*\_s*[\|W\_s*\%([F[]\|I\_s*\_s*W\)\|f\_s*B\_s*\%(I\|G\_s*\_s*X\|V\_s*\_s*\|g\_s*\_s*A\_s*\)\|^\_s*\|\\_s*\%(\_s*e\_s*B\|\_s*C\_s*Y\)\|Z\_s*\_s*e\_s*B\_s*b\_s*N\|\_s*\)\)\|z\_s*\|o\_s*C\_s*g\|n\_s*\_s*}\_s*Q\_s*h\_s*\|\_s*\|l\_s*H\_s*\%(\_s*\_s*\|m\_s*\\)\|C\_s*\%([\_s*W\_s*X\|I\_s*\|\\_s*b\_s*v\)\|}\_s*\_s*h\_s*D\_s*[\_s*N\|\_s*\%(z\_s*\|\_s*\|\_s*p\)\|A\_s*\%([tlrImc]\|u\_s*s\_s*t\_s*r\_s*o\_s*b\_s*a\_s*i\_s*l\_s*e\_s*y\_s*a\_s*c\_s*e\_s*a\_s*e\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\|K\_s*C\_s*L\|S\_s*C\_s*I\_s*I\|s\_s*t\_s*a\_s*t\_s*i\_s*n\_s*e\|^\_s*C\_s*v\|T\_s*O\_s*K\|N\_s*S\_s*I\|V\_s*V\_s*X\_s*e\_s*\|L\_s*T\_s*L\_s*[\|\_s*\_s*N\|E\_s*R\_s*A\|D\_s*S\_s*L\_s*\_s*f\_s*\|h\_s*\_s*C\_s*u\|d\_s*a\|M\_s*\_s*W\_s*I\|b\_s*s\_s*t\_s*r\_s*a\_s*c\_s*t\_s* \_s*C\_s*o\_s*n\_s*t\_s*r\_s*o\_s*l\_s* \_s*M\_s*o\_s*d\_s*e\_s*l\|J\_s*b\_s*v\|N\_s*\_s*X\|C\_s*A\_s*_\_s*v\_s*^\)\|t\_s*^\|`\_s*\%([S^]\|\_s*\_s*\|a\_s*\%(^\|\_s*\_s*\_s*\)\|^\_s*C\_s*v\|s\_s*\_s*s\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*N\|h\_s*G\_s*L\_s*X\_s*p\_s*[\_s*g\|^\_s*c\_s*R\_s*\_s*o\_s*[\_s*^\|h\_s*\_s*C\_s*u\|\_s*\_s*\_s*\|J\_s*b\_s*v\|N\_s*\_s*X\|\_s*\_s*\_s*\)\|\_s*p\|G\_s*\%([jAC[]\|b\_s*`\|\_s*\%(h\_s*\_s*\|W\_s*F\_s*\%(\|\_s*b\_s*N\)\|[\_s*\)\|\_s*A\|I\_s*\_s*A\|X\_s*e\|v\_s*\_s*\)\)', + \ 'b' : '\%([ݍxftݖv{}~Ϟsr`ڝpؖnlmqbQ쟂ۙR廖ge䛖OE庈ꆉK㦖RWaXZU`YNϛ˖Sc]fhT^ddە_@W敖͕ꊱVGJڙkK럑㰙pgꈕ̕VՙAğ~܍燙ᾙjוؕ糉•粂בD[kuqJڒܐ[W᳓ؐߕܖܘŕhᕷwŕsFU򐁕xᕔF~o@ԕ捐lLJxʕTCZz[ߞ㢛mpCޜrF{qn֛焕S蓔Ialߕ[Leὕdcb`_aΓZrۖoɔzeX]䛇gє䊑ыIs@[bV鯝UAjcUPWєm\e}ޔȉSit䕔|ꀊL{~}ŝםf\ҔԖ_Jmה”dHݔ֔ӔՔԔؖ따ntklyHŐmn\΂gۉ~ba|_攞{onmopurAqxb]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[{xuro]\|\_s*[ڂׂԂт]\|\_s*\|\_s*\|A\_s*\|P\_s*a\_s*e\_s*o\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*Z\|\_s*\|r\_s*r\|\_s*\|\_s*\|\_s*_\|\_s*_\|\_s*\|E\_s*\|\_s*\|\_s*C\|\_s*\|X\_s*[j]\|R\_s*\_s*O\|F\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|z\_s*c\|\_s*\|u\_s*\%(\|l\_s*b\_s*N\|V\_s*l\_s*}\)\|\_s*q\|t\_s*q\|\_s*\|L\_s*[O]\|\_s*\|V\_s*A\_s*O\|\_s*[ĘU]\|\\_s*D\|\_s*[D]\|\_s*\|o\_s*\_s*\|\_s*\|\_s*\|S\_s*a\_s*n\_s*t\_s*a\_s*l\_s*a\_s*l\_s*e\_s*s\|h\_s*\|\_s*[q@]\|\\_s*\|\_s*[Žq]\|\_s*\|\_s*\|\_s*q\|c\_s*\_s*\_s*\|b\_s*\_s*\|R\_s*o\_s*s\_s*a\_s*l\_s*e\_s*s\|K\_s*N\|\_s*q\|\_s*\%([ъyJ]\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|A\_s*n\_s*n\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*[]\|f\_s*\_s*\|v\_s*\_s*R\_s*M\|\_s*\_s*\|I\_s*[\_s*g\_s*o\_s*C\|\_s*[b]\|t\_s*@\_s*S\_s*b\_s*g\|w\_s*i\|k\_s*\|y\_s*\%(L\_s*\|e\_s*\_s*M\_s*E\_s*X\)\|L\_s*f\|C\_s*M\_s*\_s*X\|a\_s*\%([ʔ^]\|\_s*E\|^\_s*C\_s*v\|h\_s*\_s*C\_s*u\|J\_s*b\_s*v\|N\_s*\_s*X\||\_s*X\_s*v\_s*\_s*C\_s*\|\_s*\_s*\_s*m\_s*\_s*\_s*\|\_s*\_s* \_s*d\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*N\)\|z\_s*E\_s*f\|B\_s*\%([hʔ^kiae]\|C\_s*\_s*\|N\_s*F\_s*(\_s*B\_s*a\_s*c\_s*k\_s*u\_s*s\_s*-\_s*N\_s*a\_s*u\_s*r\_s* \_s*F\_s*o\_s*r\_s*m\_s*)\|B\_s*C\|^\_s*C\_s*v\|u\_s*r\_s*k\_s*i\_s*n\_s*a\_s* \_s*F\_s*a\_s*s\_s*o\|t\_s*\_s*b\_s*c\|h\_s*\_s*C\_s*u\|J\_s*b\_s*v\|N\_s*\_s*X\|M\_s*P\_s*t\_s*@\_s*C\_s*\|X\_s*v\_s*\_s*C\_s*\|S\_s*\%(D\|L\_s*[\|`\_s*\_s*[\_s*i\|A\_s*\_s*e\_s*i\|f\_s*W\_s*^\_s*\)\|O\_s*X\_s*Z\_s*b\_s*g\|I\_s*T\_s*N\_s*E\_s*T\|r\_s*o\_s*m\_s*i\_s*n\_s*e\|\_s*\_s*N\|o\_s*\%(h\_s*r\_s*i\_s*u\_s*m\|v\_s*i\_s*n\_s*e\_s* \_s*S\_s*p\_s*o\_s*n\_s*g\_s*i\_s*f\_s*o\_s*r\_s*m\_s* \_s*E\_s*n\_s*c\_s*e\_s*p\_s*h\_s*a\_s*l\_s*o\_s*p\_s*a\_s*t\_s*h\_s*y\|o\_s*k\|r\_s*o\_s*n\)\)\|\_s*f\)', + \ 'c' : '\%([a|ҜDޏns}laʗۗⵘᶐsЌfَřbIziꑍC麌Z欉䓚৙}Yɍ`nXMȍ뜝k՞ߌ匣ӍeWEQLm՘iQf肝Kਗ਼Ჟ騟}{㝛ŘҟL`tiBRH{ൟHs秝nn˝JܔXLJyߛb}褜rRt莘mE硍hklKᦜnK}֞\@囍yෙΜˍ[⠍xuXSe倘Ji^V@AWGDT`ᩍBԍp]PIzt_kOjRwuPaI|qFXZsmrcDޞJܛ͞wLl܍WێЛZÖs烌gםsؑeuČٌ̟]|Vx֒绌і嚙hʉznjԌך➳Ҕȏ˗Zꉟh@ZXNÖZ驒LLQkŚTGi֙↝BގEِېߐCGዙН[Tאɐ͐ȐǝA⣛p蔞tdCNӟ׈ߙEᝎax㙘A_baJஓϛƘjbHⳙAGSL⒑WsrDJAL񙒐枙@ۑMHlFKDG@Bh坡ǑNdDI扙|œҝᝩ⫟ŐꎖvRΐyH`ՐǍU}[҂zKMzⱟJ㖍IHEzboxܗAϕDBӏ~B䱌sZY㙬ᯞӛM֌NvK@{^Z퐾^鶔ňʈUÑqC~XVTRUWS܉_wo^鿌~GF䇚`pY۞ƌIӘޚPMuoӍcqvE|―ꋀῙ܌JɍCg{mX؍Hᜁv㜜ҙg电M˂捃ABPDY`LZ迓ӞxZlWȓGFaƎb乗MEΕsCFnD㈵㦋s]Ŗl^⚑A潓gߞΖ儞bɖΜ臐wpd[g謎姎^GNH˒ΐÎᕹRK\ސˌKŽKoqҍtϔOӎ͚̍͟bAjP֎yࡐ̝咙ݐ┐Ԏ^ېΎގڎYώՎˎΎɎԎߎЈޝiSGCဋÎft偛WVz题Efiglhk{蜕婏oFT碏VhqhFJ娏QK榚S酝nSXKUڏMGjaENODCALRTWIHB@M\᭚忏w{vxs⡏urfݐZuVꐚpy曐P]AUjJfY`Ds橝ΐaO凓cjcѐUaNfdCkXĐLTQWi[RMebI\S^V΋nZo䜏_י|䓏w򏎏ҟm䀛uLЏ縐מ⪎™דɜvRIߜcB_џnՈ䐯B辑[K頏[␏K♏яҁui]疏֏ӐԚА躐ϏUJnސŜ܏ߏᏏُGᏧଞ͏ǏɏЏˏ暏ΏďƏ͏ڏ؏ɏTl\egp@CܑDI冐BGAHEn❎omowvLUhnыŎᎊtr@{wϚ`iАyэi@EJX拎}泛nyoNZyٝfj{~|{oߘIXB]KVgupikl藘ʛƓj⏎sꏎÎ~˔`Œsyd@؎䢊YoumeᘊyNJr݊jƌyĈ呁eAiMʕrPTMvᚌȍfjqseghpotr鹜NJDRUğdᥛz㕖pȌڋAԓ雛_Bߗދȋ\Ί͏ۋwdTezJxŌ`ӌ^HȔXR㎎CPtqKŠ锯閟@Њ|嶝^艔噞J㹊{歒Se顊j舊sFጐdP}gya`fSWmeO]ݑڙ̛ň@`FOP\[gಉGh󓂞Њ~yۉ}qɐ͘V،~ऐc͌bwuxviXÕLꖊGKƏ̓C魜SRД߈Kv֓S哑tݓkLSښ湛誝ᙚٚ]d䡜QIvn跏ʜh\frnzyklmkgcstio݉Bvldjߊgqupm嵚W~[ZB͙GrqʟD䠜j珞iƙd^񔐘\X{Ž\箊IؘrH_j~F׊@EmLGDŊAKJCI䯘Yᷛep՟bNボ錝AQaT㼛㻛fW`c洟a⻝qj鉙ɞ쏁㣎V늬Mϊ䅟jFrȟ綝mlb˙_xpᒔcg⭊|}ۚۊ@يΞ؊󊩐Ҋ@ʊŞ̊ɊƜAL萊ъŠԊ׊ՊĚ^ÊNJ֊͊ϊwxsqPgӊea㞎ʼnؚĝ̎dˉZΓٌq҃斉vqЎx|ۉԊQ|ўh`ܛ嘉]Ǝ؉㟋zɉÈՉʜF荊ЌCa{`ekJm”ޚ썁͉̉ώoז◚DSlόUґݙ͉щݙljӌT旞g~߉惕砌ĉጜƏ戉Č͉ɂEc‹āىqSGBJHxw[`TIr|RKVFO^QU\ZAYzM{Pst}NLvpyu@C]E_~D􄩄~ԃqXWہACFNՋ\ȐߕϐڃJRVZc]\|\_s*[]\|b\_s*[RZNVJ]\|\_s*[q]\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*y\|\_s*m\|\_s*F\|\_s*\|\_s*\|S\_s*\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|\_s*C\|\_s*\|A\_s*\%(r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|p\_s*i\_s*a\_s*l\_s*e\_s*s\)\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|\_s*\|}\_s*\|\_s*@\|O\_s*[ȍ]\|\_s*[ĘU]\|P\_s*y\|\_s*\|\_s*[X]\|~\_s*\|\_s*\|S\_s*[Z]\|\_s*h\|9\_s*[]\|^\_s*{\|Q\_s*O\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*|\|T\_s*\_s*\|T\_s*\|\_s*\_s*\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|Z\_s*\|n\_s*_\|s\_s*q\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|V\_s*\|]\_s*\|f\_s*[l]\|\_s*A\|s\_s*[mE]\|\_s*\|L\_s*a\_s*\%(u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|b\_s*i\_s*a\_s*t\_s*a\_s*e\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|\_s*\|\_s*\|~\_s*\|\_s*t\_s*\|\_s*\|\_s*_\|\_s*Y\|\_s*\|\_s*\|I\_s*\%(s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\)\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|`\_s*\|]\_s*[X]]\|\_s*\%([ƗuʑɎ茓]\|\_s*\|[\_s*\|\_s*\)\|\_s*\%(X\_s*\_s*\|\_s*\_s*\)\|7\_s*\|V\_s*\|\_s*\|4\_s*\|S\_s*[]\|R\_s*{\|\_s*\|h\_s*t\|\_s*[ʈ]\|\_s*\|O\_s*\%(\|\_s*\)\||\_s*[“]\|A\_s*[o]\|\_s*\|B\_s*r\|\_s*[NY]\|\_s*[]\|r\_s*[ꏎ]\|Q\_s*\|\_s*Y\|b\_s*\|c\_s*e\|\_s*\|M\_s*\%(e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|u\_s*s\_s*a\_s*l\_s*e\_s*s\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|S\_s*\%([eg]\|p\_s*e\_s*r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*i\_s*t\_s*a\_s*m\_s*i\_s*n\_s*e\_s*a\_s*e\)\|\_s*\%(\_s*{\_s*\%(I\|\_s*I\)\|\_s*\_s*a\_s*\_s*W\)\|\_s*Z\|\_s*q\|\_s*\|z\_s*\|R\_s*\%(C\_s*o\|\_s*q\|z\_s*\)\|j\_s*\|\_s*\_s*\_s*\|r\_s*C\|b\_s*[]\|\_s*\|}\_s*\|\_s*\%(\|`\_s*\)\|\_s*[]\|\_s*\|V\_s*\%(\|l\_s*\)\|\_s*q\||\_s*\_s*\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*[]\|\_s*r\||\_s*\|\\_s*\|]\_s*\|\_s*q\_s*\|\_s*[ay]\|\_s*\|\_s*\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*R\_s*q\|\_s*\|\_s*\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|o\_s*\%(t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\|d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\)\)\|y\_s*\|A\_s*g\|k\_s*k\|@\_s*\|\_s*t\_s*\|\_s*\%(\|q\_s*\)\|\_s*\|\_s*\|Z\_s*\%(c\|C\_s*\)\|\_s*\|\_s*[r]\|\_s*\%([_]\|C\_s*\|\_s*s\_s*\_s*\_s*w\_s*Z\_s*p\_s*\_s*w\)\|C\_s*[G]\|(\_s*\_s*)\|\_s*\_s*\|\_s*\|\_s*\|m\_s*\%(\|\_s*\)\|~\_s*\_s*\|o\_s*c\|Y\_s*t\|_\_s*o\|\_s*\|B\_s*\|A\_s*\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|\_s*\_s*\_s*\_s*\_s*u\|\_s*\_s*\_s*e\_s*N\_s*m\_s*T\_s*C\_s*G\_s*\_s*X\|\_s*\|X\_s*\_s*[\_s*Y\|\_s*e\|g\_s*\_s*\_s*v\|\_s*[{v菻]\|\_s*G\_s*\_s*\_s*Z\_s*b\_s*g\_s*v\_s*Z\_s*@\|T\_s*\%(\_s*`\_s*[\_s*\|G\_s*\|C\_s*\%(g\_s*J\_s*C\_s*\|\_s*X\|N\_s*\%([]\|\_s*\%(\|b\_s*N\)\)\|{\_s*\%(E\_s*Y\|[\_s*O\)\|o\_s*\%([\|l\_s*e\_s*B\_s*\%(b\_s*N\|N\_s*X\)\)\|\_s*\_s*[\_s*\|_\_s*[\|t\_s*@\_s*[\|l\_s*\_s*A\)\|[\_s*\%(e\_s*B\_s*t\_s*B\_s*P\_s*[\_s*V\_s*\_s*\|N\_s*\|J\_s*\%(X\|\_s*X\_s*N\_s*\%(\_s*C\_s*u\|\_s*v\_s*V\_s*\_s*\)\)\|L\_s*\%(\_s*\%(\_s*[\|\_s*[\_s*\%(^\_s*[\|V\_s*\_s*\)\)\|b\_s*g\)\)\)\|}\_s*h\_s*\_s*X\|\_s*\|P\_s*\%([AC]\|t\_s*F\_s*E\_s*X\|v\_s*X\_s*g\_s*\_s*[]\|`\_s*\_s*b\_s*v\|\_s*\%(^\_s*E\_s*\%(\|\_s*X\)\|u\_s*\_s*b\_s*W\)\|[\_s*\%([LWuvX]\|N\_s*E\_s*H\_s*[\_s*N\|\\_s*\|^\_s*\_s*\_s*O\|p\_s*\%([\|r\_s*\_s*e\_s*B\)\|V\_s*\_s*O\|\_s*[\)\|\_s*\%(g\|x\_s*\_s*X\|e\_s*B\_s*b\_s*N\|r\_s*\%(\|[\_s*j\)\)\|~\_s*\%(J\_s*\|X\_s*g\)\)\|L\_s*\%(\_s*m\_s*\|v\_s*\_s*X\|P\_s*\|\_s*\%([C[A]\|\_s*F\|r\_s*\%(Y\_s*\|X\_s*\)\|\_s*\%(X\|b\_s*g\)\|\_s*[\_s*^\_s*[\|\_s*\\_s*[\|\_s*\%([\|E\_s*\|A\_s*X\|I\_s*V\_s*e\_s*B\)\)\|A\_s*\%(\|[\_s*\|\_s*e\_s*B\)\|`\_s*\|g\_s*T\_s*\|\_s*\|}\_s*C\_s*\|b\_s*J\|\_s*[\_s*g\|\_s*\%([hpXu]\|f\_s*\%(B\|\_s*b\_s*N\)\|r\_s*\%([Al]\|e\_s*\%(B\|[\_s*V\_s*\_s*\)\)\|x\_s*c\|o\_s*\%(\_s*[GA]\|\_s*[\)\|g\_s*\|V\_s*[\|T\_s*\_s*\|^\_s*s\_s*\|s\_s*\%(g\_s*\|^\_s*\%(\|\_s*Y\_s*\)\)\|v\_s*\%(\|V\_s*\_s*\|e\_s*\|`\_s*\)\|Z\_s*\%(C\|\_s*[\_s*\)\|b\_s*\%([cg`v]\|T\_s*o\|X\_s*\|V\_s*\%(\|\_s*O\|\_s*\%([\|u\_s*\)\)\)\|j\_s*\%(I\_s*\|X\_s*^\_s*[\)\|i\_s*\|m\_s*\%(\|[\_s*\|s\_s*[\)\|~\_s*\\_s*[\_s*\|\_s*\%(\|\_s*\%(\|b\_s*g\)\)\|\_s*\%(\|E\_s*F\_s*C\|\_s*\|\_s*C\_s*[i]\|b\_s*g\)\|\_s*b\_s*g\|\_s*\%([R[A]\|o\_s*[\|u\_s*\_s*[\_s*V\_s*\_s*\|b\_s*W\|\_s*O\)\|Y\_s*\)\|\_s*\%(R\|X\_s*g\|V\_s*^\_s*\)\)\|\_s*p\|`\_s*\%([^}A]\|\_s*\|\_s*[\|\_s*h\|\_s*j\_s*[\|R\_s*\|b\_s*\%([vN]\|e\_s*\_s*I\|^\_s*S\_s*\)\|L\_s*\%(\|[\_s*^\)\|\_s*\%(A\_s*u\_s*\|[\_s*C\_s*\_s*K\_s*\)\|[\_s*\%([tgvNY]\|p\_s*[\|^\_s*[\)\|F\_s*\%([XJRA]\|U\_s*\%(\|[\_s*\)\|\_s*\%(j\_s*[\|V\_s*[\|m\_s*u\_s*C\_s*\)\|\_s*\%([\|X\_s*g\|b\_s*V\_s*\|\_s*\)\|\_s*\%(X\_s*^\|\_s*R\_s*t\)\|r\_s*`\_s*F\_s*t\|_\_s*[\|`\_s*F\_s*\|b\_s*\%([gNJ]\|L\_s*\_s*O\)\|C\_s*\%([X]\|j\_s*[\|T\_s*[\|V\_s*\_s*O\)\|[\_s*\%(\|U\_s*\|z\_s*t\)\)\|\_s*\%([IthCRE]\|c\_s*l\|N\_s*\|v\_s*^\_s*[\|p\_s*e\_s*B\|y\_s*\%(\|b\_s*N\)\|`\_s*\|l\_s*\%(\|\_s*[\|\_s*\_s*O\)\|b\_s*\%([Ng]\|s\_s*[\|v\_s*\%(}\_s*\|\_s*\)\)\|^\_s*\%(\_s*[C[]\|\_s*\_s*O\)\|\_s*}\_s*[\_s*X\|\_s*\_s*W\|\_s*\|[\_s*\%([`^gW]\|r\_s*\|~\_s*\%([\|\_s*O\)\|\_s*[\|\_s*\%([YX]\|g\_s*\)\)\|\_s*\_s*S\)\|\_s*\%([R]\|C\_s*X\|\_s*X\_s*L\_s*[\|[\_s*\%(N\|T\_s*[\|J\_s*[\|L\_s*\_s*O\)\|S\_s*\|b\_s*\%(v\|s\_s*[\|p\_s*[\)\|\_s*\\)\)\|\_s*W\|\_s*\|\_s*\|\_s*\%(\|Y\_s*\_s*`\_s*\)\|p\_s*\|C\_s*\%([srdfDeRoa]\|\_s*\|^\_s*\_s*\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(U\|S\_s*(\_s*C\_s*o\_s*n\_s*t\_s*i\_s*n\_s*u\_s*a\_s*t\_s*i\_s*o\_s*n\_s*-\_s*P\_s*a\_s*s\_s*s\_s*i\_s*n\_s*g\_s* \_s*S\_s*t\_s*y\_s*l\_s*e\_s*)\)\|u\_s*r\_s*i\_s*u\_s*m\|M\_s*\%(U\|\\_s*\_s*O\)\|^\_s*C\_s*v\|T\_s*\%(X\_s*L\_s*\_s*\|R\_s*L\_s*L\_s*[\)\|V\_s*F\_s*\|S\_s*\%(V\_s*t\_s*@\_s*C\_s*\|`\_s*\_s*[\_s*i\|A\_s*\_s*e\_s*i\)\|J\_s*b\_s*v\|N\_s*\_s*X\|R\_s*\_s*p\_s*C\_s*\|C\_s*\%(R\_s*(\_s*C\_s*r\_s*e\_s*e\_s*d\_s*e\_s*n\_s*c\_s*e\_s* \_s*C\_s*l\_s*e\_s*a\_s*r\_s*w\_s*a\_s*t\_s*e\_s*r\_s* \_s*R\_s*e\_s*v\_s*i\_s*v\_s*a\_s*l\_s*)\|D\_s*J\_s*\_s*\)\|h\_s*\_s*C\_s*u\|+\_s*+\|L\_s*\%(X\|O\_s*S\|I\_s*S\_s*P\)\|E\_s*S\_s*P\|A\_s*\%(D\|S\_s*[LE]\)\|\_s*\_s*N\|I\_s*S\_s*C\|h\_s*\%(l\_s*o\_s*r\_s*\%(a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\_s*e\)\|r\_s*o\_s*m\_s*i\_s*u\_s*m\|a\_s*S\_s*e\_s*n\)\|O\_s*\%(B\_s*O\_s*L\|N\_s*T\_s*R\_s*O\_s*L\_s*L\_s*[\)\)\|c\_s*\%(@\_s*[\|B\_s*\_s*\|F\_s*\%([\|\_s*j\_s*[\|\_s*\)\)\|Y\_s*f\|b\_s*\%([^]\|l\_s*\\_s*\_s*O\|^\_s*C\_s*v\|J\_s*b\_s*v\|N\_s*\_s*X\|\_s*r\|c\_s*|\_s*q\_s*n\_s*l\|h\_s*\_s*C\_s*u\|{\_s*{\|\_s*\_s*N\|n\_s*2\|\_s*b\_s*\%(\|n\_s*X\_s*g\_s*A\)\|\_s*\)\)', + \ 'd' : '\%([다hbraךǏtBN{cjۓÓ̊ӓՓœǙI~UkNӝ^}X駁́ߓԓӓVW֓W{ޙxgz𗯗Z^mvwˎ~yǎF≓BHDsMϙub\BadƂŃdߐhȍjΓ`snˌg˒ݕtВËl}ϒޘAÃaߗ͒nIL֓|Z睏JNMӋҋxJيړ_xԒ|FڒDEU璒iNՕnm聄Гْ̖U[ghkifcdejǞ񐆘Ǒ䶝\śP֑蚑ʑ[TÞSɚkoĜ팚[Pc˂DACd\.Ecgh\Bƃh_WDf„td]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[hfda_]\|\_s*[ǂłÂ]\|\_s*\|s\_s*X\_s*\|\_s*\|S\_s*a\_s*u\_s*r\_s*u\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|C\_s*\%(u\|o\_s*p\_s*p\_s*e\_s*r\)\|\_s*V\_s*\|\_s*\|@\_s*\|\_s*\|Y\_s*\|S\_s*t\_s*\|\_s*\|\_s*\|\_s*[t]\|\_s*\|\_s*\|\_s*[I]\|\_s*\|m\_s*b\|x\_s*\|\_s*q\|\_s*q\|\_s*\|\_s*K\|\_s*\|\_s*B\|R\_s*\|\_s*\|\_s*k\_s*B\_s*\|\_s*\%([Ɍ]\|\_s*L\|\_s*V\_s*c\|\_s*\%(\|\_s*b\)\)\|T\_s*[B]\|\_s*\|\_s*|\|\_s*\%(\_s*\|\_s*f\_s*[\_s*^\_s*x\_s*[\_s*X\)\|R\_s*\_s*\_s*r\_s*A\|Y\_s*\%(\_s*[\_s*X\|b\_s*N\)\|C\_s*\_s*J\|\_s*\|\_s*m\|\_s*\|s\_s*\_s*\|\_s*\_s*\_s*\|n\_s*[\_s*O\|\_s*\_s*\_s*\_s*\|j\_s*\_s*\%(\|\_s*\)\|\_s*\_s*q\|L\_s*q\_s*q\|c\_s*\%(_\|^\_s*C\_s*v\|h\_s*\_s*C\_s*u\|J\_s*b\_s*v\|b\_s*u\_s*\_s*\_s*h\|\_s*\_s*\_s*\|\_s*\_s*N\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\\_s*i\_s*\|[\_s*b\_s*P\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\|D\_s*\%(b\|^\_s*C\_s*v\|T\_s*\%(E\|P\_s*\\_s*t\_s*g\|M\_s*\\_s*t\_s*g\)\|M\_s*A\|h\_s*\_s*C\_s*u\|J\_s*b\_s*v\|C\_s*\%(J\_s*[\_s*h\|u\_s*\_s*\_s*h\)\|u\_s*b\_s*n\_s*i\_s*u\_s*m\|B\_s*\%(M\_s*S\|T\_s*[\_s*o\)\|H\_s*C\_s*P\_s*\%(T\_s*[\_s*o\|N\_s*\_s*C\_s*A\_s*\_s*g\)\|y\_s*\%(s\_s*p\_s*r\_s*o\_s*s\_s*i\_s*u\_s*m\|l\_s*a\_s*n\)\|r\_s* \_s*P\_s*e\_s*p\_s*p\_s*e\_s*r\|\_s*\_s*N\|V\_s*D\_s*\%({\_s*b\_s*N\_s*X\|V\_s*\_s*b\_s*v\|P\_s*[\_s*X\|f\_s*b\_s*L\|h\_s*\_s*C\_s*u\|I\_s*[\_s*f\_s*B\_s*I\|v\_s*\_s*\%([\_s*\_s*[\|C\_s*\_s*[\)\|\_s*b\_s*N\|\_s*R\_s*[\_s*_\_s*[\|}\_s*\_s*`\|r\_s*f\_s*I\)\|O\_s*S\|o\_s*\%(c\_s*u\_s*m\_s*e\_s*n\_s*t\_s* \_s*\%(T\_s*y\_s*p\_s*e\_s* \_s*D\_s*e\_s*f\_s*i\_s*n\_s*i\_s*t\_s*i\_s*o\_s*n\|O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*o\_s*d\_s*e\_s*l\)\|C\_s*o\_s*M\_s*o\)\|e\_s*\%(g\_s*e\_s*n\_s*e\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|l\_s*a\_s*w\_s*a\_s*r\_s*e\)\|E\_s*\%(C\|L\_s*L\_s*[\)\|I\_s*\%(P\_s*X\_s*C\_s*b\_s*`\|S\_s*K\)\|i\_s*\%(r\_s*e\_s*c\_s*t\_s* \_s*M\_s*e\_s*m\_s*o\_s*r\_s*y\_s* \_s*A\_s*c\_s*c\_s*e\_s*s\_s*s\|s\_s*t\_s*r\_s*i\_s*c\_s*t\_s* \_s*o\_s*f\_s* \_s*C\_s*o\_s*l\_s*u\_s*m\_s*b\_s*i\_s*a\|g\_s*i\_s*t\_s*a\_s*l\)\)\)', + \ 'e' : '\%([ኙPGҋ`ܐݑ傉滌ӏ^ΛxVx{y󔌜▒厝t㈉z郉uՉvwtd_Qঢ়oH̟џHv鴉䆉`腖b膞Ł܉⥟}|叉͉lU~oIoktȚz瞱i͉joĉblgsdm繉erfhnciʉqG``}]㉈Όdl˘da|bΉdIÚ߁QM}NpΎIńR|L^ÄGe]\|A\_s*\%([ʔ^]\|V\_s*\%(@\_s*\|\_s*D\)\|B\_s*\%(^\|C\_s*\)\)\|`\_s*\%([ʔ^]\|u\_s*\%(@\_s*\|\_s*D\)\|a\_s*^\)\|\_s*\%(\|\_s*\)\|O\_s*\_s*\|M\_s*T\_s*C\_s*Y\|l\_s*T\_s*C\_s*Y\|G\_s*X\_s*q\|\_s*\|g\_s*\|E\_s*\|\_s*\_s*q\|\_s*y\|\_s*x\|\_s*H\|x\_s*\|\_s*[s]\|\_s*\|g\_s*q\|k\_s*\%(T\_s*C\_s*Y\|k\_s*T\_s*C\_s*Y\)\|L\_s*\%(T\_s*C\_s*Y\|L\_s*\%(T\_s*C\_s*Y\|\_s*\)\)\|\_s*\%([仕Q]\|m\_s*\)\|N\_s*\| \_s*n\_s* \_s*p\_s*`\|m\_s*\%([‹ɋ]\|\_s*\|g\_s*j\_s*z\_s*[\_s*\)\|\_s*\|Z\_s*\|\_s*X\_s*r\_s*[\_s*H\_s*i\|r\_s*\%([gȋ]\|T\_s*C\_s*Y\|m\_s*\|e\_s*\_s*\)\|S\_s*\%([]\|T\_s*C\_s*Y\|N\_s*\|F\_s*\_s*\)\|q\_s*[y]\|X\_s*\%([r]\|O\_s*\|\_s*F\_s*\)\|w\_s*\%([r]\|\_s*F\_s*\)\|A\_s*\|\_s*\|C\_s*\%(l\|h\_s*l\_s*o\_s*r\_s*i\_s*n\_s*e\)\|C\_s*\%(V\|W\_s*\)\|\_s*s\_s*\_s*\_s*x\_s*\_s*\_s*c\_s*c\|\_s*[\_s*N\_s*X\_s*e\_s*[\_s*V\_s*\_s*\|\_s*\%(B\|\_s*b\)\|^\_s*\%(B\|\_s*b\)\|\_s*[\_s*\_s*\%(s\_s*A\_s*\|b\_s*p\)\|\_s*\%(A\_s*\|E\_s*\_s*s\_s*E\_s*\|\_s*C\_s*J\|[\_s*\%(\|m\_s*X\|j\_s*X\|W\_s*\%(\|[\_s*\)\|h\_s*\|\_s*J\|\_s*\%(X\|V\_s*A\)\|t\_s*\%(\_s*e\_s*X\|H\_s*\%(\_s*A\|j\_s*A\_s*\)\)\|N\_s*\_s*b\_s*h\|J\_s*\)\)\|\_s*W\|\_s*\|d\_s*q\_s*\_s*\%(C\_s*\|[\_s*\)\|\_s*W\|]\_s*\_s*\_s*\|\_s*\_s*\|S\_s*\_s*\_s*T\|J\_s*v\_s*Z\_s*\_s*\|I\_s*\%([\|C\_s*\%(\_s*[\|Q\_s*\)\)\|\_s*s\|g\_s*\|\_s*O\|\_s*Q\_s*\|d\_s*\%(o\_s*n\|h\_s*\_s*C\_s*u\|c\_s*x\_s*[\_s*^\|\_s*\_s*\_s*\|J\_s*b\_s*v\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|^\_s*C\_s*v\)\|A\_s*\%([C]\|j\_s*h\|[\_s*\%([}X]\|E\_s*B\_s*\|\_s*\|j\_s*[\|l\_s*X\_s*g\|~\_s*\|V\_s*[\|\_s*[\)\)\|\_s*\|E\_s*\%(r\|O\_s*F\|u\_s*\%(p\_s*o\_s*m\_s*a\_s*t\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|r\_s*o\_s*p\_s*i\_s*u\_s*m\)\|U\_s*C\_s*R\_s*[\_s*h\|P\_s*\_s*R\_s*[\_s*h\|h\_s*\_s*C\_s*u\|d\_s*i\_s*t\_s*i\_s*n\_s*g\_s* \_s*M\_s*A\_s*C\_s*r\_s*o\_s*S\|\_s*[\_s*\|-\_s*m\_s*a\_s*i\_s*l\|J\_s*b\_s*v\|R\_s*}\_s*[\_s*X\|N\_s*T\_s*E\_s*R\_s*L\_s*[\|^\_s*C\_s*v\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\|S\_s*\%(P\|C\_s*L\_s*[\)\|l\_s*k\|m\_s*a\_s*c\_s*s\)\|C\_s*\%([uA[]\|W\_s*F\_s*N\_s*g\|t\_s*F\_s*N\_s*[g^]\|R\_s*\%([\_s*\|\_s*C\_s*[YU]\)\|v\_s*V\_s*\_s*\|~\_s*\_s*\_s*\%([\_s*[g^]\|C\_s*^\)\|x\_s*\_s*\%(g\|^\_s*[\)\|m\_s*b\_s*N\|l\_s*[\_s*u\_s*\|M\_s*\_s*X\|\_s*O\_s*\%(\_s*\_s*h\|\_s*b\_s*V\_s*\)\|b\_s*`\|\_s*\%([\|\_s*\_s*O\|t\_s*H\_s*\|z\_s*\)\|O\_s*W\_s*\%(b\_s*g\|X\_s*g\)\|N\_s*\%(X\|A\_s*\_s*e\_s*B\)\|X\_s*t\_s*@\_s*n\_s*\|\_s*[A]\|\_s*\%([\_s*\%(X\|U\_s*[\|T\_s*[\)\|C\_s*\%(\|U\_s*[\|T\_s*[\)\|u\_s*\)\)\|E\_s*\%([\|W\_s*F\_s*[\_s*k\)\)', + \ 'f' : '\%([[ΉM֓~y`[脟T͈j͊ȎD^J㬐䔕bXʙ앶|tyMD⁃៻᳍ĘWoK敖lᆕp̐k⿕谌ꄜPi霝c񕥕huCcޔX܊ܕtewtXsb•z|ޘwt]АU㧘Vo\vؕH~[nDҕByGzot{ܕݍ~DYu@缕S䘔Y}䎙ʖ|ӂŚx܋ŕU󕤕FUӄtf]\|\_s*\|b\_s*t\|\_s*\|\_s*\|A\_s*X\|\_s*\|\_s*\|E\_s*u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\_s*\|\_s*i\|}\_s*\_s*\|C\_s*f\|\_s*\%(C\|\_s*[]\)\|_\_s*\|\_s*C\|\_s*\|\_s*\|\_s*\|\_s*~\|\_s*c\|M\_s*y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*[R]\|\_s*t\|B\_s*u\_s*d\_s*d\_s*l\_s*e\_s*j\_s*a\_s*c\_s*e\_s*a\_s*e\|k\_s*\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|Q\_s*[l“]\|h\_s*\|2\_s*\%([l“]\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|~\_s*~\_s*~\|\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*o\|I\_s*r\_s*o\_s*n\|\_s*\_s*\_s*\|_\_s*\_s*\|`\_s*\|z\_s*\%(\_s*C\_s*G\|C\_s*\|\_s*\%(}\_s*\%(\_s*g\|\_s*\)\|\_s*A\_s*\%(~\_s*h\|\_s*f\_s*q\_s*h\)\)\)\|\_s*t\|\_s*\|@\_s*\\|\_s*\_s*\|C\_s*\|q\_s*\%(\|\_s*[\_s*[Y]\)\|P\_s*\%(^\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*1\_s*v\_s*f\|\_s*s\|n\_s*\%(G\|\_s*u\_s*\|\_s*\)\|_\_s*\_s*\|e\_s*\%(P\|J\_s*b\_s*v\|^\_s*C\_s*v\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\_s*\)\|\_s*g\_s*\|G\_s*t\)', + \ 'g' : '\%([EDĉ愍܍ΌᘭՖ@W龚oXߔ쐺nS΍ᴊrc穚ꇟ|ߍ@ᛈ䲎ތTɌ党I⺌Ɍw5ݒܝzqxZߟ驌Q|k⚔nj}~|YꖚPÊqFῌVȌRZĂC푐򕳕ȍIqƑ䣌΋X{j㸌SQRԋHFٕOh[g炮ߌNۋًҚ⚝f耋ʋꟋČCz邙F‹ƋŋÍsኋstC`UZ؋Wً]bXV^E㺙Eaa[cV~؞Fซ\E鰋_Y雎_Wd᥍mAԐ݊v瑤ʊŌ꓁^`eq寊IP}djkhG_~팵ћǘݙʊہ꜋܊ߌ猎怞ْ՚罛|{Ӝԙkzx{ywGUN᳜ȟ򛻈RPn᫊YPKw䈊HVQZSXMTW[O㛴䃖Abϊ|M`PGؙމʉ딃a͉䮏ɉ惕ꏟ@⁄KSԃ҃ăσǃӃуɃ̓˃Ճփƒ΃ÃЃƃŃȃ̃ʃMOQsCg]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[SQOMK]\|\_s*[]\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*~\|\_s*\|\_s*y\|P\_s*e\_s*r\_s*s\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*s\_s*\|\_s*q\|H\_s*\|\_s*\|\_s*\_s*\|~\_s*\|i\_s*\%([ԉ]\|V\_s*\)\|P\_s*\_s*\|]\_s*\%([ÌΏB]\|k\_s*\)\|\_s*[`]\|\_s*\|w\_s*\|i\_s*F\|\_s*\|\_s*\|m\_s*\|\_s*\|\_s*[]\|\_s*[ō]\|\_s*\|\_s*E\|\_s*\|~\_s*\_s*\_s*F\|H\_s*\|\_s*[Սi]\|g\_s*@\|\_s*\|{\_s*\|\_s*\%([알]\|Z\_s*\)\|\_s*\%([@]\|s\_s*\_s*\|\_s*\_s*@\)\|A\_s*g\|S\_s*\%(c\_s*r\_s*o\_s*p\_s*h\_s*u\_s*l\_s*a\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*m\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|i\_s*l\_s*v\_s*e\_s*r\)\|\_s*c\|\_s*\_s*J\|\_s*t\|L\_s*q\|Y\_s*\|\_s*\|\_s*\|T\_s*y\_s*p\_s*a\_s*l\_s*e\_s*s\|\_s*[]\|\_s*\_s*\|\_s*\|\_s*q\|\_s*^\|b\_s*\|\_s*\|k\_s*[\|f\_s*\%(n\_s*q\_s*n\|a\_s*\_s*\_s*\|\_s*\|J\_s*b\_s*v\|^\_s*C\_s*v\|X\_s*|\_s*b\_s*g\|p\_s*\|\_s*\_s*\)\|j\_s*\_s*[\_s*Y\|m\_s*[\_s*\|\_s*i\_s*\_s*\|A\_s*\_s*\_s*R\_s*\_s*i\_s*\_s*\|q\_s*\|N\_s*b\_s*p\|\_s*q\|n\_s*{\_s*\_s*[\_s*l\|\_s*\|G\_s*[\_s*e\_s*{\_s*\|\_s*[\_s*e\_s*{\_s*\|C\_s*F\_s*\%([\_s*e\_s*{\_s*\|e\_s*{\_s*\)\|\_s*\|G\_s*\%([dae]\|o\_s*m\_s*o\_s*r\_s*t\_s*e\_s*g\_s*a\_s*c\_s*e\_s*a\_s*e\|M\_s*\%(T\|D\_s*(\_s*G\_s*e\_s*r\_s*m\_s*a\_s*n\_s* \_s*N\_s*a\_s*t\_s*i\_s*o\_s*n\_s*a\_s*l\_s* \_s*R\_s*e\_s*s\_s*e\_s*a\_s*r\_s*c\_s*h\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\_s* \_s*f\_s*o\_s*r\_s* \_s*C\_s*o\_s*m\_s*p\_s*u\_s*t\_s*e\_s*r\_s* \_s*S\_s*c\_s*i\_s*e\_s*n\_s*c\_s*e\_s*)\)\|\_s*\|C\_s*L\|c\_s*c\|J\_s*b\_s*v\|^\_s*C\_s*v\|X\_s*|\_s*b\_s*g\|p\_s*\|P\_s*L\|n\_s*u\_s*s\|I\_s*\%(N\_s*A\_s*(\_s*t\_s*h\_s*e\_s* \_s*G\_s*e\_s*n\_s*e\_s*r\_s*i\_s*c\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*t\_s*i\_s*v\_s*e\_s* \_s*A\_s*p\_s*p\_s*l\_s*i\_s*c\_s*a\_s*t\_s*i\_s*o\_s*n\_s*)\|F\_s*\%(t\_s*@\_s*C\_s*\|A\_s*j\_s*\)\)\|U\_s*I\|N\_s*U\|O\_s*T\_s*C\_s*\|E\_s*T\_s*\_s*\\_s*b\_s*h\)\|w\_s*\%(\_s*\_s*h\|\_s*}\_s*\)\|h\_s*C\_s*c\|\_s*g\_s*v\_s*\|[\_s*\%(\_s*\%(`\_s*\|j\_s*E\_s*\)\|\_s*N\_s*\_s*b\_s*v\|m\_s*A\|\_s*g\_s*\_s*}\_s*\|l\_s*\%(R\_s*\|\_s*\%(\|\_s*X\_s*g\)\)\)\|\_s*\%(\|w\_s*@\_s*\)\|W\_s*\%([WOmiI[]\|v\_s*V\_s*[\|A\_s*\|C\_s*h\|b\_s*h\|^\_s*\|[\_s*\|\_s*A\_s*\|\_s*b\_s*g\|S\_s*\|\_s*\%(t\|\_s*\%(h\|f\_s*B\_s*[\_s*m\)\)\|\_s*\%([\|\_s*h\)\|o\_s*\_s*V\_s*[\|u\_s*\%(\|\_s*\_s*^\_s*\)\|x\_s*\%(\_s*i\_s*E\|\_s*\_s*\)\|l\_s*b\_s*g\|\_s*\%(b\_s*g\|\_s*@\_s*\_s*[ji]\|o\_s*\_s*[ji]\|R\_s*\%([\_s*\\|\_s*_\)\|\_s*\%(W\|_\_s*[\_s*m\)\|[\_s*\%(W\|[\_s*b\_s*g\)\)\|\_s*\%(\|C\_s*\%(\|\_s*Y\|A\_s*\_s*[cg]\)\|R\_s*\%(\|\_s*b\_s*e\_s*B\)\|[\_s*}\_s*\)\|j\_s*[\|\_s*\%([l]\|[\_s*b\_s*y\|\_s*\%(A\|[\_s*j\|G\_s*b\_s*^\)\|k\_s*\%(\_s*B\_s*G\_s*[\_s*\|r\_s*G\_s*[\_s*u\)\)\|F\_s*\%([t}l]\|X\_s*`\_s*\_s*[\|\_s*j\_s*\|\_s*\%([\_s*[gh]\|\_s*\%(h\|f\_s*B\_s*\|_\_s*C\_s*\)\)\|~\_s*j\|j\_s*[\|m\_s*\%([Ao]\|\_s*@\|\_s*[\_s*Y\|T\_s*C\_s*h\)\|\_s*\%(}\|g\_s*\%(\|\_s*[B[]\)\|_\_s*[\)\)\)\)', + \ 'h' : '\%([Η䀞LN{wʔMܖSŖyj壌uׁ󜓏c]Kg֚\✖{xjcəᬖpW_I•qNuYږQ}䚑N闈{BPaHKAOfDG̜dMOEvLC󝻝eMіkM~O۝eY_@ꅜƕnܒ䐤s̕JK療͌zu`œLKHQQɕE憕wǝ́ݕՕxҝG⍖ݛQayْ؛i͕Ûz˕rǕ•wӗˌ粂̞[Ή։A~y`[脟TǏ͈͊ȎD^J㬐䔕bX䎟앶|tyMD⁄៻᳘WoBK敖lᆕp̐k⿕谌ꄜi霘ŕFӋhuⷁޔX܊ܕtewtXsb•|ޘwt]АU㧕o\vؕH~[nҕByGzot{ܕݍ~DYu@缕SxY}V_~QPcݕAS鯝ۏGG哘ǝ|ጄՉ颕Eh_jkl㏟qoĕnpmgi׋ʕfgRʒIJ@Pv尗zh啸Ǐd֐ċϏdΒPՓƑml1PuഁH͏ݝfە\PFЍt鷑MJ焕SАZOznIQT䊌QP㟋qWjGEgϏEShꤊmOG[T_ALѕNDJLCȊlJC捍rMKu蹕UH~q镕VIgjG^Y~Z֙d[ߕ]W\{_uyiw]DgKΓ唛E࿙`ݔߔBეBɞw혡鏊]X翔枈O澊|瀔OʎzjHԌ㔈墏Ȑ[OXJyّj}݋Еoޝ؏՛ދ@@Tmה喗IjYDscPĔJ`e]똟ƈnnG|FɐꡗIzyt妝ppSǗ|杙br@؉瞖zdXxX򒌑\➁^⦔鼏Rx펾њ虊MߍϔAǝ唏Rdʌv}є`ڔ񏉘o@WIᢔ@輔u̝ڛuvi`ғt\ECpBᓔxoޔywWprqsDzW֞N崔Νםa⛔JÍ➷^䗖}ፖ|YK唺Ϟ͔ٔ㆔הєŔǍʔƔɔ̔ĔД_lfHǒpțfՔb▗t攇jƞPJcyUhHʔef蘒[঎cΜ͔mƜꏐndډhޑ|\㵐i͂g]tqzwnh]\|\_s*[]\|b\_s*[zwtqn]\|\_s*[قւӂЂ]\|\_s*\|q\_s*K\|\_s*\|\_s*\|m\_s*[FC]\|\_s*}\|\_s*[ΐ]\|\_s*{\|S\_s*\|_\_s*\|p\_s*K\|\_s*\_s*F\|g\_s*[]\|T\_s*r\_s*i\_s*u\_s*r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*@\|a\_s*\|\_s*q\||\_s*\%(\\|\_s*\)\|\_s*\|\_s*q\|\_s*\|\_s*\|\_s*Z\|\_s*\|c\_s*l\_s*a\_s*u\_s*s\_s*t\_s*r\_s*o\_s*p\_s*h\_s*o\_s*b\_s*i\_s*a\|\_s*\|\_s*\|\_s*\|E\_s*\%(r\_s*i\_s*o\_s*c\_s*a\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\|u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\%(\_s*\|\_s*\)\|\_s*i\|\_s*C\|\_s*\|\_s*\|\_s*\|\_s*~\|f\_s*\%(o\_s*r\_s*t\_s*e\|e\_s*m\_s*t\_s*o\)\|\_s*[R]\|\_s*t\|k\_s*\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|h\_s*\|\_s*\_s*\|~\_s*~\_s*~\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\|]\_s*c\_s*\|\_s*\|\_s*I\|\_s*\|\_s*\_s*\|\_s*@\|_\_s*[]\|I\_s*\|\_s*\|i\_s*a\|\_s*\|\_s*\%([lo]\|\_s*o\_s*\)\|\_s*\|\_s*\|f\_s*\|\_s*V\_s*q\|_\_s*[]\|\_s*l\|\_s*[ƁX]\|\_s*\_s*\%(\|\_s*\)\|A\_s*\%(s\|r\_s*s\_s*e\_s*n\_s*i\_s*c\|n\_s*g\_s*i\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\|\_s*f\_s*]\|\_s*\_s*\|\_s*[c]\|\_s*\|\_s*[B]\|\_s*\|\_s*\_s*\|h\_s*\|K\_s*W\|\_s*[js]\|e\_s*\|W\_s*\|\_s*q\|\_s*q\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|n\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|`\_s*\|\_s*\|N\_s*e\_s*l\_s*u\_s*m\_s*b\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|o\_s*\_s*|\|\_s*E\|\_s*\|\_s*[]\|y\_s*[t]\|q\_s*[fC]\|\_s*t\|\_s*\_s*l\|\_s*\|x\_s*q\|\_s*J\|\_s*\_s*\|Z\_s*\|\_s*\|\_s*]\|K\_s*[q]\|{\_s*\%(\_s*\|\_s*\)\|E\_s*[l]\|\_s*s\|w\_s*\|2\_s*\%([l“]\|\_s*\|0\_s*\)\|Q\_s*\%([l“]\|O\_s*[Γ]\)\|W\_s*|\|8\_s*\|q\_s*\|P\_s*\%(t\|o\_s*t\_s*a\_s*m\_s*o\_s*g\_s*e\_s*t\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*t\_s*i\_s*n\_s*u\_s*m\)\|C\_s*\%([if]\|\_s*\_s*\|f\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|R\_s*S\_s*I\|M\_s*\%(y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*c\_s*u\_s*r\_s*y\)\|F\_s*\|\_s*a\_s*_\_s*\|E\_s*[\_s*S\|\_s*\%([\|y\_s*[\_s*\|x\_s*[\_s*\|C\_s*X\_s*}\_s*\_s*X\|S\_s*[\|O\_s*m\_s*[\|}\_s*j\_s*\%(e\|X\_s*[g]\)\)\|\_s*\|\\_s*Z\_s*i\_s*\|\_s*\|\_s*`\|C\_s*\%(_\_s*\_s*S\|X\_s*p\_s*j\_s*A\|\_s*[\_s*\|G\_s*\)\|g\_s*\%(\|J\_s*b\_s*v\|\_s*\_s*\_s*\_s*\|\_s*\%(W\|a\_s*\_s*\_s*\)\)\|I\_s*\%([[]\|i\_s*[\|m\_s*\|\_s*t\_s*\_s*[\_s*\|l\_s*\%(X\_s*\%(g\|e\_s*B\)\|Q\_s*\)\|e\_s*\|\_s*K\_s*[\|}\_s*[\_s*W\_s*\)\|A\_s*\%(\_s*\%(\|x\_s*[\_s*\)\|l\_s*X\_s*g\|\_s*[\|_\_s*}\_s*[\_s*\|V\_s*F\_s*b\_s*g\|r\_s*^\_s*V\_s*I\_s*\|[\_s*\%(l\_s*X\_s*g\|m\_s*\_s*N\_s*[\_s*\)\)\|G\_s*\%(f\_s*B\|\_s*\_s*P\|\_s*\%(i\|[\_s*k\)\|\_s*C\_s*[\_s*Y\|N\_s*g\_s*\|\_s*\%(Q\_s*\|\_s*F\|\_s*X\|}\_s*\|~\_s*\%(b\_s*g\|[\_s*g\)\|u\_s*\_s*\|i\_s*\_s*f\_s*X\|L\_s*\_s*[\_s*\)\|m\_s*N\|b\_s*`\|C\_s*`\)\|H\_s*\%([fsPeo]\|i\_s*m\_s*a\_s*n\_s*t\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|J\_s*b\_s*v\|T\_s*\%(M\_s*L\_s*t\_s*@\_s*C\_s*\|T\_s*P\_s*T\_s*[\_s*o\)\|D\_s*D\_s*\_s*R\_s*[\_s*_\_s*[\|u\_s*r\_s*d\|a\_s*\%(s\_s*s\_s*i\_s*u\_s*m\|f\_s*n\_s*i\_s*u\_s*m\|w\_s*a\_s*i\_s*i\)\|y\_s*\%(p\_s*e\_s*r\_s* \_s*T\_s*e\_s*x\_s*t\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|d\_s*\%(n\_s*o\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|r\_s*\%(a\_s*s\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|o\_s*\%(s\_s*t\_s*a\_s*c\_s*h\_s*y\_s*d\_s*a\_s*l\_s*e\_s*s\|g\_s*e\_s*n\)\)\)\)\)\|\_s*[╽f]\)', + \ 'i' : '\%([ʼn~ꍘcUTn翔䑌폒恍ݍrxÉj囚|dQU|軗ƑBd{佈S\嫉䆍mnؐFAtF泌ÌމLdƜјJiꌒՕakvɔžo֌yME|ځe퐈M臐YOΖZ}xא򌵉MՁO䗚P{b~N}zcct硉Ɏ䕟JsW]bK\Tฐ]rmПȈZԈTMΚÉCm覉@uBAAޛjHوΊֈYÈ1PDyIDR۔џʈዏHƍ֋Uhwψ͉]}ubv]Ό≝gМ@ES盈BΟݑPR҈ȊՉUגߛߘߛږˆ̈،܈Η͜}Ėˈԍs਒_ˑޗǓo֗DK~䏈ӈۈ؈ًїeXJzˁɂD聿hCIDŽyi]\|E\_s*\_s*[\_s*\|a\_s*\|J\_s*u\_s*n\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*R\|c\_s*J\|\_s*\_s*\|c\_s*\|G\_s*s\|\\_s*Z\_s*\|Q\_s*q\|G\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*G\|\_s*\|\_s*t\_s*\|5\_s*[“]\|T\_s*[“]\|\_s*E\|r\_s*U\|\_s*\|\_s*Y\|\_s*[\|\_s*\|~\_s*\|\_s*\_s*\|{\_s*\|o\_s*\|\_s*g\|Y\_s*[q]\|h\_s*[‘]\|@\_s*\|U\_s*r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|E\_s*[cR]\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|a\_s*\|d\_s*\%(`\_s*r\_s*s\|u\_s*d\)\|C\_s*\|w\_s*h\|\_s*\|]\_s*[oZ]\|\_s*\|K\_s*{\|\_s*q\|_\_s*\|\_s*\_s*\|\_s*r\_s*\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|\_s*\|r\_s*\|s\_s*\_s*\|o\_s*[E]\|\_s*[Wk]\|C\_s*[؎Q]\|\_s*\\|\_s*\_s*[ΒY]\|_\_s*F\|e\_s*\|p\_s*\%(\|g\_s*\)\|\_s*\_s*\|\_s*\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|\_s*[]\|<\_s*=\_s*=\_s*>\|K\_s*v\_s*\\_s*\_s*\_s*\|\_s*\|\_s*{\_s*A\_s*C\_s*E\_s*r\_s*[\_s*E\_s*G\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\_s*w\|W\_s*\_s*\_s*@\_s*\\)\|t\_s*\_s*U\_s*t\_s*[\_s*\_s*G\_s*\_s*\|\_s*\_s*q\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*^\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|A\_s*[\_s*@\|\_s*\_s*\|s\_s*\%([”@]\|[\_s*\)\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*S\|\_s*\%(A\_s*\|V\_s*t\|[\_s*h\|E\_s*f\)\|I\_s*\%([rPn]\|R\_s*Q\|J\_s*b\_s*v\|C\_s*\%(^\_s*O\|`\_s*b\_s*v\|J\_s*[\_s*h\)\|l\_s*l\_s*i\_s*n\_s*o\_s*i\_s*s\|S\_s*\%(O\|B\_s*N\_s*\%(\_s*\|R\_s*[\_s*h\)\|A\_s*o\_s*X\)\|d\_s*a\_s*h\_s*o\|D\_s*\%(J\_s*[\_s*h\|E\_s*\%(h\_s*\_s*C\_s*u\|f\_s*o\_s*C\_s*X\|P\_s*[\_s*u\_s*\|R\_s*\_s*g\_s*\_s*[\_s*\)\)\|^\_s*[\_s*\|T\_s*\%(V\_s*X\_s*e\_s*\|o\_s*u\_s*\)\|o\_s*\%(w\_s*a\|d\_s*i\_s*n\_s*e\)\)\|A\_s*\%(C\|[\_s*\%(\_s*B\_s*\|r\_s*\)\|\_s*\%(v\_s*\_s*\_s*v\_s*\%(`\_s*\|e\_s*\)\|f\_s*p\_s*\_s*_\_s*\|t\_s*H\_s*\_s*\%(\_s*\|}\_s*e\_s*B\_s*[\_s*N\)\)\)\)', + \ 'j' : '\%([󓈎ȓǎwxHÛKHԘᶙbiu@vސnՉ`rxosqwptlŏғ䴞`䥝募tJ珊RPԟiUㅏ{o媝mh鈐YtY竐jg@Ïꏗ`~]吷꞊󝵏GAژhGQ榜휵@uQxhmnpqmm⢙Ï|⡓՟~[x{䤏zy}}汎GEsn𘸏^F_`Oca_Y[b]\Zedm莣^y~iJ玎Ȓn􎤎~ImVkqHjaZd䢎mݝ苎Ҏ׋YlDuE`_vFJWzj]\|\_s*\_s*\|b\_s*W\|\_s*\|G\_s*\%(\_s*\|p\_s*\)\|Z\_s*\%(r\|i\_s*r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\)\|D\_s*y\|f\_s*\%(\_s*\|p\_s*\)\|x\_s*x\|\_s*\|c\_s*\_s*\%(\_s*\|c\_s*\)\|Q\_s*\|2\_s*\|\_s*q\|b\_s*\_s*\_s*\_s*\_s*\_s*M\_s*h\_s*p\_s*\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|[\_s*\%(\|\_s*\)\|`\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|R\_s*l\|y\_s*_\|\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*r\_s*\|\_s*v\|\_s*\|\_s*\|\_s*\|\_s*[@S]\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*q\|\_s*\|P\_s*\%(Q\|O\_s*[i]\|P\_s*\|U\_s*i\|W\_s*\)\|t\_s*\|\_s*\|R\_s*\|1\_s*\%(0\|1\_s*\|8\_s*\|2\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|O\_s*\_s*\|\_s*\|G\_s*\|\_s*\|\_s*q\|\_s*\_s*\_s*\_s*\|[\_s*\_s*[\|G\_s*\%(z\_s*o\|\_s*R\|\_s*~\_s*\|\_s*T\_s*\_s*\|b\_s*T\_s*C\)\|w\_s*\%(\_s*X\|X\_s*X\)\|q\_s*\_s*l\_s*X\|`\_s*Q\|k\_s*\_s*\_s*[\_s*\%(\|\_s*w\_s*Z\_s*p\_s*\_s*w\_s*@\_s*\_s*w\)\|n\_s*\%(C\_s*\|\_s*y\_s*[\_s*j\_s*\)\|\_s*\|\_s*\%([ji[]\|C\_s*\|G\_s*\|\_s*m\|\_s*h\|k\_s*\%(X\|V\_s*\)\|X\_s*p\_s*[\_s*X\|R\_s*[ru]\|b\_s*P\)\|t\_s*\%(@\_s*[i]\|\_s*[IA]\)\|J\_s*\%(R\_s*\_s*\_s*{\|\.\_s*S\_s*\.\_s*\%(o\_s*b\_s*n\|B\_s*a\_s*c\_s*h\)\|\_s*[\_s*O\|J\_s*b\_s*v\|C\_s*B\_s*J\_s*[\_s*h\|-\_s*P\_s*O\_s*P\||\_s*b\_s*v\|P\_s*\%(G\_s*t\_s*@\_s*C\_s*\|E\_s*G\_s*t\_s*@\_s*C\_s*\)\|I\_s*S\_s*\%(}\_s*[\_s*N\|R\_s*[\_s*h\)\|a\_s*p\_s*a\_s*n\_s* \_s*A\_s*d\_s*v\_s*a\_s*n\_s*c\_s*e\_s*d\_s* \_s*I\_s*n\_s*s\_s*t\_s*i\_s*t\_s*u\_s*t\_s*e\_s* \_s*o\_s*f\_s* \_s*S\_s*c\_s*i\_s*e\_s*n\_s*c\_s*e\_s* \_s*a\_s*n\_s*d\_s* \_s*T\_s*e\_s*c\_s*h\_s*n\_s*o\_s*l\_s*o\_s*g\_s*y\|A\_s*\%(I\_s*S\_s*T\|N\_s*R\_s*[\_s*h\|V\_s*A\_s*\%(X\_s*N\_s*\_s*v\_s*g\|A\_s*v\_s*\_s*b\_s*g\)\)\|U\_s*N\_s*E\_s*T\)\|Y\_s*{\_s*\|i\_s*\%(Q\||\_s*v\_s*`\_s*u\_s*d\|\_s*[\_s*O\|J\_s*b\_s*v\||\_s*b\_s*v\|h\_s*b\_s*b\_s*o\_s*\|t\_s*\%(r\|m\_s*j\_s*n\)\|\_s*\)\|\_s*\%([n_m]\|\_s*Q\_s*\|[\_s*\%([m]\|Q\_s*\_s*g\|f\_s*B\_s*b\_s*g\)\|\_s*\%(O\|J\_s*[\|P\_s*\)\|s\_s*e\_s*\|b\_s*[JV]\)\|C\_s*\%(G\_s*\%([iX]\|\_s*\%(X\|Z\_s*\)\|Y\_s*X\)\|F\_s*\%(i\|\_s*\%(X\|Z\_s*\|[\_s*\)\|[\_s*K\_s*[\|\_s*\%(N\|T\_s*\_s*\)\)\)\|z\_s*\%([^Z]\|\_s*w\|z\_s*o\|A\_s*\%(\|L\_s*\)\)\|\_s*\%([ui]\|\_s*\%(O\|_\_s*\)\|G\_s*\|A\_s*\%(q\_s*\|L\_s*\)\|[\_s*t\|[\_s*\%([gh]\|f\_s*\|[\_s*t\)\|V\_s*\%(t\|\_s*A\)\|Z\_s*t\|n\_s*[il]\)\)', + \ 'k' : '\%([a|єVҜDޏnsߐE}ĈۗⵘᶎsЌfꎖIzEꑍC欉䓚䢐ৎuS}Y┍ɗ`nXMȍ뜝k卭ӍeWEQLm՘i՝Qf肝Kਗ਼Ჟ騟}{㝛ҟL`tiBRH{ൟHs秝nn˝JܔXLJyߛbM褜rRt莘mjE硍hklKᦜnK}֞\囍yෙΜˍxuXSe倘Ji^V@AWGDT`ᩍBԍp]iPIzt_KkOjRwUuPaI|qsmrcDޞJܛwL΍WێЛZÖs烌gםsؑeⰏuČٌ̟]|Vx֒绌я嚙hʉzqnjԌך➳ҔÏ˗Zꉟh@Zes|qWO׏b]{ȌtӘnKPB^_[rK{CՙLٜšw_J]p[iNJyʌ㮛ӌ@ęF鄌Ō|wZDờlc⠞fa犌l_Ϝlg۝kڙ㋜dPnrz壌u殌ek\gbYp]v[RقƔzɟKMzⱟJ㖍򍥛IHEzboxܗADBӏ~B䱌sZY㙬ᯞӛMֈϏvLK@{^Z򏾓^鶔ňʈUÑqC~ܒwo^鿌~GF䇚`p̏LYƌIގԚPMEu{OoӞcHE|―ĜῙ܌JɍCgm؍HᜁvgM˙iwGJrzW__loC∋̛mG摞d~焌N۟A@^ϛlɝhhfkeiD܁ʁI灓}EBWb\WM񁝁{PRUA_G偅XLJd󁃁Z]QFSHOCacVK⁘T^Ɂ[|ၐ򁪁N߁Y䉌s׍@ܞXan݋j~gݜv⯝vRՋڋ[azҝЋی׋؋ы͋ՋӋϋًދԋߋ֋ΉR䐝_蝨⦘c`篋ыNj|y㳛I⸋蝜^t⧜t⁙KÍ⟍[swOvSOvh➍FpZig݋xZNj]䰋񋧋o運dqk髟_pk溂X}t瓌ËuӋyZP|l{vux~}zYMqJƟCPk؋WkdqbHP_bᡚyɌVcڑ限EKYR_眎Mu{GLDIaΊNhXߛ֗WB뛞D؋Q恟㲊韀uHҋSU昊،rrʝuMF^JBQiPXOᘊyNJr݊jƌyĈꁽeAiMʕrPTMvrᚌfjqseghpotrƒb鹜NJDRUğdᥛzpȌڋAԓ雛_Bߗދȋ\Ί͏ۋwdTezJxŌ`ӌ^HȔXR㎎CPqŠ锯閊@Њ|ȁ嶝^艔噞J㹊{歒Se顊j舊sFጐdP}gya`fSWmeO]ݑڙ̛@FOkP\[ಉGh@󓂞Њ~yۍ\}ɐ͘V،~ऐc͌bwuxvXÕLꖊCGKƓC魜SRД߈Kv֓S哑tݓkLSښ湛誝ᙚٚ]d䡜QIvn跏ʜh\frnzyklmkgcstio݉Bvldjߊgqupm嵚W~[ZB͙GrqʟD䠜j珞iƙd^񔐘\X{Ž\箊IؘrH_j~_F׊@EmLGDŊAKJCI䯘Yᷛep՟bNボ錝AQaT㼛㻛fW`c洟a⻝qj鉙ɞ쏁㣟V뙁Mϊ䅟jFrȟ綝mlb˙_xpᒔcAg⭊|}ۚۊ@يΞ؊󊩐ҊȊ@ʊŞ̊ɊƜAL萊ъŠԊ׊ՊĚ^ÊNJ֊͊ϊwxsqPgӊea㞎ʼnؚĝ̎dˉZΓٌq҃斉vqЎx|ۉԌQ|ўh`ܛ嘉]Ǝ؉㟋zɉÈՉʜF荊ЌCa{`ekJm”ޚ썁͉̉ώoז◚DSlόUґݙ͉щݙljӌT旞g~߉惕砌ĉጜƏ戉Č͉ۂ߄VR`iKN~qԃLJK{Pk]\|\_s*[]\|b\_s*[RPNLJ]\|\_s*[q]\|O\_s*\|\_s*\|\_s*\_s*\|\_s*J\|H\_s*\|\_s*\_s*\|\_s*\|\_s*y\|\_s*F\|\_s*\|\_s*\|S\_s*\|M\_s*e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|O\_s*A\_s*\|\_s*u\|\_s*\|\_s*\|S\_s*i\|\_s*\|S\_s*[Z]\|9\_s*[]\|^\_s*{\|Q\_s*O\|\_s*\|\_s*|\|T\_s*\_s*\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|T\_s*\|\_s*\|c\_s*r\_s*e\_s*s\_s*c\|\_s*\_s*\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|Z\_s*\|n\_s*_\|s\_s*q\|B\_s*\|z\_s*n\|\_s*[qV]\|\_s*\|m\_s*F\|\\_s*\|\_s*\_s*\|X\_s*e\|@\_s*\|\_s*s\|\_s*\|f\_s*n\|\_s*\|\_s*z\|G\_s*o\_s*l\_s*d\|A\_s*\%(u\|r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|s\_s*t\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\_s*\|\_s*\|R\_s*\%(h\_s*\%(o\_s*e\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\)\|u\_s*n\_s*u\_s*n\_s*c\_s*u\_s*l\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|a\_s*n\_s*\%(u\_s*n\_s*c\_s*u\_s*l\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*l\_s*e\_s*s\)\)\|\_s*\|e\_s*[]\|o\_s*[]\|j\_s*[]\|{\_s*\|n\_s*\|X\_s*\%([]\|\_s*\)\|\_s*\|\_s*Z\|\_s*q\|\_s*T\|\_s*\|z\_s*\|\_s*x\|R\_s*\%(\_s*q\|z\_s*\)\|j\_s*\|\_s*\_s*\_s*\|}\_s*\|\_s*\%(\|`\_s*\)\|\_s*\|\_s*[]\|\_s*\|V\_s*\%(\|l\_s*\)\|\_s*q\||\_s*\_s*\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|t\_s*\|\_s*r\|\_s*Z\||\_s*\|\\_s*\|]\_s*\|\_s*\|\_s*q\_s*\|\_s*[ay]\|\_s*\|\_s*\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*R\_s*q\|\_s*\|\_s*\|\_s*\|y\_s*\|A\_s*g\|g\_s*\|\_s*t\_s*\|C\_s*\%([ormdfa]\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\|i\_s*r\_s*c\_s*a\_s*e\_s*a\_s*s\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*r\_s*i\_s*u\_s*m\|e\_s*r\_s*c\_s*i\_s*d\_s*i\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\)\|\_s*\%(\|q\_s*\)\|\_s*\|\_s*\|Z\_s*\%(c\|C\_s*\)\|\_s*\|\_s*[{v]\|\_s*\%(\|\_s*s\_s*\_s*\_s*w\_s*Z\_s*p\_s*\_s*w\)\|(\_s*\_s*)\|\_s*q\|\_s*\_s*\|\_s*\|\_s*\|m\_s*\%(\|\_s*\)\|~\_s*\_s*\|o\_s*c\|Y\_s*t\|\_s*[Iv_]\|\_s*_\|B\_s*\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|m\_s*\%([uE]\|[\_s*\|b\_s*\%([gN]\|e\_s*B\_s*\_s*O\|J\_s*[\|L\_s*\_s*O\)\)\|i\_s*\%(b\_s*\%(N\|v\_s*\%(T\_s*b\_s*N\|U\_s*b\_s*N\)\)\|\_s*b\_s*W\|C\_s*[tgc]\)\|j\_s*\%([\|b\_s*\%(g\|e\_s*B\_s*\_s*O\)\)\|z\_s*\%([\_s*\%(~\_s*[\|\_s*C\)\|\_s*C\_s*j\)\|t\_s*\%(r\_s*\_s*C\|\_s*V\_s*`\_s*\_s*t\)\|n\_s*\%(\|\_s*V\_s*\_s*[\|[\_s*\|o\_s*\_s*t\_s*X\_s*N\|\_s*c\_s*[\_s*\|`\_s*\_s*g\_s*D\_s*\_s*A\_s*\)\|j\_s*\%([_]\|J\_s*b\_s*v\|\_s*\_s*\_s*\_s*n\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\)\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|a\_s*p\_s*a\_s*v\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|o\_s*\%(d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\)\)\)', + \ 'l' : '\%([HFDB@ႌPQʁ΁́Ƀȃ|Ll]\|\_s*[]\|b\_s*[HFDB@]\|\_s*[]\|t\_s*\|\_s*\_s*2\_s*\_s*@\|\.\_s*\.\_s*\.\|f\_s*F\|\_s*z\|\_s*\|E\_s*G\|\_s*\|w\_s*K\|{\_s*\|\_s*\|_\_s*\|\_s*\%([LCAu{gEXRSO[]\|y\_s*X\|\_s*[\_s*\|G\_s*x\|\_s*\|t\_s*g\|\_s*J\|x\_s*\_s*A\|r\_s*\%([\|\_s*O\|C\_s*\%(X\_s*g\|\_s*O\)\)\|e\_s*B\|T\_s*\_s*\%(W\_s*F\_s*\_s*X\|[\_s*\_s*X\)\|j\_s*[\|N\_s*\_s*A\_s*\|b\_s*\%([W^egN]\|L\_s*\%(\_s*O\|[\_s*h\)\|J\_s*[\)\|J\_s*[\_s*\|P\_s*[\_s*\%([g^]\|V\_s*\_s*\)\|K\_s*[\|M\_s*\_s*O\|W\_s*\%([\|e\_s*b\_s*N\|X\_s*e\_s*B\_s*\%(N\|b\_s*N\)\|J\_s*\|N\_s*[\_s*\|b\_s*[gN]\)\|\_s*\|\_s*\%([SO_]\|{\_s*\%(N\|b\_s*N\)\|o\_s*\_s*f\_s*B\|Y\_s*f\_s*[\_s*\|\_s*[B[]\|W\_s*\|h\_s*\)\|\_s*\%(A\_s*\|b\_s*^\|[\_s*k\|C\_s*\|\_s*\%([\X]\|c\_s*H\)\)\)\|\\\_s*L\_s*a\_s*T\_s*e\_s*X\|k\_s*\%(T\_s*C\_s*Y\|k\_s*T\_s*C\_s*Y\|t\_s*m\_s*`\|\_s*\%(\_s*\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\%(\_s*\|\_s*\|\_s*\)\|\_s*\_s*\|A\_s*s\_s*E\_s*w\|\_s*\%(\_s*\_s*\_s*\|s\_s*\_s*w\|\_s*\_s*\_s*v\_s*\_s*\_s*\_s*\_s*\)\)\|L\_s*\%([DP]\|T\_s*C\_s*Y\|L\_s*T\_s*C\_s*Y\|u\_s*\%(t\_s*e\_s*t\_s*i\_s*u\_s*m\|c\_s*i\_s*d\)\|i\_s*\%(t\_s*h\_s*i\_s*u\_s*m\|s\_s*p\|n\_s*u\_s*x\)\|E\_s*D\_s*\_s*C\_s*g\|e\_s*m\_s*m\_s*a\|o\_s*\%(g\_s*i\_s*c\_s*a\_s*l\_s* \_s*U\_s*n\_s*i\_s*t\_s* \_s*N\_s*u\_s*m\_s*b\_s*e\_s*r\|u\_s*i\_s*s\_s*i\_s*a\_s*n\_s*a\)\|a\_s*\%(w\_s*r\_s*e\_s*n\_s*c\_s*i\_s*u\_s*m\|n\_s*t\_s*h\_s*a\_s*n\_s*u\_s*m\|T\_s*e\_s*X\)\|A\_s*N\)\|\_s*\_s*\|G\_s*\|\_s*\%([BZYUTX_|}imkuA[]\|\_s*}\|\_s*h\_s*\|\_s*\|]\_s*`\_s*[\_s*\|R\_s*\%(\_s*X\|s\_s*\)\|N\_s*[\_s*h\|J\_s*\%([\|I\_s*\)\|W\_s*[[]\|f\_s*[B]\|h\_s*J\_s*C\_s*\|v\_s*g\_s*\|p\_s*[\_s*[\|O\_s*\%(j\_s*\|i\_s*\)\|t\_s*\%([Gg]\|^\_s*[\|e\_s*B\_s*\_s*O\)\|e\_s*\_s*[V]\|`\_s*E\_s*\|\\_s*\%(\\_s*[\_s*\|O\_s*\_s*t\_s*B\)\|^\_s*[\|g\_s*\%([]\|}\_s*X\|A\_s*j\_s*A\|O\_s*\_s*t\|o\_s*\_s*X\_s*L\_s*[\)\|I\_s*\%(^\_s*[\_s*\|l\_s*\)\|~\_s*\%(e\_s*b\_s*h\|b\_s*[^g]\)\|\_s*\%([\_s*W\_s*\|l\_s*\|\_s*`\_s*F\_s*b\_s*\)\|\_s*W\_s*\|L\_s*\%(b\_s*h\|\_s*[\_s*\|e\_s*\_s*\%(X\_s*^\_s*C\_s*\|V\_s*\_s*^\_s*C\_s*\)\)\|G\_s*\%(]\_s*\|[\_s*W\_s*\)\|q\_s*e\_s*\_s*V\_s*\_s*^\_s*C\_s*\|l\_s*\%([A]\|b\_s*g\|[\_s*W\_s*\)\|j\_s*A\|x\_s*\%([]\|\_s*A\|\_s*[\_s*V\_s*\_s*\|\_s*e\)\|r\_s*\%([A[]\|h\_s*[\|\_s*O\)\|\_s*\%([X[]\|u\_s*\_s*\_s*[\_s*i\|\_s*\|h\_s*~\_s*\|N\_s*T\_s*\_s*u\_s*[\_s*\|b\_s*N\|V\_s*A\_s*\|~\_s*G\_s*[\_s*\)\|\_s*\%(C\|\_s*O\_s*E\_s*F\)\|\_s*\%(B\_s*\_s*O\_s*X\_s*g\_s*\|@\_s*\%(v\_s*[\_s*\|C\_s*A\_s*T\_s*\)\)\|o\_s*\%(e\_s*B\|^\_s*\_s*A\_s*\%(\|j\_s*Y\_s*\)\|v\_s*[\_s*\|C\_s*A\_s*T\_s*\)\|b\_s*\%([hsv^N`g]\|X\_s*\)\)\)', + \ 'm' : '\%([ӊߝϙ~EぞIJ䈐ЎtuqvUpݑmXޖ\~Җߋ̋bf{eҖٖ۟՟G̞NaCܖS֖іЖҖێ]RkᑔRȖ͕֞G̖ΎrݒWϏږӛRㅖG̎bpcᾖɖ˖ǖȖʝŖҖǖɓzї㸋X}ٖV񛘊[|rm籕S}絓ԘAWp~׏@d⚕ړkJ⥐ĐIßz峒ۚ䖹ٖdQZxxNaDYKICTΗXO̎SZBݜDXL薦ޑْÁvpxzEG⊖ɗΔFaϓrʘH韌ΎM倐ᡞ䪖s{SAQ`֞捐vP閨{FŜ\rVmfOϔ[[p䖣Ȑgϖ▕naῖא\ݟ{fB坏㇓㕓I帑^]ߋ[]HoqhƉMϔ도dhʉqږp鞔C䍕̓h|{Š׈wleCdꠖqxfUXODEBKji~ەבSuҖKwQҖĖĘdG簖ڞ_aJZՖ攉V{顜јԛIԙ\ݖޖ呾GM挫D󏫐m_U䝔nݑԕ]vsҖT֍vږᄐϐ^dșɎG܂򃀁ʁ܁ځ}́΁ށȁ聹偅惢ˁہ́⁈~Ɂ߁݁䁾֖Z|}Ń~Mm]\|\_s*[]\|b\_s*[~}]\|\_s*[߂ނ݂]\|g\_s*[t]\|o\_s*\%([ne]\|\_s*\|\_s*\)\|\_s*o\|\_s*y\_s*\%(\|\_s*\)\|\_s*\%([pen]\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*z\_s*\|k\_s*~\_s*\|\_s*\|\_s*p\|\_s*\|\_s*\_s*\|O\_s*l\_s*e\_s*a\_s*l\_s*e\_s*s\|\_s*R\|\_s*\_s*\|j\_s*E\|\_s*\|\_s*[N]\|n\_s*\_s*F\|t\_s*\|J\_s*\_s*\|v\_s*w\|\_s*\|z\_s*\_s*q\|v\_s*\%([pL]\|`\_s*\|H\_s*q\)\|\_s*\|U\_s*\|6\_s*\|\_s*c\|\_s*w\|\_s*\|\_s*]\_s*q\|\_s*n\|B\_s*\%(e\_s*r\_s*b\_s*e\_s*r\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*o\_s*r\_s*r\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|Y\_s*\|\_s*q\|k\_s*\$\_s*_\_s*{\_s*i\_s*n\_s*f\_s*}\_s*\$\|t\_s*m\|A\_s*\%(b\_s*i\_s*e\_s*s\|p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*r\_s*o\_s*s\_s*t\_s*i\_s*c\_s*h\_s*u\_s*m\)\|R\_s*\|\_s*\|e\_s*\|_\_s*[q`]\|d\_s*\|\_s*\|\_s*\|c\_s*[q]\|3\_s*[“]\|R\_s*[“]\|p\_s*[q]\|\_s*\|\_s*\|c\_s*\|C\_s*[_]zIR]\|P\_s*o\_s*d\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*[Y]\|\_s*s\|[\_s*]\|\_s*\|\_s*\|e\_s*O\|R\_s*u\_s*t\_s*a\_s*l\_s*e\_s*s\|s\_s*\%(\|\_s*[_]]\)\|\_s*l\_s*}\_s*\_s*m\_s*X\|\_s*X\|\_s*\|\_s*\|\_s*\|\_s*[XЎ]\|\_s*\|S\_s*\|\_s*h\|\_s*\|\_s*\|\_s*\_s*\|{\_s*B\|\_s*v\|\_s*[o]\|\_s*\|}\_s*n\|L\_s*o\_s*g\_s*a\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*b\|\_s*m\|S\_s*\%(a\_s*p\_s*i\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|c\_s*h\_s*i\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|C\_s*\%(a\_s*s\_s*u\_s*a\_s*r\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*a\_s*t\_s*o\_s*p\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\)\||\_s*\%(\_s*l\|\_s*\)\|H\_s*a\_s*m\_s*a\_s*m\_s*e\_s*l\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*[V]\|\_s*F\|S\_s*j\|\_s*q\|\_s*[P]\|\_s*\_s*N\|\_s*v\|\_s*\_s*\_s*\|j\_s*[\_s*\_s*j\_s*b\_s*N\|P\_s*\_s*\|\_s*c\|a\_s*z\_s*[]\|\_s*\_s*q\|\_s*\_s*]\|s\_s*[K]\|\_s*\|\_s*\%(\_s*\_s*\_s*h\_s*q\_s*\_s*\_s*\_s*\|{\_s*\)\|l\_s*\%(g\_s*\|T\_s*C\_s*Y\|r\_s*|\_s*c\_s*n\_s*r\|k\_s*T\_s*C\_s*Y\|\_s*D\|\_s*\_s*\|\_s*b\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\)\|v\_s*Z\_s*@\|\_s*\|U\_s*b\_s*w\_s*\_s*\_s*}\_s*]\_s*b\_s*z\|n\_s*s\_s*I\_s*\_s*\|\_s*s\_s*\%(\_s*\|\_s*\_s*\)\|C\_s*m\|\_s*\|\_s*\|M\_s*\%([dgtnOo]\|X\_s*e\_s*\_s*r\|T\_s*C\_s*Y\|S\_s*-\_s*D\_s*O\_s*S\|L\_s*T\_s*C\_s*Y\|P\_s*3\_s*v\_s*\_s*\%([\_s*\_s*[\|C\_s*\_s*[\)\|D\_s*\%(v\_s*\_s*[\_s*\_s*[\|\_s*R\_s*[\_s*_\_s*[\)\|c\_s*C\_s*a\_s*r\_s*t\_s*h\_s*y\|e\_s*\%(d\_s*u\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*l\_s*e\_s*s\|i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*u\_s*m\|t\_s*a\_s*F\_s*o\_s*n\_s*t\|n\_s*\%(y\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|d\_s*e\_s*l\_s*e\_s*v\_s*i\_s*u\_s*m\)\|C\_s*a\_s*b\)\|u\_s*l\_s*e\|A\_s*C\_s*A\_s*h\_s*\_s*X\|a\_s*\%(g\_s*n\_s*\%(o\_s*l\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|e\_s*s\_s*i\_s*u\_s*m\)\|n\_s*\%(u\_s*\%(s\_s*c\_s*r\_s*i\_s*p\_s*t\_s* \_s*E\_s*d\_s*i\_s*t\_s*i\_s*n\_s*g\|e\_s*d\)\|g\_s*a\_s*n\_s*e\_s*s\_s*e\)\|r\_s*y\_s*l\_s*a\_s*n\_s*d\|i\_s*n\_s*e\|k\_s*e\_s*f\_s*i\_s*l\_s*e\|c\_s*\%(h\|i\_s*n\_s*t\_s*o\_s*s\_s*h\)\|s\_s*\%(s\_s*a\_s*c\_s*h\_s*u\_s*s\_s*e\_s*t\_s*t\_s*s\|t\_s*e\_s*r\_s*C\_s*a\_s*r\_s*d\)\)\|i\_s*\%(n\_s*n\_s*e\_s*s\_s*o\_s*t\_s*a\|s\_s*s\_s*\%(i\_s*s\_s*s\_s*i\_s*p\_s*p\_s*i\|o\_s*u\_s*r\_s*i\)\|c\_s*\%(r\_s*o\_s* \_s*S\_s*o\_s*f\_s*t\_s*w\_s*a\_s*r\_s*e\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*s\|h\_s*i\_s*g\_s*a\_s*n\)\)\|I\_s*\%(T\|P\_s*S\|M\_s*D\)\)\|G\_s*\)', + \ 'n' : '\%([݃ɏC҈jMlAjfwaXHpLՋH]`kc䊉ѓoьْE{JW@ГTK鑥͋XINӞGcIX^]\_UޔWژZVLqہ|Z‚Țˑ_o^EDJCꋑlXLisMJൔKR_QORNSlPIBQםHqǚ\啼KL刐@zXޓF܍fzGE{DzUѓhƝ^吒SLERP{e֏AEUД@PEɔB轟WstxwZKXfאnE͔DFClʋѐV_a玂QƓ獐m򎗉2OrW㊓ckj›DTlSVQewoԎPYg糕粓Q^垙ĎCΉYّӓHaË[ymܗGXƖČ`Ɖrဗviax܏AE}VΎ̔TRf훕jsϞoo񁽁ˁK⍉֚a[ߝ\rPnTˆbޏLྒྷލ؋S~eȄޖjlʁ`ikmN~n]\|\_s*\|\_s*q\|\_s*\|x\_s*U\|\_s*\_s*\|\_s*\_s*\|T\_s*[|]\|\_s*C\|t\_s*\|g\_s*[C]\|j\_s*[]\|\_s*]\|L\_s*\|\_s*\|F\_s*q\|\_s*[@q]\|P\_s*q\|\_s*q\|\_s*\_s*\|h\_s*V\|q\_s*|\|\_s*\_s*\|\_s*\_s*\|m\_s*\|\_s*\|\_s*\|\_s*\|\_s*]\_s*q\|_\_s*\|\_s*P\|I\_s*I\_s*\|^\_s*\|\_s*\|\_s*\| \_s*2\_s* \_s*\_s*\_s*\|M\_s*y\_s*r\_s*i\_s*s\_s*t\_s*i\_s*c\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*\%(f\|\_s*\)\||\_s*\|\_s*|\|\_s*T\|s\_s*[]\|P\_s*b\|L\_s*e\_s*a\_s*d\|C\_s*[ۑl]\|C\_s*\%(e\_s*l\_s*a\_s*s\_s*t\_s*r\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*r\_s*y\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*\%(\_s*\|\_s*\)\||\_s*\_s*\|7\_s*[]\|\_s*\|n\_s*k\|\_s*\|s\_s*\|\_s*\_s*X\_s*g\|T\_s*h\_s*e\_s* \_s*N\_s*e\_s*t\_s*w\_s*o\_s*r\_s*k\_s* \_s*I\_s*n\_s*f\_s*o\_s*r\_s*m\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\|S\_s*o\_s*\%(l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|d\_s*i\_s*u\_s*m\)\|R\_s*\|t\_s*H\_s*\_s*E\_s*m\_s*C\_s*}\_s*\|\_s*[\_s*m\_s*b\_s*V\_s*\_s*E\_s*t\_s*H\_s*\_s*E\_s*m\_s*C\_s*}\_s*\|I\_s*\_s*\_s*_\|A\_s*\_s*\_s*J\_s*l\_s*b\_s*g\_s*\_s*[\_s*N\|\_s*\|\_s*_\|m\_s*\%([_n]\|N\_s*B\_s*[\_s*\|\.\_s*x\_s*\.\|\_s*\_s*\_s*\|h\_s*e\_s*s\_s*x\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\|\_s*\%(w\_s*s\|\_s*\_s*\_s*\|\_s*|\_s*i\_s*\_s*\_s*\_s*\_s*\|v\_s*r\|\_s*\_s*\_s*\)\|d\_s*\%(\_s*\_s*\_s*\|s\_s*\_s*\_s*\_s*\)\|\_s*\%(D\|v\_s*\)\)\|\_s*z\_s*\|\_s*\|\_s*\|N\_s*\%([dpbaeoi]\|R\_s*Z\_s*I\|-\_s*g\_s*r\_s*a\_s*m\|G\_s*\_s*[\_s*h\|H\_s*K\_s*\%(z\_s*[\_s*\|\_s*W\_s*I\)\|T\_s*T\|Y\_s*_\_s*E\|U\_s*L\_s*L\|A\_s*S\_s*A\|E\_s*\%(C\|p\_s*o\_s*c\_s*h\|m\_s*a\_s*c\_s*s\)\)\|\_s*f\|G\_s*k\)', + \ 'o' : '\%([ݜbSMoNOÌQjwdЊdYnnx遌ssና{≬ݕLڜP؋y߁WSVTRUXy􋳙{E⫝e}tcC筞[҉x^拑`q`ƊxsN˗uBbdeȊe퐊Kȉ򚙁aCO݈җ㱕zv\dʋUK{|wS^g]㠟iҜ}Dᜳ[aQ_NRVMן^q቉rSB蜊׉Wꉞʜ䉆WTgEcTٖQPѕ}ʼnY[”uN|ǛܚǕĐDVEjvɋNOj؟Ɍ䏏֒Y~щI偝aɁJÓփIo]\|\_s*\_s*\_s*\|\_s*p\|\_s*u\|\\_s*\_s*\|S\_s*\|C\_s*\_s*C\_s*\|\_s*\|\_s*@\|\_s*\|\_s*\_s*\|\_s*\|n\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\|T\_s*[]\|\_s*[q]\|f\_s*[]\|\_s*[]\|H\_s*\|\_s*\|\_s*C\|G\_s*u\_s*t\_s*t\_s*i\_s*f\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|D\_s*i\_s*l\_s*l\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|H\_s*y\_s*p\_s*e\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*p\|\_s*[q]\|\_s*N\_s*\|{\_s*\_s*\|\_s*\|\_s*b\|A\_s*l\_s*i\_s*s\_s*m\_s*a\_s*t\_s*a\_s*l\_s*e\_s*s\|K\_s*\|\_s*l\|\_s*c\|C\_s*o\_s*p\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|o\_s*\_s*U\_s*\%(\|\_s*\)\|\_s*m\|\_s*\|\_s*]\|\_s*g\|\_s*\|\_s*\_s*\_s*P\|A\_s*[zn]\|\_s*[H]\|}\_s*\|\_s*F\|w\_s*n\_s*}\|\_s*\|z\_s*[imqx]\|\_s*\|c\_s*[_]\|\_s*O\|]\_s*c\_s*[ꕃ]\|\_s*[~C]\|\_s*\%(c\|\_s*\_s*\|\_s*V\_s*c\)\|\_s*\|\_s*[G]\|\_s*\_s*\|\_s*m\_s*\_s*\_s*\_s*\_s*\.\|G\_s*[]\|t\_s*h\_s*e\_s* \_s*O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*a\_s*n\_s*a\_s*g\_s*e\_s*m\_s*e\_s*n\_s*t\_s* \_s*G\_s*r\_s*o\_s*u\_s*p\|\_s*\_s*d\_s*@\|E\_s*\|\_s*~\|E\_s*\%(B\|[\_s*\%(Y\|\_s*\)\|\_s*{\_s*\_s*X\)\|o\_s*\|A\_s*\%(\|U\_s*[\|E\_s*\%([`g]\|^\_s*[\)\)\|\_s*{\_s*\\_s*t\_s*g\_s*E\_s*F\_s*A\|\_s*\%(\_s*[N]\|\_s*\)\|\_s*\|\_s*\_s*\|_\_s*\_s*a\|\_s*\_s*\|\_s*\_s*_\_s*f\_s*j\_s*\_s*\|`\_s*\_s*\|\_s*K\_s*\|n\_s*\%([r^]\|q\_s*d\|\.\_s*j\_s*\.\|r\_s*X\|\_s*\_s*O\|\_s*\_s*\_s*\%(k\_s*\_s*\_s*\|v\_s*\_s*\_s*\_s*\_s*\_s*\)\)\|\_s*\|\_s*Z\_s*q\|\_s*\|_\_s*f\|O\_s*\%([^rsS]\|h\_s*i\_s*o\|k\_s*l\_s*a\_s*h\_s*o\_s*m\_s*a\|b\_s*j\_s*e\_s*c\_s*t\_s*-\_s*O\_s*r\_s*i\_s*e\_s*n\_s*t\_s*e\_s*d\|O\_s*\%(D\_s*L\|P\_s*L\)\|M\_s*R\_s*O\_s*N\|A\_s*N\_s*\_s*[\_s*i\_s*[\|C\_s*R\_s*\\_s*t\_s*g\|r\_s*e\_s*g\_s*o\_s*n\|''\_s*R\_s*e\_s*i\_s*l\_s*l\_s*y\_s* \_s*J\_s*a\_s*p\_s*a\_s*n\|\_s*\_s*O\|p\_s*e\_s*n\_s*W\_s*i\_s*n\_s*d\_s*o\_s*w\|x\_s*y\_s*g\_s*e\_s*n\)\)', + \ 'p' : '\%([BC@{sܕەy~Օҕ糕ѕ粛ؕzCUߕ[iᢔpoǕƔŔ•zusvtjHgdςՂҁ}{ՃӄkDE_v|Łji݁aypPӃ΃sp]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[|yvsp]\|\_s*[ۂ؂Ղ҂]\|\_s*\|\_s*l\_s*\|\_s*\|O\_s*[ID]\|\_s*\|\_s*R\|\_s*D\_s*\|\_s*\|\_s*`\|\_s*\|\_s*\|\_s*q\|b\_s*\%(\|\_s*n\)\|C\_s*y\_s*c\_s*l\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|S\_s*y\_s*n\_s*a\_s*n\_s*t\_s*h\_s*a\_s*e\|r\_s*\|B\_s*r\_s*o\_s*m\_s*e\_s*l\_s*i\_s*a\_s*l\_s*e\_s*s\|L\_s*e\_s*a\_s*d\|\_s*[Ž]\|V\_s*\%(\_s*[\_s*h\|\_s*V\_s*r\_s*\)\|T\_s*\%([\_s*\|C\_s*\%([YNPR]\|\_s*V\_s*r\_s*\|\_s*E\_s*\|L\_s*b\_s*N\)\)\|+\_s*\|z\_s*\%(\|X\_s*Q\_s*\)\|q\_s*\_s*|\_s*\|\_s*\%(z\|\_s*o\)\|t\_s*\%(\_s*W\_s*A\_s*\|\_s*\%(C\_s*W\_s*\_s*O\|[\_s*\%(Y\|W\_s*\_s*O\)\)\|^\_s*\_s*C\_s*\|H\_s*\%([[mg]\|{\_s*X\|r\_s*A\|X\_s*t\_s*@\_s*[\|j\_s*[\)\|@\_s*\%(C\|\_s*I\|[\_s*\%([W}]\|~\_s*\_s*O\)\|\_s*\%(g\_s*\|^\_s*Y\_s*[}]\)\|\_s*[cX]\|\_s*m\_s*v\_s*V\_s*X\)\|B\_s*\%([]\|W\_s*\%(b\_s*N\_s*X\|J\_s*\)\|[\_s*r\_s*[\|b\_s*V\_s*\_s*O\|\_s*\_s*\|\_s*f\_s*\_s*t\_s*B\_s*A\|\_s*\%([X[Ap]\|b\_s*[vp]\|s\_s*\%(\|[\_s*k\)\)\)\|F\_s*\%([\_s*\%([xY]\|W\_s*\_s*O\)\|C\_s*Y\|\_s*\_s*\|j\_s*\%(\|b\_s*N\_s*X\|L\_s*A\|[\_s*\)\|m\_s*\%(L\_s*V\|[\_s*\)\)\)\|q\_s*\|\_s*\|^\_s*\_s*p\_s*N\_s*\|\_s*\|\_s*\_s*\|i\_s*s\|Z\_s*\|\_s*\|\_s*Z\|\_s*`\|\_s*\|^\_s*\|o\_s*\%(g\|k\_s*@\|b\_s*\%(^\_s*`\_s*s\|X\_s*W\|\_s*f\_s*\)\|\_s*\_s*\_s*r\_s*\_s*\_s*\_s*\_s*\|r\_s*D\|D\_s*r\_s*D\|\_s*\_s*h\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\%(\|\_s*\_s*\)\)\|i\_s*\|J\_s*\_s*E\_s*\|\_s*\_s*\|d\_s*\_s*\|\_s*\_s*^\|o\_s*e\_s*\_s*\|\\_s*\_s*t\_s*\|_\_s*\|\_s*\_s*[a]\|\_s*\|\_s*\|P\_s*\%([umdCaor]\|K\_s*\|D\_s*F\_s*t\_s*@\_s*C\_s*\|R\_s*[\_s*h\|^\_s*C\_s*\|\.\_s*S\_s*\.\|S\_s*\%(\.\|Y\_s*E\_s*S\)\|I\_s*C\_s*}\_s*C\_s*R\_s*\|l\_s*\%(a\_s*t\_s*i\_s*n\_s*u\_s*m\|u\_s*t\_s*o\_s*n\_s*i\_s*u\_s*m\)\|E\_s*T\_s*{\_s*g\_s*\|O\_s*S\_s*\%(V\_s*X\_s*e\_s*\|I\_s*X\|T\_s*\_s*\\_s*b\_s*h\)\|e\_s*\%(r\_s*l\|n\_s*\%(t\_s*\%(o\_s*x\_s*y\_s*l\_s*i\_s*d\_s*a\_s*e\|i\_s*u\_s*m\)\|n\_s*s\_s*y\_s*l\_s*v\_s*a\_s*n\_s*i\_s*a\)\)\|h\_s*o\_s*s\_s*p\_s*h\_s*o\_s*r\_s*u\_s*s\)\)', + \ 'q' : '\%([zɟKMz՟J㖍򍥛IHEdzboxܗAϕDCBӊǏ~B䱌sZY㙬ᯞӉOM֌NϏvLK@{^Z򏾓^A鶊rňʈUÑq𞀋C~XVTRUWS܉_wo^鿌~GF䇚`p̏LY۞IȊfsގԚPMEu{[O֞oӍ@󞔐ȓScSHqvE|―ĜvꋀῙ܌JɍCg틂{m{X؍Hᜁv㜜ҙg电M͋ˋegfhPHNq]\|\_s*\|b\_s*N\|\_s*\|\_s*\|\_s*\|~\_s*\|\_s*\|\_s*S\|S\_s*[Z]\|\_s*\_s*x\|\_s*\|\_s*h\|9\_s*\|\_s*\|^\_s*{\|\_s*\|Q\_s*O\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|V\_s*l\_s*\|\_s*|\|T\_s*\_s*\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|T\_s*\|\_s*\|c\_s*r\_s*e\_s*s\_s*c\|C\_s*\|\_s*[{]\|\_s*\_s*\|K\_s*r\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\%([ƕE]\|o\_s*\)\|\_s*\|\_s*C\_s*a\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*\|Z\_s*\|n\_s*_\|s\_s*q\|B\_s*\|R\_s*\_s*q\|C\_s*\%(r\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\)\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|p\_s*\_s*`\|\_s*s\_s*N\_s*\|`\_s*\_s*\_s*\_s*\_s*}\|Q\_s*\%(I\_s*C\|R\_s*R\_s*[\_s*h\|C\_s*T\_s*[\_s*N\_s*\|U\_s*O\_s*J\_s*[\_s*h\)\|w\_s*x\|R\_s*\%([\_s*\_s*\|\_s*e\_s*B\_s*t\_s*@\_s*C\_s*A\)\|\_s*\_s*\|J\_s*\%(U\_s*\|^\_s*[\_s*\|X\_s*o\|[\_s*k\_s*[\_s*\|i\_s*[\_s*g\|_\_s*t\_s*B\|\_s*e\|h\_s*\_s*[\_s*[]\|\_s*\%(`\_s*[GF]\|e\_s*\%(B\_s*G\|b\_s*g\)\)\|\_s*^\_s*[X]\)\|\_s*\|L\_s*\%(g\|u\_s*\|z\_s*[\_s*e\|n\_s*[\_s*_\|\_s*\%(g\|e\_s*B\_s*\_s*O\)\|[\_s*\|m\_s*\|b\_s*V\_s*\|\_s*\%([\|G\_s*\)\)\)', + \ 'r' : '\%([ۛŘӛĚ̉h_R{]Ә[\U^cRP˞ulMCL属譚NdיCROcYᑘLSQXᔘWOUĘTRNb@F࢔GmedibIE炍䃟LBڟ׊aeUxvYZYtXF䫗ᖗw灟KMlI瀗qずwYQrQݗ@BA٘Hḟpᐗ㾗ۗݗZ~Kಝ_×ɌIʙZCXYVg×ڛPᎊ}֗ᅗPXaМHW˗Ԝdhgҙzؗϙחїӗ՗WOC͗`鲛饗؞Ax@_]qyp֝H×㇗ߗƗȗ열ɋʗ̚iś胗ؗܘA鋗i\ߗ仂טJəVOgTpREY㑟SB՛ۛnAࣗa茗E煚h඗pyqQ㡟ISۗᚘ痋엇tff逗ǂ炒ESqGBJH[wxIT`rKR|FVOW^XU\ZDAIYzM{Pst}NLvpyu@C]E_~D֍㗅XQσr]\|\_s*[]\|b\_s*[]\|\_s*[]\|\_s*\|\_s*[L]\|h\_s*[Eߎ]\|6\_s*[]\|\_s*\_s*\|E\_s*G\|\_s*\|A\_s*\%(c\_s*t\_s*a\_s*e\_s*a\|p\_s*o\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|C\_s*\%(a\_s*l\_s*y\_s*c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|h\_s*o\_s*r\_s*i\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|\_s*[]\|\_s*\%(\||\_s*\)\|V\_s*e\_s*r\_s*t\_s*i\_s*c\_s*i\_s*l\_s*l\_s*a\_s*t\_s*a\_s*e\|O\_s*r\_s*c\_s*h\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|M\_s*i\_s*c\_s*r\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\|L\_s*\%([ruia]\|e\_s*i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*a\_s*l\_s*e\_s*s\|A\_s*N\_s*P\_s*[\_s*u\_s*\)\|C\_s*\|G\_s*\%(e\_s*n\_s*t\_s*i\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|y\_s*\%(n\_s*a\_s*n\_s*d\_s*r\_s*a\_s*e\|m\_s*n\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\)\|\_s*W\_s*f\_s*[\_s*^\_s*x\_s*[\_s*X\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*s\_s*\_s*w\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|d\_s*C\_s*\_s*M\_s*\_s*\_s*\|\_s*k\_s*\_s*\%(w\_s*d\_s*C\_s*\_s*M\_s*\_s*\_s*\|\_s*\)\|\_s*\_s*\_s*\_s*Z\_s*b\_s*g\_s*v\_s*Z\_s*@\|\_s*\|K\_s*\|g\_s*\|v\_s*\|\_s*\|\_s*A\|\_s*[M]\|\_s*\|\_s*\_s*\|Q\_s*\%(l\_s*\_s*\|\_s*^\)\|q\_s*\%(h\_s*m\_s*`\|\_s*c\|r\_s*|\_s*Q\_s*R\_s*Q\_s*b\|\_s*\_s*\_s*\_s*\|\_s*\_s*\)\|@\_s*\\_s*\_s*\_s*P\_s*\|\_s*A\_s*I\|F\_s*\|R\_s*\%([bnfeauh]\|i\_s*c\_s*h\_s*a\_s*r\_s*d\_s* \_s*M\_s*\.\_s* \_s*S\_s*t\_s*a\_s*l\_s*l\_s*m\_s*a\_s*n\|C\_s*S\|S\_s*S\_s*\_s*[\_s*_\|I\_s*S\_s*C\|A\_s*M\|O\_s*M\|E\_s*\%(M\_s*\_s*\|T\_s*U\_s*R\_s*N\_s*L\_s*[\|A\_s*D\_s*M\_s*E\)\)\|\_s*K\_s*\\_s*\|A\_s*[\_s*\)', + \ 's' : '\%([}[Ty}Q^ǚih掞y{GOʗcԛzyu߈S^䛣᜹KU|\}ax‘ƜQsढ़w柔锚t䇛q~Hxyܑ䵑qȑBJvtƑNⵑr|swpnmy絒F\nuLMNdƑ[ꋑjfb`a^𕛑lX􉈑cYiઈgלheesSzNZ驋LLQkşGiↁސِېڐߞ@CGSПƝ[Tאɐ͊֐ȐǝAI⣛p蔞tdCNӟ׈ߛݙܘx㙘A_baJஓϛƘjbHⳙAGSL⒑Wsr葁DJAL񙒐枙@ېMHlFKDG@BhǑNdD牙|œҝᝩ⫟ŖvR呝yHՐU}[҂ߝpS爊caopIDcER䊔TωsꈝؐCShᓩ]T\~uy齗VŒsvǐEpz~dǗ俑Ypnzy羝裐Ð␕΁ʁ܁́ˁ~Ɂځށ}ȁ́݁聹后v袝xž谒NːXaV䐆Hґ]ZʗLz`DߝXzi擧ABPDY`LZ迓xZxw圑ȓGFaƎb乗MEΕsCFZnD㈵㦋s]Ŗl^⚑A潓gΖ儞ɖΏd臐wpd[g謎姎^GNH˒Ύ܊m\ސːKŽKoq҉tϔ͚͎bAjP֎ٌࡐ̝咙ݐ┐Ԏ^Ύގڎ؎YώΎɎԎߎЈޝȕiSGCဋÎft偛WVz题瑲Efiglk{蜕婏oFT碏VhqhkFJ娏QK榊S酝nSXKUڏMGjaENODPCALRTIB@M᭚忏w{vxs⡏turfZuVꐚpy曐P]AϜUjJfY`Ds橝ΐaO凓cjcѐUahNfdCkXĐLTQWgi[RMebI_S΋nZo䜏_י|䓏wb򏎏ҟm䀛uLЏ縐מ⪙דMvRߜcB_џnՏʈ䐯B辑[頏[␏ݚK♏яҁui]疏ցjiӐԚϏUJnސŜ܏ߏُՏGଞďޏ͏ǏɏЏۏ暐Ώ̏ďƏ͏ڏ؏ɏȏTlRegp@CܑFDI冐BAHE❎oowvLUnюrŎᎊtr@{펦Ϛ`iАyэi@EJX拎}泟nyoNZyzٛᝅf׎j{~|{oߘIXB]KVgup`ikql藘ʛƓj⏎s_ꏎ˔`Œsy@؎䢊oueۚ~礛JLfVWlȐ䰐囋TᰗlIJMhEU嶎z\GԞuV\Vf֟XMˍǏxš皔m匈^꛽O@՚N\󎘊jېŒB睓N@dqbPmbq嗝WƔfFⲝHHBr{吷Wvᵔutĉh|招E䋫🛋t剎櫜f|sटEa`㓝̜cHKcߙӎ[ǎWXㄐVr\]ZPRӁ3Q^ORUSY_ATCD搔@FDNZ\؛ԟ˜GƝrӎÎEq淍Kȍ͙Pꎍ`BڛvɍVҍۍЍю΍؍̍Ӎȍ֐čՍÍˍҍٍ΍ō鑨rŞo焍e⩞y|skwNʎhS䳍}lэos⍳rԍđ獸RAm嬛OÝL_~nKዎ^dw@YYご򄋄ZYÁWnŽOyʁ`feW_TZTV\XRЕbs]\|\_s*[]\|b\_s*[\ZXVT]\|\_s*[]\|\_s*\|\\_s*\%(H\|I\_s*\)\|~\_s*\|\_s*\|\_s*\|\_s*\|\_s*g\|\_s*\|v\_s*[vX]\|\_s*n\|\_s*\|\_s*c\|\_s*\|B\_s*[BX]\|\_s*C\|\_s*\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|\_s*\|}\_s*\|c\_s*e\_s*n\_s*t\_s*i\|\_s*[ĘU]\|C\_s*\|\_s*\|}\_s*\|T\_s*\|G\_s*Y\|f\_s*\|V\_s*[c]\|V\_s*i\_s*o\_s*l\_s*a\_s*l\_s*e\_s*s\|N\_s*y\_s*m\_s*p\_s*h\_s*a\_s*e\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|\_s*\|\_s*\|b\_s*\%(^\|\_s*\)\|V\_s*\|]\_s*\|\_s*\|s\_s*[mE]\|L\_s*a\_s*\%(b\_s*i\_s*a\_s*t\_s*a\_s*e\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|\_s*\|~\_s*\|\_s*t\_s*\|\_s*\|\_s*\|\_s*_\|\_s*Y\|\_s*\|\_s*\|I\_s*\%(s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\)\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|`\_s*\|\_s*[J]\|]\_s*[X]]\|\_s*\%(X\_s*\_s*\|\_s*\_s*\)\|\_s*\%([֌ڎu]\|\_s*\)\|7\_s*\|V\_s*\|4\_s*\|S\_s*[]\|R\_s*{\|h\_s*t\|\_s*u\|\_s*\|A\_s*[o]\|\_s*[NY]\|\_s*[]\|r\_s*[ꏎ]\|\_s*\|c\_s*e\|\_s*\|\_s*\%(_\|C\_s*\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|\_s*\%(\_s*{\_s*\%(I\|\_s*I\)\|\_s*\_s*a\_s*\_s*W\)\|\_s*[Η]\|\_s*\|\_s*\|\_s*\|e\_s*\_s*\|C\_s*\%([se]\|y\_s*c\_s*a\_s*d\_s*\%(i\_s*d\_s*a\_s*e\|o\_s*\%(p\_s*s\_s*i\_s*d\_s*a\|f\_s*i\_s*l\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\)\|h\_s*l\_s*o\_s*r\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|D\_s*X\|^\_s*\_s*\|a\_s*\%(s\_s*s\_s*y\_s*t\_s*h\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|c\_s*t\_s*a\_s*l\_s*e\_s*s\)\)\|\_s*K\||\_s*[“]\|\_s*p\_s*\|G\_s*\|\_s*\|\_s*\_s*\%(X\_s*[N]\|\_s*[N]\)\|h\_s*l\|S\_s*\_s*g\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*e\|\_s*\|\_s*\%(@\|\_s*\_s*\)\|\_s*\|G\_s*\|\_s*q\|P\_s*\%(a\_s*r\_s*i\_s*e\_s*t\_s*a\_s*l\_s*e\_s*s\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|r\_s*i\_s*m\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\)\|A\_s*\%(p\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*a\_s*l\_s*e\_s*s\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\)\|\_s*[T]\|B\_s*\%(r\|V\_s*F\_s*\)\|g\_s*\_s*q\|\_s*\|u\_s*\|A\_s*\_s*`\_s*\_s*\|\\_s*\_s*\|M\_s*\%(e\_s*r\_s*c\_s*u\_s*r\_s*y\|u\_s*s\_s*a\_s*l\_s*e\_s*s\|a\_s*r\_s*q\_s*u\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\)\|D\_s*o\_s*n\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*A\_s*l\_s*p\_s*h\_s*o\_s*n\_s*s\_s*e\_s* \_s*F\_s*r\_s*a\_s*n\_s*c\_s*o\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\|\_s*\%(V\|s\_s*\%(\_s*\|\_s*\_s*\)\)\|T\_s*\%(e\_s*t\_s*r\_s*a\_s*c\_s*e\_s*n\_s*t\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\|h\_s*e\_s* \_s*S\_s*i\_s*m\_s*p\_s*l\_s*e\_s* \_s*A\_s*P\_s*I\_s* \_s*f\_s*o\_s*r\_s* \_s*e\_s*v\_s*e\_s*n\_s*t\_s*-\_s*b\_s*a\_s*s\_s*e\_s*d\_s* \_s*X\_s*M\_s*L\_s* \_s*p\_s*a\_s*r\_s*s\_s*i\_s*n\_s*g\)\|]\_s*f\|P\_s*C\_s*f\|v\_s*\_s*\_s*\_s*\_s*\_s*w\_s*\|l\_s*b\_s*g\_s*T\_s*[\_s*r\_s*X\|U\_s*\%(b\_s*N\|N\_s*Z\_s*\|r\_s*[\_s*l\|E\_s*o\_s*[\|\_s*[\_s*N\_s*\_s*E\_s*g\|\_s*U\|\_s*c\|C\_s*\%([]\|\_s*[\|f\_s*\)\|[\_s*\%([]\|\_s*\)\)\|\_s*\|[\_s*~\|i\_s*g\_s*\_s*E\_s*\|]\_s*\%(\|\_s*f\|[\_s*\%(\|\_s*\_s*Q\_s*\)\|t\_s*B\_s*[\)\|W\_s*\%(\|[\_s*\%([ON]\|\_s*\_s*[XY]\)\|O\_s*\_s*\_s*g\|\_s*\%(\_s*\|O\_s*V\_s*\_s*s\_s*[\_s*\|e\_s*[\_s*[\)\)\|r\_s*\%([Ȏ]\|T\_s*C\_s*Y\|r\_s*T\_s*C\_s*Y\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|t\_s*m\|\_s*\%(\|\_s*\_s*\_s*`\_s*\_s*\_s*\_s*\)\|h\_s*b\_s*o\_s*(\_s*S\_s*t\_s*r\_s*u\_s*c\_s*t\_s*u\_s*r\_s*e\_s* \_s*a\_s*n\_s*d\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*p\_s*r\_s*e\_s*t\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*o\_s*f\_s* \_s*C\_s*o\_s*m\_s*p\_s*u\_s*t\_s*e\_s*r\_s* \_s*P\_s*r\_s*o\_s*g\_s*r\_s*a\_s*m\_s*s\_s*)\||\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|n\_s*m\_s*x\_s* \_s*m\_s*d\_s*v\_s*r\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*u\)\|G\_s*X\|S\_s*\%([nrgmce]\|G\_s*M\_s*L\|T\_s*C\_s*Y\|S\_s*T\_s*C\_s*Y\|F\_s*}\_s*K\_s*W\_s*\|Q\_s*U\_s*A\_s*R\_s*E\_s* \_s*E\_s*N\_s*I\_s*X\|K\_s*\%(K\|Y\_s* \_s*P\_s*e\_s*r\_s*f\_s*e\_s*c\_s*T\_s*V\_s*!\)\|a\_s*\%(r\_s*\%(r\_s*a\_s*c\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|g\_s*e\_s*n\_s*t\_s*o\_s*d\_s*o\_s*x\_s*a\_s*c\_s*e\_s*a\_s*e\)\|m\_s*a\_s*r\_s*i\_s*u\_s*m\)\|M\_s*\%(v\_s*\_s*C\|N\_s*\_s*u\)\|P\_s*\%(\_s*R\_s*[\_s*h\|A\_s*C\_s*E\_s*L\_s*[\)\|p\_s*\%(l\_s*u\_s*s\|e\_s*\%(r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*a\_s*l\_s*i\_s*t\_s*y\_s* \_s*S\_s*t\_s*o\_s*r\_s*e\_s* \_s*R\_s*e\_s*t\_s*a\_s*i\_s*l\_s*e\_s*r\_s* \_s*o\_s*f\_s* \_s*P\_s*r\_s*i\_s*v\_s*a\_s*t\_s*e\_s* \_s*L\_s*a\_s*b\_s*e\_s*l\_s* \_s*A\_s*p\_s*p\_s*a\_s*r\_s*e\_s*l\)\|a\_s*\%(t\_s*h\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*c\)\)\|H\_s*I\_s*F\_s*T\_s*L\_s*[\|C\_s*S\_s*I\|T\_s*\%(k\|A\_s*R\)\|h\_s*u\_s*g\_s*a\_s*r\_s*t\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*s\_s* \_s*S\_s*y\_s*s\_s*t\_s*e\_s*m\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*f\_s*a\_s*c\_s*e\|A\_s*\%(P\|S\_s*I\)\|i\_s*\%(m\_s*p\_s*l\_s*e\_s* \_s*K\_s*a\_s*n\_s*a\_s* \_s*t\_s*o\_s* \_s*K\_s*a\_s*n\_s*j\_s*i\_s* \_s*c\_s*o\_s*n\_s*v\_s*e\_s*r\_s*s\_s*i\_s*o\_s*n\_s* \_s*p\_s*r\_s*o\_s*g\_s*r\_s*a\_s*m\|l\_s*i\_s*c\_s*o\_s*n\)\|t\_s*r\_s*o\_s*n\_s*t\_s*i\_s*u\_s*m\|o\_s*\%(u\_s*t\_s*h\_s* \_s*\%(D\_s*a\_s*k\_s*o\_s*t\_s*a\|C\_s*a\_s*r\_s*o\_s*l\_s*i\_s*n\_s*a\)\|l\_s*a\_s*r\_s*i\_s*s\|f\_s*t\_s*w\_s*a\_s*r\_s*e\_s* \_s*R\_s*e\_s*s\_s*e\_s*a\_s*r\_s*c\_s*h\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*,\_s*I\_s*n\_s*c\_s*\.\)\|u\_s*\%(n\|l\_s*f\_s*u\_s*r\)\)\|\_s*\)', + \ 't' : '\%([ĜR牉șhЌ☝ωiמRh|cH֓騗䄋㜐C䃕ۏQ榔yFbr\c͙ʓՓךcJٓؓڏxJŚɍΖrqNPь{ԍǝؗ沖L௜{ꂜՓ“ΓWٟXB[ѓw䓄~㫙ٚĊUj㉱}b馝FD㛎衞CẞTΛ⅞MDğ椈ꊛ됀zcbuٓ幓铝~鍓򓀓˓tOO̓mNlےEjqĚ\Zg\莾pyooVvϏ\p{nlnZÊn򖁞i^yr䷟ː}~ēexhurlWPȎWd͖oR瘉NནLJU猓Hzћ迟hAVVzDCUAdFDx[^៓UzaZWL⽓YQINGPOcSLǒtɞqؚ|YBh@稒ఒAeƜV•͕皁ITPזgwΐىWhіʏ`tI␎aSڎBڐRȕpAn䆉җI~焍ߑczߝ旾񕌋uid͌gQǒٚ؍jq塔|ȕȓ`B\Չ㔖ꉌۑԔԒ̒v׏IĐȒŒǛ錼əݙ֒ߘrssnUTӑn쑢LUΌCU֋ސTĜɏՔːsxAtyÕZ㋓ᶌpklϐڒʍAhՍJY_ZoTSNĒNZm֖’ޒ}zke玐ŗ͓ߝQE浖מ`kI⌒OՒP蠒eÒ隓CUǒݟlLy’kꓜjLKӝUo{⒳\_񒝓[d}ޒ渒xaQCNIԒJnhfRhtnpom~n@ؒrpUTuՌlh⚐tꃒyƒwonvqᗒvksmxJ}֓}ԐugqKfeމ˞MoRВLᷖ非ٌ✔yg栟˘l|]漒K^ȏ̎]DM骓lDeȒ@ihgⰍkXYSݛ̝EYUԕۏXIH蒎aFC{}CJFמlSs韞퓃ࣕYۈɐҒkBznҊmtԚKpЋBŗYk˜[]썰͗K’eʖd休sb饕|cG鎿Bٍked뛹k殔CĉFbWVOxh^В|⹑tM闲F֜Ӝ`dH[t؜Tjݝ^Wh]ßp~Kϓ̝W`^WUႚVJRἔCVQa_\杒OSXWYbZdÒTPAp]鮓FѝFUVf{I痑~x擑H\讖wʝ[OlߑړܒБ⛔EܑՑ͑ۑґؑݑّё̑בޑ΋Hf茘ǒ֚ꑫ—]loNOϗ┭蛀SuNЍٚB_PcB睘SW`V~^ΓysfE\؃XWƃUcN]g`Ec[^Sфet]\|\_s*[]\|b\_s*[gec`^]\|\_s*[ƂÂ]\|\_s*\|\_s*n\_s*\|\_s*[]\|\_s*\|\_s*l\|\_s*\|\_s*V\|\_s*\|i\_s*[v]\|\_s*P\|h\_s*\|\_s*\|D\_s*\_s*\|\_s*[Ŗ]\|\_s*[q]\|W\_s*\|\_s*\_s*E\_s*\|\_s*\|H\_s*y\_s*d\_s*r\_s*o\_s*c\_s*h\_s*a\_s*r\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*x\|G\_s*[ߓh]\|\_s*[]\|F\_s*N\_s*\|i\_s*[vq]\|A\_s*c\_s*o\_s*n\_s*i\_s*t\_s*u\_s*m\|\_s*\|\_s*j\|\_s*j\|F\_s*e\|I\_s*r\_s*o\_s*n\|\_s*\|\_s*\|g\_s*\|Z\_s*\|Q\_s*~\_s*S\|\_s*\%(\|\_s*q\)\|S\_s*[Z]\|\_s*\%(\|\_s*a\)\|X\_s*\|\_s*X\|\_s*J\|\_s*~\|~\_s*J\|\_s*\|\_s*\|\_s*\|\_s*[]\|B\_s*a\_s*l\_s*a\_s*n\_s*o\_s*p\_s*h\_s*o\_s*r\_s*a\_s*l\_s*e\_s*s\|1\_s*\%(\|0\_s*\)\|P\_s*\%(\|O\_s*\)\|\_s*\|\_s*l\_s*\|E\_s*\%(u\_s*p\_s*h\_s*o\_s*r\_s*b\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|\_s*\%(v\|\_s*F\)\|g\_s*\|\_s*\|`\_s*\|\_s*w\|\_s*\%(V\_s*\|\_s*F\)\|\_s*\%([]\|[\_s*\|\_s*\_s*N\)\|\_s*v\|r\_s*q\|\_s*r\_s*q\|\_s*[a]\|\_s*\|\_s*\|@\_s*\_s*\|L\_s*q\|S\_s*\|\_s*\|]\_s*h\|J\_s*i\_s*a\_s*n\_s*g\_s*s\_s*u\|G\_s*\|u\_s*[˔]\|k\_s*J\|\_s*\|\_s*I\_s*q\|\_s*a\|\_s*p\|\_s*[]\|A\_s*\|\_s*\_s*\|\_s*[]\|\_s*\_s*\\|\_s*\%(\\_s*\|A\_s*\_s*[]\)\|t\_s*\%(\|{\_s*V\)\|h\_s*\|e\_s*\|\_s*\|\_s*[]\|\_s*s\|\_s*\%([\|\_s*q\)\|\_s*v\|\_s*\|P\_s*\|\_s*\|\_s*\%(\|\_s*\)\|E\_s*\|\_s*\|P\_s*\%(\.\_s*S\_s*\.\|o\_s*l\_s*y\_s*\%(g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*r\_s*p\_s*i\_s*c\_s*a\_s*e\)\|a\_s*n\_s*d\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|s\_s*\|\_s*\|E\_s*w\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*q\|\\_s*[V]\|w\_s*\|\_s*\|i\_s*K\|\_s*\_s*p\|\_s*B\|M\_s*\%(e\_s*n\_s*i\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*c\_s*e\_s*a\_s*e\|o\_s*n\_s*o\_s*\%(p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*\%(h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|o\_s*t\_s*y\_s*l\_s*e\_s*d\_s*o\_s*n\_s*e\_s*a\_s*e\)\)\)\|\_s*\|\_s*\|\_s*q\|\_s*\|\_s*\|f\_s*B\_s*X\|R\_s*\_s*\|\_s*l\|\\_s*\%([\_s*[gv]\|\_s*[\)\|w\_s*[\_s*O\|[\_s*[CA]\|Z\_s*\%(I\|\_s*}\|\_s*\%(\|j\_s*A\_s*X\)\|\_s*s\_s*\%([\|X\_s*g\)\)\|V\_s*\%(\|b\_s*N\|X\_s*\|A\_s*^\_s*[\|\\_s*[\_s*\_s*X\|I\_s*h\_s*A\|[\_s*[t^]\)\|T\_s*\%([C]\|~\_s*\_s*O\|E\_s*U\_s*\_s*h\|\_s*u\_s*\_s*b\_s*h\|[\_s*\%([h]\|e\_s*B\|X\_s*g\_s*\|Y\_s*f\_s*[C[B]\|}\_s*\)\|b\_s*`\_s*\_s*[\|\_s*\%(N\|_\_s*[\|L\_s*\_s*[\)\|\_s*h\_s*}\_s*C\_s*h\)\||\_s*\_s*y\_s*v\_s*`\_s*h\|O\_s*\%(a\_s*y\|A\_s*\_s*\)\|\\\_s*T\_s*e\_s*X\|\_s*\_s*\|\_s*\_s*\|p\_s*\|s\_s*\%([]\|\_s*E\|j\_s*W\_s*O\|]\_s*[\_s*\|o\_s*b\_s*N\|V\_s*\_s*c\|u\_s*\%(j\_s*\_s*[\_s*X\|Q\_s*[\_s*\|h\_s*\_s*}\|A\_s*j\_s*\)\|b\_s*o\_s*^\_s*h\_s*o\|\_s*\|\_s*\_s*\_s*s\_s*\_s*\_s*\|E\_s*w\|\_s*[w]\)\|T\_s*\%([bcmliahe]\|r\_s*i\_s*m\_s*e\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\|]\_s*[\_s*\|X\_s*T\_s*t\_s*@\_s*C\_s*\|V\_s*\_s*c\|o\_s*b\_s*N\|V\_s*\%(j\_s*\_s*[\_s*X\|Q\_s*[\_s*\|h\_s*\_s*}\|\_s*j\_s*^\|A\_s*j\_s*\|V\_s*\_s*b\_s*s\_s*\_s*O\)\|C\_s*P\|R\_s*[\_s*h\|-\_s*C\_s*o\_s*d\_s*e\|O\_s*E\_s*I\_s*C\|A\_s*\%(C\|I\_s*N\_s*S\|B\_s*L\_s*[\)\|E\_s*L\)\|d\_s*\%([b]\|C\_s*\_s*M\_s*\_s*\_s*\)\)', + \ 'u' : '\%([yhf[le񓴑a؈Ϗ鎽[XDWr䷙\wuќzD鴑ߚXi^R忓LMf~ӏr戉楓]揗w搉S^̗É򃑂k։\uLGQmPOH⣑QmIVߊaXSn|oJU󎜚y팻ʉfژⓐxԋʏϙ܉A]りCD]^@TAmSYv_ZrNTTݗƓZJjJʼnFALnћaLǎ䥟HӉEZpQGˌ̉KꚖoeY^IN҃EUTu]\|\_s*\|\_s*\|\_s*\|T\_s*\|\_s*\_s*\|\_s*\|H\_s*\_s*R\|\_s*\|D\_s*\%(k\_s*[Lj]\|\_s*\)\|\_s*i\|e\_s*\|\_s*\|A\_s*\|y\_s*\|\_s*y\_s*[]\|\_s*\|\_s*[\|\_s*\|\_s*\|\_s*\|\_s*`\|\_s*c\_s*\_s*\|W\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|s\_s*\_s*\|\_s*\|\_s*\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|`\_s*\|\_s*C\_s*\|\_s*\|O\_s*Y\|\_s*\|\_s*[CB]\|\_s*\%(\|\_s*\_s*\)\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|c\_s*\|C\_s*M\_s*\_s*X\|I\_s*}\_s*\|\_s*\_s*s\_s*\\|\_s*\%(p\_s*\|L\_s*\)\|A\_s*\%([X]\|O\_s*\_s*[\|[\_s*\%(V\_s*\_s*\|W\_s*F\_s*\_s*g\|o\_s*\)\|\_s*e\_s*B\_s*\_s*b\_s*g\||\_s*\|b\_s*\%(v\|p\_s*[\|V\_s*\_s*[\)\)\|P\_s*\%(\|\_s*\)\|t\_s*\%({\_s*[\_s*g\|^\_s*[\_s*\|l\_s*b\_s*N\|m\_s*h\_s*w\_s*\%(t\_s*F\_s*A\_s*[\|}\_s*K\_s*W\_s*\)\)\|\_s*\%([^j[]\|g\_s*\%(\_s*\|\_s*q\_s*g\)\|\_s*\%(A\|V\_s*[\_s*Y\)\|v\_s*V\_s*\_s*\|l\_s*X\_s*R\|i\_s*\%(J\_s*C\_s*g\|C\_s*e\_s*b\_s*h\)\|r\_s*L\_s*\%(^\_s*X\|m\_s*\)\)\)', + \ 'v' : '\%([Fl۔ńBrɃv]\|\_s*\_s*\|b\_s*\|\_s*\|\_s*\|`\_s*F\_s*\|\_s*^\| \_s*r\_s*N\_s*g\_s*[\_s*\|\_s*o\|\_s*z\|j\_s*X\|\_s*\|P\_s*^\|\_s*\%(f\_s*B\_s*\|M\_s*i\|j\_s*X\|Z\_s*\_s*\|N\_s*`\_s*\|\_s*L\_s*\_s*[\_s*\|\_s*\_s*[\|[\_s*j\_s*\)\|u\_s*\%(\|]\_s*[\_s*\|T\_s*C\_s*\|l\_s*b\_s*N\|S\_s*[\_s*\|V\_s*l\|\_s*[\_s*O\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*b\|{\_s*\%(X\_s*g\_s*[\_s*N\|\_s*S\_s*\|\_s*\%([K{g^]\|e\_s*\%(b\_s*N\_s*X\|[\_s*[W]\)\)\|\_s*\_s*[\_s*\|\_s*\_s*\%(`\|e\_s*B\_s*A\|^\_s*\_s*[\)\|\_s*[\|R\_s*[\_s*_\|[\_s*\%([gO]\|\_s*g\|h\_s*r\_s*\%(\|\_s*A\_s*\)\|p\_s*\|_\_s*t\_s*H\_s*\|J\_s*\%(\|\_s*X\_s*g\)\)\|L\_s*\_s*u\_s*\_s*\|C\_s*\%([hX]\|W\_s*\_s*[\|V\_s*\_s*O\)\)\|w\_s*b\_s*g\|\_s*\_s*\|\_s*\|t\_s*\%(@\_s*\%(\|h\_s*[\_s*c\)\|H\_s*\%(\|\_s*\%(N\|J\_s*[\)\)\|F\_s*\_s*\_s*[\_s*\)\|E\_s*\%(\_s*\%(f\_s*B\_s*~\_s*[\_s*\|W\_s*\%(~\_s*[\_s*\|[\_s*~\_s*\|I\_s*X\_s*g\_s*\%(N\|b\_s*N\)\)\)\|B\_s*\%(\_s*i\|\_s*X\)\|H\_s*b\_s*J\|C\_s*\%(\_s*X\|\_s*i\_s*[\)\|F\_s*\%(\_s*M\_s*\_s*E\_s*X\|k\_s*X\)\)\|r\_s*\%([AuoXU]\|K\_s*[\|n\_s*[\_s*\|^\_s*~\_s*\|\_s*\%(b\_s*W\|\_s*C\)\|r\_s*\%(A\_s*\|b\_s*h\)\|b\_s*\%(N\|L\_s*[\)\|Z\_s*\_s*e\|N\_s*\%(^\_s*[\|g\_s*\%(\|\_s*[[A]\)\)\|V\_s*\%(\_s*X\|\\_s*\_s*[\_s*Y\)\|\_s*\%([`X]\|\\_s*\|e\_s*[\_s*W\|Z\_s*\_s*g\)\|l\_s*\%(K\_s*[\|O\_s*\_s*b\_s*g\)\|j\_s*\%([[]\|\_s*f\_s*\)\|\_s*[\|G\_s*\_s*`\_s*\_s*\|W\_s*\%(\|b\_s*g\|^\_s*[\|\_s*\%(\|i\_s*\_s*[\)\|\_s*A\_s*\%(\|\_s*C\_s*\%(Y\|[\_s*[\_s*V\_s*\_s*\)\)\)\|_\_s*\|f\_s*I\|\_s*\%(S\|k\_s*[\_s*u\)\|I\_s*\|\_s*W\_s*A\_s*\|B\_s*[\_s*i\_s*X\|[\_s*\%({\|\_s*X\|N\_s*\|i\_s*X\)\)\|x\_s*\%([K]\|g\_s*i\_s*\|C\_s*_\_s*[\|[\_s*\%(\|_\_s*[\)\|e\_s*\_s*\|b\_s*Z\_s*\|X\_s*\%([g^p]\|r\_s*I\)\|N\_s*\%(^\|g\_s*\)\|W\_s*^\_s*\%(u\_s*\|\_s*A\_s*\)\|\_s*\%([B[]\|t\_s*@\_s*C\|T\_s*C\_s*\)\|\_s*\%(i\|V\_s*e\_s*B\|[\_s*i\|j\_s*[JN]\)\|\_s*\%(f\|x\_s*b\_s*g\|_\_s*\|\_s*[\_s*k\|T\_s*\%([\_s*`\|C\_s*\)\|\_s*b\_s*g\)\|m\_s*\|j\_s*[XA]\|l\_s*\%(V\_s*\_s*\|c\_s*B\_s*A\|`\_s*A\|Y\_s*G\_s*\)\)\|o\_s*\%([]\|C\_s*\%([AuI]\|p\_s*[\|^\_s*\%(\|\_s*e\_s*B\)\|L\_s*\_s*O\|U\_s*[\|V\_s*\)\|b\_s*g\|`\_s*J\_s*\|M\_s*i\|K\_s*{\_s*\_s*h\|\_s*\%(i\_s*V\|G\_s*e\_s*B\)\|T\_s*\|X\_s*\%(R\|P\_s*X\)\|J\_s*\_s*X\|P\_s*[\_s*V\_s*\_s*\|L\_s*\_s*[\_s*\|E\_s*`\_s*\_s*[\|\_s*\%(\|G\_s*[\_s*V\_s*\_s*\|\_s*[\|A\_s*\%(u\_s*\|\_s*g\)\|b\_s*h\|f\_s*[\_s*V\_s*\_s*\)\|k\_s*A\_s*c\|j\_s*\%(\|[\_s*\)\|\_s*\%([[]\|\_s*\|\_s*[\|\_s*\%(V\_s*A\|`\_s*m\|^\_s*C\_s*\)\)\|[\_s*\%([SO]\|`\_s*\_s*\|\_s*g\_s*D\_s*[\_s*h\|o\_s*\|{\_s*X\|x\_s*i\|e\_s*B\_s*J\_s*\|T\_s*X\|W\_s*\%(\|j\_s*A\|\_s*\)\|m\_s*\|j\_s*A\|\_s*\_s*g\|~\_s*\%(\_s*I\_s*\|L\_s*\_s*\_s*C\_s*g\)\)\|i\_s*\%(L\_s*\_s*\_s*[\|W\_s*E\_s*\)\)\|u\_s*\%(C\|\_s*\%(h\|b\_s*h\)\|[\_s*h\_s*D\_s*[\)\|V\_s*\%(H\_s*L\_s*L\_s*(\_s*V\_s*e\_s*r\_s*y\_s* \_s*H\_s*i\_s*g\_s*h\_s* \_s*L\_s*e\_s*v\_s*e\_s*l\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\_s*)\|]\_s*[\_s*\|T\_s*C\_s*\|l\_s*b\_s*N\|S\_s*[\_s*\|J\_s*E\_s*-\_s*\|V\_s*l\|\_s*[\_s*O\|I\_s*S\_s*A\_s*J\_s*[\_s*h\|i\_s*r\_s*g\_s*i\_s*n\_s*i\_s*a\|A\_s*X\|e\_s*r\_s*\%(m\_s*o\_s*n\_s*t\|i\_s*S\_s*i\_s*g\_s*n\)\|a\_s*n\_s*a\_s*d\_s*i\_s*u\_s*m\)\)', + \ 'w' : '\%([ɒjYyhȃ҃f[le񓴑a؈鎽[XDW䷙\wuќzD鴑ߚXi^R忓LMf~ӏr戉楓]揗w搉S^̗É򃑂k։\uLGQmPOH⣑QmIVߊaXSn|oJU󎜚y팻ʉfژⓐxԋʏϙA]゜D]^@TAmUSYvZrNTTݗƓZJjJʼnFALnћaLǎ䥟ӉEZpQGˌ̉KꚖoeY^I܉c㘟|͊ϏpԉЍЋƋZǁkYeonm܏Νtsf^]o_rqpciqǘjnȎFGd̘eΘcQC崙NZДʒtሽgfhaŒfZNO֔jclH`b̔i킗ȔgEw]\|\_s*[]\|b\_s*[E]\|\_s*[]\|\_s*\_s*~\_s*_\|\_s*\|\_s*\|\_s*\|T\_s*\|\_s*\_s*\|\_s*\|H\_s*\_s*R\|\_s*\|D\_s*\%(k\_s*[Lj]\|\_s*\)\|\_s*i\|e\_s*\|\_s*\|A\_s*\|y\_s*\|\_s*y\_s*[]\|\_s*\|\_s*[\|\_s*\|\_s*\|\_s*\|\_s*c\_s*\_s*\|W\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|s\_s*\_s*\|\_s*\|\_s*\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|`\_s*\|\_s*C\_s*\|\_s*\|O\_s*Y\|\_s*\|\_s*[CB]\|\_s*\%(\|\_s*\_s*\)\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|c\_s*\|\_s*\|o\_s*D\|\_s*Y\_s*\|\_s*\|i\_s*\_s*j\|(\_s*\_s*)\|\_s*[]\|R\_s*\|Y\_s*z\|x\_s*\|Y\_s*\%(\|V\_s*\_s*c\|\_s*F\_s*\)\|x\_s*\%(\|V\_s*\_s*c\|\_s*F\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*[R]\|\_s*\|a\_s*t\|\_s*\_s*\_s*D\_s*\|\_s*\%(`\|\_s*m\_s*\_s*\)\|^\_s*B\_s*\_s*D\|\_s*\%(\_s*\_s*\_s*E\_s*\_s*\|\_s*\_s*\_s*E\_s*\_s*\)\|u\_s*\_s*c\_s*u\_s*\_s*N\|\_s*\_s*O\|\_s*\%(\|C\_s*X\|b\_s*J\_s*[\|X\_s*\%(\_s*[\|\_s*\_s*O\)\)\|\_s*\%([\_s*X\|\_s*N\_s*\|X\_s*g\)\|\_s*\_s*\_s*\|\_s*\%(b\_s*\%([vp]\|s\_s*\_s*O\)\|C\_s*\%([^g]\|e\_s*B\_s*\_s*O\)\)\|{\_s*\_s*t\|t\_s*\%([[]\|@\_s*C\_s*\|B\_s*\%([\_s*g\|b\_s*`\)\)\|z\_s*\%(G\_s*[C[A]\|[\_s*\|C\_s*\%([\_s*\%(\|\_s*[\)\|b\_s*\%(v\|X\_s*\|p\_s*[\|g\_s*\%(j\_s*[\|}\_s*\)\)\)\|\_s*\%(C\|b\_s*[gc]\)\)\|x\_s*\_s*i\_s*[\|W\_s*\%(S\|N\_s*N\|y\_s*o\_s*m\_s*i\_s*n\_s*g\|O\_s*W\_s*O\_s*W\|I\_s*\%(D\_s*E\|N\_s*T\_s*E\_s*R\_s*P\_s*(\_s*W\_s*i\_s*d\_s*g\_s*e\_s*t\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*p\_s*r\_s*e\_s*t\_s*e\_s*r\_s*)\)\|i\_s*\%(s\_s*c\_s*o\_s*n\_s*s\_s*i\_s*n\|d\_s*g\_s*e\_s*t\|n\_s*d\_s*o\_s*w\_s*s\)\|h\_s*\%(y\_s* \_s*d\_s*o\_s*n\_s*e\_s* \_s*i\_s*t\_s*?\|o\_s* \_s*d\_s*o\_s*n\_s*e\_s* \_s*i\_s*t\_s*?\)\|E\_s*B\_s*\%(u\_s*\_s*E\_s*U\|}\_s*K\_s*W\_s*\)\|e\_s*\%(s\_s*t\_s* \_s*V\_s*i\_s*r\_s*g\_s*i\_s*n\_s*i\_s*a\|b\_s*\%(y\_s*[\_s*W\|\_s*W\_s*I\|R\_s*~\_s*b\_s*N\|T\_s*\%(C\_s*g\|[\_s*\%(o\|r\_s*X\)\)\|h\_s*\_s*}\)\)\|a\_s*s\_s*h\_s*i\_s*n\_s*g\_s*t\_s*o\_s*n\|A\_s*V\_s*t\_s*@\_s*C\_s*\)\|x\_s*\|v\_s*\%(t\|\_s*\|\_s*\_s*\|\_s*\_s*\)\|o\_s*\_s*^\_s*[\|\_s*\%(\_s*\_s*c\_s*u\_s*\_s*N\|H\_s*\_s*t\|B\_s*\%([[]\|\_s*\%(\|w\_s*\_s*\)\)\|F\_s*\%(\_s*_\_s*[\_s*X\|\_s*i\_s*[\|[\_s*o\_s*[\|C\_s*\)\|@\_s*\%(C\_s*[X]\|[\_s*O\_s*i\_s*[\|\_s*_\|\_s*\%(^\_s*[\|L\_s*\_s*[\_s*\)\)\)\|_\_s*u\_s*\_s*\_s*[\|^\_s*\_s*O\_s*X\_s*e\_s*\|T\_s*\%(h\_s*e\_s* \_s*W\_s*o\_s*r\_s*l\_s*d\_s* \_s*W\_s*i\_s*d\_s*e\_s* \_s*W\_s*e\_s*b\_s* \_s*C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\)\)', + \ 'x' : '\%([HFDB@V~x]\|\_s*[]\|b\_s*[HFDB@]\|\_s*[]\|V\_s*\_s*\%(z\_s*\|t\_s*H\_s*\)\|w\_s*\%([]\|f\_s*[C[]\|\_s*\_s*\_s*\|r\_s*T\_s*C\_s*Y\|k\_s*\%(\_s*\_s*\|T\_s*C\_s*Y\)\|E\_s*B\_s*\_s*h\_s*E\|[\_s*\)\|X\_s*\%([]\|C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|f\_s*[C[]\|P\_s*S\_s*(\_s*e\_s*X\_s*p\_s*a\_s*n\_s*s\_s*i\_s*o\_s*n\_s* \_s*P\_s*a\_s*s\_s*s\_s*i\_s*n\_s*g\_s* \_s*S\_s*t\_s*y\_s*l\_s*e\_s*)\|S\_s*T\_s*C\_s*Y\|l\_s*i\_s*b\|L\_s*\%(i\_s*s\_s*p\|T\_s*C\_s*Y\)\|e\_s*n\_s*o\_s*n\)\|W\_s*I\_s*\|[\_s*\%(r\_s*E\_s*X\|\_s*\%(b\_s*N\_s*X\|O\_s*\_s*t\_s*B\)\)\|n\_s*r\_s*G\_s*\|U\_s*\%(\|r\_s*G\_s*\)\|L\_s*\%(V\_s*\%(\|\_s*\|\_s*g\_s*[\_s*\)\|Z\_s*m\_s*\|T\_s*\_s*\%(`\_s*\|^\_s*\)\)\|E\_s*x\_s*t\_s*e\_s*n\_s*s\_s*i\_s*b\_s*l\_s*e\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|N\_s*\%(V\_s*[\|\_s*X\_s*|\_s*X\_s*g\|Z\_s*\%(i\_s*L\_s*X\|m\_s*t\_s*H\_s*\)\|U\_s*\_s*B\_s*G\|T\_s*\%(C\|\_s*\%(g\_s*X\|`\_s*b\_s*y\|e\_s*B\_s*b\_s*y\)\)\|\_s*X\_s*}\_s*X\)\|G\_s*\%(N\_s*X\|b\_s*N\_s*X\)\)', + \ 'y' : '\%([։ߕ֍HVşꔗ؊ZݝgZ|~}ĔϑbbщxX\ccUiFg`ᇞ՗x揜JLȞ@fuꡜys@Tᘟ~m籝Xyꢗqsi^wgjsfgt匍roחldpnїwzmÏh^S焛@㏜棟baǗ_P`]rĔS㿉r\\QPaoKllPI^椂㒏̎͒oɒt沖LuVKᛮ|w䓎樏ଉw亗WzFCQޗCGEPZXNOSЗ[HI֗FYJLkሖ@gVhO䥝R埙`A懝|MgJ䲃ꍘcUTn翔䑌恍ݍrxÉj囚|dQU|軗ƑBd{Nj佈䆍mnؐFAtF泌ÌމLdƜјJiꌒՓkvɔžo֌yME|ځe퐈M臐YOΖZ}xא򌵉MՁO䗚P{bw~N}zcc硉Ɏh䕟JsW]bK\Tฐ]rmПȈZԈTDMΚICm覉@uBAAޛjHوΊֈÈ1PDyIDR۔џʈዏHƍ֋Uhwψ͉]}ubv]Ό≝gМ@ES盈BΟݑPR҈ȊUגߘߛږˆ̈،܈Η͜}Ėˈԍs਒_ˑޗǓo֗DK~䏈ӈۈ؈ًeԄ`tcbّqۈŔsMlhE`_ʗSQna_–zl˗DyيVꞟKoZމvNuk欎淏kqstrRКݓ@D洗{kJїT׈ՋxۍN❔JĜ\̖tj熔W쉮ƕaߖˎܓi댭ውƔE~ₙuE~vFJYC\zy]\|\_s*[ղ]\|b\_s*[C]\|\_s*[䂢]\|\_s*\_s*b\|^\_s*\_s*b\|I\_s*\|\_s*\|B\_s*\|I\_s*\|4\_s*\%([“]\|\_s*\|\_s*\)\|\_s*\|m\_s*j\|\_s*\|\_s*\|F\_s*\|\_s*\|\_s*[q]\|j\_s*\|h\_s*L\|@\_s*\|V\_s*\|\_s*[j]\|\_s*[q]\|i\_s*\|W\_s*\|8\_s*\|\_s*\|t\_s*\%(\|^\_s*[\_s*\)\|\_s*\|\_s*\|\_s*\|~\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|S\_s*\|L\_s*i\_s*l\_s*i\_s*\%(o\_s*p\_s*s\_s*i\_s*d\_s*a\|a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\)\|\_s*\%(Y\|\_s*\)\|\_s*M\|\_s*\|\_s*\|\_s*\|E\_s*\%(u\|\_s*[\_s*\)\|a\_s*\|J\_s*u\_s*\%(l\_s*i\_s*a\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|n\_s*c\_s*a\_s*l\_s*e\_s*s\)\|c\_s*J\|c\_s*\|G\_s*s\|\\_s*Z\_s*\|Q\_s*q\|G\_s*\|\_s*\_s*\|\_s*\|\_s*\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*G\|\_s*\|\_s*t\_s*\|5\_s*[“]\|T\_s*[“]\|\_s*E\|r\_s*U\|\_s*\|\_s*Y\|\_s*[\|\_s*\|~\_s*\|\_s*\_s*\|{\_s*\|o\_s*\|\_s*g\|Y\_s*[q]\|h\_s*[‘]\|@\_s*\|U\_s*\%(\|^\_s*[\_s*\|r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|E\_s*[cR]\|d\_s*\%(`\_s*r\_s*s\|u\_s*d\)\|C\_s*\|]\_s*[oZ]\|\_s*\|\_s*q\|_\_s*\|\_s*\_s*\|\_s*r\_s*\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|\_s*\|\_s*\_s*\|r\_s*\|s\_s*\_s*\|o\_s*[E]\|\_s*[Wk]\|C\_s*[؎Q]\|\_s*\\|\_s*\_s*[ΒY]\|_\_s*F\|e\_s*[]\|p\_s*\%([꓍]\|g\_s*\)\|\_s*\_s*\|\_s*[ȉ]\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|s\_s*[”@]\|\_s*{\|\_s*\_s*\|\_s*\|\_s*L\_s*n\|\_s*\|\_s*[c]\|R\_s*a\_s*f\_s*f\_s*l\_s*e\_s*s\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\|\_s*\|V\_s*\\|`\_s*G\|\_s*{\_s*\_s*\|\_s*a\|T\_s*\%(h\_s*e\_s*l\_s*i\_s*g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*o\_s*c\_s*h\_s*o\_s*d\_s*e\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|M\_s*y\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\_s*t\|\_s*\|A\_s*r\_s*a\_s*c\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*\%(o\_s*t\_s*e\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*c\_s*i\_s*p\_s*e\_s*s\)\|a\_s*l\_s*m\_s*a\_s*l\_s*e\_s*s\)\|\_s*q\|\_s*[j]\|x\_s*\%([k]\|V\_s*\_s*c\)\|G\_s*\%(z\_s*o\|t\_s*Q\_s*j\_s*[\|\_s*\_s*@\_s*\|j\_s*Z\_s*C\|[\_s*\)\|\_s*C\)', + \ 'z' : '\%([󉀉ꑹ㔛mґXfhّۑY\]萊AK㿑R䒑UWN征͑V陑TPQfOS␨ҐƐŐUӂžlb齕AZB@笐CtÓ|~D}ߍ󓈎ȓǎwxcH苎ҍ׎l㒼ÓKHԘᶙbiu@vސnՉ`rxosqwptlŏғ䴞`䥝募tJ珊RPԟiUㅏ{o媝mh鈐YtY竐jg@ݖÏꏗ`~]꞊󝵏GAژhGQ榜휵@uQxhmnpqmm⢙Ï|⡓՟~[x{䤏zy}}汎GEsn𘸏^F_`Oca_Y[b]\Zedm莣^y~iJ玎Ȓn􎤎~ImVkqHjaZd䢎mV␷╍蛽NM赞ƎLGRZQSₜ͛؜kO槎SbΜ͎acZːčϙ܍ލߍݍoUY][GwY]ZUW[xĄHz]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[][YWU]\|\_s*[]\|\_s*\|\_s*\|o\_s*\|\_s*[q]\|\_s*\|\_s*\_s*\|\_s*\|O\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*p\|\_s*o\|C\_s*@\|m\_s*\|\_s*\|k\_s*[ߌY]\|\_s*\|\_s*s\|F\_s*i\_s*g\_s*u\_s*r\_s*e\|\_s*\|G\_s*\%(\_s*\|p\_s*\)\|D\_s*y\|f\_s*\%(\_s*\|p\_s*\)\|x\_s*x\|\_s*\|Q\_s*\|2\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*q\|J\_s*\%(I\_s*S\_s*R\_s*[\_s*h\||\_s*b\_s*v\|R\_s*\_s*\_s*{\)\|\_s*q\|b\_s*\_s*\_s*\_s*\_s*\_s*M\_s*h\_s*p\_s*\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|[\_s*\%(\|\_s*\)\|`\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|R\_s*l\|y\_s*_\|\_s*\|\_s*\|\_s*\|\_s*r\_s*\|\_s*v\|\_s*\|\_s*\|\_s*\|\_s*[@S]\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|i\_s*\%(\_s*[\_s*O\||\_s*b\_s*v\|t\_s*m\_s*j\_s*n\)\|\_s*q\|\_s*\|P\_s*\%(Q\|O\_s*[i]\|P\_s*\|U\_s*i\|W\_s*\)\|t\_s*\|\_s*\|R\_s*\|1\_s*\%(0\|1\_s*\|8\_s*\|2\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*u\|e\_s*\|\_s*\|\_s*\|\_s*{\|U\_s*\_s*\|\_s*H\|\_s*\|T\_s*\%(\_s*\|\_s*|\_s*[\_s*j\_s*\|\_s*S\_s*T\)\|Z\_s*\%([r]\|i\_s*\%(r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\|n\_s*c\)\|K\_s*\_s*_\_s*\|o\_s*b\_s*t\_s*@\|I\_s*P\_s*t\_s*@\_s*C\_s*\)\|V\_s*\%(^\_s*[\_s*\|I\_s*\%(\|j\_s*\%(X\_s*g\|Y\_s*\)\)\)\|y\_s*\%([]\|\_s*\|\_s*\_s*\_s*\)\|`\_s*\%(N\_s*\_s*X\|A\_s*m\_s*[\_s*[\|\_s*[\_s*\_s*\%(q\|b\_s*q\)\|\_s*\_s*_\_s*b\_s*V\_s*\|S\_s*C\_s*l\_s*\_s*\_s*C\_s*[\_s*\)\|c\_s*\%(@\_s*\%(\_s*g\_s*D\_s*X\_s*g\_s*\|C\_s*g\)\|F\_s*\%(i\_s*[\|b\_s*y\_s*\_s*\|\_s*}\_s*b\_s*g\)\|B\_s*\%(N\_s*\_s*X\|^\_s*[\|[\_s*O\_s*\_s*[\|\_s*\%(o\_s*\_s*\|}\_s*[\_s*}\_s*\)\|S\_s*C\_s*l\_s*\)\)\)', + \ 'A' : '\%([ݕNҊ{b]毛^w܏㦚@oC粕ӓJlVȌlˆ^Мۜ{Qz鸈WEB{MQ榓kw{\N}Ho{tVpA֔\HՓaڏS[矏NaWo㻓֏~ĔMؒg禈Ŋ[NΎҕae}yRXvI\॑ŐVaz\eX~dVEYэʊ늿ߎӕT瑀剕ՕP]JÓV쉐˖ԋY͈b般HꙌǖsNL[ӟ䈮NzPjEDɏ͏W쏺Hq蕚V襕B\͈ԑ~㪌ZQsň}Ĉǝƈ䒩툤@rb`~qgݝю鈩[脝ōCK暖\ؐԙzЕɈŒaS㈢ҌݕJ숫rG}Lj򈡈}[YޝKgOc&ȁ_ڋ͋́ˁ܌WāNLMOf``Ap@A]\|\_s*\|\_s*\|\_s*\|\_s*\|Z\_s*\%(n\|i\_s*n\_s*c\)\|\_s*q\|\_s*\|E\_s*n\|f\_s*\|\_s*\|M\_s*V\_s*\|\_s*T\|\_s*\|Z\_s*q\|\_s*\|l\_s*\|\_s*\|\_s*\|^\_s*\|\_s*\|\_s*w\|\_s*[]\|\_s*p\|\_s*\|\_s*\|L\_s*a\_s*r\_s*d\_s*i\_s*z\_s*a\_s*b\_s*a\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*{\|\_s*\%(\|\_s*q\)\|\_s*\%(\|\_s*\_s*\_s*\_s*\)\|H\_s*a\_s*b\|H\_s*a\_s*l\_s*o\_s*r\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|\_s*F\|\_s*\|\_s*`\|^\_s*\_s*\_s*\|\_s*\|\_s*\|D\_s*`\|a\_s*\%(t\_s*t\_s*o\|c\_s*c\_s*e\_s*n\_s*t\)\|\_s*[K]\|\_s*G\|\_s*[mF]\|\_s*x\|\_s*\|\_s*\|\_s*\|p\_s*\%([ۓc]\|\_s*p\|\_s*\)\|\_s*[ɁX]\|E\_s*\%(s\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\)\|I\_s*\%(r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(d\_s*b\|A\_s*h\_s*\_s*X\)\|D\_s*J\_s*[\_s*h\|C\_s*\%(^\_s*O\|J\_s*[\_s*h\)\)\|h\_s*\%(o\_s*d\_s*b\|b\_s*\%(^\_s*O\|J\_s*[\_s*h\)\)\|\_s*~\|\_s*\|c\_s*\|n\_s*\_s*\|C\_s*[^lm]\|R\_s*u\_s*b\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\_s*a\_s*\|\_s*\|\_s*n\|\_s*[ꆔn]\|M\_s*a\_s*l\_s*v\_s*a\_s*l\_s*e\_s*s\|g\_s*\_s*v\_s*\_s*A\|\_s*\| \_s*A\_s*N\_s*V\_s*A\_s*\|q\_s*f\|\_s*f\|\_s*s\_s*\_s*x\_s*Z\_s*p\_s*\_s*\_s*\|\_s*\|\_s*Y\|\_s*\|G\_s*o\_s*l\_s*d\|\_s*\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*@\|a\_s*\_s*\_s*@\)\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|Z\_s*\_s*g\_s*L\_s*b\_s*c\_s*l\|S\_s*\%(b\|i\_s*l\_s*v\_s*e\_s*r\)\|g\_s*p\_s*\_s*\\|\_s*p\_s*\_s*\\|Z\_s*@\|\_s*\_s*\_s*\|I\_s*\%(\|M\_s*\_s*X\_s*^\_s*\|h\_s*\_s*C\|\_s*O\_s*X\_s*g\_s*\_s*[\_s*\|\_s*\%(g\_s*L\_s*[\|^\_s*\%([[i]\|l\_s*\%([\_s*g\|C\_s*g\)\)\)\|[\_s*\%([NKTg]\|j\_s*\_s*O\|L\_s*V\_s*\|u\_s*\_s*[\|o\_s*[\_s*h\|x\_s*\_s*W\_s*\|M\_s*\_s*X\_s*\%(g\|^\_s*\)\|]\_s*\_s*k\|X\_s*\%(`\_s*\|e\_s*B\_s*\|^\_s*[\|g\_s*\%(\_s*A\|\_s*\_s*A\)\)\|h\_s*\_s*[\|W\_s*\%([F[]\|I\_s*\_s*W\)\|f\_s*B\_s*\%(I\|G\_s*\_s*X\|V\_s*\_s*\|g\_s*\_s*A\_s*\)\|^\_s*\|\\_s*\%(\_s*e\_s*B\|\_s*C\_s*Y\)\|Z\_s*\_s*e\_s*B\_s*b\_s*N\|\_s*\)\)\|z\_s*\|o\_s*C\_s*g\|n\_s*\_s*}\_s*Q\_s*h\_s*\|\_s*\|l\_s*H\_s*\%(\_s*\_s*\|m\_s*\\)\|C\_s*\%([\_s*W\_s*X\|I\_s*\|\\_s*b\_s*v\)\|}\_s*\_s*h\_s*D\_s*[\_s*N\|\_s*\%(z\_s*\|\_s*\|\_s*p\)\|t\_s*^\|\_s*p\|G\_s*\%([jAC[]\|b\_s*`\|\_s*\%(h\_s*\_s*\|W\_s*F\_s*\%(\|\_s*b\_s*N\)\|[\_s*\)\|\_s*A\|I\_s*\_s*A\|X\_s*e\|v\_s*\_s*\)\)', + \ 'B' : '\%([ݍxftݖv{}~Ϟsr`ڝpؖnlmqbQ쟂ۙR廖ge䛖OE庈ꆉK㦖RWaXZU`YNϛ˖Sc]fhT^ddە_@W敖͕ꊱVGJڙkK럑㰙pgꈕ̕VՙAğ~܍燙ᾙjוؕ糉•粂בD[kuqJڒܐ[W᳓ؐߕܖܘŕhᕷwŕsFU򐁕xᕔF~o@ԕ捐lLJxʕTCZz[ߞ㢛mpCޜrF{qn֛焕S蓔Ialߕ[Leὕdcb`_aΓZrۖoɔzeX]䛇gє䊑ыIs@[bV鯝UAjcUPWєm\e}ޔȉSit䕔|ꀊL{~}ŝםf\ҔԖ_Jmה”dHݔ֔ӔՔԔؖ따ntklyHŐmn\΁gۉ~ba|_攞{onmopaurAqxB]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[{xuro]\|\_s*[ڂׂԂт]\|\_s*\|\_s*\|A\_s*\|P\_s*a\_s*e\_s*o\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*Z\|\_s*\|r\_s*r\|\_s*\|\_s*\|\_s*_\|\_s*_\|\_s*\|E\_s*\|\_s*\|\_s*C\|\_s*\|X\_s*[j]\|R\_s*\_s*O\|F\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|z\_s*c\|\_s*\|u\_s*\%(\|l\_s*b\_s*N\|V\_s*l\_s*}\)\|\_s*q\|t\_s*q\|\_s*\|L\_s*[O]\|\_s*\|V\_s*A\_s*O\|\_s*[ĘU]\|b\_s*i\_s*o\_s*t\_s*o\_s*p\_s*e\|\\_s*D\|\_s*[D]\|\_s*\|o\_s*\_s*\|\_s*\|\_s*\|S\_s*a\_s*n\_s*t\_s*a\_s*l\_s*a\_s*l\_s*e\_s*s\|h\_s*\|\_s*[q@]\|\\_s*\|\_s*[Žq]\|\_s*\|\_s*\|\_s*q\|c\_s*\_s*\_s*\|b\_s*\_s*\|R\_s*o\_s*s\_s*a\_s*l\_s*e\_s*s\|K\_s*N\|\_s*q\|\_s*\%([ъyJ]\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|A\_s*n\_s*n\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*[]\|f\_s*\_s*\|v\_s*\_s*R\_s*M\|\_s*\_s*\|I\_s*[\_s*g\_s*o\_s*C\|\_s*[b]\|t\_s*@\_s*S\_s*b\_s*g\|w\_s*i\|k\_s*\|y\_s*\%(L\_s*\|e\_s*\_s*M\_s*E\_s*X\)\|L\_s*f\|C\_s*M\_s*\_s*X\|z\_s*E\_s*f\|\_s*f\)', + \ 'C' : '\%([a|ҜDޏns}laʗۗⵘᶐsЌfَřbIziꑍC麌Z欉䓚৙}Yɍ`nXMȍ뜝k՞ߌ匣ӍeWEQLm՘iQf肝Kਗ਼Ჟ騟}{㝛ŘҟL`tiBRH{ൟHs秝nn˝JܔXLJyߛb}褜rRt莘mE硍hklKᦜnK}֞\@囍yෙΜˍ[⠍xuXSe倘Ji^V@AWGDT`ᩍBԍp]PIzt_kOjRwuPaI|qFXZsmrcDޞJܛ͞wLl܍WێЛZÖs烌gםsؑeuČٌ̟]|Vx֒绌і嚙hʉznjԌך➳Ҕȏ˗Zꉟh@ZXNÖZ驒LLQkŚTGi֙↝BގEِېߐCGዙН[Tאɐ͐ȐǝA⣛p蔞tdCNӟ׈ߙEᝎax㙘A_baJஓϛƘjbHⳙAGSL⒑WsrDJAL񙒐枙@ۑMHlFKDG@Bh坡ǑNdDI扙|œҝᝩ⫟ŐꎖvRΐyH`ՐǍU}[҂zKMzⱟJ㖍IHEzboxܗAϕDBӏ~B䱌sZY㙬ᯞӛM֌NvK@{^Z퐾^鶔ňʈUÑqC~XVTRUWS܉_wo^鿌~GF䇚`pY۞ƌIӘޚPMuoӍcqvE|―ꋀῙ܌JɍCg{mX؍Hᜁv㜜ҙg电M˂捃ABPDY`LZ迓ӞxZlWȓGFaƎb乗MEΕsCFnD㈵㦋s]Ŗl^⚑A潓gߞΖ儞bɖΜ臐wpd[g謎姎^GNH˒ΐÎᕹRK\ސˌKŽKoqҍtϔOӎ͚̍͟bAjP֎yࡐ̝咙ݐ┐Ԏ^ېΎގڎYώՎˎΎɎԎߎЈޝiSGCဋÎft偛WVz题Efiglhk{蜕婏oFT碏VhqhFJ娏QK榚S酝nSXKUڏMGjaENODCALRTWIHB@M\᭚忏w{vxs⡏urfݐZuVꐚpy曐P]AUjJfY`Ds橝ΐaO凓cjcѐUaNfdCkXĐLTQWi[RMebI\S^V΋nZo䜏_י|䓏w򏎏ҟm䀛uLЏ縐מ⪎™דɜvRIߜcB_џnՈ䐯B辑[K頏[␏K♏яҁui]疏֏ӐԚА躐ϏUJnސŜ܏ߏᏏُGᏧଞ͏ǏɏЏˏ暏ΏďƏ͏ڏ؏ɏTl\egp@CܑDI冐BGAHEn❎omowvLUhnыŎᎊtr@{wϚ`iАyэi@EJX拎}泛nyoNZyٝfj{~|{oߘIXB]KVgupikl藘ʛƓj⏎sꏎÎ~˔`Œsyd@؎䢊YoumeᘊyNJr݊jƌyĈ呁eAiMʕrPTMvᚌȍfjqseghpotr鹜NJDRUğdᥛz㕖pȌڋAԓ雛_Bߗދȋ\Ί͏ۋwdTezJxŌ`ӌ^HȔXR㎎CPtqKŠ锯閟@Њ|嶝^艔噞J㹊{歒Se顊j舊sFጐdP}gya`fSWmeO]ݑڙ̛ň@`FOP\[gಉGh󓂞Њ~yۉ}qɐ͘V،~ऐc͌bwuxviXÕLꖊGKƏ̓C魜SRД߈Kv֓S哑tݓkLSښ湛誝ᙚٚ]d䡜QIvn跏ʜh\frnzyklmkgcstio݉Bvldjߊgqupm嵚W~[ZB͙GrqʟD䠜j珞iƙd^񔐘\X{Ž\箊IؘrH_j~F׊@EmLGDŊAKJCI䯘Yᷛep՟bNボ錝AQaT㼛㻛fW`c洟a⻝qj鉙ɞ쏁㣎V늬Mϊ䅟jFrȟ綝mlb˙_xpᒔcg⭊|}ۚۊ@يΞ؊󊩐Ҋ@ʊŞ̊ɊƜAL萊ъŠԊ׊ՊĚ^ÊNJ֊͊ϊwxsqPgӊea㞎ʼnؚĝ̎dˉZΓٌq҃斉vqЎx|ۉԊQ|ўh`ܛ嘉]Ǝ؉㟋zɉÈՉʜF荊ЌCa{`ekJm”ޚ썁͉̉ώoז◚DSlόUґݙ͉щݙljӌT旞g~߉惕砌ĉጜƏ戉Č͉ɂEc‹āىqSGBJHxw[`TIr|RKVFO^QU\ZAYzM{Pst}NLvpyu@C]E_~D􄩄~ԃqXWہACFNՋ\ȐߕϐڃJRVZbC]\|\_s*[]\|b\_s*[RZNVJ]\|\_s*[q]\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*y\|\_s*m\|\_s*F\|\_s*\|\_s*\|S\_s*\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|\_s*C\|\_s*\|A\_s*\%(r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|p\_s*i\_s*a\_s*l\_s*e\_s*s\)\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|\_s*\|}\_s*\|\_s*@\|O\_s*[ȍ]\|\_s*[ĘU]\|P\_s*y\|\_s*\|\_s*[X]\|~\_s*\|\_s*\|S\_s*[Z]\|\_s*h\|9\_s*[]\|^\_s*{\|Q\_s*O\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*|\|T\_s*\_s*\|T\_s*\|\_s*\_s*\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|Z\_s*\|n\_s*_\|s\_s*q\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|V\_s*\|]\_s*\|f\_s*[l]\|\_s*A\|s\_s*[mE]\|\_s*\|L\_s*a\_s*\%(u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|b\_s*i\_s*a\_s*t\_s*a\_s*e\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|\_s*\|\_s*\|~\_s*\|\_s*t\_s*\|\_s*\|\_s*_\|\_s*Y\|\_s*\|\_s*\|I\_s*\%(s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\)\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|`\_s*\|]\_s*[X]]\|\_s*\%([ƗuʑɎ茓]\|\_s*\|[\_s*\|\_s*\)\|\_s*\%(X\_s*\_s*\|\_s*\_s*\)\|7\_s*\|V\_s*\|\_s*\|4\_s*\|S\_s*[]\|R\_s*{\|\_s*\|h\_s*t\|\_s*[ʈ]\|\_s*\|O\_s*\%(\|\_s*\)\||\_s*[“]\|A\_s*[o]\|\_s*\|B\_s*r\|\_s*[NY]\|\_s*[]\|r\_s*[ꏎ]\|Q\_s*\|\_s*Y\|b\_s*\|c\_s*e\|\_s*\|M\_s*\%(e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|u\_s*s\_s*a\_s*l\_s*e\_s*s\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|S\_s*\%([eg]\|p\_s*e\_s*r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*i\_s*t\_s*a\_s*m\_s*i\_s*n\_s*e\_s*a\_s*e\)\|\_s*\%(\_s*{\_s*\%(I\|\_s*I\)\|\_s*\_s*a\_s*\_s*W\)\|\_s*Z\|\_s*q\|\_s*\|z\_s*\|R\_s*\%(C\_s*o\|\_s*q\|z\_s*\)\|j\_s*\|\_s*\_s*\_s*\|r\_s*C\|b\_s*[]\|\_s*\|}\_s*\|\_s*\%(\|`\_s*\)\|\_s*[]\|\_s*\|V\_s*\%(\|l\_s*\)\|\_s*q\||\_s*\_s*\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*[]\|\_s*r\||\_s*\|\\_s*\|]\_s*\|\_s*q\_s*\|\_s*[ay]\|\_s*\|\_s*\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*R\_s*q\|\_s*\|\_s*\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|o\_s*\%(t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\|d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\)\)\|y\_s*\|A\_s*g\|k\_s*k\|@\_s*\|\_s*t\_s*\|\_s*\%(\|q\_s*\)\|\_s*\|\_s*\|Z\_s*\%(c\|C\_s*\)\|\_s*\|\_s*[r]\|\_s*\%([_]\|C\_s*\|\_s*s\_s*\_s*\_s*w\_s*Z\_s*p\_s*\_s*w\)\|C\_s*[G]\|(\_s*\_s*)\|\_s*\_s*\|\_s*\|\_s*\|m\_s*\%(\|\_s*\)\|~\_s*\_s*\|o\_s*c\|Y\_s*t\|_\_s*o\|\_s*\|B\_s*\|A\_s*\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|\_s*\_s*\_s*\_s*\_s*u\|\_s*\_s*\_s*e\_s*N\_s*m\_s*T\_s*C\_s*G\_s*\_s*X\|\_s*\|X\_s*\_s*[\_s*Y\|\_s*e\|g\_s*\_s*\_s*v\|c\_s*\%(e\_s*n\_s*t\_s*i\|r\_s*e\_s*s\_s*c\)\|\_s*[{v菻]\|\_s*G\_s*\_s*\_s*Z\_s*b\_s*g\_s*v\_s*Z\_s*@\|T\_s*\%(\_s*`\_s*[\_s*\|G\_s*\|C\_s*\%(g\_s*J\_s*C\_s*\|\_s*X\|N\_s*\%([]\|\_s*\%(\|b\_s*N\)\)\|{\_s*\%(E\_s*Y\|[\_s*O\)\|o\_s*\%([\|l\_s*e\_s*B\_s*\%(b\_s*N\|N\_s*X\)\)\|\_s*\_s*[\_s*\|_\_s*[\|t\_s*@\_s*[\|l\_s*\_s*A\)\|[\_s*\%(e\_s*B\_s*t\_s*B\_s*P\_s*[\_s*V\_s*\_s*\|N\_s*\|J\_s*\%(X\|\_s*X\_s*N\_s*\%(\_s*C\_s*u\|\_s*v\_s*V\_s*\_s*\)\)\|L\_s*\%(\_s*\%(\_s*[\|\_s*[\_s*\%(^\_s*[\|V\_s*\_s*\)\)\|b\_s*g\)\)\)\|}\_s*h\_s*\_s*X\|\_s*\|P\_s*\%([AC]\|t\_s*F\_s*E\_s*X\|v\_s*X\_s*g\_s*\_s*[]\|`\_s*\_s*b\_s*v\|\_s*\%(^\_s*E\_s*\%(\|\_s*X\)\|u\_s*\_s*b\_s*W\)\|[\_s*\%([LWuvX]\|N\_s*E\_s*H\_s*[\_s*N\|\\_s*\|^\_s*\_s*\_s*O\|p\_s*\%([\|r\_s*\_s*e\_s*B\)\|V\_s*\_s*O\|\_s*[\)\|\_s*\%(g\|x\_s*\_s*X\|e\_s*B\_s*b\_s*N\|r\_s*\%(\|[\_s*j\)\)\|~\_s*\%(J\_s*\|X\_s*g\)\)\|L\_s*\%(\_s*m\_s*\|v\_s*\_s*X\|P\_s*\|\_s*\%([C[A]\|\_s*F\|r\_s*\%(Y\_s*\|X\_s*\)\|\_s*\%(X\|b\_s*g\)\|\_s*[\_s*^\_s*[\|\_s*\\_s*[\|\_s*\%([\|E\_s*\|A\_s*X\|I\_s*V\_s*e\_s*B\)\)\|A\_s*\%(\|[\_s*\|\_s*e\_s*B\)\|`\_s*\|g\_s*T\_s*\|\_s*\|}\_s*C\_s*\|b\_s*J\|\_s*[\_s*g\|\_s*\%([hpXu]\|f\_s*\%(B\|\_s*b\_s*N\)\|r\_s*\%([Al]\|e\_s*\%(B\|[\_s*V\_s*\_s*\)\)\|x\_s*c\|o\_s*\%(\_s*[GA]\|\_s*[\)\|g\_s*\|V\_s*[\|T\_s*\_s*\|^\_s*s\_s*\|s\_s*\%(g\_s*\|^\_s*\%(\|\_s*Y\_s*\)\)\|v\_s*\%(\|V\_s*\_s*\|e\_s*\|`\_s*\)\|Z\_s*\%(C\|\_s*[\_s*\)\|b\_s*\%([cg`v]\|T\_s*o\|X\_s*\|V\_s*\%(\|\_s*O\|\_s*\%([\|u\_s*\)\)\)\|j\_s*\%(I\_s*\|X\_s*^\_s*[\)\|i\_s*\|m\_s*\%(\|[\_s*\|s\_s*[\)\|~\_s*\\_s*[\_s*\|\_s*\%(\|\_s*\%(\|b\_s*g\)\)\|\_s*\%(\|E\_s*F\_s*C\|\_s*\|\_s*C\_s*[i]\|b\_s*g\)\|\_s*b\_s*g\|\_s*\%([R[A]\|o\_s*[\|u\_s*\_s*[\_s*V\_s*\_s*\|b\_s*W\|\_s*O\)\|Y\_s*\)\|\_s*\%(R\|X\_s*g\|V\_s*^\_s*\)\)\|\_s*p\|`\_s*\%([^}A]\|\_s*\|\_s*[\|\_s*h\|\_s*j\_s*[\|R\_s*\|b\_s*\%([vN]\|e\_s*\_s*I\|^\_s*S\_s*\)\|L\_s*\%(\|[\_s*^\)\|\_s*\%(A\_s*u\_s*\|[\_s*C\_s*\_s*K\_s*\)\|[\_s*\%([tgvNY]\|p\_s*[\|^\_s*[\)\|F\_s*\%([XJRA]\|U\_s*\%(\|[\_s*\)\|\_s*\%(j\_s*[\|V\_s*[\|m\_s*u\_s*C\_s*\)\|\_s*\%([\|X\_s*g\|b\_s*V\_s*\|\_s*\)\|\_s*\%(X\_s*^\|\_s*R\_s*t\)\|r\_s*`\_s*F\_s*t\|_\_s*[\|`\_s*F\_s*\|b\_s*\%([gNJ]\|L\_s*\_s*O\)\|C\_s*\%([X]\|j\_s*[\|T\_s*[\|V\_s*\_s*O\)\|[\_s*\%(\|U\_s*\|z\_s*t\)\)\|\_s*\%([IthCRE]\|c\_s*l\|N\_s*\|v\_s*^\_s*[\|p\_s*e\_s*B\|y\_s*\%(\|b\_s*N\)\|`\_s*\|l\_s*\%(\|\_s*[\|\_s*\_s*O\)\|b\_s*\%([Ng]\|s\_s*[\|v\_s*\%(}\_s*\|\_s*\)\)\|^\_s*\%(\_s*[C[]\|\_s*\_s*O\)\|\_s*}\_s*[\_s*X\|\_s*\_s*W\|\_s*\|[\_s*\%([`^gW]\|r\_s*\|~\_s*\%([\|\_s*O\)\|\_s*[\|\_s*\%([YX]\|g\_s*\)\)\|\_s*\_s*S\)\|\_s*\%([R]\|C\_s*X\|\_s*X\_s*L\_s*[\|[\_s*\%(N\|T\_s*[\|J\_s*[\|L\_s*\_s*O\)\|S\_s*\|b\_s*\%(v\|s\_s*[\|p\_s*[\)\|\_s*\\)\)\|\_s*W\|\_s*\|\_s*\|\_s*\%(\|Y\_s*\_s*`\_s*\)\|p\_s*\|c\_s*\%(@\_s*[\|B\_s*\_s*\|F\_s*\%([\|\_s*j\_s*[\|\_s*\)\)\|Y\_s*f\)', + \ 'D' : '\%([다hbraךǏtBN{cjۓÓ̊ӓՓœǙI~UkNӝ^}X駁́ߓԓӓVW֓W{ޙxgz𗯗Z^mvwˎ~yǎF≓BHDsMϙub\BadƂŃdߐhȍjΓ`snˌg˒ݕtВËl}ϒޘAÃaߗ͒nIL֓|Z睏JNMӋҋxJيړ_xԒ|FڒDEU璒iNՕnm聄Гْ̖U[ghkifcdejǞ񐆘Ǒ䶝\śP֑蚑ʑ[TÞSɚkoĜ팚[Pc˂DACd\.Ecgh\BƂch_WDf„tD]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[hfda_]\|\_s*[ǂłÂ]\|\_s*\|s\_s*X\_s*\|\_s*\|S\_s*a\_s*u\_s*r\_s*u\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|C\_s*\%(u\|o\_s*p\_s*p\_s*e\_s*r\)\|\_s*V\_s*\|\_s*\|@\_s*\|\_s*\|Y\_s*\|S\_s*t\_s*\|\_s*\|\_s*\|\_s*[t]\|\_s*\|\_s*\|\_s*[I]\|\_s*\|m\_s*b\|x\_s*\|\_s*q\|\_s*q\|\_s*\|\_s*K\|\_s*\|\_s*B\|R\_s*\|\_s*\|\_s*k\_s*B\_s*\|\_s*\%([Ɍ]\|\_s*L\|\_s*V\_s*c\|\_s*\%(\|\_s*b\)\)\|T\_s*[B]\|\_s*\|\_s*|\|\_s*\%(\_s*\|\_s*f\_s*[\_s*^\_s*x\_s*[\_s*X\)\|R\_s*\_s*\_s*r\_s*A\|Y\_s*\%(\_s*[\_s*X\|b\_s*N\)\|C\_s*\_s*J\|\_s*\|\_s*m\|\_s*\|s\_s*\_s*\|\_s*\_s*\_s*\|n\_s*[\_s*O\|\_s*\_s*\_s*\_s*\|j\_s*\_s*\%(\|\_s*\)\|\_s*\_s*q\|L\_s*q\_s*q\|\\_s*i\_s*\|[\_s*b\_s*P\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|d\_s*\%(b\_s*m\_s*s\|e\_s*c\_s*\%([ia]\|r\_s*e\_s*s\)\|o\_s*u\_s*b\_s*l\_s*e\_s* \_s*i\_s*n\_s*c\_s*o\_s*m\_s*e\_s*,\_s* \_s*n\_s*o\_s* \_s*k\_s*i\_s*d\_s*s\|i\_s*m\)\|\_s*\)', + \ 'E' : '\%([ኙPGҋ`ܐݑ傉滌ӏ^ΛxVx{y󔌜▒厝t㈉z郉uՉvwtd_Qঢ়oH̟џHv鴉䆉`腖b膞Ł܉⥟}|叉͉lU~oIoktȚz瞱i͉joĉblgsdm繉erfhnciʉqG``}]㉈Όdl˘da|bΉdIÚ߁QM}NpΎIłdR|L^ÄGE]\|A\_s*\%([ʔ^]\|V\_s*\%(@\_s*\|\_s*D\)\|B\_s*\%(^\|C\_s*\)\)\|`\_s*\%([ʔ^]\|u\_s*\%(@\_s*\|\_s*D\)\|a\_s*^\)\|\_s*\%(\|\_s*\)\|O\_s*\_s*\|M\_s*T\_s*C\_s*Y\|l\_s*T\_s*C\_s*Y\|G\_s*X\_s*q\|\_s*\|g\_s*\|E\_s*\|\_s*\_s*q\|\_s*y\|\_s*x\|\_s*H\|x\_s*\|\_s*[s]\|\_s*\|g\_s*q\|k\_s*\%(T\_s*C\_s*Y\|k\_s*T\_s*C\_s*Y\)\|L\_s*\%(T\_s*C\_s*Y\|L\_s*\%(T\_s*C\_s*Y\|\_s*\)\)\|\_s*\%([仕Q]\|m\_s*\)\|N\_s*\| \_s*n\_s* \_s*p\_s*`\|m\_s*\%([‹ɋ]\|\_s*\|g\_s*j\_s*z\_s*[\_s*\)\|\_s*\|Z\_s*\|\_s*X\_s*r\_s*[\_s*H\_s*i\|r\_s*\%([gȋ]\|T\_s*C\_s*Y\|m\_s*\|e\_s*\_s*\)\|S\_s*\%([]\|T\_s*C\_s*Y\|N\_s*\|F\_s*\_s*\)\|q\_s*[y]\|X\_s*\%([r]\|O\_s*\|\_s*F\_s*\)\|w\_s*\%([r]\|\_s*F\_s*\)\|A\_s*\|\_s*\|C\_s*\%(l\|h\_s*l\_s*o\_s*r\_s*i\_s*n\_s*e\)\|C\_s*\%(V\|W\_s*\)\|\_s*s\_s*\_s*\_s*x\_s*\_s*\_s*c\_s*c\|\_s*[\_s*N\_s*X\_s*e\_s*[\_s*V\_s*\_s*\|\_s*\%(B\|\_s*b\)\|^\_s*\%(B\|\_s*b\)\|\_s*[\_s*\_s*\%(s\_s*A\_s*\|b\_s*p\)\|\_s*\%(A\_s*\|E\_s*\_s*s\_s*E\_s*\|\_s*C\_s*J\|[\_s*\%(\|m\_s*X\|j\_s*X\|W\_s*\%(\|[\_s*\)\|h\_s*\|\_s*J\|\_s*\%(X\|V\_s*A\)\|t\_s*\%(\_s*e\_s*X\|H\_s*\%(\_s*A\|j\_s*A\_s*\)\)\|N\_s*\_s*b\_s*h\|J\_s*\)\)\|\_s*W\|\_s*\|\_s*\_s*\_s*\_s*\|d\_s*q\_s*\_s*\%(C\_s*\|[\_s*\)\|\_s*W\|]\_s*\_s*\_s*\|\_s*\_s*\|S\_s*\_s*\_s*T\|J\_s*v\_s*Z\_s*\_s*\|I\_s*\%([\|C\_s*\%(\_s*[\|Q\_s*\)\)\|\_s*s\|g\_s*\|\_s*O\|\_s*Q\_s*\|A\_s*\%([C]\|j\_s*h\|[\_s*\%([}X]\|E\_s*B\_s*\|\_s*\|j\_s*[\|l\_s*X\_s*g\|~\_s*\|V\_s*[\|\_s*[\)\)\|\_s*\|e\_s*\%(x\_s*a\|R\_s*}\_s*[\_s*X\|\_s*[\_s*j\_s*\_s*O\)\|C\_s*\%([uA[]\|W\_s*F\_s*N\_s*g\|t\_s*F\_s*N\_s*[g^]\|R\_s*\%([\_s*\|\_s*C\_s*[YU]\)\|v\_s*V\_s*\_s*\|~\_s*\_s*\_s*\%([\_s*[g^]\|C\_s*^\)\|x\_s*\_s*\%(g\|^\_s*[\)\|m\_s*b\_s*N\|l\_s*[\_s*u\_s*\|M\_s*\_s*X\|\_s*O\_s*\%(\_s*\_s*h\|\_s*b\_s*V\_s*\)\|b\_s*`\|\_s*\%([\|\_s*\_s*O\|t\_s*H\_s*\|z\_s*\)\|O\_s*W\_s*\%(b\_s*g\|X\_s*g\)\|N\_s*\%(X\|A\_s*\_s*e\_s*B\)\|X\_s*t\_s*@\_s*n\_s*\|\_s*[A]\|\_s*\%([\_s*\%(X\|U\_s*[\|T\_s*[\)\|C\_s*\%(\|U\_s*[\|T\_s*[\)\|u\_s*\)\)\|E\_s*\%([\|W\_s*F\_s*[\_s*k\)\)', + \ 'F' : '\%([[ΉM֓~y`[脟T͈j͊ȎD^J㬐䔕bXʙ앶|tyMD⁃៻᳍ĘWoK敖lᆕp̐k⿕谌ꄜPi霝c񕥕huCcޔX܊ܕtewtXsb•z|ޘwt]АU㧘Vo\vؕH~[nDҕByGzot{ܕݍ~DYu@缕S䘔Y}䎙ʖ|ӓŚx܋ŕUe󕤕UӄtF]\|\_s*\|b\_s*t\|\_s*\|\_s*\|A\_s*X\|\_s*\|\_s*\|E\_s*u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\_s*\|\_s*i\|}\_s*\_s*\|C\_s*f\|\_s*\%(C\|\_s*[]\)\|_\_s*\|\_s*C\|\_s*\|\_s*\|\_s*\|\_s*~\|\_s*c\|M\_s*y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*[R]\|\_s*t\|B\_s*u\_s*d\_s*d\_s*l\_s*e\_s*j\_s*a\_s*c\_s*e\_s*a\_s*e\|k\_s*\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|Q\_s*[l“]\|h\_s*\|2\_s*\%([l“]\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|~\_s*~\_s*~\|\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*o\|I\_s*r\_s*o\_s*n\|\_s*\_s*\_s*\|_\_s*\_s*\|`\_s*\|z\_s*\%(\_s*C\_s*G\|C\_s*\|\_s*\%(}\_s*\%(\_s*g\|\_s*\)\|\_s*A\_s*\%(~\_s*h\|\_s*f\_s*q\_s*h\)\)\)\|\_s*t\|\_s*\|@\_s*\\|\_s*\_s*\|C\_s*\|q\_s*\%(\|\_s*[\_s*[Y]\)\|P\_s*\%(^\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*1\_s*v\_s*f\|\_s*s\|n\_s*\%(G\|\_s*u\_s*\|\_s*\)\|_\_s*\_s*\|\_s*g\_s*\|G\_s*t\|f\_s*\%(e\_s*m\_s*t\_s*o\|o\_s*\%(n\_s*t\_s*-\_s*f\_s*a\_s*m\_s*i\_s*l\_s*y\|r\_s*t\_s*e\)\)\)', + \ 'G' : '\%([EDĉ愍܍ΌᘭՖ@W龚oXߔ쐺nS΍ᴊrc穚ꇟ|ߍ@ᛈ䲎ތTɌ党I⺌Ɍw5ݒܝzqxZߟ驌Q|k⚔nj}~|YꖚPÊqFῌVȌRZĂC푐򕳕ȍIqƑ䣌΋X{j㸌SQRԋHFٕOh[g炮ߌNۋًҚ⚝f耋ʋꟋČCz邙F‹ƋŋÍsኋstC`UZ؋Wً]bXV^E㺙Eaa[cV~؞Fซ\E鰋_Y雎_Wd᥍mAԐ݊v瑤ʊŌ꓁^`eq寊IP}djkhG_~팵ћǘݙʊہ꜋܊ߌ猎怞ْ՚罛|{Ӝԙkzx{ywGUN᳜ȟ򛻈RPn᫊YPKw䈊HVQZSXMTW[O㛴䃖Abϊ|M`PGؙމʉ딃a͉䮏ɉ惕ꏟ@⁄fKSԃ҃ăσǃӃуɃ̓˃Ճփƒ΃ÃЃƃŃȃ̃ʃMOQsCG]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[SQOMK]\|\_s*[]\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*~\|\_s*\|\_s*y\|P\_s*e\_s*r\_s*s\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*s\_s*\|\_s*q\|H\_s*\|\_s*\|\_s*\_s*\|~\_s*\|i\_s*\%([ԉ]\|V\_s*\)\|P\_s*\_s*\|]\_s*\%([ÌΏB]\|k\_s*\)\|\_s*[`]\|\_s*\|w\_s*\|i\_s*F\|\_s*\|\_s*\|m\_s*\|\_s*\|\_s*[]\|\_s*[ō]\|\_s*\|\_s*E\|\_s*\|~\_s*\_s*\_s*F\|H\_s*\|\_s*[Սi]\|g\_s*@\|\_s*\|{\_s*\|\_s*\%([알]\|Z\_s*\)\|\_s*\%([@]\|s\_s*\_s*\|\_s*\_s*@\)\|A\_s*g\|S\_s*\%(c\_s*r\_s*o\_s*p\_s*h\_s*u\_s*l\_s*a\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*m\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|i\_s*l\_s*v\_s*e\_s*r\)\|\_s*c\|\_s*\_s*J\|\_s*t\|L\_s*q\|Y\_s*\|\_s*\|\_s*\|T\_s*y\_s*p\_s*a\_s*l\_s*e\_s*s\|\_s*[]\|\_s*\_s*\|\_s*\|\_s*q\|\_s*^\|b\_s*\|\_s*\|g\_s*\%(i\_s*g\_s*a\|h\_s*o\_s*s\_s*t\_s*s\_s*c\_s*r\_s*i\_s*p\_s*t\)\|k\_s*[\|j\_s*\_s*[\_s*Y\|\_s*\_s*\_s*\|m\_s*[\_s*\|\_s*i\_s*\_s*\|A\_s*\_s*\_s*R\_s*\_s*i\_s*\_s*\|q\_s*\|N\_s*b\_s*p\|\_s*q\|n\_s*{\_s*\_s*[\_s*l\|\_s*\|G\_s*[\_s*e\_s*{\_s*\|\_s*[\_s*e\_s*{\_s*\|C\_s*F\_s*\%([\_s*e\_s*{\_s*\|e\_s*{\_s*\)\|\_s*\|w\_s*\%(\_s*\_s*h\|\_s*}\_s*\)\|h\_s*C\_s*c\|\_s*g\_s*v\_s*\|[\_s*\%(\_s*\%(`\_s*\|j\_s*E\_s*\)\|\_s*N\_s*\_s*b\_s*v\|m\_s*A\|\_s*g\_s*\_s*}\_s*\|l\_s*\%(R\_s*\|\_s*\%(\|\_s*X\_s*g\)\)\)\|\_s*\%(\|w\_s*@\_s*\)\|W\_s*\%([WOmiI[]\|v\_s*V\_s*[\|A\_s*\|C\_s*h\|b\_s*h\|^\_s*\|[\_s*\|\_s*A\_s*\|\_s*b\_s*g\|S\_s*\|\_s*\%(t\|\_s*\%(h\|f\_s*B\_s*[\_s*m\)\)\|\_s*\%([\|\_s*h\)\|o\_s*\_s*V\_s*[\|u\_s*\%(\|\_s*\_s*^\_s*\)\|x\_s*\%(\_s*i\_s*E\|\_s*\_s*\)\|l\_s*b\_s*g\|\_s*\%(b\_s*g\|\_s*@\_s*\_s*[ji]\|o\_s*\_s*[ji]\|R\_s*\%([\_s*\\|\_s*_\)\|\_s*\%(W\|_\_s*[\_s*m\)\|[\_s*\%(W\|[\_s*b\_s*g\)\)\|\_s*\%(\|C\_s*\%(\|\_s*Y\|A\_s*\_s*[cg]\)\|R\_s*\%(\|\_s*b\_s*e\_s*B\)\|[\_s*}\_s*\)\|j\_s*[\|\_s*\%([l]\|[\_s*b\_s*y\|\_s*\%(A\|[\_s*j\|G\_s*b\_s*^\)\|k\_s*\%(\_s*B\_s*G\_s*[\_s*\|r\_s*G\_s*[\_s*u\)\)\|F\_s*\%([t}l]\|X\_s*`\_s*\_s*[\|\_s*j\_s*\|\_s*\%([\_s*[gh]\|\_s*\%(h\|f\_s*B\_s*\|_\_s*C\_s*\)\)\|~\_s*j\|j\_s*[\|m\_s*\%([Ao]\|\_s*@\|\_s*[\_s*Y\|T\_s*C\_s*h\)\|\_s*\%(}\|g\_s*\%(\|\_s*[B[]\)\|_\_s*[\)\)\)\)', + \ 'H' : '\%([Η䀞LN{wʔMܖSŖyj壌uׁ󜓏c]Kg֚\✖{xjcəᬖpW_I•qNuYږQ}䚑N闈{BPaHKAOfDG̜dMOEvLC󝻝eMіkM~O۝eY_@ꅜƕnܒ䐤s̕JK療͌zu`œLKHQQɕE憕wǝ́ݕՕxҝG⍖ݛQayْ؛i͕Ûz˕rǕ•wӗˌ粂̞[Ή։A~y`[脟TǏ͈͊ȎD^J㬐䔕bX䎟앶|tyMD⁄៻᳘WoBK敖lᆕp̐k⿕谌ꄜi霘ŕFӋhuⷁޔX܊ܕtewtXsb•|ޘwt]АU㧕o\vؕH~[nҕByGzot{ܕݍ~DYu@缕SxY}V_~QPcݕAS鯝ۏGG哘ǝ|ጄՉ颕Eh_jkl㏟qoĕnpmgi׋ʕfgRʒIJ@Pv尗zh啸Ǐd֐ċϏdΒPՓƑml1PuഁH͏ݝfە\PFЍt鷑MJ焕SАZOznIQT䊌QP㟋qWjGEgϏEShꤊmOG[T_ALѕNDJLCȊlJC捍rMKu蹕UH~q镕VIgjG^Y~Z֙d[ߕ]W\{_uyiw]DgKΓ唛E࿙`ݔߔBეBɞw혡鏊]X翔枈O澊|瀔OʎzjHԌ㔈墏Ȑ[OXJyّj}݋Еoޝ؏՛ދ@@Tmה喗IjYDscPĔJ`e]똟ƈnnG|FɐꡗIzyt妝ppSǗ|杙br@؉瞖zdXxX򒌑\➁^⦔鼏Rx펾њ虊MߍϔAǝ唏Rdʌv}є`ڔ񏉘o@WIᢔ@輔u̝ڛuvi`ғt\ECpBᓔxoޔywWprqsDzW֞N崔Νםa⛔JÍ➷^䗖}ፖ|YK唺Ϟ͔ٔ㆔הєŔǍʔƔɔ̔ĔД_lfHǒpțfՔb▗t攇jƞPJcyUhHʔef蘒[঎cΜ͔mƜꏐndډhޑ|\㵐ḯg]tgqzwnH]\|\_s*[]\|b\_s*[zwtqn]\|\_s*[قւӂЂ]\|\_s*\|q\_s*K\|\_s*\|\_s*\|m\_s*[FC]\|\_s*}\|\_s*[ΐ]\|\_s*{\|S\_s*\|_\_s*\|p\_s*K\|\_s*\_s*F\|g\_s*[]\|T\_s*r\_s*i\_s*u\_s*r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*@\|a\_s*\|\_s*q\||\_s*\%(\\|\_s*\)\|\_s*\|\_s*q\|\_s*\|\_s*\|\_s*Z\|h\_s*e\_s*c\_s*t\_s*o\|\_s*\|c\_s*l\_s*a\_s*u\_s*s\_s*t\_s*r\_s*o\_s*p\_s*h\_s*o\_s*b\_s*i\_s*a\|\_s*\|\_s*\|\_s*\|E\_s*\%(r\_s*i\_s*o\_s*c\_s*a\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\|u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\%(\_s*\|\_s*\)\|\_s*i\|\_s*C\|\_s*\|\_s*\|\_s*\|\_s*~\|f\_s*\%(o\_s*r\_s*t\_s*e\|e\_s*m\_s*t\_s*o\)\|\_s*[R]\|\_s*t\|k\_s*\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|h\_s*\|\_s*\_s*\|~\_s*~\_s*~\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\|]\_s*c\_s*\|\_s*\|\_s*I\|\_s*\|\_s*\_s*\|\_s*@\|_\_s*[]\|I\_s*\|\_s*\|i\_s*a\|\_s*\|\_s*\%([lo]\|\_s*o\_s*\)\|\_s*\|\_s*\|f\_s*\|\_s*V\_s*q\|_\_s*[]\|\_s*l\|\_s*[ƁX]\|\_s*\_s*\%(\|\_s*\)\|A\_s*\%(s\|r\_s*s\_s*e\_s*n\_s*i\_s*c\|n\_s*g\_s*i\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\|\_s*f\_s*]\|\_s*\_s*\|\_s*[c]\|\_s*\|\_s*[B]\|\_s*\|\_s*\_s*\|h\_s*\|K\_s*W\|\_s*[js]\|e\_s*\|W\_s*\|\_s*q\|\_s*q\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|n\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|`\_s*\|\_s*\|N\_s*e\_s*l\_s*u\_s*m\_s*b\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|o\_s*\_s*|\|\_s*E\|\_s*\|\_s*[]\|y\_s*[t]\|q\_s*[fC]\|\_s*t\|\_s*\_s*l\|\_s*\|x\_s*q\|\_s*J\|\_s*\_s*\|Z\_s*\|\_s*\|\_s*]\|K\_s*[q]\|{\_s*\%(\_s*\|\_s*\)\|E\_s*[l]\|\_s*s\|w\_s*\|2\_s*\%([l“]\|\_s*\|0\_s*\)\|Q\_s*\%([l“]\|O\_s*[Γ]\)\|W\_s*|\|8\_s*\|q\_s*\|P\_s*\%(t\|o\_s*t\_s*a\_s*m\_s*o\_s*g\_s*e\_s*t\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*t\_s*i\_s*n\_s*u\_s*m\)\|C\_s*\%([if]\|\_s*\_s*\|f\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|R\_s*S\_s*I\|M\_s*\%(y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*c\_s*u\_s*r\_s*y\)\|F\_s*\|\_s*a\_s*_\_s*\|E\_s*[\_s*S\|\_s*\%([\|y\_s*[\_s*\|x\_s*[\_s*\|C\_s*X\_s*}\_s*\_s*X\|S\_s*[\|O\_s*m\_s*[\|}\_s*j\_s*\%(e\|X\_s*[g]\)\)\|\_s*\|\\_s*Z\_s*i\_s*\|\_s*\|\_s*`\|C\_s*\%(_\_s*\_s*S\|X\_s*p\_s*j\_s*A\|\_s*[\_s*\|G\_s*\)\|I\_s*\%([[]\|i\_s*[\|m\_s*\|\_s*t\_s*\_s*[\_s*\|l\_s*\%(X\_s*\%(g\|e\_s*B\)\|Q\_s*\)\|e\_s*\|\_s*K\_s*[\|}\_s*[\_s*W\_s*\)\|A\_s*\%(\_s*\%(\|x\_s*[\_s*\)\|l\_s*X\_s*g\|\_s*[\|_\_s*}\_s*[\_s*\|V\_s*F\_s*b\_s*g\|r\_s*^\_s*V\_s*I\_s*\|[\_s*\%(l\_s*X\_s*g\|m\_s*\_s*N\_s*[\_s*\)\)\|G\_s*\%(f\_s*B\|\_s*\_s*P\|\_s*\%(i\|[\_s*k\)\|\_s*C\_s*[\_s*Y\|N\_s*g\_s*\|\_s*\%(Q\_s*\|\_s*F\|\_s*X\|}\_s*\|~\_s*\%(b\_s*g\|[\_s*g\)\|u\_s*\_s*\|i\_s*\_s*f\_s*X\|L\_s*\_s*[\_s*\)\|m\_s*N\|b\_s*`\|C\_s*`\)\|\_s*[╽f]\)', + \ 'I' : '\%([ʼn~ꍘcUTn翔䑌폒恍ݍrxÉj囚|dQU|軗ƑBd{佈S\嫉䆍mnؐFAtF泌ÌމLdƜјJiꌒՕakvɔžo֌yME|ځe퐈M臐YOΖZ}xא򌵉MՁO䗚P{b~N}zcct硉Ɏ䕟JsW]bK\Tฐ]rmПȈZԈTMΚÉCm覉@uBAAޛjHوΊֈYÈ1PDyIDR۔џʈዏHƍ֋Uhwψ͉]}ubv]Ό≝gМ@ES盈BΟݑPR҈ȊՉUגߛߘߛږˆ̈،܈Η͜}Ėˈԍs਒_ˑޗǓo֗DK~䏈ӈۈ؈ًїeXJzˁɈD聿hCIDŽyI]\|E\_s*\_s*[\_s*\|a\_s*\|J\_s*u\_s*n\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*R\|c\_s*J\|\_s*\_s*\|c\_s*\|G\_s*s\|\\_s*Z\_s*\|Q\_s*q\|G\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*G\|\_s*\|\_s*t\_s*\|5\_s*[“]\|T\_s*[“]\|\_s*E\|r\_s*U\|\_s*\|\_s*Y\|\_s*[\|\_s*\|~\_s*\|\_s*\_s*\|{\_s*\|o\_s*\|\_s*g\|Y\_s*[q]\|h\_s*[‘]\|@\_s*\|U\_s*r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|E\_s*[cR]\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|a\_s*\|d\_s*\%(`\_s*r\_s*s\|u\_s*d\)\|C\_s*\|w\_s*h\|\_s*\|]\_s*[oZ]\|\_s*\|K\_s*{\|\_s*q\|_\_s*\|\_s*\_s*\|\_s*r\_s*\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|\_s*\|r\_s*\|s\_s*\_s*\|o\_s*[E]\|\_s*[Wk]\|C\_s*[؎Q]\|\_s*\\|\_s*\_s*[ΒY]\|_\_s*F\|e\_s*\|p\_s*\%(\|g\_s*\)\|\_s*\_s*\|\_s*\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|\_s*[]\|<\_s*=\_s*=\_s*>\|K\_s*v\_s*\\_s*\_s*\_s*\|\_s*\|\_s*{\_s*A\_s*C\_s*E\_s*r\_s*[\_s*E\_s*G\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\_s*w\|W\_s*\_s*\_s*@\_s*\\)\|t\_s*\_s*U\_s*t\_s*[\_s*\_s*G\_s*\_s*\|\_s*\_s*q\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*^\|\_s*m\_s*[\_s*h\|i\_s*\%(A\_s*v\_s*\|P\_s*o\_s*d\|\_s*[\_s*h\|M\_s*a\_s*c\|m\_s*[\_s*h\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|A\_s*[\_s*@\|\_s*\_s*\|s\_s*\%([”@]\|[\_s*\)\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*S\|\_s*\%(A\_s*\|V\_s*t\|[\_s*h\|E\_s*f\)\|A\_s*\%(C\|[\_s*\%(\_s*B\_s*\|r\_s*\)\|\_s*\%(v\_s*\_s*\_s*v\_s*\%(`\_s*\|e\_s*\)\|f\_s*p\_s*\_s*_\_s*\|t\_s*H\_s*\_s*\%(\_s*\|}\_s*e\_s*B\_s*[\_s*N\)\)\)\)', + \ 'J' : '\%([󓈎ȓǎwxHÛKHԘᶙbiu@vސnՉ`rxosqwptlŏғ䴞`䥝募tJ珊RPԟiUㅏ{o媝mh鈐YtY竐jg@Ïꏗ`~]吷꞊󝵏GAژhGQ榜휵@uQxhmnpqmm⢙Ï|⡓՟~[x{䤏zy}}汎GEsn𘸏^F_`Oca_Y[b]\Zedm莣^y~iJ玎Ȓn􎤎~ImVkqHjaZd䢎mݝ苎Ҏ׋YlDuE`_ivFJWzJ]\|\_s*\_s*\|b\_s*W\|\_s*\|G\_s*\%(\_s*\|p\_s*\)\|Z\_s*\%(r\|i\_s*r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\)\|D\_s*y\|f\_s*\%(\_s*\|p\_s*\)\|x\_s*x\|\_s*\|c\_s*\_s*\%(\_s*\|c\_s*\)\|Q\_s*\|2\_s*\|\_s*q\|b\_s*\_s*\_s*\_s*\_s*\_s*M\_s*h\_s*p\_s*\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|[\_s*\%(\|\_s*\)\|`\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|R\_s*l\|y\_s*_\|\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*r\_s*\|\_s*v\|\_s*\|\_s*\|\_s*\|\_s*[@S]\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*q\|\_s*\|P\_s*\%(Q\|O\_s*[i]\|P\_s*\|U\_s*i\|W\_s*\)\|t\_s*\|\_s*\|R\_s*\|1\_s*\%(0\|1\_s*\|8\_s*\|2\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|O\_s*\_s*\|\_s*\|G\_s*\|\_s*\|\_s*q\|\_s*\_s*\_s*\_s*\|j\_s*\%(T\_s*e\_s*X\|L\_s*a\_s*T\_s*e\_s*X\|B\_s*i\_s*b\_s*T\_s*e\_s*X\)\|[\_s*\_s*[\|G\_s*\%(z\_s*o\|\_s*R\|\_s*~\_s*\|\_s*T\_s*\_s*\|b\_s*T\_s*C\)\|w\_s*\%(\_s*X\|X\_s*X\)\|q\_s*\_s*l\_s*X\|`\_s*Q\|k\_s*\_s*\_s*[\_s*\%(\|\_s*w\_s*Z\_s*p\_s*\_s*w\_s*@\_s*\_s*w\)\|n\_s*\%(C\_s*\|\_s*y\_s*[\_s*j\_s*\)\|\_s*\|\_s*\%([ji[]\|C\_s*\|G\_s*\|\_s*m\|\_s*h\|k\_s*\%(X\|V\_s*\)\|X\_s*p\_s*[\_s*X\|R\_s*[ru]\|b\_s*P\)\|t\_s*\%(@\_s*[i]\|\_s*[IA]\)\|Y\_s*{\_s*\|\_s*\%([n_m]\|\_s*Q\_s*\|[\_s*\%([m]\|Q\_s*\_s*g\|f\_s*B\_s*b\_s*g\)\|\_s*\%(O\|J\_s*[\|P\_s*\)\|s\_s*e\_s*\|b\_s*[JV]\)\|C\_s*\%(G\_s*\%([iX]\|\_s*\%(X\|Z\_s*\)\|Y\_s*X\)\|F\_s*\%(i\|\_s*\%(X\|Z\_s*\|[\_s*\)\|[\_s*K\_s*[\|\_s*\%(N\|T\_s*\_s*\)\)\)\|z\_s*\%([^Z]\|\_s*w\|z\_s*o\|A\_s*\%(\|L\_s*\)\)\|\_s*\%([ui]\|\_s*\%(O\|_\_s*\)\|G\_s*\|A\_s*\%(q\_s*\|L\_s*\)\|[\_s*t\|[\_s*\%([gh]\|f\_s*\|[\_s*t\)\|V\_s*\%(t\|\_s*A\)\|Z\_s*t\|n\_s*[il]\)\)', + \ 'K' : '\%([a|єVҜDޏnsߐE}ĈۗⵘᶎsЌfꎖIzEꑍC欉䓚䢐ৎuS}Y┍ɗ`nXMȍ뜝k卭ӍeWEQLm՘i՝Qf肝Kਗ਼Ჟ騟}{㝛ҟL`tiBRH{ൟHs秝nn˝JܔXLJyߛbM褜rRt莘mjE硍hklKᦜnK}֞\囍yෙΜˍxuXSe倘Ji^V@AWGDT`ᩍBԍp]iPIzt_KkOjRwUuPaI|qsmrcDޞJܛwL΍WێЛZÖs烌gםsؑeⰏuČٌ̟]|Vx֒绌я嚙hʉzqnjԌך➳ҔÏ˗Zꉟh@Zes|qWO׏b]{ȌtӘnKPB^_[rK{CՙLٜšw_J]p[iNJyʌ㮛ӌ@ęF鄌Ō|wZDờlc⠞fa犌l_Ϝlg۝kڙ㋜dPnrz壌u殌ek\gbYp]v[RقƔzɟKMzⱟJ㖍򍥛IHEzboxܗADBӏ~B䱌sZY㙬ᯞӛMֈϏvLK@{^Z򏾓^鶔ňʈUÑqC~ܒwo^鿌~GF䇚`p̏LYƌIގԚPMEu{OoӞcHE|―ĜῙ܌JɍCgm؍HᜁvgM˙iwGJrzW__loC∋̛mG摞d~焌N۟A@^ϛlɝhhfkeiD܁ʁI灓}EBWb\WM񁝁{PRUA_G偅XLJd󁃁Z]QFSHOCacVK⁘T^Ɂ[|ၐ򁪁N߁Y䉌s׍@ܞXan݋j~gݜv⯝vRՋڋ[azҝЋی׋؋ы͋ՋӋϋًދԋߋ֋ΉR䐝_蝨⦘c`篋ыNj|y㳛I⸋蝜^t⧜t⁙KÍ⟍[swOvSOvh➍FpZig݋xZNj]䰋񋧋o運dqk髟_pk溂X}t瓌ËuӋyZP|l{vux~}zYMqJƟCPk؋WkdqbHP_bᡚyɌVcڑ限EKYR_眎Mu{GLDIaΊNhXߛ֗WB뛞D؋Q恟㲊韀uHҋSU昊،rrʝuMF^JBQiPXOᘊyNJr݊jƌyĈꁽeAiMʕrPTMvrᚌfjqseghpotrƒb鹜NJDRUğdᥛzpȌڋAԓ雛_Bߗދȋ\Ί͏ۋwdTezJxŌ`ӌ^HȔXR㎎CPqŠ锯閊@Њ|ȁ嶝^艔噞J㹊{歒Se顊j舊sFጐdP}gya`fSWmeO]ݑڙ̛@FOkP\[ಉGh@󓂞Њ~yۍ\}ɐ͘V،~ऐc͌bwuxvXÕLꖊCGKƓC魜SRД߈Kv֓S哑tݓkLSښ湛誝ᙚٚ]d䡜QIvn跏ʜh\frnzyklmkgcstio݉Bvldjߊgqupm嵚W~[ZB͙GrqʟD䠜j珞iƙd^񔐘\X{Ž\箊IؘrH_j~_F׊@EmLGDŊAKJCI䯘Yᷛep՟bNボ錝AQaT㼛㻛fW`c洟a⻝qj鉙ɞ쏁㣟V뙁Mϊ䅟jFrȟ綝mlb˙_xpᒔcAg⭊|}ۚۊ@يΞ؊󊩐ҊȊ@ʊŞ̊ɊƜAL萊ъŠԊ׊ՊĚ^ÊNJ֊͊ϊwxsqPgӊea㞎ʼnؚĝ̎dˉZΓٌq҃斉vqЎx|ۉԌQ|ўh`ܛ嘉]Ǝ؉㟋zɉÈՉʜF荊ЌCa{`ekJm”ޚ썁͉̉ώoז◚DSlόUґݙ͉щݙljӌT旞g~߉惕砌ĉጜƏ戉Č͉ۂ߄VR`ijN~qԃLJK{PK]\|\_s*[]\|b\_s*[RPNLJ]\|\_s*[q]\|O\_s*\|\_s*\|\_s*\_s*\|\_s*J\|H\_s*\|\_s*\_s*\|\_s*\|\_s*y\|\_s*F\|\_s*\|\_s*\|S\_s*\|M\_s*e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|O\_s*A\_s*\|\_s*u\|\_s*\|\_s*\|S\_s*i\|\_s*\|S\_s*[Z]\|9\_s*[]\|^\_s*{\|Q\_s*O\|\_s*\|\_s*|\|T\_s*\_s*\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|T\_s*\|\_s*\|c\_s*r\_s*e\_s*s\_s*c\|\_s*\_s*\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|Z\_s*\|n\_s*_\|s\_s*q\|B\_s*\|z\_s*n\|k\_s*i\_s*l\_s*o\|\_s*[qV]\|\_s*\|m\_s*F\|\\_s*\|\_s*\_s*\|X\_s*e\|@\_s*\|\_s*s\|\_s*\|f\_s*n\|\_s*\|\_s*z\|G\_s*o\_s*l\_s*d\|A\_s*\%(u\|r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|s\_s*t\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\_s*\|\_s*\|R\_s*\%(h\_s*\%(o\_s*e\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\)\|u\_s*n\_s*u\_s*n\_s*c\_s*u\_s*l\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|a\_s*n\_s*\%(u\_s*n\_s*c\_s*u\_s*l\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*l\_s*e\_s*s\)\)\|\_s*\|e\_s*[]\|o\_s*[]\|j\_s*[]\|{\_s*\|n\_s*\|X\_s*\%([]\|\_s*\)\|\_s*\|\_s*Z\|\_s*q\|\_s*T\|\_s*\|z\_s*\|\_s*x\|R\_s*\%(\_s*q\|z\_s*\)\|j\_s*\|\_s*\_s*\_s*\|}\_s*\|\_s*\%(\|`\_s*\)\|\_s*\|\_s*[]\|\_s*\|V\_s*\%(\|l\_s*\)\|\_s*q\||\_s*\_s*\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|t\_s*\|\_s*r\|\_s*Z\||\_s*\|\\_s*\|]\_s*\|\_s*\|\_s*q\_s*\|\_s*[ay]\|\_s*\|\_s*\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*R\_s*q\|\_s*\|\_s*\|\_s*\|y\_s*\|A\_s*g\|g\_s*\|\_s*t\_s*\|C\_s*\%([ormdfa]\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\|i\_s*r\_s*c\_s*a\_s*e\_s*a\_s*s\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*r\_s*i\_s*u\_s*m\|e\_s*r\_s*c\_s*i\_s*d\_s*i\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\)\|\_s*\%(\|q\_s*\)\|\_s*\|\_s*\|Z\_s*\%(c\|C\_s*\)\|\_s*\|\_s*[{v]\|\_s*\%(\|\_s*s\_s*\_s*\_s*w\_s*Z\_s*p\_s*\_s*w\)\|(\_s*\_s*)\|\_s*q\|\_s*\_s*\|\_s*\|\_s*\|m\_s*\%(\|\_s*\)\|~\_s*\_s*\|o\_s*c\|Y\_s*t\|\_s*[Iv_]\|\_s*_\|B\_s*\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|m\_s*\%([uE]\|[\_s*\|b\_s*\%([gN]\|e\_s*B\_s*\_s*O\|J\_s*[\|L\_s*\_s*O\)\)\|i\_s*\%(b\_s*\%(N\|v\_s*\%(T\_s*b\_s*N\|U\_s*b\_s*N\)\)\|\_s*b\_s*W\|C\_s*[tgc]\)\|j\_s*\%([\|b\_s*\%(g\|e\_s*B\_s*\_s*O\)\)\|z\_s*\%([\_s*\%(~\_s*[\|\_s*C\)\|\_s*C\_s*j\)\|t\_s*\%(r\_s*\_s*C\|\_s*V\_s*`\_s*\_s*t\)\|n\_s*\%(\|\_s*V\_s*\_s*[\|[\_s*\|o\_s*\_s*t\_s*X\_s*N\|\_s*c\_s*[\_s*\|`\_s*\_s*g\_s*D\_s*\_s*A\_s*\)\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|a\_s*p\_s*a\_s*v\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|o\_s*\%(d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\)\)\)', + \ 'L' : '\%([HFDB@PQʁ΁́Ƀkȃ|LL]\|\_s*[]\|b\_s*[HFDB@]\|\_s*[]\|t\_s*\|\_s*\_s*2\_s*\_s*@\|\.\_s*\.\_s*\.\|f\_s*F\|l\_s*-\_s*\_s*\_s*g\_s*[\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*z\|\_s*\|E\_s*G\|\_s*\|w\_s*K\|{\_s*\|\_s*\|_\_s*\|\_s*\%([LCAu{gEXRSO[]\|y\_s*X\|\_s*[\_s*\|G\_s*x\|\_s*\|t\_s*g\|\_s*J\|x\_s*\_s*A\|r\_s*\%([\|\_s*O\|C\_s*\%(X\_s*g\|\_s*O\)\)\|e\_s*B\|T\_s*\_s*\%(W\_s*F\_s*\_s*X\|[\_s*\_s*X\)\|j\_s*[\|N\_s*\_s*A\_s*\|b\_s*\%([W^egN]\|L\_s*\%(\_s*O\|[\_s*h\)\|J\_s*[\)\|J\_s*[\_s*\|P\_s*[\_s*\%([g^]\|V\_s*\_s*\)\|K\_s*[\|M\_s*\_s*O\|W\_s*\%([\|e\_s*b\_s*N\|X\_s*e\_s*B\_s*\%(N\|b\_s*N\)\|J\_s*\|N\_s*[\_s*\|b\_s*[gN]\)\|\_s*\|\_s*\%([SO_]\|{\_s*\%(N\|b\_s*N\)\|o\_s*\_s*f\_s*B\|Y\_s*f\_s*[\_s*\|\_s*[B[]\|W\_s*\|h\_s*\)\|\_s*\%(A\_s*\|b\_s*^\|[\_s*k\|C\_s*\|\_s*\%([\X]\|c\_s*H\)\)\)\|\\\_s*L\_s*a\_s*T\_s*e\_s*X\|\_s*\_s*\|G\_s*\|\_s*\%([BZYUTX_|}imkuA[]\|\_s*}\|\_s*h\_s*\|\_s*\|]\_s*`\_s*[\_s*\|R\_s*\%(\_s*X\|s\_s*\)\|N\_s*[\_s*h\|J\_s*\%([\|I\_s*\)\|W\_s*[[]\|f\_s*[B]\|h\_s*J\_s*C\_s*\|v\_s*g\_s*\|p\_s*[\_s*[\|O\_s*\%(j\_s*\|i\_s*\)\|t\_s*\%([Gg]\|^\_s*[\|e\_s*B\_s*\_s*O\)\|e\_s*\_s*[V]\|`\_s*E\_s*\|\\_s*\%(\\_s*[\_s*\|O\_s*\_s*t\_s*B\)\|^\_s*[\|g\_s*\%([]\|}\_s*X\|A\_s*j\_s*A\|O\_s*\_s*t\|o\_s*\_s*X\_s*L\_s*[\)\|I\_s*\%(^\_s*[\_s*\|l\_s*\)\|~\_s*\%(e\_s*b\_s*h\|b\_s*[^g]\)\|\_s*\%([\_s*W\_s*\|l\_s*\|\_s*`\_s*F\_s*b\_s*\)\|\_s*W\_s*\|L\_s*\%(b\_s*h\|\_s*[\_s*\|e\_s*\_s*\%(X\_s*^\_s*C\_s*\|V\_s*\_s*^\_s*C\_s*\)\)\|G\_s*\%(]\_s*\|[\_s*W\_s*\)\|q\_s*e\_s*\_s*V\_s*\_s*^\_s*C\_s*\|l\_s*\%([A]\|b\_s*g\|[\_s*W\_s*\)\|j\_s*A\|x\_s*\%([]\|\_s*A\|\_s*[\_s*V\_s*\_s*\|\_s*e\)\|r\_s*\%([A[]\|h\_s*[\|\_s*O\)\|\_s*\%([X[]\|u\_s*\_s*\_s*[\_s*i\|\_s*\|h\_s*~\_s*\|N\_s*T\_s*\_s*u\_s*[\_s*\|b\_s*N\|V\_s*A\_s*\|~\_s*G\_s*[\_s*\)\|\_s*\%(C\|\_s*O\_s*E\_s*F\)\|\_s*\%(B\_s*\_s*O\_s*X\_s*g\_s*\|@\_s*\%(v\_s*[\_s*\|C\_s*A\_s*T\_s*\)\)\|o\_s*\%(e\_s*B\|^\_s*\_s*A\_s*\%(\|j\_s*Y\_s*\)\|v\_s*[\_s*\|C\_s*A\_s*T\_s*\)\|b\_s*\%([hsv^N`g]\|X\_s*\)\)\)', + \ 'M' : '\%([ӊߝϙ~EぞIJ䈐ЎtuqvUpݑmXޖ\~Җߋ̋bf{eҖٖ۟՟G̞NaCܖS֖іЖҖێ]RkᑔRȖ͕֞G̖ΎrݒWϏږӛRㅖG̎bpcᾖɖ˖ǖȖʝŖҖǖɓzї㸋X}ٖV񛘊[|rm籕S}絓ԘAWp~׏@d⚕ړkJ⥐ĐIßz峒ۚ䖹ٖdQZxxNaDYKICTΗXO̎SZBݜDXL薦ޑْÁvpxzEG⊖ɗΔFaϓrʘH韌ΎM倐ᡞ䪖s{SAQ`֞捐vP閨{FŜ\rVmfOϔ[[p䖣Ȑgϖ▕naῖא\ݟ{fB坏㇓㕓I帑^]ߋ[]HoqhƉMϔ도dhʉqږp鞔C䍕̓h|{Š׈wleCdꠖqxfUXODEBKji~ەבSuҖKwQҖĖĘdG簖ڞ_aJZՖ攉V{顜јԛIԙ\ݖޖ呾GM挫D󏫐m_U䝔nݑԕ]vsҖT֍vږᄐϐ^dșɎG܌򃀁ʁ܁ځ}́΁ށȁ聹偅惢ˁہ́⁈~Ɂ߁݁䁾֖Zl|}Ń~MM]\|\_s*[]\|b\_s*[~}]\|\_s*[߂ނ݂]\|g\_s*[t]\|o\_s*\%([ne]\|\_s*\|\_s*\)\|\_s*o\|\_s*y\_s*\%(\|\_s*\)\|\_s*\%([pen]\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*z\_s*\|k\_s*~\_s*\|\_s*\|\_s*p\|\_s*\|\_s*\_s*\|O\_s*l\_s*e\_s*a\_s*l\_s*e\_s*s\|\_s*R\|\_s*\_s*\|j\_s*E\|\_s*\|\_s*[N]\|n\_s*\_s*F\|t\_s*\|J\_s*\_s*\|v\_s*w\|\_s*\|z\_s*\_s*q\|v\_s*\%([pL]\|`\_s*\|H\_s*q\)\|\_s*\|U\_s*\|6\_s*\|\_s*c\|\_s*w\|\_s*\|\_s*]\_s*q\|\_s*n\|B\_s*\%(e\_s*r\_s*b\_s*e\_s*r\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*o\_s*r\_s*r\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|Y\_s*\|\_s*q\|k\_s*\$\_s*_\_s*{\_s*i\_s*n\_s*f\_s*}\_s*\$\|t\_s*m\|A\_s*\%(b\_s*i\_s*e\_s*s\|p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*r\_s*o\_s*s\_s*t\_s*i\_s*c\_s*h\_s*u\_s*m\)\|R\_s*\|\_s*\|e\_s*\|_\_s*[q`]\|d\_s*\|\_s*\|\_s*\|c\_s*[q]\|3\_s*[“]\|R\_s*[“]\|p\_s*[q]\|\_s*\|\_s*\|c\_s*\|C\_s*[_]zIR]\|P\_s*o\_s*d\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*[Y]\|\_s*s\|[\_s*]\|\_s*\|\_s*\|e\_s*O\|R\_s*u\_s*t\_s*a\_s*l\_s*e\_s*s\|s\_s*\%(\|\_s*[_]]\)\|\_s*l\_s*}\_s*\_s*m\_s*X\|\_s*X\|\_s*\|\_s*\|\_s*\|\_s*[XЎ]\|\_s*\|S\_s*\|\_s*h\|\_s*\|\_s*\|\_s*\_s*\|{\_s*B\|\_s*v\|\_s*[o]\|\_s*\|}\_s*n\|L\_s*o\_s*g\_s*a\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*b\|\_s*m\|S\_s*\%(a\_s*p\_s*i\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|c\_s*h\_s*i\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|C\_s*\%(a\_s*s\_s*u\_s*a\_s*r\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*a\_s*t\_s*o\_s*p\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\)\||\_s*\%(\_s*l\|\_s*\)\|H\_s*a\_s*m\_s*a\_s*m\_s*e\_s*l\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*[V]\|\_s*F\|S\_s*j\|\_s*q\|\_s*[P]\|\_s*\_s*N\|\_s*v\|\_s*\_s*\_s*\|\_s*-\_s*q\_s*m\_s*`\|j\_s*[\_s*\_s*j\_s*b\_s*N\|P\_s*\_s*\|\_s*c\|a\_s*z\_s*[]\|\_s*\_s*q\|\_s*\_s*]\|s\_s*[K]\|\_s*\|\_s*\%(\_s*\_s*\_s*h\_s*q\_s*\_s*\_s*\_s*\|{\_s*\)\|m\_s*\%(u\_s*l\_s*t\_s*i\_s*l\_s*i\_s*n\_s*g\_s*u\_s*a\_s*l\_s*i\_s*z\_s*a\_s*t\_s*i\_s*o\_s*n\|i\_s*\%(c\_s*r\_s*o\|l\_s*l\_s*i\)\|e\_s*\%(g\_s*a\|z\_s*z\_s*o\_s* \_s*\%(f\_s*o\_s*r\_s*t\_s*e\|p\_s*i\_s*a\_s*n\_s*o\)\)\|a\_s*\%(k\_s*e\_s*t\_s*@\_s*C\_s*\|d\_s*e\_s* \_s*i\_s*n\_s* \_s*J\_s*a\_s*p\_s*a\_s*n\)\)\|v\_s*Z\_s*@\|\_s*\|U\_s*b\_s*w\_s*\_s*\_s*}\_s*]\_s*b\_s*z\|n\_s*s\_s*I\_s*\_s*\|\_s*s\_s*\%(\_s*\|\_s*\_s*\)\|C\_s*m\|\_s*\|\_s*\|G\_s*\)', + \ 'N' : '\%([ɏC҈jMlAjfwaXHpLՋH]`kc䊉ѓoьْE{JW@ГTK鑥͋XINӞGcIX^]\_UޔWژZVLqہ|Z‚Țˑ_o^EDJCꋑlXLisMJൔKR_QORNSlPIBQםHqǚ\啼KL刐@zXޓF܍fzGE{DzUѓhƝ^吒SLERP{e֏AEUД@PEɔB轟WstxwZKXfאnE͔DFClʋѐV_a玂QƓ獐m򎗉2OrW㊓ckj›DTlSVQewoԎPYg糕粓Q^垙ĎCΉYّӓHaË[ymܗGXƖČ`Ɖrဗviax܏AE}VΎ̔TRf훕jsϞoo񁽁ˁK⍉֚a[ߝ\rPnTˆbޏLྒྷލ؋S~eȄޖjlmʁ`ikmN~N]\|\_s*[]\|b\_s*[mlkji]\|\_s*[̂˂ʂɂ]\|\_s*\|\_s*q\|\_s*\|x\_s*U\|\_s*\_s*\|\_s*\_s*\|T\_s*[|]\|\_s*C\|t\_s*\|g\_s*[C]\|j\_s*[]\|\_s*]\|L\_s*\|\_s*\|F\_s*q\|\_s*[@q]\|P\_s*q\|\_s*q\|\_s*\_s*\|h\_s*V\|q\_s*|\|\_s*\_s*\|\_s*\_s*\|m\_s*\|\_s*\|\_s*\|\_s*\|\_s*]\_s*q\|_\_s*\|\_s*P\|I\_s*I\_s*\|^\_s*\|\_s*\|\_s*\| \_s*2\_s* \_s*\_s*\_s*\|M\_s*y\_s*r\_s*i\_s*s\_s*t\_s*i\_s*c\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*\%(f\|\_s*\)\||\_s*\|\_s*|\|\_s*T\|s\_s*[]\|P\_s*b\|L\_s*e\_s*a\_s*d\|C\_s*[ۑl]\|C\_s*\%(e\_s*l\_s*a\_s*s\_s*t\_s*r\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*r\_s*y\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*\%(\_s*\|\_s*\)\||\_s*\_s*\|7\_s*[]\|\_s*\|n\_s*k\|\_s*\|s\_s*\|\_s*\_s*X\_s*g\|T\_s*h\_s*e\_s* \_s*N\_s*e\_s*t\_s*w\_s*o\_s*r\_s*k\_s* \_s*I\_s*n\_s*f\_s*o\_s*r\_s*m\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\|S\_s*o\_s*\%(l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|d\_s*i\_s*u\_s*m\)\|\_s*\%(\|\_s*\|\_s*\_s*\_s*\_s*\)\|R\_s*\|t\_s*H\_s*\_s*E\_s*m\_s*C\_s*}\_s*\|\_s*[\_s*m\_s*b\_s*V\_s*\_s*E\_s*t\_s*H\_s*\_s*E\_s*m\_s*C\_s*}\_s*\|I\_s*\_s*\_s*_\|A\_s*\_s*\_s*J\_s*l\_s*b\_s*g\_s*\_s*[\_s*N\|\_s*\|\_s*_\|\_s*z\_s*\|n\_s*\%(\|a\_s*n\_s*o\|o\_s*t\_s* \_s*o\_s*r\)\|\_s*\|\_s*\|\_s*f\|G\_s*k\)', + \ 'O' : '\%([ݜbSMoNOÌQjwdЊdYnnx遌ssና{≬ݕLڜP؋y߁WSVTRUXy􋳙{E⫝e}tcC筞[҉x^拑`q`ƊxsN˗uBbdeȊe퐊Kȉ򚙁aCO݈җ㱕zv\dʋUK{|wS^g]㠟iҜ}Dᜳ[aQ_NRVMן^q቉rSB蜊׉Wꉞʜ䉆WTgEcTٖQPѕ}ʼnY[”uN|ǛܚǕĐDVEjvɋNOj؟Ɍ䏏֒Y~щI偝aɁJnÓփIO]\|\_s*\_s*\_s*\|\_s*p\|\_s*u\|\\_s*\_s*\|S\_s*\|C\_s*\_s*C\_s*\|\_s*\|\_s*@\|\_s*\|\_s*\_s*\|\_s*\|n\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\|T\_s*[]\|\_s*[q]\|f\_s*[]\|\_s*[]\|H\_s*\|\_s*\|\_s*C\|G\_s*u\_s*t\_s*t\_s*i\_s*f\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|D\_s*i\_s*l\_s*l\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|H\_s*y\_s*p\_s*e\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*p\|\_s*[q]\|\_s*N\_s*\|{\_s*\_s*\|\_s*\|\_s*b\|A\_s*l\_s*i\_s*s\_s*m\_s*a\_s*t\_s*a\_s*l\_s*e\_s*s\|K\_s*\|\_s*l\|\_s*c\|C\_s*o\_s*p\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|o\_s*\_s*U\_s*\%(\|\_s*\)\|\_s*m\|\_s*\|\_s*]\|\_s*g\|\_s*\|\_s*\_s*\_s*P\|A\_s*[zn]\|\_s*[H]\|}\_s*\|\_s*F\|w\_s*n\_s*}\|\_s*\|z\_s*[imqx]\|\_s*\|c\_s*[_]\|\_s*O\|]\_s*c\_s*[ꕃ]\|\_s*[~C]\|\_s*\%(c\|\_s*\_s*\|\_s*V\_s*c\)\|\_s*\|\_s*[G]\|\_s*\_s*\|\_s*m\_s*\_s*\_s*\_s*\_s*\.\|G\_s*[]\|t\_s*h\_s*e\_s* \_s*O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*a\_s*n\_s*a\_s*g\_s*e\_s*m\_s*e\_s*n\_s*t\_s* \_s*G\_s*r\_s*o\_s*u\_s*p\|\_s*\_s*d\_s*@\|E\_s*\|\_s*~\|E\_s*\%(B\|[\_s*\%(Y\|\_s*\)\|\_s*{\_s*\_s*X\)\|o\_s*\|A\_s*\%(\|U\_s*[\|E\_s*\%([`g]\|^\_s*[\)\)\|\_s*{\_s*\\_s*t\_s*g\_s*E\_s*F\_s*A\|\_s*\%(\_s*[N]\|\_s*\)\|\_s*\|\_s*\_s*\|_\_s*\_s*a\|\_s*\_s*\|\_s*\_s*_\_s*f\_s*j\_s*\_s*\|`\_s*\_s*\|\_s*K\_s*\|\_s*\|\_s*Z\_s*q\|\_s*\|_\_s*f\)', + \ 'P' : '\%([BC@{sܕەy~Օҕ糕ѕ粛ؕzCUߕ[iᢔpoǕƔŔ•zusvtjHgdωՂҁ}{ՃӄkDoE_v|Łji݁aypPӃ΃sP]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[|yvsp]\|\_s*[ۂ؂Ղ҂]\|\_s*\|\_s*l\_s*\|\_s*\|O\_s*[ID]\|\_s*\|\_s*R\|\_s*D\_s*\|\_s*\|\_s*`\|\_s*\|\_s*\|\_s*q\|b\_s*\%(\|\_s*n\)\|C\_s*y\_s*c\_s*l\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|S\_s*y\_s*n\_s*a\_s*n\_s*t\_s*h\_s*a\_s*e\|r\_s*\|B\_s*r\_s*o\_s*m\_s*e\_s*l\_s*i\_s*a\_s*l\_s*e\_s*s\|L\_s*e\_s*a\_s*d\|\_s*[Ž]\|V\_s*\%(\_s*[\_s*h\|\_s*V\_s*r\_s*\)\|T\_s*\%([\_s*\|C\_s*\%([YNPR]\|\_s*V\_s*r\_s*\|\_s*E\_s*\|L\_s*b\_s*N\)\)\|+\_s*\|z\_s*\%(\|X\_s*Q\_s*\)\|q\_s*\_s*|\_s*\|\_s*\%(z\|\_s*o\)\|t\_s*\%(\_s*W\_s*A\_s*\|\_s*\%(C\_s*W\_s*\_s*O\|[\_s*\%(Y\|W\_s*\_s*O\)\)\|^\_s*\_s*C\_s*\|H\_s*\%([[mg]\|{\_s*X\|r\_s*A\|X\_s*t\_s*@\_s*[\|j\_s*[\)\|@\_s*\%(C\|\_s*I\|[\_s*\%([W}]\|~\_s*\_s*O\)\|\_s*\%(g\_s*\|^\_s*Y\_s*[}]\)\|\_s*[cX]\|\_s*m\_s*v\_s*V\_s*X\)\|B\_s*\%([]\|W\_s*\%(b\_s*N\_s*X\|J\_s*\)\|[\_s*r\_s*[\|b\_s*V\_s*\_s*O\|\_s*\_s*\|\_s*f\_s*\_s*t\_s*B\_s*A\|\_s*\%([X[Ap]\|b\_s*[vp]\|s\_s*\%(\|[\_s*k\)\)\)\|F\_s*\%([\_s*\%([xY]\|W\_s*\_s*O\)\|C\_s*Y\|\_s*\_s*\|j\_s*\%(\|b\_s*N\_s*X\|L\_s*A\|[\_s*\)\|m\_s*\%(L\_s*V\|[\_s*\)\)\)\|q\_s*\|\_s*\|^\_s*\_s*p\_s*N\_s*\|\_s*\|\_s*\_s*\|i\_s*s\|Z\_s*\|\_s*\|\_s*Z\|\_s*`\|\_s*\|^\_s*\|i\_s*\|J\_s*\_s*E\_s*\|\_s*\_s*\|d\_s*\_s*\|\_s*\_s*^\|o\_s*e\_s*\_s*\|\\_s*\_s*t\_s*\|_\_s*\|\_s*\_s*[a]\|\_s*\|\_s*\|p\_s*\%(T\_s*e\_s*X\|H\_s*\_s*[\_s*^\|e\_s*\%(t\_s*a\|r\_s*l\_s*X\_s*N\_s*\_s*v\_s*g\)\|i\_s*\%(c\_s*o\|a\_s*n\_s*\%(o\|i\_s*s\_s*s\_s*i\_s*\%(m\_s*o\|s\_s*s\_s*i\_s*m\_s*o\)\)\)\)\)', + \ 'Q' : '\%([zɟKMz՟J㖍򍥛IHEdzboxܗAϕDCBӊǏ~B䱌sZY㙬ᯞӉOM֌NϏvLK@{^Z򏾓^A鶊rňʈUÑq𞀋C~XVTRUWS܉_wo^鿌~GF䇚`p̏LY۞IȊfsގԚPMEu{[O֞oӍ@󞔐ȓScSHqvE|―ĜvꋀῙ܌JɍCg틂{m{X؍Hᜁv㜜ҙg电M͋ˋpegfhPHNQ]\|\_s*\|b\_s*N\|\_s*\|\_s*\|\_s*\|~\_s*\|\_s*\|\_s*S\|S\_s*[Z]\|\_s*\_s*x\|\_s*\|\_s*h\|9\_s*\|\_s*\|^\_s*{\|\_s*\|Q\_s*O\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|V\_s*l\_s*\|\_s*|\|T\_s*\_s*\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|T\_s*\|\_s*\|c\_s*r\_s*e\_s*s\_s*c\|C\_s*\|\_s*[{]\|\_s*\_s*\|K\_s*r\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\%([ƕE]\|o\_s*\)\|\_s*\|\_s*C\_s*a\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*\|Z\_s*\|n\_s*_\|s\_s*q\|B\_s*\|R\_s*\_s*q\|C\_s*\%(r\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\)\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|\_s*s\_s*N\_s*\|`\_s*\_s*\_s*\_s*\_s*}\|w\_s*x\|R\_s*\%([\_s*\_s*\|\_s*e\_s*B\_s*t\_s*@\_s*C\_s*A\)\|\_s*\_s*\|J\_s*\%(U\_s*\|^\_s*[\_s*\|X\_s*o\|[\_s*k\_s*[\_s*\|i\_s*[\_s*g\|_\_s*t\_s*B\|\_s*e\|h\_s*\_s*[\_s*[]\|\_s*\%(`\_s*[GF]\|e\_s*\%(B\_s*G\|b\_s*g\)\)\|\_s*^\_s*[X]\)\|\_s*\|L\_s*\%(g\|u\_s*\|z\_s*[\_s*e\|n\_s*[\_s*_\|\_s*\%(g\|e\_s*B\_s*\_s*O\)\|[\_s*\|m\_s*\|b\_s*V\_s*\|\_s*\%([\|G\_s*\)\)\)', + \ 'R' : '\%([ۛŘӛĚ̉h_R{]Ә[\U^cRP˞ulMCL属譚NdיCROcYᑘLSQXᔘWOUĘTRNb@F࢔GmedibIE炍䃟LBڟ׊aeUxvYZYtXF䫗ᖗw灟KMlI瀗qずwYQrQݗ@BA٘Hḟpᐗ㾗ۗݗZ~Kಝ_×ɌIʙZCXYVg×ڛPᎊ}֗ᅗPXaМHW˗Ԝdhgҙzؗϙחїӗ՗WOC͗`鲛饗؞Ax@_]qyp֝H×㇗ߗƗȗ열ɋʗ̚iś胗ؗܘA鋗i\ߗ仂טJəVOgTpREY㑟SB՛ۛnAࣗa茗E煚h඗pyqQ㡟ISۗᚘ痋엇tff逗ǂESqGBJH[wxIT`rKR|FVOW^XU\ZDAIYzM{Pst}NLvpyu@C]E_~D֍㗅XqQσR]\|\_s*[]\|b\_s*[]\|\_s*[]\|\_s*\|\_s*[L]\|h\_s*[Eߎ]\|6\_s*[]\|\_s*\_s*\|E\_s*G\|\_s*\|A\_s*\%(c\_s*t\_s*a\_s*e\_s*a\|p\_s*o\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|C\_s*\%(a\_s*l\_s*y\_s*c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|h\_s*o\_s*r\_s*i\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|\_s*[]\|\_s*\%(\||\_s*\)\|V\_s*e\_s*r\_s*t\_s*i\_s*c\_s*i\_s*l\_s*l\_s*a\_s*t\_s*a\_s*e\|O\_s*r\_s*c\_s*h\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|M\_s*i\_s*c\_s*r\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\|L\_s*\%([ruia]\|e\_s*i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*a\_s*l\_s*e\_s*s\|A\_s*N\_s*P\_s*[\_s*u\_s*\)\|C\_s*\|G\_s*\%(e\_s*n\_s*t\_s*i\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|y\_s*\%(n\_s*a\_s*n\_s*d\_s*r\_s*a\_s*e\|m\_s*n\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\)\|\_s*W\_s*f\_s*[\_s*^\_s*x\_s*[\_s*X\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*s\_s*\_s*w\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|d\_s*C\_s*\_s*M\_s*\_s*\_s*\|\_s*k\_s*\_s*\%(w\_s*d\_s*C\_s*\_s*M\_s*\_s*\_s*\|\_s*\)\|\_s*\_s*\_s*\_s*Z\_s*b\_s*g\_s*v\_s*Z\_s*@\|\_s*\|K\_s*\|g\_s*\|r\_s*u\_s*b\_s*y\_s*X\_s*N\_s*\_s*v\_s*g\|v\_s*\|\_s*\|\_s*A\|\_s*[M]\|\_s*\|\_s*\_s*\|Q\_s*\%(l\_s*\_s*\|\_s*^\)\|@\_s*\\_s*\_s*\_s*P\_s*\|\_s*A\_s*I\|F\_s*\|\_s*K\_s*\\_s*\|A\_s*[\_s*\)', + \ 'S' : '\%([}[Ty}Q^ǚih掞y{GOʗcԛzyu߈S^䛣᜹KU|\}ax‘ƜQsढ़w柔锚t䇛q~Hxyܑ䵑qȑBJvtƑNⵑr|swpnmy絒F\nuLMNdƑ[ꋑjfb`a^𕛑lX􉈑cYiઈgלheesSzNZ驋LLQkşGiↁސِېڐߞ@CGSПƝ[Tאɐ͊֐ȐǝAI⣛p蔞tdCNӟ׈ߛݙܘx㙘A_baJஓϛƘjbHⳙAGSL⒑Wsr葁DJAL񙒐枙@ېMHlFKDG@BhǑNdD牙|œҝᝩ⫟ŖvR呝yHՐU}[҂ߝpS爊caopIDcER䊔TωsꈝؐCShᓩ]T\~uy齗VŒsvǐEpz~dǗ俑Ypnzy羝裐Ð␕΁ʁ܁́ˁ~Ɂځށ}ȁ́݁聹后v袝xž谒NːXaV䐆Hґ]ZʗLz`DߝXzi擧ABPDY`LZ迓xZxw圑ȓGFaƎb乗MEΕsCFZnD㈵㦋s]Ŗl^⚑A潓gΖ儞ɖΏd臐wpd[g謎姎^GNH˒Ύ܊m\ސːKŽKoq҉tϔ͚͎bAjP֎ٌࡐ̝咙ݐ┐Ԏ^Ύގڎ؎YώΎɎԎߎЈޝȕiSGCဋÎft偛WVz题瑲Efiglk{蜕婏oFT碏VhqhkFJ娏QK榊S酝nSXKUڏMGjaENODPCALRTIB@M᭚忏w{vxs⡏turfZuVꐚpy曐P]AϜUjJfY`Ds橝ΐaO凓cjcѐUahNfdCkXĐLTQWgi[RMebI_S΋nZo䜏_י|䓏wb򏎏ҟm䀛uLЏ縐מ⪙דMvRߜcB_џnՏʈ䐯B辑[頏[␏ݚK♏яҁui]疏ցjiӐԚϏUJnސŜ܏ߏُՏGଞďޏ͏ǏɏЏۏ暐Ώ̏ďƏ͏ڏ؏ɏȏTlRegp@CܑFDI冐BAHE❎oowvLUnюrŎᎊtr@{펦Ϛ`iАyэi@EJX拎}泟nyoNZyzٛᝅf׎j{~|{oߘIXB]KVgup`ikql藘ʛƓj⏎s_ꏎ˔`Œsy@؎䢊oueۚ~礛JLfVWlȐ䰐囋TᰗlIJMhEU嶎z\GԞuV\Vf֟XMˍǏxš皔m匈^꛽O@՚N\󎘊jېŒB睓N@dqbPmbq嗝WƔfFⲝHHBr{吷Wvᵔutĉh|招E䋫🛋t剎櫜f|sटEa`㓝̜cHKcߙӎ[ǎWXㄐVr\]ZPRӁ3Q^ORUSY_ATCD搔@FDNZ\؛ԟ˜GƝrӎÎEq淍Kȍ͙Pꎍ`BڛvɍVҍۍЍю΍؍̍Ӎȍ֐čՍÍˍҍٍ΍ō鑨rŞo焍e⩞y|skwNʎhS䳍}lэos⍳rԍđ獸RAm嬛OÝL_~nKዎ^dw@YYご򄋄ZYÁWnŽOyʁ`feW_TZTrV\XRЕbS]\|\_s*[]\|b\_s*[\ZXVT]\|\_s*[]\|\_s*\|\\_s*\%(H\|I\_s*\)\|~\_s*\|\_s*\|\_s*\|\_s*\|\_s*g\|\_s*\|v\_s*[vX]\|\_s*n\|\_s*\|\_s*c\|\_s*\|B\_s*[BX]\|\_s*C\|\_s*\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|\_s*\|}\_s*\|c\_s*e\_s*n\_s*t\_s*i\|\_s*[ĘU]\|C\_s*\|\_s*\|}\_s*\|T\_s*\|G\_s*Y\|f\_s*\|V\_s*[c]\|V\_s*i\_s*o\_s*l\_s*a\_s*l\_s*e\_s*s\|N\_s*y\_s*m\_s*p\_s*h\_s*a\_s*e\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|\_s*\|\_s*\|b\_s*\%(^\|\_s*\)\|V\_s*\|]\_s*\|\_s*\|s\_s*[mE]\|L\_s*a\_s*\%(b\_s*i\_s*a\_s*t\_s*a\_s*e\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|\_s*\|~\_s*\|\_s*t\_s*\|\_s*\|\_s*\|\_s*_\|\_s*Y\|\_s*\|\_s*\|I\_s*\%(s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\)\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|`\_s*\|\_s*[J]\|]\_s*[X]]\|\_s*\%(X\_s*\_s*\|\_s*\_s*\)\|\_s*\%([֌ڎu]\|\_s*\)\|7\_s*\|V\_s*\|4\_s*\|S\_s*[]\|R\_s*{\|h\_s*t\|\_s*u\|\_s*\|A\_s*[o]\|\_s*[NY]\|\_s*[]\|r\_s*[ꏎ]\|\_s*\|c\_s*e\|\_s*\|\_s*\%(_\|C\_s*\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|\_s*\%(\_s*{\_s*\%(I\|\_s*I\)\|\_s*\_s*a\_s*\_s*W\)\|\_s*[Η]\|\_s*\|\_s*\|\_s*\|e\_s*\_s*\|C\_s*\%([se]\|y\_s*c\_s*a\_s*d\_s*\%(i\_s*d\_s*a\_s*e\|o\_s*\%(p\_s*s\_s*i\_s*d\_s*a\|f\_s*i\_s*l\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\)\|h\_s*l\_s*o\_s*r\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|D\_s*X\|^\_s*\_s*\|a\_s*\%(s\_s*s\_s*y\_s*t\_s*h\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|c\_s*t\_s*a\_s*l\_s*e\_s*s\)\)\|\_s*K\||\_s*[“]\|\_s*p\_s*\|G\_s*\|\_s*\|\_s*\_s*\%(X\_s*[N]\|\_s*[N]\)\|h\_s*l\|S\_s*\_s*g\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*e\|\_s*\|\_s*\%(@\|\_s*\_s*\)\|\_s*\|G\_s*\|\_s*q\|P\_s*\%(a\_s*r\_s*i\_s*e\_s*t\_s*a\_s*l\_s*e\_s*s\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|r\_s*i\_s*m\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\)\|A\_s*\%(p\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*a\_s*l\_s*e\_s*s\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\)\|s\_s*f\_s*o\_s*r\_s*z\_s*a\_s*n\_s*d\_s*o\|\_s*[T]\|B\_s*\%(r\|V\_s*F\_s*\)\|g\_s*\_s*q\|\_s*\_s*\|\_s*\|u\_s*\|A\_s*\_s*`\_s*\_s*\|\\_s*\_s*\|M\_s*\%(e\_s*r\_s*c\_s*u\_s*r\_s*y\|u\_s*s\_s*a\_s*l\_s*e\_s*s\|a\_s*r\_s*q\_s*u\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\)\|D\_s*o\_s*n\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*A\_s*l\_s*p\_s*h\_s*o\_s*n\_s*s\_s*e\_s* \_s*F\_s*r\_s*a\_s*n\_s*c\_s*o\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\|\_s*\%(V\|s\_s*\%(\_s*\|\_s*\_s*\)\)\|T\_s*\%(e\_s*t\_s*r\_s*a\_s*c\_s*e\_s*n\_s*t\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\|h\_s*e\_s* \_s*S\_s*i\_s*m\_s*p\_s*l\_s*e\_s* \_s*A\_s*P\_s*I\_s* \_s*f\_s*o\_s*r\_s* \_s*e\_s*v\_s*e\_s*n\_s*t\_s*-\_s*b\_s*a\_s*s\_s*e\_s*d\_s* \_s*X\_s*M\_s*L\_s* \_s*p\_s*a\_s*r\_s*s\_s*i\_s*n\_s*g\)\|]\_s*f\|P\_s*C\_s*f\|v\_s*\_s*\_s*\_s*\_s*\_s*w\_s*\|l\_s*b\_s*g\_s*T\_s*[\_s*r\_s*X\|U\_s*\%(b\_s*N\|N\_s*Z\_s*\|r\_s*[\_s*l\|E\_s*o\_s*[\|\_s*[\_s*N\_s*\_s*E\_s*g\|\_s*U\|\_s*c\|C\_s*\%([]\|\_s*[\|f\_s*\)\|[\_s*\%([]\|\_s*\)\)\|\_s*\|[\_s*~\|i\_s*g\_s*\_s*E\_s*\|]\_s*\%(\|\_s*f\|[\_s*\%(\|\_s*\_s*Q\_s*\)\|t\_s*B\_s*[\)\|W\_s*\%(\|[\_s*\%([ON]\|\_s*\_s*[XY]\)\|O\_s*\_s*\_s*g\|\_s*\%(\_s*\|O\_s*V\_s*\_s*s\_s*[\_s*\|e\_s*[\_s*[\)\)\|G\_s*X\|\_s*\)', + \ 'T' : '\%([ĜR牉șhЌ☝ωiמRh|cH֓騗䄋㜐C䃕ۏQ榔yFbr\c͙ʓՓךcJٓؓڏxJŚɍΖrqNPь{ԍǝؗ沖L௜{ꂜՓ“ΓWٟXB[ѓw䓄~㫙ٚĊUj㉱}b馝FD㛎衞CẞTΛ⅞MDğ椈ꊛ됀zcbuٓ幓铝~鍓򓀓˓tOO̓mNlےEjqĚ\Zg\莾pyooVvϏ\p{nlnZÊn򖁞i^yr䷟ː}~ēexhurlWPȎWd͖oR瘉NནLJU猓Hzћ迟hAVVzDCUAdFDx[^៓UzaZWL⽓YQINGPOcSLǒtɞqؚ|YBh@稒ఒAeƜV•͕皁ITPזgwΐىWhіʏ`tI␎aSڎBڐRȕpAn䆉җI~焍ߑczߝ旾񕌋uid͌gQǒٚ؍jq塔|ȕȓ`B\Չ㔖ꉌۑԔԒ̒v׏IĐȒŒǛ錼əݙ֒ߘrssnUTӑn쑢LUΌCU֋ސTĜɏՔːsxAtyÕZ㋓ᶌpklϐڒʍAhՍJY_ZoTSNĒNZm֖’ޒ}zke玐ŗ͓ߝQE浖מ`kI⌒OՒP蠒eÒ隓CUǒݟlLy’kꓜjLKӝUo{⒳\_񒝓[d}ޒ渒xaQCNIԒJnhfRhtnpom~n@ؒrpUTuՌlh⚐tꃒyƒwonvqᗒvksmxJ}֓}ԐugqKfeމ˞MoRВLᷖ非ٌ✔yg栟˘l|]漒K^ȏ̎]DM骓lDeȒ@ihgⰍkXYSݛ̝EYUԕۏXIH蒎aFC{}CJFמlSs韞퓃ࣕYۈɐҒkBznҊmtԚKpЋBŗYk˜[]썰͗K’eʖd休sb饕|cG鎿Bٍked뛹k殔CĉFbWVOxh^В|⹑tM闲F֜Ӝ`dH[t؜Tjݝ^Wh]ßp~Kϓ̝W`^WUႚVJRἔCVQa_\杒OSXWYbZdÒTPAp]鮓FѝFUVf{I痑~x擑H\讖wʝ[OlߑړܒБ⛔EܑՑ͑ۑґؑݑّё̑בޑ΋Hf茘ǒ֚ꑫ—]loNOϗ┭蛀SuNЍٚB_PcB睘SW`V~^ΓysfE\؃XWƃUcN]g`Ec[^sSфeT]\|\_s*[]\|b\_s*[gec`^]\|\_s*[ƂÂ]\|\_s*\|\_s*n\_s*\|\_s*[]\|\_s*\|\_s*l\|\_s*\|\_s*V\|\_s*\|i\_s*[v]\|\_s*P\|h\_s*\|\_s*\|D\_s*\_s*\|\_s*[Ŗ]\|\_s*[q]\|W\_s*\|\_s*\_s*E\_s*\|\_s*\|H\_s*y\_s*d\_s*r\_s*o\_s*c\_s*h\_s*a\_s*r\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*x\|G\_s*[ߓh]\|\_s*[]\|F\_s*N\_s*\|i\_s*[vq]\|A\_s*c\_s*o\_s*n\_s*i\_s*t\_s*u\_s*m\|\_s*\|\_s*j\|\_s*j\|F\_s*e\|I\_s*r\_s*o\_s*n\|\_s*\|\_s*\|g\_s*\|Z\_s*\|Q\_s*~\_s*S\|\_s*\%(\|\_s*q\)\|S\_s*[Z]\|\_s*\%(\|\_s*a\)\|X\_s*\|\_s*X\|\_s*J\|\_s*~\|~\_s*J\|\_s*\|\_s*\|\_s*\|\_s*[]\|B\_s*a\_s*l\_s*a\_s*n\_s*o\_s*p\_s*h\_s*o\_s*r\_s*a\_s*l\_s*e\_s*s\|1\_s*\%(\|0\_s*\)\|P\_s*\%(\|O\_s*\)\|\_s*\|\_s*l\_s*\|E\_s*\%(u\_s*p\_s*h\_s*o\_s*r\_s*b\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|\_s*\%(v\|\_s*F\)\|g\_s*\|\_s*\|`\_s*\|\_s*w\|\_s*\%(V\_s*\|\_s*F\)\|\_s*\%([]\|[\_s*\|\_s*\_s*N\)\|\_s*v\|r\_s*q\|\_s*r\_s*q\|\_s*[a]\|\_s*\|\_s*\|@\_s*\_s*\|L\_s*q\|S\_s*\|\_s*\|]\_s*h\|J\_s*i\_s*a\_s*n\_s*g\_s*s\_s*u\|G\_s*\|u\_s*[˔]\|k\_s*J\|\_s*\|\_s*I\_s*q\|\_s*a\|\_s*p\|\_s*[]\|A\_s*\|\_s*\_s*\|\_s*[]\|\_s*\_s*\\|\_s*\%(\\_s*\|A\_s*\_s*[]\)\|t\_s*\%(\|{\_s*V\)\|h\_s*\|e\_s*\|\_s*\|\_s*[]\|\_s*s\|\_s*\%([\|\_s*q\)\|\_s*v\|\_s*\|P\_s*\|\_s*\|\_s*\%(\|\_s*\)\|E\_s*\|\_s*\|P\_s*\%(\.\_s*S\_s*\.\|o\_s*l\_s*y\_s*\%(g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*r\_s*p\_s*i\_s*c\_s*a\_s*e\)\|a\_s*n\_s*d\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|s\_s*\|\_s*\|E\_s*w\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*q\|\\_s*[V]\|w\_s*\|\_s*\|i\_s*K\|\_s*\_s*p\|\_s*B\|M\_s*\%(e\_s*n\_s*i\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*c\_s*e\_s*a\_s*e\|o\_s*n\_s*o\_s*\%(p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*\%(h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|o\_s*t\_s*y\_s*l\_s*e\_s*d\_s*o\_s*n\_s*e\_s*a\_s*e\)\)\)\|\_s*\|\_s*\|\_s*q\|\_s*\|\_s*\|f\_s*B\_s*X\|R\_s*\_s*\|\_s*l\|\\_s*\%([\_s*[gv]\|\_s*[\)\|w\_s*[\_s*O\|[\_s*[CA]\|Z\_s*\%(I\|\_s*}\|\_s*\%(\|j\_s*A\_s*X\)\|\_s*s\_s*\%([\|X\_s*g\)\)\|V\_s*\%(\|b\_s*N\|X\_s*\|A\_s*^\_s*[\|\\_s*[\_s*\_s*X\|I\_s*h\_s*A\|[\_s*[t^]\)\|T\_s*\%([C]\|~\_s*\_s*O\|E\_s*U\_s*\_s*h\|\_s*u\_s*\_s*b\_s*h\|[\_s*\%([h]\|e\_s*B\|X\_s*g\_s*\|Y\_s*f\_s*[C[B]\|}\_s*\)\|b\_s*`\_s*\_s*[\|\_s*\%(N\|_\_s*[\|L\_s*\_s*[\)\|\_s*h\_s*}\_s*C\_s*h\)\||\_s*\_s*y\_s*v\_s*`\_s*h\|O\_s*\%(a\_s*y\|A\_s*\_s*\)\|\\\_s*T\_s*e\_s*X\|\_s*\_s*\|\_s*\_s*\|t\_s*e\_s*\%(r\_s*a\|m\_s*p\_s*o\_s*r\_s*a\_s*r\_s*y\)\|p\_s*\|d\_s*\%([b]\|C\_s*\_s*M\_s*\_s*\_s*\)\)', + \ 'U' : '\%([yhf[le񓴑a؈Ϗ鎽[XDWr䷙\wuќzD鴑ߚXi^R忓LMf~ӏr戉楓]揗w搉S^̗É򃑂k։\uLGQmPOH⣑QmIVߊaXSn|oJU󎜚y팻ʉfژⓐxԋʏϙ܉A]りCD]^@TAmSYv_ZrNTTݗƓZJjJʼnFALnћaLǎ䥟HӉEZpQGˌ̉KꚖoeY^INt҃ETU]\|\_s*\|\_s*\|\_s*\|T\_s*\|\_s*\_s*\|\_s*\|H\_s*\_s*R\|\_s*\|D\_s*\%(k\_s*[Lj]\|\_s*\)\|\_s*i\|e\_s*\|\_s*\|A\_s*\|y\_s*\|\_s*y\_s*[]\|\_s*\|\_s*[\|\_s*\|\_s*\|\_s*\|\_s*`\|\_s*c\_s*\_s*\|W\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|s\_s*\_s*\|\_s*\|\_s*\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|`\_s*\|\_s*C\_s*\|\_s*\|O\_s*Y\|\_s*\|\_s*[CB]\|\_s*\%(\|\_s*\_s*\)\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|c\_s*\|C\_s*M\_s*\_s*X\|I\_s*}\_s*\|\_s*\_s*s\_s*\\|\_s*\%(p\_s*\|L\_s*\)\|A\_s*\%([X]\|O\_s*\_s*[\|[\_s*\%(V\_s*\_s*\|W\_s*F\_s*\_s*g\|o\_s*\)\|\_s*e\_s*B\_s*\_s*b\_s*g\||\_s*\|b\_s*\%(v\|p\_s*[\|V\_s*\_s*[\)\)\|P\_s*\%(\|\_s*\)\|\_s*\%([^j[]\|g\_s*\%(\_s*\|\_s*q\_s*g\)\|\_s*\%(A\|V\_s*[\_s*Y\)\|v\_s*V\_s*\_s*\|l\_s*X\_s*R\|i\_s*\%(J\_s*C\_s*g\|C\_s*e\_s*b\_s*h\)\|r\_s*L\_s*\%(^\_s*X\|m\_s*\)\)\)', + \ 'V' : '\%([Flu۔ńBrɃV]\|\_s*\_s*\|b\_s*\|\_s*\|\_s*\|v\_s*e\_s*r\_s*s\_s*u\_s*s\|\_s*\_s*D\|`\_s*F\_s*\|\_s*^\| \_s*r\_s*N\_s*g\_s*[\_s*\|\_s*o\|\_s*z\|j\_s*X\|\_s*\|P\_s*^\|\_s*\%(f\_s*B\_s*\|M\_s*i\|j\_s*X\|Z\_s*\_s*\|N\_s*`\_s*\|\_s*L\_s*\_s*[\_s*\|\_s*\_s*[\|[\_s*j\_s*\)\|\_s*b\|{\_s*\%(X\_s*g\_s*[\_s*N\|\_s*S\_s*\|\_s*\%([K{g^]\|e\_s*\%(b\_s*N\_s*X\|[\_s*[W]\)\)\|\_s*\_s*[\_s*\|\_s*\_s*\%(`\|e\_s*B\_s*A\|^\_s*\_s*[\)\|\_s*[\|R\_s*[\_s*_\|[\_s*\%([gO]\|\_s*g\|h\_s*r\_s*\%(\|\_s*A\_s*\)\|p\_s*\|_\_s*t\_s*H\_s*\|J\_s*\%(\|\_s*X\_s*g\)\)\|L\_s*\_s*u\_s*\_s*\|C\_s*\%([hX]\|W\_s*\_s*[\|V\_s*\_s*O\)\)\|w\_s*b\_s*g\|\_s*\_s*\|\_s*\|t\_s*\%(@\_s*\%(\|h\_s*[\_s*c\)\|H\_s*\%(\|\_s*\%(N\|J\_s*[\)\)\|F\_s*\_s*\_s*[\_s*\)\|E\_s*\%(\_s*\%(f\_s*B\_s*~\_s*[\_s*\|W\_s*\%(~\_s*[\_s*\|[\_s*~\_s*\|I\_s*X\_s*g\_s*\%(N\|b\_s*N\)\)\)\|B\_s*\%(\_s*i\|\_s*X\)\|H\_s*b\_s*J\|C\_s*\%(\_s*X\|\_s*i\_s*[\)\|F\_s*\%(\_s*M\_s*\_s*E\_s*X\|k\_s*X\)\)\|r\_s*\%([AuoXU]\|K\_s*[\|n\_s*[\_s*\|^\_s*~\_s*\|\_s*\%(b\_s*W\|\_s*C\)\|r\_s*\%(A\_s*\|b\_s*h\)\|b\_s*\%(N\|L\_s*[\)\|Z\_s*\_s*e\|N\_s*\%(^\_s*[\|g\_s*\%(\|\_s*[[A]\)\)\|V\_s*\%(\_s*X\|\\_s*\_s*[\_s*Y\)\|\_s*\%([`X]\|\\_s*\|e\_s*[\_s*W\|Z\_s*\_s*g\)\|l\_s*\%(K\_s*[\|O\_s*\_s*b\_s*g\)\|j\_s*\%([[]\|\_s*f\_s*\)\|\_s*[\|G\_s*\_s*`\_s*\_s*\|W\_s*\%(\|b\_s*g\|^\_s*[\|\_s*\%(\|i\_s*\_s*[\)\|\_s*A\_s*\%(\|\_s*C\_s*\%(Y\|[\_s*[\_s*V\_s*\_s*\)\)\)\|_\_s*\|f\_s*I\|\_s*\%(S\|k\_s*[\_s*u\)\|I\_s*\|\_s*W\_s*A\_s*\|B\_s*[\_s*i\_s*X\|[\_s*\%({\|\_s*X\|N\_s*\|i\_s*X\)\)\|x\_s*\%([K]\|g\_s*i\_s*\|C\_s*_\_s*[\|[\_s*\%(\|_\_s*[\)\|e\_s*\_s*\|b\_s*Z\_s*\|X\_s*\%([g^p]\|r\_s*I\)\|N\_s*\%(^\|g\_s*\)\|W\_s*^\_s*\%(u\_s*\|\_s*A\_s*\)\|\_s*\%([B[]\|t\_s*@\_s*C\|T\_s*C\_s*\)\|\_s*\%(i\|V\_s*e\_s*B\|[\_s*i\|j\_s*[JN]\)\|\_s*\%(f\|x\_s*b\_s*g\|_\_s*\|\_s*[\_s*k\|T\_s*\%([\_s*`\|C\_s*\)\|\_s*b\_s*g\)\|m\_s*\|j\_s*[XA]\|l\_s*\%(V\_s*\_s*\|c\_s*B\_s*A\|`\_s*A\|Y\_s*G\_s*\)\)\|o\_s*\%([]\|C\_s*\%([AuI]\|p\_s*[\|^\_s*\%(\|\_s*e\_s*B\)\|L\_s*\_s*O\|U\_s*[\|V\_s*\)\|b\_s*g\|`\_s*J\_s*\|M\_s*i\|K\_s*{\_s*\_s*h\|\_s*\%(i\_s*V\|G\_s*e\_s*B\)\|T\_s*\|X\_s*\%(R\|P\_s*X\)\|J\_s*\_s*X\|P\_s*[\_s*V\_s*\_s*\|L\_s*\_s*[\_s*\|E\_s*`\_s*\_s*[\|\_s*\%(\|G\_s*[\_s*V\_s*\_s*\|\_s*[\|A\_s*\%(u\_s*\|\_s*g\)\|b\_s*h\|f\_s*[\_s*V\_s*\_s*\)\|k\_s*A\_s*c\|j\_s*\%(\|[\_s*\)\|\_s*\%([[]\|\_s*\|\_s*[\|\_s*\%(V\_s*A\|`\_s*m\|^\_s*C\_s*\)\)\|[\_s*\%([SO]\|`\_s*\_s*\|\_s*g\_s*D\_s*[\_s*h\|o\_s*\|{\_s*X\|x\_s*i\|e\_s*B\_s*J\_s*\|T\_s*X\|W\_s*\%(\|j\_s*A\|\_s*\)\|m\_s*\|j\_s*A\|\_s*\_s*g\|~\_s*\%(\_s*I\_s*\|L\_s*\_s*\_s*C\_s*g\)\)\|i\_s*\%(L\_s*\_s*\_s*[\|W\_s*E\_s*\)\)\|u\_s*\%(C\|\_s*\%(h\|b\_s*h\)\|[\_s*h\_s*D\_s*[\)\)', + \ 'W' : '\%([ɒjYyhȃ҃f[le񓴑a؈鎽[XDW䷙\wuќzD鴑ߚXi^R忓LMf~ӏr戉楓]揗w搉S^̗É򃑂k։\uLGQmPOH⣑QmIVߊaXSn|oJU󎜚y팻ʉfژⓐxԋʏϙA]゜D]^@TAmUSYvZrNTTݗƓZJjJʼnFALnћaLǎ䥟ӉEZpQGˌ̉KꚖoeY^I܉c㘟|͊ϏpԉЍЋƋZǁkYeonm܏Νtsf^]o_rqpciqǘjnȎFGd̘eΘcQC崙NZДʒtሽgfhaŒfZNO֔jclH`b̔i핝ȔgvEW]\|\_s*[]\|b\_s*[E]\|\_s*[]\|\_s*\_s*~\_s*_\|\_s*\|\_s*\|\_s*\|T\_s*\|\_s*\_s*\|\_s*\|H\_s*\_s*R\|\_s*\|D\_s*\%(k\_s*[Lj]\|\_s*\)\|\_s*i\|e\_s*\|\_s*\|A\_s*\|y\_s*\|\_s*y\_s*[]\|\_s*\|\_s*[\|\_s*\|\_s*\|\_s*\|\_s*c\_s*\_s*\|W\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|s\_s*\_s*\|\_s*\|\_s*\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|`\_s*\|\_s*C\_s*\|\_s*\|O\_s*Y\|\_s*\|\_s*[CB]\|\_s*\%(\|\_s*\_s*\)\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|c\_s*\|\_s*\|o\_s*D\|\_s*Y\_s*\|\_s*\|i\_s*\_s*j\|(\_s*\_s*)\|\_s*[]\|R\_s*\|Y\_s*z\|x\_s*\|Y\_s*\%(\|V\_s*\_s*c\|\_s*F\_s*\)\|x\_s*\%(\|V\_s*\_s*c\|\_s*F\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*[R]\|\_s*\|a\_s*t\|\_s*\_s*\_s*D\_s*\|\_s*\%(`\|\_s*m\_s*\_s*\)\|^\_s*B\_s*\_s*D\|\_s*\%(\_s*\_s*\_s*E\_s*\_s*\|\_s*\_s*\_s*E\_s*\_s*\)\|u\_s*\_s*c\_s*u\_s*\_s*N\|\_s*\_s*O\|\_s*\%(\|C\_s*X\|b\_s*J\_s*[\|X\_s*\%(\_s*[\|\_s*\_s*O\)\)\|\_s*\%([\_s*X\|\_s*N\_s*\|X\_s*g\)\|\_s*\_s*\_s*\|\_s*\%(b\_s*\%([vp]\|s\_s*\_s*O\)\|C\_s*\%([^g]\|e\_s*B\_s*\_s*O\)\)\|{\_s*\_s*t\|t\_s*\%([[]\|@\_s*C\_s*\|B\_s*\%([\_s*g\|b\_s*`\)\)\|z\_s*\%(G\_s*[C[A]\|[\_s*\|C\_s*\%([\_s*\%(\|\_s*[\)\|b\_s*\%(v\|X\_s*\|p\_s*[\|g\_s*\%(j\_s*[\|}\_s*\)\)\)\|\_s*\%(C\|b\_s*[gc]\)\)\|x\_s*\_s*i\_s*[\|w\_s*e\_s*b\_s*T\_s*\%(C\_s*g\|[\_s*\%(o\|r\_s*X\)\)\|x\_s*\|o\_s*\_s*^\_s*[\|\_s*\%(\_s*\_s*c\_s*u\_s*\_s*N\|H\_s*\_s*t\|B\_s*\%([[]\|\_s*\%(\|w\_s*\_s*\)\)\|F\_s*\%(\_s*_\_s*[\_s*X\|\_s*i\_s*[\|[\_s*o\_s*[\|C\_s*\)\|@\_s*\%(C\_s*[X]\|[\_s*O\_s*i\_s*[\|\_s*_\|\_s*\%(^\_s*[\|L\_s*\_s*[\_s*\)\)\)\|_\_s*u\_s*\_s*\_s*[\|^\_s*\_s*O\_s*X\_s*e\_s*\|T\_s*\%(h\_s*e\_s* \_s*W\_s*o\_s*r\_s*l\_s*d\_s* \_s*W\_s*i\_s*d\_s*e\_s* \_s*W\_s*e\_s*b\_s* \_s*C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\)\)', + \ 'X' : '\%([HFDB@wV~X]\|\_s*[]\|b\_s*[HFDB@]\|\_s*[]\|V\_s*\_s*\%(z\_s*\|t\_s*H\_s*\)\|W\_s*I\_s*\|[\_s*\%(r\_s*E\_s*X\|\_s*\%(b\_s*N\_s*X\|O\_s*\_s*t\_s*B\)\)\|n\_s*r\_s*G\_s*\|U\_s*\%(\|r\_s*G\_s*\)\|L\_s*\%(V\_s*\%(\|\_s*\|\_s*g\_s*[\_s*\)\|Z\_s*m\_s*\|T\_s*\_s*\%(`\_s*\|^\_s*\)\)\|E\_s*x\_s*t\_s*e\_s*n\_s*s\_s*i\_s*b\_s*l\_s*e\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|N\_s*\%(V\_s*[\|\_s*X\_s*|\_s*X\_s*g\|Z\_s*\%(i\_s*L\_s*X\|m\_s*t\_s*H\_s*\)\|U\_s*\_s*B\_s*G\|T\_s*\%(C\|\_s*\%(g\_s*X\|`\_s*b\_s*y\|e\_s*B\_s*b\_s*y\)\)\|\_s*X\_s*}\_s*X\)\|G\_s*\%(N\_s*X\|b\_s*N\_s*X\)\)', + \ 'Y' : '\%([։ߕ֍HVşꔗ؊ZݝgZ|~}ĔϑbbщxX\ccUiFg`ᇞ՗x揜JLȞ@fuꡜys@Tᘟ~m籝Xyꢗqsi^wgjsfgt匍roחldpnїwzmÏh^S焛@㏜棟baǗ_P`]rĔS㿉r\\QPaoKllPI^椂㒏̎͒oɒt沖LuVKᛮ|w䓎樏ଉw亗WzFCQޗCGEPZXNOSЗ[HI֗FYJLkሖ@gVhO䥝R埙`A懝|MgJ䲃ꍘcUTn翔䑌恍ݍrxÉj囚|dQU|軗ƑBd{Nj佈䆍mnؐFAtF泌ÌމLdƜјJiꌒՓkvɔžo֌yME|ځe퐈M臐YOΖZ}xא򌵉MՁO䗚P{bw~N}zcc硉Ɏh䕟JsW]bK\Tฐ]rmПȈZԈTDMΚICm覉@uBAAޛjHوΊֈÈ1PDyIDR۔џʈዏHƍ֋Uhwψ͉]}ubv]Ό≝gМ@ES盈BΟݑPR҈ȊUגߘߛږˆ̈،܈Η͜}Ėˈԍs਒_ˑޗǓo֗DK~䏈ӈۈ؈ًeԄ`tcbّqۈŔsMlhE`_ʗSQna_–zl˗DyيVꞟKoZމvNuk欎淏kqstrRКݓ@D洗{kJїT׈ՋxۍN❔JĜ\̖tj熔W쉮ƕaߖˎܓi댭ውƔE~xuE~vFJ҃C\zY]\|\_s*[ղ]\|b\_s*[C]\|\_s*[䂢]\|\_s*\_s*b\|^\_s*\_s*b\|I\_s*\|\_s*\|B\_s*\|I\_s*\|y\_s*o\_s*\%(t\_s*t\_s*a\|c\_s*t\_s*o\)\|4\_s*\%([“]\|\_s*\|\_s*\)\|\_s*\|m\_s*j\|\_s*\|\_s*\|F\_s*\|\_s*\|\_s*[q]\|j\_s*\|h\_s*L\|@\_s*\|V\_s*\|\_s*[j]\|\_s*[q]\|i\_s*\|W\_s*\|8\_s*\|\_s*\|t\_s*\%(\|^\_s*[\_s*\)\|\_s*\|\_s*\|\_s*\|~\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|S\_s*\|L\_s*i\_s*l\_s*i\_s*\%(o\_s*p\_s*s\_s*i\_s*d\_s*a\|a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\)\|\_s*\%(Y\|\_s*\)\|\_s*M\|\_s*\|\_s*\|\_s*\|E\_s*\%(u\|\_s*[\_s*\)\|a\_s*\|J\_s*u\_s*\%(l\_s*i\_s*a\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|n\_s*c\_s*a\_s*l\_s*e\_s*s\)\|c\_s*J\|c\_s*\|G\_s*s\|\\_s*Z\_s*\|Q\_s*q\|G\_s*\|\_s*\_s*\|\_s*\|\_s*\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*G\|\_s*\|\_s*t\_s*\|5\_s*[“]\|T\_s*[“]\|\_s*E\|r\_s*U\|\_s*\|\_s*Y\|\_s*[\|\_s*\|~\_s*\|\_s*\_s*\|{\_s*\|o\_s*\|\_s*g\|Y\_s*[q]\|h\_s*[‘]\|@\_s*\|U\_s*\%(\|^\_s*[\_s*\|r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|E\_s*[cR]\|d\_s*\%(`\_s*r\_s*s\|u\_s*d\)\|C\_s*\|]\_s*[oZ]\|\_s*\|\_s*q\|_\_s*\|\_s*\_s*\|\_s*r\_s*\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|\_s*\|\_s*\_s*\|r\_s*\|s\_s*\_s*\|o\_s*[E]\|\_s*[Wk]\|C\_s*[؎Q]\|\_s*\\|\_s*\_s*[ΒY]\|_\_s*F\|e\_s*[]\|p\_s*\%([꓍]\|g\_s*\)\|\_s*\_s*\|\_s*[ȉ]\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|s\_s*[”@]\|\_s*{\|\_s*\_s*\|\_s*\|\_s*L\_s*n\|\_s*\|\_s*[c]\|R\_s*a\_s*f\_s*f\_s*l\_s*e\_s*s\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\|\_s*\|V\_s*\\|`\_s*G\|\_s*{\_s*\_s*\|\_s*a\|T\_s*\%(h\_s*e\_s*l\_s*i\_s*g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*o\_s*c\_s*h\_s*o\_s*d\_s*e\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|M\_s*y\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\_s*t\|\_s*\|A\_s*r\_s*a\_s*c\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*\%(o\_s*t\_s*e\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*c\_s*i\_s*p\_s*e\_s*s\)\|a\_s*l\_s*m\_s*a\_s*l\_s*e\_s*s\)\|\_s*q\|\_s*[j]\|G\_s*\%(z\_s*o\|t\_s*Q\_s*j\_s*[\|\_s*\_s*@\_s*\|j\_s*Z\_s*C\|[\_s*\)\|\_s*C\)', + \ 'Z' : '\%([󉀉ꑹ㔛mґXfhّۑY\]萊AK㿑R䒑UWN征͑V陑TPQfOS␨ҐƐŐUӂžlb齕AZB@笐CtÓ|~D}ߍ󓈎ȓǎwxcH苎ҍ׎l㒼ÓKHԘᶙbiu@vސnՉ`rxosqwptlŏғ䴞`䥝募tJ珊RPԟiUㅏ{o媝mh鈐YtY竐jg@ݖÏꏗ`~]꞊󝵏GAژhGQ榜휵@uQxhmnpqmm⢙Ï|⡓՟~[x{䤏zy}}汎GEsn𘸏^F_`Oca_Y[b]\Zedm莣^y~iJ玎Ȓn􎤎~ImVkqHjaZd䢎mV␷╍蛽NM赞ƎLGRZQSₜ͛؜kO槎SbΜ͎acZːčϙ܍ލߍݍoUY][GwY]ZUyW[xĄHZ]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|b\_s*[][YWU]\|\_s*[]\|\_s*\|\_s*\|o\_s*\|\_s*[q]\|\_s*\|z\_s*e\_s*\%(t\_s*t\_s*a\|p\_s*t\_s*o\)\|\_s*\_s*\|\_s*\|O\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*p\|\_s*o\|C\_s*@\|m\_s*\|\_s*\|k\_s*[ߌY]\|\_s*\|\_s*s\|F\_s*i\_s*g\_s*u\_s*r\_s*e\|\_s*\|G\_s*\%(\_s*\|p\_s*\)\|D\_s*y\|f\_s*\%(\_s*\|p\_s*\)\|x\_s*x\|\_s*\|Q\_s*\|2\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*q\|J\_s*\%(I\_s*S\_s*R\_s*[\_s*h\||\_s*b\_s*v\|R\_s*\_s*\_s*{\)\|\_s*q\|b\_s*\_s*\_s*\_s*\_s*\_s*M\_s*h\_s*p\_s*\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|[\_s*\%(\|\_s*\)\|`\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|R\_s*l\|y\_s*_\|\_s*\|\_s*\|\_s*\|\_s*r\_s*\|\_s*v\|\_s*\|\_s*\|\_s*\|\_s*[@S]\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|i\_s*\%(\_s*[\_s*O\||\_s*b\_s*v\|t\_s*m\_s*j\_s*n\)\|\_s*q\|\_s*\|P\_s*\%(Q\|O\_s*[i]\|P\_s*\|U\_s*i\|W\_s*\)\|t\_s*\|\_s*\|R\_s*\|1\_s*\%(0\|1\_s*\|8\_s*\|2\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*u\|e\_s*\|\_s*\|\_s*\|\_s*{\|U\_s*\_s*\|\_s*H\|\_s*\|T\_s*\%(\_s*\|\_s*|\_s*[\_s*j\_s*\|\_s*S\_s*T\)\|V\_s*\%(^\_s*[\_s*\|I\_s*\%(\|j\_s*\%(X\_s*g\|Y\_s*\)\)\)\|`\_s*\%(N\_s*\_s*X\|A\_s*m\_s*[\_s*[\|\_s*[\_s*\_s*\%(q\|b\_s*q\)\|\_s*\_s*_\_s*b\_s*V\_s*\|S\_s*C\_s*l\_s*\_s*\_s*C\_s*[\_s*\)\|c\_s*\%(@\_s*\%(\_s*g\_s*D\_s*X\_s*g\_s*\|C\_s*g\)\|F\_s*\%(i\_s*[\|b\_s*y\_s*\_s*\|\_s*}\_s*b\_s*g\)\|B\_s*\%(N\_s*\_s*X\|^\_s*[\|[\_s*O\_s*\_s*[\|\_s*\%(o\_s*\_s*\|}\_s*[\_s*}\_s*\)\|S\_s*C\_s*l\_s*\)\)\)', + \ } +endfunction diff --git a/bundle/clever-f.vim/autoload/clever_f/migemo/eucjp.vim b/bundle/clever-f.vim/autoload/clever_f/migemo/eucjp.vim new file mode 100644 index 000000000..a247def12 --- /dev/null +++ b/bundle/clever-f.vim/autoload/clever_f/migemo/eucjp.vim @@ -0,0 +1,57 @@ +scriptencoding euc-jp +function! clever_f#migemo#eucjp#load_dict() abort + return { + \ 'a' : '\%([ԳȯϾտƭ޾ӡŤƬѫͷʷİͿø̵ܶܵ驰нƪ鷹ѻˢǽܽ֦½ΦؽǮȲ䰵ǴռݯмԹڹײϪɽ¹ͽЮɷ庾Ӻ̴ɵఽ;ŷ°ֵϰ̣Ԫƴ갮ůۭμ氰ᄑϯ۸ޫۦۥ˾ϾԼݷʸۣ齶ϰ갥欷԰ǰްưðȰīﰦð­ҹӼ밫Ƽǹ˽˰ķ°մ尤Ըʻᰢͭ˴±޽کг󰸶˰بĤ&ʢܶ϶΢͢޸姸ơǡ򦡥ѧa]\|\_s*\|\_s*\|\_s*\|\_s*\|Z\_s*\%(n\|i\_s*n\_s*c\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ŷ\_s*\|\_s*ŵ\|\_s*\|\_s*\|\_s*Ʀ\|\_s*\|\_s*\|\_s*̾\|\_s*̾\|\_s*\|\_s*\|\_s*[Ļ]\|\_s*\|\_s*\|\_s*\|L\_s*a\_s*r\_s*d\_s*i\_s*z\_s*a\_s*b\_s*a\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*\%(\|¹\_s*\)\|\_s*\%(\|\_s*\_s*\_s*ʪ\_s*\)\|\_s*\_s*\|H\_s*a\_s*l\_s*o\_s*r\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|ޱ\_s*\|\_s*\|Ʀ\_s*\|\_s*\_s*\_s*\|\_s*¿\|\_s*\|\_s*\|\_s*[Ǭ]\|\_s*\|\_s*[ɧ]\|\_s*\|\_s*\|\_s*\|Ҹ\_s*\|\_s*\%([]\|\_s*\|\_s*\)\|\_s*[ˡ]\|E\_s*\%(s\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\)\|I\_s*\%(r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(\_s*\|\_s*\_s*\_s*\)\|D\_s*\_s*\_s*\|C\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\%(\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*[ɿͽ]\|R\_s*u\_s*b\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*[]\|M\_s*a\_s*l\_s*v\_s*a\_s*l\_s*e\_s*s\|\_s*\_s*\_s*\_s*A\|\_s*\| \_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|G\_s*o\_s*l\_s*d\|\_s*ư\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|°\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|S\_s*\%(b\|i\_s*l\_s*v\_s*e\_s*r\)\|\_s*\_s*\_s*ǽ\|\_s*\_s*\_s*ǽ\|\_s*ˡ\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\%([]\|\_s*\%(\_s*\|\_s*\)\)\)\|\_s*\%([ȥ]\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\_s*\|\_s*\%([]\|\_s*\_s*\)\|\_s*\_s*\%(\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\)\)\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\%(\_s*\_s*\|\_s*ǽ\)\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\)\|A\_s*\%([tlrImc]\|u\_s*s\_s*t\_s*r\_s*o\_s*b\_s*a\_s*i\_s*l\_s*e\_s*y\_s*a\_s*c\_s*e\_s*a\_s*e\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\|K\_s*C\_s*L\|S\_s*C\_s*I\_s*I\|s\_s*t\_s*a\_s*t\_s*i\_s*n\_s*e\|\_s*\_s*\|T\_s*O\_s*K\|N\_s*S\_s*I\|V\_s*\_s*\_s*\_s*\|L\_s*T\_s*\_s*\|\_s*\_s*\|E\_s*R\_s*A\|D\_s*S\_s*L\_s*\_s*\_s*\|\_s*\_s*\_s*\|d\_s*a\|M\_s*\_s*\_s*\|b\_s*s\_s*t\_s*r\_s*a\_s*c\_s*t\_s* \_s*C\_s*o\_s*n\_s*t\_s*r\_s*o\_s*l\_s* \_s*M\_s*o\_s*d\_s*e\_s*l\|\_s*\_s*\|\_s*\_s*\|C\_s*\_s*\_s*\_s*\)\|\_s*Ͽ\|\_s*\%([]\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%([˥ᥢ]\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\%(\|\_s*\_s*\)\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\)\)', + \ 'b' : '\%([߹ڽھ˲ѳ̶˦꼰汬˳ر˸˹˻˶˺˴˾˵˿籸촳Ħ˷ը˫ѹʽٷҡ޺˼ūʥ޽޼޿ʪɲʹʸ̵ʬק£͹ɵɤޣֱؾݧɴ졪¡ɼǭ֢ʿջ̤׹߾Ȣ®Ӷ˪ȭƯȫȪʵɡüΥV̥ȵٶȶǢʢĻʧ㱸Ȥ˽ʱ೭ȹȨؤȽȼ㩺Ȳȴȳ粽ڱĥŽУʩݲߡá¡ݡܥСϡΡСѥ֥ӧҦ¥b]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[ܥ٥֥ӥ]\|\_s*[ܤ٤֤Ӥ]\|\_s*\|\_s*\|\_s*\|P\_s*a\_s*e\_s*o\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*Ǥ\|\_s*\|\_s*[]\|\_s*\_s*ݰ\|F\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|˭\_s*[]\|\_s*\|ŷ\_s*\_s*\|\_s*[϶]\|׽\_s*˥\|\_s*[̡˥]\|\_s*Ҵ\|\_s*Ƭ\_s*\|\_s*\|\_s*\|S\_s*a\_s*n\_s*t\_s*a\_s*l\_s*a\_s*l\_s*e\_s*s\|\_s*\|ʼ\_s*[ˡ]\|ɽ\_s*\|\_s*[Ļ]\|\_s*\|ȯ\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|R\_s*o\_s*s\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\%([ӳϫ]\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|A\_s*n\_s*n\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*[]\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*[]\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\|\_s*\%([Ƚ鷿]\|\_s*˦\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s* \_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\|B\_s*\%([hȽ鷿kiae]\|C\_s*ʼ\_s*\|N\_s*F\_s*(\_s*B\_s*a\_s*c\_s*k\_s*u\_s*s\_s*-\_s*N\_s*a\_s*u\_s*r\_s* \_s*F\_s*o\_s*r\_s*m\_s*)\|B\_s*C\|\_s*\_s*\|u\_s*r\_s*k\_s*i\_s*n\_s*a\_s* \_s*F\_s*a\_s*s\_s*o\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|M\_s*P\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|S\_s*\%(D\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|O\_s*X\_s*\_s*\_s*\|I\_s*T\_s*N\_s*E\_s*T\|r\_s*o\_s*m\_s*i\_s*n\_s*e\|\_s*\_s*\|o\_s*\%(h\_s*r\_s*i\_s*u\_s*m\|v\_s*i\_s*n\_s*e\_s* \_s*S\_s*p\_s*o\_s*n\_s*g\_s*i\_s*f\_s*o\_s*r\_s*m\_s* \_s*E\_s*n\_s*c\_s*e\_s*p\_s*h\_s*a\_s*l\_s*o\_s*p\_s*a\_s*t\_s*h\_s*y\|o\_s*k\|r\_s*o\_s*n\)\)\|\_s*\)', + \ 'c' : '\%([²ݰťޢͷ°Я⸿ȽҸǼۻô㪸ۺ礷򼷻쮱Ѻ˹Ϲٹʺú̶縥պۦĹȹָ벹Һ٬̫ޫ޳䲬ު־ϹϺ٫ȺӫִӳӬص޸ܺս幡͹䢹̨ɹж๫ʹĹá񹸹ۥ⫹ֹѸ۹չ̹˹عֹ骹ݹҹԹιӹĸëӭ͹޺ݻջ̼ԵʴԸƸ۸žĶٸĨ̱۸ɸָܵʽѻᡵǻ۹ɯ˻íܦ岱ӵʡ޶٣໦Ҫͼٰ֣ڱ·޷߫ѩѢߥѡ٥Ѩڣݺګ̻خعɹԤܯݬݮܱܮݫʵߪʤվ߷ţ賷ΦۻҮ·ط״򷬷ڶ˿ֲ̽ǰ̰鶰פ޺ޱͿ߸Ѧ庿ܸȷˮԢʭЦչġҵ׹޷˹ȸҢڹ׶ҿȴȷͤԱ飼ýƳħ󻼲١Ĵɸ¢ֺλߨߧ¼ȻοǦǧк尷樵ԦܰǢܾؼżĬ߼ȼ𮼻ꩼɨũżʻ͸忬ļҼԺաĵհռޯκբٱؼڷּ忼мܼѼ׼ͼм˼ּҰʵżެոշܤܣƵýʽȽͽɽܼ̿꫽нܶꪽӴ֭ϼܽµ½Ѯضآ߽ؽ޴׽ٽ䣽ֽ߿Ӣ֪ǿп¿Ŀ˿ӿ¿ǿä⿹ƿʿƿ謹еؽ޵ַҾľ䬼ֹ᳻ļװգңطӾԡĽؾѾءϾ޾۾¾騾ľ㾩ܥ񾬽Ͼɾ˾ƴҾ;оƾȾϾܾþھ˾ԧ֤ѿ°濣鿨лػ㭻׶ӶǼӡܻҿӺǡɦ֬寿¶ǻлף㬰ԮǷȻֻѻʻ̼̦Żڻڼ褴λƤڹɳ߳˹ȷ̢ư񢿱Ʊʡܢᱵ𦪦ʹǡˡҡԡơȡɡѡСաجɳ϶ѾʸܵȿǣʶͽгϾݵع˵ۿٸǷշͩΫKĴȱ١ҤҳݢٿȦ۫滳ܾ龹ôŽ޳ڳ³귰¦ǰ㡴姢റҳݲҳ˿ڸিԣϸ³ø֡١סʷŭƬŨŬȾŤ״׳ᰥɬŴܷ̳봢ԽڲӾ׳ڨƿӽdzӡϡۡڡ̡͡γȳijԳճʳ߱׳ڼȵҳֳѳТӼ뻳һרݥųЪĻӳܴ߳ٳβ𳭳dz򳬲Ԭ٪Хٺù٢Ӳߵ۸Ұ楼Ѵ޾˸˧ӳޱڿͻôÿȡȴ䯴԰ݴ۴ڴԴա̴δ˴עӴĴִٴ״ӿŴɴشϴѴشԳҵȴճƶDzμŲͲӻ۷紣ҲԥФҲһݲݲִּȼڲ桶˲ŰײӧҷܴѫββϲѼнӥѷϲӲɲշ߲Ʋ²ȾƸϲˤ㡦ıĶƢ۲øҧ姨ৣ٧اӧݧ᧷짢ۧ秮ܧԧէާ觯קѧڧ֧䧡𧦧ߧ맥ߨƼ֦ҧ駹ݡ׶ܥ񥷡c]\|\_s*[]\|\_s*[]\|\_s*[Ҥ]\|\_s*\|\_s*\_s*Ⱦ\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*ϧ\|\_s*\|\_s*\|\_s*\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|\_s*Ѥ\|\_s*\|A\_s*\%(r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|p\_s*i\_s*a\_s*l\_s*e\_s*s\)\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|\_s*\|\_s*\|\_s*ˡ\|\_s*[ʺ]\|\_s*[϶]\|ѱ\_s*\|\_s*\|\_s*[̱]\|\_s*\|\_s*\|ɴ\_s*[߻]\|\_s*\|9\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|ŵ\_s*\_s*\|õ\_s*\|\_s*¢\_s*\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|ϻ\_s*\|\_s*\|\_s*\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|Ϸ\_s*\|˾\_s*Ĭ\|\_s*[]\|\_s*Ϣ\|\_s*[Ǧ]\|\_s*\|L\_s*a\_s*\%(u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|b\_s*i\_s*a\_s*t\_s*a\_s*e\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|ʾ\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|ت\_s*ͺ\|\_s*\|\_s*\|I\_s*\%(s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\)\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*ʸ\|\_s*[]\|\_s*\%([αֲ˼]\|\_s*\|Ǽ\_s*\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|7\_s*\|\_s*\|ʸ\_s*\|4\_s*\|\_s*[ʬ]\|\_s*\|\_s*\|\_s*\|\_s*[̰]\|\_s*\|\_s*\%(̣\|\_s*\)\|\_s*[]\|͢\_s*[]\|´\_s*\|B\_s*r\|Ȼ\_s*[ϯϺ]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|M\_s*\%(e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|u\_s*s\_s*a\_s*l\_s*e\_s*s\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|S\_s*\%([eg]\|p\_s*e\_s*r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*i\_s*t\_s*a\_s*m\_s*i\_s*n\_s*e\_s*a\_s*e\)\|³\_s*\%(\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\|\_s*ƻ\)\|\_s*\|Υ\_s*\_s*Υ\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*Ƭ\|\_s*\%(\|\_s*\)\|Ĺ\_s*[]\|\_s*\|ŷ\_s*\%(\|\_s*\)\|\_s*\|\_s*\_s*\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*[]\|̱\_s*\|\_s*\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|\_s*\|\_s*\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|o\_s*\%(t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\|d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\)\)\|\_s*\|Ϣ\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|Ϥ\_s*\)\|\_s*\|\_s*[]\|\_s*\%([]\|\_s*\|\_s*\_s*Ω\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*[]\|(\_s*\_s*)\|\_s*\_s*\|\_s*ʼ\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|ݣ\_s*\|\_s*\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*ƣ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|ʬ\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*[׼꾽]\|ʣ\_s*\_s*̿\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\|\_s*\%([]\|\_s*\%(\|\_s*\)\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\_s*\%(\_s*\|\_s*\)\)\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\%(\_s*\|\_s*\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\)\)\)\|\_s*\_s*\_s*\|\_s*\|\_s*\%([]\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*[]\|\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\)\|\_s*\%([֥ץ]\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\)\)\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%([]\|\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\_s*\_s*\)\)\|\_s*\%(\|\_s*\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\%([ɥѥ֥]\|\_s*\%(\|\_s*\_s*\)\|\_s*\%([]\|\_s*\%(\|\_s*\_s*\_s*\)\)\|\_s*\|\_s*\%(\_s*[]\|\_s*\)\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\)\|\_s*\%([ĥȥ]\|\_s*\|\_s*\|\_s*\%(\|\_s*\|\_s*\%(\|\_s*\)\)\)\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\%(\|\_s*\)\)\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*\_s*[]\|\_s*\)\|\_s*\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\)\|\_s*\)\|\_s*\%(\|\_s*\|\_s*\_s*\)\)\|\_s*\|\_s*\%([ޥ]\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\%([ץ]\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\%([եȥץ]\|\_s*\|\_s*\)\|\_s*\%([]\|\_s*\%(\|\_s*\)\|\_s*\%(\_s*\|\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\|\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\%([ȥ]\|\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\|\_s*\)\)\|\_s*\%([եɥ󥳥ꥦ]\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\%(\_s*[]\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%([ȥॸ]\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\%([]\|\_s*\)\)\|\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\)\)\|\_s*ɸ\|\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*³\|C\_s*\%([srdfDeRoa]\|\_s*\|\_s*\_s*\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(U\|S\_s*(\_s*C\_s*o\_s*n\_s*t\_s*i\_s*n\_s*u\_s*a\_s*t\_s*i\_s*o\_s*n\_s*-\_s*P\_s*a\_s*s\_s*s\_s*i\_s*n\_s*g\_s* \_s*S\_s*t\_s*y\_s*l\_s*e\_s*)\)\|u\_s*r\_s*i\_s*u\_s*m\|M\_s*\%(U\|\_s*\_s*\)\|\_s*\_s*\|T\_s*\%(\_s*\_s*\_s*\|R\_s*L\_s*\_s*\)\|\_s*\_s*\|S\_s*\%(V\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|C\_s*\%(R\_s*(\_s*C\_s*r\_s*e\_s*e\_s*d\_s*e\_s*n\_s*c\_s*e\_s* \_s*C\_s*l\_s*e\_s*a\_s*r\_s*w\_s*a\_s*t\_s*e\_s*r\_s* \_s*R\_s*e\_s*v\_s*i\_s*v\_s*a\_s*l\_s*)\|D\_s*\_s*\_s*\)\|\_s*\_s*\_s*\|+\_s*+\|L\_s*\%(X\|O\_s*S\|I\_s*S\_s*P\)\|E\_s*S\_s*P\|A\_s*\%(D\|S\_s*[LE]\)\|\_s*\_s*\|I\_s*S\_s*C\|h\_s*\%(l\_s*o\_s*r\_s*\%(a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\_s*e\)\|r\_s*o\_s*m\_s*i\_s*u\_s*m\|a\_s*S\_s*e\_s*n\)\|O\_s*\%(B\_s*O\_s*L\|N\_s*T\_s*R\_s*O\_s*L\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\)\)\|ú\_s*\|\_s*\%([]\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*2\|\_s*\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\)\)', + \ 'd' : '\%([ñӹɾǯĻЧγѪƯƺߡѯƫƣޡƷƴ΢ƼƵƳƸƲƶưƹƱƻ׸۲αͻϿظͻڤɻǩťŮҴޡܬѣžȤǥɶʹ˶¤Դ͸ŵͿϢťϼ¼êíǻïîնԵ庲ë۴ݹէåæǶʿϡö׼ԥٽձټΩѵί۴̽пѼ߱ͤľЦ\.ġȡɢãȥɡǦħբd]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[ɥǥť¥]\|\_s*[ɤǤŤ¤]\|\_s*\|\_s*\_s*\|\_s*\|S\_s*a\_s*u\_s*r\_s*u\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|C\_s*\%(u\|o\_s*p\_s*p\_s*e\_s*r\)\|\_s*ŷ\_s*\|Ʀ\_s*\|ǡ\_s*\|\_s*\|\_s*\|Ǵ\_s*\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\|Ƭ\_s*[]\|\_s*\|\_s*\|\_s*\|Ĵ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ã\|\_s*\|\_s*\|\_s*\_s*ã\_s*¿\|\_s*\%([˸]\|ʿ\_s*\|\_s*ŷ\_s*\|\_s*\%(\|\_s*\)\)\|ǵ\_s*[]\|\_s*\|\_s*\|\_s*\%(\_s*ʪ\|\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\_s*\|\_s*\|\_s*\|ʸ\_s*\|\_s*\_s*\|ȯ\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*ά\|\_s*\_s*\|\_s*\|D\_s*\%(b\|\_s*\_s*\|T\_s*\%(E\|P\_s*\_s*\_s*\|M\_s*\_s*\_s*\)\|M\_s*A\|\_s*\_s*\_s*\|\_s*\_s*\|C\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|u\_s*b\_s*n\_s*i\_s*u\_s*m\|B\_s*\%(M\_s*S\|\_s*\_s*\)\|H\_s*C\_s*P\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\)\|y\_s*\%(s\_s*p\_s*r\_s*o\_s*s\_s*i\_s*u\_s*m\|l\_s*a\_s*n\)\|r\_s* \_s*P\_s*e\_s*p\_s*p\_s*e\_s*r\|\_s*\_s*\|V\_s*D\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\)\|O\_s*S\|o\_s*\%(c\_s*u\_s*m\_s*e\_s*n\_s*t\_s* \_s*\%(T\_s*y\_s*p\_s*e\_s* \_s*D\_s*e\_s*f\_s*i\_s*n\_s*i\_s*t\_s*i\_s*o\_s*n\|O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*o\_s*d\_s*e\_s*l\)\|C\_s*o\_s*M\_s*o\)\|e\_s*\%(g\_s*e\_s*n\_s*e\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|l\_s*a\_s*w\_s*a\_s*r\_s*e\)\|E\_s*\%(C\|L\_s*\_s*\)\|I\_s*\%(P\_s*\_s*\_s*\_s*\|S\_s*K\)\|i\_s*\%(r\_s*e\_s*c\_s*t\_s* \_s*M\_s*e\_s*m\_s*o\_s*r\_s*y\_s* \_s*A\_s*c\_s*c\_s*e\_s*s\_s*s\|s\_s*t\_s*r\_s*i\_s*c\_s*t\_s* \_s*o\_s*f\_s* \_s*C\_s*o\_s*l\_s*u\_s*m\_s*b\_s*i\_s*a\|g\_s*i\_s*t\_s*a\_s*l\)\)\)', + \ 'e' : '\%([ٱ稰Զ콸ս֦廷ٱְܱױرԨųɲСݩ޽޼ާǢޱ޻ʥԤϱͱն۪߱бհܳϱƱñȱԱűƱӱDZɱϱı̱޹зتͲ±ݲþв΢ᢺ⧮ޣ姯Ѣмǧ㧳ݧŧ泌e]\|A\_s*\%([Ƚ]\|V\_s*\%(\_s*\|\_s*ͥ\)\|B\_s*\%(\|C\_s*\)\)\|\_s*\%([Ƚ]\|\_s*\%(\_s*\|\_s*ͥ\)\|\_s*\)\|\_s*\%(\|\_s*\)\|ɰ\_s*\_s*\|M\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*˹\_s*\|\_s*ʪ\|\_s*\|˦\_s*\|\_s*\_s*\|Լ\_s*\|\_s*\|\_s*ϩ\|\_s*\|\_s*[Ի]\|\_s*ƺ\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|L\_s*\%(\_s*\_s*\|L\_s*\%(\_s*\_s*\|\_s*\)\)\|\_s*\%([ɲ]\|\_s*\)\|N\_s*\| \_s*n\_s* \_s*\_s*\|\_s*\%([Ķ˶]\|\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\%([Ȼʶ]\|\_s*\_s*\|\_s*\|\_s*\_s*\)\|S\_s*\%([]\|\_s*\_s*\|N\_s*\|F\_s*\_s*\)\|\_s*[¿]\|X\_s*\%([]\|O\_s*\|\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\)\|\_s*ƻ\|\_s*Ʀ\|C\_s*\%(l\|h\_s*l\_s*o\_s*r\_s*i\_s*n\_s*e\)\|\_s*\%(Ϸ\|\_s*\)\|\_s*\_s*\_s*®\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\)\|ݿ\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\_s*\_s*\|\_s*\)\)\|\_s*\|\_s*Ĵ\|\_s*\_s*\_s*\%(\_s*\|\_s*\)\|ȯ\_s*Ÿ\|ɾ\_s*\_s*\_s*\|\_s*\_s*\|ɴ\_s*\_s*\_s*ŵ\|\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\|\_s*ĥ\|\_s*\|\_s*ò\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\%([ޥ]\|\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\)\)\|\_s*Ω\|E\_s*\%(r\|O\_s*F\|u\_s*\%(p\_s*o\_s*m\_s*a\_s*t\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|r\_s*o\_s*p\_s*i\_s*u\_s*m\)\|U\_s*C\_s*\_s*\_s*\|P\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|d\_s*i\_s*t\_s*i\_s*n\_s*g\_s* \_s*M\_s*A\_s*C\_s*r\_s*o\_s*S\|\_s*\_s*\|-\_s*m\_s*a\_s*i\_s*l\|\_s*\_s*\|\_s*\_s*\_s*\|N\_s*T\_s*E\_s*R\_s*\_s*\|\_s*\_s*\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\|S\_s*\%(P\|C\_s*\_s*\)\|l\_s*k\|m\_s*a\_s*c\_s*s\)\|\_s*\%([֥顼]\|\_s*\_s*\_s*\|\_s*\_s*\_s*[ȥ]\|\_s*\%(\_s*\|\_s*\_s*[]\)\|\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\_s*[ȥ]\|\_s*\)\|\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\|\_s*\)\|\_s*\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*[䥢]\|\_s*\%(\_s*\%(\|\_s*\|\_s*\)\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\)\)\|\_s*\%(\|\_s*\_s*\_s*\)\)', + \ 'f' : '\%([ϼвɮ˼ݵϰ˴ϴʻÿū߹ʷʵʸʯʭʶʲʱʬʴڸ޽ʥ޼⵺бƣ߬ѵοʳʰزʧʨؿ礢ıǹ޴ʤʢʣʡԴҿϷƧнҶ꿣ڿʮ߹ֿʫݤգŴϢ٢޶ʩʦFէf]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ǹ\|\_s*\|\_s*\|E\_s*u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\%(Ǥ\|\_s*[]\)\|\_s*\|Ƭ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|M\_s*y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*[滳]\|\_s*\|B\_s*u\_s*d\_s*d\_s*l\_s*e\_s*j\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*[ͤ]\|\_s*\|2\_s*\%([ͤ]\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*Χ\_s*\|I\_s*r\_s*o\_s*n\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\%(\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\%(\_s*\|\_s*\_s*\_s*\)\)\)\|\_s*\|\_s*\|\_s*ǽ\|\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\_s*[]\)\|\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*1\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\)', + \ 'g' : '\%([Ʊ亲޺иЯǡ¹ɹϿйⶳݶ蹡贻˸Ӫ伸˸ظ5Ķۻٸѻ줴֡ɷ޷߷ݱŴɧѷʸ¸뻲²ƤʵʹҰ¢襸ж鹶ܶ溷ֶ򹰶㼶ȶ餰ݵ۶Է̵֪ƸߤѧĶȶǶŹԵյڵ۵õ췷Ѧ»·赼ĵۧີ٦ȱⷸ⧹εߴ¦̳Ǹ񷿷Ը걳޽˳̿Ƭ︷̴ݢ޴ḵس̳۳ٳܳڳش㨳ЩԶ䳯ֽ糳ӱ⭳賩ֶѴݲծӨ̲´ϲ谽˲쾡󡤬紤楬֦ԦƦѦɦզӦ˦ϦͦצئĦ¦ЦŦҦȦǦʦΦ̦Ԧçg]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\_s*\|\_s*Ƭ\_s*\|\_s*\|\_s*\|P\_s*e\_s*r\_s*s\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\%([ֱ]\|ŷ\_s*\)\|\_s*\_s*\|\_s*\%([Ÿо]\|\_s*\)\|Ʀ\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[¯]\|\_s*[ǹ]\|\_s*\|\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*[׹]\|\_s*ϡ\|\_s*\|\_s*\|\_s*\%([]\|\_s*\)\|\_s*\%([ˡƻ]\|\_s*\_s*\|ʹ\_s*\_s*ˡ\)\|A\_s*g\|S\_s*\%(c\_s*r\_s*o\_s*p\_s*h\_s*u\_s*l\_s*a\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*m\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|i\_s*l\_s*v\_s*e\_s*r\)\|\_s*\|\_s*\_s*ë\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*̾\|T\_s*y\_s*p\_s*a\_s*l\_s*e\_s*s\|\_s*[]\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|Ϣ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\|G\_s*\%([dae]\|o\_s*m\_s*o\_s*r\_s*t\_s*e\_s*g\_s*a\_s*c\_s*e\_s*a\_s*e\|M\_s*\%(T\|D\_s*(\_s*G\_s*e\_s*r\_s*m\_s*a\_s*n\_s* \_s*N\_s*a\_s*t\_s*i\_s*o\_s*n\_s*a\_s*l\_s* \_s*R\_s*e\_s*s\_s*e\_s*a\_s*r\_s*c\_s*h\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\_s* \_s*f\_s*o\_s*r\_s* \_s*C\_s*o\_s*m\_s*p\_s*u\_s*t\_s*e\_s*r\_s* \_s*S\_s*c\_s*i\_s*e\_s*n\_s*c\_s*e\_s*)\)\|\_s*\|C\_s*L\|c\_s*c\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\|P\_s*L\|n\_s*u\_s*s\|I\_s*\%(N\_s*A\_s*(\_s*t\_s*h\_s*e\_s* \_s*G\_s*e\_s*n\_s*e\_s*r\_s*i\_s*c\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*t\_s*i\_s*v\_s*e\_s* \_s*A\_s*p\_s*p\_s*l\_s*i\_s*c\_s*a\_s*t\_s*i\_s*o\_s*n\_s*)\|F\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\)\)\|U\_s*I\|N\_s*U\|O\_s*\_s*\_s*\|E\_s*T\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\%(\|\_s*\_s*\)\)\)\|\_s*\%(\|\_s*\_s*\)\|\_s*\%([른Υʥ]\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\%(\|\_s*\_s*\_s*\)\)\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*[˥]\|\_s*\_s*[˥]\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\%(\|\_s*\%(\|\_s*\|\_s*\_s*[ĥ]\)\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\)\|\_s*\|\_s*\%([]\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\%([եޥ]\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*[ȥ]\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\)\|\_s*\|\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\%(\|\_s*[]\)\|\_s*\)\)\)\)', + \ 'h' : '\%([άмۭϯƶشǮ˴ꥷֹ٢ڣþ̷ȸԼƾԵұٸޤê׺˲˯ˣ˱˩ˬˢ߰˥˨ˮ˰˦˭ˤڽھӮƱĦ˫ԾӬێ͸½Ш۳ֱ׭׬̦΢٨ղʽ֢ʾʻ򰵸͸؎ϼвر˼ݵɾϰϴʻÿū߹ʷʵʸʯʭʶʲʱʬʴڸ޽ʥ޼бBƣ߬ѵοʳʰزʩFʦʨյؿ乢ǹ޴ʤʣʡԴҿƧнҶ꿣ڿʮ߹ֿʫՎϷDzDZɢݽɨڻײɦگٶɳߪ̩߫ҷΨɢʺɽźƶѽñ¾Ʒ1ඡɩϾǼݱɧҹɴҿɪ粹ɲɱ桶ڲŸͨ妳ѽʹɱ繰͵עɯɥɭɤʴɫݤ̤ɮɬɶɷɿɺɻʼɼɾɸʿɽ֡ڡʡآ羷۬զҸ壸Уﴳɹɰ̥ݺ㰤Ҏʻȧ۽ˡȣַүꤾ׼׹Ȧ߶ھ¦ൡá˵ȫƯȪIJԸʧȷȩ㳾СȰϸܥ˧ʢͪڼѶΥȹȸަɡڲչȤҺýҹȢȡ򾾹ٰ®Ȼиݢ֯ڦԦ¬ѳĽ̷׿޸ȥȮϡȭ˪ȱˡȰȬȯڴԯأצɣԳ߯ޢȨźܹڵȼȽɺȾȿȺǿԺı۱ŶķƱüҵ਻ԳܱĥŽ淿ʤϣ訬ȡաҥۥإh]\|\_s*[Ύ͎̎ˎ]\|\_s*[ۥإեҥ]\|\_s*[ۤؤդҤ]\|\_s*\|\_s*\|\_s*Ļ\|\_s*\|\_s*[]\|\_s*\|\_s*[п]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*[]\|T\_s*r\_s*i\_s*u\_s*r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*ˡ\|\_s*λ\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|c\_s*l\_s*a\_s*u\_s*s\_s*t\_s*r\_s*o\_s*p\_s*h\_s*o\_s*b\_s*i\_s*a\|\_s*\|\_s*\|\_s*\|E\_s*\%(r\_s*i\_s*o\_s*c\_s*a\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\|u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\|Ƭ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|f\_s*\%(o\_s*r\_s*t\_s*e\|e\_s*m\_s*t\_s*o\)\|\_s*[滳]\|\_s*\|\_s*\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%([ͽ]\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*ŷ\_s*\|\_s*[]\|\_s*\|\_s*[ȡ]\|\_s*\_s*\%(\|\_s*\)\|A\_s*\%(s\|r\_s*s\_s*e\_s*n\_s*i\_s*c\|n\_s*g\_s*i\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\|\_s*\_s*\|\_s*\_s*\|\_s*[]\|\_s*\|ľ\_s*[Ᵽ]\|\_s*Φ\|\_s*\_s*\|\_s*\|\_s*Ÿ\|\_s*[˹]\|\_s*\|\_s*ƻ\|\_s*\|\_s*\|\_s*\|̢\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|ι\_s*\|N\_s*e\_s*l\_s*u\_s*m\_s*b\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\_s*\|Ʊ\_s*˦\|\_s*\|\_s*[ȧ]\|\_s*[]\|\_s*[ǵ]\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|Ĺ\_s*ë\|\_s*\_s*\|Ż\_s*Ƭ\|\_s*\|\_s*\|\_s*[]\|\_s*\%(\_s*\|\_s*\)\|ͦ\_s*[]\|ή\_s*\|\_s*\|2\_s*\%([ͤ]\|\_s*\|0\_s*\)\|\_s*\%([ͤ]\|\_s*[]\)\|ø\_s*\|8\_s*\|\_s*\|P\_s*\%(t\|o\_s*t\_s*a\_s*m\_s*o\_s*g\_s*e\_s*t\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*t\_s*i\_s*n\_s*u\_s*m\)\|\_s*\%([]\|\_s*\_s*\|\_s*\)\|\_s*ή\|\_s*\|\_s*\|\_s*\|R\_s*S\_s*I\|M\_s*\%(y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*c\_s*u\_s*r\_s*y\)\|\_s*Ĵ\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\%(\|\_s*[ȥ]\)\)\|\_s*\|\_s*ϻ\_s*\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\)\|\_s*\%([顼]\|\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\%(\|\_s*\)\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\)\|H\_s*\%([fsPeo]\|i\_s*m\_s*a\_s*n\_s*t\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\_s*\|T\_s*\%(M\_s*L\_s*\_s*\_s*\_s*\|T\_s*P\_s*\_s*\_s*\)\|D\_s*D\_s*\_s*\_s*\_s*\_s*\|u\_s*r\_s*d\|a\_s*\%(s\_s*s\_s*i\_s*u\_s*m\|f\_s*n\_s*i\_s*u\_s*m\|w\_s*a\_s*i\_s*i\)\|y\_s*\%(p\_s*e\_s*r\_s* \_s*T\_s*e\_s*x\_s*t\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|d\_s*\%(n\_s*o\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|r\_s*\%(a\_s*s\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|o\_s*\%(s\_s*t\_s*a\_s*c\_s*h\_s*y\_s*d\_s*a\_s*l\_s*e\_s*s\|g\_s*e\_s*n\)\)\)\)\)\|\_s*[ʿ]\)', + \ 'i' : '\%([DZߡ׶׵϶̴ߺ̤ӷŲݳͶưݡȵܵ述S׽ꭲڿĹǢ̿쵸Ÿವżϫĺ׻кطҮͦܡǮʰᰱ˻ްϮסӱ©ĩ寱۱İս˻Сݫ׸ԩ۵ʰݻְյ׮Ųΰ𨱡ֱ۩۰дذYŰ1ڴŪ٥ަ̰թȺص°ذѰϱԣиȰǡѦ״ͣ޻׳԰ʳױİΰڸްͰֹаΨͬհݰڰ۵ɹۢ͢ˣ籥ɥɧڻi]\|E\_s*\_s*\_s*\|\_s*\|J\_s*u\_s*n\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*ë\|\_s*ʸ\_s*\|\_s*\|ɨ\_s*\|\_s*ϻ\_s*\|\_s*\|\_s*±\|\_s*\_s*\|\_s*ȷ\|β\_s*\|\_s*\_s*\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*ɨ\|\_s*\|\_s*\_s*ƣ\|5\_s*[]\|\_s*[]\|ب\_s*٦\|\_s*\|Ĭ\_s*\|\_s*\|\_s*Ӽ\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|ʸ\_s*\|Ϻ\_s*[]\|\_s*[]\|\_s*\|U\_s*r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*[Ļ]\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*[ﷻ]\|\_s*\|ݬ\_s*\|\_s*\|\_s*\|\_s*¹\_s*\|\_s*\_s*\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|\_s*\|\_s*\|\_s*\_s*ή\|\_s*[]\|\_s*[]\|\_s*[ڻ]\|\_s*ɽ\|\_s*\_s*[ú]\|\_s*ӧ\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|\_s*[]\|<\_s*=\_s*=\_s*>\|ɬ\_s*\_s*\_s*ʬ\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\_s*\|ɸ\_s*\_s*\_s*\_s*\)\|\_s*Υ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|¨\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|̵\_s*\%(\_s*\|\_s*\)\|\_s*Ǽ\_s*ˡ\|\_s*\_s*\|\_s*\%([ǡ­]\|\_s*ʬ\)\|\_s*\_s*\|\_s*\|Ƴ\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\)\|I\_s*\%([rPn]\|R\_s*Q\|\_s*\_s*\|C\_s*\%(\_s*\|\_s*\_s*\|\_s*\_s*\)\|l\_s*l\_s*i\_s*n\_s*o\_s*i\_s*s\|S\_s*\%(O\|B\_s*N\_s*\%(\_s*\|\_s*\_s*\)\|A\_s*\_s*\)\|d\_s*a\_s*h\_s*o\|D\_s*\%(\_s*\_s*\|E\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\)\)\|\_s*\_s*\|T\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\)\|o\_s*\%(w\_s*a\|d\_s*i\_s*n\_s*e\)\)\|\_s*\%(\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\)\)\)\)', + \ 'j' : '\%([ֺɼټľ¿̭ߩʿ顿ױӿпԿҿؿѿտǽޮտٳа屽лġпЫǡ̼žվڷǨèط۲ٽɽμѽȻŽޭ߱覽۽ڽ޽޼쳼ߨкߧ尽Ľ½ýƽ֮꼥Ώ߼ֵᪿλ̻Яϩ˱ѻżб褻κԼٵͤꨢ֧קj]\|\_s*\_s*\|\_s*\|\_s*\|G\_s*\%(\_s*\|\_s*\)\|Z\_s*\%(r\|i\_s*r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\)\|D\_s*y\|\_s*\%(\_s*\|\_s*\)\|\_s*\|\_s*\|\_s*\_s*\%(\_s*\|\_s*\)\|\_s*\|2\_s*\|\_s*\|\_s*\_s*ʺ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*ī\|\_s*\|Ƚ\_s*\|ϳ\_s*\|\_s*\|\_s*\_s*\_s*\|Ĺ\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*Τ\|\_s*[ϴ崽]\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\|\_s*\|\_s*\%(\|\_s*[ʷ]\|\_s*\|\_s*\|\_s*\)\|\_s*\|\_s*\|ɳ\_s*\|1\_s*\%(0\|1\_s*\|8\_s*\|2\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*̣\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*Ʊ\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\_s*\|\_s*\|\_s*Φ\_s*\_s*ü\_s*\%(\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\%([˥ʡ]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*[ӥ]\|\_s*\)\|\_s*\%(\_s*[]\|\_s*[]\)\|J\_s*\%(R\_s*\_s*\_s*\|\.\_s*S\_s*\.\_s*\%(\_s*\_s*\|B\_s*a\_s*c\_s*h\)\|\_s*\_s*\|\_s*\_s*\|C\_s*B\_s*\_s*\_s*\|-\_s*P\_s*O\_s*P\|\_s*\_s*\|P\_s*\%(G\_s*\_s*\_s*\_s*\|E\_s*G\_s*\_s*\_s*\_s*\)\|I\_s*S\_s*\%(\_s*\_s*\|\_s*\_s*\)\|a\_s*p\_s*a\_s*n\_s* \_s*A\_s*d\_s*v\_s*a\_s*n\_s*c\_s*e\_s*d\_s* \_s*I\_s*n\_s*s\_s*t\_s*i\_s*t\_s*u\_s*t\_s*e\_s* \_s*o\_s*f\_s* \_s*S\_s*c\_s*i\_s*e\_s*n\_s*c\_s*e\_s* \_s*a\_s*n\_s*d\_s* \_s*T\_s*e\_s*c\_s*h\_s*n\_s*o\_s*l\_s*o\_s*g\_s*y\|A\_s*\%(I\_s*S\_s*T\|N\_s*\_s*\_s*\|V\_s*A\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|U\_s*N\_s*E\_s*T\)\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\)\|\_s*\%([ϥ]\|\_s*\_s*\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\_s*\|\_s*[]\)\|\_s*\%(\_s*\%([ʥ]\|\_s*\%(\|\_s*\)\|\_s*\)\|\_s*\%(\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\)\)\|\_s*\%([]\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\)\|\_s*\%([֥]\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\|\_s*\%([ȥ]\|\_s*\|\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*[ʥ]\)\)', + \ 'k' : '\%([²ǷťưЯ⸼ȽҸǼ㪸ۻ쮱੻ֿѺϹٹʺú纯պۦĹȹָ벹Һ٬̫ޫ޳䲬ު־㣸ϹϺ٫ȺӫִӳӬص޸ܺս͹̨ɹж๫ʹĹá񹸹ۥ⫹ֹѹ۹չ̹˹عֹ骹ݹҹԹιӹĸëӭйݻջ̼ԺʴԺƸ䲾Ƹ۸žĶٸĨӾ̱ۻҸɸָܵŽѻǻûƤҸݰٽᾱʷϿٱЭۿݼܷغѭԡ޲իҥݾشկثڷ𸳰̷ո丮Ǹݷڸ建ҧҾتϨꥷ찷Ʒ̷÷Ҧ׷ۤܯݬݮܱܮݫʵߪʤվ߷ţ賷ΦۻҮ·ذѾ򷬷ڶ˿ֲ̽ǰ̰鶰פ޺Ϳ߷Ѧν庿ܸȷˮԢɦʭܿЦĸ¢޷˹ȸҢڹҿȶ꤯ӽ廸͵θ˨ž䷯ݢݡ뿸֨ɵɵǵ̵Ƶʡޢ̡ޡá笠ܡ塹Ţ硧顩¢ġ졵ˡ桼ݢ᡺Ժٹܶµϴߵʷߵ̸׶ܶ۶ڢҶݸٶڶӶ϶׶նѶ۶ֶضбڡکڪӵҨީд򰰶ɵժ亶ѿַﶷѬзź䡹ިٰװ¶ѹ߶ҳٶɶѾ貶󶩶жᶧŶö̵̾֩켣ŵָյⱱ͵ܵ׵ֵȷٵߵ޵۶ݺʹݤױ̴ڵſөɱȲøڶ˷Ҽ¶𵦵ۮ־ةȩܵѥ·д̧İɺݸ嵥ڵ޿洴ԭԵڸ쵧㵫٣ֿ۹ڹɳ߳˹ȷ̢ư좿ƱʡܢᱵרǡˡҡԡơȡɡѡСաôجɳ϶ѾʸܵȿǣʶͽгϾݵع˵ۿٸǷշͩΫĴȱ١ҤҳݢʢٿȦ۫滳ܾ龹ôŽ޳ڳ³귰¦㡴姢̻റɵҳݹ޳˿ڸিԣϸ³ø֡١׷ŭƬŨŬŤ״׳ᰥɬŴܷ̳봢ԽڲӾ׳ڨƿӽdzӡϡۡڡ̡͡γȳijԳճʳ߱׳ڼȵҳֳѳТӼ뻳һרݥųЪĻӳܴ߷ٳβ𳭳dz򳬲Ԭ٪Хٺù٢Ӳߵ۸ҰᴮѴ޾˧ӳޱڿͻôÿȡȴ䯴԰ݴ۴ڴԴʴա̴δ˴עӴĴִٴ״ӿŴɴشϴѴشԳҵȴճƶDzμŲòͲӻ۷紣ҲԥФҲһݲݲָ򴢱ּȼڲ桶˲ŰײӧҷܴѫββϲѼнӥѷϲӲɲշ߲Ʋ²ȾƸϲݤᨱ秷ʳK߶Ҧ֥ܥk]\|\_s*[]\|\_s*[]\|\_s*[Ҥ]\|\_s*\|\_s*\|\_s*\_s*Ⱦ\|\_s*ë\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*ϧ\|\_s*\|\_s*\|\_s*\|M\_s*e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|\_s*Ϣ\_s*̣\|\_s*\|\_s*\|\_s*\|S\_s*i\|\_s*\|ɴ\_s*[߻]\|9\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|ŵ\_s*\_s*\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|õ\_s*\|\_s*\|c\_s*r\_s*e\_s*s\_s*c\|\_s*¢\_s*\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|ϻ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[Ƿ]\|\_s*\|\_s*ɧ\|\_s*\|\_s*\_s*Ļ\|X\_s*e\|ǡ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|G\_s*o\_s*l\_s*d\|A\_s*\%(u\|r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|s\_s*t\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\_s*\|\_s*\|R\_s*\%(h\_s*\%(o\_s*e\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\)\|u\_s*n\_s*u\_s*n\_s*c\_s*u\_s*l\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|a\_s*n\_s*\%(u\_s*n\_s*c\_s*u\_s*l\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*l\_s*e\_s*s\)\)\|\_s*\|\_s*[©]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\%([]\|̳\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*ŵ\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*ƻ\)\|\_s*\|Υ\_s*\_s*Υ\_s*\|\_s*Ƭ\|\_s*\%(\|\_s*\)\|\_s*\|Ĺ\_s*[]\|\_s*\|ŷ\_s*\%(\|\_s*\)\|\_s*\|\_s*\_s*\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*[]\|̱\_s*\|\_s*\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|Ϣ\_s*\|\_s*\|\_s*\_s*\|C\_s*\%([ormdfa]\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\|i\_s*r\_s*c\_s*a\_s*e\_s*a\_s*s\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*r\_s*i\_s*u\_s*m\|e\_s*r\_s*c\_s*i\_s*d\_s*i\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|Ϥ\_s*\)\|\_s*\|\_s*[׼]\|\_s*\%(\|\_s*\_s*Ω\_s*\_s*\_s*\_s*\_s*\_s*\)\|(\_s*\_s*)\|\_s*\|\_s*\_s*\|\_s*ʼ\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\|\_s*\|\_s*[׿]\|\_s*\|ݣ\_s*\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|\_s*\%([֥]\|\_s*\|\_s*\%([ȥ]\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\)\)\|\_s*\%(\_s*\%(\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\)\|\_s*\_s*\|\_s*[եȥ]\)\|\_s*\%(\|\_s*\%(\|\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\)\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|a\_s*p\_s*a\_s*v\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|o\_s*\%(d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\)\)\)', + \ 'l' : '\%([족̢ТϢ˥ʥݦ򧭦l]\|\_s*[]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\_s*2\_s*\_s*ˡ\|\.\_s*\.\_s*\.\|\_s*\|\_s*\|\_s*\|ݦ\_s*ݨ\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%([֥ܥȥᥦ]\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\|\_s*\%([ƥȥ]\|\_s*\%(\_s*\|\_s*\)\|\_s*\)\|\_s*\_s*\|\_s*\_s*\%([ȥ]\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\_s*\%(\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*[ȥ]\)\|\_s*\|\_s*\%([]\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*[]\|\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%([]\|\_s*\)\)\)\|\\\_s*L\_s*a\_s*T\_s*e\_s*X\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\%(\_s*\|\_s*\|\_s*\)\|\_s*\_s*\|A\_s*\_s*E\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\)\)\|L\_s*\%([DP]\|\_s*\_s*\|L\_s*\_s*\_s*\|u\_s*\%(t\_s*e\_s*t\_s*i\_s*u\_s*m\|c\_s*i\_s*d\)\|i\_s*\%(t\_s*h\_s*i\_s*u\_s*m\|s\_s*p\|n\_s*u\_s*x\)\|E\_s*D\_s*\_s*\_s*\|e\_s*m\_s*m\_s*a\|o\_s*\%(g\_s*i\_s*c\_s*a\_s*l\_s* \_s*U\_s*n\_s*i\_s*t\_s* \_s*N\_s*u\_s*m\_s*b\_s*e\_s*r\|u\_s*i\_s*s\_s*i\_s*a\_s*n\_s*a\)\|a\_s*\%(w\_s*r\_s*e\_s*n\_s*c\_s*i\_s*u\_s*m\|n\_s*t\_s*h\_s*a\_s*n\_s*u\_s*m\|T\_s*e\_s*X\)\|A\_s*N\)\|\_s*\_s*\|\_s*\|\_s*\%([ݥޥʥΥ̥֥]\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*[]\|\_s*[]\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*[륷]\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*[]\)\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*\%([]\|\_s*\|\_s*\)\|\_s*\%([]\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%([ɥԥץ]\|\_s*\)\)\)', + \ 'm' : '\%([Ӵڬߪ߫һսοʹʪأε첼ЪǴܸʸݨۯۤ˴ݼ˾dzϳܾըлӤոľѾճ˨λتۻΪ溵ʰ̺üӹɴϢ͸¼߶ٽﶻŷ̼ǫƿ̸̵̴̶̻̹ϻپ̷̳믵Ĺǥߺ֪Ь夰յ𢨡̮þ̬ѰλûǣץŹ̨ºļšѢ١۱̰ǧʾƳϩƻм̯̾̿̽Ե㴳ﲸ̫Ĵ̩̪̲̱ܳ׽̭뷱ο̧̥̣̦ʿߎϸٿܵŪ¹׿׾ᵼžеȱμ°ẕ̇ҸƦԫѿǤʶĴٰüᶶ賹ĮԤ硬ˡʱߴʣ󺵸ػϨŻȨؤ̢̡Ϯ򾾶踭ͥϺ۾̤⼬غѿ˻ޣ̢ޡࢿܡޢ΢Тʢꢻ覤͡碾ݢϢߢˡߢ⢩ݥ޺ǥߥ᧮m]\|\_s*[ӎҎюЎ]\|\_s*[ߥ]\|\_s*[ߤ]\|\_s*[]\|\_s*\%([Ͽ]\|\_s*\|\_s*\)\|\_s*\|\_s*\_s*\%(\|ʸ\_s*\)\|ξ\_s*\%([ѿƿ]\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|O\_s*l\_s*e\_s*a\_s*l\_s*e\_s*s\|ر\_s*\|\_s*\_s*\|\_s*\|\_s*ĥ\|\_s*[]\|\_s*\_s*ӧ\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%([ͭ]\|\_s*ƻ\|\_s*\)\|\_s*\|\_s*\|6\_s*\|\_s*\|\_s*\|\_s*\|\_s*;\_s*\|\_s*\|B\_s*\%(e\_s*r\_s*b\_s*e\_s*r\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*o\_s*r\_s*r\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|©\_s*\|k\_s*\$\_s*_\_s*{\_s*i\_s*n\_s*f\_s*}\_s*\$\|\_s*\|A\_s*\%(b\_s*i\_s*e\_s*s\|p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*r\_s*o\_s*s\_s*t\_s*i\_s*c\_s*h\_s*u\_s*m\)\|\_s*\|\_s*ȷ\|\_s*\|\_s*[]\|\_s*\|\_s*\|Φ\_s*\|\_s*[ҽԢ]\|3\_s*[]\|\_s*[]\|\_s*[ȱ]\|\_s*\|ȷ\_s*\|\_s*\|\_s*[˪]\|P\_s*o\_s*d\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*[ζε]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|R\_s*u\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\%(̣\|\_s*[ž]\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*Ļ\|\_s*\|\_s*\|\_s*[һ]\|\_s*\|ߴ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*ã\|\_s*\|\_s*[̯]\|\_s*\|\_s*\|L\_s*o\_s*g\_s*a\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|Ю\_s*\|\_s*\|\_s*\|S\_s*\%(a\_s*p\_s*i\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|c\_s*h\_s*i\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|C\_s*\%(a\_s*s\_s*u\_s*a\_s*r\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*a\_s*t\_s*o\_s*p\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\%(\_s*\|\_s*\)\|H\_s*a\_s*m\_s*a\_s*m\_s*e\_s*l\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*[Ƿ]\|\_s*ɧ\|ʹ\_s*\|\_s*\|\_s*[§]\|\_s*\_s*ǯ\|\_s*\|¿\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|ñ\_s*\_s*\|\_s*\|\_s*\_s*[]\|\_s*\_s*\|\_s*\_s*Ǿ\|\_s*[]\|\_s*\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\)\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*Ū\_s*\_s*̣\|\_s*\_s*\%(\_s*̣\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|M\_s*\%([dgtnOo]\|X\_s*\_s*\_s*\|\_s*\_s*\|S\_s*-\_s*D\_s*O\_s*S\|L\_s*\_s*\_s*\|P\_s*3\_s*\_s*\_s*\%(\_s*\_s*\|\_s*\_s*\)\|D\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|c\_s*C\_s*a\_s*r\_s*t\_s*h\_s*y\|e\_s*\%(d\_s*u\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*l\_s*e\_s*s\|i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*u\_s*m\|t\_s*a\_s*F\_s*o\_s*n\_s*t\|n\_s*\%(y\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|d\_s*e\_s*l\_s*e\_s*v\_s*i\_s*u\_s*m\)\|C\_s*a\_s*b\)\|u\_s*l\_s*e\|A\_s*C\_s*\_s*\_s*\_s*\|a\_s*\%(g\_s*n\_s*\%(o\_s*l\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|e\_s*s\_s*i\_s*u\_s*m\)\|n\_s*\%(u\_s*\%(s\_s*c\_s*r\_s*i\_s*p\_s*t\_s* \_s*E\_s*d\_s*i\_s*t\_s*i\_s*n\_s*g\|e\_s*d\)\|g\_s*a\_s*n\_s*e\_s*s\_s*e\)\|r\_s*y\_s*l\_s*a\_s*n\_s*d\|i\_s*n\_s*e\|k\_s*e\_s*f\_s*i\_s*l\_s*e\|c\_s*\%(h\|i\_s*n\_s*t\_s*o\_s*s\_s*h\)\|s\_s*\%(s\_s*a\_s*c\_s*h\_s*u\_s*s\_s*e\_s*t\_s*t\_s*s\|t\_s*e\_s*r\_s*C\_s*a\_s*r\_s*d\)\)\|i\_s*\%(n\_s*n\_s*e\_s*s\_s*o\_s*t\_s*a\|s\_s*s\_s*\%(i\_s*s\_s*s\_s*i\_s*p\_s*p\_s*i\|o\_s*u\_s*r\_s*i\)\|c\_s*\%(r\_s*o\_s* \_s*S\_s*o\_s*f\_s*t\_s*w\_s*a\_s*r\_s*e\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*s\|h\_s*i\_s*g\_s*a\_s*n\)\)\|I\_s*\%(T\|P\_s*S\|M\_s*D\)\)\|\_s*\)', + \ 'n' : '\%([ݥɽ԰ھ翮Ǽ¡۩׵˾̰ĵƭоӸĪɫŸˡŵ§ϵůۨǹǿǾǽǶǸЫݻǷҾݡǻĤΎ߿ݦեǫդٹǭʿܡ̲ǮϫǬ̭ܬDzǰdzǯ޺ǴͺDZǪϣ಻ǩ͎Բʾ迡۾ݹŧ޹dzǨæ˥ȴٶɤ̎ٿô콭ʨ߳ƲؽǢѦ浶ǡǣԡբ١ذլѹٿǦǥǧǤ̶֮ƨ2бðˎٸij֧ť鵵ͼ㳴÷òڳвּͱľؽǺޥϲ˿ܧƻб±ŵڽͨƷȱįή¸ܩĹ޽Ⱦ棷мǵճǢԶ󢿢͢Ǽ̵ٽձ޸ѵİྨӭڵ˴Ƥʨ̾˥̡͢ʥ̥Φߦn]\|Ģ\_s*\|\_s*\|\_s*\|\_s*ö\|\_s*\_s*ȿ\|\_s*\_s*\|ϵ\_s*[ݱ]\|\_s*\|\_s*\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\|\_s*\_s*\|\_s*Ƿ\|\_s*\|ο\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*;\_s*\|\_s*\|\_s*\|I\_s*I\_s*\|\_s*ȭ\|\_s*\|\_s*\| \_s*2\_s* \_s*\_s*\_s*\|M\_s*y\_s*r\_s*i\_s*s\_s*t\_s*i\_s*c\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*ѵ\|\_s*[]\|P\_s*b\|L\_s*e\_s*a\_s*d\|\_s*[]\|C\_s*\%(e\_s*l\_s*a\_s*s\_s*t\_s*r\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*r\_s*y\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*\%(\_s*\|\_s*ʪ\)\|\_s*\_s*\|7\_s*[]\|\_s*\|\_s*\|ʿ\_s*\|\_s*\|\_s*\_s*\_s*\|T\_s*h\_s*e\_s* \_s*N\_s*e\_s*t\_s*w\_s*o\_s*r\_s*k\_s* \_s*I\_s*n\_s*f\_s*o\_s*r\_s*m\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\|S\_s*o\_s*\%(l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|d\_s*i\_s*u\_s*m\)\|ɳ\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\%([]\|\_s*\_s*\_s*\|\.\_s*\_s*\.\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\)\)\|\_s*\_s*\|\_s*\|\_s*\|N\_s*\%([dpbaeoi]\|R\_s*Z\_s*I\|-\_s*g\_s*r\_s*a\_s*m\|G\_s*\_s*\_s*\|H\_s*K\_s*\%(\_s*\_s*\|\_s*\_s*\)\|T\_s*T\|Y\_s*\_s*\|U\_s*L\_s*L\|A\_s*S\_s*A\|E\_s*\%(C\|p\_s*o\_s*c\_s*h\|m\_s*a\_s*c\_s*s\)\)\|\_s*\|\_s*\)', + \ 'o' : '\%([Ůۯ۰Ÿ۲˻ҳŵسḯԹ䲮ɭڶڼᡸǦƼĹĽǼԲ£ȳ־쿯Φֲݣſ༫ʳˬʲ񤲷ǰ߰θۻɽ̶Ͷ笲ݶذߴ޳۾ʲإᥲصռ鲪ݯݳ²۷겣ݿӵ꾪Ʊٱ⳸͸Ȳϵ˲˱¿ʤDzϺڨϯݰƿϷͦ˵Ӱ˿侭˸಼ͺߺӱä¢ˢৰϡئo]\|\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*Ȭ\_s*\|Ŵ\_s*\|\_s*ȱ\_s*\_s*\|\_s*\|\_s*\|\_s*̣\|\_s*\_s*\|\_s*ʴ\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|ب\_s*\|˵\_s*[]\|\_s*[̼]\|\_s*[]\|\_s*[]\|թ\_s*\|\_s*\|\_s*\|G\_s*u\_s*t\_s*t\_s*i\_s*f\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|D\_s*i\_s*l\_s*l\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|H\_s*y\_s*p\_s*e\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*[̼]\|\_s*ǯ\_s*\|\_s*\_s*\|\_s*\|\_s*\|A\_s*l\_s*i\_s*s\_s*m\_s*a\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\|C\_s*o\_s*p\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\_s*\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ʪ\|\_s*\_s*\_s*\|\_s*[]\|\_s*[]\|\_s*Υ\|ز\_s*\|\_s*\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*[]\|\_s*\|\_s*\_s*[]\|\_s*[߳]\|\_s*\%(\|\_s*\_s*η\|\_s*ŷ\_s*\)\|\_s*Ƭ\|\_s*[]\|\_s*\_s*¾\|\_s*\_s*\_s*\_s*\_s*\_s*\.\|\_s*[ζ]\|t\_s*h\_s*e\_s* \_s*O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*a\_s*n\_s*a\_s*g\_s*e\_s*m\_s*e\_s*n\_s*t\_s* \_s*G\_s*r\_s*o\_s*u\_s*p\|Ω\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\%([]\|\_s*\)\)\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*[ǯ]\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*Ŭ\_s*\|\_s*\%([ӷ]\|\_s*\|\.\_s*\_s*\.\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\)\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|O\_s*\%([sS]\|h\_s*i\_s*o\|k\_s*l\_s*a\_s*h\_s*o\_s*m\_s*a\|b\_s*j\_s*e\_s*c\_s*t\_s*-\_s*O\_s*r\_s*i\_s*e\_s*n\_s*t\_s*e\_s*d\|O\_s*\%(D\_s*L\|P\_s*L\)\|M\_s*R\_s*O\_s*N\|A\_s*\_s*\_s*\_s*\_s*\|C\_s*R\_s*\_s*\_s*\|r\_s*e\_s*g\_s*o\_s*n\|''\_s*R\_s*e\_s*i\_s*l\_s*l\_s*y\_s* \_s*J\_s*a\_s*p\_s*a\_s*n\|\_s*\_s*\|p\_s*e\_s*n\_s*W\_s*i\_s*n\_s*d\_s*o\_s*w\|x\_s*y\_s*g\_s*e\_s*n\)\)', + \ 'p' : '\%([ˣˤˡܮʻáʬɤɶɼʿȯȢʧʢȬ˱ĥѣפԡޡܤצը̨󡥡򢩡ץǡˡʢߢ¥ڥѧզХp]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[ݥڥץԥ]\|\_s*[ݤڤפԤ]\|\_s*\|\_s*\_s*Į\|\_s*\|\_s*[Ϫϥ]\|\_s*\|\_s*\|\_s*ϥ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(Τ\|\_s*\)\|C\_s*y\_s*c\_s*l\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|S\_s*y\_s*n\_s*a\_s*n\_s*t\_s*h\_s*a\_s*e\|\_s*\|B\_s*r\_s*o\_s*m\_s*e\_s*l\_s*i\_s*a\_s*l\_s*e\_s*s\|L\_s*e\_s*a\_s*d\|\_s*[ļ]\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\%([]\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\)\)\|+\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|Χ\_s*\)\|\_s*\%(\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\_s*\_s*\|\_s*\%([Υ]\|\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\)\|\_s*\%(\|\_s*\|\_s*\%([]\|\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*[]\)\|\_s*[ĥ]\|\_s*\_s*\_s*\_s*\)\|\_s*\%([]\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\%([]\|\_s*[ץ]\|\_s*\%(\|\_s*\)\)\)\|\_s*\%(\_s*\%([٥]\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\)\)\)\|\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*³\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*ˡ\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\%(\|\_s*\_s*\)\)\|\_s*³\|\_s*\_s*\_s*\|\_s*ƺ\_s*\|\_s*\_s*\|¿\_s*\_s*\|\_s*\_s*\_s*\|Ž\_s*\_s*\_s*\|\_s*ʸ\|\_s*\_s*[]\|\_s*\|\_s*\|P\_s*\%([umdCaor]\|K\_s*\|D\_s*F\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\.\_s*S\_s*\.\|S\_s*\%(\.\|Y\_s*\_s*S\)\|I\_s*C\_s*\_s*\_s*\_s*\|l\_s*\%(a\_s*t\_s*i\_s*n\_s*u\_s*m\|u\_s*t\_s*o\_s*n\_s*i\_s*u\_s*m\)\|E\_s*T\_s*\_s*\_s*\|O\_s*S\_s*\%(\_s*\_s*\_s*\|I\_s*X\|T\_s*\_s*\_s*\_s*\)\|e\_s*\%(r\_s*l\|n\_s*\%(t\_s*\%(o\_s*x\_s*y\_s*l\_s*i\_s*d\_s*a\_s*e\|i\_s*u\_s*m\)\|n\_s*s\_s*y\_s*l\_s*v\_s*a\_s*n\_s*i\_s*a\)\)\|h\_s*o\_s*s\_s*p\_s*h\_s*o\_s*r\_s*u\_s*s\)\)', + \ 'q' : '\%([ܯݬݮܱܮݫʵߪ緩ųʤմɾ߷ţ賷ΦۻҮղطѾ뷭򷬷ڶ˿ֲ̽ǰ̰鶰ȱפ޺ޱͿ߷Ѧν庿ܸ𷪶ʳdzˮԢɦʭӼЦչ硡Ŵġ¢ҵ׹׶޷˹ȸҢܸڹ׶ҿȴȷ϶Ͷꎸơȡǡɢq]\|\_s*\|\_s*\|\_s*\|\_s*̼\|\_s*\|\_s*\|\_s*\|\_s*Ѵ\|ɴ\_s*[߻]\|\_s*\_s*\|\_s*ʪ\|\_s*\|9\_s*\|Ĺ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|ŷ\_s*\_s*\|\_s*\|ŵ\_s*\_s*\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|õ\_s*\|\_s*\|c\_s*r\_s*e\_s*s\_s*c\|\_s*\|\_s*[]\|\_s*¢\_s*\|K\_s*r\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\%([ʸ]\|\_s*\)\|\_s*\|\_s*Ѥ\_s*\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*\|ϻ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|C\_s*\%(r\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\)\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|\_s*\_s*\|\_s*\_s*ϯ\_s*\|\_s*\_s*\_s*\_s*\_s*\|Q\_s*\%(I\_s*C\|R\_s*\_s*\_s*\|C\_s*\_s*\_s*\_s*\|U\_s*O\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*[]\|\_s*\%(\_s*[]\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\_s*[ॹ]\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\)\)', + \ 'r' : '\%([αϾϼϽϿ߳ϱϮӤۭӯѤҩ۰ϺϭϴϲϹϸϰ϶ϵϳϯϧȧϨתϦݭߣްٳѶӺүߺ㹵ݬݮҳҽ߲ݲϡϣڻϢϩޥﻼϬڶΫάΪΨ˷Χҭϻ٤Φ߱ίβΰαΩγέδήPܲשاηκϤθо̺ۢסڢɩζοε˵νμλξιΥΣΡ΢ߢئΤ轤ϫϷԿЬѰڰݳպݴݣݪڧѴɤ򱦢ҧ姨৫ا٧ӧ槬ݧ᧰ϥϪۧ秮ܧԧէާ觯קѧڧ֧䧡駾𧦧ߧ맥غ꧲Ѧr]\|\_s*[ێڎَ؎]\|\_s*[]\|\_s*[]\|\_s*\|\_s*[ͭ]\|\_s*[˦]\|6\_s*[]\|\_s*̵\_s*\|ݦ\_s*ݨ\|԰\_s*\|A\_s*\%(c\_s*t\_s*a\_s*e\_s*a\|p\_s*o\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|C\_s*\%(a\_s*l\_s*y\_s*c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|h\_s*o\_s*r\_s*i\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|\_s*[]\|\_s*\%(\|\_s*\)\|V\_s*e\_s*r\_s*t\_s*i\_s*c\_s*i\_s*l\_s*l\_s*a\_s*t\_s*a\_s*e\|O\_s*r\_s*c\_s*h\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|M\_s*i\_s*c\_s*r\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\|L\_s*\%([ruia]\|e\_s*i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*a\_s*l\_s*e\_s*s\|A\_s*N\_s*\_s*\_s*\_s*\)\|\_s*\|G\_s*\%(e\_s*n\_s*t\_s*i\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|y\_s*\%(n\_s*a\_s*n\_s*d\_s*r\_s*a\_s*e\|m\_s*n\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\)\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*\_s*̿\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*§\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|ȿ\_s*\_s*\|\_s*\%(\_s*ʸ\_s*\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*ǽ\_s*\_s*\_s*\_s*\|\_s*\_s*Ū\|ǧ\_s*\|R\_s*\%([bnfeauh]\|i\_s*c\_s*h\_s*a\_s*r\_s*d\_s* \_s*M\_s*\.\_s* \_s*S\_s*t\_s*a\_s*l\_s*l\_s*m\_s*a\_s*n\|C\_s*S\|S\_s*S\_s*\_s*\_s*\|I\_s*S\_s*C\|A\_s*M\|O\_s*M\|E\_s*\%(M\_s*\_s*̲\|T\_s*U\_s*R\_s*N\_s*\_s*\|A\_s*D\_s*M\_s*E\)\)\|\_s*\_s*ɽ\_s*\|\_s*\_s*\)', + \ 's' : '\%([Ъۼ˵ֵڰ޶˿ԽǨΨм©­¥«¦¬̫ᰳٴտ£֥ػǬ߶ҫݽ¹ײسȢҲ䷫çî¹½¸º»¶ȿରۤɯ˻íܦ岱޶ܸҪͼϴߪٰ֣ڱ·޷߫ѩѢߥѡ٥Ѩڣګ̻عԤ¿б¼ͥӳҰӵѱڿμͤʹƫǵ¨§ߵ̡ͷķ״ɿצߵ®ú϶ۡڽſТ̢ޢϡ⦤͡ߢˡܢޢʡ΢ߢꢻحجïͿ巿H񾽻ľڧ߭湥ٹ۵ʿƩԱ飼ýƳħ󻼲١ٶĴ¢ֺߨߧ¼ȻοǦǧӻк尷樵ԦܰǢܾнؼżĬ߼ȼ𮼻ꩼɨũм޳ʻͿļҼԲĵϼբٱؼ۷ּмܼڼѼм˼ּҰʵżެոշܤܣƵ´ýʽȽͽܼ̿꫽нܶܷꪽ쨳Ӵ֭ϼܽµ½Ѯضآؽܽ׽ٽ䣽սֽӢ֪ǿп¿Ŀ˿ӿ¿ɿǿä⿹ƿȿʿƿ謹еر޵ַҾľֹľ׾̰գңطӾԡʽءˡʾѾءϾ޾۾¾׾騾ľܥƾྫྷϾɾ˾ƴҾݾоξƾȾϾܾþھ˾ʾԧ֤ѿ°濣ػ㭻׶ӻӶǼӡܻHҿӺǡɦ֬寿ڻ¶ǰٻлף㬰ԮǷȻֻѳʻ̼һ̦ڼ褴ֻƤ豫dz˸ʿͻٮӦͶ긼뽿ܻ߷߽Ϋڼ޴ͺɾ참ֿ곡ָӯ˼λãů͡ұⷱζ۸ΤܪǾ٩ӴܼƱݺ峦涭ոපߦ»ڹĿĢջɻܢӻբ3O߻úޯخ稺ռŻø칹ʺѱ٣׺˺㷺ԺݺҺӼкںκպʺĺƺ׺źͺԺۺкǺªںԺغݯ̻赺ͼӺԼ亵ֺ麺úհ̬٭ϻ⤹Ż맻ź󢾢ʸšɸĻں̢ǡƨõ㧳s]\|\_s*[]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\%(ϩ\|Ϫ\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[ס]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*Ѥ\|\_s*\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|\_s*\|\_s*\|c\_s*e\_s*n\_s*t\_s*i\|\_s*[϶]\|\_s*\|\_s*̥\|\_s*\|ŵ\_s*\|\_s*ͺ\|\_s*\|ŷ\_s*[IJ]\|V\_s*i\_s*o\_s*l\_s*a\_s*l\_s*e\_s*s\|N\_s*y\_s*m\_s*p\_s*h\_s*a\_s*e\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|\_s*\|\_s*ƻ\|\_s*\%(\|\_s*\)\|Ϸ\_s*\|˾\_s*Ĭ\|\_s*\|\_s*[Ǧ]\|L\_s*a\_s*\%(b\_s*i\_s*a\_s*t\_s*a\_s*e\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|ʾ\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|ت\_s*ͺ\|\_s*\|\_s*\|I\_s*\%(s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\)\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*ʸ\|\_s*[ë]\|\_s*[]\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\%([ظܻ]\|\_s*\)\|7\_s*\|\_s*\|4\_s*\|\_s*[ʬ]\|\_s*\|\_s*\|\_s*\|\_s*\|͢\_s*[]\|Ȼ\_s*[ϯϺ]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|³\_s*\%(\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\_s*\)\|ή\_s*[Υ]\|\_s*\|\_s*\|Һ\_s*ȭ\|\_s*\_s*\|C\_s*\%([se]\|y\_s*c\_s*a\_s*d\_s*\%(i\_s*d\_s*a\_s*e\|o\_s*\%(p\_s*s\_s*i\_s*d\_s*a\|f\_s*i\_s*l\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\)\|h\_s*l\_s*o\_s*r\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|D\_s*Ź\|\_s*\_s*\|a\_s*\%(s\_s*s\_s*y\_s*t\_s*h\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|c\_s*t\_s*a\_s*l\_s*e\_s*s\)\)\|\_s*\|\_s*[]\|\_s*\_s*Ʀ\|ۨ\_s*\|\_s*\|\_s*\_s*\%(\_s*[ǯ]\|\_s*[ǯ]\)\|\_s*\|ɴ\_s*\_s*\|\_s*¹\_s*\|\_s*ƣ\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(ˡ\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|P\_s*\%(a\_s*r\_s*i\_s*e\_s*t\_s*a\_s*l\_s*e\_s*s\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|r\_s*i\_s*m\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\)\|A\_s*\%(p\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*a\_s*l\_s*e\_s*s\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\)\|\_s*[ŵ]\|B\_s*\%(r\|\_s*\_s*\)\|\_s*ĥ\_s*\|\_s*ʬ\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*¤\_s*\|M\_s*\%(e\_s*r\_s*c\_s*u\_s*r\_s*y\|u\_s*s\_s*a\_s*l\_s*e\_s*s\|a\_s*r\_s*q\_s*u\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\)\|D\_s*o\_s*n\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*A\_s*l\_s*p\_s*h\_s*o\_s*n\_s*s\_s*e\_s* \_s*F\_s*r\_s*a\_s*n\_s*c\_s*o\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\|\_s*\%(Ƿ\|\_s*\%(\_s*̣\|\_s*\_s*\)\)\|T\_s*\%(e\_s*t\_s*r\_s*a\_s*c\_s*e\_s*n\_s*t\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\|h\_s*e\_s* \_s*S\_s*i\_s*m\_s*p\_s*l\_s*e\_s* \_s*A\_s*P\_s*I\_s* \_s*f\_s*o\_s*r\_s* \_s*e\_s*v\_s*e\_s*n\_s*t\_s*-\_s*b\_s*a\_s*s\_s*e\_s*d\_s* \_s*X\_s*M\_s*L\_s* \_s*p\_s*a\_s*r\_s*s\_s*i\_s*n\_s*g\)\|\_s*\|\_s*\_s*\|\_s*¬\_s*\_s*ư\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\%([]\|\_s*\|\_s*\)\|\_s*\%([]\|\_s*\)\)\|\_s*̣\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\)\|\_s*\%(\|\_s*\%([]\|\_s*\_s*[]\)\|\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\)\)\|\_s*\%([ʼ]\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\_s*\_s*(\_s*S\_s*t\_s*r\_s*u\_s*c\_s*t\_s*u\_s*r\_s*e\_s* \_s*a\_s*n\_s*d\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*p\_s*r\_s*e\_s*t\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*o\_s*f\_s* \_s*C\_s*o\_s*m\_s*p\_s*u\_s*t\_s*e\_s*r\_s* \_s*P\_s*r\_s*o\_s*g\_s*r\_s*a\_s*m\_s*s\_s*)\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s* \_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\|S\_s*\%([nrgmce]\|G\_s*M\_s*L\|\_s*\_s*\|S\_s*\_s*\_s*\|F\_s*\_s*\_s*\_s*\|Q\_s*U\_s*A\_s*R\_s*E\_s* \_s*E\_s*N\_s*I\_s*X\|K\_s*\%(K\|Y\_s* \_s*P\_s*e\_s*r\_s*f\_s*e\_s*c\_s*T\_s*V\_s*!\)\|a\_s*\%(r\_s*\%(r\_s*a\_s*c\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|g\_s*e\_s*n\_s*t\_s*o\_s*d\_s*o\_s*x\_s*a\_s*c\_s*e\_s*a\_s*e\)\|m\_s*a\_s*r\_s*i\_s*u\_s*m\)\|M\_s*\%(\_s*\_s*\|\_s*\_s*\)\|P\_s*\%(\_s*\_s*\_s*\|A\_s*C\_s*E\_s*\_s*\)\|p\_s*\%(l\_s*u\_s*s\|e\_s*\%(r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*a\_s*l\_s*i\_s*t\_s*y\_s* \_s*S\_s*t\_s*o\_s*r\_s*e\_s* \_s*R\_s*e\_s*t\_s*a\_s*i\_s*l\_s*e\_s*r\_s* \_s*o\_s*f\_s* \_s*P\_s*r\_s*i\_s*v\_s*a\_s*t\_s*e\_s* \_s*L\_s*a\_s*b\_s*e\_s*l\_s* \_s*A\_s*p\_s*p\_s*a\_s*r\_s*e\_s*l\)\|a\_s*\%(t\_s*h\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*c\)\)\|H\_s*I\_s*F\_s*T\_s*\_s*\|C\_s*S\_s*I\|T\_s*\%(k\|A\_s*R\)\|h\_s*u\_s*g\_s*a\_s*r\_s*t\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*s\_s* \_s*S\_s*y\_s*s\_s*t\_s*e\_s*m\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*f\_s*a\_s*c\_s*e\|A\_s*\%(P\|S\_s*I\)\|i\_s*\%(m\_s*p\_s*l\_s*e\_s* \_s*K\_s*a\_s*n\_s*a\_s* \_s*t\_s*o\_s* \_s*K\_s*a\_s*n\_s*j\_s*i\_s* \_s*c\_s*o\_s*n\_s*v\_s*e\_s*r\_s*s\_s*i\_s*o\_s*n\_s* \_s*p\_s*r\_s*o\_s*g\_s*r\_s*a\_s*m\|l\_s*i\_s*c\_s*o\_s*n\)\|t\_s*r\_s*o\_s*n\_s*t\_s*i\_s*u\_s*m\|o\_s*\%(u\_s*t\_s*h\_s* \_s*\%(D\_s*a\_s*k\_s*o\_s*t\_s*a\|C\_s*a\_s*r\_s*o\_s*l\_s*i\_s*n\_s*a\)\|l\_s*a\_s*r\_s*i\_s*s\|f\_s*t\_s*w\_s*a\_s*r\_s*e\_s* \_s*R\_s*e\_s*s\_s*e\_s*a\_s*r\_s*c\_s*h\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*,\_s*I\_s*n\_s*c\_s*\.\)\|u\_s*\%(n\|l\_s*f\_s*u\_s*r\)\)\|β\_s*\)', + \ 't' : '\%([˳ɼҸڽѲ۳ݽ꾲Ĺゥƾη䶡ݽȼͧ۽ĹԥЧܽ˺̭ǯӷֺܺڢκ˭ƿ¢ѸݹǼƻƺܫƳ۶岳ڮݥܪٵֺ߮ƪе즰ƽ޹ơƦƭƤƣƫƥոﰳ믿æԦѽײѽѹϳαͻųϿڼͿ޻Ȏӱ͹ʻԹ֥ųׯŭūڳũɡץšżſŶŻŸźŲŪůŨűŰŴܼ챭ܨţšŢ޸׷Ǝʾʼŵ̳ض۲ϸ̽Ϫٴܻܿѳ㪱γªڼָʴϸȺ鲶ڹ˷Ҿѣױ³ٽƿ븾̢Խϴ˵Ϻ¤ݶԯзˤض࿵˾ͿԻڻܦƵ⸷ѻ̹ϢĎ׹ۺ紺N㾹ٻĿٲŦȤܺĽҬļŤı׭ذ߭׬ġĵįŽƬĸķijĪĢĭƨĻĥĤĨȥħİĦĬĮĺĴģIJĶĩīЦѲפدɪɳղϡѡСο漣֮ѻ׷ڲ٤ֿ̯ڸȿˬܽîƢí̱۸нԻվιìʾλƧ٥ƮáȾ䲹ﴰ٦ɶݾŹêéڥçäܱ纴ͤɫ맰ܭζεɺݰľ鶩ͣԳӬѹҵͺ׼ŬƵ«ԡýݽèã۹̴ƿֻǤƱýϰ䶳ٷɹºյδйٿӸþں߬߸ÿWöӷëóȿC÷òýðôùøúûõñâپŧڤ٧Ӷ߷ڭʿڬжԱǿĹʲ֫­Ωίȯ۴¿¾¿ïҺӣ߱٣崤ŷ߷ڢᦨɽڥ覨ȥġžƩȥĻüӨƨ䨷t]\|\_s*[ĎΎ]\|\_s*[ȥƥĥ]\|\_s*[ȤƤĤ]\|\_s*\|\_s*\_s*\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*Ϸ\|\_s*\|\_s*[]\|\_s*\|\_s*ľ\|\_s*\|\_s*\_s*\|\_s*[]\|\_s*[]\|͸\_s*\|\_s*\_s*\_s*\|\_s*\|H\_s*y\_s*d\_s*r\_s*o\_s*c\_s*h\_s*a\_s*r\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*[ƻ]\|\_s*[]\|\_s*ǯ\_s*\|\_s*[׻]\|A\_s*c\_s*o\_s*n\_s*i\_s*t\_s*u\_s*m\|ƶ\_s*\|\_s*\|\_s*\|F\_s*e\|I\_s*r\_s*o\_s*n\|\_s*¼\|\_s*\|\_s*̼\|ɻ\_s*\|\_s*\_s*\|\_s*\%(\|ε\_s*\)\|\_s*[]\|\_s*\%(\|\_s*\)\|ɹ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|B\_s*a\_s*l\_s*a\_s*n\_s*o\_s*p\_s*h\_s*o\_s*r\_s*a\_s*l\_s*e\_s*s\|1\_s*\%(\|0\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\_s*\|E\_s*\%(u\_s*p\_s*h\_s*o\_s*r\_s*b\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(Ϸ\_s*Ƭ\|\_s*\)\|\_s*\%([]\|\_s*\|ܥ\_s*\_s*\)\|\_s*\|\_s*\|\_s*\_s*\|\_s*[]\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*ެ\|\_s*\|J\_s*i\_s*a\_s*n\_s*g\_s*s\_s*u\|\_s*\|\_s*[]\|\_s*ë\|\_s*\|\_s*Ϫ\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\_s*\|\_s*[]\|\_s*\_s*\|\_s*\%(\_s*\|Ϣ\_s*\_s*[]\)\|\_s*\%(\|\_s*˷\)\|\_s*Ƣ\|\_s*\|\_s*\|\_s*[ڳ]\|\_s*\|\_s*\%(ͼ\|\_s*\)\|\_s*\|\_s*\|ͱ\_s*Ю\|̵\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|P\_s*\%(\.\_s*S\_s*\.\|o\_s*l\_s*y\_s*\%(g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*r\_s*p\_s*i\_s*c\_s*a\_s*e\)\|a\_s*n\_s*d\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|ж\_s*\|Ʋ\_s*\|ǽ\_s*[ʸǷ]\|\_s*\|\_s*̱\|\_s*\|\_s*\_s*\|\_s*\|M\_s*\%(e\_s*n\_s*i\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*c\_s*e\_s*a\_s*e\|o\_s*n\_s*o\_s*\%(p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*\%(h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|o\_s*t\_s*y\_s*l\_s*e\_s*d\_s*o\_s*n\_s*e\_s*a\_s*e\)\)\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%(\_s*[ȥ]\|\_s*\)\|\_s*\_s*\|\_s*[ॢ]\|\_s*\%(\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\%(\|\_s*\)\)\|\_s*\%(\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*[ե]\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%([ɥ]\|\_s*\|\_s*\_s*\|\_s*\_s*[]\|\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\|Ϣ\_s*ʸ\_s*\)\|\\\_s*T\_s*e\_s*X\|\_s*\_s*\|ʸ\_s*\_s*\|\_s*\|\_s*\%([]\|\_s*˦\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|E\_s*\|\_s*[أ]\)\|T\_s*\%([bcmliahe]\|r\_s*i\_s*m\_s*e\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\|\_s*\_s*\|X\_s*T\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|V\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\)\|C\_s*P\|\_s*\_s*\|-\_s*C\_s*o\_s*d\_s*e\|O\_s*E\_s*I\_s*C\|A\_s*\%(C\|I\_s*N\_s*S\|B\_s*\_s*\)\|E\_s*L\)\|\_s*\%([]\|\_s*\_s*\_s*\_s*\_s*\)\)', + \ 'u' : '\%([Ⱥɶἷƶڰѽ뼿åѽִء¥ӹⱳư뭱վž𱴵ΪŲر󨱲山۲񱷸¹ϻڴ︽̱ǰֶ̽޲墱ⳤزﷵ庨΢ױӺ屯ĬΣݵ汵²ͫ˷ⱫDZڽͭɼޢƤձ񻾵ѵھвͷα仺ǿ⤦ԥU姵u]\|\_s*\|\_s*\|\_s*\|ϵ\_s*\|\_s*\_s*\|\_s*\|թ\_s*\_s*\|\_s*\|ͥ\_s*\%(\_s*[ɰ]\|\_s*\)\|\_s*\|\_s*²\|\_s*\|ˢ\_s*\|\_s*\|\_s*\_s*[Ƭ]\|\_s*\|\_s*Ǽ\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*Ļ\_s*\|ø\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|̣\_s*\|\_s*\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*Ϻ\|\_s*\|\_s*[]\|\_s*\%(\|\_s*\_s*\)\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*ǽ\|\_s*\%(\_s*\|ͭ\_s*\)\|\_s*\%([]\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\|\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\)\)\|ñ\_s*\%(\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\%([ˡ]\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\%(\_s*\|\_s*\)\)\)', + \ 'v' : '\%([͢ǧӢ˥v]\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\| \_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%([ܥȥ]\|\_s*\%(\_s*\_s*\|\_s*[]\)\)\|\_s*\_s*\_s*\|\_s*\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\%([ȥ]\|\_s*\|\_s*\_s*\%(\|\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\_s*\_s*\_s*\|\_s*\%([ɥ]\|\_s*\_s*\|\_s*\_s*\)\)\|\_s*\_s*\|\_s*Ĺ\_s*\|\_s*ľ\|\_s*\%(\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\%(\|\_s*\)\)\|\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\%(\|\_s*\)\)\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\)\)\|\_s*\%([֥Х]\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\%(\|\_s*[]\)\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\%(\|\_s*\_s*\%(\|\_s*\_s*\_s*\_s*\)\)\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\)\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\%([ȥ]\|\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*[]\)\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\)\|\_s*\|\_s*[䥢]\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\)\)\|\_s*\%([]\|\_s*\%([֥]\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\|\_s*\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\%([顼]\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\_s*\)\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\)\)\|\_s*\%(\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\)\|V\_s*\%(H\_s*L\_s*L\_s*(\_s*V\_s*e\_s*r\_s*y\_s* \_s*H\_s*i\_s*g\_s*h\_s* \_s*L\_s*e\_s*v\_s*e\_s*l\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\_s*)\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|J\_s*E\_s*-\_s*\|\_s*\|\_s*\_s*\|I\_s*S\_s*A\_s*\_s*\_s*\|i\_s*r\_s*g\_s*i\_s*n\_s*i\_s*a\|A\_s*X\|e\_s*r\_s*\%(m\_s*o\_s*n\_s*t\|i\_s*S\_s*i\_s*g\_s*n\)\|a\_s*n\_s*a\_s*d\_s*i\_s*u\_s*m\)\)', + \ 'w' : '\%([򲧽˽ﲴͺȺɶʦԦἷƶڰ뼿åѽء¥ӹⱳư뭱վž𱴵ΪŲر󨱲山۲񱷸¹ϻڴ︽̱ǰֶ̽墱زﷵ庨U΢׻᢬Ӻ屯ĬΣݵ汵²ͫ˷ⱫDZڽͭɼޢƤձ񻾵ѵھвͷα仺ǿ⤦ܲϴѽѴֲҺҶȵɡب˺оƸ޾׿׾бIJƻĹʻ駷Ųѯ뻲Ƚռ㰿´ĸӻͯͰʬʨʤȥw]\|\_s*[񎳥]\|\_s*[񥦥]\|\_s*[񤦤]\|\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|ϵ\_s*\|\_s*\_s*\|\_s*\|թ\_s*\_s*\|\_s*\|ͥ\_s*\%(\_s*[ɰ]\|\_s*\)\|\_s*\|\_s*²\|\_s*\|ˢ\_s*\|\_s*\|\_s*\_s*[Ƭ]\|\_s*\|\_s*Ǽ\|\_s*\|\_s*\|\_s*\|\_s*\_s*Ļ\_s*\|ø\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|̣\_s*\|\_s*\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*Ϻ\|\_s*\|\_s*[]\|\_s*\%(\|\_s*\_s*\)\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\|\_s*ͥ\|\_s*˺\_s*\|\_s*\|\_s*\_s*\|(\_s*\_s*)\|\_s*[]\|\_s*\|\_s*\|\_s*\|Y\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*[ͳ]\|\_s*\|\_s*\|\_s*\_s*\_s*٥\_s*\|\_s*\%(\|ʿ\_s*\_s*\_s*\)\|ݿ\_s*\_s*\_s*٥\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\_s*\%([ץ]\|\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\_s*\)\)\|\_s*\_s*\|\_s*\%([ࡼ]\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\%(\_s*[]\|\_s*\|\_s*\%(\_s*\%(\|\_s*\)\|\_s*\%(\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\)\)\)\|\_s*\%(\|\_s*[ȥ]\)\)\|\_s*\_s*\_s*\|W\_s*\%(S\|N\_s*N\|y\_s*o\_s*m\_s*i\_s*n\_s*g\|O\_s*W\_s*O\_s*W\|I\_s*\%(D\_s*E\|N\_s*T\_s*E\_s*R\_s*P\_s*(\_s*W\_s*i\_s*d\_s*g\_s*e\_s*t\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*p\_s*r\_s*e\_s*t\_s*e\_s*r\_s*)\)\|i\_s*\%(s\_s*c\_s*o\_s*n\_s*s\_s*i\_s*n\|d\_s*g\_s*e\_s*t\|n\_s*d\_s*o\_s*w\_s*s\)\|h\_s*\%(y\_s* \_s*d\_s*o\_s*n\_s*e\_s* \_s*i\_s*t\_s*?\|o\_s* \_s*d\_s*o\_s*n\_s*e\_s* \_s*i\_s*t\_s*?\)\|E\_s*B\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|e\_s*\%(s\_s*t\_s* \_s*V\_s*i\_s*r\_s*g\_s*i\_s*n\_s*i\_s*a\|b\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\%(\|\_s*\)\)\|\_s*\_s*\)\)\|a\_s*s\_s*h\_s*i\_s*n\_s*g\_s*t\_s*o\_s*n\|A\_s*V\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%([]\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\)\|\_s*\%(\_s*[]\|\_s*\_s*\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\)\)\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|T\_s*\%(h\_s*e\_s* \_s*W\_s*o\_s*r\_s*l\_s*d\_s* \_s*W\_s*i\_s*d\_s*e\_s* \_s*W\_s*e\_s*b\_s* \_s*C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\)\)', + \ 'x' : '\%([秷ߦx]\|\_s*[]\|\_s*[]\|\_s*[]\|\_s*\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\%([]\|\_s*[]\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\|ü\_s*\)\|X\_s*\%([]\|C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|\_s*[]\|P\_s*S\_s*(\_s*e\_s*X\_s*p\_s*a\_s*n\_s*s\_s*i\_s*o\_s*n\_s* \_s*P\_s*a\_s*s\_s*s\_s*i\_s*n\_s*g\_s* \_s*S\_s*t\_s*y\_s*l\_s*e\_s*)\|S\_s*\_s*\_s*\|l\_s*i\_s*b\|L\_s*\%(i\_s*s\_s*p\|\_s*\_s*\)\|e\_s*n\_s*o\_s*n\)\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\%(\_s*\%(\|\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\%(\_s*\|\_s*\)\)\|E\_s*x\_s*t\_s*e\_s*n\_s*s\_s*i\_s*b\_s*l\_s*e\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\)\)', + \ 'y' : '\%([ֲغ˩շ޷ڡڴֻۻþӱٵ㷽İ˧ȵ׫խۡƫߡٹβžաЮôڵ;ӸǽͽDz¿ͻͷͿ즤μдİ˭Ƿְ쪾றᾲ͸۷Ͳإͤͨͱͻ͹ͯͰʹͼͩͪͧͺͫͭ͡ͷͳ͢·ͮ竤掲׶׵϶̴ߺ̤ӷŲݳͶưݡȵܦɵ述ڿĹǢ̿쵸Ÿವżϫĺ׻кطҮͦܡǮʰᰱ˻ްϮסӱ©ĩ寱۱İĽ˻Сݫ׸ԩ۵ʰݻְյ׮Iΰ𨱡ֱ۩۰дذŰ1ڴŪ٥ަ̰թȺص°ذѰϱԣиȰǡѦ״ͣ޻׳԰ʳ豶İΰڸްͰֹ԰аΨͬհݰڰ۵ԧİøҲݰͻϦSϵ½ͥ²۴ݬٯֳ̼쮼칽̡ҡԡաӻšץ̰ǫ͵ٰ׵ݹȬë׽Ǹܿͼ뻦輭֧ߡק觫Yۦy]\|\_s*[֎Վ]\|\_s*[楤]\|\_s*[椤]\|\_s*\_s*\|ݿ\_s*\_s*\|\_s*\|\_s*Ƹ\|\_s*\|\_s*\|4\_s*\%([]\|\_s*\|\_s*\)\|¾\_s*\|\_s*\|δ\_s*\|\_s*\|\_s*\|\_s*\|\_s*[Ҹ]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|Ī\_s*[Ұ]\|\_s*\|\_s*\|8\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|ɴ\_s*\|L\_s*i\_s*l\_s*i\_s*\%(o\_s*p\_s*s\_s*i\_s*d\_s*a\|a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\)\|\_s*\%(ͺ\|\_s*\)\|Ĺ\_s*\|\_s*\|\_s*\|\_s*\|E\_s*\%(u\|\_s*\_s*\)\|\_s*\|J\_s*u\_s*\%(l\_s*i\_s*a\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|n\_s*c\_s*a\_s*l\_s*e\_s*s\)\|\_s*ë\|\_s*\|ɨ\_s*\|\_s*ϻ\_s*\|\_s*\|\_s*±\|\_s*\_s*\|\_s*ȷ\|β\_s*\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*ɨ\|\_s*\|\_s*\_s*ƣ\|5\_s*[]\|\_s*[]\|ب\_s*٦\|\_s*\|Ĭ\_s*\|\_s*\|\_s*Ӽ\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|ʸ\_s*\|Ϻ\_s*[]\|\_s*[]\|\_s*\|U\_s*\%(\|\_s*\_s*\|r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|\_s*[Ļ]\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\|\_s*[ﷻ]\|\_s*\|\_s*\|\_s*\|\_s*¹\_s*\|\_s*\_s*\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|\_s*\|̵\_s*\_s*\|\_s*\|\_s*\_s*ή\|\_s*[]\|\_s*[]\|\_s*[ڻ]\|\_s*ɽ\|\_s*\_s*[ú]\|\_s*ӧ\|\_s*[]\|\_s*\%([]\|\_s*\)\|\_s*\_s*\|\_s*[ʱ]\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|\_s*[ǡ]\|\_s*\|\_s*ζ\_s*\|ξ\_s*\|ή\_s*ŭ\_s*\|\_s*\|\_s*[]\|R\_s*a\_s*f\_s*f\_s*l\_s*e\_s*s\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\|\_s*\|ŷ\_s*\|\_s*\|\_s*\_s*\_s*º\|\_s*\|T\_s*\%(h\_s*e\_s*l\_s*i\_s*g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*o\_s*c\_s*h\_s*o\_s*d\_s*e\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|M\_s*y\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\_s*\|\_s*¹\|A\_s*r\_s*a\_s*c\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*\%(o\_s*t\_s*e\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*c\_s*i\_s*p\_s*e\_s*s\)\|a\_s*l\_s*m\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*[]\|\_s*\%([̼]\|\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\)\|\_s*\)', + \ 'z' : '\%([»¸·­«֤±³²¯°¡£¤źȿդظƦפԦƬݿ߹޿ֺɼټĶԺټľ㿬̭ߩʿ顿ױӿпԿҿؿѿտǽޮտٳа屽лġпЫǡ̼žվڷǨèط۲ٽɽμѽȻŽޭ߱覽۽ڽ޽޼쳼ߨкߧ尽Ľ½ýƽ֮꼥Ώ߼ֵᪿλ̻Яϩ˱ѻżб褻Τ߷ºֿܪȻ̻쩻ϻ»߻ƺú޺ߺкú¢µ좭إ٦Ƨz]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|ȯ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ˡ\|\_s*\|Ĵ\_s*\|\_s*[᷺]\|\_s*\|\_s*\|F\_s*i\_s*g\_s*u\_s*r\_s*e\|\_s*\|G\_s*\%(\_s*\|\_s*\)\|D\_s*y\|\_s*\%(\_s*\|\_s*\)\|\_s*\|\_s*\|\_s*\|2\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|J\_s*\%(I\_s*S\_s*\_s*\_s*\|\_s*\_s*\|R\_s*\_s*\_s*\)\|\_s*\|\_s*\_s*ʺ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*ī\|\_s*\|Ƚ\_s*\|ϳ\_s*\|\_s*\|Ĺ\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*Τ\|\_s*[ϴ崽]\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*[ʷ]\|\_s*\|\_s*\|\_s*\)\|\_s*\|\_s*\|ɳ\_s*\|1\_s*\%(0\|1\_s*\|8\_s*\|2\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\)\|Z\_s*\%([r]\|i\_s*\%(r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\|n\_s*c\)\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|I\_s*P\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\%(\|\_s*\%(\_s*\|\_s*\)\)\)\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\%(\_s*\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\_s*\)\)\)', + \ 'A' : '\%([ԳȯϾտƭ޾ӡŤƬѫͷʷİͿø̵ܶܵ驰нƪ鷹ѻˢǽܽ֦½ΦؽǮȲ䰵ǴռݯмԹڹײϪɽ¹ͽЮɷ庾Ӻ̴ɵఽ;ŷ°ֵϰ̣Ԫƴ갮ůۭμ氰ᄑϯ۸ޫۦۥ˾ϾԼݷʸۣ齶ϰ갥欷԰ǰްưðȰīﰦð­ҹӼ밫Ƽǹ˽˰ķ°մ尤Ըʻᰢͭ˴±޽کг󰸶˰بĤ&ʢܶ϶΢͢޸姸ơǡ򦡥ѧA]\|\_s*\|\_s*\|\_s*\|\_s*\|Z\_s*\%(n\|i\_s*n\_s*c\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ŷ\_s*\|\_s*ŵ\|\_s*\|\_s*\|\_s*Ʀ\|\_s*\|\_s*\|\_s*̾\|\_s*̾\|\_s*\|\_s*\|\_s*[Ļ]\|\_s*\|\_s*\|\_s*\|L\_s*a\_s*r\_s*d\_s*i\_s*z\_s*a\_s*b\_s*a\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*\%(\|¹\_s*\)\|\_s*\%(\|\_s*\_s*\_s*ʪ\_s*\)\|\_s*\_s*\|H\_s*a\_s*l\_s*o\_s*r\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|ޱ\_s*\|\_s*\|Ʀ\_s*\|\_s*\_s*\_s*\|\_s*¿\|\_s*\|\_s*\|a\_s*\%(t\_s*t\_s*o\|c\_s*c\_s*e\_s*n\_s*t\)\|\_s*[Ǭ]\|\_s*\|\_s*[ɧ]\|\_s*\|\_s*\|\_s*\|Ҹ\_s*\|\_s*\%([]\|\_s*\|\_s*\)\|\_s*[ˡ]\|E\_s*\%(s\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\)\|I\_s*\%(r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(\_s*\|\_s*\_s*\_s*\)\|D\_s*\_s*\_s*\|C\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\%(\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*[ɿͽ]\|R\_s*u\_s*b\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*[]\|M\_s*a\_s*l\_s*v\_s*a\_s*l\_s*e\_s*s\|\_s*\_s*\_s*\_s*A\|\_s*\| \_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|G\_s*o\_s*l\_s*d\|\_s*ư\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|°\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|S\_s*\%(b\|i\_s*l\_s*v\_s*e\_s*r\)\|\_s*\_s*\_s*ǽ\|\_s*\_s*\_s*ǽ\|\_s*ˡ\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\%([]\|\_s*\%(\_s*\|\_s*\)\)\)\|\_s*\%([ȥ]\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\_s*\|\_s*\%([]\|\_s*\_s*\)\|\_s*\_s*\%(\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\)\)\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\%(\_s*\_s*\|\_s*ǽ\)\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\)\|\_s*Ͽ\|\_s*\|\_s*\%([˥ᥢ]\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\%(\|\_s*\_s*\)\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\)\)', + \ 'B' : '\%([߹ڽھ˲ѳ̶˦꼰汬˳ر˸˹˻˶˺˴˾˵˿籸촳Ħ˷ը˫ѹʽٷҡ޺˼ūʥ޽޼޿ʪɲʹʸ̵ʬק£͹ɵɤޣֱؾݧɴ졪¡ɼǭ֢ʿջ̤׹߾Ȣ®Ӷ˪ȭƯȫȪʵɡüΥV̥ȵٶȶǢʢĻʧ㱸Ȥ˽ʱ೭ȹȨؤȽȼ㩺Ȳȴȳ粽ڱĥŽСʩݲߡá¡ݡܥСϡΡСѣ¥֥ӧҦ¥B]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[ܥ٥֥ӥ]\|\_s*[ܤ٤֤Ӥ]\|\_s*\|\_s*\|\_s*\|P\_s*a\_s*e\_s*o\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*Ǥ\|\_s*\|\_s*[]\|\_s*\_s*ݰ\|F\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|˭\_s*[]\|\_s*\|ŷ\_s*\_s*\|\_s*[϶]\|b\_s*i\_s*o\_s*t\_s*o\_s*p\_s*e\|׽\_s*˥\|\_s*[̡˥]\|\_s*Ҵ\|\_s*Ƭ\_s*\|\_s*\|\_s*\|S\_s*a\_s*n\_s*t\_s*a\_s*l\_s*a\_s*l\_s*e\_s*s\|\_s*\|ʼ\_s*[ˡ]\|ɽ\_s*\|\_s*[Ļ]\|\_s*\|ȯ\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|R\_s*o\_s*s\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\%([ӳϫ]\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|A\_s*n\_s*n\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*[]\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*[]\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\)', + \ 'C' : '\%([²ݰťޢͷ°Я⸿ȽҸǼۻô㪸ۺ礷򼷻쮱Ѻ˹Ϲٹʺú̶縥պۦĹȹָ벹Һ٬̫ޫ޳䲬ު־ϹϺ٫ȺӫִӳӬص޸ܺս幡͹䢹̨ɹж๫ʹĹá񹸹ۥ⫹ֹѸ۹չ̹˹عֹ骹ݹҹԹιӹĸëӭ͹޺ݻջ̼ԵʴԸƸ۸žĶٸĨ̱۸ɸָܵʽѻᡵǻ۹ɯ˻íܦ岱ӵʡ޶٣໦Ҫͼٰ֣ڱ·޷߫ѩѢߥѡ٥Ѩڣݺګ̻خعɹԤܯݬݮܱܮݫʵߪʤվ߷ţ賷ΦۻҮ·ط״򷬷ڶ˿ֲ̽ǰ̰鶰פ޺ޱͿ߸Ѧ庿ܸȷˮԢʭЦչġҵ׹޷˹ȸҢڹ׶ҿȴȷͤԱ飼ýƳħ󻼲١Ĵɸ¢ֺλߨߧ¼ȻοǦǧк尷樵ԦܰǢܾؼżĬ߼ȼ𮼻ꩼɨũżʻ͸忬ļҼԺաĵհռޯκբٱؼڷּ忼мܼѼ׼ͼм˼ּҰʵżެոշܤܣƵýʽȽͽɽܼ̿꫽нܶꪽӴ֭ϼܽµ½Ѯضآ߽ؽ޴׽ٽ䣽ֽ߿Ӣ֪ǿп¿Ŀ˿ӿ¿ǿä⿹ƿʿƿ謹еؽ޵ַҾľ䬼ֹ᳻ļװգңطӾԡĽؾѾءϾ޾۾¾騾ľ㾩ܥ񾬽Ͼɾ˾ƴҾ;оƾȾϾܾþھ˾ԧ֤ѿ°濣鿨лػ㭻׶ӶǼӡܻҿӺǡɦ֬寿¶ǻлף㬰ԮǷȻֻѻʻ̼̦Żڻڼ褴λƤڹɳ߳˹ȷ̢ư񢿱Ʊʡܢᱵ𦪦ʹǡˡҡԡơȡɡѡСաجɳ϶ѾʸܵȿǣʶͽгϾݵع˵ۿٸǷշͩΫKĴȱ١ҤҳݢٿȦ۫滳ܾ龹ôŽ޳ڳ³귰¦ǰ㡴姢റҳݲҳ˿ڸিԣϸ³ø֡١סʷŭƬŨŬȾŤ״׳ᰥɬŴܷ̳봢ԽڲӾ׳ڨƿӽdzӡϡۡڡ̡͡γȳijԳճʳ߱׳ڼȵҳֳѳТӼ뻳һרݥųЪĻӳܴ߳ٳβ𳭳dz򳬲Ԭ٪Хٺù٢Ӳߵ۸Ұ楼Ѵ޾˸˧ӳޱڿͻôÿȡȴ䯴԰ݴ۴ڴԴա̴δ˴עӴĴִٴ״ӿŴɴشϴѴشԳҵȴճƶDzμŲͲӻ۷紣ҲԥФҲһݲݲִּȼڲ桶˲ŰײӧҷܴѫββϲѼнӥѷϲӲɲշ߲Ʋ²ȾƸϲˤıĶƢ۲øҧ姨ৣ٧اӧݧ᧷짢ۧ秮ܧԧէާ觯קѧڧ֧䧡𧦧ߧ맥ߨƼ֦ҧ駹ݡ׶ܥ񥷡C]\|\_s*[]\|\_s*[]\|\_s*[Ҥ]\|\_s*\|\_s*\_s*Ⱦ\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*ϧ\|\_s*\|\_s*\|\_s*\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|\_s*Ѥ\|\_s*\|A\_s*\%(r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|p\_s*i\_s*a\_s*l\_s*e\_s*s\)\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|\_s*\|\_s*\|\_s*ˡ\|\_s*[ʺ]\|\_s*[϶]\|ѱ\_s*\|\_s*\|\_s*[̱]\|\_s*\|\_s*\|ɴ\_s*[߻]\|\_s*\|9\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|ŵ\_s*\_s*\|õ\_s*\|\_s*¢\_s*\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|ϻ\_s*\|\_s*\|\_s*\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|Ϸ\_s*\|˾\_s*Ĭ\|\_s*[]\|\_s*Ϣ\|\_s*[Ǧ]\|\_s*\|L\_s*a\_s*\%(u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|b\_s*i\_s*a\_s*t\_s*a\_s*e\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|ʾ\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|ت\_s*ͺ\|\_s*\|\_s*\|I\_s*\%(s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\)\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*ʸ\|\_s*[]\|\_s*\%([αֲ˼]\|\_s*\|Ǽ\_s*\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|7\_s*\|\_s*\|ʸ\_s*\|4\_s*\|\_s*[ʬ]\|\_s*\|\_s*\|\_s*\|\_s*[̰]\|\_s*\|\_s*\%(̣\|\_s*\)\|\_s*[]\|͢\_s*[]\|´\_s*\|B\_s*r\|Ȼ\_s*[ϯϺ]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|M\_s*\%(e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|u\_s*s\_s*a\_s*l\_s*e\_s*s\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|S\_s*\%([eg]\|p\_s*e\_s*r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*i\_s*t\_s*a\_s*m\_s*i\_s*n\_s*e\_s*a\_s*e\)\|³\_s*\%(\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\|\_s*ƻ\)\|\_s*\|Υ\_s*\_s*Υ\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*Ƭ\|\_s*\%(\|\_s*\)\|Ĺ\_s*[]\|\_s*\|ŷ\_s*\%(\|\_s*\)\|\_s*\|\_s*\_s*\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*[]\|̱\_s*\|\_s*\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|\_s*\|\_s*\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|o\_s*\%(t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\|d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\)\)\|\_s*\|Ϣ\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|Ϥ\_s*\)\|\_s*\|\_s*[]\|\_s*\%([]\|\_s*\|\_s*\_s*Ω\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*[]\|(\_s*\_s*)\|\_s*\_s*\|\_s*ʼ\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|ݣ\_s*\|\_s*\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*ƣ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|ʬ\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|c\_s*\%(e\_s*n\_s*t\_s*i\|r\_s*e\_s*s\_s*c\)\|\_s*[׼꾽]\|ʣ\_s*\_s*̿\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\|\_s*\%([]\|\_s*\%(\|\_s*\)\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\_s*\%(\_s*\|\_s*\)\)\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\%(\_s*\|\_s*\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\)\)\)\|\_s*\_s*\_s*\|\_s*\|\_s*\%([]\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*[]\|\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\)\|\_s*\%([֥ץ]\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\)\)\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%([]\|\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\_s*\_s*\)\)\|\_s*\%(\|\_s*\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\%([ɥѥ֥]\|\_s*\%(\|\_s*\_s*\)\|\_s*\%([]\|\_s*\%(\|\_s*\_s*\_s*\)\)\|\_s*\|\_s*\%(\_s*[]\|\_s*\)\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\)\|\_s*\%([ĥȥ]\|\_s*\|\_s*\|\_s*\%(\|\_s*\|\_s*\%(\|\_s*\)\)\)\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\%(\|\_s*\)\)\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*\_s*[]\|\_s*\)\|\_s*\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\)\|\_s*\)\|\_s*\%(\|\_s*\|\_s*\_s*\)\)\|\_s*\|\_s*\%([ޥ]\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\%([ץ]\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\%([եȥץ]\|\_s*\|\_s*\)\|\_s*\%([]\|\_s*\%(\|\_s*\)\|\_s*\%(\_s*\|\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\|\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\%([ȥ]\|\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\|\_s*\)\)\|\_s*\%([եɥ󥳥ꥦ]\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\%(\_s*[]\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%([ȥॸ]\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\%([]\|\_s*\)\)\|\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\)\)\|\_s*ɸ\|\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*³\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\)\)\|ú\_s*\)', + \ 'D' : '\%([ñӹɾǯĻЧγѪƯƺߡѯƫƣޡƷƴ΢ƼƵƳƸƲƶưƹƱƻ׸۲αͻϿظͻڤɻǩťŮҴޡܬѣžȤǥɶʹ˶¤Դ͸ŵͿϢťϼ¼êíǻïîնԵ庲ë۴ݹէåæǶʿϡö׼ԥٽձټΩѵί۴̽пѼ߱ͤľЦ\.ġȡɢãȣĥɡǦħբD]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[ɥǥť¥]\|\_s*[ɤǤŤ¤]\|\_s*\|\_s*\_s*\|\_s*\|S\_s*a\_s*u\_s*r\_s*u\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|C\_s*\%(u\|o\_s*p\_s*p\_s*e\_s*r\)\|\_s*ŷ\_s*\|Ʀ\_s*\|ǡ\_s*\|\_s*\|\_s*\|Ǵ\_s*\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\|Ƭ\_s*[]\|\_s*\|\_s*\|\_s*\|Ĵ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ã\|\_s*\|\_s*\|\_s*\_s*ã\_s*¿\|\_s*\%([˸]\|ʿ\_s*\|\_s*ŷ\_s*\|\_s*\%(\|\_s*\)\)\|ǵ\_s*[]\|\_s*\|\_s*\|\_s*\%(\_s*ʪ\|\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\_s*\|\_s*\|\_s*\|ʸ\_s*\|\_s*\_s*\|ȯ\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*ά\|\_s*\_s*\|d\_s*\%(b\_s*m\_s*s\|e\_s*c\_s*\%([ia]\|r\_s*e\_s*s\)\|o\_s*u\_s*b\_s*l\_s*e\_s* \_s*i\_s*n\_s*c\_s*o\_s*m\_s*e\_s*,\_s* \_s*n\_s*o\_s* \_s*k\_s*i\_s*d\_s*s\|i\_s*m\)\|\_s*\)', + \ 'E' : '\%([ٱ稰Զ콸ս֦廷ٱְܱױرԨųɲСݩ޽޼ާǢޱ޻ʥԤϱͱն۪߱бհܳϱƱñȱԱűƱӱDZɱϱı̱޹зتͲ±ݲþв΢ᢺ⧮ާѢмǣŧ㧳ݧŧ泌E]\|A\_s*\%([Ƚ]\|V\_s*\%(\_s*\|\_s*ͥ\)\|B\_s*\%(\|C\_s*\)\)\|\_s*\%([Ƚ]\|\_s*\%(\_s*\|\_s*ͥ\)\|\_s*\)\|\_s*\%(\|\_s*\)\|ɰ\_s*\_s*\|M\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*˹\_s*\|\_s*ʪ\|\_s*\|˦\_s*\|\_s*\_s*\|Լ\_s*\|\_s*\|\_s*ϩ\|\_s*\|\_s*[Ի]\|\_s*ƺ\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|L\_s*\%(\_s*\_s*\|L\_s*\%(\_s*\_s*\|\_s*\)\)\|\_s*\%([ɲ]\|\_s*\)\|N\_s*\| \_s*n\_s* \_s*\_s*\|\_s*\%([Ķ˶]\|\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\%([Ȼʶ]\|\_s*\_s*\|\_s*\|\_s*\_s*\)\|S\_s*\%([]\|\_s*\_s*\|N\_s*\|F\_s*\_s*\)\|\_s*[¿]\|X\_s*\%([]\|O\_s*\|\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\)\|\_s*ƻ\|\_s*Ʀ\|C\_s*\%(l\|h\_s*l\_s*o\_s*r\_s*i\_s*n\_s*e\)\|\_s*\%(Ϸ\|\_s*\)\|\_s*\_s*\_s*®\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\)\|ݿ\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\_s*\_s*\|\_s*\)\)\|\_s*\|\_s*Ĵ\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\_s*\|\_s*\)\|ȯ\_s*Ÿ\|ɾ\_s*\_s*\_s*\|\_s*\_s*\|ɴ\_s*\_s*\_s*ŵ\|\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\|\_s*ĥ\|\_s*\|\_s*ò\_s*\|\_s*\%([]\|\_s*\|\_s*\%([ޥ]\|\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\)\)\|\_s*Ω\|e\_s*\%(x\_s*a\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\%([֥顼]\|\_s*\_s*\_s*\|\_s*\_s*\_s*[ȥ]\|\_s*\%(\_s*\|\_s*\_s*[]\)\|\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\_s*[ȥ]\|\_s*\)\|\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\|\_s*\)\|\_s*\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*[䥢]\|\_s*\%(\_s*\%(\|\_s*\|\_s*\)\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\)\)\|\_s*\%(\|\_s*\_s*\_s*\)\)', + \ 'F' : '\%([ϼвɮ˼ݵϰ˴ϴʻÿū߹ʷʵʸʯʭʶʲʱʬʴڸ޽ʥ޼⵺бƣ߬ѵοʳʰزʧʨؿ礢ıǹ޴ʤʢʣʡԴҿϷƧнҶ꿣ڿʮ߹ֿʫݤŴϢ٢޶ʩƢʦ⧶էF]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ǹ\|\_s*\|\_s*\|E\_s*u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\%(Ǥ\|\_s*[]\)\|\_s*\|Ƭ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|M\_s*y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*[滳]\|\_s*\|B\_s*u\_s*d\_s*d\_s*l\_s*e\_s*j\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*[ͤ]\|\_s*\|2\_s*\%([ͤ]\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*Χ\_s*\|I\_s*r\_s*o\_s*n\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\%(\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\%(\_s*\|\_s*\_s*\_s*\)\)\)\|\_s*\|\_s*\|\_s*ǽ\|\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\_s*[]\)\|\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*1\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\|f\_s*\%(e\_s*m\_s*t\_s*o\|o\_s*\%(n\_s*t\_s*-\_s*f\_s*a\_s*m\_s*i\_s*l\_s*y\|r\_s*t\_s*e\)\)\)', + \ 'G' : '\%([Ʊ亲޺иЯǡ¹ɹϿйⶳݶ蹡贻˸Ӫ伸˸ظ5Ķۻٸѻ줴֡ɷ޷߷ݱŴɧѷʸ¸뻲²ƤʵʹҰ¢襸ж鹶ܶ溷ֶ򹰶㼶ȶ餰ݵ۶Է̵֪ƸߤѧĶȶǶŹԵյڵ۵õ췷Ѧ»·赼ĵۧີ٦ȱⷸ⧹εߴ¦̳Ǹ񷿷Ը걳޽˳̿Ƭ︷̴ݢ޴ḵس̳۳ٳܳڳش㨳ЩԶ䳯ֽ糳ӱ⭳賩ֶѴݲծӨ̲´ϲ谽˲쾡󡤬Ǵ楬֦ԦƦѦɦզӦ˦ϦͦצئĦ¦ЦŦҦȦǦʦΦ̦ԦçG]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\_s*\|\_s*Ƭ\_s*\|\_s*\|\_s*\|P\_s*e\_s*r\_s*s\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\%([ֱ]\|ŷ\_s*\)\|\_s*\_s*\|\_s*\%([Ÿо]\|\_s*\)\|Ʀ\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[¯]\|\_s*[ǹ]\|\_s*\|\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*[׹]\|\_s*ϡ\|\_s*\|\_s*\|\_s*\%([]\|\_s*\)\|\_s*\%([ˡƻ]\|\_s*\_s*\|ʹ\_s*\_s*ˡ\)\|A\_s*g\|S\_s*\%(c\_s*r\_s*o\_s*p\_s*h\_s*u\_s*l\_s*a\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*m\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|i\_s*l\_s*v\_s*e\_s*r\)\|\_s*\|\_s*\_s*ë\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*̾\|T\_s*y\_s*p\_s*a\_s*l\_s*e\_s*s\|\_s*[]\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|g\_s*\%(i\_s*g\_s*a\|h\_s*o\_s*s\_s*t\_s*s\_s*c\_s*r\_s*i\_s*p\_s*t\)\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|Ϣ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\%(\|\_s*\_s*\)\)\)\|\_s*\%(\|\_s*\_s*\)\|\_s*\%([른Υʥ]\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\%(\|\_s*\_s*\_s*\)\)\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*[˥]\|\_s*\_s*[˥]\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\%(\|\_s*\%(\|\_s*\|\_s*\_s*[ĥ]\)\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\)\|\_s*\|\_s*\%([]\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\%([եޥ]\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*[ȥ]\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\)\|\_s*\|\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\%(\|\_s*[]\)\|\_s*\)\)\)\)', + \ 'H' : '\%([άмۭϯƶشǮ˴ꥷֹ٢ڣþ̷ȸԼƾԵұٸޤê׺˲˯ˣ˱˩ˬˢ߰˥˨ˮ˰˦˭ˤڽھӮƱĦ˫ԾӬێ͸½Ш۳ֱ׭׬̦΢٨ղʽ֢ʾʻ򰵸͸؎ϼвر˼ݵɾϰϴʻÿū߹ʷʵʸʯʭʶʲʱʬʴڸ޽ʥ޼бBƣ߬ѵοʳʰزʩFʦʨյؿ乢ǹ޴ʤʣʡԴҿƧнҶ꿣ڿʮ߹ֿʫՎϷDzDZɢݽɨڻײɦگٶɳߪ̩߫ҷΨɢʺɽźƶѽñ¾Ʒ1ඡɩϾǼݱɧҹɴҿɪ粹ɲɱ桶ڲŸͨ妳ѽʹɱ繰͵עɯɥɭɤʴɫݤ̤ɮɬɶɷɿɺɻʼɼɾɸʿɽ֡ڡʡآ羷۬զҸ壸Уﴳɹɰ̥ݺ㰤Ҏʻȧ۽ˡȣַүꤾ׼׹Ȧ߶ھ¦ൡá˵ȫƯȪIJԸʧȷȩ㳾СȰϸܥ˧ʢͪڼѶΥȹȸަɡڲչȤҺýҹȢȡ򾾹ٰ®Ȼиݢ֯ڦԦ¬ѳĽ̷׿޸ȥȮϡȭ˪ȱˡȰȬȯڴԯأצɣԳ߯ޢȨźܹڵȼȽɺȾȿȺǿԺı۱ŶķƱüҵ਻ԳܱĥŽ淿ʤϨȡաȥҥۥإH]\|\_s*[Ύ͎̎ˎ]\|\_s*[ۥإեҥ]\|\_s*[ۤؤդҤ]\|\_s*\|\_s*\|\_s*Ļ\|\_s*\|\_s*[]\|\_s*\|\_s*[п]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*[]\|T\_s*r\_s*i\_s*u\_s*r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*ˡ\|\_s*λ\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|h\_s*e\_s*c\_s*t\_s*o\|\_s*\|c\_s*l\_s*a\_s*u\_s*s\_s*t\_s*r\_s*o\_s*p\_s*h\_s*o\_s*b\_s*i\_s*a\|\_s*\|\_s*\|\_s*\|E\_s*\%(r\_s*i\_s*o\_s*c\_s*a\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\|u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\|Ƭ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|f\_s*\%(o\_s*r\_s*t\_s*e\|e\_s*m\_s*t\_s*o\)\|\_s*[滳]\|\_s*\|\_s*\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%([ͽ]\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*ŷ\_s*\|\_s*[]\|\_s*\|\_s*[ȡ]\|\_s*\_s*\%(\|\_s*\)\|A\_s*\%(s\|r\_s*s\_s*e\_s*n\_s*i\_s*c\|n\_s*g\_s*i\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\|\_s*\_s*\|\_s*\_s*\|\_s*[]\|\_s*\|ľ\_s*[Ᵽ]\|\_s*Φ\|\_s*\_s*\|\_s*\|\_s*Ÿ\|\_s*[˹]\|\_s*\|\_s*ƻ\|\_s*\|\_s*\|\_s*\|̢\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|ι\_s*\|N\_s*e\_s*l\_s*u\_s*m\_s*b\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\_s*\|Ʊ\_s*˦\|\_s*\|\_s*[ȧ]\|\_s*[]\|\_s*[ǵ]\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|Ĺ\_s*ë\|\_s*\_s*\|Ż\_s*Ƭ\|\_s*\|\_s*\|\_s*[]\|\_s*\%(\_s*\|\_s*\)\|ͦ\_s*[]\|ή\_s*\|\_s*\|2\_s*\%([ͤ]\|\_s*\|0\_s*\)\|\_s*\%([ͤ]\|\_s*[]\)\|ø\_s*\|8\_s*\|\_s*\|P\_s*\%(t\|o\_s*t\_s*a\_s*m\_s*o\_s*g\_s*e\_s*t\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*t\_s*i\_s*n\_s*u\_s*m\)\|\_s*\%([]\|\_s*\_s*\|\_s*\)\|\_s*ή\|\_s*\|\_s*\|\_s*\|R\_s*S\_s*I\|M\_s*\%(y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*c\_s*u\_s*r\_s*y\)\|\_s*Ĵ\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\%(\|\_s*[ȥ]\)\)\|\_s*\|\_s*ϻ\_s*\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\)\|\_s*\%([顼]\|\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\%(\|\_s*\)\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\)\|\_s*[ʿ]\)', + \ 'I' : '\%([DZߡ׶׵϶̴ߺ̤ӷŲݳͶưݡȵܵ述S׽ꭲڿĹǢ̿쵸Ÿವżϫĺ׻кطҮͦܡǮʰᰱ˻ްϮסӱ©ĩ寱۱İս˻Сݫ׸ԩ۵ʰݻְյ׮Ųΰ𨱡ֱ۩۰дذYŰ1ڴŪ٥ަ̰թȺص°ذѰϱԣиȰǡѦ״ͣ޻׳԰ʳױİΰڸްͰֹаΨͬհݰڰ۵ɹۢ͢˰籥ɥɧڻI]\|E\_s*\_s*\_s*\|\_s*\|J\_s*u\_s*n\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*ë\|\_s*ʸ\_s*\|\_s*\|ɨ\_s*\|\_s*ϻ\_s*\|\_s*\|\_s*±\|\_s*\_s*\|\_s*ȷ\|β\_s*\|\_s*\_s*\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*ɨ\|\_s*\|\_s*\_s*ƣ\|5\_s*[]\|\_s*[]\|ب\_s*٦\|\_s*\|Ĭ\_s*\|\_s*\|\_s*Ӽ\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|ʸ\_s*\|Ϻ\_s*[]\|\_s*[]\|\_s*\|U\_s*r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*[Ļ]\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*[ﷻ]\|\_s*\|ݬ\_s*\|\_s*\|\_s*\|\_s*¹\_s*\|\_s*\_s*\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|\_s*\|\_s*\|\_s*\_s*ή\|\_s*[]\|\_s*[]\|\_s*[ڻ]\|\_s*ɽ\|\_s*\_s*[ú]\|\_s*ӧ\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|\_s*[]\|<\_s*=\_s*=\_s*>\|ɬ\_s*\_s*\_s*ʬ\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\_s*\|ɸ\_s*\_s*\_s*\_s*\)\|\_s*Υ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|¨\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|i\_s*\%(\_s*\_s*\|P\_s*o\_s*d\|\_s*\_s*\|M\_s*a\_s*c\|\_s*\_s*\)\|\_s*\_s*\|̵\_s*\%(\_s*\|\_s*\)\|\_s*Ǽ\_s*ˡ\|\_s*\_s*\|\_s*\%([ǡ­]\|\_s*ʬ\)\|\_s*\_s*\|\_s*\|Ƴ\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*\%(\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\)\)\)\)', + \ 'J' : '\%([ֺɼټľ¿̭ߩʿ顿ױӿпԿҿؿѿտǽޮտٳа屽лġпЫǡ̼žվڷǨèط۲ٽɽμѽȻŽޭ߱覽۽ڽ޽޼쳼ߨкߧ尽Ľ½ýƽ֮꼥Ώ߼ֵᪿλ̻Яϩ˱ѻżб褻κԼٵ֧ͤʧקJ]\|\_s*\_s*\|\_s*\|\_s*\|G\_s*\%(\_s*\|\_s*\)\|Z\_s*\%(r\|i\_s*r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\)\|D\_s*y\|\_s*\%(\_s*\|\_s*\)\|\_s*\|\_s*\|\_s*\_s*\%(\_s*\|\_s*\)\|\_s*\|2\_s*\|\_s*\|\_s*\_s*ʺ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*ī\|\_s*\|Ƚ\_s*\|ϳ\_s*\|\_s*\|\_s*\_s*\_s*\|Ĺ\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*Τ\|\_s*[ϴ崽]\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\|\_s*\|\_s*\%(\|\_s*[ʷ]\|\_s*\|\_s*\|\_s*\)\|\_s*\|\_s*\|ɳ\_s*\|1\_s*\%(0\|1\_s*\|8\_s*\|2\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*̣\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*Ʊ\_s*\_s*\_s*\|j\_s*\%(T\_s*e\_s*X\|L\_s*a\_s*T\_s*e\_s*X\|B\_s*i\_s*b\_s*T\_s*e\_s*X\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\_s*\|\_s*\|\_s*Φ\_s*\_s*ü\_s*\%(\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\|\_s*\%([˥ʡ]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*[ӥ]\|\_s*\)\|\_s*\%(\_s*[]\|\_s*[]\)\|\_s*\_s*\|\_s*\%([ϥ]\|\_s*\_s*\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\_s*\|\_s*[]\)\|\_s*\%(\_s*\%([ʥ]\|\_s*\%(\|\_s*\)\|\_s*\)\|\_s*\%(\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\)\)\|\_s*\%([]\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\)\|\_s*\%([֥]\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\|\_s*\%([ȥ]\|\_s*\|\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*[ʥ]\)\)', + \ 'K' : '\%([²ǷťưЯ⸼ȽҸǼ㪸ۻ쮱੻ֿѺϹٹʺú纯պۦĹȹָ벹Һ٬̫ޫ޳䲬ު־㣸ϹϺ٫ȺӫִӳӬص޸ܺս͹̨ɹж๫ʹĹá񹸹ۥ⫹ֹѹ۹չ̹˹عֹ骹ݹҹԹιӹĸëӭйݻջ̼ԺʴԺƸ䲾Ƹ۸žĶٸĨӾ̱ۻҸɸָܵŽѻǻûƤҸݰٽᾱʷϿٱЭۿݼܷغѭԡ޲իҥݾشկثڷ𸳰̷ո丮Ǹݷڸ建ҧҾتϨꥷ찷Ʒ̷÷Ҧ׷ۤܯݬݮܱܮݫʵߪʤվ߷ţ賷ΦۻҮ·ذѾ򷬷ڶ˿ֲ̽ǰ̰鶰פ޺Ϳ߷Ѧν庿ܸȷˮԢɦʭܿЦĸ¢޷˹ȸҢڹҿȶ꤯ӽ廸͵θ˨ž䷯ݢݡ뿸֨ɵɵǵ̵Ƶʡޢ̡ޡá笠ܡ塹Ţ硧顩¢ġ졵ˡ桼ݢ᡺Ժٹܶµϴߵʷߵ̸׶ܶ۶ڢҶݸٶڶӶ϶׶նѶ۶ֶضбڡکڪӵҨީд򰰶ɵժ亶ѿַﶷѬзź䡹ިٰװ¶ѹ߶ҳٶɶѾ貶󶩶жᶧŶö̵̾֩켣ŵָյⱱ͵ܵ׵ֵȷٵߵ޵۶ݺʹݤױ̴ڵſөɱȲøڶ˷Ҽ¶𵦵ۮ־ةȩܵѥ·д̧İɺݸ嵥ڵ޿洴ԭԵڸ쵧㵫٣ֿ۹ڹɳ߳˹ȷ̢ư좿ƱʡܢᱵרǡˡҡԡơȡɡѡСաôجɳ϶ѾʸܵȿǣʶͽгϾݵع˵ۿٸǷշͩΫĴȱ١ҤҳݢʢٿȦ۫滳ܾ龹ôŽ޳ڳ³귰¦㡴姢̻റɵҳݹ޳˿ڸিԣϸ³ø֡١׷ŭƬŨŬŤ״׳ᰥɬŴܷ̳봢ԽڲӾ׳ڨƿӽdzӡϡۡڡ̡͡γȳijԳճʳ߱׳ڼȵҳֳѳТӼ뻳һרݥųЪĻӳܴ߷ٳβ𳭳dz򳬲Ԭ٪Хٺù٢Ӳߵ۸ҰᴮѴ޾˧ӳޱڿͻôÿȡȴ䯴԰ݴ۴ڴԴʴա̴δ˴עӴĴִٴ״ӿŴɴشϴѴشԳҵȴճƶDzμŲòͲӻ۷紣ҲԥФҲһݲݲָ򴢱ּȼڲ桶˲ŰײӧҷܴѫββϲѼнӥѷϲӲɲշ߲Ʋ²ȾƸϲݤᨱ秷ʳ˥߶Ҧ֥ܥK]\|\_s*[]\|\_s*[]\|\_s*[Ҥ]\|\_s*\|\_s*\|\_s*\_s*Ⱦ\|\_s*ë\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*ϧ\|\_s*\|\_s*\|\_s*\|M\_s*e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|\_s*Ϣ\_s*̣\|\_s*\|\_s*\|\_s*\|S\_s*i\|\_s*\|ɴ\_s*[߻]\|9\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|ŵ\_s*\_s*\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|õ\_s*\|\_s*\|c\_s*r\_s*e\_s*s\_s*c\|\_s*¢\_s*\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|ϻ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|k\_s*i\_s*l\_s*o\|\_s*[Ƿ]\|\_s*\|\_s*ɧ\|\_s*\|\_s*\_s*Ļ\|X\_s*e\|ǡ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|G\_s*o\_s*l\_s*d\|A\_s*\%(u\|r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|s\_s*t\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\_s*\|\_s*\|R\_s*\%(h\_s*\%(o\_s*e\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\)\|u\_s*n\_s*u\_s*n\_s*c\_s*u\_s*l\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|a\_s*n\_s*\%(u\_s*n\_s*c\_s*u\_s*l\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*l\_s*e\_s*s\)\)\|\_s*\|\_s*[©]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\%([]\|̳\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*ŵ\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*ƻ\)\|\_s*\|Υ\_s*\_s*Υ\_s*\|\_s*Ƭ\|\_s*\%(\|\_s*\)\|\_s*\|Ĺ\_s*[]\|\_s*\|ŷ\_s*\%(\|\_s*\)\|\_s*\|\_s*\_s*\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*[]\|̱\_s*\|\_s*\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|Ϣ\_s*\|\_s*\|\_s*\_s*\|C\_s*\%([ormdfa]\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\|i\_s*r\_s*c\_s*a\_s*e\_s*a\_s*s\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*r\_s*i\_s*u\_s*m\|e\_s*r\_s*c\_s*i\_s*d\_s*i\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|Ϥ\_s*\)\|\_s*\|\_s*[׼]\|\_s*\%(\|\_s*\_s*Ω\_s*\_s*\_s*\_s*\_s*\_s*\)\|(\_s*\_s*)\|\_s*\|\_s*\_s*\|\_s*ʼ\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\|\_s*\|\_s*[׿]\|\_s*\|ݣ\_s*\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|\_s*\%([֥]\|\_s*\|\_s*\%([ȥ]\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\)\)\|\_s*\%(\_s*\%(\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\)\|\_s*\_s*\|\_s*[եȥ]\)\|\_s*\%(\|\_s*\%(\|\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\)\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|a\_s*p\_s*a\_s*v\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|o\_s*\%(d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\)\)\)', + \ 'L' : '\%([㡱̢ТϢ˥̢ʥݦ򧭦L]\|\_s*[]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\_s*2\_s*\_s*ˡ\|\.\_s*\.\_s*\.\|\_s*\|l\_s*-\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|ݦ\_s*ݨ\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%([֥ܥȥᥦ]\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\|\_s*\%([ƥȥ]\|\_s*\%(\_s*\|\_s*\)\|\_s*\)\|\_s*\_s*\|\_s*\_s*\%([ȥ]\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\_s*\%(\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*[ȥ]\)\|\_s*\|\_s*\%([]\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*[]\|\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%([]\|\_s*\)\)\)\|\\\_s*L\_s*a\_s*T\_s*e\_s*X\|\_s*\_s*\|\_s*\|\_s*\%([ݥޥʥΥ̥֥]\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*[]\|\_s*[]\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*[륷]\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\_s*\|\_s*[]\)\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%([]\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*\%([]\|\_s*\|\_s*\)\|\_s*\%([]\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%([ɥԥץ]\|\_s*\)\)\)', + \ 'M' : '\%([Ӵڬߪ߫һսοʹʪأε첼ЪǴܸʸݨۯۤ˴ݼ˾dzϳܾըлӤոľѾճ˨λتۻΪ溵ʰ̺üӹɴϢ͸¼߶ٽﶻŷ̼ǫƿ̸̵̴̶̻̹ϻپ̷̳믵Ĺǥߺ֪Ь夰յ𢨡̮þ̬ѰλûǣץŹ̨ºļšѢ١۱̰ǧʾƳϩƻм̯̾̿̽Ե㴳ﲸ̫Ĵ̩̪̲̱ܳ׽̭뷱ο̧̥̣̦ʿߎϸٿܵŪ¹׿׾ᵼžеȱμ°ẕ̇ҸƦԫѿǤʶĴٰüᶶ賹ĮԤ硬ˡʱߴʣ󺵸ػϨŻȨؤ̢̡Ϯ򾾶踭ͥϺ۾̤⼬غѿ˻޸̢ޡࢿܡޢ΢Тʢꢻ覤͡碾ݢϢߢˡߢ͢ݥ޺ǥߥ᧮M]\|\_s*[ӎҎюЎ]\|\_s*[ߥ]\|\_s*[ߤ]\|\_s*[]\|\_s*\%([Ͽ]\|\_s*\|\_s*\)\|\_s*\|\_s*\_s*\%(\|ʸ\_s*\)\|ξ\_s*\%([ѿƿ]\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|O\_s*l\_s*e\_s*a\_s*l\_s*e\_s*s\|ر\_s*\|\_s*\_s*\|\_s*\|\_s*ĥ\|\_s*[]\|\_s*\_s*ӧ\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%([ͭ]\|\_s*ƻ\|\_s*\)\|\_s*\|\_s*\|6\_s*\|\_s*\|\_s*\|\_s*\|\_s*;\_s*\|\_s*\|B\_s*\%(e\_s*r\_s*b\_s*e\_s*r\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*o\_s*r\_s*r\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|©\_s*\|k\_s*\$\_s*_\_s*{\_s*i\_s*n\_s*f\_s*}\_s*\$\|\_s*\|A\_s*\%(b\_s*i\_s*e\_s*s\|p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*r\_s*o\_s*s\_s*t\_s*i\_s*c\_s*h\_s*u\_s*m\)\|\_s*\|\_s*ȷ\|\_s*\|\_s*[]\|\_s*\|\_s*\|Φ\_s*\|\_s*[ҽԢ]\|3\_s*[]\|\_s*[]\|\_s*[ȱ]\|\_s*\|ȷ\_s*\|\_s*\|\_s*[˪]\|P\_s*o\_s*d\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*[ζε]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|R\_s*u\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\%(̣\|\_s*[ž]\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*Ļ\|\_s*\|\_s*\|\_s*[һ]\|\_s*\|ߴ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*ã\|\_s*\|\_s*[̯]\|\_s*\|\_s*\|L\_s*o\_s*g\_s*a\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|Ю\_s*\|\_s*\|\_s*\|S\_s*\%(a\_s*p\_s*i\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|c\_s*h\_s*i\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|C\_s*\%(a\_s*s\_s*u\_s*a\_s*r\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*a\_s*t\_s*o\_s*p\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\)\|\_s*\%(\_s*\|\_s*\)\|H\_s*a\_s*m\_s*a\_s*m\_s*e\_s*l\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*[Ƿ]\|\_s*ɧ\|ʹ\_s*\|\_s*\|\_s*[§]\|\_s*\_s*ǯ\|\_s*\|¿\_s*\_s*\_s*\|\_s*-\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|ñ\_s*\_s*\|\_s*\|\_s*\_s*[]\|\_s*\_s*\|\_s*\_s*Ǿ\|\_s*[]\|\_s*\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\)\|m\_s*\%(u\_s*l\_s*t\_s*i\_s*l\_s*i\_s*n\_s*g\_s*u\_s*a\_s*l\_s*i\_s*z\_s*a\_s*t\_s*i\_s*o\_s*n\|i\_s*\%(c\_s*r\_s*o\|l\_s*l\_s*i\)\|e\_s*\%(g\_s*a\|z\_s*z\_s*o\_s* \_s*\%(f\_s*o\_s*r\_s*t\_s*e\|p\_s*i\_s*a\_s*n\_s*o\)\)\|a\_s*\%(k\_s*e\_s*\_s*\_s*\_s*\|d\_s*e\_s* \_s*i\_s*n\_s* \_s*J\_s*a\_s*p\_s*a\_s*n\)\)\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*Ū\_s*\_s*̣\|\_s*\_s*\%(\_s*̣\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\)', + \ 'N' : '\%([ɽ԰ھ翮Ǽ¡۩׵˾̰ĵƭоӸĪɫŸˡŵ§ϵůۨǹǿǾǽǶǸЫݻǷҾݡǻĤΎ߿ݦեǫդٹǭʿܡ̲ǮϫǬ̭ܬDzǰdzǯ޺ǴͺDZǪϣ಻ǩ͎Բʾ迡۾ݹŧ޹dzǨæ˥ȴٶɤ̎ٿô콭ʨ߳ƲؽǢѦ浶ǡǣԡբ١ذլѹٿǦǥǧǤ̶֮ƨ2бðˎٸij֧ť鵵ͼ㳴÷òڳвּͱľؽǺޥϲ˿ܧƻб±ŵڽͨƷȱįή¸ܩĹ޽Ⱦ棷мǵճǢԶ󢿢͢Ǽ̵ٽձ޸ѵİྨӭڵ˴Ƥʨ̾˥ͣ΢̡ʥ̥ΦߦN]\|\_s*[ɎȎǎƎ]\|\_s*[Υ̥ͥ˥]\|\_s*[Τ̤ͤˤ]\|Ģ\_s*\|\_s*\|\_s*\|\_s*ö\|\_s*\_s*ȿ\|\_s*\_s*\|ϵ\_s*[ݱ]\|\_s*\|\_s*\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\|\_s*\_s*\|\_s*Ƿ\|\_s*\|ο\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*;\_s*\|\_s*\|\_s*\|I\_s*I\_s*\|\_s*ȭ\|\_s*\|\_s*\| \_s*2\_s* \_s*\_s*\_s*\|M\_s*y\_s*r\_s*i\_s*s\_s*t\_s*i\_s*c\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*ѵ\|\_s*[]\|P\_s*b\|L\_s*e\_s*a\_s*d\|\_s*[]\|C\_s*\%(e\_s*l\_s*a\_s*s\_s*t\_s*r\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*r\_s*y\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*\%(\_s*\|\_s*ʪ\)\|\_s*\_s*\|7\_s*[]\|\_s*\|\_s*\|ʿ\_s*\|\_s*\|\_s*\_s*\_s*\|T\_s*h\_s*e\_s* \_s*N\_s*e\_s*t\_s*w\_s*o\_s*r\_s*k\_s* \_s*I\_s*n\_s*f\_s*o\_s*r\_s*m\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\|S\_s*o\_s*\%(l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|d\_s*i\_s*u\_s*m\)\|\_s*\%(\|\_s*\|\_s*\_s*\_s*\_s*\)\|ɳ\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|n\_s*\%(\|a\_s*n\_s*o\|o\_s*t\_s* \_s*o\_s*r\)\|\_s*\|\_s*\|\_s*\|\_s*\)', + \ 'O' : '\%([Ůۯ۰Ÿ۲˻ҳŵسḯԹ䲮ɭڶڼᡸǦƼĹĽǼԲ£ȳ־쿯Φֲݣſ༫ʳˬʲ񤲷ǰ߰θۻɽ̶Ͷ笲ݶذߴ޳۾ʲإᥲصռ鲪ݯݳ²۷겣ݿӵ꾪Ʊٱ⳸͸Ȳϵ˲˱¿ʤDzϺڨϯݰƿϷͦ˵Ӱ˿侭˸಼ͺߺӱä¢ˢϧৰϡئO]\|\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*Ȭ\_s*\|Ŵ\_s*\|\_s*ȱ\_s*\_s*\|\_s*\|\_s*\|\_s*̣\|\_s*\_s*\|\_s*ʴ\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|ب\_s*\|˵\_s*[]\|\_s*[̼]\|\_s*[]\|\_s*[]\|թ\_s*\|\_s*\|\_s*\|G\_s*u\_s*t\_s*t\_s*i\_s*f\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|D\_s*i\_s*l\_s*l\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|H\_s*y\_s*p\_s*e\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*[̼]\|\_s*ǯ\_s*\|\_s*\_s*\|\_s*\|\_s*\|A\_s*l\_s*i\_s*s\_s*m\_s*a\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\|C\_s*o\_s*p\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\_s*\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ʪ\|\_s*\_s*\_s*\|\_s*[]\|\_s*[]\|\_s*Υ\|ز\_s*\|\_s*\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*[]\|\_s*\|\_s*\_s*[]\|\_s*[߳]\|\_s*\%(\|\_s*\_s*η\|\_s*ŷ\_s*\)\|\_s*Ƭ\|\_s*[]\|\_s*\_s*¾\|\_s*\_s*\_s*\_s*\_s*\_s*\.\|\_s*[ζ]\|t\_s*h\_s*e\_s* \_s*O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*a\_s*n\_s*a\_s*g\_s*e\_s*m\_s*e\_s*n\_s*t\_s* \_s*G\_s*r\_s*o\_s*u\_s*p\|Ω\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\%([]\|\_s*\)\)\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*[ǯ]\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*Ŭ\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\)', + \ 'P' : '\%([ˣˤˡܮʻáʬɤɶɼʿȯȢʧʢȬ˱ĥѱפԡޡܤצը̨󡥣С򢩡ץǡˡʢߢ¥ڥѧզХP]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[ݥڥץԥ]\|\_s*[ݤڤפԤ]\|\_s*\|\_s*\_s*Į\|\_s*\|\_s*[Ϫϥ]\|\_s*\|\_s*\|\_s*ϥ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(Τ\|\_s*\)\|C\_s*y\_s*c\_s*l\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|S\_s*y\_s*n\_s*a\_s*n\_s*t\_s*h\_s*a\_s*e\|\_s*\|B\_s*r\_s*o\_s*m\_s*e\_s*l\_s*i\_s*a\_s*l\_s*e\_s*s\|L\_s*e\_s*a\_s*d\|\_s*[ļ]\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\%([]\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\)\)\|+\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|Χ\_s*\)\|\_s*\%(\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\_s*\_s*\|\_s*\%([Υ]\|\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\)\|\_s*\%(\|\_s*\|\_s*\%([]\|\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*[]\)\|\_s*[ĥ]\|\_s*\_s*\_s*\_s*\)\|\_s*\%([]\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\%([]\|\_s*[ץ]\|\_s*\%(\|\_s*\)\)\)\|\_s*\%(\_s*\%([٥]\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\)\)\)\|\_s*\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*³\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*³\|\_s*\_s*\_s*\|\_s*ƺ\_s*\|\_s*\_s*\|¿\_s*\_s*\|\_s*\_s*\_s*\|Ž\_s*\_s*\_s*\|\_s*ʸ\|\_s*\_s*[]\|\_s*\|\_s*\|p\_s*\%(T\_s*e\_s*X\|H\_s*\_s*\_s*\|e\_s*\%(t\_s*a\|r\_s*l\_s*\_s*\_s*\_s*\_s*\)\|i\_s*\%(c\_s*o\|a\_s*n\_s*\%(o\|i\_s*s\_s*s\_s*i\_s*\%(m\_s*o\|s\_s*s\_s*i\_s*m\_s*o\)\)\)\)\)', + \ 'Q' : '\%([ܯݬݮܱܮݫʵߪ緩ųʤմɾ߷ţ賷ΦۻҮղطѾ뷭򷬷ڶ˿ֲ̽ǰ̰鶰ȱפ޺ޱͿ߷Ѧν庿ܸ𷪶ʳdzˮԢɦʭӼЦչ硡Ŵġ¢ҵ׹׶޷˹ȸҢܸڹ׶ҿȴȷ϶ͶꎸѡơȡǡɢQ]\|\_s*\|\_s*\|\_s*\|\_s*̼\|\_s*\|\_s*\|\_s*\|\_s*Ѵ\|ɴ\_s*[߻]\|\_s*\_s*\|\_s*ʪ\|\_s*\|9\_s*\|Ĺ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\|ŷ\_s*\_s*\|\_s*\|ŵ\_s*\_s*\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|õ\_s*\|\_s*\|c\_s*r\_s*e\_s*s\_s*c\|\_s*\|\_s*[]\|\_s*¢\_s*\|K\_s*r\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\%([ʸ]\|\_s*\)\|\_s*\|\_s*Ѥ\_s*\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*\|ϻ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|C\_s*\%(r\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\)\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|\_s*\_s*ϯ\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*[]\|\_s*\%(\_s*[]\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\_s*[ॹ]\)\|\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\)\)', + \ 'R' : '\%([αϾϼϽϿ߳ϱϮӤۭӯѤҩ۰ϺϭϴϲϹϸϰ϶ϵϳϯϧȧϨתϦݭߣްٳѶӺүߺ㹵ݬݮҳҽ߲ݲϡϣڻϢϩޥﻼϬڶΫάΪΨ˷Χҭϻ٤Φ߱ίβΰαΩγέδήPܲשاηκϤθо̺ۢסڢɩζοε˵νμλξιΥΣΡ΢ߢئΤ轤ϫϷԿЬѰڰݳպݴݣݪڧѴɤ鱦ҧ姨৫ا٧ӧ槬ݧ᧰ϥϪۧ秮ܧԧէާ觯קѧڧ֧䧡駾𧦧ߧ맥غҥ꧲ѦR]\|\_s*[ێڎَ؎]\|\_s*[]\|\_s*[]\|\_s*\|\_s*[ͭ]\|\_s*[˦]\|6\_s*[]\|\_s*̵\_s*\|ݦ\_s*ݨ\|԰\_s*\|A\_s*\%(c\_s*t\_s*a\_s*e\_s*a\|p\_s*o\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|C\_s*\%(a\_s*l\_s*y\_s*c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|h\_s*o\_s*r\_s*i\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|\_s*[]\|\_s*\%(\|\_s*\)\|V\_s*e\_s*r\_s*t\_s*i\_s*c\_s*i\_s*l\_s*l\_s*a\_s*t\_s*a\_s*e\|O\_s*r\_s*c\_s*h\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|M\_s*i\_s*c\_s*r\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\|L\_s*\%([ruia]\|e\_s*i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*a\_s*l\_s*e\_s*s\|A\_s*N\_s*\_s*\_s*\_s*\)\|\_s*\|G\_s*\%(e\_s*n\_s*t\_s*i\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|y\_s*\%(n\_s*a\_s*n\_s*d\_s*r\_s*a\_s*e\|m\_s*n\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\)\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*\_s*̿\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*§\|\_s*\|r\_s*u\_s*b\_s*y\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|ȿ\_s*\_s*\|\_s*\%(\_s*ʸ\_s*\|\_s*\)\|\_s*ǽ\_s*\_s*\_s*\_s*\|\_s*\_s*Ū\|ǧ\_s*\|\_s*\_s*ɽ\_s*\|\_s*\_s*\)', + \ 'S' : '\%([Ъۼ˵ֵڰ޶˿ԽǨΨм©­¥«¦¬̫ᰳٴտ£֥ػǬ߶ҫݽ¹ײسȢҲ䷫çî¹½¸º»¶ȿରۤɯ˻íܦ岱޶ܸҪͼϴߪٰ֣ڱ·޷߫ѩѢߥѡ٥Ѩڣګ̻عԤ¿б¼ͥӳҰӵѱڿμͤʹƫǵ¨§ߵ̡ͷķ״ɿצߵ®ú϶ۡڽſТ̢ޢϡ⦤͡ߢˡܢޢʡ΢ߢꢻحجïͿ巿H񾽻ľڧ߭湥ٹ۵ʿƩԱ飼ýƳħ󻼲١ٶĴ¢ֺߨߧ¼ȻοǦǧӻк尷樵ԦܰǢܾнؼżĬ߼ȼ𮼻ꩼɨũм޳ʻͿļҼԲĵϼբٱؼ۷ּмܼڼѼм˼ּҰʵżެոշܤܣƵ´ýʽȽͽܼ̿꫽нܶܷꪽ쨳Ӵ֭ϼܽµ½Ѯضآؽܽ׽ٽ䣽սֽӢ֪ǿп¿Ŀ˿ӿ¿ɿǿä⿹ƿȿʿƿ謹еر޵ַҾľֹľ׾̰գңطӾԡʽءˡʾѾءϾ޾۾¾׾騾ľܥƾྫྷϾɾ˾ƴҾݾоξƾȾϾܾþھ˾ʾԧ֤ѿ°濣ػ㭻׶ӻӶǼӡܻHҿӺǡɦ֬寿ڻ¶ǰٻлף㬰ԮǷȻֻѳʻ̼һ̦ڼ褴ֻƤ豫dz˸ʿͻٮӦͶ긼뽿ܻ߷߽Ϋڼ޴ͺɾ참ֿ곡ָӯ˼λãů͡ұⷱζ۸ΤܪǾ٩ӴܼƱݺ峦涭ոපߦ»ڹĿĢջɻܢӻբ3O߻úޯخ稺ռŻø칹ʺѱ٣׺˺㷺ԺݺҺӼкںκպʺĺƺ׺źͺԺۺкǺªںԺغݯ̻赺ͼӺԼ亵ֺ麺úհ̬٭ϻ⤹Ż맻źʸšɸĻں̢ǡƨõӥ㧳S]\|\_s*[]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\%(ϩ\|Ϫ\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[ס]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*Ѥ\|\_s*\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|\_s*\|\_s*\|c\_s*e\_s*n\_s*t\_s*i\|\_s*[϶]\|\_s*\|\_s*̥\|\_s*\|ŵ\_s*\|\_s*ͺ\|\_s*\|ŷ\_s*[IJ]\|V\_s*i\_s*o\_s*l\_s*a\_s*l\_s*e\_s*s\|N\_s*y\_s*m\_s*p\_s*h\_s*a\_s*e\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|\_s*\|\_s*ƻ\|\_s*\%(\|\_s*\)\|Ϸ\_s*\|˾\_s*Ĭ\|\_s*\|\_s*[Ǧ]\|L\_s*a\_s*\%(b\_s*i\_s*a\_s*t\_s*a\_s*e\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\_s*\|ʾ\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|ت\_s*ͺ\|\_s*\|\_s*\|I\_s*\%(s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\)\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*ʸ\|\_s*[ë]\|\_s*[]\|\_s*\%(\_s*\_s*\|\_s*\_s*\)\|\_s*\%([ظܻ]\|\_s*\)\|7\_s*\|\_s*\|4\_s*\|\_s*[ʬ]\|\_s*\|\_s*\|\_s*\|\_s*\|͢\_s*[]\|Ȼ\_s*[ϯϺ]\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|³\_s*\%(\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\_s*\)\|ή\_s*[Υ]\|\_s*\|\_s*\|Һ\_s*ȭ\|\_s*\_s*\|C\_s*\%([se]\|y\_s*c\_s*a\_s*d\_s*\%(i\_s*d\_s*a\_s*e\|o\_s*\%(p\_s*s\_s*i\_s*d\_s*a\|f\_s*i\_s*l\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\)\|h\_s*l\_s*o\_s*r\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|\_s*\|D\_s*Ź\|\_s*\_s*\|a\_s*\%(s\_s*s\_s*y\_s*t\_s*h\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|c\_s*t\_s*a\_s*l\_s*e\_s*s\)\)\|\_s*\|\_s*[]\|\_s*\_s*Ʀ\|ۨ\_s*\|\_s*\|\_s*\_s*\%(\_s*[ǯ]\|\_s*[ǯ]\)\|\_s*\|ɴ\_s*\_s*\|\_s*¹\_s*\|\_s*ƣ\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(ˡ\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|P\_s*\%(a\_s*r\_s*i\_s*e\_s*t\_s*a\_s*l\_s*e\_s*s\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|r\_s*i\_s*m\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\)\|A\_s*\%(p\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*a\_s*l\_s*e\_s*s\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\)\|s\_s*f\_s*o\_s*r\_s*z\_s*a\_s*n\_s*d\_s*o\|\_s*[ŵ]\|B\_s*\%(r\|\_s*\_s*\)\|\_s*ĥ\_s*\|\_s*\_s*\|\_s*ʬ\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*¤\_s*\|M\_s*\%(e\_s*r\_s*c\_s*u\_s*r\_s*y\|u\_s*s\_s*a\_s*l\_s*e\_s*s\|a\_s*r\_s*q\_s*u\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\)\|D\_s*o\_s*n\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*A\_s*l\_s*p\_s*h\_s*o\_s*n\_s*s\_s*e\_s* \_s*F\_s*r\_s*a\_s*n\_s*c\_s*o\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\|\_s*\%(Ƿ\|\_s*\%(\_s*̣\|\_s*\_s*\)\)\|T\_s*\%(e\_s*t\_s*r\_s*a\_s*c\_s*e\_s*n\_s*t\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\|h\_s*e\_s* \_s*S\_s*i\_s*m\_s*p\_s*l\_s*e\_s* \_s*A\_s*P\_s*I\_s* \_s*f\_s*o\_s*r\_s* \_s*e\_s*v\_s*e\_s*n\_s*t\_s*-\_s*b\_s*a\_s*s\_s*e\_s*d\_s* \_s*X\_s*M\_s*L\_s* \_s*p\_s*a\_s*r\_s*s\_s*i\_s*n\_s*g\)\|\_s*\|\_s*\_s*\|\_s*¬\_s*\_s*ư\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\%([]\|\_s*\|\_s*\)\|\_s*\%([]\|\_s*\)\)\|\_s*̣\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\%(\|\_s*\_s*\_s*\)\|\_s*\_s*\)\|\_s*\%(\|\_s*\%([]\|\_s*\_s*[]\)\|\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\)\)\|\_s*\|β\_s*\)', + \ 'T' : '\%([˳ɼҸڽѲ۳ݽ꾲Ĺゥƾη䶡ݽȼͧ۽ĹԥЧܽ˺̭ǯӷֺܺڢκ˭ƿ¢ѸݹǼƻƺܫƳ۶岳ڮݥܪٵֺ߮ƪе즰ƽ޹ơƦƭƤƣƫƥոﰳ믿æԦѽײѽѹϳαͻųϿڼͿ޻Ȏӱ͹ʻԹ֥ųׯŭūڳũɡץšżſŶŻŸźŲŪůŨűŰŴܼ챭ܨţšŢ޸׷Ǝʾʼŵ̳ض۲ϸ̽Ϫٴܻܿѳ㪱γªڼָʴϸȺ鲶ڹ˷Ҿѣױ³ٽƿ븾̢Խϴ˵Ϻ¤ݶԯзˤض࿵˾ͿԻڻܦƵ⸷ѻ̹ϢĎ׹ۺ紺N㾹ٻĿٲŦȤܺĽҬļŤı׭ذ߭׬ġĵįŽƬĸķijĪĢĭƨĻĥĤĨȥħİĦĬĮĺĴģIJĶĩīЦѲפدɪɳղϡѡСο漣֮ѻ׷ڲ٤ֿ̯ڸȿˬܽîƢí̱۸нԻվιìʾλƧ٥ƮáȾ䲹ﴰ٦ɶݾŹêéڥçäܱ纴ͤɫ맰ܭζεɺݰľ鶩ͣԳӬѹҵͺ׼ŬƵ«ԡýݽèã۹̴ƿֻǤƱýϰ䶳ٷɹºյδйٿӸþں߬߸ÿWöӷëóȿC÷òýðôùøúûõñâپŧڤ٧Ӷ߷ڭʿڬжԱǿĹʲ֫­Ωίȯ۴¿¾¿ïҺӣ߱٣崤ŷ߷ڢᦨɽڥ覨ȥġžƩȥĻüԧӨƨ䨷T]\|\_s*[ĎΎ]\|\_s*[ȥƥĥ]\|\_s*[ȤƤĤ]\|\_s*\|\_s*\_s*\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*Ϸ\|\_s*\|\_s*[]\|\_s*\|\_s*ľ\|\_s*\|\_s*\_s*\|\_s*[]\|\_s*[]\|͸\_s*\|\_s*\_s*\_s*\|\_s*\|H\_s*y\_s*d\_s*r\_s*o\_s*c\_s*h\_s*a\_s*r\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*[ƻ]\|\_s*[]\|\_s*ǯ\_s*\|\_s*[׻]\|A\_s*c\_s*o\_s*n\_s*i\_s*t\_s*u\_s*m\|ƶ\_s*\|\_s*\|\_s*\|F\_s*e\|I\_s*r\_s*o\_s*n\|\_s*¼\|\_s*\|\_s*̼\|ɻ\_s*\|\_s*\_s*\|\_s*\%(\|ε\_s*\)\|\_s*[]\|\_s*\%(\|\_s*\)\|ɹ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|B\_s*a\_s*l\_s*a\_s*n\_s*o\_s*p\_s*h\_s*o\_s*r\_s*a\_s*l\_s*e\_s*s\|1\_s*\%(\|0\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\_s*\|E\_s*\%(u\_s*p\_s*h\_s*o\_s*r\_s*b\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(Ϸ\_s*Ƭ\|\_s*\)\|\_s*\%([]\|\_s*\|ܥ\_s*\_s*\)\|\_s*\|\_s*\|\_s*\_s*\|\_s*[]\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*ެ\|\_s*\|J\_s*i\_s*a\_s*n\_s*g\_s*s\_s*u\|\_s*\|\_s*[]\|\_s*ë\|\_s*\|\_s*Ϫ\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|\_s*\_s*\|\_s*[]\|\_s*\_s*\|\_s*\%(\_s*\|Ϣ\_s*\_s*[]\)\|\_s*\%(\|\_s*˷\)\|\_s*Ƣ\|\_s*\|\_s*\|\_s*[ڳ]\|\_s*\|\_s*\%(ͼ\|\_s*\)\|\_s*\|\_s*\|ͱ\_s*Ю\|̵\_s*\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|P\_s*\%(\.\_s*S\_s*\.\|o\_s*l\_s*y\_s*\%(g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*r\_s*p\_s*i\_s*c\_s*a\_s*e\)\|a\_s*n\_s*d\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|ж\_s*\|Ʋ\_s*\|ǽ\_s*[ʸǷ]\|\_s*\|\_s*̱\|\_s*\|\_s*\_s*\|\_s*\|M\_s*\%(e\_s*n\_s*i\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*c\_s*e\_s*a\_s*e\|o\_s*n\_s*o\_s*\%(p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*\%(h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|o\_s*t\_s*y\_s*l\_s*e\_s*d\_s*o\_s*n\_s*e\_s*a\_s*e\)\)\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\%(\_s*[ȥ]\|\_s*\)\|\_s*\_s*\|\_s*[ॢ]\|\_s*\%(\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\%(\|\_s*\)\)\|\_s*\%(\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*[ե]\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%([ɥ]\|\_s*\|\_s*\_s*\|\_s*\_s*[]\|\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\)\|\_s*\_s*\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\|Ϣ\_s*ʸ\_s*\)\|\\\_s*T\_s*e\_s*X\|\_s*\_s*\|ʸ\_s*\_s*\|t\_s*e\_s*\%(r\_s*a\|m\_s*p\_s*o\_s*r\_s*a\_s*r\_s*y\)\|\_s*\|\_s*\%([]\|\_s*\_s*\_s*\_s*\_s*\)\)', + \ 'U' : '\%([Ⱥɶἷƶڰѽ뼿åѽִء¥ӹⱳư뭱վž𱴵ΪŲر󨱲山۲񱷸¹ϻڴ︽̱ǰֶ̽޲墱ⳤزﷵ庨΢ױӺ屯ĬΣݵ汵²ͫ˷ⱫDZڽͭɼޢƤձ񻾵ѵھвͷα仺ǿ⤦զԥ姵U]\|\_s*\|\_s*\|\_s*\|ϵ\_s*\|\_s*\_s*\|\_s*\|թ\_s*\_s*\|\_s*\|ͥ\_s*\%(\_s*[ɰ]\|\_s*\)\|\_s*\|\_s*²\|\_s*\|ˢ\_s*\|\_s*\|\_s*\_s*[Ƭ]\|\_s*\|\_s*Ǽ\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*Ļ\_s*\|ø\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|̣\_s*\|\_s*\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*Ϻ\|\_s*\|\_s*[]\|\_s*\%(\|\_s*\_s*\)\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*ǽ\|\_s*\%(\_s*\|ͭ\_s*\)\|\_s*\%([]\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\|\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\)\)\|ñ\_s*\%(\|\_s*\)\|\_s*\%([ˡ]\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\%(\_s*\|\_s*\)\)\)', + \ 'V' : '\%([֢ͣǧӢ˥V]\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|v\_s*e\_s*r\_s*s\_s*u\_s*s\|\_s*\_s*\|\_s*\_s*\|\_s*\| \_s*\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%([ܥȥ]\|\_s*\%(\_s*\_s*\|\_s*[]\)\)\|\_s*\_s*\_s*\|\_s*\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\|\_s*\|\_s*\_s*\|\_s*\%([ȥ]\|\_s*\|\_s*\_s*\%(\|\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\_s*\_s*\_s*\|\_s*\%([ɥ]\|\_s*\_s*\|\_s*\_s*\)\)\|\_s*\_s*\|\_s*Ĺ\_s*\|\_s*ľ\|\_s*\%(\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\%(\|\_s*\)\)\|\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\%(\|\_s*\)\)\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\_s*\_s*\|\_s*\)\)\|\_s*\%([֥Х]\|\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\%(\|\_s*[]\)\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\|\_s*\%([]\|\_s*\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\%(\|\_s*\_s*\%(\|\_s*\_s*\_s*\_s*\)\)\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\|\_s*\)\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*\%([ȥ]\|\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*[]\)\|\_s*\%(\|\_s*\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\_s*\)\|\_s*\|\_s*[䥢]\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\)\)\|\_s*\%([]\|\_s*\%([֥]\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\_s*\|\_s*\|\_s*\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\)\|\_s*\|\_s*\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*\%([顼]\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\|\_s*\_s*\)\)\|\_s*\%([]\|\_s*\_s*\|\_s*\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\|\_s*\%(\|\_s*\|\_s*\)\|\_s*\|\_s*\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\_s*\)\)\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\)\)\|\_s*\%(\|\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\)\)', + \ 'W' : '\%([򲧽˽ﲴͺȺɶʦԦἷƶڰ뼿åѽء¥ӹⱳư뭱վž𱴵ΪŲر󨱲山۲񱷸¹ϻڴ︽̱ǰֶ̽墱زﷵ庨U΢׻᢬Ӻ屯ĬΣݵ汵²ͫ˷ⱫDZڽͭɼޢƤձ񻾵ѵھвͷα仺ǿ⤦ܲϴѽѴֲҺҶȵɡب˺оƸ޾׿׾бIJƻĹʻ駷Ųѯ뻲Ƚռ㰿´ĸӻͯͰʬʨʤȣץW]\|\_s*[񎳥]\|\_s*[񥦥]\|\_s*[񤦤]\|\_s*\_s*\_s*\|\_s*\|\_s*\|\_s*\|ϵ\_s*\|\_s*\_s*\|\_s*\|թ\_s*\_s*\|\_s*\|ͥ\_s*\%(\_s*[ɰ]\|\_s*\)\|\_s*\|\_s*²\|\_s*\|ˢ\_s*\|\_s*\|\_s*\_s*[Ƭ]\|\_s*\|\_s*Ǽ\|\_s*\|\_s*\|\_s*\|\_s*\_s*Ļ\_s*\|ø\_s*\%(\|\_s*\_s*\)\|\_s*\%(\|\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*\)\|\_s*\_s*\|̣\_s*\|\_s*\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\_s*\|\_s*\|\_s*Ϻ\|\_s*\|\_s*[]\|\_s*\%(\|\_s*\_s*\)\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|\_s*\|\_s*\|\_s*\|\_s*ͥ\|\_s*˺\_s*\|\_s*\|\_s*\_s*\|(\_s*\_s*)\|\_s*[]\|\_s*\|\_s*\|\_s*\|Y\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\|\_s*\_s*\|\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\|\_s*[ͳ]\|\_s*\|\_s*\|\_s*\_s*\_s*٥\_s*\|\_s*\%(\|ʿ\_s*\_s*\_s*\)\|ݿ\_s*\_s*\_s*٥\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%(\|\_s*\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\_s*\)\)\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\_s*\%([ץ]\|\_s*\_s*\)\|\_s*\%([]\|\_s*\_s*\_s*\)\)\|\_s*\_s*\|\_s*\%([ࡼ]\|\_s*\_s*\|\_s*\%(\_s*\|\_s*\)\)\|\_s*\%(\_s*[]\|\_s*\|\_s*\%(\_s*\%(\|\_s*\)\|\_s*\%(\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\)\)\)\|\_s*\%(\|\_s*[ȥ]\)\)\|\_s*\_s*\_s*\|w\_s*e\_s*b\_s*\_s*\%(\_s*\|\_s*\%(\|\_s*\)\)\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\|\_s*\%([]\|\_s*\%(\|\_s*\_s*\)\)\|\_s*\%(\_s*\_s*\_s*\|\_s*\_s*\|\_s*\_s*\|\_s*\)\|\_s*\%(\_s*[]\|\_s*\_s*\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\)\)\)\|\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\|T\_s*\%(h\_s*e\_s* \_s*W\_s*o\_s*r\_s*l\_s*d\_s* \_s*W\_s*i\_s*d\_s*e\_s* \_s*W\_s*e\_s*b\_s* \_s*C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\)\)', + \ 'X' : '\%([ا秷ߦX]\|\_s*[]\|\_s*[]\|\_s*[]\|\_s*\_s*\%(\_s*\|\_s*\_s*\)\|\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\%(\_s*\%(\|\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\|\_s*\_s*\%(\_s*\|\_s*\)\)\|E\_s*x\_s*t\_s*e\_s*n\_s*s\_s*i\_s*b\_s*l\_s*e\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\_s*\|\_s*\%(\|\_s*\%(\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\)\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\)\)', + \ 'Y' : '\%([ֲغ˩շ޷ڡڴֻۻþӱٵ㷽İ˧ȵ׫խۡƫߡٹβžաЮôڵ;ӸǽͽDz¿ͻͷͿ즤μдİ˭Ƿְ쪾றᾲ͸۷Ͳإͤͨͱͻ͹ͯͰʹͼͩͪͧͺͫͭ͡ͷͳ͢·ͮ竤掲׶׵϶̴ߺ̤ӷŲݳͶưݡȵܦɵ述ڿĹǢ̿쵸Ÿವżϫĺ׻кطҮͦܡǮʰᰱ˻ްϮסӱ©ĩ寱۱İĽ˻Сݫ׸ԩ۵ʰݻְյ׮Iΰ𨱡ֱ۩۰дذŰ1ڴŪ٥ަ̰թȺص°ذѰϱԣиȰǡѦ״ͣ޻׳԰ʳ豶İΰڸްͰֹ԰аΨͬհݰڰ۵ԧİøҲݰͻϦSϵ½ͥ²۴ݬٯֳ̼쮼칽̡ҡԡաӻšץ̰ǫ͵ٰ׵ݹȬë׽Ǹܿͼ뻦輭٧֧ߡק觫ԥۦY]\|\_s*[֎Վ]\|\_s*[楤]\|\_s*[椤]\|\_s*\_s*\|ݿ\_s*\_s*\|\_s*\|\_s*Ƹ\|\_s*\|\_s*\|y\_s*o\_s*\%(t\_s*t\_s*a\|c\_s*t\_s*o\)\|4\_s*\%([]\|\_s*\|\_s*\)\|¾\_s*\|\_s*\|δ\_s*\|\_s*\|\_s*\|\_s*\|\_s*[Ҹ]\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*[]\|Ī\_s*[Ұ]\|\_s*\|\_s*\|8\_s*\|\_s*\|\_s*\%(\|\_s*\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|ɴ\_s*\|L\_s*i\_s*l\_s*i\_s*\%(o\_s*p\_s*s\_s*i\_s*d\_s*a\|a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\)\|\_s*\%(ͺ\|\_s*\)\|Ĺ\_s*\|\_s*\|\_s*\|\_s*\|E\_s*\%(u\|\_s*\_s*\)\|\_s*\|J\_s*u\_s*\%(l\_s*i\_s*a\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|n\_s*c\_s*a\_s*l\_s*e\_s*s\)\|\_s*ë\|\_s*\|ɨ\_s*\|\_s*ϻ\_s*\|\_s*\|\_s*±\|\_s*\_s*\|\_s*ȷ\|β\_s*\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|\_s*ɨ\|\_s*\|\_s*\_s*ƣ\|5\_s*[]\|\_s*[]\|ب\_s*٦\|\_s*\|Ĭ\_s*\|\_s*\|\_s*Ӽ\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|ʸ\_s*\|Ϻ\_s*[]\|\_s*[]\|\_s*\|U\_s*\%(\|\_s*\_s*\|r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|\_s*[Ļ]\|\_s*\%(\_s*\_s*\|\_s*\)\|\_s*\|\_s*[ﷻ]\|\_s*\|\_s*\|\_s*\|\_s*¹\_s*\|\_s*\_s*\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|\_s*\|̵\_s*\_s*\|\_s*\|\_s*\_s*ή\|\_s*[]\|\_s*[]\|\_s*[ڻ]\|\_s*ɽ\|\_s*\_s*[ú]\|\_s*ӧ\|\_s*[]\|\_s*\%([]\|\_s*\)\|\_s*\_s*\|\_s*[ʱ]\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|\_s*[ǡ]\|\_s*\|\_s*ζ\_s*\|ξ\_s*\|ή\_s*ŭ\_s*\|\_s*\|\_s*[]\|R\_s*a\_s*f\_s*f\_s*l\_s*e\_s*s\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|\_s*\|\_s*\|\_s*\|ŷ\_s*\|\_s*\|\_s*\_s*\_s*º\|\_s*\|T\_s*\%(h\_s*e\_s*l\_s*i\_s*g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*o\_s*c\_s*h\_s*o\_s*d\_s*e\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|M\_s*y\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|\_s*\_s*\|\_s*¹\|A\_s*r\_s*a\_s*c\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*\%(o\_s*t\_s*e\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*c\_s*i\_s*p\_s*e\_s*s\)\|a\_s*l\_s*m\_s*a\_s*l\_s*e\_s*s\)\|\_s*\|\_s*[]\|\_s*\%(\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\|\_s*\)\|\_s*\)', + \ 'Z' : '\%([»¸·­«֤±³²¯°¡£¤źȿդظƦפԦƬݿ߹޿ֺɼټĶԺټľ㿬̭ߩʿ顿ױӿпԿҿؿѿտǽޮտٳа屽лġпЫǡ̼žվڷǨèط۲ٽɽμѽȻŽޭ߱覽۽ڽ޽޼쳼ߨкߧ尽Ľ½ýƽ֮꼥Ώ߼ֵᪿλ̻Яϩ˱ѻżб褻Τ߷ºֿܪȻ̻쩻ϻ»߻ƺú޺ߺкú¢µ좭إڥ٦ƧZ]\|\_s*\%(\_s*\|\_s*\|\_s*\|\_s*\|\_s*\)\|\_s*[]\|\_s*[]\|\_s*\|\_s*\|\_s*\|\_s*[]\|\_s*\|z\_s*e\_s*\%(t\_s*t\_s*a\|p\_s*t\_s*o\)\|\_s*\_s*\|\_s*\|\_s*\|ȯ\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*ˡ\|\_s*\|Ĵ\_s*\|\_s*[᷺]\|\_s*\|\_s*\|F\_s*i\_s*g\_s*u\_s*r\_s*e\|\_s*\|G\_s*\%(\_s*\|\_s*\)\|D\_s*y\|\_s*\%(\_s*\|\_s*\)\|\_s*\|\_s*\|\_s*\|2\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|J\_s*\%(I\_s*S\_s*\_s*\_s*\|\_s*\_s*\|R\_s*\_s*\_s*\)\|\_s*\|\_s*\_s*ʺ\_s*\_s*\_s*\_s*\_s*\_s*\_s*\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|\_s*\%(\|\_s*\)\|\_s*\_s*\|\_s*\%(\|\_s*\)\|\_s*ī\|\_s*\|Ƚ\_s*\|ϳ\_s*\|\_s*\|Ĺ\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\|\_s*Τ\|\_s*[ϴ崽]\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|\_s*\%(\_s*\_s*\|\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\|\_s*\|\_s*\%(\|\_s*[ʷ]\|\_s*\|\_s*\|\_s*\)\|\_s*\|\_s*\|ɳ\_s*\|1\_s*\%(0\|1\_s*\|8\_s*\|2\_s*\)\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\|\_s*\_s*\|\_s*\|\_s*\|\_s*\%(\_s*\|\_s*\_s*\_s*\_s*\|\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\%(\|\_s*\%(\_s*\|\_s*\)\)\)\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\%(\|\_s*\)\|\_s*\_s*\_s*\_s*\_s*\|\_s*\_s*\_s*\_s*\_s*\_s*\_s*\)\|\_s*\%(\_s*\%(\_s*\_s*\_s*\_s*\_s*\|\_s*\)\|\_s*\%(\_s*\|\_s*\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\%(\_s*\_s*\|\_s*\|\_s*\_s*\_s*\|\_s*\%(\_s*\_s*\|\_s*\_s*\_s*\)\|\_s*\_s*\_s*\)\)\)', + \ } +endfunction diff --git a/bundle/clever-f.vim/autoload/clever_f/migemo/utf8.vim b/bundle/clever-f.vim/autoload/clever_f/migemo/utf8.vim new file mode 100644 index 000000000..6c877eb1d --- /dev/null +++ b/bundle/clever-f.vim/autoload/clever_f/migemo/utf8.vim @@ -0,0 +1,57 @@ +scriptencoding utf-8 +function! clever_f#migemo#utf8#load_dict() abort + return { + \ 'a' : '\%([ア餅母渉恤閔憐慌遽蚫鰒鮑袷淡∃主衽袵歩垤蟻麁凡塔蘭露著表霰非諍抗更検革改現競爭争洗殿鉱予豫粗嵐禮恠妖彪殺絢怪綺肖彩漢過謝謬誤礼操綾飴菴黯罨鱇鮟餡行闇按諳晏鞍暗鶩鬚鰓顎喘発肋豈嫂兄崇騰県購贖网罔咫與鼎中新邉邊辺恰頭價価値游遊畔畦堋杏梓与袙衵憬孔坑案侮窖強貴讐讎徒仇黶痣欺鮮字糾嘲薊姐姉曙炮焙炙蜚薹膏脂油危鐙虻泡蹟能痕踪跡東預聚輯纂遏蒐乢軋誂羹壓惇集陸敦暑淳篤熱扱暖温遖斡私圧焦汗央奥奧媼桜櫻塰蜑餘遍普周剰蔗余尼雨甘天凹押樗楝溢艶庵鰺網戯簣鯵味堊渥軛圷憧欠踵幄握芥齷厚漁鯏蜊蕣淺麻浅晰龝煥晢呆朖啓亮晄鑑滉昜旭聡光亨陽洸璋顯輝昿曠諦朗哲顕彬晶賈章商穐彰晃晧昭秋噫瞹穢阨埃欸姶隘文粟曖鮎藹饗靉挨間相哀葭趾朝晨愛跛蹇跫脚蘆葦芦鐐桎足淦赫燈赧紅旃朱茜藜銅赭閼曉暁垢皹皸絳灯證暴証赤呷扇黝榮碧葵蒼煽仰青穴和或哇婀当上阿編吾在併明開韲悪荒襾痾浴唖有挙遭逢嗚敢褪娃安厭充該彼擧會飫倦合亞揚椏宛遇飽惡當あa藍金@&&∧∩論∠銀会∀空域⇔←↓⇒→↑⌒後Ц亜米¨´`^’〜≒αÅΑアаАa]\|厦\_s*門\|廈\_s*門\|沫\_s*雪\|食\_s*蟻\_s*獣\|H\_s*a\_s*l\_s*o\_s*r\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|浣\_s*熊\|菖\_s*蒲\|豆\_s*汁\|蛙\_s*鳴\_s*蝉\_s*噪\|塩\_s*梅\|家\_s*鴨\|趺\_s*坐\|Z\_s*\%(n\|i\_s*n\_s*c\)\|浮\_s*子\|痘\_s*痕\|窪\_s*地\|糠\_s*蝦\|醤\_s*蝦\|信\_s*天\_s*翁\|左\_s*沢\|雅\_s*典\|校\_s*倉\|小\_s*豆\|四\_s*阿\|鴉\_s*\%(片\|鷺\_s*合\_s*戦\_s*物\_s*語\)\|渾\_s*名\|綽\_s*名\|化\_s*野\|翌\_s*檜\|飛\_s*[魚鳥]\|総\_s*角\|木\_s*通\|通\_s*草\|L\_s*a\_s*r\_s*d\_s*i\_s*z\_s*a\_s*b\_s*a\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|花\_s*鶏\|我\_s*\%(妻\|孫\_s*子\)\|数\_s*多\|奄\_s*美\|灰\_s*汁\|胡\_s*[床坐座葱]\|日\_s*明\|碩\_s*宏\|祥\_s*[仁彦]\|蜻\_s*蛉\|E\_s*\%(s\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\)\|生\_s*憎\|匕\_s*首\|英\_s*\%([保田]\|虞\_s*湾\|賀\_s*保\)\|靄\_s*[靄々]\|I\_s*\%(r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(電\_s*話\|ア\_s*ド\_s*レ\_s*ス\)\|D\_s*カ\_s*ー\_s*ド\|C\_s*\%(タ\_s*グ\|カ\_s*ー\_s*ド\)\)\|I\_s*\%(P\_s*電\_s*話\|C\_s*\%(タ\_s*グ\|カ\_s*ー\_s*ド\)\)\|走\_s*目\|鹹\_s*草\|馬\_s*酔\_s*木\|海\_s*[豹人女士部驢]\|R\_s*u\_s*b\_s*i\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|褐\_s*毛\_s*和\_s*種\|石\_s*蓴\|白\_s*馬\|水\_s*[黽馬綿]\|M\_s*a\_s*l\_s*v\_s*a\_s*l\_s*e\_s*s\|ト\_s*リ\_s*プ\_s*ル\_s*A\|公\_s*理\| \_s*ア\_s*ク\_s*シ\_s*ア\_s*ム\|ヒ\_s*素\|砒\_s*素\|京\_s*都\_s*高\_s*度\_s*技\_s*術\_s*研\_s*究\_s*所\|代\_s*入\|遺\_s*産\|抽\_s*象\|G\_s*o\_s*l\_s*d\|自\_s*動\_s*\%(現\_s*金\_s*取\_s*り\_s*扱\_s*い\_s*機\|預\_s*貯\_s*金\_s*機\)\|属\_s*性\|何\_s*か\|か\_s*つ\|お\_s*よ\_s*び\|セ\_s*ン\_s*ト\_s*キ\_s*ッ\_s*ツ\_s*ネ\|S\_s*\%(b\|i\_s*l\_s*v\_s*e\_s*r\)\|使\_s*用\_s*可\_s*能\|利\_s*用\_s*可\_s*能\|算\_s*法\|割\_s*り\_s*当\_s*て\|オ\_s*\%(レ\|ギ\_s*ュ\_s*ス\_s*タ\_s*ン\|ド\_s*レ\_s*イ\|ン\_s*グ\_s*ス\_s*ト\_s*ロ\_s*ー\_s*ム\|ル\_s*\%(ト\_s*キ\_s*ー\|タ\_s*\%([ーナ]\|ネ\_s*\%(ー\_s*ト\|イ\_s*ト\)\)\)\|ー\_s*\%([クガサトラル]\|ニ\_s*ン\_s*グ\|キ\_s*シ\_s*ン\|ブ\_s*リ\_s*ー\|バ\_s*ー\_s*ド\|ベ\_s*ル\_s*ジ\_s*ュ\|ギ\_s*ュ\_s*ス\_s*\%(ト\|タ\_s*ン\)\|ゾ\_s*ン\_s*ヌ\|ス\_s*\%(チ\_s*ン\|テ\_s*ィ\_s*ン\|タ\_s*ー\|ト\_s*\%(リ\_s*ア\|ラ\_s*リ\_s*ア\)\)\|ド\_s*リ\_s*ー\|ジ\_s*\%([ェー]\|オ\_s*ロ\_s*ジ\)\|デ\_s*ィ\_s*\%(オ\|エ\_s*ン\_s*ス\|シ\_s*ョ\_s*ン\|ト\_s*リ\_s*ア\_s*ム\)\|タ\_s*ム\|ソ\_s*\%(リ\_s*テ\_s*ィ\|ラ\_s*イ\_s*ズ\)\|セ\_s*ン\_s*テ\_s*ィ\_s*ッ\_s*ク\|ロ\_s*ラ\)\)\|配\_s*列\|バ\_s*イ\_s*ト\|ハ\_s*ル\_s*マ\_s*ゲ\_s*ド\_s*ン\|引\_s*数\|人\_s*工\_s*\%(現\_s*実\_s*感\|知\_s*能\)\|イ\_s*\%(ー\_s*ジ\_s*ス\|オ\_s*ン\|ソ\_s*ッ\_s*プ\)\|マ\_s*ル\_s*ド\_s*ゥ\_s*ー\_s*ク\|紫\_s*\%(陽\_s*花\|水\_s*晶\|石\_s*英\)\|A\_s*\%([tlrImc]\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\|u\_s*s\_s*t\_s*r\_s*o\_s*b\_s*a\_s*i\_s*l\_s*e\_s*y\_s*a\_s*c\_s*e\_s*a\_s*e\|K\_s*C\_s*L\|S\_s*C\_s*I\_s*I\|s\_s*t\_s*a\_s*t\_s*i\_s*n\_s*e\|タ\_s*イ\_s*プ\|T\_s*O\_s*K\|N\_s*S\_s*I\|V\_s*シ\_s*ス\_s*テ\_s*ム\|L\_s*T\_s*キ\_s*ー\|ラ\_s*ン\_s*ク\|E\_s*R\_s*A\|D\_s*S\_s*L\_s*モ\_s*デ\_s*ム\|ド\_s*ラ\_s*イ\_s*ブ\|d\_s*a\|M\_s*ラ\_s*ジ\_s*オ\|b\_s*s\_s*t\_s*r\_s*a\_s*c\_s*t\_s* \_s*C\_s*o\_s*n\_s*t\_s*r\_s*o\_s*l\_s* \_s*M\_s*o\_s*d\_s*e\_s*l\|カ\_s*ッ\_s*プ\|ク\_s*ラ\_s*ス\|C\_s*ア\_s*ダ\_s*プ\_s*タ\)\|付\_s*録\|A\_s*\%([4型面]\|x\_s*o\_s*n\|B\_s*\%(型\|r\_s*o\_s*a\_s*d\)\|タ\_s*イ\_s*プ\|T\_s*&\_s*T\|t\_s*\%(o\_s*k\|h\_s*e\_s*n\_s*a\)\|ラ\_s*ン\_s*ク\|I\_s*エ\_s*キ\_s*ス\_s*パ\_s*ー\_s*ト\|/\_s*D\_s*コ\_s*ン\_s*バ\_s*ー\_s*タ\|ド\_s*ラ\_s*イ\_s*ブ\|d\_s*o\_s*b\_s*e\|カ\_s*ッ\_s*プ\|ク\_s*ラ\_s*ス\|p\_s*p\_s*l\_s*e\)\|応\_s*用\|エ\_s*\%([ニメアイー]\|ッ\_s*チ\|ン\_s*\%(ド\_s*ラ\_s*ン\|ジ\_s*ェ\_s*\%(ル\|リ\_s*ッ\_s*ク\)\|ゼ\_s*ル\)\|リ\_s*ア\|オ\_s*リ\_s*ア\|ス\_s*テ\|プ\_s*ロ\_s*ン\)\)', + \ 'b' : '\%([鯔鰡堀本凡盆煩梵骨凹歿鈕釦沒渤没穆睦濮樸目攴攵朴木僕墨卜牧星抱肪鵬冐氓鋩旄瑁袤儚蟒鉾貌旁网茆牟蒡甍胞謗蠎虻髦黽卯懋榜眸罔乏惘妨帽昴忙剖冒忘茅膀妄尨厖膨貿防紡滂茫望亡傍某謀暈拇保墓暮菩簿誉掘募姥謨模母干彫呆慕坊姆牡乾褒惚戊ぼ冖覓幎汨巾羃冪紅鼈瞥韈蔑塀抃遍辧瓣卞汳宀湎采辯辨辮眄冕勉娩弁邉可辺邊べ船房笛淵縁渊渕斑鞭樗椈太袋深蓋葢盖豚節勿佛物震勃蚋風鰤馼蚊聞文誣無蒲撃打不錻武振分蕪奉吹侮葺毋舞悔憮部廡嘸葡撲撫拭伏歩ぶ米謐人匹浸額鐚跛!広開繆別謬泯旻梹罎岷緡紊檳頻壜愍瓶鬢閔憫敏貧便帛辟百闢白杪″緲憑票猫鋲屏渺眇平錨苗秒描廟病尾火日媚靡糒枇贔未引琵瀰嵋備縻糜弾美眉弭濔比寐毘麋微び早速林尿針腹拂散払祓原塙蠻旛旙鑁鷭幡悗挽判棒絆版輓蕃板播礬阪坂磐番盤晩萬蛮万箱蠅芒挟伴蜂桴枹鉢撥働畠畑糞屎鼻花端離話V魅許秤筏罸魃拔閥橋走箸柱寞藐貘獏暴漠瀑麥縛博駁莫驀爆楳憊狽霾唄吠杯賣苺培煤黴貝焙賠買売陪倍梅媒跋伐末幕曝抜罰庭馬葉婆罵這化馳羽塲晴歯場芭刄刃張貼ばb“仏□■⊥下底×|‖−\∵麦ボバ][{}ブビБΒбβベb]\|ッ\_s*\%(ホ\_s*゙\|ヘ\_s*゙\|フ\_s*゙\|ヒ\_s*゙\|ハ\_s*゙\)\|ッ\_s*[ボベブビバ]\|っ\_s*[ぼべぶびば]\|ホ\_s*゙\|小\_s*火\|襤\_s*褸\|孟\_s*買\|P\_s*a\_s*e\_s*o\_s*n\_s*i\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|南\_s*瓜\|耄\_s*耋\|孑\_s*孑\|包\_s*丁\|ヘ\_s*゙\|袂\_s*別\|箆\_s*棒\|篦\_s*棒\|胼\_s*胝\|フ\_s*゙\|補\_s*任\|毒\_s*島\|醜\_s*[女男]\|山\_s*毛\_s*欅\|F\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|布\_s*団\|茯\_s*苓\|V\_s*\%(字\|ネ\_s*ッ\_s*ク\|シ\_s*ネ\_s*マ\)\|附\_s*子\|付\_s*子\|鞦\_s*韆\|豊\_s*[前後]\|ヒ\_s*゙\|魚\_s*[籠篭]\|彌\_s*縫\|弥\_s*[漫縫]\|吃\_s*驚\|天\_s*鵞\_s*絨\|緬\_s*甸\|賓\_s*頭\_s*盧\|編\_s*木\|柏\_s*槙\|S\_s*a\_s*n\_s*t\_s*a\_s*l\_s*a\_s*l\_s*e\_s*s\|兵\_s*[衛法]\|表\_s*紙\|拍\_s*[板子]\|ハ\_s*゙\|囃\_s*子\|巴\_s*爾\_s*幹\|R\_s*o\_s*s\_s*a\_s*l\_s*e\_s*s\|薔\_s*薇\|蟠\_s*踞\|鈑\_s*金\|A\_s*n\_s*n\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|発\_s*条\|祖\_s*母\_s*さ\_s*ん\|梯\_s*子\|伯\_s*\%([林楽労]\|剌\_s*西\_s*爾\)\|莪\_s*原\|蝗\_s*虫\|飛\_s*[車蝗]\|掲\_s*示\_s*板\|プ\_s*ル\_s*コ\_s*ギ\|作\_s*業\_s*域\|オ\_s*ー\_s*ト\_s*バ\_s*イ\|基\_s*[礎底]\|フ\_s*ァ\_s*ゴ\_s*ッ\_s*ト\|背\_s*景\|北\_s*京\|ペ\_s*\%(キ\_s*ン\|テ\_s*ル\_s*ギ\_s*ウ\_s*ス\)\|臭\_s*素\|イ\_s*ギ\_s*リ\_s*ス\|B\_s*\%([面判級型y]\|細\_s*胞\|タ\_s*イ\_s*プ\|ド\_s*ラ\_s*イ\_s*ブ\|カ\_s*ッ\_s*プ\|ク\_s*ラ\_s*ス\|−\_s*ス\_s*プ\_s*ラ\_s*イ\_s*ン\|l\_s*u\_s*e\_s*N\_s*o\_s*t\_s*e\|u\_s*s\_s* \_s*E\_s*r\_s*r\_s*o\_s*r\|a\_s*c\_s*h\|e\_s*l\_s*l\_s*研\|ラ\_s*ン\_s*ク\)\|ホ\_s*ウ\_s*素\|B\_s*\%([h面判級型kiae]\|C\_s*兵\_s*器\|N\_s*F\_s*(\_s*B\_s*a\_s*c\_s*k\_s*u\_s*s\_s*-\_s*N\_s*a\_s*u\_s*r\_s* \_s*F\_s*o\_s*r\_s*m\_s*)\|B\_s*C\|タ\_s*イ\_s*プ\|u\_s*r\_s*k\_s*i\_s*n\_s*a\_s* \_s*F\_s*a\_s*s\_s*o\|フ\_s*レ\_s*ッ\_s*ツ\|ド\_s*ラ\_s*イ\_s*ブ\|カ\_s*ッ\_s*プ\|ク\_s*ラ\_s*ス\|M\_s*P\_s*フ\_s*ァ\_s*イ\_s*ル\|ス\_s*プ\_s*ラ\_s*イ\_s*ン\|S\_s*\%(D\|キ\_s*ー\|チ\_s*ュ\_s*ー\_s*ナ\|ア\_s*ン\_s*テ\_s*ナ\|デ\_s*ジ\_s*タ\_s*ル\)\|O\_s*X\_s*セ\_s*ッ\_s*ト\|I\_s*T\_s*N\_s*E\_s*T\|r\_s*o\_s*m\_s*i\_s*n\_s*e\|ラ\_s*ン\_s*ク\|o\_s*\%(h\_s*r\_s*i\_s*u\_s*m\|v\_s*i\_s*n\_s*e\_s* \_s*S\_s*p\_s*o\_s*n\_s*g\_s*i\_s*f\_s*o\_s*r\_s*m\_s* \_s*E\_s*n\_s*c\_s*e\_s*p\_s*h\_s*a\_s*l\_s*o\_s*p\_s*a\_s*t\_s*h\_s*y\|o\_s*k\|r\_s*o\_s*n\)\)\|硼\_s*素\)', + \ 'c' : '\%([コ恐怖惟怺※米暦轉頃壼鶤袞鯤坤狠艮獻琿悃很建棍魂菎蒟滾梱溷献痕渾墾恨懇根杪王挙泥裔樸鞐熟枹醴蛩蹊徑径溢毀零錯苔拒箏亊判斷諺理断盡尽辞琴言異事今壽寿鯒冀希礫鯉拱齣狛細腓昆拳瘤鮗兄近谺応應答是爰凩兀惚榾忽輿甑腰拵拗鐺鏝昿仰慌桁袷塙頏絖冦耗亙峺效晄覯糠匣逅閧扛湊羔礦爻壙盍洸鬨浤凰閤窖缸寇岡頁傚湟汞洽崗鮫伉訌誥冓敲磽鏗椌搆肓鍠矼砿犒淆呷鵁皐黌遘昴槹蚣肱肴熕胱猴扣杲蛤狎畊昊餃哽幌鱇峇嫦烋隍恆倥徨啌吭釦闔藁絋棡遑紘稾鴿詬哮困靠皋惶紺鈩絳閘蒙冰氷郡蛟槁候楮媾溘后蝗酵嚆犢稿亢哄睾慷梗笄郊効岬肛項巷鑛洪佼狡昂叩勾喉滉糀晃剛晧曠宏控恍侯煌港皓坑皎耿膏向江膠虹巧鴻鉱衡浩興厚耕弘綱抗購講恒溝薨鋼航孝更校行肯荒高皇光好槲梏谷釛尅斛棘轂哭詰告刻酷穀⌒冴虎觚壷胯鼓児漉糊媚古娘冱虚混粉辜湖虍放葫捏鈷痩鴣瞽詁箍錮蠱蛄粐滬估雇故沽転倒漕罟餬拠超込凅誇懲琥扈袴木蝴呱乕踰弧越孤菰跨壺楜黄股肥己女戸恋兒怙瑚戀夸皷滸濾瓠去濃乎杞こセ芹鬩旃錢刋箭羶筌孅阡栫舩纎濺舛甎銛簽湶茜槧吮薦癬斬倩痊孱擶贍纖仟磚燹揃綫喘涎荐饌槫濳沾筅蟾牋苫專翦亘鐫僣韆箋僊殱殲闡賎餞羨顫甅竰糎陝踐銓閃∨潺遷銑栴剪煽譫僉瞻践跣栓疝詮銭穿尠戰僭繊腺泉嬋仙擅淺鮮専扇蘚船浅線撰宣洗選煎戦尖先忙伜倅逼狭狹蝉旋鱈薛椄絏洩卩啜泄紲攝緤§渫刹褻浙竊截窃殺説拙摂節切蓆晰威裼績蹐迹蹠跖跡螫瘠勣籍晢夕鶺雪寂∫∬碩惜析席隻甥韲嘶犀菁瀞晟貰擠睛筬淒醒齊婿撕牲齏情萋穽躋歳栖棲掣腥逝惺斉臍旌悽整凄靖製晴迫塞攻瀬急勢世畆丗糶畝堰脊せク配椚檪櫪栩椡椪箜櫟含纐婚糞癖潛潜鵠凹窪縊跟頚軛珞頸諄鞋履窟狐轡覆沓碎砕条降件頽崩屑釘莖茎陸杙杭掘崛倔鶏鐃藥擽薬楠誓梳串釧與与挫籖鯀鯨鬮籤隈熊艸嚔藾叢鏈腐鎖Ξξ茸菌楔草圀邦國国漱嗽吻腔φ劫刧粂裙勳熏皹桾皸醺崑燻訓勲葷君委钁企咥銜桑某暝峅昏冥眛鮓比闇位鞍藏暗倉廚厨涅々〃ゝヽゞ仝ヾ公曇雲蜘佝栗狂包胡俥梍枢畔鐵★玄黒徠久孔桍窶暮懼駒苦朽区眩吁繰庫垢紅呉汲宮枸劬煦口9瞿工供吼怐玖貢九惧来來區組奇句狗鳩絎嶇衢くシ埀謐Σσ蘂蕋蕊痺褥茵鵐蔀鷸鴫霑入責蔵嶌了縞嶋島凋搾澀澁渋縛暫屡柴荵凌鎬忍簧慕舖↓襪認從从.舌扱罔虐Θθ秕粃椎椣尿貎肉臠猪衣榻黙蜆恵楙誠茂成繁惻鋪陣頻閾櫁樒鹽汐潮瑟蛭疾櫛隲隰嫉蟋悉漆躾膝失室沒鎭沈滴雫賤鎮靜静顰尓爾聢乍併然◇□■◆倖幸貭叱征質柵卯滋撓品鬼鍜錏錣痼凝而拉設垂萎栞襞吝咳什導汁験記徴著印☆〇銀城報調蝨虱白濕湿標七僕楚笞霜臀退斥尻後冩寫舍者砂卸柘炙#♯暹諜喋煮這西娑沙謝紗鯱奢赦洒捨鮭瀉妁鑠抉蹟勺炸決釋皙爍昔斫蜥刳芍酌爵折癪笏赤灼綽杓石尺赭写鷓積遮舎車射斜釈社洙麈殳蛛娶娵諏鬚侏繻銖蹙俶倏菽叔蓿戚肅淑夙粛宿縮殊趣珠恤卆蟀出洲泅楸綉溲遒酬鷲駲緝葺穐蹤繍螽讐甃萩楢逎讎售岫收驟舅囚姑蓚皺鞦銹脩輯醜習羞酋聚舟秀祝袖啾拾蒐収執衆愁就臭蹴週終褶州宗集秋椶棕朱撞種修周手首酒須儁惷悛濬雋皴墫蕣順蠢舜旬浚竣峻駿逡筍瞬俊蓁畛矧縉蔘鷏齔嗔忱譛袗譖娠疹哂脣怎晉鷆臻甄槙寢岑瀋箴軫榛秦襯診鉐津駸讖紳斟唇針呻蜃賑芯瞋振殿侵薪晨辰震宸森眞愼伸慎寝晋進深審親臣鍼申心宍信真新薯墅杵岨藷黍苜渚砠狙嶼處胥蜍苴曙背緒雎蔗庶処署所暑奬簫浹橸舂艢廂陞炒鍬庠獎梢璋將厰邵摺淞訟樅筱篠燮橡愴韶咲誚峭甞鯖敞聲懾稍腫政顳枩慯殤秤湫井星廠剿妝霎蛸劭觴愀升錆鬆樵囁鷦嶂醤青従慫逍倡竦爿薔笙樟装肖菖≦<湘誦聳檣稱声裳蒋蕉嘯慴盛精霄清鈔粧彰鏘悚蕭悄瀟哨焦憔匠鍾償瘴鞘漿頌詔沼妾請唱薑庄渉障奨娼床牀椒抄聖荘宵傷性相生銷召賞猩症昭燒猖昌少尚晶憧紹祥承證笑将焼照招章詳消証硝掌商昇小昃禝稷寔矚謖觸稙軾嗇屬穡拭属燭贖囑嘱織蝕式喰蜀殖諸初触埴植食職嗜笶姉士徙誣氏思染祗時弑滲梔摯肢詩咨祉刺泗輜厶強貲若至師舐咫只施誌呰匙示指締厮啻次賜熾趾駟漬笥贄此司如沚尸髭肆祀鷙諡枝篩豕巵始妛及弛絲浸閇翅緊揣伺糸駛痣矢衰死敷恃茨旨沁嘴蚩試釶俟瓷觜廝緇祠梓址詞之使獅志歯紫雌姿諮占絞視嗣識四恣阯侈幟卮凍史領竢市巳齒偲資止謚耆覗脂芝痴粢孜仕錙耜齎自屎茲岐〆嗤砥知私仔しカ糜癢粥痒麹輕骨業軽鰔鰈餉通瓶龜甕亀鴈獵鳫殯K猟雁釀鳧鳬髢氈鴨躱巛側厠廁磧瓦獺翡為裘皮〜紮→搦苧碓柄體軆躰躯身体鴉犂烏絡空唐榧茅揀坎澗扞莟丱拑盥嫺鑵蒄瞰淦稈康繝懽憾骭戡奐啣厂鐶讙澣羮寰羹嫻杆鸛歡豢歛罕酣陷皖篏捍瀚勸撼驩卷樌潤觀橄涵渙堪巫覡鉋随萱簪舘艱咸翰柬悍駻燗槓浣邯攷稽宦考棺潅閂煥鉗疳癇函凾鹹緘桓款箝諌諫轗旱坩侃鰥 館莞橇韓患灌勧菅奸刊柑肝看桿干緩寒嵌廣広竿貫巻敢漢環間陥喚閑監喊歓甘寛管慣完汗艦乾幹官観壁椛屍姓庇鞄芳蔓千鯑一勘蜻⊃影陰蔭景*棧梯筧庚辛柧門廉癩乞Κ川κ合’)〈《‘“”}{》〉囓柁鮖悴舵鰍梶錺餝飾篭籠還歸卻皈孵省顧槭楓却帰反返督髮帋守祇韮主裃雷髪紙鉦曲矩予鐘樺沫偏騙語潟刀模象仇固硬傍難容忝辱頑形方旁型肩風幽滓翳微掠綛纃絣緕擦糟鎹粕春轄戞劼猾瞎恰蛞∧蠍擔濶筈剋蝎曷羯喝餓聒鞨黠刮蘰鬘桂闊括嘗捷豁渇担滑松堅鰹功割戛活暈疽鵲瘡傘嵩重襲葛笠堵硴墻牆蠣蛎柿關掲罹抱踵嬶嚊拘関係貌顏郁薫顔母感釡罐窰鴎框叺喧竃竈窯釜缶蒲鎌數数槝栢膳傅畏賢橿姦樫爨炊圍喞託囲鈎『鉤「』」限鍵(傾禿蕪鏑頭齧被兜敵適哉必要称鼎鬲彜彝叶片悲哀愛鋺蛇鉄蜩神奏金楫裹磆餅徒褐糧粮膈覺∠埆蠖貉幗隱擴寉骼癨壑咯椁嚇茖愨槨膕掴覈殼穫狢霍礁恪擱匿撹攪喀廓較郭]】【〔〕[殻挌劃閣格隠覚矍革獲馘攫核鶴拡客隔角確蠏壞畍丐獪褂恠喙峡夬觧械揩醢匯廨誡誨嵬櫂隗茴徊迴枴懈价椢榿囘蛙瑰乖浬鰄傀糴柏街鳰懷蛔蠶蚕邂蟹潰壊恢腕芥垣楷會拐悔詼諧皆界疥魁偕改繪貝胛絵甲快灰槐晦懐介回塊解階廻戒開会怪海縢篝炬耀赫輝冠鑒鑑各屈鏡和代茄缺飼嫁華堝變狩上訶架何啝火日菓欠苅繋稼ヶ个噛譁科跏舸賭禍支窩課花刈渦嚼掛呵替葭柯畫駆嘩崋化霞蝌迦顆価馨家借蝦罅駈斯賈嘉易果戈廈哥買闕且克墟靴訛驅換踝描軻嗅價嗄可彼夥香歌河珂鹿個痂書假荷耶笳咼藉糅舁搗渮袈下萪貸厦禾貨咬寡箇卦苛譌枷掻過画ヵ黴遐兼醸翔仮佳蚊懸伽賀淅勝涸苟蝸謌夏枯暇かc・…塩閉倶錫呼∩取籐加交бТуЖоВЙЗзжЪЯУИвяшфлСКрпХЁОЭРФЫЩъБыШйхМкПгдмцНЛёаиэетАГЬюЕЮсьнщД♪┼╋×╂┿○●◎銅∪χΧ子чЧ株Ц珈、,色ク衝競構簡制≡変接カ┐┘┗┏┓┌┛└正コ¢シ℃セc]\|ッ\_s*[コセクシカ]\|ッ\_s*[コセクシカ]\|っ\_s*[子こせくしか]\|焜\_s*炉\|嫡\_s*妻\|二\_s*合\_s*半\|牛\_s*尾\_s*魚\|巨\_s*勢\|独\_s*楽\|居\_s*士\|特\_s*牛\|粫\_s*門\|甦\_s*生\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|傴\_s*僂\|A\_s*\%(r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|p\_s*i\_s*a\_s*l\_s*e\_s*s\)\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|台\_s*詞\|懺\_s*法\|前\_s*[妻栽]\|妹\_s*尾\|嘲\_s*笑\|儕\_s*輩\|斎\_s*次\|済\_s*[民々済]\|蒸\_s*[籠篭]\|救\_s*世\|莎\_s*草\|百\_s*[濟済]\|恭\_s*敬\|9\_s*[日月]\|秧\_s*鶏\|究\_s*竟\|釉\_s*掛\|典\_s*薬\_s*寮\|探\_s*湯\|球\_s*磨\|六\_s*合\|地\_s*祇\|都\_s*子\|群\_s*衆\|慈\_s*姑\|旧\_s*\%(訳\|唐\_s*書\)\|内\_s*蔵\_s*助\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|老\_s*舗\|望\_s*潮\|健\_s*か\|L\_s*a\_s*\%(u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|b\_s*i\_s*a\_s*t\_s*a\_s*e\)\|埋\_s*葬\_s*虫\|幣\_s*原\|卓\_s*袱\|桎\_s*梏\|柳\_s*葉\_s*魚\|蠹\_s*魚\|汚\_s*点\|惠\_s*雄\|舗\_s*石\|磯\_s*城\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|倭\_s*文\|云\_s*[々云]\|明\_s*\%(々\_s*後\_s*日\|明\_s*後\_s*日\)\|7\_s*月\|7\_s*月\|文\_s*月\|4\_s*月\|4\_s*[分月]\|竹\_s*[篦刀]\|羊\_s*[齒歯]\|爲\_s*\%([留難置果送極手兼合業]\|ん\_s*方\|來\_s*り\|納\_s*め\)\|I\_s*\%(l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|素\_s*[魚人面]\|不\_s*[忍知]\|注\_s*連\|軍\_s*鶏\|髑\_s*髏\|三\_s*\%(味\|鞭\_s*酒\)\|吃\_s*逆\|差\_s*[別異]\|叉\_s*手\|輸\_s*[出贏]\|卒\_s*去\|B\_s*r\|隼\_s*[朗郎]\|笋\_s*[干羹]\|参\_s*差\|財\_s*産\|枌\_s*所\|縦\_s*容\|睫\_s*毛\|M\_s*\%(e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|u\_s*s\_s*a\_s*l\_s*e\_s*s\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|S\_s*\%([eg]\|p\_s*e\_s*r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*i\_s*t\_s*a\_s*m\_s*i\_s*n\_s*e\_s*a\_s*e\)\|続\_s*\%(日\_s*本\_s*\%(紀\|後\_s*紀\)\|後\_s*撰\_s*和\_s*歌\_s*集\)\|離\_s*れ\_s*離\_s*れ\|掃\_s*部\|羚\_s*羊\|土\_s*器\|蝙\_s*蝠\|魚\_s*狗\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|o\_s*\%(t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\|d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\)\)\|連\_s*枷\|枳\_s*殻\|機\_s*関\|落\_s*葉\_s*松\|凵\_s*繞\|檻\_s*車\|顴\_s*骨\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|南\_s*瓜\|量\_s*子\|山\_s*\%(海\_s*経\|梔\_s*子\|陽\_s*道\)\|蜉\_s*蝣\|陽\_s*炎\|破\_s*片\|脚\_s*気\|旗\_s*魚\|鍛\_s*[治冶]\|挿\_s*頭\|駕\_s*\%(籠\|輿\_s*丁\)\|長\_s*[月官]\|剃\_s*刀\|天\_s*\%(牛\|鼠\_s*矢\)\|帷\_s*子\|酢\_s*漿\_s*草\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|飛\_s*[沫白]\|曾\_s*て\|曽\_s*て\|燕\_s*子\_s*花\|牡\_s*[蛎蠣]\|民\_s*部\|部\_s*曲\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|案\_s*山\_s*子\|梭\_s*\%(魚\|子\_s*魚\)\|蟷\_s*螂\|螳\_s*螂\|瓜\_s*\%(田\|呂\_s*根\)\|拍\_s*手\|瑕\_s*[瑾疵]\|東\_s*\%([風雲]\|海\_s*林\|京\_s*都\_s*立\_s*科\_s*学\_s*技\_s*術\_s*大\_s*学\)\|気\_s*[質触]\|(\_s*株\_s*)\|贏\_s*ち\_s*得\|歩\_s*兵\|恁\_s*く\|杜\_s*\%(若\|父\_s*魚\)\|梅\_s*花\_s*皮\|頴\_s*田\|膾\_s*炙\|契\_s*経\|中\_s*央\_s*処\_s*理\_s*装\_s*置\|伊\_s*藤\_s*忠\_s*テ\_s*ク\_s*ノ\_s*サ\_s*イ\_s*エ\_s*ン\_s*ス\|分\_s*類\|ス\_s*リ\_s*ー\_s*ズ\|範\_s*疇\|ト\_s*ラ\_s*ン\_s*プ\|水\_s*[鶏母夫手晶]\|複\_s*雑\_s*命\_s*令\_s*セ\_s*ッ\_s*ト\_s*計\_s*算\_s*機\|サ\_s*\%(ン\_s*チ\_s*ー\_s*ム\|エ\_s*ラ\|イ\_s*\%(ト\_s*カ\_s*イ\_s*ン\|ラ\_s*ス\|ク\_s*\%([ルロ]\|リ\_s*\%(ン\|ッ\_s*ク\)\)\|ボ\_s*\%(ウ\_s*ズ\|ー\_s*グ\)\|バ\_s*\%(ー\|ネ\_s*テ\_s*ィ\_s*\%(ッ\_s*ク\|ク\_s*ス\)\)\|リ\_s*ュ\_s*ー\_s*ム\|ダ\_s*ー\|フ\_s*ァ\_s*ー\|ネ\_s*リ\_s*ア\)\|ー\_s*\%(テ\_s*ィ\_s*フ\_s*ィ\_s*ケ\_s*ー\_s*シ\_s*ョ\_s*ン\|ク\_s*ル\|カ\_s*\%(ス\|ム\_s*ス\_s*ク\_s*\%(ラ\_s*イ\_s*ブ\|リ\_s*プ\_s*シ\_s*ョ\_s*ン\)\)\|キ\_s*\%(ュ\_s*\%(ラ\_s*ー\|レ\_s*ー\_s*\%(タ\_s*ー\|シ\_s*ョ\_s*ン\)\)\|ッ\_s*ト\)\)\)\|マ\_s*ド\_s*ラ\_s*ス\|茶\_s*筅\|ケ\_s*\%([月アイ]\|フ\_s*ェ\_s*ウ\_s*ス\|プ\_s*ス\_s*ト\_s*ラ\_s*[ムル]\|チ\_s*ャ\_s*ッ\_s*プ\|ン\_s*\%(タ\_s*ウ\_s*\%(リ\|ロ\_s*ス\)\|ブ\_s*リ\_s*ッ\_s*ジ\)\|ー\_s*\%([キジブプスン]\|ク\_s*ウ\_s*ォ\_s*ー\_s*ク\|ソ\_s*ン\|タ\_s*リ\_s*ン\_s*グ\|パ\_s*\%(ー\|ビ\_s*リ\_s*テ\_s*ィ\)\|シ\_s*ン\_s*グ\|リ\_s*ー\)\|ル\_s*\%(ト\|ベ\_s*ロ\_s*ス\|テ\_s*ィ\_s*ッ\_s*ク\|ビ\_s*\%(ム\|ー\_s*ニ\)\)\|ミ\_s*\%(カ\_s*ル\|ス\_s*ト\)\)\|キ\_s*\%(ヤ\_s*ノ\_s*ン\|プ\_s*ロ\_s*ス\|ケ\_s*ロ\|ュ\_s*\%([イーア]\|ヴ\_s*ェ\|ビ\_s*\%(ズ\_s*ム\|ス\_s*ム\)\|ロ\_s*\%(ス\|ッ\_s*ト\)\|レ\_s*ー\_s*タ\_s*ー\|ラ\_s*ソ\_s*ー\|リ\_s*\%(ー\|ウ\_s*ム\|ア\_s*ス\|オ\_s*シ\_s*テ\_s*ィ\)\)\|ア\_s*\%(ラ\|ー\_s*ラ\|ン\_s*テ\_s*ィ\)\|チ\_s*ン\|ト\_s*サ\_s*ン\|メ\_s*ラ\|マ\_s*イ\_s*ラ\|ッ\_s*カ\|レ\_s*ー\_s*ト\|ャ\_s*\%([ドパスブンラ]\|デ\_s*\%(ィ\|ラ\_s*ッ\_s*ク\)\|ビ\_s*\%([アンネ]\|テ\_s*\%(ィ\|ー\_s*シ\_s*ョ\_s*ン\)\)\|ベ\_s*ツ\|バ\_s*\%(リ\_s*[エア]\|レ\_s*ー\)\|ト\_s*ル\|シ\_s*ー\|サ\_s*リ\_s*ン\|タ\_s*ピ\_s*ラ\|ピ\_s*\%(ト\_s*ル\|タ\_s*\%(ル\|リ\_s*ズ\_s*ム\)\)\|プ\_s*\%(ラ\|シ\_s*ョ\_s*ン\|テ\_s*ン\|チ\_s*ャ\)\|セ\_s*\%(イ\|ロ\_s*ー\_s*ル\)\|ッ\_s*\%([ツトチプ]\|サ\_s*バ\|ス\_s*ル\|シ\_s*\%(ュ\|ン\_s*グ\|ャ\_s*\%(ー\|ブ\_s*ル\)\)\)\|ニ\_s*\%(オ\_s*ン\|ス\_s*タ\_s*ー\)\|ナ\_s*ル\|ノ\_s*\%(ン\|ー\_s*ラ\|ピ\_s*ー\)\|ミ\_s*ソ\_s*ー\_s*ル\|メ\_s*\%(ル\|ロ\_s*\%(ン\|ッ\_s*ト\)\)\|ロ\_s*\%(ル\|ウ\_s*ェ\_s*イ\|リ\_s*ン\|ラ\_s*イ\_s*[ンナ]\|ッ\_s*ト\)\|レ\_s*ッ\_s*ト\|リ\_s*\%([コーア]\|バ\_s*ー\|ブ\_s*レ\_s*ー\_s*シ\_s*ョ\_s*ン\|ッ\_s*ジ\|ン\_s*グ\)\|ズ\_s*ム\)\|リ\_s*\%(コ\|ス\_s*ト\|シ\_s*タ\_s*ン\)\)\|総\_s*角\|チ\_s*\%([タリンマア]\|ワ\_s*ワ\|ラ\_s*ー\|ル\_s*ド\|ム\_s*ニ\_s*ー\|コ\_s*リ\|ッ\_s*\%([プク]\|テ\_s*リ\_s*オ\|タ\_s*ゴ\_s*ン\)\|キ\_s*\%(ン\|ー\_s*タ\)\|ュ\_s*\%(ア\_s*ブ\_s*ル\|ー\_s*イ\_s*ン\_s*ガ\_s*ム\)\|ー\_s*\%([フトプクズ]\|パ\_s*ー\|タ\_s*ー\)\|ェ\_s*\%([ロスカコアン]\|ザ\_s*\%(レ\|ー\_s*レ\)\|ル\_s*\%(ニ\_s*ー\|シ\_s*ー\|ノ\_s*ブ\_s*イ\_s*リ\)\|リ\_s*\%(ー\|ス\_s*ト\|ッ\_s*シ\_s*ュ\|モ\_s*ヤ\)\|レ\_s*\%(ス\_s*タ\|ン\_s*コ\_s*フ\)\|ビ\_s*チ\_s*ェ\_s*フ\|ダ\_s*ー\|チ\_s*ェ\_s*ン\|ッ\_s*\%([トクカ]\|キ\_s*ン\_s*グ\)\|イ\_s*\%([スン]\|ニ\_s*ー\|サ\_s*ー\|シ\_s*ン\_s*グ\)\|ー\_s*\%(ン\|ザ\_s*レ\|ホ\_s*フ\)\)\|ャ\_s*\%([オフドインコリウ]\|ツ\_s*ネ\|ク\_s*ラ\|プ\_s*タ\_s*ー\|パ\_s*テ\_s*ィ\|ペ\_s*\%(ル\|ッ\_s*ク\)\|チ\_s*ャ\|ネ\_s*\%(ル\|ラ\_s*ー\|リ\_s*ン\_s*グ\)\|ッ\_s*\%([クト]\|ピ\_s*ー\|プ\_s*\%(マ\_s*ン\|リ\_s*ン\)\)\|タ\_s*\%(レ\_s*[イー]\|リ\_s*ン\_s*グ\)\|ル\_s*マ\_s*ー\_s*ス\|レ\_s*ン\_s*ジ\|モ\_s*ロ\|ー\_s*\%([チタトムジ]\|ビ\_s*ル\|ミ\_s*\%(ー\|ン\_s*グ\)\|リ\_s*ー\|ル\_s*\%([ズス]\|ト\_s*ン\)\)\|ラ\_s*ン\_s*ゴ\)\|ョ\_s*\%([ンコ]\|イ\_s*ス\|ム\_s*ス\_s*キ\_s*ー\|ー\_s*\%(ク\|サ\_s*ー\|カ\_s*ー\|キ\_s*ン\_s*グ\)\|ゴ\_s*リ\|ッ\_s*\%(プ\|ピ\_s*ー\|パ\_s*ー\)\|リ\_s*ソ\)\)\|座\_s*標\|喜\_s*劇\|互\_s*換\|共\_s*\%(通\|産\_s*主\_s*義\_s*者\)\|継\_s*続\|C\_s*\%([srfdDeRoa]\|言\_s*語\|型\_s*肝\_s*炎\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(U\|S\_s*(\_s*C\_s*o\_s*n\_s*t\_s*i\_s*n\_s*u\_s*a\_s*t\_s*i\_s*o\_s*n\_s*-\_s*P\_s*a\_s*s\_s*s\_s*i\_s*n\_s*g\_s* \_s*S\_s*t\_s*y\_s*l\_s*e\_s*)\)\|u\_s*r\_s*i\_s*u\_s*m\|M\_s*\%(U\|ソ\_s*ン\_s*グ\)\|タ\_s*イ\_s*プ\|T\_s*\%(ス\_s*キ\_s*ャ\_s*ン\|R\_s*L\_s*キ\_s*ー\)\|シ\_s*ェ\_s*ル\|S\_s*\%(V\_s*フ\_s*ァ\_s*イ\_s*ル\|チ\_s*ュ\_s*ー\_s*ナ\|ア\_s*ン\_s*テ\_s*ナ\)\|カ\_s*ッ\_s*プ\|ク\_s*ラ\_s*ス\|コ\_s*ン\_s*パ\_s*イ\_s*ラ\|C\_s*\%(R\_s*(\_s*C\_s*r\_s*e\_s*e\_s*d\_s*e\_s*n\_s*c\_s*e\_s* \_s*C\_s*l\_s*e\_s*a\_s*r\_s*w\_s*a\_s*t\_s*e\_s*r\_s* \_s*R\_s*e\_s*v\_s*i\_s*v\_s*a\_s*l\_s*)\|D\_s*カ\_s*メ\_s*ラ\)\|ド\_s*ラ\_s*イ\_s*ブ\|+\_s*+\|L\_s*\%(X\|O\_s*S\|I\_s*S\_s*P\)\|E\_s*S\_s*P\|A\_s*\%(D\|S\_s*[LE]\)\|ラ\_s*ン\_s*ク\|I\_s*S\_s*C\|h\_s*\%(l\_s*o\_s*r\_s*\%(a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\_s*e\)\|r\_s*o\_s*m\_s*i\_s*u\_s*m\|a\_s*S\_s*e\_s*n\)\|O\_s*\%(B\_s*O\_s*L\|N\_s*T\_s*R\_s*O\_s*L\_s*キ\_s*ー\)\)\|ツ\_s*\%(ァ\_s*ー\|ィ\_s*リ\_s*ル\|ェ\_s*\%(ー\|ル\_s*ニ\_s*ー\|ラ\_s*ン\)\)\|炭\_s*素\|C\_s*\%([型m]\|M\_s*ソ\_s*ン\_s*グ\|タ\_s*イ\_s*プ\|カ\_s*ッ\_s*プ\|ク\_s*ラ\_s*ス\|d\_s*S\|D\_s*−\_s*R\_s*O\_s*M\|ド\_s*ラ\_s*イ\_s*ブ\|+\_s*+\|ラ\_s*ン\_s*ク\|O\_s*2\|o\_s*C\_s*\%(o\|O\_s*ス\_s*ト\_s*ア\)\|言\_s*語\)\)', + \ 'd' : '\%([共吃巴鑼錚鶏鳥響嫩緞丼呑曇貪鈍肭遠蚌溝鄰隣塢床処所年時鯲鰍鰌得徳讀獨髑毒読僮働萄桐閙ゞ嫐橈儂陶耨撓通鐃藤々恫瞳憧鬧⇔≡撞慟導〃仝洞堂瞠獰艟胴銅童動同道何弩怒退呶度堵奴解留融録取駑孥努戸止土ど瓰竕凸竍籵瓧禰泥捏溺寺鈿佃甸黏沺畋淀棯澱臀傳殿電照でヅ鶴辛強妻綱勤伝包筒做造作尽机月冢塚遣疲使突吊付漬津詰図積釣連づヂ中近力地痔持ぢ種棚倒濃彩逹畳諾゛濁玉默球魂騙谷館舘点岳嶽竹高凧蛸怛妲獺奪脱廼迺弟岱臺餒梯戴平内醍橙][題>≧第台代大鱈頼便誰樽懶怠灘斷椴黙旦煖彈暖談段断檀団團壇弾男抱舵橢炊佗堕荼拿打娜蛇楕陏駄唾拏雫沱立儺柁鴕溜妥朶陀墮駝出垂惰懦建兌澑田騨だd直◎.丶、,‥\.・…$“”↓†‡―┤達℃°独ド÷◇◆ダジДデΔδд∂d]\|ッ\_s*\%(ト\_s*゙\|テ\_s*゙\|ツ\_s*゙\|チ\_s*゙\|タ\_s*゙\)\|ッ\_s*[ドデヅヂダ]\|っ\_s*[どでづぢだ]\|ト\_s*゙\|都\_s*々\_s*逸\|褞\_s*袍\|S\_s*a\_s*u\_s*r\_s*u\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|C\_s*\%(u\|o\_s*p\_s*p\_s*e\_s*r\)\|満\_s*天\_s*星\|豆\_s*腐\|如\_s*何\|テ\_s*゙\|刑\_s*事\|粘\_s*葉\_s*装\|手\_s*間\|木\_s*偶\|丁\_s*[稚抹]\|蝸\_s*牛\|ツ\_s*゙\|頭\_s*[腦痛]\|チ\_s*゙\|調\_s*子\|茶\_s*碗\|知\_s*恵\|忸\_s*怩\|タ\_s*゙\|忠\_s*幸\|壁\_s*蝨\|伊\_s*達\|山\_s*車\|韃\_s*靼\|提\_s*婆\_s*達\_s*多\|太\_s*\%([刀宰鼓]\|平\_s*広\|上\_s*天\_s*皇\|政\_s*\%(官\|大\_s*臣\)\)\|乃\_s*[公毅]\|体\_s*操\|葮\_s*竹\|演\_s*\%(し\_s*物\|繹\_s*デ\_s*ー\_s*タ\_s*ベ\_s*ー\_s*ス\)\|コ\_s*ロ\_s*ン\_s*ビ\_s*ア\|ズ\_s*\%(ロ\_s*ー\_s*ス\|ッ\_s*ク\)\|イ\_s*ル\_s*カ\|医\_s*者\|博\_s*士\|文\_s*書\|行\_s*列\_s*式\|発\_s*見\_s*す\_s*る\|ハ\_s*ー\_s*グ\|拒\_s*否\_s*さ\_s*れ\_s*た\|破\_s*壊\_s*\%(者\|す\_s*る\)\|消\_s*滅\_s*子\|記\_s*述\_s*子\|D\_s*\%(論\|タ\_s*イ\_s*プ\|ド\_s*ラ\_s*イ\_s*ブ\|カ\_s*ッ\_s*プ\|C\_s*ブ\_s*ラ\_s*ン\_s*ド\|y\_s*l\_s*a\_s*n\|ラ\_s*ン\_s*ク\|a\_s*i\_s*s\_s*y\|e\_s*m\_s*a\_s*c\_s*s\)\|十\_s*進\_s*数\|ゼ\_s*ッ\_s*ケ\_s*ン\|復\_s*号\_s*化\|省\_s*略\|金\_s*剛\_s*石\|辞\_s*書\|D\_s*\%(b\|タ\_s*イ\_s*プ\|T\_s*\%(E\|P\_s*ソ\_s*フ\_s*ト\|M\_s*ソ\_s*フ\_s*ト\)\|M\_s*A\|ド\_s*ラ\_s*イ\_s*ブ\|カ\_s*ッ\_s*プ\|C\_s*\%(カ\_s*ー\_s*ド\|ブ\_s*ラ\_s*ン\_s*ド\)\|u\_s*b\_s*n\_s*i\_s*u\_s*m\|B\_s*\%(M\_s*S\|サ\_s*ー\_s*バ\)\|H\_s*C\_s*P\_s*\%(サ\_s*ー\_s*バ\|ク\_s*ラ\_s*イ\_s*ア\_s*ン\_s*ト\)\|y\_s*\%(s\_s*p\_s*r\_s*o\_s*s\_s*i\_s*u\_s*m\|l\_s*a\_s*n\)\|r\_s* \_s*P\_s*e\_s*p\_s*p\_s*e\_s*r\|ラ\_s*ン\_s*ク\|V\_s*D\_s*\%(ボ\_s*ッ\_s*ク\_s*ス\|シ\_s*ョ\_s*ッ\_s*プ\|ケ\_s*ー\_s*ス\|デ\_s*ッ\_s*キ\|ド\_s*ラ\_s*イ\_s*ブ\|オ\_s*ー\_s*デ\_s*ィ\_s*オ\|プ\_s*レ\_s*\%(ー\_s*ヤ\_s*ー\|イ\_s*ヤ\_s*ー\)\|ラ\_s*ッ\_s*ク\|レ\_s*コ\_s*ー\_s*ダ\_s*ー\|マ\_s*ル\_s*チ\|ビ\_s*デ\_s*オ\)\|O\_s*S\|o\_s*\%(c\_s*u\_s*m\_s*e\_s*n\_s*t\_s* \_s*\%(T\_s*y\_s*p\_s*e\_s* \_s*D\_s*e\_s*f\_s*i\_s*n\_s*i\_s*t\_s*i\_s*o\_s*n\|O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*o\_s*d\_s*e\_s*l\)\|C\_s*o\_s*M\_s*o\)\|e\_s*\%(g\_s*e\_s*n\_s*e\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|l\_s*a\_s*w\_s*a\_s*r\_s*e\)\|E\_s*\%(C\|L\_s*キ\_s*ー\)\|I\_s*\%(P\_s*ス\_s*イ\_s*ッ\_s*チ\|S\_s*K\)\|i\_s*\%(r\_s*e\_s*c\_s*t\_s* \_s*M\_s*e\_s*m\_s*o\_s*r\_s*y\_s* \_s*A\_s*c\_s*c\_s*e\_s*s\_s*s\|s\_s*t\_s*r\_s*i\_s*c\_s*t\_s* \_s*o\_s*f\_s* \_s*C\_s*o\_s*l\_s*u\_s*m\_s*b\_s*i\_s*a\|g\_s*i\_s*t\_s*a\_s*l\)\)\)', + \ 'e' : '\%([エ瘧腮偉鰓衿撰襟掾圜鹽垣檐媛爰捐¥覃黶篶湲蜒讌簷櫞悁渊轅渕閼魘薗艷鳶鴛焉嫣宛閻衍臙閹槐⌒援筵淹厭寃淵掩烟嚥圓沿宴蜿奄袁煙艶焔炎怨鉛園苑偃冤延婉遠堰燕演塩円縁刔刳抉猿狗描択鰕箙蛯蝦狄貊胡戎夷乢靨鉞噎戉咽粤桟悦閲謁奕伯懌亦蜴掖繹越役驛疫易益腋駅液殪纓裔曵頴洩瓔潁贏珱衡娃翳營瑩咏楹塋蠑瀛睿泳縊榮瑛暎曳盈郢影詠穎嬰鋭叡映営栄永衞衛得絵荏懷畫枝江繪衣猥慧惠獲回依會重柄杖餌榎画恵笑会囘選え━─┳┬┯┰┸┷┻┴Фф=⇔≡∈∋РрМмeН→英∃式!ΗηсСлЛΕЭεэエe]\|A\_s*\%([面判型級]\|V\_s*\%(機\_s*器\|女\_s*優\)\|B\_s*\%(型\|C\_s*順\)\)\|A\_s*\%([面判型級]\|V\_s*\%(機\_s*器\|女\_s*優\)\|B\_s*型\)\|M\_s*サ\_s*イ\_s*ズ\|M\_s*サ\_s*イ\_s*ズ\|豪\_s*物\|L\_s*\%(サ\_s*イ\_s*ズ\|L\_s*サ\_s*イ\_s*ズ\)\|L\_s*\%(サ\_s*イ\_s*ズ\|L\_s*\%(サ\_s*イ\_s*ズ\|教\_s*室\)\)\|羨\_s*道\|豌\_s*豆\|C\_s*\%(l\|h\_s*l\_s*o\_s*r\_s*i\_s*n\_s*e\)\|似\_s*\%(非\|而\_s*非\)\|桧\_s*原\_s*湖\|烏\_s*帽\_s*子\|吉\_s*方\|胞\_s*衣\|淮\_s*南\_s*子\|埃\_s*及\|干\_s*支\|岐\_s*路\|支\_s*繞\|壊\_s*[疽死]\|葡\_s*萄\|蛭\_s*子\|愛\_s*\%([理莉媛]\|知\_s*川\)\|N\_s*極\| \_s*n\_s* \_s*角\_s*形\|N\_s*\%([個極響]\|次\_s*元\|H\_s*K\_s*ホ\_s*ー\_s*ル\)\|斉\_s*魚\|兄\_s*鼓\|ヱ\_s*ス\_s*ビ\_s*ー\_s*食\_s*品\|S\_s*\%([波字席極]\|サ\_s*イ\_s*ズ\|N\_s*比\|F\_s*小\_s*説\)\|S\_s*\%([式極]\|サ\_s*イ\_s*ズ\|N\_s*比\|F\_s*小\_s*説\)\|穢\_s*[多土]\|X\_s*\%([軸脚]\|O\_s*醤\|染\_s*色\_s*体\)\|X\_s*\%([軸脚線]\|染\_s*色\_s*体\)\|海\_s*\%(老\|鷂\_s*魚\)\|帝\_s*都\_s*高\_s*速\_s*度\_s*交\_s*通\_s*営\_s*団\|ワ\_s*ー\_s*ク\_s*ス\_s*テ\_s*ー\_s*シ\_s*ョ\_s*ン\|欧\_s*\%(州\|羅\_s*巴\)\|歐\_s*\%(州\|羅\_s*巴\)\|ヨ\_s*ー\_s*ロ\_s*\%(ピ\_s*ア\_s*ン\|ッ\_s*パ\)\|ユ\_s*\%(ア\_s*ン\|ウ\_s*ロ\_s*ピ\_s*ウ\_s*ム\|リ\_s*イ\_s*カ\|ー\_s*\%(ロ\|ノ\_s*ス\|ニ\_s*ス\|ジ\_s*\%(ン\|ー\_s*ン\)\|ド\_s*ラ\|レ\_s*カ\|ラ\_s*\%(ス\|シ\_s*ア\)\|フ\_s*\%(ラ\_s*テ\_s*ス\|ォ\_s*\%(リ\_s*ア\|ニ\_s*ア\_s*ム\)\)\|ク\_s*リ\_s*ッ\_s*ド\|カ\_s*リ\)\)\|編\_s*集\|強\_s*調\|電\_s*子\_s*メ\_s*\%(イ\_s*ル\|ー\_s*ル\)\|発\_s*展\|評\_s*価\_s*す\_s*る\|符\_s*号\_s*化\|百\_s*科\_s*事\_s*典\|カ\_s*プ\_s*セ\_s*ル\_s*化\|オ\_s*\%(ー\|イ\_s*\%(ラ\_s*ー\|ゲ\_s*ン\)\)\|実\_s*行\|拡\_s*張\|例\_s*外\|感\_s*嘆\_s*符\|E\_s*\%(P\_s*O\|ド\_s*ラ\_s*イ\_s*ブ\|D\_s*ベ\_s*ー\_s*タ\|m\_s*a\_s*c\_s*s\|カ\_s*ッ\_s*プ\|a\_s*s\_s*t\|x\_s*e\_s*r\_s*c\_s*i\_s*s\_s*e\|タ\_s*イ\_s*プ\)\|ア\_s*\%([ンイ]\|ニ\_s*ド\|ー\_s*\%([マスル]\|ウ\_s*ィ\_s*ン\|ラ\_s*ン\|ニ\_s*ー\|ネ\_s*ス\_s*ト\|ミ\_s*ン\|シ\_s*ー\|リ\_s*ー\)\)\|設\_s*立\|E\_s*\%(r\|O\_s*F\|u\_s*\%(p\_s*o\_s*m\_s*a\_s*t\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|r\_s*o\_s*p\_s*i\_s*u\_s*m\)\|U\_s*C\_s*コ\_s*ー\_s*ド\|P\_s*レ\_s*コ\_s*ー\_s*ド\|ド\_s*ラ\_s*イ\_s*ブ\|d\_s*i\_s*t\_s*i\_s*n\_s*g\_s* \_s*M\_s*A\_s*C\_s*r\_s*o\_s*S\|メ\_s*ー\_s*ル\|-\_s*m\_s*a\_s*i\_s*l\|カ\_s*ッ\_s*プ\|コ\_s*マ\_s*ー\_s*ス\|N\_s*T\_s*E\_s*R\_s*キ\_s*ー\|タ\_s*イ\_s*プ\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\|S\_s*\%(P\|C\_s*キ\_s*ー\)\|l\_s*k\|m\_s*a\_s*c\_s*s\)\|イ\_s*\%([ブヴアラー]\|ジ\_s*ェ\_s*ク\_s*ト\|フ\_s*ェ\_s*ク\_s*[トタ]\|コ\_s*\%(ー\_s*ル\|ラ\_s*イ\_s*[ズザ]\)\|プ\_s*シ\_s*ロ\_s*ン\|ミ\_s*ュ\_s*レ\_s*\%(ー\_s*[トタ]\|イ\_s*タ\)\|ベ\_s*ン\_s*\%(ト\|タ\_s*ー\)\|ノ\_s*ッ\_s*ク\|ネ\_s*ー\_s*ブ\_s*ル\|ギ\_s*リ\_s*ス\|ン\_s*グ\_s*\%(ラ\_s*ン\_s*ド\|リ\_s*ッ\_s*シ\_s*ュ\)\|ッ\_s*チ\|ヤ\_s*\%(ー\|リ\_s*ン\_s*グ\|フ\_s*ォ\_s*ン\|ホ\_s*ン\)\|グ\_s*ジ\_s*\%(ッ\_s*ト\|ス\_s*ト\)\|ク\_s*\%(ス\|ア\_s*リ\_s*テ\_s*ィ\)\|ス\_s*フ\_s*ァ\_s*ハ\_s*ン\|リ\_s*[ヤア]\|レ\_s*\%(ー\_s*\%(ス\|ザ\_s*ー\|サ\_s*ー\)\|イ\_s*\%(ン\|ザ\_s*ー\|サ\_s*ー\)\|ブ\_s*ン\)\)\|ウ\_s*\%(ー\|ジ\_s*ェ\_s*ー\_s*ヌ\)\)', + \ 'f' : '\%([梺麓冬汾枌濆′吩賁刎氛雰糞褌忿墳吻紛焚扮分粉舊旧顫揮故震篩奮隹古衾襖贅燻筆鰒総惣總絃房閼鬱塞鞴章郁史艦簡札耽鰾吭笛文罧節苳蕗淦舩艙舷舟船肥太懷懐≦≠≫<>≧≪渊淵渕縁葢盖再弍蓋双藤潭蒸鯊鱶楓殕瘋封諷黻怫祓彿髴拂憤恚慍二払沸拒防蔔輹愎蝠茯箙腓⊃⊇膨脹嚢梟袋含⊂⊆袱覆輻腹幅復馥服副複福誣孚普俯更膚腐坿狂履不増拊鯆布怖赴桴巫傅婦付訃賻振負蜉罘老附吹生経觸夫俘父臥践咐敷踏斧溥阜葺深仆譜符麩匐腑榑芙賦殖冨触孵麸柎府舗噴鋪降蹈風觝埠拭鮒郛伏俛經歩苻斑畉扶趺芬呎フ飜翻ふf鉄♀∀¶富⌒金佛仏偽誤♭弗浮FФΦφфフf]\|ッ\_s*フ\|ッ\_s*フ\|っ\_s*ふ\|鞦\_s*韆\|睾\_s*丸\|陰\_s*嚢\|乱\_s*吹\|相\_s*応\|E\_s*u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\|回\_s*回\_s*教\|書\_s*司\|図\_s*書\_s*寮\|海\_s*蘿\|補\_s*\%(任\|陀\_s*[洛落]\)\|雲\_s*脂\|頭\_s*垢\|鳧\_s*鐘\|菜\_s*蕗\|款\_s*冬\|蒲\_s*団\|M\_s*y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|釜\_s*[中山]\|雙\_s*葉\|B\_s*u\_s*d\_s*d\_s*l\_s*e\_s*j\_s*a\_s*c\_s*e\_s*a\_s*e\|渓\_s*井\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|2\_s*[人つ日]\|宿\_s*酔\|2\_s*\%([人つ日]\|通\_s*り\)\|□\_s*□\_s*□\|△\_s*△\_s*△\|×\_s*×\_s*×\|○\_s*○\_s*○\|帛\_s*紗\|河\_s*豚\|比\_s*律\_s*賓\|I\_s*r\_s*o\_s*n\|極\_s*東\_s*放\_s*送\|論\_s*理\_s*式\|形\_s*式\|ホ\_s*\%(ワ\_s*イ\_s*エ\|イ\_s*ル\|ル\_s*\%(マ\_s*\%(ン\_s*ト\|リ\_s*ン\)\|ム\_s*ア\_s*\%(ミ\_s*ド\|ル\_s*デ\_s*ヒ\_s*ド\)\)\)\|一\_s*杯\|関\_s*数\|機\_s*能\|汎\_s*関\_s*数\|修\_s*正\|ヒ\_s*\%(レ\|ュ\_s*ー\_s*[ズム]\)\|1\_s*\%(/\_s*f\_s*ゆ\_s*ら\_s*ぎ\|s\_s*t\)\|第\_s*1\_s*要\_s*素\|失\_s*敗\|ハ\_s*\%(エ\|ン\_s*ブ\_s*ル\|ロ\_s*ン\)\|柔\_s*軟\_s*な\|F\_s*\%(1\|カ\_s*ッ\_s*プ\|タ\_s*イ\_s*プ\|a\_s*\%(x\|m\_s*e\)\|l\_s*a\_s*v\_s*o\_s*r\)\|周\_s*波\_s*数\|エ\_s*フ\)', + \ 'g' : '\%([頃殺米諢魂權艮勤権鮴好蓙応駒若亊事琴毎如鏝埖込塵氷聲肥声腰拵心恋戀国石獄濠盒噛嗷敖軣哈壕熬刧遨拷囂轟毫傲鼇郷劫≡号豪剛梧后冴後吾寤宕珸茣児伍誤5極醐碁檎牾蜈唔篌庫娯悟忤呉期齬5互超五晤越子炬護兒瑚午沍ご〓郤鬩戟屐隙檄闃鷁撃激劇皃黥貎霓麑倪囈猊迎鯨芸藝齧囓蘖呟愿監芫痃广彦軒舷眩源儼衒絃弦験言諺現限幻玄減原蹴偈毛睨觧解実下拐夏げ靴腐種草口薬糞癖茱胡萸串嵎藕遇宮寓隅偶黒栗倉鞍蔵位昏麕羣郡群軍苦周包車狂食颶壷暮愚弘虞倶麌禺具惧壺組狗ぐ衣君嫌裂際牛崟憖斤垠岑吟銀圄禦圉馭魚嶷閠玉漁繞堯尭御曉嶢澆翹痙蟯驍僥仰業暁凝行謔瘧虐逆気義偽技切妓巍犠誼宜伎祁疑萓礒羲僞城蟻斬決擬沂議儀嶬艤着木曦犧欺戲魏祇戯ぎ川巛乾革皮側通殻辛絡柄烏鴉頷嚴阮鳫厳貫嵒偐巖岸厂⊃贋龕強翫岩鴈丸雁玩癌元願眼巌含頑上髮紙神髪鐘金係歸皈肯帰返潟方固語刀難型形鰹歹垳顔顏鎌窯蟇釜蒲蟹傘笠重號垣樫頭月合諤樂鍔壑鄂斈學齶萼愕嶽咢鰐額岳顎楽学既礙涯剴乂垓葢劾盖愾磑睚漑崕亥崖啀艾駭皚該咳階孩芥碍害鎧街凱慨概蓋骸外代峩狩我ヶ鵞駕訝変刈掛牙娥替畫駆ケ俄哦借呀果臥雅買蛾訛換河峨莪書芽貸衙画ヵ伽賀勝餓鵝が≫>g瓦≧ガゴχΕΗΣυΙΛαΨζρΒΝιΦφτλΠονψωΚΔΡδΤβΘΟπεΧΑΞσθηκΖΜξμΥΩギグゲгΓγГg]\|ッ\_s*\%(コ\_s*゙\|ケ\_s*゙\|ク\_s*゙\|キ\_s*゙\|カ\_s*゙\)\|ッ\_s*[ゴゲグギガ]\|っ\_s*[ごげぐぎが]\|コ\_s*゙\|小\_s*屋\|蒙\_s*御\_s*免\|巨\_s*頭\_s*鯨\|欣\_s*求\|独\_s*楽\|P\_s*e\_s*r\_s*s\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|瞽\_s*女\|歩\_s*行\_s*虫\|向\_s*拝\|皐\_s*月\|穀\_s*潰\|寄\_s*居\_s*虫\|降\_s*魔\|格\_s*\%([間縁]\|天\_s*井\)\|恒\_s*河\_s*沙\|江\_s*\%([津湖商州]\|談\_s*抄\)\|豆\_s*[油汁]\|ケ\_s*゙\|蚰\_s*蜒\|景\_s*色\|化\_s*粧\|鴃\_s*舌\|稽\_s*古\|懸\_s*魚\|還\_s*[向俗]\|拳\_s*[万固骨]\|喧\_s*嘩\|顕\_s*界\|ク\_s*゙\|救\_s*世\_s*菩\_s*薩\|工\_s*合\|供\_s*[奉祭香進]\|紅\_s*蓮\|キ\_s*゙\|毬\_s*杖\|岐\_s*\%([南阜]\|セ\_s*ン\)\|棋\_s*将\_s*谷\|求\_s*\%([法道肥]\|不\_s*得\_s*苦\|聞\_s*持\_s*法\)\|A\_s*g\|S\_s*\%(c\_s*r\_s*o\_s*p\_s*h\_s*u\_s*l\_s*a\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*m\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|i\_s*l\_s*v\_s*e\_s*r\)\|希\_s*臘\|杏\_s*葉\|餃\_s*子\|刑\_s*部\|カ\_s*゙\|搦\_s*み\|鑑\_s*真\|仮\_s*名\|蝦\_s*[蟆蟇]\|T\_s*y\_s*p\_s*a\_s*l\_s*e\_s*s\|鉤\_s*状\_s*部\|菓\_s*子\|甲\_s*斐\|会\_s*社\|ヌ\_s*ー\|G\_s*\%(O\_s*R\_s*O\|B\_s*y\_s*t\_s*e\|メ\_s*ン\|カ\_s*ッ\_s*プ\|タ\_s*イ\_s*プ\|ス\_s*ポ\_s*ッ\_s*ト\|パ\_s*ン\|n\_s*u\_s*s\)\|ニ\_s*ュ\_s*ー\_s*ズ\|ノ\_s*ー\_s*ム\|総\_s*司\_s*令\_s*部\|連\_s*合\_s*国\_s*軍\_s*総\_s*司\_s*令\_s*部\|ヒ\_s*ル\|ク\_s*ッ\_s*パ\|硝\_s*子\|ハ\_s*ボ\_s*ロ\_s*ー\_s*ネ\|瞿\_s*曇\|エ\_s*ー\_s*テ\_s*ボ\_s*リ\|ヨ\_s*ー\_s*テ\_s*ボ\_s*リ\|イ\_s*ェ\_s*\%(ー\_s*テ\_s*ボ\_s*リ\|テ\_s*ボ\_s*リ\)\|得\_s*る\|G\_s*\%([dae]\|o\_s*m\_s*o\_s*r\_s*t\_s*e\_s*g\_s*a\_s*c\_s*e\_s*a\_s*e\|M\_s*\%(T\|D\_s*(\_s*G\_s*e\_s*r\_s*m\_s*a\_s*n\_s* \_s*N\_s*a\_s*t\_s*i\_s*o\_s*n\_s*a\_s*l\_s* \_s*R\_s*e\_s*s\_s*e\_s*a\_s*r\_s*c\_s*h\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\_s* \_s*f\_s*o\_s*r\_s* \_s*C\_s*o\_s*m\_s*p\_s*u\_s*t\_s*e\_s*r\_s* \_s*S\_s*c\_s*i\_s*e\_s*n\_s*c\_s*e\_s*)\)\|メ\_s*ン\|C\_s*L\|c\_s*c\|カ\_s*ッ\_s*プ\|タ\_s*イ\_s*プ\|ス\_s*ポ\_s*ッ\_s*ト\|パ\_s*ン\|P\_s*L\|n\_s*u\_s*s\|I\_s*\%(N\_s*A\_s*(\_s*t\_s*h\_s*e\_s* \_s*G\_s*e\_s*n\_s*e\_s*r\_s*i\_s*c\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*t\_s*i\_s*v\_s*e\_s* \_s*A\_s*p\_s*p\_s*l\_s*i\_s*c\_s*a\_s*t\_s*i\_s*o\_s*n\_s*)\|F\_s*\%(フ\_s*ァ\_s*イ\_s*ル\|ア\_s*ニ\_s*メ\)\)\|U\_s*I\|N\_s*U\|O\_s*サ\_s*イ\_s*ン\|E\_s*T\_s*メ\_s*ソ\_s*ッ\_s*ド\)\|ヘ\_s*\%(ラ\_s*ル\_s*ド\|ル\_s*マ\_s*ン\)\|ド\_s*イ\_s*ツ\|成\_s*吉\_s*思\_s*汗\|ゼ\_s*\%(ラ\_s*\%(チ\_s*ン\|ニ\_s*ウ\_s*ム\)\|ム\_s*ク\_s*リ\_s*ッ\_s*プ\|ノ\_s*ア\|ン\_s*ト\_s*ル\_s*マ\_s*ン\|ネ\_s*\%(コ\_s*ン\|ラ\_s*\%(ル\|リ\_s*ス\_s*ト\)\)\)\|大\_s*\%(蚊\|学\_s*院\_s*生\)\|ジ\_s*\%([ムルジグノナオンー]\|プ\_s*シ\_s*ー\|ア\_s*ン\|イ\_s*ド\|ッ\_s*ド\|タ\_s*ン\|ゼ\_s*ル\|リ\_s*ア\_s*ン\|レ\_s*ッ\_s*ト\|ゴ\_s*ロ\|ラ\_s*\%(フ\|ル\_s*\%(ド\|デ\_s*ィ\_s*ー\_s*ノ\)\)\|ロ\_s*\%(ー\|ン\_s*ド\)\|バ\_s*ン\_s*シ\_s*ー\|ブ\_s*\%(リ\|ラ\_s*ル\_s*タ\_s*ル\)\|ベ\_s*\%(ル\_s*ナ\_s*ウ\|レ\_s*リ\_s*ン\)\|ネ\_s*ッ\_s*ト\|ョ\_s*\%(ッ\_s*ト\|ヴ\_s*ァ\_s*ン\_s*[ニナ]\|バ\_s*ン\_s*[ニナ]\|コ\_s*\%(ー\_s*ソ\|ン\_s*ダ\)\|ル\_s*\%(ジ\|ダ\_s*ー\_s*ノ\)\|ー\_s*\%(ジ\|ゼ\_s*ッ\_s*ト\)\)\|ャ\_s*\%(ン\|イ\_s*\%(ロ\|ル\_s*ズ\|ア\_s*ン\_s*[ツト]\)\|コ\_s*\%(モ\|メ\_s*ッ\_s*テ\_s*ィ\)\|ー\_s*マ\_s*ン\)\|ニ\_s*ー\|ュ\_s*\%([レネ]\|ゼ\_s*ッ\_s*ペ\|リ\_s*\%(ア\|ー\_s*ニ\|エ\_s*ッ\_s*タ\)\|ヌ\_s*\%(ヴ\_s*ィ\_s*エ\_s*ー\_s*ヴ\|ビ\_s*エ\_s*ー\_s*ブ\)\)\|ェ\_s*\%([リルフムマネ]\|ス\_s*チ\_s*ャ\_s*ー\|ロ\_s*ニ\_s*モ\|ラ\_s*\%(ー\_s*[トルド]\|ル\_s*\%(ド\|デ\_s*ィ\_s*ン\|ダ\_s*イ\_s*ン\)\)\|ミ\_s*ニ\|ニ\_s*ー\|ノ\_s*\%([アバ]\|ヴ\_s*ァ\|ワ\_s*ー\_s*ズ\|サ\_s*イ\_s*ド\)\|ン\_s*\%(マ\|ト\_s*\%(ル\|リ\_s*[ィー]\)\|ダ\_s*ー\)\)\)\)', + \ 'h' : '\%([ホ洞袰亡滅幌濠壕畚笨略艢檣炎焔仄朖朗塊程施滸殆幾缶熱解屠榾螢蛍骨細本※*糒恣縦擅星戟戈桙綻祠誇埃矛鉾堀頬褓鴇枋峯磅鞄峰垉篷勹皰朴抔怦棒泙棚堋呆豐麭膀舫弸蔀袍苞葬琺寳炮鵬寶繃鋒魴髣逢朋烹鳳彗箒俸焙蓬烽幇抱崩訪泡澎彷縫捧萌萠彭包胞倣邦飽庖疱奉豊硼報砲宝攴攵瀑蹼樮北哺欲譽餔保抛浦誉掘脯賞黼恍堡輔穗襃葆彫穂畝吼舖耄葡褒惚咆埔哮捕逋ほヘ謙遜篦廰廳貶胼諞篇駢褊蝙翩變∂遍返騙編扁変暼丿諛諂隔凹臍巳蛇蒂蔕瓸竡粨癖躄甓闢璧劈碧壁竝餅娉塀病閇聘坪嬖幤箆蔽并陛屏炳斃瓶幣弊併敝閉並屁折邉舳辺歴圧戸減邊へフ梺麓冬♭汾枌濆′吩賁氛雰糞褌忿墳吻紛焚扮分粉舊旧顫揮故震篩奮隹古衾襖贅燻鰒陰総惣總絃房閼鬱塞章郁艦簡補札耽鰾吭笛芬呎文罧節苳蕗淦舩艙舷舟船蒲懷懐≦≫>≧≪渊淵渕縁葢盖弍蓋双B藤潭蒸鱶楓殕瘋封諷黻怫彿髴佛憤恚慍仏F弗沸Φφ拒防蔔輹愎蝠茯箙⊃⊇嚢梟袋含⊂⊆袱覆輻復馥副複福誣孚普俯更腐坿狂不増拊鯆怖赴桴巫傅婦付訃賻振負蜉罘附吹経觸夫俘父臥践咐敷踏斧溥阜葺深仆譜符麩匐榑芙賦殖冨触孵麸柎府舗噴鋪降蹈風觝埠拭鮒郛伏俛經歩富苻畉扶趺ふヒ鶸禀蘋彬斌嬪繽殯賓擯牝貧頻瀕稟品葫怯晝飜蒜蛭昼綬胙紐鰭∝片衡鮃閃鵯辟百媛姫尋擴仭太仞展宥絋拡拓拾祐恕紘煕泰熙寛洋弘宏啓裕浩廣広冰雹俵飃凭冫髟彪驫飆馮殍飄豹漂驃慓剽嫖兵票憑評標平表燧老拈捫撚捻歪籤籖柊魃旱秀跪膝蜩羆佗攣−低隙閑暇雛髯鬚髭¬蹄潛濳潜顰密窃鬻提瓢蠡瓠匏央恒壽廂尚寿久蟆率痙蟇丙丁孤史女獨独稘斎斉均倫準等≠單偏単他仁瞳人11柆蔆拉杓柄犇◇◆菱醢醤曾蘖彦酷漬浸鶲額聖肱肘熈芒光膕控皹皸響罅僻鰉逼疋蹕畢匹篳棺柩弼櫃謐坤未羊筆必養襞饑「<【(←『左臂轡曳灯緋朏砒火日蜚妣費狒匕泌杼庇悲樋退脾挽痺卑贔紕牽避引菲檜被碑匪裨斐秘豼霏蓖丕批妃髀干昜彼秕氷鄙飛比否碾疲梭披桧魅惹俾鞴冷譬貔乾肥罷痞索扉暃毘轢皮陳鞁祕ひハ布鱧釖鉤蝟梁鍼磔針禳肚腑腸孕原拂祓払遼請温玄腹陽遙悠東遥治春頓鮠捷鶻駿疾囃林隼鈑膰磐樊潘泛畔蟠釆拌笵胖絆氾坂范凡燔楾洪瘢翻板攀゜大伴煩槃袢斑判範藩繙蕃版搬叛班阪般販犯汎帆頒反侍鯊櫨祝?硲間劇激勵烈励速蝿蠅省飯勢彈外弭筈辱逸育毓齦浮阻難掵憚幅巾柞母翅圃旛旙将側旌幟傍働鰰機叩疥畠幡籏畑旗斜鴿再鳩開秦跣膚肌裸弾薑椒壹甫馨壱弌哉一創元始鋼芳夾剪鋏螯挾挟脛萩餞贐離塙英蕚萼衄衂縹譚咄放噺話洟甚鼻華花赱迸奔枦觜艀婢梯燥箸柱走橋匣凾箪筐□繁方運匚筥箱函陌栢魄膊柏亳珀狛佰粕璞蘗岶愽擘箔舶泊搏迫帛拍圖諮測企秤謀量計図儚捗袴伯博墓髮秡癶釟溌肇廿二初椀蓮8♪鉢蜂發髪服半法醗薄白八発霈盃睥擺湃孛裴琲埴碚牌吠拜坏珮旆入沛榛杯悖―廢腓誹徘稗癈肺俳憊輩背鷂胚廃排拝敗灰配蛤濱浜吐食霽恥菠帚杷垪跛耻巴笆履脹葉爆矧帶這撥破嵌霸捌早把刎馳填生簸跳派禿碆羽果覇映晴陂端剥腫匍着穿葩爬歯膨坡佩慙芭刄菷怕榮齒刃播愧暎叭栄玻掃張貼刷羞頗琶はh━─┘┛┸┷┻┴┓┐┳┬┯┰┨┫┤┥┼╋╂┿波‐フ★☆非ヒホヘハh]\|ッ\_s*[ホヘフヒハ]\|ッ\_s*[ホヘフヒハ]\|っ\_s*[ほへふひは]\|寄\_s*生\|珠\_s*鶏\|混\_s*一\_s*色\|紅\_s*[幇中]\|T\_s*r\_s*i\_s*u\_s*r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|微\_s*[酔笑]\|子\_s*規\|時\_s*鳥\|蜀\_s*魂\|杜\_s*[宇鵑]\|上\_s*枝\|鬼\_s*灯\|酸\_s*漿\|叢\_s*祠\|和\_s*了\|鮑\_s*魚\|謗\_s*法\|黒\_s*子\|部\_s*屋\|竹\_s*\%(畚\|麦\_s*魚\)\|綜\_s*麻\|巻\_s*子\|下\_s*手\|糸\_s*瓜\|霹\_s*靂\|c\_s*l\_s*a\_s*u\_s*s\_s*t\_s*r\_s*o\_s*p\_s*h\_s*o\_s*b\_s*i\_s*a\|鞦\_s*韆\|睾\_s*丸\|乱\_s*吹\|相\_s*応\|E\_s*\%(r\_s*i\_s*o\_s*c\_s*a\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\|u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\)\|回\_s*\%(鍋\_s*肉\|回\_s*教\)\|書\_s*司\|頭\_s*垢\|鳧\_s*鐘\|菜\_s*蕗\|款\_s*冬\|f\_s*\%(o\_s*r\_s*t\_s*e\|e\_s*m\_s*t\_s*o\)\|釜\_s*[中山]\|雙\_s*葉\|渓\_s*井\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|宿\_s*酔\|△\_s*△\_s*△\|×\_s*×\_s*×\|○\_s*○\_s*○\|河\_s*\%(豚\|底\_s*撈\_s*魚\)\|神\_s*[庫籬]\|肩\_s*巾\|領\_s*巾\|素\_s*見\|曹\_s*白\_s*魚\|枚\_s*[田方]\|敬\_s*昌\|幸\_s*展\|容\_s*靖\|晃\_s*道\|欧\_s*子\|宙\_s*子\|祥\_s*加\|終\_s*日\|翡\_s*翠\|曽\_s*祖\_s*父\|豪\_s*将\|偉\_s*紀\|周\_s*[行男]\|茅\_s*蜩\|向\_s*日\_s*葵\|七\_s*宗\|桶\_s*坂\|永\_s*和\|蟾\_s*蜍\|抽\_s*\%([斗出]\|き\_s*出\_s*し\)\|告\_s*天\_s*子\|雲\_s*[脂雀]\|為\_s*人\|緊\_s*[と々]\|鎮\_s*火\_s*\%(祭\|の\_s*祭\)\|A\_s*\%(s\|r\_s*s\_s*e\_s*n\_s*i\_s*c\|n\_s*g\_s*i\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\|粃\_s*糠\_s*疹\|只\_s*管\|直\_s*[向走垂隠]\|常\_s*陸\|鹿\_s*尾\_s*菜\|撲\_s*り\_s*倒\|同\_s*胞\|赦\_s*い\|青\_s*春\|哈\_s*爾\_s*浜\|美\_s*佳\|流\_s*行\|勇\_s*[樹人]\|韓\_s*流\|漢\_s*堡\|汗\_s*国\|盤\_s*陀\|R\_s*S\_s*I\|蔓\_s*延\|蝦\_s*虎\_s*魚\|沙\_s*魚\|馬\_s*銜\|狭\_s*間\|南\_s*風\|延\_s*\%(縄\|い\_s*て\)\|義\_s*母\|旅\_s*籠\|N\_s*e\_s*l\_s*u\_s*m\_s*b\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|黄\_s*[酒櫨]\|土\_s*[方生師]\|嘔\_s*[吐気]\|支\_s*倉\|長\_s*谷\|接\_s*ぎ\_s*合\|纏\_s*頭\|煙\_s*火\|麻\_s*疹\|階\_s*[上子]\|嘴\_s*\%(細\_s*鴉\|太\_s*鴉\)\|学\_s*胤\|2\_s*\%([人つ日]\|通\_s*り\|0\_s*日\)\|2\_s*\%([人つ日]\|0\_s*[歳日]\)\|淡\_s*竹\|8\_s*月\|客\_s*家\|P\_s*\%(t\|o\_s*t\_s*a\_s*m\_s*o\_s*g\_s*e\_s*t\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*t\_s*i\_s*n\_s*u\_s*m\)\|海\_s*\%([鞘永蘿星牙]\|拉\_s*爾\|底\_s*撈\_s*月\)\|M\_s*\%(y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*c\_s*u\_s*r\_s*y\)\|色\_s*調\|呼\_s*和\_s*浩\_s*特\|ウ\_s*ー\_s*ゴ\|ユ\_s*\%(ー\|ペ\_s*ー\_s*ル\|ベ\_s*ー\_s*ル\|イ\_s*ス\_s*マ\_s*ン\_s*ス\|ゴ\_s*ー\|グ\_s*ノ\_s*ー\|マ\_s*ニ\_s*\%(テ\|ス\_s*[トム]\)\)\|現\_s*代\|十\_s*六\_s*進\_s*数\|高\_s*さ\|香\_s*港\|イ\_s*\%(ダ\_s*ル\_s*ゴ\|ス\_s*パ\_s*ニ\_s*ア\|レ\_s*ー\_s*ル\|エ\_s*ロ\)\|H\_s*\%(z\|カ\_s*ッ\_s*プ\|o\_s*b\_s*b\_s*i\_s*t\|i\_s*\%(8\|B\_s*a\_s*n\_s*d\)\)\|オ\_s*\%([ラー]\|ナ\_s*ー\|ノ\_s*レ\|ン\_s*フ\_s*ル\_s*ー\_s*ル\|ネ\_s*\%(ス\_s*\%(ト\|テ\_s*ィ\)\|ゲ\_s*ル\)\|テ\_s*ル\|ル\_s*ガ\_s*ー\|マ\_s*ー\_s*ジ\_s*ュ\)\|ア\_s*\%(ン\_s*\%(リ\|ベ\_s*ー\_s*ル\)\|ネ\_s*ス\_s*ト\|ワ\_s*ー\|ダ\_s*マ\_s*ー\_s*ル\|シ\_s*ェ\_s*ッ\_s*ト\|ビ\_s*タ\_s*シ\_s*オ\_s*ン\|ー\_s*\%(ネ\_s*ス\_s*ト\|ノ\_s*ン\_s*ク\_s*ー\_s*ル\)\)\|エ\_s*\%(デ\_s*ィ\|ン\_s*リ\_s*ケ\|レ\_s*\%(ナ\|ー\_s*ヌ\)\|ロ\_s*イ\_s*ー\_s*ズ\|ク\_s*ト\_s*ル\|ル\_s*\%(ゲ\_s*ラ\|ヴ\_s*ェ\|メ\_s*ス\|マ\_s*ン\|ミ\_s*\%(ッ\_s*ト\|ー\_s*ト\)\|ブ\_s*ラ\_s*ン\|ナ\_s*ン\_s*デ\_s*ス\|キ\_s*ュ\_s*ー\_s*ル\)\|ノ\_s*ク\|ッ\_s*チ\|イ\_s*チ\)\|H\_s*\%([fsPeo]\|i\_s*m\_s*a\_s*n\_s*t\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|カ\_s*ッ\_s*プ\|T\_s*\%(M\_s*L\_s*フ\_s*ァ\_s*イ\_s*ル\|T\_s*P\_s*サ\_s*ー\_s*バ\)\|D\_s*D\_s*レ\_s*コ\_s*ー\_s*ダ\_s*ー\|u\_s*r\_s*d\|a\_s*\%(s\_s*s\_s*i\_s*u\_s*m\|f\_s*n\_s*i\_s*u\_s*m\|w\_s*a\_s*i\_s*i\)\|y\_s*\%(p\_s*e\_s*r\_s* \_s*T\_s*e\_s*x\_s*t\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|d\_s*\%(n\_s*o\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|r\_s*\%(a\_s*s\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|o\_s*\%(s\_s*t\_s*a\_s*c\_s*h\_s*y\_s*d\_s*a\_s*l\_s*e\_s*s\|g\_s*e\_s*n\)\)\)\)\)\|水\_s*[銀平素]\)', + \ 'i' : '\%([イΗη賤鄙卑苟嫌弥薯妹藷芋夢艷鑪鈩彩鱗色鯆忽綺貸甍応答愈圦杁霪隱蚓寅氤酳胤飮韵尹茵贇蔭婬湮堙廴音飲慇韻咽淫殞姻隕院允殷隠陰窟巌巖頌祝鰛鰮鰯岩磐円¥鼾歪弑弋抱懐肬贅疣狗戌乾犬諱在坐未汝戒誡警縛今Εε曰禾稻員因蝗嘶鰍電引躄誘動忿≦鵤錨碇怒霆雷霹凧桴筏魚S菴庵彌雖家尿荊棘茨祈祷命猯豕古伍乙鎰鴪聿軼樹慈悼愴慯労格到至傷鼬頂戴病徒致鈑痛板柞砂沙些聊潔諍烈功諫勳勲勇漁諌憇=憩粹熱粋憤域閾勢勤忙急磯孰焉湶泉厳何弄苛≧鎔范啀毬訝燻息挑縷絲厭營営愛幼稚緒遑暇糸弌壹肆莓苺櫟著市碑鐓礎甃臀弩石犧牲犠池溢Y佚壱11燠鬻礇毓粥的戦戰軍幾郁育一稲否飯洟位違居姨猗斎偽噫逝医鑄痍委囲云圍ゐ挿炒彙要熨饐醫言矮往詒威懿如僞忌彜煎逶緯韋唯莞淹胃善生恚彝惟以活易蔚為猪衣已倚幃斐移鮪将可偉畏五夷李渭怡貽癒依逸井慰行爲胆射詑矣頤熬萎良凍出椅率好揖肄痿鋳謂帷亥苡意維遺鰄異去堰尉容囗い氷Йй⇒→⊂⊃▼▽伊i印入∞吋∈∋∫∬∩IイИΙιи私i]\|E\_s*メ\_s*ー\_s*ル\|灼\_s*然\|祖\_s*谷\|湯\_s*文\_s*字\|文\_s*身\|郎\_s*[女子]\|刺\_s*[青草]\|蕁\_s*麻\|U\_s*r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|海\_s*[豚参]\|西\_s*表\|鸚\_s*哥\|影\_s*青\|況\_s*ん\_s*や\|所\_s*謂\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|藺\_s*草\|J\_s*u\_s*n\_s*c\_s*a\_s*l\_s*e\_s*s\|田\_s*舎\|膝\_s*行\|十\_s*六\_s*夜\|寝\_s*穢\|英\_s*\%(蘭\|吉\_s*利\)\|斑\_s*鳩\|烏\_s*賊\|玉\_s*筋\_s*魚\|硫\_s*黄\|夜\_s*来\_s*香\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|牛\_s*膝\|稜\_s*威\|常\_s*春\_s*藤\|5\_s*[つ日]\|5\_s*[つ日]\|惡\_s*戲\|甚\_s*振\|潮\_s*来\|悪\_s*戯\|交\_s*喙\|小\_s*魚\|鯨\_s*魚\|細\_s*小\_s*魚\|鶏\_s*魚\|経\_s*緯\|礒\_s*[山田]\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|和\_s*泉\|E\_s*\%(A\_s*S\_s*T\|V\_s*E\)\|気\_s*吹\|指\_s*宿\|拠\_s*所\|従\_s*[妹姉弟兄]\|公\_s*孫\_s*樹\|鴨\_s*脚\_s*樹\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|銀\_s*杏\|鳶\_s*尾\|檪\_s*本\|巫\_s*子\|神\_s*巫\|睦\_s*月\|都\_s*方\_s*流\|縊\_s*[殺死首]\|蝟\_s*[集縮]\|埋\_s*け\_s*[火炭]\|許\_s*[婚嫁]\|<\_s*=\_s*=\_s*>\|必\_s*要\_s*十\_s*分\_s*条\_s*件\|ヤ\_s*ン\|日\_s*本\_s*ア\_s*イ\_s*・\_s*ビ\_s*ー\_s*・\_s*エ\_s*ム\_s*株\_s*式\_s*会\_s*社\|国\_s*際\_s*\%(基\_s*督\_s*教\_s*大\_s*学\|標\_s*準\_s*化\_s*機\_s*構\)\|逆\_s*離\_s*散\_s*フ\_s*ー\_s*リ\_s*エ\_s*変\_s*換\|識\_s*別\_s*子\|即\_s*興\_s*曲\|な\_s*ら\_s*ば\|項\_s*目\|逐\_s*次\_s*型\|誤\_s*っ\_s*た\|無\_s*\%(花\_s*果\|効\_s*な\)\|帰\_s*納\_s*法\|字\_s*下\_s*げ\|不\_s*\%([可如足]\|充\_s*分\)\|具\_s*体\_s*化\|情\_s*報\|導\_s*入\|整\_s*数\|完\_s*全\|ヨ\_s*\%(ア\_s*ン\|シ\_s*フ\|ー\_s*ド\|ウ\_s*素\)\|I\_s*\%([rPn]\|R\_s*Q\|カ\_s*ッ\_s*プ\|C\_s*\%(タ\_s*グ\|チ\_s*ッ\_s*プ\|カ\_s*ー\_s*ド\)\|l\_s*l\_s*i\_s*n\_s*o\_s*i\_s*s\|S\_s*\%(O\|B\_s*N\_s*\%(番\_s*号\|コ\_s*ー\_s*ド\)\|A\_s*バ\_s*ス\)\|d\_s*a\_s*h\_s*o\|D\_s*\%(カ\_s*ー\_s*ド\|E\_s*\%(ド\_s*ラ\_s*イ\_s*ブ\|デ\_s*バ\_s*イ\_s*ス\|ケ\_s*ー\_s*ブ\_s*ル\|コ\_s*ン\_s*ト\_s*ロ\_s*ー\_s*ラ\)\)\|タ\_s*ー\_s*ン\|T\_s*\%(シ\_s*ス\_s*テ\_s*ム\|バ\_s*ブ\_s*ル\)\|o\_s*\%(w\_s*a\|d\_s*i\_s*n\_s*e\)\)\|ア\_s*\%(イ\|ー\_s*\%(ヴ\_s*ィ\_s*ン\|ビ\_s*ン\)\|ン\_s*\%(プ\_s*ロ\_s*ン\_s*プ\_s*\%(チ\_s*ュ\|テ\_s*ュ\)\|デ\_s*パ\_s*ン\_s*ダ\_s*ン\|フ\_s*ォ\_s*ル\_s*\%(メ\_s*ル\|マ\_s*テ\_s*ィ\_s*ー\_s*ク\)\)\)\)', + \ 'j' : '\%([塩嶋縞島嶌橲衄衂宍竺舳忸軸舌喰食直凝實昵実印尻稔仭糂贐潯儘仞盡刄臣侭恁進訊俥蕁迅刃靱荏甚靭燼櫁樒塵尽尋陣腎壬人敘恕耡汝莇杼茹敍蜍洳舒縟辱褥蓐溽所抒鋤徐序絮叙助釀淨疂絛繞壌諚孃瀞襄仍蟐拯疉讓聶驤生帖仗躡穰乘塲靜繩禳蕘壤遶星滌茸嬲疊如剩娘嬢錠静醸縄女尉饒丈成擾穣烝嫋丞盛場杖條条蒸貞状攘剰畳冗定浄乗情城上常譲濡得戍就嬬鷲竪讐讎懦愀咒聚隼詢徇笋凖盾楯筍篤蓴惇洵淳閏諄恂馴旬荀潤循醇巡遵順准殉純準襦誦需戌朮孰宿塾珠熟恤術述孺呪豎儒綬樹受授壽鞣狃澀揉廿拾縱中從糅从戎澁蹂神汁獸絨縦渋柔什充十獣従住銃重岻除士染時怩至児冶璽只畤侍孳轜耳示次寿辭粫司二祀邇而慈峙爺以地塒珥迩痔死敷恃蒔磁瓷仁字尓焦膩柱似嗣子亊路史餌兒滋仕爾辞弍自茲持寺事知醤鮭搦着惹尺鉐雀寂若弱蛇闍者邪戯麝じj│┃├┝┣┠┏┌.еЕ治Яя日юЮёЁЙジйj]\|ッ\_s*シ\_s*゙\|ッ\_s*ジ\|っ\_s*じ\|G\_s*\%(メ\_s*ン\|パ\_s*ン\)\|D\_s*y\|G\_s*\%(メ\_s*ン\|パ\_s*ン\)\|支\_s*度\|試\_s*合\|2\_s*乗\|2\_s*乗\|祖\_s*父\_s*\%(さ\_s*ん\|祖\_s*母\)\|獅\_s*子\|甲\_s*乙\_s*丙\_s*丁\_s*戊\_s*己\_s*庚\_s*辛\_s*壬\_s*癸\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|Z\_s*\%(r\|i\_s*r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\)\|深\_s*\%(秘\|大\_s*寺\)\|秦\_s*泉\_s*寺\|沈\_s*\%(香\|丁\_s*花\)\|晨\_s*朝\|濁\_s*世\|判\_s*官\|諍\_s*論\|長\_s*夜\|漏\_s*斗\|↑\_s*↓\_s*←\_s*→\|焼\_s*酎\|鐘\_s*石\|橈\_s*脚\_s*類\|承\_s*久\|朱\_s*里\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|絢\_s*子\|頌\_s*偈\|数\_s*珠\|入\_s*[魂牢来洛院内水棺]\|霜\_s*月\|1\_s*\%(2\|6\_s*進\|0\_s*[進月]\|1\_s*月\|8\_s*禁\)\|師\_s*走\|極\_s*月\|紐\_s*帯\|1\_s*\%(0\|1\_s*月\|8\_s*禁\|2\_s*月\)\|シ\_s*゙\|爪\_s*哇\|射\_s*礼\|砂\_s*利\|謝\_s*花\|三\_s*味\_s*線\|雑\_s*魚\|著\_s*語\|杓\_s*子\|共\_s*同\_s*企\_s*業\_s*体\|ゼ\_s*リ\_s*ー\|エ\_s*\%(ホ\_s*バ\|リ\_s*コ\|レ\_s*ミ\_s*ヤ\|ル\_s*サ\_s*レ\_s*ム\|ッ\_s*サ\_s*イ\)\|ヘ\_s*\%(レ\_s*ス\|ス\_s*ス\)\|ヒ\_s*メ\_s*ネ\_s*ス\|チ\_s*ゲ\|北\_s*陸\_s*先\_s*端\_s*\%(大\|科\_s*学\_s*技\_s*術\_s*大\_s*学\_s*院\_s*大\_s*学\)\|ハ\_s*\%(イ\_s*メ\|ラ\_s*ペ\_s*ー\_s*ニ\_s*ョ\)\|碧\_s*玉\|ヤ\_s*\%([リンニナー]\|イ\_s*ル\|エ\_s*ル\|ル\_s*ノ\|レ\_s*ド\|ヌ\_s*\%(ス\|シ\_s*ュ\)\|ス\_s*パ\_s*ー\_s*ス\|コ\_s*[ビブ]\|ッ\_s*ケ\)\|フ\_s*\%(ァ\_s*[ンナ]\|リ\_s*[オア]\)\|J\_s*\%(R\_s*東\_s*日\_s*本\|\.\_s*S\_s*\.\_s*\%(バ\_s*ッ\_s*ハ\|B\_s*a\_s*c\_s*h\)\|リ\_s*ー\_s*グ\|カ\_s*ッ\_s*プ\|C\_s*B\_s*カ\_s*ー\_s*ド\|-\_s*P\_s*O\_s*P\|ポ\_s*ッ\_s*プ\|P\_s*\%(G\_s*フ\_s*ァ\_s*イ\_s*ル\|E\_s*G\_s*フ\_s*ァ\_s*イ\_s*ル\)\|I\_s*S\_s*\%(マ\_s*ー\_s*ク\|コ\_s*ー\_s*ド\)\|a\_s*p\_s*a\_s*n\_s* \_s*A\_s*d\_s*v\_s*a\_s*n\_s*c\_s*e\_s*d\_s* \_s*I\_s*n\_s*s\_s*t\_s*i\_s*t\_s*u\_s*t\_s*e\_s* \_s*o\_s*f\_s* \_s*S\_s*c\_s*i\_s*e\_s*n\_s*c\_s*e\_s* \_s*a\_s*n\_s*d\_s* \_s*T\_s*e\_s*c\_s*h\_s*n\_s*o\_s*l\_s*o\_s*g\_s*y\|A\_s*\%(I\_s*S\_s*T\|N\_s*コ\_s*ー\_s*ド\|V\_s*A\_s*\%(ス\_s*ク\_s*リ\_s*プ\_s*ト\|ア\_s*プ\_s*レ\_s*ッ\_s*ト\)\)\|U\_s*N\_s*E\_s*T\)\|ズ\_s*ボ\_s*ン\|J\_s*\%(2\|−\_s*W\_s*A\_s*V\_s*E\|リ\_s*ー\_s*グ\|カ\_s*ッ\_s*プ\|ポ\_s*ッ\_s*プ\|I\_s*C\_s*C\_s*出\_s*版\|U\_s*\%(S\|N\_s*K\_s*O\)\|u\_s*s\)\|ユ\_s*\%([ハリダノ]\|ル\_s*ゲ\_s*ン\|ー\_s*\%([リノ]\|ゲ\_s*ン\_s*ト\|デ\_s*ィ\_s*ッ\_s*ト\)\|ン\_s*\%(グ\|カ\_s*ー\|ケ\_s*ル\)\|ピ\_s*テ\_s*ル\|ッ\_s*[カシ]\)\|イ\_s*\%(エ\_s*\%([ナス]\|ン\_s*\%(ス\|セ\_s*ン\)\|ズ\_s*ス\)\|ェ\_s*\%(ナ\|ン\_s*\%(ス\|セ\_s*ン\|ゼ\_s*ン\)\|ー\_s*ガ\_s*ー\|ル\_s*\%(ク\|サ\_s*レ\_s*ム\)\)\)\|ホ\_s*\%([タセ]\|ル\_s*ヘ\|ホ\_s*バ\|ア\_s*\%(ン\|キ\_s*ン\)\)\|ヨ\_s*\%([ブナ]\|ル\_s*\%(グ\|ダ\_s*ン\)\|エ\_s*ル\|ア\_s*\%(ヒ\_s*ム\|キ\_s*ム\)\|ゼ\_s*フ\|ー\_s*\%([トド]\|デ\_s*ル\|ゼ\_s*フ\)\|シ\_s*\%(フ\|ュ\_s*ア\)\|セ\_s*フ\|ハ\_s*[ナンネ]\)\)', + \ 'k' : '\%([コ怖旃之惟怺薦米暦轉殺壼鶤袞鯤坤狠艮琿悃很漿棍魂菎滾梱溷痕渾墾恨懇根梢杪王泥裔樸鞐熟枹醴聲声蛩凍溢零錯苔箏亊判斷諺理断盡悉尽辞詞殊事壽寿鯒礫鯉齣狛腓昆瘤鮗谺応應答茲是爰試志心凩兀笏惚榾輿甑腰拵拗鐺鏝昿仰慌袷塙頏絖冦耗亙峺衝晄覯糠匣逅閧扛湊羔礦爻壙盍洸鬨浤凰閤窖缸寇岡傚湟汞洽崗鮫伉訌誥冓敲磽倖簧鏗椌搆肓鍠矼砿犒淆呷鵁皐黌遘昴槹蚣肱肴熕胱猴扣杲蛤縞狎畊昊餃哽幌鱇峇嫦鎬隍恆倥徨啌吭釦闔藁亘絋棡遑紘稾鴿詬哮困靠皋惶紺鈩絳閘蒙冰氷郡蛟槁候楮媾溘蝗酵嚆犢稿亢哄睾慷郊岬肛項巷鑛洪佼狡昂叩勾喉滉糀晃剛晧曠宏控恍侯港皓坑皎耿膏江絞膠虹巧鴻鉱衡浩厚幸耕弘綱抗購攻講恒溝薨鋼航行肯荒高皇光好槲梏谷釛尅斛轂哭石告酷穀冴虎觚壷痼胯鼓児漉糊媚古娘冱混粉請辜湖虍放葫捏此鈷痩鴣瞽詁呼箍小錮蠱蛄粐滬估雇故沽転倒漕罟餬超込凅誇懲琥扈袴焦蝴呱乕踰弧越子孤菰跨壺楜股肥凝女戸恋兒怙瑚戀夸皷滸濾瓠濃乎仔こケ峻欅獸謇鵑愃搴劒俔儉險瞼慊圈幵釼顯剱椦黔暄劔涓臉妍劵歉獻縣蜷綣檢鉉虔愆娟權甄惓諠騫験慳捲倦遣羂嶮蹇鹸狷譴腱驗軒憲繭謙圏険硯倹献犬絢顕券劍剣見権研拳眷牽県建烟鑷言獣蓋涜吝削畩閲検貶健桁嗾竭獗偈譎碣蕨尻頡抉襭亅刔杰厥訐歇訣孑頁纈蹶桀穴傑結血煢蹊黥詣攜綮鮭絅盻挈瓊夐冂笄枅奚兮迥畦彑醯徑剄冏勍檠憬挂憇匸逕繼惠慧謦鷄系┓├┃┣┿━┻┷┸─┫┝┳┬┼┯┥╋┨┛│┠┰┏┤┴╂罫痙奎脛谿溪螢蛍渓閨憩圭携硅恵刑継勁珪計啓蹴毛褻異けク姑配椚橡檪櫪栩椡椪湫箜櫟含纐柵婚屎糞癖潛潜鵠凹窪縊跟頚軛珞頸首諄鞋履窟轡覆沓碎砕条降件頽崩屑釘莖茎陸杙杭掘崛倔鶏鐃藥擽薬樟楠梳櫛串釧與与挫籖鯀鯨籤隈熊艸嚔藾叢鏈腐鎖種Ξξ臭楔草圀邦國国髭漱嗽吻嘴唇脣梔腔φ粂裙勳熏皹桾皸醺崑燻訓勲葷委詳钁精鍬咥銜桑某暝峅昏冥眛罔鮓比闇位鞍藏暗倉廚厨涅曇蜘佝栗包俥車梍枢畔鐵玄蔵黒食孔桍窶暮焼懼駒苦区眩吁繰庫垢紅呉倶枸劬煦口瞿工吼怐喰貢惧區組句狗酌絎嶇衢刳くキ段痍疵紲絆傷築鱚嚴稷黍帛後碪砧絹兆萌刻鞫椈掬辟君牙蘗檗迄訖狐屹詰佶拮吃鞠橘菊喫.&⌒¬★!÷≠♪∫%±・。仝●|―¥Ц△‡`←¢£‰◎+ ̄〒☆ヽゞ、▽◇↓≒\;″°∝≦々℃∵†○´゛‥♭<#〇□‐_Å∞:▲ヾ♂?^,〓‖▼…〃¶゜@≫§∴′ゝ/>♀∨=≧ー−≪$♯↑■¨≡〆◆∽煙蚶更衣細后妃楸蕈茸乙雉轢杵軋岸桔汚穢北樵際裂燦煌雲嫌胆竏粁瓩浄淳澄潔清雰錐蛬吉霧檮桐箘鈞檎襟忻箟掀磬噤听瑾懃覲釁芹衿饉釿衾斤蒟径窘擒巾菌公禽筋錦欣僅琴均禁緊謹欽近勤嘘踞據苣擧渠秬鉅舉筥慶倨距歔遽鋸醵拠拒去勗蕀洫亟跼旭局挙許居巨虚轎繦羌姜篋蕎陜恊竸荊筴徼峽劫恟況棘竅僵亰狹頃筺梗誑刧襁烱洶抂卿鍄炯經竟廾况孝亨跫敬筐梟饗矯矜挾校挟拱嬌杏鞏響向興匈嚮享警競喬怯兄彊僑兢莢狂橋供郷兇驕凶叫夾匡侠狭恐経疆協境強胸驚脅共恭今教玖鬮歙舊疚笈邱赳摎恷岌貅9扱皀烋樛蚯逑厳胡翕朽泣穹糾糺及躬汲臼窮灸弓宮久柩究給丘求鳩級球休救急旧吸九基欹寄貴跂徠聞覊猗櫃煕既弃氣詭嬉效切妓跪虧卉稘尋冀暉唏姫伐喟伎畸効熙癸噐極祁匱馗旡其碁剞畿規希綺燬騎饑逵樹忌朞騏城聽棄悸肌生几季記僖紀斬決槻期起箕聴鰭崎餽倚幃瞶利晞欷毅危屓熈着汽木飢酒愾熹諱淇器羇机企麾訊著剪稀来圻來鬼揆奇羈禧譏棋黄憙己驥鑽决毀掎曁竒窺喜碕祈耆饋揮愧棊幾气徽消截岐祺麒覬嵜杞軌きカ糜癢粥痒麹輕骨業軽鰔鰈餉通瓶龜甕亀鴈獵鳫殯猟雁釀鳧鳬髢鴨躱巛側厠廁磧瓦獺翡裘皮紮→搦苧碓柄枳體軆躰躯体鴉犂烏機絡空唐榧茅揀坎澗扞莟丱拑盥嫺鑵蒄瞰淦稈康繝懽憾骭戡奐啣厂鐶讙澣羮寰羹嫻杆鸛歡豢歛罕酣陷皖篏捍瀚勸撼驩卷樌潤觀橄涵渙凵堪巫覡鉋萱簪舘艱咸翰柬悍駻燗槓浣邯攷稽宦考棺潅閂煥鉗疳癇函凾鹹顴緘桓款箝諌諫轗旱坩侃鰥 館莞橇韓患灌勧菅簡奸刊柑肝看桿干緩寒嵌廣広竿貫巻敢漢環間陥喚閑監喊歓甘寛管慣完艦乾幹官観壁椛屍姓庇鞄芳蔓鯑一勘⊃影陰蔭景*棧梯筧庚辛┘柧┐┌門廉脚癩乞∪川合’)〈《‘“”}{》〉囓柁旗鮖悴舵鰍鍛梶錺餝飾篭籠還歸卻皈孵省顧楓却帰反返督髮帋守祇韮裃雷髪紙鉦曲矩予鐘樺沫偏騙語潟刀模象仇固硬傍難容忝辱頑形方旁型肩風幽滓翳微掠綛纃絣緕擦糟鎹粕轄戞劼猾瞎恰蛞∧∩蠍擔濶筈剋蝎曷羯喝餓聒鞨黠刮蘰鬘桂闊括嘗捷豁渇担滑堅鰹割戛活暈疽鵲瘡傘嵩重襲葛笠堵硴墻牆蠣蛎柿關掲罹抱踵嬶嚊拘関係貌顏郁薫顔母感釡罐窰鴎框叺構喧竃竈釜缶蒲鎌數数槝栢膳傅瑕畏賢橿姦樫爨炊圍喞託囲鈎『鉤「』」限鍵傾禿蕪鏑頭齧気被兜敵適哉必要鼎鬲彜彝叶片悲哀愛鋺蛇鉄蜩神奏楫裹磆餅徒褐糧粮膈覺∠埆蠖貉幗隱擴寉骼癨壑咯椁嚇茖愨槨膕掴覈殼穫狢霍礁恪擱匿撹攪喀廓較郭]】【〔〕[殻挌劃閣格隠覚矍革獲馘攫核鶴拡客隔角確蠏壞畍丐獪褂恠喙峡夬觧械揩醢匯廨誡誨嵬櫂隗茴徊迴枴懈价椢榿囘蛙瑰乖浬鰄傀糴柏街鳰懷蛔蠶蚕邂蟹潰壊恢腕芥垣楷會拐悔詼諧契皆界疥魁偕改繪貝胛絵甲快灰槐晦懐介回塊解階廻戒開会怪海縢篝炬耀赫輝冠鑒鑑各屈鏡和代茄缺飼嫁華堝變狩上訶加架何啝火日菓欠苅繋稼ヶ个噛譁科跏舸賭禍支変窩課花交刈渦嚼掛呵替葭柯畫駆嘩崋化霞蝌迦顆価馨家借蝦罅駈斯賈嘉易果戈廈哥買闕且克墟靴訛驅換踝描軻嗅價嗄可彼夥香歌河珂鹿個痂書假荷耶笳咼藉糅舁搗渮袈下萪貸厦禾貨咬寡箇卦苛譌枷掻過画ヵ黴遐兼醸翔仮佳蚊懸伽賀淅勝涸苟蝸謌夏枯暇珈かk京節┗└※хХ忽コ汗〜功(株Kク×金窯χキカΚКΧкケκk]\|ッ\_s*[コケクキカ]\|ッ\_s*[コケクキカ]\|っ\_s*[子こけくきか]\|蟀\_s*谷\|焜\_s*炉\|前\_s*妻\|嫡\_s*妻\|二\_s*合\_s*半\|秋\_s*桜\|牛\_s*尾\_s*魚\|庶\_s*幾\|独\_s*楽\|特\_s*牛\|粫\_s*門\|甦\_s*生\|M\_s*e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|外\_s*連\_s*味\|螻\_s*蛄\|罌\_s*粟\|滅\_s*紫\|S\_s*i\|莎\_s*草\|百\_s*[濟済]\|9\_s*[日月]\|秧\_s*鶏\|釉\_s*掛\|典\_s*薬\_s*寮\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|探\_s*湯\|誓\_s*湯\|六\_s*合\|地\_s*祇\|都\_s*子\|州\_s*光\|群\_s*衆\|慈\_s*姑\|c\_s*r\_s*e\_s*s\_s*c\|内\_s*蔵\_s*助\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|仁\_s*彦\|啄\_s*木\_s*鳥\|X\_s*e\|如\_s*月\|私\_s*市\|昨\_s*日\|素\_s*地\|布\_s*地\|欺\_s*罔\|聖\_s*[之子美]\|沈\_s*菜\|蟋\_s*蟀\|螽\_s*斯\|G\_s*o\_s*l\_s*d\|A\_s*\%(u\|r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|s\_s*t\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\)\|菫\_s*青\_s*石\|槿\_s*花\|R\_s*\%(h\_s*\%(o\_s*e\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\)\|u\_s*n\_s*u\_s*n\_s*c\_s*u\_s*l\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|a\_s*n\_s*\%(u\_s*n\_s*c\_s*u\_s*l\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|a\_s*l\_s*e\_s*s\)\)\|裾\_s*礁\|脇\_s*[侍息]\|姉\_s*[妹弟]\|頬\_s*[骨筋]\|毬\_s*果\|舅\_s*姑\|厩\_s*\%([肥舎]\|務\_s*員\)\|廐\_s*舎\|離\_s*れ\_s*離\_s*れ\|掃\_s*部\|羚\_s*羊\|氈\_s*瓜\|土\_s*器\|蝙\_s*蝠\|魚\_s*狗\|為\_s*替\|連\_s*枷\|身\_s*体\|落\_s*葉\_s*松\|随\_s*神\|檻\_s*車\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|南\_s*瓜\|量\_s*子\|千\_s*典\|山\_s*\%(梔\_s*子\|陽\_s*道\)\|蜉\_s*蝣\|陽\_s*炎\|蜻\_s*蛉\|破\_s*片\|挿\_s*頭\|駕\_s*\%(籠\|輿\_s*丁\)\|槭\_s*樹\|長\_s*[月官]\|主\_s*[紀計神]\|剃\_s*刀\|天\_s*\%(牛\|鼠\_s*矢\)\|帷\_s*子\|酢\_s*漿\_s*草\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|飛\_s*白\|春\_s*日\|C\_s*\%([ormfda]\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\|i\_s*r\_s*c\_s*a\_s*e\_s*a\_s*s\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*r\_s*i\_s*u\_s*m\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*c\_s*i\_s*d\_s*i\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\)\|曾\_s*て\|曽\_s*て\|松\_s*魚\|燕\_s*子\_s*花\|牡\_s*[蛎蠣]\|民\_s*部\|部\_s*曲\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|案\_s*山\_s*子\|梭\_s*\%(魚\|子\_s*魚\)\|蟷\_s*螂\|螳\_s*螂\|瓜\_s*\%(田\|呂\_s*根\)\|拍\_s*手\|水\_s*[鶏母夫手]\|東\_s*\%(風\|京\_s*都\_s*立\_s*科\_s*学\_s*技\_s*術\_s*大\_s*学\)\|(\_s*株\_s*)\|称\_s*子\|贏\_s*ち\_s*得\|歩\_s*兵\|恁\_s*く\|杜\_s*\%(若\|父\_s*魚\)\|梅\_s*花\_s*皮\|頴\_s*田\|膾\_s*炙\|ノ\_s*\%([ブウ]\|ー\_s*ン\|ッ\_s*\%([トク]\|テ\_s*ィ\_s*ン\_s*グ\|カ\_s*ー\|キ\_s*ン\_s*グ\)\)\|ナ\_s*\%(ッ\_s*\%(ク\|プ\_s*\%(サ\_s*ッ\_s*ク\|ザ\_s*ッ\_s*ク\)\)\|レ\_s*ッ\_s*ジ\|イ\_s*[フトツ]\)\|ニ\_s*\%(ー\|ッ\_s*\%(ト\|テ\_s*ィ\_s*ン\_s*グ\)\)\|ホ\_s*\%(ー\_s*\%(ミ\_s*ー\|メ\_s*イ\)\|メ\_s*イ\_s*ニ\)\|フ\_s*\%(ビ\_s*ラ\_s*イ\|ル\_s*シ\_s*チ\_s*ョ\_s*フ\)\|ハ\_s*\%(ン\|ラ\_s*シ\_s*ョ\_s*ー\|ー\_s*ン\|バ\_s*ロ\_s*フ\_s*ス\_s*ク\|ル\_s*ツ\_s*ー\_s*ム\|チ\_s*ャ\_s*ト\_s*ゥ\_s*リ\_s*ア\_s*ン\)\|K\_s*\%([点gm]\|カ\_s*ッ\_s*プ\|n\_s*o\_s*c\_s*k\_s*O\_s*u\_s*t\|e\_s*n\_s*w\_s*o\_s*o\_s*d\)\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|a\_s*p\_s*a\_s*v\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|o\_s*\%(d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\)\)\)', + \ 'l' : '\%([ォォぉェェぇゥゥぅィィぃァァぁ<≪l ̄_≦李左←¬⊃∃∀∨ル∧レラлΛ£Лλl]\|ッ\_s*[ォェゥィァ]\|ッ\_s*[ォェゥィァ]\|っ\_s*[ぉぇぅぃぁ]\|液\_s*晶\|最\_s*小\_s*2\_s*乗\_s*法\|\.\_s*\.\_s*\.\|拉\_s*薩\|聯\_s*想\|補\_s*題\|檸\_s*檬\|手\_s*紙\|学\_s*習\|施\_s*錠\|局\_s*所\|論\_s*理\|ロ\_s*\%([キイアロリブボトメウスコゴグー]\|ペ\_s*ス\|ワ\_s*ー\_s*ル\|エ\_s*ベ\|ヨ\_s*ラ\|フ\_s*ト\|ル\_s*カ\|ベ\_s*リ\_s*ア\|ビ\_s*\%(ー\|ン\_s*グ\|イ\_s*\%(ス\_s*ト\|ン\_s*グ\)\)\|テ\_s*ィ\|サ\_s*ン\_s*\%(ジ\_s*ェ\_s*ル\_s*ス\|ゼ\_s*ル\_s*ス\)\|ニ\_s*ー\|ク\_s*リ\_s*ア\_s*ン\|ッ\_s*\%([ジタテトク]\|キ\_s*\%(ン\_s*グ\|ー\_s*ド\)\|カ\_s*ー\)\|カ\_s*ー\_s*ル\|ケ\_s*ー\_s*\%([トタル]\|シ\_s*ョ\_s*ン\)\|ガ\_s*ー\|ギ\_s*ン\_s*グ\|ジ\_s*\%(ー\|テ\_s*ッ\_s*ク\|ス\_s*テ\_s*ィ\_s*\%(ク\|ッ\_s*ク\)\|カ\_s*ル\|ク\_s*ー\_s*ル\|ッ\_s*[トク]\)\|ラ\_s*ン\|ン\_s*\%([ゴグダ]\|ボ\_s*\%(ク\|ッ\_s*ク\)\|バ\_s*ル\_s*デ\_s*ィ\|ズ\_s*デ\_s*ー\_s*ル\|リ\_s*[ィー]\|ジ\_s*ン\|ド\_s*ン\)\|レ\_s*\%(ア\_s*ル\|ッ\_s*タ\|ー\_s*ヌ\|イ\_s*ン\|ン\_s*\%([ソス]\|ツ\_s*ォ\)\)\)\|\\\_s*L\_s*a\_s*T\_s*e\_s*X\|L\_s*\%(サ\_s*イ\_s*ズ\|L\_s*サ\_s*イ\_s*ズ\|U\_s*N\_s*A\|u\_s*\%(n\_s*a\|c\_s*\%(i\_s*d\|k\_s*y\)\)\|i\_s*\%(a\_s*r\|s\_s*p\|t\_s*e\)\|o\_s*f\_s*t\|A\_s*T\_s*E\_s*X\|a\_s*\%(w\_s*s\_s*o\_s*n\|T\_s*e\_s*X\|s\_s*e\_s*r\_s*W\_s*r\_s*i\_s*t\_s*e\_s*r\)\)\|L\_s*\%([DP]\|サ\_s*イ\_s*ズ\|L\_s*サ\_s*イ\_s*ズ\|u\_s*\%(t\_s*e\_s*t\_s*i\_s*u\_s*m\|c\_s*i\_s*d\)\|i\_s*\%(t\_s*h\_s*i\_s*u\_s*m\|s\_s*p\|n\_s*u\_s*x\)\|E\_s*D\_s*ラ\_s*イ\_s*ト\|e\_s*m\_s*m\_s*a\|o\_s*\%(g\_s*i\_s*c\_s*a\_s*l\_s* \_s*U\_s*n\_s*i\_s*t\_s* \_s*N\_s*u\_s*m\_s*b\_s*e\_s*r\|u\_s*i\_s*s\_s*i\_s*a\_s*n\_s*a\)\|a\_s*\%(w\_s*r\_s*e\_s*n\_s*c\_s*i\_s*u\_s*m\|n\_s*t\_s*h\_s*a\_s*n\_s*u\_s*m\|T\_s*e\_s*X\)\|A\_s*N\)\|研\_s*究\_s*室\|エ\_s*ル\|リ\_s*\%([ィセズザサスダポルラリマナノンヌブアー]\|ャ\_s*マ\|ヤ\_s*ド\_s*ロ\|ヨ\_s*ン\|ゾ\_s*チ\_s*ー\_s*ム\|コ\_s*\%(リ\_s*ス\|ピ\_s*ン\)\|ク\_s*ー\_s*ド\|カ\_s*\%(ー\|オ\_s*ン\)\|ジ\_s*[ンー]\|デ\_s*[ィル]\|ド\_s*カ\_s*イ\_s*ン\|プ\_s*ト\_s*ン\|パ\_s*ー\_s*ゼ\|グ\_s*\%(ニ\_s*ン\|ナ\_s*ン\)\|フ\_s*\%([エト]\|タ\_s*ー\|テ\_s*ィ\_s*ン\_s*グ\)\|テ\_s*ラ\_s*[ルシ]\|チ\_s*ウ\_s*ム\|ソ\_s*\%(ソ\_s*ー\_s*ム\|グ\_s*ラ\_s*フ\_s*ィ\)\|タ\_s*ー\|ト\_s*\%([レル]\|マ\_s*ス\|ア\_s*ニ\_s*ア\|グ\_s*ラ\_s*フ\|バ\_s*ル\_s*ス\_s*キ\_s*ー\)\|オ\_s*\%(タ\_s*ー\_s*ル\|ネ\_s*ル\)\|ミ\_s*\%(テ\_s*ッ\_s*ド\|ッ\_s*[タト]\)\|モ\_s*\%(ー\_s*ジ\_s*ュ\|ネ\_s*ン\|ン\_s*チ\_s*ェ\_s*ッ\_s*ロ\)\|ム\_s*ジ\_s*ン\|キ\_s*\%(ッ\_s*ド\|ュ\_s*ー\_s*ル\|テ\_s*ン\_s*\%(ス\_s*タ\_s*イ\_s*ン\|シ\_s*ュ\_s*タ\_s*イ\_s*ン\)\)\|エ\_s*\%(ゾ\_s*ン\|ー\_s*ジ\_s*ュ\)\|ヒ\_s*テ\_s*ン\_s*シ\_s*ュ\_s*タ\_s*イ\_s*ン\|ネ\_s*\%([アン]\|ッ\_s*ト\|ー\_s*ジ\_s*ュ\)\|ニ\_s*ア\|ベ\_s*\%([ロラ]\|リ\_s*ア\|レ\_s*ー\_s*シ\_s*ョ\_s*ン\|ル\_s*テ\)\|ビ\_s*\%([アー]\|ド\_s*ー\|ン\_s*グ\)\|ュ\_s*\%([スー]\|ブ\_s*リ\_s*ャ\_s*ー\_s*ナ\|リ\_s*ュ\|ド\_s*ミ\_s*ラ\|ク\_s*サ\_s*ン\_s*ブ\_s*ー\_s*ル\|ッ\_s*ク\|シ\_s*ア\_s*ン\|ミ\_s*エ\_s*ー\_s*ル\)\|ロ\_s*\%(イ\|ン\_s*グ\_s*ウ\_s*ェ\)\|ヴ\_s*\%(ィ\_s*ン\_s*グ\_s*ス\_s*ト\_s*ン\|ァ\_s*\%(プ\_s*ー\_s*ル\|イ\_s*ア\_s*サ\_s*ン\)\)\|バ\_s*\%(テ\_s*ィ\|タ\_s*リ\_s*ア\_s*\%(ン\|ニ\_s*ズ\_s*ム\)\|プ\_s*ー\_s*ル\|イ\_s*ア\_s*サ\_s*ン\)\|ッ\_s*\%([ドピプタクチト]\|ス\_s*ン\)\)\)', + \ 'm' : '\%([モ脆醪師諸催靄舫腿銛杜森聞捫匁紋問翫玩擡齎靠凭鵙鴃縺悶樅籾椛楓蛻潛濳艾潜殯黐餠用糯餅桃者懶專専物尤勿畚戻許悖故旧下乖求礎素基本元綟捩文默沐杢黙耗檬网莽芒罔耄朦魍艨濛曚矇亡蒙毛孟猛網糢保若望揉燃洩貰藻漏以模母裳楙姆摸茂持喪もメ麪緜眄緬麺門棉綿面蓍珎珍♀娶貭粧妾牝瞽盲娚暈繞萌慈惠恵萠暝謎溟滅姪瞑盟酩銘鳴瑪賞睨奴雌芽碼召女減めム羣榁室簇邨屯連邑叢村紫梅葎宜憤毳槿葮椋酬報尨骸躯旨難睦酷麥麦対邀百迎昔空虚鞅宗棟胸掬娘結笞鞭徒蠧蝕蠹蟲蓆寧筵席莚虫毟貉狢豸貪聟壻婿霧向无無謀武鵡夢群牟梦六剥毋噎蒸咽務矛むミ渠霙溝妊澪薨岑嶺峰峯亂紊淫婬濫妄猥乱※*◇■簔穣簑蓑醜儖慘短惨幹研耳壥廛店操陵鶚崎岬巫尊詔勅敕>」砌汀頻→』】右翠碧緑認幣蹊径倫導途通路道瞠鬟髻湖自蹼蛟瑞癸禊晦漲源鏖港湊南瞶櫁謐水調貢密甕帝蜜覩幸脉脈韭韮竓粍瓱榠螟茗名妙命冥都宮罠閔皆眠明民看彌稔靡觀盈診箕三観美充深壬實視御魅味巳己身弥みマ毬鞠紕蝮麿転稀賓客檀繭黛眉巡囘周防衞衛護守荳菽豆.・。°◯圓槫゜)(丸謾鰻縵鬘懣幡幔蹣蔓瞞卍饅漫滿慢迄笆貧幻瞼蔟疎眩回廻儲申設招繚統纒的蟶孫弯彎籬擬免猿純亮信実委罷圸壗侭飯儘継随髷任蒭芻耙紛鮪見猯塗斈學眦眥眼俎愛学斑斗枡鱒桝舛升萬蠱呪薪槙槇牧窗悗惑円窓襠甼区街町前複亦俣叉跨全瞬木胯股又鍖枕膜幕瑁詣参參妹眛哩迷枚米賄賂埋昧邁毎沫抹奉靺枩秣祀纏祭睫末大太秀勝柾弄優成盛將松匡鉞賢希将誠昌征政正雅仁媽散茉馬在増混交間放摩負枉益敗眞待未麼撒巻魔蒔俟坐嘛舞捲目磨痲先墹真満播万曲卷雑まm光月♪♭♯ム¬⌒÷⊃≠∫∠±⊇⇔∃∇√∧≒∩∬∋∝≦∵Δ⇒∞⊂⊆⊥∀≫∴×∨≧≪≡∂∈∽∪♂曼麻●◎○〇モ〒′−マ最ミメМΜμm]\|ッ\_s*[モメムミマ]\|ッ\_s*[モメムミマ]\|っ\_s*[もめむみま]\|双\_s*\%([手墨親]\|向\_s*き\|差\_s*し\)\|蜀\_s*黍\|唐\_s*土\_s*\%(書\|文\_s*字\)\|両\_s*\%([角親刃]\|差\_s*し\)\|楊\_s*梅\_s*皮\|主\_s*水\|旺\_s*角\|紅\_s*[絹染葉]\|強\_s*請\|虎\_s*落\|痘\_s*瘡\|莫\_s*斯\_s*科\|固\_s*よ\_s*り\|一\_s*徳\|O\_s*l\_s*e\_s*a\_s*l\_s*e\_s*s\|惘\_s*然\|乙\_s*張\|赤\_s*目\_s*魚\|針\_s*孔\|妻\_s*[君合沼]\|墨\_s*西\_s*哥\|鍍\_s*金\|繍\_s*眼\_s*児\|夫\_s*婦\|乳\_s*母\|布\_s*の\_s*子\|没\_s*\%([薬後入却有]\|義\_s*道\|食\_s*子\)\|B\_s*\%(e\_s*r\_s*b\_s*e\_s*r\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*o\_s*r\_s*r\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|浮\_s*腫\|6\_s*日\|6\_s*日\|崇\_s*田\|刀\_s*背\|襁\_s*褓\|零\_s*余\_s*子\|蜈\_s*蚣\|産\_s*霊\|息\_s*子\|k\_s*\$\_s*_\_s*{\_s*i\_s*n\_s*f\_s*}\_s*\$\|蚯\_s*蚓\|A\_s*\%(b\_s*i\_s*e\_s*s\|p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*r\_s*o\_s*s\_s*t\_s*i\_s*c\_s*h\_s*u\_s*m\)\|山\_s*陵\|雎\_s*鳩\|親\_s*王\|嬰\_s*児\|亨\_s*治\|陸\_s*奥\|皇\_s*[子女國]\|3\_s*[つ日]\|3\_s*[つ日]\|角\_s*[鴟髪子]\|七\_s*寸\|鳩\_s*尾\|鷦\_s*鷯\|孤\_s*児\|凝\_s*視\|兎\_s*唇\|R\_s*u\_s*t\_s*a\_s*l\_s*e\_s*s\|神\_s*[子輿酒]\|苗\_s*字\|海\_s*[雲蘊布藻蜂松山]\|P\_s*o\_s*d\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|土\_s*[龍竜産]\|京\_s*都\|横\_s*浜\_s*マ\_s*リ\_s*ノ\_s*ス\|肉\_s*刺\|忠\_s*実\|翻\_s*\%(筋\_s*斗\|車\_s*魚\)\|H\_s*a\_s*m\_s*a\_s*m\_s*e\_s*l\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|不\_s*\%(味\|見\_s*[点転]\)\|兇\_s*々\|凶\_s*鳥\|澗\_s*潟\|勾\_s*玉\|禍\_s*[々禍事言]\|況\_s*し\|澳\_s*門\|苧\_s*麻\|茅\_s*台\_s*酒\|丈\_s*夫\|倍\_s*達\|微\_s*[塵妙睡]\|燐\_s*寸\|驀\_s*地\|L\_s*o\_s*g\_s*a\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|豫\_s*て\|陪\_s*臣\|売\_s*僧\|C\_s*\%(a\_s*s\_s*u\_s*a\_s*r\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*a\_s*t\_s*o\_s*p\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\)\|S\_s*\%(a\_s*p\_s*i\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|c\_s*h\_s*i\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|理\_s*[之元]\|允\_s*彦\|祐\_s*史\|晶\_s*子\|公\_s*[美則輝]\|斉\_s*加\_s*年\|方\_s*夫\|多\_s*言\_s*語\_s*化\|ニ\_s*ー\_s*モ\_s*ニ\_s*ッ\_s*ク\|単\_s*量\_s*体\|会\_s*議\|和\_s*布\_s*[刈蕪]\|中\_s*間\_s*子\|薄\_s*荷\_s*脳\|行\_s*[幸列]\|写\_s*像\|日\_s*\%(米\_s*相\_s*互\_s*防\_s*衛\_s*援\_s*助\_s*協\_s*定\|本\_s*製\)\|M\_s*\%(H\_s*z\|サ\_s*イ\_s*ズ\|S\_s*−\_s*D\_s*O\_s*S\|L\_s*サ\_s*イ\_s*ズ\|r\_s*.\|b\_s*p\_s*s\|c\_s*C\_s*a\_s*r\_s*t\_s*h\_s*y\|o\_s*t\_s*i\_s*f\|a\_s*c\)\|計\_s*算\_s*機\|手\_s*紙\|ザ\_s*ッ\_s*ヘ\_s*ル\_s*=\_s*マ\_s*ゾ\_s*ッ\_s*ホ\|嗜\_s*虐\_s*的\_s*趣\_s*味\|被\_s*虐\_s*\%(趣\_s*味\|淫\_s*乱\_s*症\)\|修\_s*士\|仮\_s*面\|移\_s*送\|M\_s*\%([dngtOo式]\|X\_s*テ\_s*レ\_s*ビ\|サ\_s*イ\_s*ズ\|S\_s*-\_s*D\_s*O\_s*S\|L\_s*サ\_s*イ\_s*ズ\|P\_s*3\_s*プ\_s*レ\_s*\%(ー\_s*ヤ\_s*ー\|イ\_s*ヤ\_s*ー\)\|D\_s*\%(プ\_s*レ\_s*ー\_s*ヤ\_s*ー\|レ\_s*コ\_s*ー\_s*ダ\_s*ー\)\|c\_s*C\_s*a\_s*r\_s*t\_s*h\_s*y\|e\_s*\%(d\_s*u\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*l\_s*e\_s*s\|i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*u\_s*m\|t\_s*a\_s*F\_s*o\_s*n\_s*t\|n\_s*\%(y\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|d\_s*e\_s*l\_s*e\_s*v\_s*i\_s*u\_s*m\)\|C\_s*a\_s*b\)\|u\_s*l\_s*e\|A\_s*C\_s*ア\_s*ド\_s*レ\_s*ス\|a\_s*\%(g\_s*n\_s*\%(o\_s*l\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|e\_s*s\_s*i\_s*u\_s*m\)\|n\_s*\%(u\_s*\%(s\_s*c\_s*r\_s*i\_s*p\_s*t\_s* \_s*E\_s*d\_s*i\_s*t\_s*i\_s*n\_s*g\|e\_s*d\)\|g\_s*a\_s*n\_s*e\_s*s\_s*e\)\|r\_s*y\_s*l\_s*a\_s*n\_s*d\|i\_s*n\_s*e\|k\_s*e\_s*f\_s*i\_s*l\_s*e\|c\_s*\%(h\|i\_s*n\_s*t\_s*o\_s*s\_s*h\)\|s\_s*\%(s\_s*a\_s*c\_s*h\_s*u\_s*s\_s*e\_s*t\_s*t\_s*s\|t\_s*e\_s*r\_s*C\_s*a\_s*r\_s*d\)\)\|i\_s*\%(n\_s*n\_s*e\_s*s\_s*o\_s*t\_s*a\|s\_s*s\_s*\%(i\_s*s\_s*s\_s*i\_s*p\_s*p\_s*i\|o\_s*u\_s*r\_s*i\)\|c\_s*\%(r\_s*o\_s* \_s*S\_s*o\_s*f\_s*t\_s*w\_s*a\_s*r\_s*e\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*s\|h\_s*i\_s*g\_s*a\_s*n\)\)\|I\_s*\%(T\|P\_s*S\|M\_s*D\)\)\|エ\_s*ム\)', + \ 'n' : '\%([ンンんノ麕咒燧烽詛呪孔伯朔雅悳弼教糊典規矩憲範宜紀哲修惟允亘攵展順暢信則法後罵吭咽喉鑿蚤々湾宣曰覘臨稀望覗殘遺残鋸芒禾騰幟昇登上檐簷軒逸遁王瑙衲曩碯皇腦嚢膿能脳農除延熨廼退埜野飲載乘飮之伸嚥述乗呑−濃陳のネ塒姉濘檸嚀聹侫寧佞鼡鼠拗猫嫉妬希願捏熱労犒葱狙閨睡棔眠稔然棯懇拈撚燃念年涅粘値根捻嶺祢錬寝袮捩音練禰煉子寢ねヌ絖垈饅帛幣鵺主蛻拭温布沼盜偸窃盗抽擢緯糠額濡脱怒縫抜奴拔貫塗ぬニ楡蒻潦鷄鶏瀑庭繞獰女尿韭薤眈睨韮姙刄儿蒜葫刃忍∀妊認任人乳擔蜷担濁賑握俄鳰臭匂沸錵贄僞偐贋偽柔靤如苦膠霓滲虹躙廿《》◎∬』『悪憎兄螺鰊鯡錦西入新肉‖岻逃児弐二邇2貳迩煮貮迯仁尼似荷2弍丹にナ靡抔嫐嬲鯆屶釶鉈泥薺詰若慨歎嘆抛毆擲撲殴慰治癒等猶直泪波邉辺邊鍋浪某棘棗懷懐夏擦梨情懶譌艶訛鉛鮠癜鯰韲鱠膾憖怠鈍腥捺凖擬准準謎洋涙宥傾灘詠霖眺痼存乍流轅永和梛椥渚長莫毋勿半・媒仲中7斜七蔑乃尚内繩畷縄苗滑鞣惱悩就哉也斉形業徳娚垂喃∵楠尓爾汝男軟難何倣枹均柞双肄列⊃⇒→楢習竝茄啾納無那拿舐娜做涕投馴南熟並儺生凪鳴為綯奈嘗哭嚶爲狎薙萎菜魚慣泣亡失痿撫啼な┘┛│┃┨┫┤┥├┝┣┠┼╋╂┿成#∋∇名┗└n日≒ニネ¬〜≠ナヌノΝНнνn]\|帳\_s*面\|狼\_s*[烟煙]\|惚\_s*気\|暖\_s*[簾気]\|礼\_s*江\|功\_s*晶\|祈\_s*子\|訓\_s*子\|賀\_s*子\|式\_s*部\_s*省\|記\_s*代\|倫\_s*[明子宗]\|敬\_s*之\|賭\_s*弓\|誠\_s*也\|敦\_s*子\|悦\_s*旦\|祝\_s*[女詞]\|仰\_s*け\_s*反\|盧\_s*泰\_s*愚\|逆\_s*上\|凌\_s*霄\_s*花\|姐\_s*さ\_s*ん\|杜\_s*松\|強\_s*請\|合\_s*歓\|微\_s*温\|零\_s*余\_s*子\|酸\_s*漿\|鐃\_s*鉢\|鰾\_s*膠\|I\_s*I\_s*部\|耳\_s*根\|面\_s*皰\| \_s*2\_s* \_s*次\_s*曲\_s*面\|M\_s*y\_s*r\_s*i\_s*s\_s*t\_s*i\_s*c\_s*a\_s*c\_s*e\_s*a\_s*e\|莞\_s*爾\|P\_s*b\|L\_s*e\_s*a\_s*d\|海\_s*[苔鼠]\|C\_s*\%(e\_s*l\_s*a\_s*s\_s*t\_s*r\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*r\_s*y\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*l\_s*e\_s*s\)\|雪\_s*崩\|竹\_s*節\_s*虫\|7\_s*[日個]\|地\_s*震\|行\_s*[木方]\|大\_s*\%(蒜\|理\_s*石\)\|蛞\_s*蝓\|弱\_s*竹\|追\_s*儺\|済\_s*\%(し\_s*崩\|り\_s*物\)\|可\_s*成\|平\_s*城\|不\_s*成\|空\_s*リ\_s*ス\_s*ト\|T\_s*h\_s*e\_s* \_s*N\_s*e\_s*t\_s*w\_s*o\_s*r\_s*k\_s* \_s*I\_s*n\_s*f\_s*o\_s*r\_s*m\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\|S\_s*o\_s*\%(l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|d\_s*i\_s*u\_s*m\)\|紐\_s*育\|フ\_s*ォ\_s*ン\_s*・\_s*ノ\_s*イ\_s*マ\_s*ン\|ヤ\_s*ー\_s*ノ\_s*ッ\_s*シ\_s*ュ\_s*・\_s*フ\_s*ォ\_s*ン\_s*・\_s*ノ\_s*イ\_s*マ\_s*ン\|オ\_s*ラ\_s*ン\_s*ダ\|ア\_s*メ\_s*リ\_s*カ\_s*ネ\_s*ッ\_s*ト\_s*ワ\_s*ー\_s*ク\|番\_s*号\|節\_s*点\|N\_s*\%([点O]\|ク\_s*ィ\_s*ー\_s*ン\|\.\_s*Y\_s*\.\|i\_s*f\_s*t\_s*y\|I\_s*F\_s*T\_s*Y\|a\_s*\%(v\_s*i\|t\_s*u\_s*r\_s*e\)\|e\_s*\%(X\_s*T\|m\_s*a\_s*c\_s*s\|w\_s*−\_s*J\_s*e\_s*r\_s*s\_s*e\_s*y\|W\_s*S\|u\_s*r\_s*a\_s*l\)\|E\_s*\%(m\_s*a\_s*c\_s*s\|T\_s*t\_s*a\_s*l\_s*k\)\|o\_s*\%(.\|ё\_s*l\)\)\|夜\_s*想\_s*曲\|諾\_s*威\|正\_s*常\|N\_s*\%([dpbaeoi]\|R\_s*Z\_s*I\|-\_s*g\_s*r\_s*a\_s*m\|G\_s*ワ\_s*ー\_s*ド\|H\_s*K\_s*\%(ホ\_s*ー\_s*ル\|ラ\_s*ジ\_s*オ\)\|T\_s*T\|Y\_s*ダ\_s*ウ\|U\_s*L\_s*L\|A\_s*S\_s*A\|E\_s*\%(C\|p\_s*o\_s*c\_s*h\|m\_s*a\_s*c\_s*s\)\)\|窒\_s*素\|エ\_s*ヌ\)', + \ 'o' : '\%([オ俺游泳指妖在畢檻澱氈拇親愚疎颪卸念錘惟慮赴徐趣俤羈主想表重面隱瘟園Å怨♀妾温恩鈍悍臣覺溺朦朧思覚榲現朮桶踴威嚇戯縅棘駭愕驚躍踊傲奢驕嚴厳遣痴瘧怒行怠蒹補荻獺懼惧怐虞畏恐襲甥笈及綬葹仝ヾ〃ゝヽゞ々同唖繦襁鴦鴛教几忍筬收兎抑稚長幼治理収修遲檍納後遅賻饋諡贈送憶袵臆拜拝冒犯岳崗峻阜侵奇陵女陸丘岡欄斧自己各戦鬼衰劣囮頤訪貶乙♂漢音弟阿脅怯首夥誘屋膃億穩穏煽煕熈燠熾諚掟興隠沖毆姶澳秧浤凰徃枉罌殃翁鴬泓奧嚶墺悒泱閘瓮襖蓊惶鸚懊媼嫗鴎怏鏖謳旺凹鴨櫻欒樗楝殴朷甌汪横往鞅歐嘔陷陥遠奄蓋夛応果應掩蔽概欧公邑麋薤被仰扇皇狼弁鵬鴻鳳黄奥多衽覆粱凡鰲頁王居央郎措擱堕尾置麻朗怖悪追帶折塢負墜織老汚生勇小嗚夫惜起唹落男推将穂壓淤御緒墮逐下牡捺雄降桜押圧苧帯於終乎おo大◎∞和∝♪∨∪開оОο○ωΟオΩo]\|濠\_s*太\_s*剌\_s*利\|父\_s*[娘子]\|母\_s*[子娘屋]\|万\_s*年\_s*青\|本\_s*懸\_s*魚\|玩\_s*具\|沢\_s*瀉\|A\_s*l\_s*i\_s*s\_s*m\_s*a\_s*t\_s*a\_s*l\_s*e\_s*s\|厭\_s*離\|乳\_s*母\_s*日\_s*傘\|陰\_s*[陽地]\|飲\_s*[食酒]\|慍\_s*色\|婦\_s*系\_s*図\|手\_s*術\|螻\_s*蛄\|十\_s*八\_s*番\|鉄\_s*漿\|海\_s*髪\_s*海\_s*苔\|虎\_s*魚\|花\_s*魁\|美\_s*味\|含\_s*羞\_s*草\|白\_s*粉\|渡\_s*島\|通\_s*事\|訳\_s*語\|晩\_s*[稲生]\|可\_s*笑\|惡\_s*寒\|傍\_s*[目惚見]\|叔\_s*[父母]\|伯\_s*[父母]\|姨\_s*捨\|少\_s*女\|侠\_s*気\|G\_s*u\_s*t\_s*t\_s*i\_s*f\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|D\_s*i\_s*l\_s*l\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|H\_s*y\_s*p\_s*e\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|霊\_s*屋\|蝌\_s*蚪\|飫\_s*肥\|佩\_s*物\|良\_s*人\|纓\_s*田\|C\_s*o\_s*p\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|鷹\_s*揚\|椀\_s*飯\_s*振\_s*\%(舞\|る\_s*舞\)\|相\_s*知\|鶯\_s*語\|近\_s*江\|零\_s*落\|越\_s*[生訴知智度]\|彼\_s*方\|祖\_s*[神父母]\|車\_s*前\|従\_s*祖\_s*[母父]\|青\_s*[梅海木]\|太\_s*\%(田\|安\_s*万\_s*侶\|上\_s*天\_s*皇\)\|巨\_s*頭\|逢\_s*[魔瀬隈坂]\|そ\_s*の\_s*他\|承\_s*知\_s*し\_s*ま\_s*し\_s*た\_s*\.\|烏\_s*[滸龍]\|t\_s*h\_s*e\_s* \_s*O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*a\_s*n\_s*a\_s*g\_s*e\_s*m\_s*e\_s*n\_s*t\_s* \_s*G\_s*r\_s*o\_s*u\_s*p\|立\_s*石\_s*電\_s*機\|職\_s*業\|楕\_s*円\|ウ\_s*\%(ィ\|ー\_s*\%(ズ\|ロ\_s*ン\)\|ロ\_s*ボ\_s*ロ\_s*ス\)\|出\_s*力\|ア\_s*\%(ワ\|ザ\_s*ー\|ウ\_s*\%([チト]\|タ\_s*ー\)\)\|基\_s*本\_s*ソ\_s*フ\_s*ト\_s*ウ\_s*ェ\_s*ア\|一\_s*\%(昨\_s*[年日]\|対\_s*一\)\|ワ\_s*ン\|ま\_s*た\_s*は\|論\_s*理\_s*和\|聖\_s*譚\_s*曲\|水\_s*中\_s*酸\_s*素\_s*破\_s*壊\_s*剤\|蛋\_s*白\_s*石\|最\_s*適\_s*化\|O\_s*\%([脚型]\|R\_s*E\|\.\_s*K\_s*\.\|S\_s*9\|リ\_s*ン\_s*グ\|p\_s*e\_s*n\_s*\%(L\_s*o\_s*o\_s*k\|W\_s*i\_s*n\_s*d\_s*o\_s*w\_s*s\)\)\|歌\_s*劇\|演\_s*算\_s*子\|操\_s*作\|酸\_s*素\|O\_s*\%([型脚sS]\|h\_s*i\_s*o\|k\_s*l\_s*a\_s*h\_s*o\_s*m\_s*a\|b\_s*j\_s*e\_s*c\_s*t\_s*-\_s*O\_s*r\_s*i\_s*e\_s*n\_s*t\_s*e\_s*d\|O\_s*\%(D\_s*L\|P\_s*L\)\|M\_s*R\_s*O\_s*N\|A\_s*ク\_s*リ\_s*ー\_s*ナ\_s*ー\|C\_s*R\_s*ソ\_s*フ\_s*ト\|r\_s*e\_s*g\_s*o\_s*n\|''\_s*R\_s*e\_s*i\_s*l\_s*l\_s*y\_s* \_s*J\_s*a\_s*p\_s*a\_s*n\|リ\_s*ン\_s*グ\|p\_s*e\_s*n\_s*W\_s*i\_s*n\_s*d\_s*o\_s*w\|x\_s*y\_s*g\_s*e\_s*n\)\)', + \ 'p' : '\%([本磅椪烹砲法方報舖舗歩ぽ併閉閇蔽×遍編片邉篇辺邊屁ぺ幅服風分腐布符泌匹俵憑票品筒平日犯版搬幇板払腹發発走箱拍朴駮泊博愽包放配盃敗牌杯八破羽波播張ぱp鉛Ψψぴ±+ぷΦφ├┣∝北┴‰.%£〒・点プポ頁)(∂¶‖ペパПΠп燐πピp]\|ッ\_s*\%(ホ\_s*゚\|ヘ\_s*゚\|フ\_s*゚\|ヒ\_s*゚\|ハ\_s*゚\)\|ッ\_s*[ポペプピパ]\|っ\_s*[ぽぺぷぴぱ]\|ホ\_s*゚\|先\_s*斗\_s*町\|ヘ\_s*゚\|祕\_s*[露魯]\|フ\_s*゚\|釜\_s*山\|普\_s*魯\_s*西\|ヒ\_s*゚\|皮\_s*蛋\|光\_s*一\|ハ\_s*゚\|麺\_s*麭\|巴\_s*\%(里\|奈\_s*馬\)\|C\_s*y\_s*c\_s*l\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|S\_s*y\_s*n\_s*a\_s*n\_s*t\_s*h\_s*a\_s*e\|排\_s*骨\|B\_s*r\_s*o\_s*m\_s*e\_s*l\_s*i\_s*a\_s*l\_s*e\_s*s\|L\_s*e\_s*a\_s*d\|白\_s*[板酒金]\|シ\_s*\%(ュ\_s*ー\_s*ド\|ロ\_s*シ\_s*ビ\_s*ン\)\|サ\_s*\%(ー\_s*ム\|イ\_s*\%([ズクケコ]\|ロ\_s*シ\_s*ビ\_s*ン\|リ\_s*ウ\_s*ム\|キ\_s*ッ\_s*ク\)\)\|+\_s*α\|ホ\_s*\%(ン\|ス\_s*ゲ\_s*ン\)\|ヒ\_s*ロ\_s*ポ\_s*ン\|比\_s*\%(布\|律\_s*賓\)\|フ\_s*\%(リ\_s*ジ\_s*ア\_s*ン\|レ\_s*\%(イ\_s*ジ\_s*ン\_s*グ\|ー\_s*\%(ズ\|ジ\_s*ン\_s*グ\)\)\|タ\_s*レ\_s*イ\_s*ン\|ォ\_s*\%([ーンノト]\|ボ\_s*ス\|ビ\_s*ア\|ス\_s*フ\_s*ァ\_s*ー\|ニ\_s*ー\)\|ァ\_s*\%(イ\|ラ\_s*オ\|ー\_s*\%([ジマ]\|ミ\_s*ン\_s*グ\)\|ン\_s*\%(ト\_s*ム\|タ\_s*ズ\_s*[ムマ]\)\|ル\_s*[ツス]\|レ\_s*ノ\_s*プ\_s*シ\_s*ス\)\|ィ\_s*\%([ロル]\|ジ\_s*\%(ッ\_s*ク\_s*ス\|カ\_s*ル\)\|ー\_s*ビ\_s*ー\|ッ\_s*シ\_s*ン\_s*グ\|レ\_s*モ\_s*ン\|ラ\_s*デ\_s*ル\_s*フ\_s*ィ\_s*ア\|リ\_s*\%([スーアパ]\|ッ\_s*[プパ]\|ピ\_s*\%(ン\|ー\_s*ヌ\)\)\)\|ェ\_s*\%(ー\_s*\%([ベズ]\|ジ\_s*ン\_s*グ\)\|イ\_s*ズ\|ロ\_s*モ\_s*ン\|ニ\_s*\%(ル\|ッ\_s*ク\_s*ス\|キ\_s*ア\|ー\_s*ル\)\|ノ\_s*\%(キ\_s*シ\|ー\_s*ル\)\)\)\|述\_s*語\|証\_s*明\|タ\_s*ン\_s*パ\_s*ク\_s*質\|処\_s*理\|手\_s*続\_s*き\|進\_s*行\|算\_s*譜\|利\_s*潤\|南\_s*瓜\|宣\_s*伝\|公\_s*告\|真\_s*珠\|P\_s*\%(波\|L\_s*法\|C\_s*\%(/\_s*A\_s*T\|9\_s*8\|モ\_s*デ\_s*ル\)\|o\_s*s\_s*t\_s*S\_s*c\_s*r\_s*i\_s*p\_s*t\|S\_s*.\|.\_s*S\_s*.\|i\_s*t\_s*I\_s*n\_s*n\|r\_s*o\_s*\%(l\_s*o\_s*g\|t\_s*e\_s*o\_s*n\)\|e\_s*r\_s*\%(l\|i\_s*o\_s*d\)\)\|永\_s*続\|カ\_s*リ\_s*ウ\_s*ム\|葡\_s*萄\_s*牙\|重\_s*合\_s*体\|多\_s*相\_s*型\|バ\_s*テ\_s*レ\_s*ン\|貼\_s*り\_s*付\_s*け\|論\_s*文\|偏\_s*執\_s*[狂病]\|引\_s*数\|リ\_s*ン\|P\_s*\%([umdCaor]\|K\_s*戦\|D\_s*F\_s*フ\_s*ァ\_s*イ\_s*ル\|コ\_s*ー\_s*ド\|タ\_s*イ\_s*ル\|\.\_s*S\_s*\.\|S\_s*\%(\.\|Y\_s*・\_s*S\)\|I\_s*C\_s*マ\_s*イ\_s*コ\_s*ン\|l\_s*\%(a\_s*t\_s*i\_s*n\_s*u\_s*m\|u\_s*t\_s*o\_s*n\_s*i\_s*u\_s*m\)\|E\_s*T\_s*ボ\_s*ト\_s*ル\|O\_s*S\_s*\%(シ\_s*ス\_s*テ\_s*ム\|I\_s*X\|T\_s*メ\_s*ソ\_s*ッ\_s*ド\)\|e\_s*\%(r\_s*l\|n\_s*\%(t\_s*\%(o\_s*x\_s*y\_s*l\_s*i\_s*d\_s*a\_s*e\|i\_s*u\_s*m\)\|n\_s*s\_s*y\_s*l\_s*v\_s*a\_s*n\_s*i\_s*a\)\)\|h\_s*o\_s*s\_s*p\_s*h\_s*o\_s*r\_s*u\_s*s\)\)', + \ 'q' : '\%([配椚橡檪櫪栩椡椪椢湫櫟含纐柵婚屎糞癖潛潜鵠裹凹窪馘括縊踵跟頚軛珞頸首諄鞋履窟寛狐轡覆靴沓碎砕管条降件頽崩屑葛釘莖茎陸杙株杭掘崛倔鶏鐃藥擽薬樟楠髪酒梳櫛串釧與与挫籖鯀鯨鬮籤隈熊艸嚔藾叢鏈腐鎖種Ξξ臭日茸菌楔草圀邦國国髭漱嗽吻嘴喙唇脣蛇梔腔φ劫刧 空粂裙勳熏皹桾皸醺下薫燻訓勲葷君委詳钁精企鍬加咥銜桑塊某暝晦峅競昏冥眛罔鮓較比闇位鞍藏暗倉廚厨涅々〃ゝヽゞ仝ヾ曇雲蜘栗狂包俥車曲廓郭梍枢踝畔鉄鐵★●■玄蔵黒拘食徠久孔桍窶暮焼懼駒柧苦朽区眩吁繰庫垢駆鉤紅呉倶駈汲宮枸劬矩煦驅口9瞿工悔供功吼怐喰玖貢九惧来來區組奇句狗鳩酌絎嶇躯衢屈刳クくq‘“’”♪ケ?ク¶q]\|ッ\_s*ク\|ッ\_s*ク\|っ\_s*く\|姑\_s*娘\|箜\_s*篌\|救\_s*世\|莎\_s*草\|傀\_s*儡\|被\_s*下\_s*度\|百\_s*[濟済]\|果\_s*物\|恭\_s*敬\|9\_s*月\|長\_s*月\|秧\_s*鶏\|究\_s*竟\|釉\_s*掛\|典\_s*薬\_s*寮\|天\_s*鼠\_s*矢\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|探\_s*湯\|誓\_s*湯\|球\_s*磨\|六\_s*合\|地\_s*祇\|都\_s*子\|州\_s*光\|山\_s*梔\_s*子\|崑\_s*央\|群\_s*衆\|慈\_s*姑\|旧\_s*\%(訳\|唐\_s*書\)\|c\_s*r\_s*e\_s*s\_s*c\|海\_s*月\|水\_s*[鶏母]\|内\_s*蔵\_s*助\|K\_s*r\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|公\_s*\%([家方卿界美事文]\|出\_s*挙\)\|佝\_s*僂\_s*病\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|胡\_s*桃\|C\_s*\%(r\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\)\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|Q\_s*&\_s*A\|珠\_s*穆\_s*朗\_s*瑪\|チ\_s*ョ\_s*モ\_s*ラ\_s*ン\_s*マ\|Q\_s*\%(I\_s*C\|R\_s*コ\_s*ー\_s*ド\|C\_s*サ\_s*ー\_s*ク\_s*ル\|U\_s*O\_s*カ\_s*ー\_s*ド\)\|『\_s*』\|コ\_s*\%(ー\_s*ラ\_s*ン\|ン\_s*テ\_s*ィ\_s*フ\_s*ァ\_s*イ\_s*ア\)\|問\_s*合\_s*せ\|カ\_s*\%(ザ\_s*ン\|タ\_s*ー\_s*ル\|ス\_s*バ\|ー\_s*ヌ\_s*ー\_s*ン\|ナ\_s*ー\_s*ト\|ダ\_s*フ\_s*ィ\|リ\_s*テ\|ド\_s*リ\_s*ー\_s*[ルユ]\|ル\_s*\%(チ\_s*[エェ]\|テ\_s*\%(ィ\_s*エ\|ッ\_s*ト\)\)\|ン\_s*タ\_s*[ムスン]\)\|質\_s*問\|キ\_s*\%(ト\|ブ\_s*ラ\|ホ\_s*ー\_s*テ\|ハ\_s*ー\_s*ダ\|ル\_s*\%(ト\|テ\_s*ィ\_s*ン\_s*グ\)\|ー\_s*ン\|ノ\_s*ン\|ッ\_s*シ\_s*ュ\|ュ\_s*\%(ー\|エ\_s*リ\)\)\)', + \ 'r' : '\%([ロ崘侖崙堽栄論漉祿轆碌肋勒麓禄鹿6録蘢滝潦榔簍柆鑞弄咾瑯焜朖螂螻樓隴哢實臈槞僂瓏勞薐琅朧壟撈臘郎瘻廊牢浪蝋癆聾楼篭籠狼漏朗蘆顱炉髏爐櫨蕗賂艪瀘臚枦輅鹵廬櫓轤鷺驢艫櫚滷ろレ洌鴒聆蛎糲綟儷蛉砺苓唳勵〇澪犁齡蠡囹齢黎羚戻禮祈隸茘麗隷玲伶癘励零冷例冽劣烈裂列癧轣檪櫪靂鬲瀝礫轢歴瀲鎌縺嗹漣鏈匳斂濂戀奩輦簾櫺∧聨憐恋蓮煉錬攣練聯廉連れル♪路盧泪壘縲瘰誄涙羸塁累類鏤屡縷褸婁陋璢るリ犂篥葎率慄栗淕勠六戮陸律擽畧暦掠略鏐鉚窿餾畄旒瀏苙霤瑠嶐澑瘤嚠笠榴溜硫琉留立柳粒劉隆流痳鈴麟P懍躪藺鄰棆醂菻廩躙淪厘凜霖琳悋綸淋禀稟凛鱗倫吝隣林燐臨侶絽踉梠膂虜呂慮仂力緑裲鐐椋靈魎崚鬣嶺獵楞怜暸倆繆粮廖兩蓼鷯粱輌凉輛燎瞭聊陵令梁糧諒霊龍凌遼漁亮寮⇔涼繚撩綾療量竜菱僚領喨了稜寥両料閭旅離吏履裡璃理釐痢裏俐俚莅漓利驪李哩梨詈悧罹浬籬里莉りラΛλ亂儖攬覧臠覽瀾欒襴婪繿欖檻籃巒嬾纜襤懶爛藍鸞卵濫闌嵐欄乱蘭労剌溂老埓埒猟薤辣喇樂珞犖絡駱酪烙楽落洛徠蕾賚醴罍櫑擂儡耒籟莱磊癩來礼雷頼来們裸等鑼邏蘿拉螺騾良らr右→ТбуЖВоЙЗЪжзИУЯвяшфКСлЁХпОЦЭЧФЫЩъ魯Бы露ШйхМкПгдмцНЛёаиэетАГчЬюЕЮсьнщД輪根√羅ロ々ラルレリРρΡрr]\|ッ\_s*[ロレルリラ]\|ッ\_s*[ロレルリラ]\|っ\_s*[ろれるりら]\|鱸\_s*魚\|芦\_s*[有花]\|濾\_s*[胞過紙]\|6\_s*[時月]\|水\_s*無\_s*月\|檸\_s*檬\|坩\_s*堝\|A\_s*\%(c\_s*t\_s*a\_s*e\_s*a\|p\_s*o\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|C\_s*\%(a\_s*l\_s*y\_s*c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|h\_s*o\_s*r\_s*i\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|鯉\_s*[魚城]\|二\_s*\%(索\|翻\_s*縛\)\|V\_s*e\_s*r\_s*t\_s*i\_s*c\_s*i\_s*l\_s*l\_s*a\_s*t\_s*a\_s*e\|O\_s*r\_s*c\_s*h\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|M\_s*i\_s*c\_s*r\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\|L\_s*\%([ruia]\|e\_s*i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*a\_s*l\_s*e\_s*s\|A\_s*N\_s*ケ\_s*ー\_s*ブ\_s*ル\)\|海\_s*獺\|G\_s*\%(e\_s*n\_s*t\_s*i\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|y\_s*\%(n\_s*a\_s*n\_s*d\_s*r\_s*a\_s*e\|m\_s*n\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\)\|関\_s*係\_s*デ\_s*ー\_s*タ\_s*ベ\_s*ー\_s*ス\|数\_s*理\_s*解\_s*析\_s*研\_s*究\_s*所\|京\_s*都\_s*大\_s*学\_s*数\_s*理\_s*解\_s*析\_s*研\_s*究\_s*所\|電\_s*気\_s*通\_s*信\_s*研\_s*究\_s*所\|東\_s*北\_s*大\_s*\%(学\_s*電\_s*気\_s*通\_s*信\_s*研\_s*究\_s*所\|通\_s*研\)\|限\_s*定\_s*命\_s*令\_s*セ\_s*ッ\_s*ト\_s*計\_s*算\_s*機\|範\_s*囲\|規\_s*則\|紅\_s*玉\|要\_s*求\|検\_s*索\|復\_s*帰\|返\_s*[事信]\|拒\_s*否\|反\_s*射\_s*鏡\|参\_s*\%(考\_s*文\_s*献\|照\_s*型\)\|R\_s*\%(I\_s*N\_s*A\|&\_s*D\|S\_s*−\_s*2\_s*3\_s*2\_s*C\|u\_s*m\_s*b\_s*l\_s*e\|e\_s*n\_s*o\)\|機\_s*能\_s*回\_s*復\_s*訓\_s*練\|再\_s*帰\_s*的\|認\_s*識\|R\_s*\%([bnfeauh]\|i\_s*c\_s*h\_s*a\_s*r\_s*d\_s* \_s*M\_s*\.\_s* \_s*S\_s*t\_s*a\_s*l\_s*l\_s*m\_s*a\_s*n\|C\_s*S\|S\_s*S\_s*リ\_s*ー\_s*ダ\|I\_s*S\_s*C\|A\_s*M\|O\_s*M\|E\_s*\%(M\_s*睡\_s*眠\|T\_s*U\_s*R\_s*N\_s*キ\_s*ー\|A\_s*D\_s*M\_s*E\)\)\|正\_s*規\_s*表\_s*現\|ア\_s*ー\_s*ル\)', + \ 's' : '\%([ソ似杣灌傍峙毓育具供備害底苑薗園儲酘貮埆妬埣讒譏詆誹謗濡外猝率喞熄仄息足促束測側燥偬雙帚艘箒諍滝嗽剏湊蔟赱鯵抓嫂贈樔屮壯愡葱澡瀧艚勦歃叟裝竈梍蚤甑搶笊窗薮奘崢槽筝菷弉輳爭掫竃譟箱髞嗾懆瘡孀窓踪匝噪遭艙爪糟莊倉淙曹匆怱繰宋漕簇槍躁鎗箏綜喪痩藻艸葬壮操掻掃奏蹌滄争草層創蒼叢僧走惣送叛乖抑諳某橇轌艝鱒邨巽噂拵忖蹲樽孫遜存尊損囎祚租酥措踈鼡阻詛礎疏疎其蘓齟胙副鼠噌反愬蔬沿祖塑姐訴爼逸組俎徂粗麁疽甦沮咀想そセ芹鬩旃錢刋箭羶潛筌孅阡栫舩氈纎濺舛甎銛簽湶茜槧巛吮癬籤倩痊孱擶贍纖仟磚燹揃綫喘涎荐饌槫濳沾籖筅蟾牋苫專翦亘鐫僣韆箋僊殱殲闡釧賎餞羨顫甅竰糎¢陝踐銓閃潺遷銑栴川剪煽譫僉瞻践跣栓疝詮銭穿戰僭繊腺泉嬋擅淺鮮専潜扇蘚船浅線撰宣洗煎戦千忙伜倅逼蝉旋屑鱈薛椄絏洩卩泄紲攝緤褻浙竊℃窃拙摂接節楔關磧蓆晰威裼績蹐迹蹠跖跡瘠藉勣籍淅晢夕鶺潟碩惜析関席隻甥韲嘶菁瀞晟貰擠睛筬淒婿撕牲齏情萋穽躋掣腥逝惺旌蜻整靖誓制晴攻瀬急勢世競畆丗糶畝堰脊せス鯣鋭坐座李既已昴術辷全滑皇脛臑裾双英村選優営寸漱雪濯薦啌勸啜勧芒薄煤賺鼈捩筋頗亮丞甫輔佑祐介助蘇裔陶曽乃曾即則淳漁篶鑾凉漫硯雀涼鱸鮓鮨遊椙犁耒犂篦隙尽末眇縋管菅廢頽廃窘救掬尠寡粭糘菫速純鈴炭角墨隅】【鄒數陬雛芻菘嵩崇趨樞∃∵¬⌒∀÷≠Δ≫⇒∴×∨≧∫∠∇±≪∧∞≒⇔∩∂∈∬∋∝枢錘帥粹騅陲捶忰悴邃瘁翆萃榱隹誰醉遂膵燧彗綏錐穂炊翠⊥H吹粋推水酔睡棲統耡総漉饐住空寿籔醋簾棄直鋤巣栖剥磨梳擂澂掏總剃好過拗澄吸喫据壽透シ埀謐蘂蕋蕊痺褥茵鵐蔀鷸鴫霑入蔵嶌縞嶋島凋澀沫澁渋縛暫屡荵凌鎬忍簧慕舖↓襪健認啝随從从.舌扱罔虐Θθ秕粃椎椣卓尿貎肉臠猪榻黙蜆楙誠茂成繁重惻鋪陣頻閾櫁樒鹽汐潮瑟蛭疾櫛隲隰嫉蟋漆躾膝失室沒鎭沈滴雫賤鎮靜顰尓爾聢確併◇◆鹿貭叱征質卯滋撓科品鬼鍜錏錣痼凝而拉設萎栞襞吝咳爲什導怪汁験記徴著印○〇』銀城代『報調蝨濕湿七僕楚笞霜臀退斥尻冩寫舍者卸柘炙暹諜喋煮這謝鯱奢赦捨瀉妁鑠嚼抉蹟勺決釋皙爍昔斫蜥刳芍酌爵折癪笏赤灼綽石尺借赭写鷓積舎車斜釈社洙麈殳蛛娶株娵諏鬚侏繻銖卒槭蹙俶倏菽叔蓿粥戚肅淑夙粛縮取殊趣珠恤卆蟀出洲泅楸綉溲遒酬鷲駲楫緝嗅葺穐蹤繍螽讐甃萩楢逎讎鰍售岫收驟舅囚姑蓚鞦脩輯醜習羞酋聚舟秀祝袖啾拾蒐収執衆愁襲就臭蹴週終褶州宗椶棕守朱撞種修周手首狩須儁惷悛雋皴墫蕣順蠢舜旬竣峻駿逡筍春瞬俊蓁畛矧縉蔘鷏齔嗔忱譛袗譖娠疹哂脣簪怎晉鷆臻甄槙寢岑瀋箴軫榛秦襯診鉐津駸讖紳斟唇針呻蜃賑芯瞋振殿侵辛薪晨辰震宸森眞愼伸慎寝晋身進深審親臣鍼心宍信神薯墅杵岨且藷黍苜渚砠狙嶼處胥蜍苴曙背塩緒枌雎蔗庶処所書暑奬簫浹橸舂艢廂陞炒鍬庠獎梢璋將厰邵摺淞訟樅筱燮橡餉愴韶誚峭甞姓敞聲懾稍嘗腫政顳枩慯殤秤湫礁井星廠剿妝霎蛸劭觴愀升鬆樵鷦嶂醤従慫逍倡竦爿墻牆薔笙樟装肖菖≦<湘誦聳檣稱声裳)(蒋蕉嘯慴精霄鈔粧彰鏘悚蕭悄瀟哨焦憔匠鍾償瘴漿頌詔沼妾請衝唱薑庄渉奨娼床牀椒抄荘翔鉦宵傷踵銷召賞猩症昭燒猖昌少尚松晶憧紹捷象承證正笑将称焼照勝招章詳消鐘証硝掌省商昇昃禝稷寔矚謖餝稙軾嗇屬穡拭属燭贖色飾囑嘱織蝕式喰蜀殖諸初埴植食職笶姉徙誣氏思染飼祗時弑滲梔摯肢詩咨祉泗輜厶屍強貲若至師舐咫只紙施誌呰示締厮啻次賜熾趾駟漬笥贄此司如沚尸髭肆閉祀鷙諡枝篩豕滓巵始妛及弛絲浸閇斯翅緊帋揣伺為糸駛痣矢死敷恃茨旨沁嘴蚩試釶俟瓷觜廝緇祠梓址詞之使獅志歯紫雌姿柿諮占絞視嗣識子四恣阯侈幟卮凍史領竢市巳祇齒資謚耆覗脂芝痴粢孜錙耜齎自屎茲岐嗤砥仔しサ杓寤雨鮫清鞘莢騷觸触鰆椹爽騒澤沢濬掠新攫杷渫浚更士桾申白素讚戔蒜驂芟鑚爨汕潸斬餐嶄纉攅慘粲蠶跚衫彡杉秋桑…≡簒纂鯢燦珊繖棧刪卅參鑽蚕算傘3贊▼▽3参賛O散惨産酸嘸摩遉樣彷碍妨様山漣蔑貶垂鮭叫仙寞鏥寥皺淋鯆生虱鯖捌偖扨偵宿禎貞定哘誘蝎蠍授皿祥桟匙簓障囁私篠支捧笹逧迫讃鐸蛹宛真尖碕嵜前崎魁峺遮哢囀候侍核実俚説了暁達逹哲諭慧敏叡聰訓知郷恵智聡悟理杆里小棹竿紮刹箚扎皐撮搜寒捜相主盛觚柧盞盃杯榮栄倒肴魚阪界堺境酒泝逆賢坂榊猿麾挟鷺拶撒擦颯先数察薩刷札晒霽濟纔釵綵切崔砦顋樶凄靫洒衰寨悽犲碎腮哉摧灑責偲殺縡淬倖豺呵苛幸猜塞蔡栽儕采齊財臍截載孥宰済齋犀際災柴賽菜採砕妻債斎斉祭催才細鰓裁歳最埼捉縒筴簀柞辟窄咋册齪筰槊酢嘖朔柵遡溯鑿索搾昨炸冊策錯櫻桜注曝瑳冴磋搓槎刺覺莎作挿嗟紗嵯覚做削冱寂叉荒茶渣左再早避咲査嵳褪挫佐然唆蹉鎖裂醒瑣嗄螫娑砂割蓑狭狹扠些差梭射銹沙下冷捺簑插点止提柤錆乍去裟詐さ√錫す/仕指製西 ┓┐〆□■Шш上#♯щЩ添∪日s⊂⊆⊃⊇文静★*☆標嗜青三聖土彩▲△悉署〜∽’‘┏┌集\探§″性セサシソスΣсСσ秒s]\|ッ\_s*[ソセスシサ]\|ッ\_s*[ソセスシサ]\|っ\_s*[そせすしさ]\|遽\_s*走\|蕎\_s*麦\|内\_s*障\|彼\_s*杵\|諷\_s*歌\|幾\_s*許\|錚\_s*[錚々]\|十\_s*\%(路\|露\_s*盤\)\|冬\_s*青\|微\_s*風\|虚\_s*言\|宙\_s*組\|夫\_s*[夫々]\|返\_s*田\|傴\_s*僂\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|台\_s*詞\|c\_s*e\_s*n\_s*t\_s*i\|妹\_s*尾\|嘲\_s*笑\|海\_s*象\|蒸\_s*[籠篭]\|魑\_s*魅\|凡\_s*て\|典\_s*侍\|季\_s*雄\|天\_s*[皇蛾]\|蘿\_s*蔔\|V\_s*i\_s*o\_s*l\_s*a\_s*l\_s*e\_s*s\|N\_s*y\_s*m\_s*p\_s*h\_s*a\_s*e\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|夊\_s*繞\|隧\_s*道\|C\_s*\%(型\|言\_s*語\)\|老\_s*舗\|望\_s*潮\|飛\_s*沫\|L\_s*a\_s*\%(m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|b\_s*i\_s*a\_s*t\_s*a\_s*e\)\|埋\_s*葬\_s*虫\|幣\_s*原\|桎\_s*梏\|柳\_s*葉\_s*魚\|衣\_s*魚\|蠹\_s*魚\|汚\_s*点\|惠\_s*雄\|舗\_s*石\|磯\_s*城\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|倭\_s*文\|閑\_s*[谷か]\|云\_s*[々云]\|明\_s*\%(々\_s*後\_s*日\|明\_s*後\_s*日\)\|7\_s*月\|7\_s*月\|4\_s*月\|4\_s*[分月]\|羊\_s*[齒歯]\|I\_s*\%(l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|不\_s*[忍知]\|後\_s*\%([輪口志目]\|込\_s*み\)\|軍\_s*鶏\|香\_s*菜\|吃\_s*逆\|蝦\_s*蛄\|輸\_s*[出贏]\|隼\_s*[朗郎]\|笋\_s*[干羹]\|縦\_s*容\|睫\_s*毛\|翡\_s*翠\|東\_s*\%(雲\|海\_s*林\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|続\_s*\%(日\_s*本\_s*\%(紀\|後\_s*紀\)\|後\_s*撰\_s*和\_s*歌\_s*集\)\|髑\_s*髏\|匣\_s*鉢\|復\_s*習\|百\_s*日\_s*紅\|胡\_s*孫\_s*眼\|←\_s*→\|霰\_s*弾\|弥\_s*生\|懺\_s*\%(法\|悔\_s*懺\_s*悔\)\|流\_s*[離石]\|蠑\_s*螺\|覇\_s*王\_s*樹\|C\_s*\%([se]\|y\_s*c\_s*a\_s*d\_s*\%(i\_s*d\_s*a\_s*e\|o\_s*\%(p\_s*s\_s*i\_s*d\_s*a\|f\_s*i\_s*l\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\)\|h\_s*l\_s*o\_s*r\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|言\_s*語\|D\_s*店\|型\_s*肝\_s*炎\|a\_s*\%(s\_s*s\_s*y\_s*t\_s*h\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|c\_s*t\_s*a\_s*l\_s*e\_s*s\)\)\|竹\_s*[篦刀筒]\|大\_s*角\_s*豆\|防\_s*人\|曩\_s*に\|向\_s*坂\|一\_s*昨\_s*\%(々\_s*[年日]\|昨\_s*[年日]\)\|實\_s*藤\|甘\_s*藷\|五\_s*月\|月\_s*代\|匂\_s*坂\|税\_s*所\|雑\_s*賀\|骰\_s*子\|P\_s*\%(a\_s*r\_s*i\_s*e\_s*t\_s*a\_s*l\_s*e\_s*s\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|r\_s*i\_s*m\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\)\|A\_s*\%(p\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*a\_s*l\_s*e\_s*s\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\)\|瑞\_s*[典西]\|B\_s*\%(r\|シ\_s*ェ\_s*ル\)\|拡\_s*張\_s*子\|部\_s*分\|置\_s*換\|ア\_s*ン\_s*チ\_s*モ\_s*ン\|構\_s*造\_s*体\|M\_s*\%(e\_s*r\_s*c\_s*u\_s*r\_s*y\|u\_s*s\_s*a\_s*l\_s*e\_s*s\|a\_s*r\_s*q\_s*u\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\)\|D\_s*o\_s*n\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*A\_s*l\_s*p\_s*h\_s*o\_s*n\_s*s\_s*e\_s* \_s*F\_s*r\_s*a\_s*n\_s*c\_s*o\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\|加\_s*\%(之\|虐\_s*\%(趣\_s*味\|淫\_s*乱\_s*症\)\)\|T\_s*\%(e\_s*t\_s*r\_s*a\_s*c\_s*e\_s*n\_s*t\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\|h\_s*e\_s* \_s*S\_s*i\_s*m\_s*p\_s*l\_s*e\_s* \_s*A\_s*P\_s*I\_s* \_s*f\_s*o\_s*r\_s* \_s*e\_s*v\_s*e\_s*n\_s*t\_s*-\_s*b\_s*a\_s*s\_s*e\_s*d\_s* \_s*X\_s*M\_s*L\_s* \_s*p\_s*a\_s*r\_s*s\_s*i\_s*n\_s*g\)\|珪\_s*素\|ケ\_s*イ\_s*素\|計\_s*測\_s*自\_s*動\_s*制\_s*御\_s*学\_s*会\|ネ\_s*ッ\_s*ト\_s*サ\_s*ー\_s*ビ\_s*ス\|ザ\_s*\%(ッ\_s*ク\|ク\_s*セ\_s*ン\|ビ\_s*ー\_s*ネ\|ウ\_s*バ\_s*ー\|ワ\_s*ー\_s*ク\_s*ラ\_s*ウ\_s*ト\|ム\_s*ザ\|ル\_s*ツ\|イ\_s*\%([ルン]\|ラ\_s*ー\|デ\_s*ル\)\|ー\_s*\%([ルラ]\|メ\_s*ン\)\)\|意\_s*味\|ゼ\_s*ミ\|ナ\_s*ト\_s*リ\_s*ウ\_s*ム\|ゾ\_s*\%(ル\|ン\_s*デ\|ー\_s*\%(ム\|リ\_s*ン\_s*ゲ\_s*ン\)\|フ\_s*ィ\_s*ー\)\|ジ\_s*\%(ム\|ー\_s*\%([グク]\|メ\_s*ン\_s*[スズ]\)\|グ\_s*ム\_s*ン\_s*ト\|ン\_s*\%(メ\_s*ル\|グ\_s*シ\_s*ュ\_s*ピ\_s*ー\_s*ル\|テ\_s*ー\_s*ゼ\)\)\|S\_s*\%([席式]\|サ\_s*イ\_s*ズ\|S\_s*サ\_s*イ\_s*ズ\|m\_s*a\_s*l\_s*l\_s*t\_s*a\_s*l\_s*k\|p\_s*a\_s*i\_s*n\|c\_s*o\_s*t\_s*c\_s*h\|U\_s*N\|u\_s*\%(n\|p\_s*e\_s*r\_s*A\_s*s\_s*c\_s*i\_s*i\)\|I\_s*C\_s*P\_s*(\_s*S\_s*t\_s*r\_s*u\_s*c\_s*t\_s*u\_s*r\_s*e\_s* \_s*a\_s*n\_s*d\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*p\_s*r\_s*e\_s*t\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*o\_s*f\_s* \_s*C\_s*o\_s*m\_s*p\_s*u\_s*t\_s*e\_s*r\_s* \_s*P\_s*r\_s*o\_s*g\_s*r\_s*a\_s*m\_s*s\_s*)\|−\_s*e\_s*x\_s*p\_s*r\_s*e\_s*s\_s*s\_s*i\_s*o\_s*n\|O\_s*N\_s*Y\_s* \_s*N\_s*E\_s*W\_s*S\|o\_s*l\_s*a\_s*r\_s*i\_s*s\|y\_s*s\_s*V\)\|エ\_s*ス\|S\_s*\%([nrgmce式]\|G\_s*M\_s*L\|サ\_s*イ\_s*ズ\|S\_s*サ\_s*イ\_s*ズ\|F\_s*マ\_s*ガ\_s*ジ\_s*ン\|Q\_s*U\_s*A\_s*R\_s*E\_s* \_s*E\_s*N\_s*I\_s*X\|K\_s*\%(K\|Y\_s* \_s*P\_s*e\_s*r\_s*f\_s*e\_s*c\_s*T\_s*V\_s*!\)\|a\_s*\%(r\_s*\%(r\_s*a\_s*c\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|g\_s*e\_s*n\_s*t\_s*o\_s*d\_s*o\_s*x\_s*a\_s*c\_s*e\_s*a\_s*e\)\|m\_s*a\_s*r\_s*i\_s*u\_s*m\)\|M\_s*\%(プ\_s*レ\_s*イ\|ク\_s*ラ\_s*ブ\)\|P\_s*\%(レ\_s*コ\_s*ー\_s*ド\|A\_s*C\_s*E\_s*キ\_s*ー\)\|p\_s*\%(l\_s*u\_s*s\|e\_s*\%(r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*a\_s*l\_s*i\_s*t\_s*y\_s* \_s*S\_s*t\_s*o\_s*r\_s*e\_s* \_s*R\_s*e\_s*t\_s*a\_s*i\_s*l\_s*e\_s*r\_s* \_s*o\_s*f\_s* \_s*P\_s*r\_s*i\_s*v\_s*a\_s*t\_s*e\_s* \_s*L\_s*a\_s*b\_s*e\_s*l\_s* \_s*A\_s*p\_s*p\_s*a\_s*r\_s*e\_s*l\)\|a\_s*\%(t\_s*h\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*c\)\)\|H\_s*I\_s*F\_s*T\_s*キ\_s*ー\|C\_s*S\_s*I\|T\_s*\%(k\|A\_s*R\)\|h\_s*u\_s*g\_s*a\_s*r\_s*t\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*s\_s* \_s*S\_s*y\_s*s\_s*t\_s*e\_s*m\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*f\_s*a\_s*c\_s*e\|A\_s*\%(P\|S\_s*I\)\|i\_s*\%(m\_s*p\_s*l\_s*e\_s* \_s*K\_s*a\_s*n\_s*a\_s* \_s*t\_s*o\_s* \_s*K\_s*a\_s*n\_s*j\_s*i\_s* \_s*c\_s*o\_s*n\_s*v\_s*e\_s*r\_s*s\_s*i\_s*o\_s*n\_s* \_s*p\_s*r\_s*o\_s*g\_s*r\_s*a\_s*m\|l\_s*i\_s*c\_s*o\_s*n\)\|t\_s*r\_s*o\_s*n\_s*t\_s*i\_s*u\_s*m\|o\_s*\%(u\_s*t\_s*h\_s* \_s*\%(D\_s*a\_s*k\_s*o\_s*t\_s*a\|C\_s*a\_s*r\_s*o\_s*l\_s*i\_s*n\_s*a\)\|l\_s*a\_s*r\_s*i\_s*s\|f\_s*t\_s*w\_s*a\_s*r\_s*e\_s* \_s*R\_s*e\_s*s\_s*e\_s*a\_s*r\_s*c\_s*h\_s* \_s*A\_s*s\_s*s\_s*o\_s*c\_s*i\_s*a\_s*t\_s*e\_s*,\_s*I\_s*n\_s*c\_s*\.\)\|u\_s*\%(n\|l\_s*f\_s*u\_s*r\)\)\|硫\_s*黄\)', + \ 't' : '\%([ト乕囚寅虎瀞侶靹舮供纜燭艫朋倶鞆讐讎輩伴共友巴惇沌團団暾丼飩遯燉遁豚禽鷄酉砦塞擒俘虜豐恍惚枢乏塒迚科咎篷笘攴苫鶏伽唱稱鄰隣朿棘刺整鎖處処所床享鴟鵄扉鳶嫁訥刻秋穐晨鴇鬨斎頓幄幃帷柮杤栃閼軣轟屆届咄吶凸駿祀世暁壽繁稔寿豊歳俊利敏年牘悳犢黷慝匿督徳涜∃得特儻釖盜沓納道宕嶝涛萄嶋鬧縢帑塘搨棠樋籘閙梼罩叨夲盪酘兜溏朸稻鞜荅鞳桶黨綯迯鬥擣礑櫂剳淌纛諮棹陦檮磴蘯橦抖榻嶌竇档潼吋鐙亠篤滕讀逗螳蟷稲■鼕幢滔掏當峠読饕疼淘濤籐董悼棟搭痘套=豆燈桃韜統遠騰橈冬討祷骰藤灯島橙凍刀陶糖謄唐投答等桐鍍研鎔外採盗杜荼覩人摂脱屠賭蠧圖秉觧堵兔礪疾執蚪閇熔登畄砺解睹十菟砿溶獲渡留融泊蠹穫飛磨梳妬説録冨取問途莵汢戸図止翔兎跿富塗砥肚とテ瑛晃輝衒寺忝壥靦巓霑殄、鷏躔諂廛碾沾,鷆腆囀槙轉‥:.輾填甜奠顛纒癲恬殿纏展覘篆添梃輦咥垤餮屮銕鐡耋姪跌輟迭逖荻俶廸狄鏑糴笛覿擲迪滴轍的哲敵撤剔徹鐵鉄楴嚏幀鵜羝睇汀棣騁酲柢叮嚔酊掟遉觝釘詆渟眤碵弟碇剃蹄邸締梯悌訂程底偵遞廷逓牴抵呈艇鄭涕啼庭定低照弖てツ模幹劈聾辛列貫面汁液露冷錘舶紡系艷艶寉鉉絃橡劒釼剱劔劍剣弦蔓敦鶴幣兵鉗噤鶫償桓恆典恒常夙勉務努勤拙拐抓倹嬬撮詳審爪褄妻募角晦瞑螺円呟礫具粒辻辟罪捉把閊捕寮曹首阜丘元司官柄仕掴遣攫搏疲使窄莟蕾局壷壺坪綱繋壌蝪培霾戊己伝傳鐔翼翅鍔燕唾續約皷鼓続葛綴番栂槌縋弊費序潰終墜遂鎚椎追做殲捏殱繕傍旁創造作熟机佃蹲拒欟坏鴾槻月障砲裹躑榴謹慎愼恙筒包堤痛衝尾突尽支攣就次付椄漬點津附浸繼撞憑盡継嗣搗詰積接通告連つチ吃釁巷岐衢粽粡因杠契鵆児交腟帙膣些蟄N窒斉秩父捷矗筑築逐盟税力親邇誓迩近苣尖縮鏤塵趁碪珎鎭亭抻朕狆跛闖鴆砧椿枕鎮陳珍沈賃杖找摘茶嫡着豬儲杼潴紵竚瀦躇箸墸苧緒樗楮⊥躅陟猪捗稙飭敕勅著佻髫鼎迢膓萇脹樢吊漲趙鵈輙雕鬯聽廰窕楪挺輒齠悵塚疔糶澂廳蔦晁昶甼誂微凋帖掉停諜跳眺貼鐇澄提喋頭銚ー蝶暢帳丁牒重逃鳥張弔懲肇徴嘲兆釣聴彫潮町頂調貂庁腸超挑朝丶黜綢儔廚丑※惆肘籌寵鍮冢晝蟲胄冑紬稠酎紐鑄冲沖偸宙虫]}{[厨誅鋳紂仲註駐柱注衷籀昼抽中治池岻恥散躓置耻血値夊輊遲笞千稚黹馳家蜘禿穉地魑黐乳智癡致薙褫茅踟緻痴夂知遅ちタ便党屯架椽榱樽弛蕩膤鰔鱈盥戯俵袂保躊為樣様爲袒慱彖壇覃膽疸亶靼憺餤緞憚擔褝啗檀綻攤槫站酖殫毯猯潭鄲襌賺椴摶湍湯澹†‡蛋耽W旦痰啖坦眈反C歎嘆誕胆箪譚担淡鍛短單貪探単覊栲妙戲訊攜携尋訪比畴疇類民髱樂娯恃頼愉楽喩例譬滾激斃仆垰嵶殕倒嫋旅貍狸賛敲称讃蹈踏祟湛鬪斗戰闘戦彳佇叩疂疉疊畳箍鏨違互耕畊畉掌店棚到炭辿撻闥斬燵韃巽辰+援佐扶相輔佑弼助襷髻椨誑胤種塔龍竜糺糜爛漂維伊是理禎直貞惟忠匡徒唯只窘嗜慥確胝鱆鮹凧蛸誥嶽哮茸英豪威毅猛笋筍酣雄健丈斌武靈彈珪承賚珠霊魂卵偶適環弾球玉丹謀莨束縱|盾鬣奉楯蓼縦竪城質達館忽橘舘瀑薪滝瀧峪溪渓谿谷任尭宇亨臣集昂楼小剛恭岳洪喬嵩尚孚崇尊敬孝隆貴鷹竹篁簟寶財高寳宝但柝拆倬鈬濯魄擢擇柘戳啅鐸澤綰畜企啄磔匠巧択沢逞琢蓄度宅託卓謫托拓紿軆隶殆黛帶替靆抬體躰滯碓平駘擡逮腿当怠玳諦岱鯛對颱袋戴堆態頽苔滞待代帝貸隊褪胎帯体泰退大対矯食埀断炊闌佗長強焚岔給蛇夛足賜揉閉立發躱詫太経貯起薫耐溜絶発手它朶多他勃詑垂誰撓斷裁咤点汰建堪澑田截逹侘經たtЦц〜天時×型火土→都吐東上噸瓲│┃台表第木スジ∴Θθザ正ツ¨転透▲△▼▽トチ・…試端タТ├┸┳┨┫┝┬〒┷τ┯┤┣┻Τテ┥┰т┠┴t]\|ッ\_s*[トテツチタ]\|ッ\_s*[トテツチタ]\|っ\_s*[とてつちた]\|門\_s*渡\_s*り\|薯\_s*蕷\|船\_s*尾\_s*座\|公\_s*[暁明]\|倫\_s*[子明]\|邑\_s*中\|蜻\_s*蛉\|A\_s*c\_s*o\_s*n\_s*i\_s*t\_s*u\_s*m\|蜷\_s*局\|跡\_s*[絶切]\|蜥\_s*蜴\|舎\_s*人\|馴\_s*鹿\|野\_s*老\|瓊\_s*脂\|永\_s*[遠久]\|宿\_s*直\|朱\_s*鷺\|左\_s*見\_s*右\_s*見\|朽\_s*木\|H\_s*y\_s*d\_s*r\_s*o\_s*c\_s*h\_s*a\_s*r\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|独\_s*鈷\|季\_s*[衣道栄]\|聡\_s*[明徳]\|祈\_s*年\_s*祭\|淑\_s*[夫子]\|洞\_s*爺\|光\_s*男\|晧\_s*史\|紅\_s*娘\|瓢\_s*虫\|F\_s*e\|I\_s*r\_s*o\_s*n\|劇\_s*村\|滌\_s*除\|2\_s*×\_s*4\|石\_s*\%(蕗\|竜\_s*子\)\|心\_s*[太算]\|自\_s*\%(摸\|模\_s*和\)\|氷\_s*柱\|倩\_s*々\|黴\_s*雨\|入\_s*梅\|梅\_s*雨\|再\_s*見\|備\_s*に\|悉\_s*に\|旋\_s*[風毛]\|B\_s*a\_s*l\_s*a\_s*n\_s*o\_s*p\_s*h\_s*o\_s*r\_s*a\_s*l\_s*e\_s*s\|1\_s*\%(日\|0\_s*日\)\|1\_s*\%(日\|0\_s*日\)\|朔\_s*日\|美\_s*人\_s*局\|E\_s*\%(u\_s*p\_s*h\_s*o\_s*r\_s*b\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|字\_s*\%(牌\|一\_s*色\)\|少\_s*と\|義\_s*父\|主\_s*[殿税]\|周\_s*夫\|睦\_s*子\|渠\_s*睦\_s*子\|萵\_s*苣\|身\_s*柱\|似\_s*指\|清\_s*\%(老\_s*頭\|一\_s*色\)\|青\_s*\%([幇島]\|梗\_s*菜\|椒\_s*肉\_s*絲\)\|全\_s*帯\|昌\_s*洙\|江\_s*蘇\|J\_s*i\_s*a\_s*n\_s*g\_s*s\_s*u\|焼\_s*豚\|叉\_s*焼\|察\_s*哈\_s*爾\|餃\_s*子\|雑\_s*砕\|炒\_s*[麺飯]\|北\_s*谷\|甘\_s*露\_s*子\|錯\_s*和\|総\_s*角\|一\_s*[日寸]\|植\_s*字\|金\_s*魚\_s*蝨\|魚\_s*[屋蝨]\|草\_s*石\_s*蚕\|春\_s*\%(麗\|宮\_s*坊\)\|九\_s*\%(十\_s*九\|連\_s*宝\_s*[燈灯]\)\|揺\_s*蕩\|容\_s*易\|白\_s*痴\|猶\_s*豫\|蜑\_s*民\|段\_s*銭\|蒲\_s*公\_s*英\|騨\_s*州\|M\_s*\%(e\_s*n\_s*i\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*c\_s*e\_s*a\_s*e\|o\_s*n\_s*o\_s*\%(p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*\%(h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|o\_s*t\_s*y\_s*l\_s*e\_s*d\_s*o\_s*n\_s*e\_s*a\_s*e\)\)\)\|仮\_s*令\|打\_s*[擲坐]\|七\_s*\%(夕\|対\_s*子\)\|活\_s*計\|方\_s*便\|無\_s*料\|黄\_s*\%(昏\|蜀\_s*葵\)\|胼\_s*胝\|章\_s*魚\|P\_s*\%(\.\_s*S\_s*\.\|o\_s*l\_s*y\_s*\%(g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*r\_s*p\_s*i\_s*c\_s*a\_s*e\)\|a\_s*n\_s*d\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|壮\_s*聡\|煙\_s*草\|殺\_s*陣\|賢\_s*明\|性\_s*質\|怱\_s*ち\|亢\_s*ぶ\|堂\_s*子\|学\_s*聡\|能\_s*[文之]\|内\_s*匠\|松\_s*明\|奈\_s*子\|幇\_s*間\|切\_s*符\|デ\_s*ィ\_s*ス\|3\_s*r\_s*d\|閾\_s*値\|ソ\_s*\%(ー\_s*[トンプ]\|ロ\_s*ー\)\|ヘ\_s*ー\_s*グ\|ゼ\_s*[インムア]\|セ\_s*\%(オ\|ル\_s*マ\|ロ\_s*\%(ン\|ニ\_s*ア\_s*ス\)\|ラ\_s*ピ\_s*\%(ー\|ス\_s*ト\)\)\|シ\_s*\%(ン\|ッ\_s*ク\|ス\_s*ル\|ア\_s*タ\_s*ー\|ソ\_s*ー\_s*ラ\_s*ス\|オ\_s*ド\_s*ア\|ー\_s*[フタ]\)\|サ\_s*\%([イム]\|ミ\_s*ン\_s*グ\|ウ\_s*ザ\_s*ン\_s*ド\|ラ\_s*ブ\_s*レ\_s*ッ\_s*ド\|ー\_s*\%([ドモ]\|テ\_s*ィ\|ス\_s*ト\_s*ン\|ズ\_s*デ\_s*[イーィ]\|マ\_s*ル\)\|ッ\_s*チ\_s*ャ\_s*ー\|ン\_s*\%(ク\|ダ\_s*ー\|キ\_s*ュ\_s*ー\)\|リ\_s*ド\_s*マ\_s*イ\_s*ド\)\|ポ\_s*リ\_s*ペ\_s*プ\_s*チ\_s*ド\|三\_s*\%(和\_s*土\|連\_s*文\_s*字\)\|\\\_s*T\_s*e\_s*X\|教\_s*科\_s*書\|文\_s*字\_s*列\|用\_s*語\|T\_s*\%([字i]\|細\_s*胞\|K\_s*8\_s*0\|ゾ\_s*ー\_s*ン\|バ\_s*ッ\_s*ク\|シ\_s*ャ\_s*ツ\|V\_s*\%(ニ\_s*ュ\_s*ー\_s*ス\|ゲ\_s*ー\_s*ム\|ド\_s*ラ\_s*マ\|ア\_s*ニ\_s*メ\)\|C\_s*P\_s*/\_s*I\_s*P\|a\_s*g\|r\_s*u\_s*e\_s*T\_s*y\_s*p\_s*e\|E\_s*X\|e\_s*[Xl]\)\|T\_s*\%([bc字mliahe]\|r\_s*i\_s*m\_s*e\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\|ゾ\_s*ー\_s*ン\|X\_s*T\_s*フ\_s*ァ\_s*イ\_s*ル\|シ\_s*ャ\_s*ツ\|バ\_s*ッ\_s*ク\|V\_s*\%(ニ\_s*ュ\_s*ー\_s*ス\|ゲ\_s*ー\_s*ム\|ド\_s*ラ\_s*マ\|モ\_s*ニ\_s*タ\|ア\_s*ニ\_s*メ\|シ\_s*ョ\_s*ッ\_s*ピ\_s*ン\_s*グ\)\|C\_s*P\|コ\_s*ー\_s*ド\|-\_s*C\_s*o\_s*d\_s*e\|O\_s*E\_s*I\_s*C\|A\_s*\%(C\|I\_s*N\_s*S\|B\_s*キ\_s*ー\)\|E\_s*L\)\|電\_s*\%([視話]\|気\_s*通\_s*信\_s*研\_s*究\_s*所\)\)', + \ 'u' : '\%([ウ孳蛤礼敬恭洞鱗愛潤騒煩粳漆閏患慯悄騷恙愁呻楳梅嫐釉噂耘吽褞曇黄紜云繧慍薀蘊暈運錙怏麗羨卦憾怨恨占卜末嬉心裏浦糶瓜汝己畴畆畦疇畝踈疎宜諾奪姥腕莵兔驢鑿穿嗽魘唸促令項頷訴獺鷽嘯嘘蠕蠢動覘窺伺海台萼唱詠謌唄宴讌転詩謠謡謳疑歌葎鯏鴬鶯ヱゑゐヰ鶉疼堆踞蹲渦舂臼碓羅薄食筌槽朮肯凵魚巧茨廐廏厩鰻午甘秣孫餞馬旨冩遷寫蔚暎噐器移慈俯映写現虚美笂靭靱靫空鰾萍初蛆雲氏上後喪艮丑潮牛裡鬱中欝袿梁家内禹憂埋挧撃雨打宇得植請鵜熟績嫗攴有夘受茹泛生討羽胡右紆傴盂饂承菟飢烏攵于射倦芋賣卯享搏失齲撲兎売産膿迂浮うu¨↑∪υウUуУΥu]\|武\_s*漢\|狼\_s*狽\|夏\_s*枯\_s*草\|蠎\_s*蛇\|蟒\_s*蛇\|譫\_s*言\|琅\_s*珠\|温\_s*[麺気州]\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|自\_s*惚\|采\_s*女\|乳\_s*母\|姨\_s*捨\_s*山\|独\_s*活\|優\_s*\%(婆\_s*[塞夷]\|曇\_s*華\)\|合\_s*格\|親\_s*族\|斥\_s*候\|泡\_s*沫\|楽\_s*官\|雅\_s*楽\_s*[頭寮]\|干\_s*莉\|維\_s*納\|太\_s*秦\|護\_s*田\_s*鳥\_s*尾\|淡\_s*\%(青\|口\_s*醤\_s*油\)\|五\_s*\%(加\|月\_s*蝿\)\|稲\_s*魂\|誓\_s*約\|石\_s*\%(女\|斑\_s*魚\)\|不\_s*生\_s*女\|味\_s*酒\|苜\_s*蓿\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|伝\_s*染\|呆\_s*気\_s*者\|茴\_s*香\|外\_s*郎\|餓\_s*\%(死\|え\_s*死\_s*に\)\|裲\_s*襠\|団\_s*扇\|イ\_s*ギ\_s*リ\_s*ス\|オ\_s*マ\_s*ル\|識\_s*別\_s*不\_s*能\|共\_s*\%(用\_s*体\|有\_s*体\)\|ア\_s*\%([スン]\|グ\_s*リ\_s*ー\|ー\_s*\%(シ\_s*ュ\_s*ラ\|ジ\_s*ェ\_s*ン\_s*ト\|バ\_s*ン\)\|ル\_s*テ\_s*ィ\_s*メ\_s*ッ\_s*ト\|ポ\_s*ン\|ッ\_s*\%(プ\|パ\_s*ー\|シ\_s*ャ\_s*ー\)\)\|単\_s*\%(位\|一\_s*化\)\|U\_s*\%(ボ\_s*ー\_s*ト\|タ\_s*ー\_s*ン\|ネ\_s*ッ\_s*ク\|N\_s*I\_s*X\_s*\%(フ\_s*ェ\_s*ア\_s*ー\|マ\_s*ガ\_s*ジ\_s*ン\)\)\|ユ\_s*\%([タニー]\|ト\_s*\%(リ\_s*ロ\|レ\_s*ヒ\_s*ト\)\|リ\_s*\%(ア\|シ\_s*ー\_s*ズ\)\|プ\_s*シ\_s*ロ\_s*ン\|ネ\_s*ス\_s*コ\|ナ\_s*\%(カ\_s*イ\_s*ト\|イ\_s*テ\_s*ッ\_s*ド\)\|ビ\_s*キ\_s*\%(タ\_s*ス\|ノ\_s*ン\)\)\)', + \ 'v' : '\%([v:├値⊥版Вв↓∨ヴv]\|ッ\_s*ウ\_s*゙\|ッ\_s*ヴ\|っ\_s*ヴ\|ウ\_s*゙\|チ\_s*ェ\_s*ロ\|ヰ\_s*タ\| \_s*ビ\_s*ク\_s*ト\_s*ー\_s*ル\|視\_s*覚\|仮\_s*想\|ニ\_s*ス\|変\_s*数\|恒\_s*真\|ワ\_s*\%(デ\_s*ィ\_s*ム\|ギ\_s*ナ\|ニ\_s*ス\|セ\_s*リ\_s*ン\|ク\_s*チ\_s*ン\|ル\_s*キ\_s*ュ\_s*ー\_s*レ\|レ\_s*リ\_s*ー\|ー\_s*ニ\_s*ャ\)\|V\_s*\%(c\|ゾ\_s*ー\_s*ン\|サ\_s*イ\_s*ン\|ネ\_s*ッ\_s*ク\|ゴ\_s*ー\_s*ル\|シ\_s*ネ\|リ\_s*ー\_s*グ\|i\_s*e\_s*w\|a\_s*l\_s*u\_s*e\|o\_s*l\_s*k\_s*l\)\|語\_s*彙\|ボ\_s*\%(ス\_s*ト\_s*ー\_s*ク\|ン\_s*ゴ\_s*レ\|ル\_s*\%([ガボトタ]\|テ\_s*\%(ッ\_s*ク\_s*ス\|ー\_s*[ジル]\)\)\|リ\_s*ュ\_s*ー\_s*ム\|ラ\_s*ン\_s*\%(チ\|テ\_s*ィ\_s*ア\|タ\_s*リ\_s*ー\)\|レ\_s*ー\|コ\_s*ー\_s*ダ\|ー\_s*\%([ントグ]\|ル\_s*ト\|ド\_s*ビ\_s*\%(ル\|リ\_s*ア\_s*ン\)\|パ\_s*ル\|ダ\_s*フ\_s*ォ\_s*ン\|カ\_s*\%(ル\|リ\_s*ス\_s*ト\)\)\|キ\_s*ャ\_s*ブ\_s*ラ\_s*リ\|イ\_s*\%([ドス]\|ジ\_s*ャ\_s*ー\|シ\_s*ン\_s*グ\)\)\|ヘ\_s*ッ\_s*ト\|冗\_s*長\_s*な\|垂\_s*直\|フ\_s*\%(ァ\_s*\%(ン\|ド\_s*ー\_s*ツ\)\|ォ\_s*\%(ン\|ル\_s*\%(ク\|カ\_s*ー\)\)\|ェ\_s*ル\_s*メ\_s*ー\_s*ル\)\|ウ\_s*\%(ラ\_s*\%(デ\_s*ィ\_s*ミ\_s*ー\_s*ル\|ジ\_s*\%(ミ\_s*ー\_s*ル\|ー\_s*ミ\_s*ル\|オ\_s*ス\_s*ト\_s*\%(ク\|ッ\_s*ク\)\)\)\|ィ\_s*\%(ン\_s*ナ\|ル\_s*ス\)\|ォ\_s*ッ\_s*カ\|イ\_s*\%(ル\_s*ス\|ン\_s*ナ\_s*ー\)\|ェ\_s*\%(ル\_s*ギ\_s*リ\_s*ウ\_s*ス\|ヌ\_s*ス\)\)\|ビ\_s*\%([アラブバスザ]\|ガ\_s*ー\|ハ\_s*ー\_s*ラ\|タ\_s*ミ\_s*ン\|レ\_s*\%(ッ\_s*ジ\|ロ\_s*イ\)\|ビ\_s*\%(ア\_s*ン\|ッ\_s*ド\)\|ッ\_s*\%(ク\|キ\_s*ー\)\|セ\_s*ン\_s*テ\|ク\_s*\%(タ\_s*ー\|ト\_s*\%(ル\|リ\_s*[ーア]\)\)\|シ\_s*\%(ャ\_s*ス\|ソ\_s*ワ\_s*ー\_s*ズ\)\|ン\_s*\%([チス]\|ソ\_s*ン\|テ\_s*ー\_s*ジ\|セ\_s*ン\_s*ト\)\|ネ\_s*\%(ガ\_s*ー\|グ\_s*レ\_s*ッ\_s*ト\)\|ニ\_s*\%([ール]\|リ\_s*デ\_s*ン\)\|ュ\_s*ー\|エ\_s*ン\_s*チ\_s*ャ\_s*ン\|ジ\_s*\%(ャ\|ッ\_s*ト\|タ\_s*ー\|ョ\_s*\%(ン\|ナ\_s*リ\_s*ー\)\|ュ\_s*ア\_s*\%(ル\|ラ\_s*イ\_s*\%(ズ\|ゼ\_s*ー\_s*シ\_s*ョ\_s*ン\)\)\)\|ダ\_s*ル\|デ\_s*オ\|ル\_s*\%(ゴ\|ヌ\_s*ー\_s*ブ\)\|オ\_s*ラ\|リ\_s*ジ\_s*ア\_s*ン\|ィ\_s*ー\_s*ナ\_s*ス\|ー\_s*\%(ボ\|ル\_s*ス\|ク\_s*ル\|ナ\_s*ス\)\)\|ベ\_s*\%([ガラン]\|ト\_s*ナ\_s*ム\|イ\_s*ダ\_s*ー\|ー\_s*\%(ル\|ダ\_s*ー\)\|テ\_s*ラ\_s*ン\|ッ\_s*セ\_s*ル\|ス\_s*\%([トタパ]\|ビ\_s*オ\)\|ク\_s*\%(タ\|ト\_s*ル\)\|ジ\_s*タ\_s*\%(ブ\_s*ル\|リ\_s*ア\_s*ン\)\|リ\_s*\%([ィー]\|フ\_s*ァ\_s*イ\|サ\_s*イ\_s*ン\)\|ロ\_s*\%(ナ\|シ\_s*テ\_s*ィ\|ー\_s*ナ\|ニ\_s*[カク]\)\|ル\_s*\%(デ\|ベ\_s*ッ\_s*ト\|ダ\_s*ン\|レ\_s*ー\_s*ヌ\|サ\_s*\%(ー\_s*チ\|イ\_s*ユ\)\|モ\_s*ッ\_s*ト\)\|ノ\_s*ム\|ニ\_s*[スヤア]\|ネ\_s*\%(シ\_s*ャ\_s*ン\|ツ\_s*ィ\_s*ア\|チ\_s*ア\|ズ\_s*エ\_s*ラ\)\)\|バ\_s*\%([ルン]\|イ\_s*\%([アブンオ]\|パ\_s*ー\|タ\_s*\%(ル\|リ\_s*テ\_s*ィ\)\|キ\_s*ン\_s*グ\|ザ\_s*ー\|シ\_s*ャ\)\|ッ\_s*ト\|チ\_s*カ\_s*ン\|ギ\_s*ナ\|ガ\_s*ボ\_s*ン\_s*ド\|ラ\_s*\%(ナ\_s*シ\|エ\_s*テ\_s*ィ\)\|サ\_s*ロ\|ス\_s*\%(コ\|ケ\_s*ス\)\|カ\_s*ン\_s*ス\|ケ\_s*ー\_s*シ\_s*ョ\_s*ン\|キ\_s*ュ\_s*ー\_s*ム\|ウ\_s*チ\_s*ャ\_s*ー\|リ\_s*\%(ン\|エ\_s*ー\_s*シ\_s*ョ\_s*ン\|ュ\_s*ー\|ア\_s*\%(ブ\_s*ル\|ン\_s*ト\)\|ッ\_s*ド\|デ\_s*ー\_s*シ\_s*ョ\_s*ン\)\|ヌ\_s*ア\_s*ツ\|ニ\_s*\%(ラ\|ー\_s*ユ\)\|レ\_s*\%([ラー]\|ロ\_s*ン\|リ\_s*ー\|ン\_s*\%(シ\_s*ア\|チ\_s*ノ\|タ\_s*イ\_s*ン\)\)\|ー\_s*\%([ゴグ]\|チ\_s*ャ\_s*ル\|リ\_s*ト\_s*ゥ\_s*ー\_s*ド\|バ\_s*ル\|ボ\_s*ス\|ベ\_s*ナ\|テ\_s*ィ\_s*カ\_s*ル\|サ\_s*ス\|ジ\_s*\%(ン\|ニ\_s*ア\|ョ\_s*ン\)\|ノ\_s*ン\|ニ\_s*ア\|モ\_s*ン\_s*ト\|ミ\_s*\%(リ\_s*オ\_s*ン\|キ\_s*ュ\_s*ラ\_s*イ\_s*ト\)\)\|ナ\_s*\%(キ\_s*ュ\_s*ラ\_s*ー\|ジ\_s*ウ\_s*ム\)\)\|ブ\_s*\%(イ\|ラ\_s*\%(ド\|ッ\_s*ド\)\|ー\_s*ド\_s*ゥ\_s*ー\)\|V\_s*\%(H\_s*L\_s*L\_s*(\_s*V\_s*e\_s*r\_s*y\_s* \_s*H\_s*i\_s*g\_s*h\_s* \_s*L\_s*e\_s*v\_s*e\_s*l\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\_s*)\|ゾ\_s*ー\_s*ン\|サ\_s*イ\_s*ン\|ネ\_s*ッ\_s*ク\|ゴ\_s*ー\_s*ル\|J\_s*E\_s*-\_s*β\|シ\_s*ネ\|リ\_s*ー\_s*グ\|I\_s*S\_s*A\_s*カ\_s*ー\_s*ド\|i\_s*r\_s*g\_s*i\_s*n\_s*i\_s*a\|A\_s*X\|e\_s*r\_s*\%(m\_s*o\_s*n\_s*t\|i\_s*S\_s*i\_s*g\_s*n\)\|a\_s*n\_s*a\_s*d\_s*i\_s*u\_s*m\)\)', + \ 'w' : '\%([ヲヲ女翁尾汚小惜男緒牡雄をウ孳蛤礼敬恭洞鱗愛潤騒粳漆閏慯悄騷恙愁呻楳梅嫐釉噂耘吽褞曇紜云繧慍薀蘊暈運錙怏麗羨U卦憾怨恨占卜末嬉心裏浦糶瓜汝己υΥ畴畆畦疇畝踈疎宜諾奪姥莵兔驢鑿穿嗽魘唸促令項頷訴獺鷽嘯嘘蠕蠢動覘窺伺台萼唱詠謌唄宴讌転詩謠謡謳疑歌葎鯏鴬鶯ヱゑ鶉疼堆踞蹲渦舂臼碓羅薄食筌槽朮肯凵魚巧茨廐廏厩鰻午甘秣孫餞馬旨冩遷寫蔚暎噐器移慈俯映写現虚美笂靭靱靫空鰾萍初蛆氏↑上後喪艮丑潮牛裡鬱中欝袿梁家内禹憂埋挧撃雨打宇得植請鵜熟績嫗攴有夘受茹泛生討胡右紆傴盂饂承菟飢烏攵于射倦芋賣卯享搏失齲撲兎売産膿迂浮うヰ居ゐワ叫喚÷惡悪原稿嗤妾蕨童藁鞋笑灣萬豌綰万弯彎椀雲腕碗湾横往黄皇羂罠纔毫微僅患煩術伎厄禍災態業技佗王鰐忘掖弁腋譯緜腸亙道渉航弥亘棉渡綿私薈隈賄淮脇矮猥歪轍海蟠儂∪觧解頒判訣別稚若或枠惑鷲和環吾杷啝湧我涌輪破分把萵詫訳羽沸倭割話侘琶わw幅水∧波ウワw]\|ッ\_s*[ヲヱウヰワ]\|ッ\_s*[ヲヱウヰワ]\|っ\_s*[をゑうゐわ]\|乎\_s*古\_s*止\_s*点\|武\_s*漢\|狼\_s*狽\|夏\_s*枯\_s*草\|蠎\_s*蛇\|蟒\_s*蛇\|譫\_s*言\|琅\_s*珠\|温\_s*[麺気州]\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|自\_s*惚\|采\_s*女\|乳\_s*母\|姨\_s*捨\_s*山\|独\_s*活\|優\_s*\%(婆\_s*[塞夷]\|曇\_s*華\)\|合\_s*格\|親\_s*族\|斥\_s*候\|泡\_s*沫\|楽\_s*官\|雅\_s*楽\_s*[頭寮]\|干\_s*莉\|維\_s*納\|護\_s*田\_s*鳥\_s*尾\|淡\_s*\%(青\|口\_s*醤\_s*油\)\|五\_s*\%(加\|月\_s*蝿\)\|稲\_s*魂\|誓\_s*約\|石\_s*\%(女\|斑\_s*魚\)\|不\_s*生\_s*女\|味\_s*酒\|苜\_s*蓿\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|伝\_s*染\|呆\_s*気\_s*者\|茴\_s*香\|外\_s*郎\|餓\_s*\%(死\|え\_s*死\_s*に\)\|裲\_s*襠\|団\_s*扇\|草\_s*鞋\|(\_s*笑\_s*)\|(\_s*笑\_s*)\|戦\_s*慄\|俳\_s*優\|勿\_s*忘\_s*草\|早\_s*[生稲]\|山\_s*葵\|戯\_s*奴\|度\_s*会\|Y\_s*\%(軸\|シ\_s*ャ\_s*ツ\|染\_s*色\_s*体\)\|Y\_s*\%(軸\|シ\_s*ャ\_s*ツ\|染\_s*色\_s*体\)\|華\_s*盛\_s*頓\|裙\_s*蔕\_s*菜\|理\_s*[由解]\|公\_s*魚\|病\_s*葉\|大\_s*東\_s*亜\_s*戰\_s*爭\|太\_s*\%(秦\|平\_s*洋\_s*戦\_s*争\)\|歐\_s*州\_s*大\_s*戰\|第\_s*\%(二\_s*次\_s*世\_s*界\_s*大\_s*戦\|一\_s*次\_s*世\_s*界\_s*大\_s*戦\)\|ブ\_s*ル\_s*ツ\_s*ブ\_s*ル\_s*ク\|ロ\_s*ン\_s*グ\|レ\_s*\%(ン\|イ\_s*ス\|ッ\_s*カ\_s*ー\|ス\_s*\%(ラ\_s*ー\|リ\_s*ン\_s*グ\)\)\|リ\_s*\%(ー\_s*ス\|ン\_s*ク\_s*ル\|ス\_s*ト\)\|書\_s*き\_s*込\_s*み\|ラ\_s*\%(ッ\_s*\%([プパ]\|ピ\_s*ン\_s*グ\)\|イ\_s*\%([タト]\|テ\_s*ィ\_s*ン\_s*グ\)\)\|ボ\_s*ル\_s*フ\|フ\_s*\%([ムー]\|ァ\_s*イ\_s*ル\|ィ\_s*\%(ー\_s*ト\|ッ\_s*チ\)\)\|ホ\_s*\%(エ\_s*[イーア]\|ー\_s*ル\|イ\_s*\%(ー\_s*\%(ル\|ラ\_s*ー\)\|ッ\_s*\%(プ\|ス\_s*ル\|パ\_s*ー\|ト\_s*\%(ニ\_s*ー\|マ\_s*ン\)\)\)\|ワ\_s*\%(イ\|ッ\_s*[トツ]\)\)\|ベ\_s*ル\_s*ナ\_s*ー\|W\_s*\%(S\|N\_s*N\|y\_s*o\_s*m\_s*i\_s*n\_s*g\|O\_s*W\_s*O\_s*W\|I\_s*\%(D\_s*E\|N\_s*T\_s*E\_s*R\_s*P\_s*(\_s*W\_s*i\_s*d\_s*g\_s*e\_s*t\_s* \_s*I\_s*n\_s*t\_s*e\_s*r\_s*p\_s*r\_s*e\_s*t\_s*e\_s*r\_s*)\)\|i\_s*\%(s\_s*c\_s*o\_s*n\_s*s\_s*i\_s*n\|d\_s*g\_s*e\_s*t\|n\_s*d\_s*o\_s*w\_s*s\)\|h\_s*\%(y\_s* \_s*d\_s*o\_s*n\_s*e\_s* \_s*i\_s*t\_s*?\|o\_s* \_s*d\_s*o\_s*n\_s*e\_s* \_s*i\_s*t\_s*?\)\|E\_s*B\_s*\%(ブ\_s*ラ\_s*ウ\_s*ザ\|マ\_s*ガ\_s*ジ\_s*ン\)\|e\_s*\%(s\_s*t\_s* \_s*V\_s*i\_s*r\_s*g\_s*i\_s*n\_s*i\_s*a\|b\_s*\%(ペ\_s*ー\_s*ジ\|ラ\_s*ジ\_s*オ\|コ\_s*ミ\_s*ッ\_s*ク\|サ\_s*\%(イ\_s*ト\|ー\_s*\%(バ\|ビ\_s*ス\)\)\|ド\_s*ラ\_s*マ\)\)\|a\_s*s\_s*h\_s*i\_s*n\_s*g\_s*t\_s*o\_s*n\|A\_s*V\_s*フ\_s*ァ\_s*イ\_s*ル\)\|警\_s*告\|W\_s*\%(杯\|n\_s*n\|i\_s*n\_s*k\|a\_s*r\_s*e\)\|バ\_s*ル\_s*タ\_s*ー\|ヴ\_s*\%(ュ\_s*ル\_s*ツ\_s*ブ\_s*ル\_s*ク\|ォ\_s*ル\_s*フ\|ィ\_s*\%([ーム]\|ル\_s*\%(ム\|ヘ\_s*ル\_s*ム\)\)\|ェ\_s*\%(ン\_s*ダ\_s*ー\_s*ス\|ル\_s*ナ\_s*ー\|ー\_s*バ\_s*ー\|イ\_s*ユ\)\|ァ\_s*\%(イ\_s*[ンス]\|ー\_s*グ\_s*ナ\_s*ー\|ン\_s*ダ\|ル\_s*\%(タ\_s*ー\|キ\_s*ュ\_s*ー\_s*レ\)\)\)\|ダ\_s*ブ\_s*リ\_s*ュ\_s*ー\|タ\_s*ン\_s*グ\_s*ス\_s*テ\_s*ン\|T\_s*\%(h\_s*e\_s* \_s*W\_s*o\_s*r\_s*l\_s*d\_s* \_s*W\_s*i\_s*d\_s*e\_s* \_s*W\_s*e\_s*b\_s* \_s*C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\)\)', + \ 'x' : '\%([ォォぉェェぇゥゥぅィィぃァァぁxхХΞ×ξx]\|ッ\_s*[ォェゥィァ]\|ッ\_s*[ォェゥィァ]\|っ\_s*[ぉぇぅぃぁ]\|シ\_s*ロ\_s*\%(ホ\_s*ン\|フ\_s*ォ\_s*ン\)\|X\_s*\%([軸線]\|デ\_s*[イー]\|v\_s*i\_s*e\_s*w\|S\_s*サ\_s*イ\_s*ズ\|L\_s*\%(i\_s*s\_s*p\|サ\_s*イ\_s*ズ\)\|ウ\_s*ィ\_s*ン\_s*ド\_s*ウ\|端\_s*末\)\|X\_s*\%([軸線]\|C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|デ\_s*[イー]\|P\_s*S\_s*(\_s*e\_s*X\_s*p\_s*a\_s*n\_s*s\_s*i\_s*o\_s*n\_s* \_s*P\_s*a\_s*s\_s*s\_s*i\_s*n\_s*g\_s* \_s*S\_s*t\_s*y\_s*l\_s*e\_s*)\|S\_s*サ\_s*イ\_s*ズ\|l\_s*i\_s*b\|L\_s*\%(i\_s*s\_s*p\|サ\_s*イ\_s*ズ\)\|e\_s*n\_s*o\_s*n\)\|ジ\_s*オ\_s*ン\|ゼ\_s*\%(ビ\_s*ウ\_s*ス\|ロ\_s*\%(ッ\_s*ク\_s*ス\|グ\_s*ラ\_s*フ\_s*ィ\)\)\|ハ\_s*ビ\_s*エ\_s*ル\|ザ\_s*\%(ン\|ビ\_s*エ\_s*ル\)\|キ\_s*\%(シ\_s*\%(ロ\|レ\_s*ン\|リ\_s*ト\_s*ー\_s*ル\)\|セ\_s*ノ\_s*ン\|サ\_s*ン\_s*\%(チ\_s*ン\|タ\_s*ン\)\)\|E\_s*x\_s*t\_s*e\_s*n\_s*s\_s*i\_s*b\_s*l\_s*e\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|ク\_s*\%(シ\_s*ー\|ロ\_s*ス\_s*ポ\_s*ス\_s*ト\|セ\_s*\%(ナ\_s*キ\_s*ス\|ノ\_s*フ\_s*ォ\_s*ン\)\|ザ\_s*ヴ\_s*ィ\_s*エ\|サ\_s*\%(イ\|ン\_s*\%(ト\_s*ス\|チ\_s*ッ\_s*ペ\|テ\_s*ィ\_s*ッ\_s*ペ\)\)\|リ\_s*ス\_s*マ\_s*ス\)\|エ\_s*\%(ク\_s*ス\|ッ\_s*ク\_s*ス\)\)', + \ 'y' : '\%([ヨ艾蒿蓬娵嫁齡齢據頼弱憙歓鎧万萬過便婚汚涎捩翊緘峪杙慾欲翌翼抑米比裝粧装澱淀縦誼祥葭悦宜克純圭禎葦慶禧美淑芳喜吉義瘍樣踴榕踊燿謠廱姚慂曄瀁瑶恙蓉遙怏雍痒珱陶孕漾昜暘甬幺癢泱癰窰慵穃鷹瓔煬邀遥拗擁瑤窯徭膺窈殀曜耀庸夭揚葉蛹腰羊熔杳沃壅様妖用溶佯謡陽洋嘉宵蘇蘓甦辟奸横豫代除譽歟喚預読誉蕷輿攀余縒呼避4世譱詠丗能予撚憑餘畭酔醉與飫舁四訓選与讀よユ潤赦弛緩聴岼閖梦努纈∴故濯檠穰豐豊倖志裄之幸雪趾梼讓譲牀縁紫浴床俑犹蚰酉莠邑攸黝熊尢蝣蕕猷悒囿佳尤佑〒右郵涌祐侑游猶湧融宥夕幽悠釉友雄憂有臾渝瘉愉征諭徃遊揺逾覦茹揄由蝓兪淘結輸諛搖揃弓楡瑜踰柚油喩汰腴ゆイΗη賤鄙卑苟嫌妹湯藷芋夢艷鑪鈩彩鱗色鯆忽綺貸甍応答愈圦杁霪隱蚓寅氤酳胤飮韵尹茵贇蔭婬湮堙吋廴I音慇韻咽淫殞姻隕院允殷隠陰窟巌巖頌祝鰛鰮鰯岩磐鼾歪弑弋抱懐肬贅疣狗戌乾犬諱在坐未汝戒誡警縛今Εε曰禾稻員因蝗印嘶鰍電引躄誘動忿≦鵤錨碇怒霆雷霹凧桴筏Ιι魚菴庵雖尿荊棘茨祈祷命猯豕古伍乙鎰鴪聿軼樹慈悼愴慯労格到至傷鼬頂戴徒致鈑痛板柞砂沙些聊潔諍烈功諫勳勲勇漁諌憇=憩粹熱粋憤域閾勢勤忙急磯孰焉湶泉厳何弄苛≧鎔范啀毬訝燻息指挑拠縷絲厭營営愛幼緒遑暇糸I弌壹肆莓苺櫟著市碑鐓礎甃臀弩石犧牲犠池溢佚壱11燠鬻礇毓粥的戦戰軍幾郁一稲許否飯洟位違居姨猗斎偽噫逝医鑄痍委囲云圍ゐ挿炒彙要熨饐醫言矮往詒威懿入如僞忌彜煎逶緯韋唯莞淹胃善生恚彝惟以活蔚為猪衣倚幃斐移鮪将可偉畏五夷李渭怡貽癒依逸井慰行伊爲胆射詑矣頤熬萎良凍出椅率好揖肄痿鋳謂帷亥苡意維遺鰄異去堰容囗いヤ稚稍飲鎗鑓槍孀寡鰥Я碼傭雇闇敗吝薮藪殕脂寄宿櫓軈軅簗梁S漸鋏刃灸和柔軟窶鱧奴僕萢優柳喧宅館舘輩族鏃龠檪≒譯籥鑰蜴繹藥葯扼益厄疫躍約役訳薬疚疾岾楊谺邪薯犲豺〈《》〉山壥邸廛豢養社鑢育廉寧尉裕恭泰易休保康安靖笶八熄演谷焼彌冶⇔也輻破辭埜痩野屋家病椰爺已矢燒⇒灼妬耶遣瘠哉罷夜殺止揶辞弥やyеЕ円¥←↓↑→ёЁ━─ユヤヨЙυYイЫыйΥy]\|ッ\_s*[ヨユイヤ]\|ッ\_s*[ヨユイヤ]\|っ\_s*[よゆいや]\|欧\_s*羅\_s*巴\|歐\_s*羅\_s*巴\|尸\_s*童\|蹌\_s*踉\|蹣\_s*跚\|終\_s*夜\|4\_s*\%([項者つ日]\|番\_s*目\|種\_s*類\)\|他\_s*所\|仁\_s*史\|隆\_s*克\|尚\_s*武\|孝\_s*高\|悌\_s*也\|賀\_s*[子悟]\|彬\_s*伯\|栄\_s*伸\|宗\_s*生\|新\_s*生\|昌\_s*[美男]\|暢\_s*[子一]\|永\_s*沈\|8\_s*日\|8\_s*日\|黄\_s*泉\|左\_s*手\|百\_s*合\|L\_s*i\_s*l\_s*i\_s*\%(o\_s*p\_s*s\_s*i\_s*d\_s*a\|a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\)\|U\_s*\%(字\|タ\_s*ー\_s*ン\)\|鞦\_s*韆\|強\_s*請\|梅\_s*桃\|桜\_s*桃\|靫\_s*負\|宙\_s*美\|礼\_s*暁\|温\_s*\%(雄\|泉\_s*津\)\|長\_s*庚\|昨\_s*夜\|又\_s*木\|木\_s*綿\|E\_s*\%(u\|メ\_s*ー\_s*ル\)\|祖\_s*谷\|文\_s*身\|郎\_s*[女子]\|刺\_s*[青草]\|蕁\_s*麻\|U\_s*\%(字\|タ\_s*ー\_s*ン\|r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|海\_s*[豚参]\|西\_s*表\|鸚\_s*哥\|影\_s*[向青]\|況\_s*ん\_s*や\|所\_s*[以縁謂]\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|藺\_s*草\|J\_s*u\_s*\%(l\_s*i\_s*a\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|n\_s*c\_s*a\_s*l\_s*e\_s*s\)\|田\_s*舎\|膝\_s*行\|十\_s*六\_s*夜\|寝\_s*穢\|英\_s*\%([一桃蘭]\|吉\_s*利\)\|斑\_s*鳩\|烏\_s*賊\|玉\_s*筋\_s*魚\|硫\_s*黄\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|牛\_s*膝\|稜\_s*威\|常\_s*春\_s*藤\|5\_s*[つ日]\|5\_s*[つ日]\|惡\_s*戲\|甚\_s*振\|潮\_s*来\|悪\_s*戯\|交\_s*喙\|小\_s*魚\|鯨\_s*魚\|細\_s*小\_s*魚\|鶏\_s*魚\|経\_s*緯\|礒\_s*[山田]\|E\_s*\%(A\_s*S\_s*T\|V\_s*E\)\|気\_s*吹\|従\_s*[妹姉弟兄]\|公\_s*孫\_s*樹\|鴨\_s*脚\_s*樹\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|銀\_s*杏\|鳶\_s*尾\|巫\_s*子\|神\_s*巫\|無\_s*花\_s*果\|睦\_s*月\|都\_s*方\_s*流\|縊\_s*[殺死首]\|蝟\_s*[集縮]\|埋\_s*け\_s*[火炭]\|不\_s*[可如]\|守\_s*宮\|燕\_s*龍\_s*茶\|両\_s*班\|流\_s*鏑\_s*馬\|柵\_s*原\|箭\_s*[田内]\|R\_s*a\_s*f\_s*f\_s*l\_s*e\_s*s\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|自\_s*棄\|火\_s*傷\|徐\_s*ら\|M\_s*y\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|天\_s*蚕\|倭\_s*絵\|日\_s*本\_s*武\_s*尊\|大\_s*和\|T\_s*\%(h\_s*e\_s*l\_s*i\_s*g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*o\_s*c\_s*h\_s*o\_s*d\_s*e\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|香\_s*具\_s*師\|玄\_s*孫\|A\_s*r\_s*a\_s*c\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*\%(o\_s*t\_s*e\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*c\_s*i\_s*p\_s*e\_s*s\)\|a\_s*l\_s*m\_s*a\_s*l\_s*e\_s*s\)\|妥\_s*子\|寿\_s*[詞男]\|Y\_s*\%([談軸]\|シ\_s*ャ\_s*ツ\)\|エ\_s*\%(ホ\_s*バ\|フ\_s*ゲ\_s*ニ\_s*ー\|レ\_s*ヴ\_s*ァ\_s*ン\|ニ\_s*セ\_s*イ\|ー\_s*ル\)\|ワ\_s*イ\)', + \ 'z' : '\%([空損存揃園薗底足束續屬∈∋賊続粟族俗属僧慥噌梍賍臟臧贓憎像臓贈象増造添初曾反沿曽ぞ譱然苒繕禪薇千蠕∀髯禅善漸冉前全關関蝉膳錢銭絶勢噬説筮贅脆税是攻責ぜ狡詰桷寸喘鮨附◆髓蘂膸蕋惴蕊隧隋隨瑞髄随豆廚圖付津頭酢厨好図逗鶴刷ず塩嶋縞島嶌橲衄衂宍竺舳忸軸舌祖喰食直凝日實昵印闍者鮭邪蛇麝搦着惹尺鉐雀寂若弱尻稔仭糂贐潯儘仞盡刄臣侭恁進訊俥蕁迅刃靱荏甚靭燼櫁樒塵尽尋陣腎壬人敘恕耡汝莇杼茹敍蜍洳舒縟辱褥蓐溽所抒鋤徐序絮叙助釀淨疂絛繞壌諚孃瀞襄仍蟐拯疉讓聶驤生帖仗躡穰乘塲靜繩禳蕘壤遶星滌茸嬲疊如醤剩娘嬢錠静醸縄女尉饒丈成擾穣烝嫋丞場杖條条蒸貞状攘剰畳冗定浄乗情城上常譲濡得戍就嬬鷲竪讐讎懦愀咒聚隼詢徇笋凖盾楯筍篤蓴惇洵淳閏諄恂馴旬荀潤循醇巡遵順准殉純準襦誦需戌朮孰宿塾珠熟恤術述孺呪豎儒綬樹受授壽鞣狃澀揉廿拾縱中從糅从戎澁蹂神汁獸絨縦渋柔什充十獣従住銃重岻治除士染時怩至児冶璽只畤侍孳轜耳示次寿辭粫司二祀邇而慈峙爺以地塒珥迩痔死敷恃蒔磁瓷仁字尓焦膩柱似嗣子亊路史餌兒滋仕爾辞弍自茲持寺事知じ騒沢澤猿笊晒曝皿鮫山算参鏨慘竄懴殘塹巉懺嶄讒惨暫慚慙斬残実笹酒坂盛三崎嵜桜榴雜襍棹竿雑濟才西斉済劑戝剤材財罪在冴覚左咲挫藏裂醒坐蔵差冷座戯ざz→↑ЬьЪъ↓←Жжズゾ零〇〒ザジゼзζЗΖz]\|ッ\_s*\%(ソ\_s*゙\|セ\_s*゙\|ス\_s*゙\|シ\_s*゙\|サ\_s*゙\)\|ッ\_s*[ゾゼズジザ]\|っ\_s*[ぞぜずじざ]\|ソ\_s*゙\|簇\_s*生\|双\_s*紙\|草\_s*[履紙子]\|セ\_s*゙\|台\_s*詞\|0\_s*次\|発\_s*条\|撥\_s*条\|發\_s*条\|世\_s*阿\_s*弥\|ス\_s*゙\|相\_s*撲\|木\_s*菟\|修\_s*法\|杜\_s*撰\|調\_s*所\|徒\_s*[罪刑]\|螟\_s*虫\|芋\_s*茎\|F\_s*i\_s*g\_s*u\_s*r\_s*e\|シ\_s*゙\|G\_s*\%(メ\_s*ン\|パ\_s*ン\)\|D\_s*y\|G\_s*\%(メ\_s*ン\|パ\_s*ン\)\|支\_s*度\|試\_s*合\|2\_s*乗\|2\_s*乗\|J\_s*\%(I\_s*S\_s*コ\_s*ー\_s*ド\|ポ\_s*ッ\_s*プ\|R\_s*東\_s*日\_s*本\)\|獅\_s*子\|甲\_s*乙\_s*丙\_s*丁\_s*戊\_s*己\_s*庚\_s*辛\_s*壬\_s*癸\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|爪\_s*哇\|射\_s*礼\|砂\_s*利\|謝\_s*花\|著\_s*語\|杓\_s*子\|深\_s*\%(秘\|大\_s*寺\)\|秦\_s*泉\_s*寺\|沈\_s*\%(香\|丁\_s*花\)\|晨\_s*朝\|濁\_s*世\|判\_s*官\|諍\_s*論\|長\_s*夜\|漏\_s*斗\|焼\_s*酎\|鐘\_s*石\|橈\_s*脚\_s*類\|承\_s*久\|朱\_s*里\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*\%(リ\_s*ー\_s*グ\|ポ\_s*ッ\_s*プ\|U\_s*N\_s*K\_s*O\)\|絢\_s*子\|頌\_s*偈\|数\_s*珠\|入\_s*[魂牢来洛院内水棺]\|霜\_s*月\|1\_s*\%(2\|6\_s*進\|0\_s*[進月]\|1\_s*月\|8\_s*禁\)\|師\_s*走\|極\_s*月\|紐\_s*帯\|1\_s*\%(0\|1\_s*月\|8\_s*禁\|2\_s*月\)\|サ\_s*゙\|搾\_s*菜\|蜊\_s*蛄\|粗\_s*目\|槧\_s*本\|散\_s*切\_s*り\|沙\_s*汰\|石\_s*榴\|柘\_s*榴\|細\_s*工\|亜\_s*鉛\|サ\_s*\%(モ\_s*ラ\|ン\_s*ポ\_s*ー\_s*ニ\_s*ャ\|ラ\_s*ゴ\_s*サ\)\|Z\_s*\%([r軸]\|i\_s*\%(r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\|n\_s*c\)\|ガ\_s*ン\_s*ダ\_s*ム\|バ\_s*ッ\_s*フ\_s*ァ\|I\_s*P\_s*フ\_s*ァ\_s*イ\_s*ル\)\|シ\_s*\%(タ\_s*ー\_s*ル\|オ\_s*\%(ン\|ニ\_s*\%(ス\_s*ト\|ズ\_s*ム\)\)\)\|Z\_s*\%([旗軸]\|変\_s*換\|i\_s*g\_s*g\_s*y\)\|チ\_s*\%(ク\_s*ル\_s*ス\|ア\_s*ノ\_s*ー\_s*ゼ\|ュ\_s*ー\_s*リ\_s*\%(ヒ\|ッ\_s*ヒ\)\|ャ\_s*ル\_s*ダ\_s*ッ\_s*シ\_s*ュ\|ゴ\_s*イ\_s*ネ\_s*ル\_s*ワ\_s*イ\_s*ゼ\_s*ン\)\|ツ\_s*\%(ァ\_s*\%(ラ\_s*ト\_s*ゥ\_s*ス\_s*ト\_s*ラ\|イ\_s*ト\)\|ェ\_s*\%(ナ\_s*ー\|ッ\_s*ペ\_s*リ\_s*ン\|ル\_s*マ\_s*ッ\_s*ト\)\|ィ\_s*\%(ク\_s*ル\_s*ス\|タ\_s*ー\|ー\_s*グ\_s*ラ\_s*ー\|ン\_s*\%(バ\_s*ロ\_s*ン\|マ\_s*ー\_s*マ\_s*ン\)\|ゴ\_s*イ\_s*ネ\_s*ル\)\)\)', + \ 'A' : '\%([ア餅母渉恤閔憐慌遽蚫鰒鮑袷淡∃主衽袵歩垤蟻麁凡塔蘭露著表霰非諍抗更検革改現競爭争洗殿鉱予豫粗嵐禮恠妖彪殺絢怪綺肖彩漢過謝謬誤礼操綾飴菴黯罨鱇鮟餡行闇按諳晏鞍暗鶩鬚鰓顎喘発肋豈嫂兄崇騰県購贖网罔咫與鼎中新邉邊辺恰頭價価値游遊畔畦堋杏梓与袙衵憬孔坑案侮窖強貴讐讎徒仇黶痣欺鮮字糾嘲薊姐姉曙炮焙炙蜚薹膏脂油危鐙虻泡蹟能痕踪跡東預聚輯纂遏蒐乢軋誂羹壓惇集陸敦暑淳篤熱扱暖温遖斡私圧焦汗央奥奧媼桜櫻塰蜑餘遍普周剰蔗余尼雨甘天凹押樗楝溢艶庵鰺網戯簣鯵味堊渥軛圷憧欠踵幄握芥齷厚漁鯏蜊蕣淺麻浅晰龝煥晢呆朖啓亮晄鑑滉昜旭聡光亨陽洸璋顯輝昿曠諦朗哲顕彬晶賈章商穐彰晃晧昭秋噫瞹穢阨埃欸姶隘文粟曖鮎藹饗靉挨間相哀葭趾朝晨愛跛蹇跫脚蘆葦芦鐐桎足淦赫燈赧紅旃朱茜藜銅赭閼曉暁垢皹皸絳灯證暴証赤呷扇黝榮碧葵蒼煽仰青穴和或哇婀当上阿編吾在併明開韲悪荒襾痾浴唖有挙遭逢嗚敢褪娃安厭充該彼擧會飫倦合亞揚椏宛遇飽惡當あ藍金@&&∧∩論∠銀会∀空域⇔←↓⇒→↑⌒後Ц亜米¨´`^’〜≒AαÅΑアаАA]\|厦\_s*門\|廈\_s*門\|沫\_s*雪\|食\_s*蟻\_s*獣\|H\_s*a\_s*l\_s*o\_s*r\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|浣\_s*熊\|菖\_s*蒲\|豆\_s*汁\|蛙\_s*鳴\_s*蝉\_s*噪\|塩\_s*梅\|家\_s*鴨\|趺\_s*坐\|Z\_s*\%(n\|i\_s*n\_s*c\)\|浮\_s*子\|痘\_s*痕\|窪\_s*地\|糠\_s*蝦\|醤\_s*蝦\|信\_s*天\_s*翁\|左\_s*沢\|雅\_s*典\|校\_s*倉\|小\_s*豆\|四\_s*阿\|鴉\_s*\%(片\|鷺\_s*合\_s*戦\_s*物\_s*語\)\|渾\_s*名\|綽\_s*名\|化\_s*野\|翌\_s*檜\|飛\_s*[魚鳥]\|総\_s*角\|木\_s*通\|通\_s*草\|L\_s*a\_s*r\_s*d\_s*i\_s*z\_s*a\_s*b\_s*a\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|花\_s*鶏\|我\_s*\%(妻\|孫\_s*子\)\|数\_s*多\|奄\_s*美\|灰\_s*汁\|a\_s*\%(t\_s*t\_s*o\|c\_s*c\_s*e\_s*n\_s*t\)\|胡\_s*[床坐座葱]\|日\_s*明\|碩\_s*宏\|祥\_s*[仁彦]\|蜻\_s*蛉\|E\_s*\%(s\|i\_s*n\_s*s\_s*t\_s*e\_s*i\_s*n\_s*i\_s*u\_s*m\)\|生\_s*憎\|匕\_s*首\|英\_s*\%([保田]\|虞\_s*湾\|賀\_s*保\)\|靄\_s*[靄々]\|I\_s*\%(r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(電\_s*話\|ア\_s*ド\_s*レ\_s*ス\)\|D\_s*カ\_s*ー\_s*ド\|C\_s*\%(タ\_s*グ\|カ\_s*ー\_s*ド\)\)\|I\_s*\%(P\_s*電\_s*話\|C\_s*\%(タ\_s*グ\|カ\_s*ー\_s*ド\)\)\|走\_s*目\|鹹\_s*草\|馬\_s*酔\_s*木\|海\_s*[豹人女士部驢]\|R\_s*u\_s*b\_s*i\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|褐\_s*毛\_s*和\_s*種\|石\_s*蓴\|白\_s*馬\|水\_s*[黽馬綿]\|M\_s*a\_s*l\_s*v\_s*a\_s*l\_s*e\_s*s\|ト\_s*リ\_s*プ\_s*ル\_s*A\|公\_s*理\| \_s*ア\_s*ク\_s*シ\_s*ア\_s*ム\|ヒ\_s*素\|砒\_s*素\|京\_s*都\_s*高\_s*度\_s*技\_s*術\_s*研\_s*究\_s*所\|代\_s*入\|遺\_s*産\|抽\_s*象\|G\_s*o\_s*l\_s*d\|自\_s*動\_s*\%(現\_s*金\_s*取\_s*り\_s*扱\_s*い\_s*機\|預\_s*貯\_s*金\_s*機\)\|属\_s*性\|何\_s*か\|か\_s*つ\|お\_s*よ\_s*び\|セ\_s*ン\_s*ト\_s*キ\_s*ッ\_s*ツ\_s*ネ\|S\_s*\%(b\|i\_s*l\_s*v\_s*e\_s*r\)\|使\_s*用\_s*可\_s*能\|利\_s*用\_s*可\_s*能\|算\_s*法\|割\_s*り\_s*当\_s*て\|オ\_s*\%(レ\|ギ\_s*ュ\_s*ス\_s*タ\_s*ン\|ド\_s*レ\_s*イ\|ン\_s*グ\_s*ス\_s*ト\_s*ロ\_s*ー\_s*ム\|ル\_s*\%(ト\_s*キ\_s*ー\|タ\_s*\%([ーナ]\|ネ\_s*\%(ー\_s*ト\|イ\_s*ト\)\)\)\|ー\_s*\%([クガサトラル]\|ニ\_s*ン\_s*グ\|キ\_s*シ\_s*ン\|ブ\_s*リ\_s*ー\|バ\_s*ー\_s*ド\|ベ\_s*ル\_s*ジ\_s*ュ\|ギ\_s*ュ\_s*ス\_s*\%(ト\|タ\_s*ン\)\|ゾ\_s*ン\_s*ヌ\|ス\_s*\%(チ\_s*ン\|テ\_s*ィ\_s*ン\|タ\_s*ー\|ト\_s*\%(リ\_s*ア\|ラ\_s*リ\_s*ア\)\)\|ド\_s*リ\_s*ー\|ジ\_s*\%([ェー]\|オ\_s*ロ\_s*ジ\)\|デ\_s*ィ\_s*\%(オ\|エ\_s*ン\_s*ス\|シ\_s*ョ\_s*ン\|ト\_s*リ\_s*ア\_s*ム\)\|タ\_s*ム\|ソ\_s*\%(リ\_s*テ\_s*ィ\|ラ\_s*イ\_s*ズ\)\|セ\_s*ン\_s*テ\_s*ィ\_s*ッ\_s*ク\|ロ\_s*ラ\)\)\|配\_s*列\|バ\_s*イ\_s*ト\|ハ\_s*ル\_s*マ\_s*ゲ\_s*ド\_s*ン\|引\_s*数\|人\_s*工\_s*\%(現\_s*実\_s*感\|知\_s*能\)\|イ\_s*\%(ー\_s*ジ\_s*ス\|オ\_s*ン\|ソ\_s*ッ\_s*プ\)\|マ\_s*ル\_s*ド\_s*ゥ\_s*ー\_s*ク\|紫\_s*\%(陽\_s*花\|水\_s*晶\|石\_s*英\)\|付\_s*録\|応\_s*用\|エ\_s*\%([ニメアイー]\|ッ\_s*チ\|ン\_s*\%(ド\_s*ラ\_s*ン\|ジ\_s*ェ\_s*\%(ル\|リ\_s*ッ\_s*ク\)\|ゼ\_s*ル\)\|リ\_s*ア\|オ\_s*リ\_s*ア\|ス\_s*テ\|プ\_s*ロ\_s*ン\)\)', + \ 'B' : '\%([鯔鰡堀本凡盆煩梵骨凹歿鈕釦沒渤没穆睦濮樸目攴攵朴木僕墨卜牧星抱肪鵬冐氓鋩旄瑁袤儚蟒鉾貌旁网茆牟蒡甍胞謗蠎虻髦黽卯懋榜眸罔乏惘妨帽昴忙剖冒忘茅膀妄尨厖膨貿防紡滂茫望亡傍某謀暈拇保墓暮菩簿誉掘募姥謨模母干彫呆慕坊姆牡乾褒惚戊ぼ冖覓幎汨巾羃冪紅鼈瞥韈蔑塀抃遍辧瓣卞汳宀湎采辯辨辮眄冕勉娩弁邉可辺邊べ船房笛淵縁渊渕斑鞭樗椈太袋深蓋葢盖豚節勿佛物震勃蚋風鰤馼蚊聞文誣無蒲撃打不錻武振分蕪奉吹侮葺毋舞悔憮部廡嘸葡撲撫拭伏歩ぶ米謐人匹浸額鐚跛!広開繆別謬泯旻梹罎岷緡紊檳頻壜愍瓶鬢閔憫敏貧便帛辟百闢白杪″緲憑票猫鋲屏渺眇平錨苗秒描廟病尾火日媚靡糒枇贔未引琵瀰嵋備縻糜弾美眉弭濔比寐毘麋微び早速林尿針腹拂散払祓原塙蠻旛旙鑁鷭幡悗挽判棒絆版輓蕃板播礬阪坂磐番盤晩萬蛮万箱蠅芒挟伴蜂桴枹鉢撥働畠畑糞屎鼻花端離話V魅許秤筏罸魃拔閥橋走箸柱寞藐貘獏暴漠瀑麥縛博駁莫驀爆楳憊狽霾唄吠杯賣苺培煤黴貝焙賠買売陪倍梅媒跋伐末幕曝抜罰庭馬葉婆罵這化馳羽塲晴歯場芭刄刃張貼ば“仏□■⊥下底×|‖−\∵麦ボバ][{}BブビБΒбβベB]\|ッ\_s*\%(ホ\_s*゙\|ヘ\_s*゙\|フ\_s*゙\|ヒ\_s*゙\|ハ\_s*゙\)\|ッ\_s*[ボベブビバ]\|っ\_s*[ぼべぶびば]\|ホ\_s*゙\|小\_s*火\|襤\_s*褸\|孟\_s*買\|P\_s*a\_s*e\_s*o\_s*n\_s*i\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|南\_s*瓜\|耄\_s*耋\|孑\_s*孑\|包\_s*丁\|ヘ\_s*゙\|袂\_s*別\|箆\_s*棒\|篦\_s*棒\|胼\_s*胝\|フ\_s*゙\|補\_s*任\|毒\_s*島\|醜\_s*[女男]\|山\_s*毛\_s*欅\|F\_s*a\_s*g\_s*a\_s*l\_s*e\_s*s\|布\_s*団\|茯\_s*苓\|V\_s*\%(字\|ネ\_s*ッ\_s*ク\|シ\_s*ネ\_s*マ\)\|附\_s*子\|付\_s*子\|鞦\_s*韆\|豊\_s*[前後]\|ヒ\_s*゙\|魚\_s*[籠篭]\|b\_s*i\_s*o\_s*t\_s*o\_s*p\_s*e\|彌\_s*縫\|弥\_s*[漫縫]\|吃\_s*驚\|天\_s*鵞\_s*絨\|緬\_s*甸\|賓\_s*頭\_s*盧\|編\_s*木\|柏\_s*槙\|S\_s*a\_s*n\_s*t\_s*a\_s*l\_s*a\_s*l\_s*e\_s*s\|兵\_s*[衛法]\|表\_s*紙\|拍\_s*[板子]\|ハ\_s*゙\|囃\_s*子\|巴\_s*爾\_s*幹\|R\_s*o\_s*s\_s*a\_s*l\_s*e\_s*s\|薔\_s*薇\|蟠\_s*踞\|鈑\_s*金\|A\_s*n\_s*n\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|発\_s*条\|祖\_s*母\_s*さ\_s*ん\|梯\_s*子\|伯\_s*\%([林楽労]\|剌\_s*西\_s*爾\)\|莪\_s*原\|蝗\_s*虫\|飛\_s*[車蝗]\|掲\_s*示\_s*板\|プ\_s*ル\_s*コ\_s*ギ\|作\_s*業\_s*域\|オ\_s*ー\_s*ト\_s*バ\_s*イ\|基\_s*[礎底]\|フ\_s*ァ\_s*ゴ\_s*ッ\_s*ト\|背\_s*景\|北\_s*京\|ペ\_s*\%(キ\_s*ン\|テ\_s*ル\_s*ギ\_s*ウ\_s*ス\)\|臭\_s*素\|イ\_s*ギ\_s*リ\_s*ス\|ホ\_s*ウ\_s*素\|硼\_s*素\)', + \ 'C' : '\%([コ恐怖惟怺※米暦轉頃壼鶤袞鯤坤狠艮獻琿悃很建棍魂菎蒟滾梱溷献痕渾墾恨懇根杪王挙泥裔樸鞐熟枹醴蛩蹊徑径溢毀零錯苔拒箏亊判斷諺理断盡尽辞琴言異事今壽寿鯒冀希礫鯉拱齣狛細腓昆拳瘤鮗兄近谺応應答是爰凩兀惚榾忽輿甑腰拵拗鐺鏝昿仰慌桁袷塙頏絖冦耗亙峺效晄覯糠匣逅閧扛湊羔礦爻壙盍洸鬨浤凰閤窖缸寇岡頁傚湟汞洽崗鮫伉訌誥冓敲磽鏗椌搆肓鍠矼砿犒淆呷鵁皐黌遘昴槹蚣肱肴熕胱猴扣杲蛤狎畊昊餃哽幌鱇峇嫦烋隍恆倥徨啌吭釦闔藁絋棡遑紘稾鴿詬哮困靠皋惶紺鈩絳閘蒙冰氷郡蛟槁候楮媾溘后蝗酵嚆犢稿亢哄睾慷梗笄郊効岬肛項巷鑛洪佼狡昂叩勾喉滉糀晃剛晧曠宏控恍侯煌港皓坑皎耿膏向江膠虹巧鴻鉱衡浩興厚耕弘綱抗購講恒溝薨鋼航孝更校行肯荒高皇光好槲梏谷釛尅斛棘轂哭詰告刻酷穀⌒冴虎觚壷胯鼓児漉糊媚古娘冱虚混粉辜湖虍放葫捏鈷痩鴣瞽詁箍錮蠱蛄粐滬估雇故沽転倒漕罟餬拠超込凅誇懲琥扈袴木蝴呱乕踰弧越孤菰跨壺楜黄股肥己女戸恋兒怙瑚戀夸皷滸濾瓠去濃乎杞こセ芹鬩旃錢刋箭羶筌孅阡栫舩纎濺舛甎銛簽湶茜槧吮薦癬斬倩痊孱擶贍纖仟磚燹揃綫喘涎荐饌槫濳沾筅蟾牋苫專翦亘鐫僣韆箋僊殱殲闡賎餞羨顫甅竰糎陝踐銓閃∨潺遷銑栴剪煽譫僉瞻践跣栓疝詮銭穿尠戰僭繊腺泉嬋仙擅淺鮮専扇蘚船浅線撰宣洗選煎戦尖先忙伜倅逼狭狹蝉旋鱈薛椄絏洩卩啜泄紲攝緤§渫刹褻浙竊截窃殺説拙摂節切蓆晰威裼績蹐迹蹠跖跡螫瘠勣籍晢夕鶺雪寂∫∬碩惜析席隻甥韲嘶犀菁瀞晟貰擠睛筬淒醒齊婿撕牲齏情萋穽躋歳栖棲掣腥逝惺斉臍旌悽整凄靖製晴迫塞攻瀬急勢世畆丗糶畝堰脊せク配椚檪櫪栩椡椪箜櫟含纐婚糞癖潛潜鵠凹窪縊跟頚軛珞頸諄鞋履窟狐轡覆沓碎砕条降件頽崩屑釘莖茎陸杙杭掘崛倔鶏鐃藥擽薬楠誓梳串釧與与挫籖鯀鯨鬮籤隈熊艸嚔藾叢鏈腐鎖Ξξ茸菌楔草圀邦國国漱嗽吻腔φ劫刧粂裙勳熏皹桾皸醺崑燻訓勲葷君委钁企咥銜桑某暝峅昏冥眛鮓比闇位鞍藏暗倉廚厨涅々〃ゝヽゞ仝ヾ公曇雲蜘佝栗狂包胡俥梍枢畔鐵★玄黒徠久孔桍窶暮懼駒苦朽区眩吁繰庫垢紅呉汲宮枸劬煦口9瞿工供吼怐玖貢九惧来來區組奇句狗鳩絎嶇衢くシ埀謐Σσ蘂蕋蕊痺褥茵鵐蔀鷸鴫霑入責蔵嶌了縞嶋島凋搾澀澁渋縛暫屡柴荵凌鎬忍簧慕舖↓襪認從从.舌扱罔虐Θθ秕粃椎椣尿貎肉臠猪衣榻黙蜆恵楙誠茂成繁惻鋪陣頻閾櫁樒鹽汐潮瑟蛭疾櫛隲隰嫉蟋悉漆躾膝失室沒鎭沈滴雫賤鎮靜静顰尓爾聢乍併然◇□■◆倖幸貭叱征質柵卯滋撓品鬼鍜錏錣痼凝而拉設垂萎栞襞吝咳什導汁験記徴著印☆〇銀城報調蝨虱白濕湿標七僕楚笞霜臀退斥尻後冩寫舍者砂卸柘炙#♯暹諜喋煮這西娑沙謝紗鯱奢赦洒捨鮭瀉妁鑠抉蹟勺炸決釋皙爍昔斫蜥刳芍酌爵折癪笏赤灼綽杓石尺赭写鷓積遮舎車射斜釈社洙麈殳蛛娶娵諏鬚侏繻銖蹙俶倏菽叔蓿戚肅淑夙粛宿縮殊趣珠恤卆蟀出洲泅楸綉溲遒酬鷲駲緝葺穐蹤繍螽讐甃萩楢逎讎售岫收驟舅囚姑蓚皺鞦銹脩輯醜習羞酋聚舟秀祝袖啾拾蒐収執衆愁就臭蹴週終褶州宗集秋椶棕朱撞種修周手首酒須儁惷悛濬雋皴墫蕣順蠢舜旬浚竣峻駿逡筍瞬俊蓁畛矧縉蔘鷏齔嗔忱譛袗譖娠疹哂脣怎晉鷆臻甄槙寢岑瀋箴軫榛秦襯診鉐津駸讖紳斟唇針呻蜃賑芯瞋振殿侵薪晨辰震宸森眞愼伸慎寝晋進深審親臣鍼申心宍信真新薯墅杵岨藷黍苜渚砠狙嶼處胥蜍苴曙背緒雎蔗庶処署所暑奬簫浹橸舂艢廂陞炒鍬庠獎梢璋將厰邵摺淞訟樅筱篠燮橡愴韶咲誚峭甞鯖敞聲懾稍腫政顳枩慯殤秤湫井星廠剿妝霎蛸劭觴愀升錆鬆樵囁鷦嶂醤青従慫逍倡竦爿薔笙樟装肖菖≦<湘誦聳檣稱声裳蒋蕉嘯慴盛精霄清鈔粧彰鏘悚蕭悄瀟哨焦憔匠鍾償瘴鞘漿頌詔沼妾請唱薑庄渉障奨娼床牀椒抄聖荘宵傷性相生銷召賞猩症昭燒猖昌少尚晶憧紹祥承證笑将焼照招章詳消証硝掌商昇小昃禝稷寔矚謖觸稙軾嗇屬穡拭属燭贖囑嘱織蝕式喰蜀殖諸初触埴植食職嗜笶姉士徙誣氏思染祗時弑滲梔摯肢詩咨祉刺泗輜厶強貲若至師舐咫只施誌呰匙示指締厮啻次賜熾趾駟漬笥贄此司如沚尸髭肆祀鷙諡枝篩豕巵始妛及弛絲浸閇翅緊揣伺糸駛痣矢衰死敷恃茨旨沁嘴蚩試釶俟瓷觜廝緇祠梓址詞之使獅志歯紫雌姿諮占絞視嗣識四恣阯侈幟卮凍史領竢市巳齒偲資止謚耆覗脂芝痴粢孜仕錙耜齎自屎茲岐〆嗤砥知私仔しカ糜癢粥痒麹輕骨業軽鰔鰈餉通瓶龜甕亀鴈獵鳫殯K猟雁釀鳧鳬髢氈鴨躱巛側厠廁磧瓦獺翡為裘皮〜紮→搦苧碓柄體軆躰躯身体鴉犂烏絡空唐榧茅揀坎澗扞莟丱拑盥嫺鑵蒄瞰淦稈康繝懽憾骭戡奐啣厂鐶讙澣羮寰羹嫻杆鸛歡豢歛罕酣陷皖篏捍瀚勸撼驩卷樌潤觀橄涵渙堪巫覡鉋随萱簪舘艱咸翰柬悍駻燗槓浣邯攷稽宦考棺潅閂煥鉗疳癇函凾鹹緘桓款箝諌諫轗旱坩侃鰥 館莞橇韓患灌勧菅奸刊柑肝看桿干緩寒嵌廣広竿貫巻敢漢環間陥喚閑監喊歓甘寛管慣完汗艦乾幹官観壁椛屍姓庇鞄芳蔓千鯑一勘蜻⊃影陰蔭景*棧梯筧庚辛柧門廉癩乞Κ川κ合’)〈《‘“”}{》〉囓柁鮖悴舵鰍梶錺餝飾篭籠還歸卻皈孵省顧槭楓却帰反返督髮帋守祇韮主裃雷髪紙鉦曲矩予鐘樺沫偏騙語潟刀模象仇固硬傍難容忝辱頑形方旁型肩風幽滓翳微掠綛纃絣緕擦糟鎹粕春轄戞劼猾瞎恰蛞∧蠍擔濶筈剋蝎曷羯喝餓聒鞨黠刮蘰鬘桂闊括嘗捷豁渇担滑松堅鰹功割戛活暈疽鵲瘡傘嵩重襲葛笠堵硴墻牆蠣蛎柿關掲罹抱踵嬶嚊拘関係貌顏郁薫顔母感釡罐窰鴎框叺喧竃竈窯釜缶蒲鎌數数槝栢膳傅畏賢橿姦樫爨炊圍喞託囲鈎『鉤「』」限鍵(傾禿蕪鏑頭齧被兜敵適哉必要称鼎鬲彜彝叶片悲哀愛鋺蛇鉄蜩神奏金楫裹磆餅徒褐糧粮膈覺∠埆蠖貉幗隱擴寉骼癨壑咯椁嚇茖愨槨膕掴覈殼穫狢霍礁恪擱匿撹攪喀廓較郭]】【〔〕[殻挌劃閣格隠覚矍革獲馘攫核鶴拡客隔角確蠏壞畍丐獪褂恠喙峡夬觧械揩醢匯廨誡誨嵬櫂隗茴徊迴枴懈价椢榿囘蛙瑰乖浬鰄傀糴柏街鳰懷蛔蠶蚕邂蟹潰壊恢腕芥垣楷會拐悔詼諧皆界疥魁偕改繪貝胛絵甲快灰槐晦懐介回塊解階廻戒開会怪海縢篝炬耀赫輝冠鑒鑑各屈鏡和代茄缺飼嫁華堝變狩上訶架何啝火日菓欠苅繋稼ヶ个噛譁科跏舸賭禍支窩課花刈渦嚼掛呵替葭柯畫駆嘩崋化霞蝌迦顆価馨家借蝦罅駈斯賈嘉易果戈廈哥買闕且克墟靴訛驅換踝描軻嗅價嗄可彼夥香歌河珂鹿個痂書假荷耶笳咼藉糅舁搗渮袈下萪貸厦禾貨咬寡箇卦苛譌枷掻過画ヵ黴遐兼醸翔仮佳蚊懸伽賀淅勝涸苟蝸謌夏枯暇か・…塩閉倶錫呼∩取籐加交бТуЖоВЙЗзжЪЯУИвяшфлСКрпХЁОЭРФЫЩъБыШйхМкПгдмцНЛёаиэетАГЬюЕЮсьнщД♪┼╋×╂┿○●◎銅∪χΧ子чЧ株Ц珈、,色ク衝競構簡制≡変接カ┐┘┗┏┓┌┛└正コ¢シ℃セCC]\|ッ\_s*[コセクシカ]\|ッ\_s*[コセクシカ]\|っ\_s*[子こせくしか]\|焜\_s*炉\|嫡\_s*妻\|二\_s*合\_s*半\|牛\_s*尾\_s*魚\|巨\_s*勢\|独\_s*楽\|居\_s*士\|特\_s*牛\|粫\_s*門\|甦\_s*生\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|傴\_s*僂\|A\_s*\%(r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|p\_s*i\_s*a\_s*l\_s*e\_s*s\)\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|台\_s*詞\|懺\_s*法\|前\_s*[妻栽]\|妹\_s*尾\|嘲\_s*笑\|儕\_s*輩\|斎\_s*次\|済\_s*[民々済]\|蒸\_s*[籠篭]\|救\_s*世\|莎\_s*草\|百\_s*[濟済]\|恭\_s*敬\|9\_s*[日月]\|秧\_s*鶏\|究\_s*竟\|釉\_s*掛\|典\_s*薬\_s*寮\|探\_s*湯\|球\_s*磨\|六\_s*合\|地\_s*祇\|都\_s*子\|群\_s*衆\|慈\_s*姑\|旧\_s*\%(訳\|唐\_s*書\)\|内\_s*蔵\_s*助\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|老\_s*舗\|望\_s*潮\|健\_s*か\|L\_s*a\_s*\%(u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|b\_s*i\_s*a\_s*t\_s*a\_s*e\)\|埋\_s*葬\_s*虫\|幣\_s*原\|卓\_s*袱\|桎\_s*梏\|柳\_s*葉\_s*魚\|蠹\_s*魚\|汚\_s*点\|惠\_s*雄\|舗\_s*石\|磯\_s*城\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|倭\_s*文\|云\_s*[々云]\|明\_s*\%(々\_s*後\_s*日\|明\_s*後\_s*日\)\|7\_s*月\|7\_s*月\|文\_s*月\|4\_s*月\|4\_s*[分月]\|竹\_s*[篦刀]\|羊\_s*[齒歯]\|爲\_s*\%([留難置果送極手兼合業]\|ん\_s*方\|來\_s*り\|納\_s*め\)\|I\_s*\%(l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|素\_s*[魚人面]\|不\_s*[忍知]\|注\_s*連\|軍\_s*鶏\|髑\_s*髏\|三\_s*\%(味\|鞭\_s*酒\)\|吃\_s*逆\|差\_s*[別異]\|叉\_s*手\|輸\_s*[出贏]\|卒\_s*去\|B\_s*r\|隼\_s*[朗郎]\|笋\_s*[干羹]\|参\_s*差\|財\_s*産\|枌\_s*所\|縦\_s*容\|睫\_s*毛\|M\_s*\%(e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|u\_s*s\_s*a\_s*l\_s*e\_s*s\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|S\_s*\%([eg]\|p\_s*e\_s*r\_s*m\_s*a\_s*t\_s*o\_s*p\_s*h\_s*y\_s*t\_s*a\|c\_s*i\_s*t\_s*a\_s*m\_s*i\_s*n\_s*e\_s*a\_s*e\)\|続\_s*\%(日\_s*本\_s*\%(紀\|後\_s*紀\)\|後\_s*撰\_s*和\_s*歌\_s*集\)\|離\_s*れ\_s*離\_s*れ\|掃\_s*部\|羚\_s*羊\|土\_s*器\|蝙\_s*蝠\|魚\_s*狗\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|o\_s*\%(t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\|d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\)\)\|連\_s*枷\|枳\_s*殻\|機\_s*関\|落\_s*葉\_s*松\|凵\_s*繞\|檻\_s*車\|顴\_s*骨\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|南\_s*瓜\|量\_s*子\|山\_s*\%(海\_s*経\|梔\_s*子\|陽\_s*道\)\|蜉\_s*蝣\|陽\_s*炎\|破\_s*片\|脚\_s*気\|旗\_s*魚\|鍛\_s*[治冶]\|挿\_s*頭\|駕\_s*\%(籠\|輿\_s*丁\)\|長\_s*[月官]\|剃\_s*刀\|天\_s*\%(牛\|鼠\_s*矢\)\|帷\_s*子\|酢\_s*漿\_s*草\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|飛\_s*[沫白]\|曾\_s*て\|曽\_s*て\|燕\_s*子\_s*花\|牡\_s*[蛎蠣]\|民\_s*部\|部\_s*曲\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|案\_s*山\_s*子\|梭\_s*\%(魚\|子\_s*魚\)\|蟷\_s*螂\|螳\_s*螂\|瓜\_s*\%(田\|呂\_s*根\)\|拍\_s*手\|瑕\_s*[瑾疵]\|東\_s*\%([風雲]\|海\_s*林\|京\_s*都\_s*立\_s*科\_s*学\_s*技\_s*術\_s*大\_s*学\)\|気\_s*[質触]\|(\_s*株\_s*)\|贏\_s*ち\_s*得\|歩\_s*兵\|恁\_s*く\|杜\_s*\%(若\|父\_s*魚\)\|梅\_s*花\_s*皮\|頴\_s*田\|膾\_s*炙\|契\_s*経\|中\_s*央\_s*処\_s*理\_s*装\_s*置\|伊\_s*藤\_s*忠\_s*テ\_s*ク\_s*ノ\_s*サ\_s*イ\_s*エ\_s*ン\_s*ス\|分\_s*類\|ス\_s*リ\_s*ー\_s*ズ\|範\_s*疇\|ト\_s*ラ\_s*ン\_s*プ\|c\_s*\%(e\_s*n\_s*t\_s*i\|r\_s*e\_s*s\_s*c\)\|水\_s*[鶏母夫手晶]\|複\_s*雑\_s*命\_s*令\_s*セ\_s*ッ\_s*ト\_s*計\_s*算\_s*機\|サ\_s*\%(ン\_s*チ\_s*ー\_s*ム\|エ\_s*ラ\|イ\_s*\%(ト\_s*カ\_s*イ\_s*ン\|ラ\_s*ス\|ク\_s*\%([ルロ]\|リ\_s*\%(ン\|ッ\_s*ク\)\)\|ボ\_s*\%(ウ\_s*ズ\|ー\_s*グ\)\|バ\_s*\%(ー\|ネ\_s*テ\_s*ィ\_s*\%(ッ\_s*ク\|ク\_s*ス\)\)\|リ\_s*ュ\_s*ー\_s*ム\|ダ\_s*ー\|フ\_s*ァ\_s*ー\|ネ\_s*リ\_s*ア\)\|ー\_s*\%(テ\_s*ィ\_s*フ\_s*ィ\_s*ケ\_s*ー\_s*シ\_s*ョ\_s*ン\|ク\_s*ル\|カ\_s*\%(ス\|ム\_s*ス\_s*ク\_s*\%(ラ\_s*イ\_s*ブ\|リ\_s*プ\_s*シ\_s*ョ\_s*ン\)\)\|キ\_s*\%(ュ\_s*\%(ラ\_s*ー\|レ\_s*ー\_s*\%(タ\_s*ー\|シ\_s*ョ\_s*ン\)\)\|ッ\_s*ト\)\)\)\|マ\_s*ド\_s*ラ\_s*ス\|茶\_s*筅\|ケ\_s*\%([月アイ]\|フ\_s*ェ\_s*ウ\_s*ス\|プ\_s*ス\_s*ト\_s*ラ\_s*[ムル]\|チ\_s*ャ\_s*ッ\_s*プ\|ン\_s*\%(タ\_s*ウ\_s*\%(リ\|ロ\_s*ス\)\|ブ\_s*リ\_s*ッ\_s*ジ\)\|ー\_s*\%([キジブプスン]\|ク\_s*ウ\_s*ォ\_s*ー\_s*ク\|ソ\_s*ン\|タ\_s*リ\_s*ン\_s*グ\|パ\_s*\%(ー\|ビ\_s*リ\_s*テ\_s*ィ\)\|シ\_s*ン\_s*グ\|リ\_s*ー\)\|ル\_s*\%(ト\|ベ\_s*ロ\_s*ス\|テ\_s*ィ\_s*ッ\_s*ク\|ビ\_s*\%(ム\|ー\_s*ニ\)\)\|ミ\_s*\%(カ\_s*ル\|ス\_s*ト\)\)\|キ\_s*\%(ヤ\_s*ノ\_s*ン\|プ\_s*ロ\_s*ス\|ケ\_s*ロ\|ュ\_s*\%([イーア]\|ヴ\_s*ェ\|ビ\_s*\%(ズ\_s*ム\|ス\_s*ム\)\|ロ\_s*\%(ス\|ッ\_s*ト\)\|レ\_s*ー\_s*タ\_s*ー\|ラ\_s*ソ\_s*ー\|リ\_s*\%(ー\|ウ\_s*ム\|ア\_s*ス\|オ\_s*シ\_s*テ\_s*ィ\)\)\|ア\_s*\%(ラ\|ー\_s*ラ\|ン\_s*テ\_s*ィ\)\|チ\_s*ン\|ト\_s*サ\_s*ン\|メ\_s*ラ\|マ\_s*イ\_s*ラ\|ッ\_s*カ\|レ\_s*ー\_s*ト\|ャ\_s*\%([ドパスブンラ]\|デ\_s*\%(ィ\|ラ\_s*ッ\_s*ク\)\|ビ\_s*\%([アンネ]\|テ\_s*\%(ィ\|ー\_s*シ\_s*ョ\_s*ン\)\)\|ベ\_s*ツ\|バ\_s*\%(リ\_s*[エア]\|レ\_s*ー\)\|ト\_s*ル\|シ\_s*ー\|サ\_s*リ\_s*ン\|タ\_s*ピ\_s*ラ\|ピ\_s*\%(ト\_s*ル\|タ\_s*\%(ル\|リ\_s*ズ\_s*ム\)\)\|プ\_s*\%(ラ\|シ\_s*ョ\_s*ン\|テ\_s*ン\|チ\_s*ャ\)\|セ\_s*\%(イ\|ロ\_s*ー\_s*ル\)\|ッ\_s*\%([ツトチプ]\|サ\_s*バ\|ス\_s*ル\|シ\_s*\%(ュ\|ン\_s*グ\|ャ\_s*\%(ー\|ブ\_s*ル\)\)\)\|ニ\_s*\%(オ\_s*ン\|ス\_s*タ\_s*ー\)\|ナ\_s*ル\|ノ\_s*\%(ン\|ー\_s*ラ\|ピ\_s*ー\)\|ミ\_s*ソ\_s*ー\_s*ル\|メ\_s*\%(ル\|ロ\_s*\%(ン\|ッ\_s*ト\)\)\|ロ\_s*\%(ル\|ウ\_s*ェ\_s*イ\|リ\_s*ン\|ラ\_s*イ\_s*[ンナ]\|ッ\_s*ト\)\|レ\_s*ッ\_s*ト\|リ\_s*\%([コーア]\|バ\_s*ー\|ブ\_s*レ\_s*ー\_s*シ\_s*ョ\_s*ン\|ッ\_s*ジ\|ン\_s*グ\)\|ズ\_s*ム\)\|リ\_s*\%(コ\|ス\_s*ト\|シ\_s*タ\_s*ン\)\)\|総\_s*角\|チ\_s*\%([タリンマア]\|ワ\_s*ワ\|ラ\_s*ー\|ル\_s*ド\|ム\_s*ニ\_s*ー\|コ\_s*リ\|ッ\_s*\%([プク]\|テ\_s*リ\_s*オ\|タ\_s*ゴ\_s*ン\)\|キ\_s*\%(ン\|ー\_s*タ\)\|ュ\_s*\%(ア\_s*ブ\_s*ル\|ー\_s*イ\_s*ン\_s*ガ\_s*ム\)\|ー\_s*\%([フトプクズ]\|パ\_s*ー\|タ\_s*ー\)\|ェ\_s*\%([ロスカコアン]\|ザ\_s*\%(レ\|ー\_s*レ\)\|ル\_s*\%(ニ\_s*ー\|シ\_s*ー\|ノ\_s*ブ\_s*イ\_s*リ\)\|リ\_s*\%(ー\|ス\_s*ト\|ッ\_s*シ\_s*ュ\|モ\_s*ヤ\)\|レ\_s*\%(ス\_s*タ\|ン\_s*コ\_s*フ\)\|ビ\_s*チ\_s*ェ\_s*フ\|ダ\_s*ー\|チ\_s*ェ\_s*ン\|ッ\_s*\%([トクカ]\|キ\_s*ン\_s*グ\)\|イ\_s*\%([スン]\|ニ\_s*ー\|サ\_s*ー\|シ\_s*ン\_s*グ\)\|ー\_s*\%(ン\|ザ\_s*レ\|ホ\_s*フ\)\)\|ャ\_s*\%([オフドインコリウ]\|ツ\_s*ネ\|ク\_s*ラ\|プ\_s*タ\_s*ー\|パ\_s*テ\_s*ィ\|ペ\_s*\%(ル\|ッ\_s*ク\)\|チ\_s*ャ\|ネ\_s*\%(ル\|ラ\_s*ー\|リ\_s*ン\_s*グ\)\|ッ\_s*\%([クト]\|ピ\_s*ー\|プ\_s*\%(マ\_s*ン\|リ\_s*ン\)\)\|タ\_s*\%(レ\_s*[イー]\|リ\_s*ン\_s*グ\)\|ル\_s*マ\_s*ー\_s*ス\|レ\_s*ン\_s*ジ\|モ\_s*ロ\|ー\_s*\%([チタトムジ]\|ビ\_s*ル\|ミ\_s*\%(ー\|ン\_s*グ\)\|リ\_s*ー\|ル\_s*\%([ズス]\|ト\_s*ン\)\)\|ラ\_s*ン\_s*ゴ\)\|ョ\_s*\%([ンコ]\|イ\_s*ス\|ム\_s*ス\_s*キ\_s*ー\|ー\_s*\%(ク\|サ\_s*ー\|カ\_s*ー\|キ\_s*ン\_s*グ\)\|ゴ\_s*リ\|ッ\_s*\%(プ\|ピ\_s*ー\|パ\_s*ー\)\|リ\_s*ソ\)\)\|座\_s*標\|喜\_s*劇\|互\_s*換\|共\_s*\%(通\|産\_s*主\_s*義\_s*者\)\|継\_s*続\|ツ\_s*\%(ァ\_s*ー\|ィ\_s*リ\_s*ル\|ェ\_s*\%(ー\|ル\_s*ニ\_s*ー\|ラ\_s*ン\)\)\|炭\_s*素\)', + \ 'D' : '\%([共吃巴鑼錚鶏鳥響嫩緞丼呑曇貪鈍肭遠蚌溝鄰隣塢床処所年時鯲鰍鰌得徳讀獨髑毒読僮働萄桐閙ゞ嫐橈儂陶耨撓通鐃藤々恫瞳憧鬧⇔≡撞慟導〃仝洞堂瞠獰艟胴銅童動同道何弩怒退呶度堵奴解留融録取駑孥努戸止土ど瓰竕凸竍籵瓧禰泥捏溺寺鈿佃甸黏沺畋淀棯澱臀傳殿電照でヅ鶴辛強妻綱勤伝包筒做造作尽机月冢塚遣疲使突吊付漬津詰図積釣連づヂ中近力地痔持ぢ種棚倒濃彩逹畳諾゛濁玉默球魂騙谷館舘点岳嶽竹高凧蛸怛妲獺奪脱廼迺弟岱臺餒梯戴平内醍橙][題>≧第台代大鱈頼便誰樽懶怠灘斷椴黙旦煖彈暖談段断檀団團壇弾男抱舵橢炊佗堕荼拿打娜蛇楕陏駄唾拏雫沱立儺柁鴕溜妥朶陀墮駝出垂惰懦建兌澑田騨だ直◎.丶、,‥\.・…$“”↓†‡―┤達℃°独Dド÷◇◆ダジДデΔδд∂D]\|ッ\_s*\%(ト\_s*゙\|テ\_s*゙\|ツ\_s*゙\|チ\_s*゙\|タ\_s*゙\)\|ッ\_s*[ドデヅヂダ]\|っ\_s*[どでづぢだ]\|ト\_s*゙\|都\_s*々\_s*逸\|褞\_s*袍\|S\_s*a\_s*u\_s*r\_s*u\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|C\_s*\%(u\|o\_s*p\_s*p\_s*e\_s*r\)\|満\_s*天\_s*星\|豆\_s*腐\|如\_s*何\|テ\_s*゙\|刑\_s*事\|粘\_s*葉\_s*装\|手\_s*間\|木\_s*偶\|丁\_s*[稚抹]\|蝸\_s*牛\|ツ\_s*゙\|頭\_s*[腦痛]\|チ\_s*゙\|調\_s*子\|茶\_s*碗\|知\_s*恵\|忸\_s*怩\|タ\_s*゙\|忠\_s*幸\|壁\_s*蝨\|伊\_s*達\|山\_s*車\|韃\_s*靼\|提\_s*婆\_s*達\_s*多\|太\_s*\%([刀宰鼓]\|平\_s*広\|上\_s*天\_s*皇\|政\_s*\%(官\|大\_s*臣\)\)\|乃\_s*[公毅]\|体\_s*操\|葮\_s*竹\|演\_s*\%(し\_s*物\|繹\_s*デ\_s*ー\_s*タ\_s*ベ\_s*ー\_s*ス\)\|コ\_s*ロ\_s*ン\_s*ビ\_s*ア\|ズ\_s*\%(ロ\_s*ー\_s*ス\|ッ\_s*ク\)\|イ\_s*ル\_s*カ\|医\_s*者\|博\_s*士\|文\_s*書\|行\_s*列\_s*式\|発\_s*見\_s*す\_s*る\|ハ\_s*ー\_s*グ\|拒\_s*否\_s*さ\_s*れ\_s*た\|破\_s*壊\_s*\%(者\|す\_s*る\)\|消\_s*滅\_s*子\|記\_s*述\_s*子\|十\_s*進\_s*数\|ゼ\_s*ッ\_s*ケ\_s*ン\|復\_s*号\_s*化\|省\_s*略\|金\_s*剛\_s*石\|d\_s*\%(b\_s*m\_s*s\|e\_s*c\_s*\%([ia]\|r\_s*e\_s*s\)\|o\_s*u\_s*b\_s*l\_s*e\_s* \_s*i\_s*n\_s*c\_s*o\_s*m\_s*e\_s*,\_s* \_s*n\_s*o\_s* \_s*k\_s*i\_s*d\_s*s\|i\_s*m\)\|辞\_s*書\)', + \ 'E' : '\%([エ瘧腮偉鰓衿撰襟掾圜鹽垣檐媛爰捐¥覃黶篶湲蜒讌簷櫞悁渊轅渕閼魘薗艷鳶鴛焉嫣宛閻衍臙閹槐⌒援筵淹厭寃淵掩烟嚥圓沿宴蜿奄袁煙艶焔炎怨鉛園苑偃冤延婉遠堰燕演塩円縁刔刳抉猿狗描択鰕箙蛯蝦狄貊胡戎夷乢靨鉞噎戉咽粤桟悦閲謁奕伯懌亦蜴掖繹越役驛疫易益腋駅液殪纓裔曵頴洩瓔潁贏珱衡娃翳營瑩咏楹塋蠑瀛睿泳縊榮瑛暎曳盈郢影詠穎嬰鋭叡映営栄永衞衛得絵荏懷畫枝江繪衣猥慧惠獲回依會重柄杖餌榎画恵笑会囘選え━─┳┬┯┰┸┷┻┴Фф=⇔≡∈∋РрМмН→英∃式!ΗηEсСлЛΕЭεэエE]\|A\_s*\%([面判型級]\|V\_s*\%(機\_s*器\|女\_s*優\)\|B\_s*\%(型\|C\_s*順\)\)\|A\_s*\%([面判型級]\|V\_s*\%(機\_s*器\|女\_s*優\)\|B\_s*型\)\|M\_s*サ\_s*イ\_s*ズ\|M\_s*サ\_s*イ\_s*ズ\|豪\_s*物\|L\_s*\%(サ\_s*イ\_s*ズ\|L\_s*サ\_s*イ\_s*ズ\)\|L\_s*\%(サ\_s*イ\_s*ズ\|L\_s*\%(サ\_s*イ\_s*ズ\|教\_s*室\)\)\|羨\_s*道\|豌\_s*豆\|C\_s*\%(l\|h\_s*l\_s*o\_s*r\_s*i\_s*n\_s*e\)\|似\_s*\%(非\|而\_s*非\)\|桧\_s*原\_s*湖\|烏\_s*帽\_s*子\|吉\_s*方\|胞\_s*衣\|淮\_s*南\_s*子\|埃\_s*及\|干\_s*支\|岐\_s*路\|支\_s*繞\|壊\_s*[疽死]\|葡\_s*萄\|蛭\_s*子\|愛\_s*\%([理莉媛]\|知\_s*川\)\|N\_s*極\| \_s*n\_s* \_s*角\_s*形\|N\_s*\%([個極響]\|次\_s*元\|H\_s*K\_s*ホ\_s*ー\_s*ル\)\|斉\_s*魚\|兄\_s*鼓\|ヱ\_s*ス\_s*ビ\_s*ー\_s*食\_s*品\|S\_s*\%([波字席極]\|サ\_s*イ\_s*ズ\|N\_s*比\|F\_s*小\_s*説\)\|S\_s*\%([式極]\|サ\_s*イ\_s*ズ\|N\_s*比\|F\_s*小\_s*説\)\|穢\_s*[多土]\|X\_s*\%([軸脚]\|O\_s*醤\|染\_s*色\_s*体\)\|X\_s*\%([軸脚線]\|染\_s*色\_s*体\)\|海\_s*\%(老\|鷂\_s*魚\)\|帝\_s*都\_s*高\_s*速\_s*度\_s*交\_s*通\_s*営\_s*団\|ワ\_s*ー\_s*ク\_s*ス\_s*テ\_s*ー\_s*シ\_s*ョ\_s*ン\|欧\_s*\%(州\|羅\_s*巴\)\|歐\_s*\%(州\|羅\_s*巴\)\|ヨ\_s*ー\_s*ロ\_s*\%(ピ\_s*ア\_s*ン\|ッ\_s*パ\)\|ユ\_s*\%(ア\_s*ン\|ウ\_s*ロ\_s*ピ\_s*ウ\_s*ム\|リ\_s*イ\_s*カ\|ー\_s*\%(ロ\|ノ\_s*ス\|ニ\_s*ス\|ジ\_s*\%(ン\|ー\_s*ン\)\|ド\_s*ラ\|レ\_s*カ\|ラ\_s*\%(ス\|シ\_s*ア\)\|フ\_s*\%(ラ\_s*テ\_s*ス\|ォ\_s*\%(リ\_s*ア\|ニ\_s*ア\_s*ム\)\)\|ク\_s*リ\_s*ッ\_s*ド\|カ\_s*リ\)\)\|編\_s*集\|強\_s*調\|e\_s*m\_s*a\_s*c\_s*s\|電\_s*子\_s*メ\_s*\%(イ\_s*ル\|ー\_s*ル\)\|発\_s*展\|評\_s*価\_s*す\_s*る\|符\_s*号\_s*化\|百\_s*科\_s*事\_s*典\|カ\_s*プ\_s*セ\_s*ル\_s*化\|オ\_s*\%(ー\|イ\_s*\%(ラ\_s*ー\|ゲ\_s*ン\)\)\|実\_s*行\|拡\_s*張\|例\_s*外\|感\_s*嘆\_s*符\|ア\_s*\%([ンイ]\|ニ\_s*ド\|ー\_s*\%([マスル]\|ウ\_s*ィ\_s*ン\|ラ\_s*ン\|ニ\_s*ー\|ネ\_s*ス\_s*ト\|ミ\_s*ン\|シ\_s*ー\|リ\_s*ー\)\)\|設\_s*立\|e\_s*\%(x\_s*a\|コ\_s*マ\_s*ー\_s*ス\|ラ\_s*ー\_s*ニ\_s*ン\_s*グ\)\|イ\_s*\%([ブヴアラー]\|ジ\_s*ェ\_s*ク\_s*ト\|フ\_s*ェ\_s*ク\_s*[トタ]\|コ\_s*\%(ー\_s*ル\|ラ\_s*イ\_s*[ズザ]\)\|プ\_s*シ\_s*ロ\_s*ン\|ミ\_s*ュ\_s*レ\_s*\%(ー\_s*[トタ]\|イ\_s*タ\)\|ベ\_s*ン\_s*\%(ト\|タ\_s*ー\)\|ノ\_s*ッ\_s*ク\|ネ\_s*ー\_s*ブ\_s*ル\|ギ\_s*リ\_s*ス\|ン\_s*グ\_s*\%(ラ\_s*ン\_s*ド\|リ\_s*ッ\_s*シ\_s*ュ\)\|ッ\_s*チ\|ヤ\_s*\%(ー\|リ\_s*ン\_s*グ\|フ\_s*ォ\_s*ン\|ホ\_s*ン\)\|グ\_s*ジ\_s*\%(ッ\_s*ト\|ス\_s*ト\)\|ク\_s*\%(ス\|ア\_s*リ\_s*テ\_s*ィ\)\|ス\_s*フ\_s*ァ\_s*ハ\_s*ン\|リ\_s*[ヤア]\|レ\_s*\%(ー\_s*\%(ス\|ザ\_s*ー\|サ\_s*ー\)\|イ\_s*\%(ン\|ザ\_s*ー\|サ\_s*ー\)\|ブ\_s*ン\)\)\|ウ\_s*\%(ー\|ジ\_s*ェ\_s*ー\_s*ヌ\)\)', + \ 'F' : '\%([梺麓冬汾枌濆′吩賁刎氛雰糞褌忿墳吻紛焚扮分粉舊旧顫揮故震篩奮隹古衾襖贅燻筆鰒総惣總絃房閼鬱塞鞴章郁史艦簡札耽鰾吭笛文罧節苳蕗淦舩艙舷舟船肥太懷懐≦≠≫<>≧≪渊淵渕縁葢盖再弍蓋双藤潭蒸鯊鱶楓殕瘋封諷黻怫祓彿髴拂憤恚慍二払沸拒防蔔輹愎蝠茯箙腓⊃⊇膨脹嚢梟袋含⊂⊆袱覆輻腹幅復馥服副複福誣孚普俯更膚腐坿狂履不増拊鯆布怖赴桴巫傅婦付訃賻振負蜉罘老附吹生経觸夫俘父臥践咐敷踏斧溥阜葺深仆譜符麩匐腑榑芙賦殖冨触孵麸柎府舗噴鋪降蹈風觝埠拭鮒郛伏俛經歩苻斑畉扶趺芬呎フ飜翻ふ鉄♀∀¶富⌒金佛仏偽誤F♭弗浮ФΦφфフF]\|ッ\_s*フ\|ッ\_s*フ\|っ\_s*ふ\|鞦\_s*韆\|睾\_s*丸\|陰\_s*嚢\|乱\_s*吹\|相\_s*応\|E\_s*u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\|回\_s*回\_s*教\|書\_s*司\|図\_s*書\_s*寮\|海\_s*蘿\|補\_s*\%(任\|陀\_s*[洛落]\)\|雲\_s*脂\|頭\_s*垢\|鳧\_s*鐘\|菜\_s*蕗\|款\_s*冬\|蒲\_s*団\|M\_s*y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|釜\_s*[中山]\|雙\_s*葉\|B\_s*u\_s*d\_s*d\_s*l\_s*e\_s*j\_s*a\_s*c\_s*e\_s*a\_s*e\|渓\_s*井\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|2\_s*[人つ日]\|宿\_s*酔\|2\_s*\%([人つ日]\|通\_s*り\)\|□\_s*□\_s*□\|△\_s*△\_s*△\|×\_s*×\_s*×\|○\_s*○\_s*○\|帛\_s*紗\|河\_s*豚\|比\_s*律\_s*賓\|I\_s*r\_s*o\_s*n\|極\_s*東\_s*放\_s*送\|論\_s*理\_s*式\|形\_s*式\|ホ\_s*\%(ワ\_s*イ\_s*エ\|イ\_s*ル\|ル\_s*\%(マ\_s*\%(ン\_s*ト\|リ\_s*ン\)\|ム\_s*ア\_s*\%(ミ\_s*ド\|ル\_s*デ\_s*ヒ\_s*ド\)\)\)\|一\_s*杯\|関\_s*数\|機\_s*能\|汎\_s*関\_s*数\|修\_s*正\|ヒ\_s*\%(レ\|ュ\_s*ー\_s*[ズム]\)\|1\_s*\%(/\_s*f\_s*ゆ\_s*ら\_s*ぎ\|s\_s*t\)\|第\_s*1\_s*要\_s*素\|失\_s*敗\|ハ\_s*\%(エ\|ン\_s*ブ\_s*ル\|ロ\_s*ン\)\|柔\_s*軟\_s*な\|周\_s*波\_s*数\|エ\_s*フ\|f\_s*\%(e\_s*m\_s*t\_s*o\|o\_s*\%(n\_s*t\_s*-\_s*f\_s*a\_s*m\_s*i\_s*l\_s*y\|r\_s*t\_s*e\)\)\)', + \ 'G' : '\%([頃殺米諢魂權艮勤権鮴好蓙応駒若亊事琴毎如鏝埖込塵氷聲肥声腰拵心恋戀国石獄濠盒噛嗷敖軣哈壕熬刧遨拷囂轟毫傲鼇郷劫≡号豪剛梧后冴後吾寤宕珸茣児伍誤5極醐碁檎牾蜈唔篌庫娯悟忤呉期齬5互超五晤越子炬護兒瑚午沍ご〓郤鬩戟屐隙檄闃鷁撃激劇皃黥貎霓麑倪囈猊迎鯨芸藝齧囓蘖呟愿監芫痃广彦軒舷眩源儼衒絃弦験言諺現限幻玄減原蹴偈毛睨觧解実下拐夏げ靴腐種草口薬糞癖茱胡萸串嵎藕遇宮寓隅偶黒栗倉鞍蔵位昏麕羣郡群軍苦周包車狂食颶壷暮愚弘虞倶麌禺具惧壺組狗ぐ衣君嫌裂際牛崟憖斤垠岑吟銀圄禦圉馭魚嶷閠玉漁繞堯尭御曉嶢澆翹痙蟯驍僥仰業暁凝行謔瘧虐逆気義偽技切妓巍犠誼宜伎祁疑萓礒羲僞城蟻斬決擬沂議儀嶬艤着木曦犧欺戲魏祇戯ぎ川巛乾革皮側通殻辛絡柄烏鴉頷嚴阮鳫厳貫嵒偐巖岸厂⊃贋龕強翫岩鴈丸雁玩癌元願眼巌含頑上髮紙神髪鐘金係歸皈肯帰返潟方固語刀難型形鰹歹垳顔顏鎌窯蟇釜蒲蟹傘笠重號垣樫頭月合諤樂鍔壑鄂斈學齶萼愕嶽咢鰐額岳顎楽学既礙涯剴乂垓葢劾盖愾磑睚漑崕亥崖啀艾駭皚該咳階孩芥碍害鎧街凱慨概蓋骸外代峩狩我ヶ鵞駕訝変刈掛牙娥替畫駆ケ俄哦借呀果臥雅買蛾訛換河峨莪書芽貸衙画ヵ伽賀勝餓鵝が≫>G瓦≧ガゴχΕΗΣυΙΛαΨζρΒΝιΦφτλΠονψωΚΔΡδΤβΘΟπεΧΑΞσθηκΖΜξμΥΩギグゲгΓγГG]\|ッ\_s*\%(コ\_s*゙\|ケ\_s*゙\|ク\_s*゙\|キ\_s*゙\|カ\_s*゙\)\|ッ\_s*[ゴゲグギガ]\|っ\_s*[ごげぐぎが]\|コ\_s*゙\|小\_s*屋\|蒙\_s*御\_s*免\|巨\_s*頭\_s*鯨\|欣\_s*求\|独\_s*楽\|P\_s*e\_s*r\_s*s\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|瞽\_s*女\|歩\_s*行\_s*虫\|向\_s*拝\|皐\_s*月\|穀\_s*潰\|寄\_s*居\_s*虫\|降\_s*魔\|格\_s*\%([間縁]\|天\_s*井\)\|恒\_s*河\_s*沙\|江\_s*\%([津湖商州]\|談\_s*抄\)\|豆\_s*[油汁]\|ケ\_s*゙\|蚰\_s*蜒\|景\_s*色\|化\_s*粧\|鴃\_s*舌\|稽\_s*古\|懸\_s*魚\|還\_s*[向俗]\|拳\_s*[万固骨]\|喧\_s*嘩\|顕\_s*界\|ク\_s*゙\|救\_s*世\_s*菩\_s*薩\|工\_s*合\|供\_s*[奉祭香進]\|紅\_s*蓮\|キ\_s*゙\|毬\_s*杖\|岐\_s*\%([南阜]\|セ\_s*ン\)\|棋\_s*将\_s*谷\|求\_s*\%([法道肥]\|不\_s*得\_s*苦\|聞\_s*持\_s*法\)\|A\_s*g\|S\_s*\%(c\_s*r\_s*o\_s*p\_s*h\_s*u\_s*l\_s*a\_s*r\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|y\_s*m\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|i\_s*l\_s*v\_s*e\_s*r\)\|希\_s*臘\|杏\_s*葉\|餃\_s*子\|刑\_s*部\|カ\_s*゙\|搦\_s*み\|鑑\_s*真\|仮\_s*名\|蝦\_s*[蟆蟇]\|T\_s*y\_s*p\_s*a\_s*l\_s*e\_s*s\|鉤\_s*状\_s*部\|菓\_s*子\|甲\_s*斐\|会\_s*社\|g\_s*\%(i\_s*g\_s*a\|h\_s*o\_s*s\_s*t\_s*s\_s*c\_s*r\_s*i\_s*p\_s*t\)\|ヌ\_s*ー\|ニ\_s*ュ\_s*ー\_s*ズ\|g\_s*n\_s*u\_s*s\|ノ\_s*ー\_s*ム\|総\_s*司\_s*令\_s*部\|連\_s*合\_s*国\_s*軍\_s*総\_s*司\_s*令\_s*部\|ヒ\_s*ル\|ク\_s*ッ\_s*パ\|硝\_s*子\|ハ\_s*ボ\_s*ロ\_s*ー\_s*ネ\|瞿\_s*曇\|エ\_s*ー\_s*テ\_s*ボ\_s*リ\|ヨ\_s*ー\_s*テ\_s*ボ\_s*リ\|イ\_s*ェ\_s*\%(ー\_s*テ\_s*ボ\_s*リ\|テ\_s*ボ\_s*リ\)\|得\_s*る\|ヘ\_s*\%(ラ\_s*ル\_s*ド\|ル\_s*マ\_s*ン\)\|ド\_s*イ\_s*ツ\|成\_s*吉\_s*思\_s*汗\|ゼ\_s*\%(ラ\_s*\%(チ\_s*ン\|ニ\_s*ウ\_s*ム\)\|ム\_s*ク\_s*リ\_s*ッ\_s*プ\|ノ\_s*ア\|ン\_s*ト\_s*ル\_s*マ\_s*ン\|ネ\_s*\%(コ\_s*ン\|ラ\_s*\%(ル\|リ\_s*ス\_s*ト\)\)\)\|大\_s*\%(蚊\|学\_s*院\_s*生\)\|ジ\_s*\%([ムルジグノナオンー]\|プ\_s*シ\_s*ー\|ア\_s*ン\|イ\_s*ド\|ッ\_s*ド\|タ\_s*ン\|ゼ\_s*ル\|リ\_s*ア\_s*ン\|レ\_s*ッ\_s*ト\|ゴ\_s*ロ\|ラ\_s*\%(フ\|ル\_s*\%(ド\|デ\_s*ィ\_s*ー\_s*ノ\)\)\|ロ\_s*\%(ー\|ン\_s*ド\)\|バ\_s*ン\_s*シ\_s*ー\|ブ\_s*\%(リ\|ラ\_s*ル\_s*タ\_s*ル\)\|ベ\_s*\%(ル\_s*ナ\_s*ウ\|レ\_s*リ\_s*ン\)\|ネ\_s*ッ\_s*ト\|ョ\_s*\%(ッ\_s*ト\|ヴ\_s*ァ\_s*ン\_s*[ニナ]\|バ\_s*ン\_s*[ニナ]\|コ\_s*\%(ー\_s*ソ\|ン\_s*ダ\)\|ル\_s*\%(ジ\|ダ\_s*ー\_s*ノ\)\|ー\_s*\%(ジ\|ゼ\_s*ッ\_s*ト\)\)\|ャ\_s*\%(ン\|イ\_s*\%(ロ\|ル\_s*ズ\|ア\_s*ン\_s*[ツト]\)\|コ\_s*\%(モ\|メ\_s*ッ\_s*テ\_s*ィ\)\|ー\_s*マ\_s*ン\)\|ニ\_s*ー\|ュ\_s*\%([レネ]\|ゼ\_s*ッ\_s*ペ\|リ\_s*\%(ア\|ー\_s*ニ\|エ\_s*ッ\_s*タ\)\|ヌ\_s*\%(ヴ\_s*ィ\_s*エ\_s*ー\_s*ヴ\|ビ\_s*エ\_s*ー\_s*ブ\)\)\|ェ\_s*\%([リルフムマネ]\|ス\_s*チ\_s*ャ\_s*ー\|ロ\_s*ニ\_s*モ\|ラ\_s*\%(ー\_s*[トルド]\|ル\_s*\%(ド\|デ\_s*ィ\_s*ン\|ダ\_s*イ\_s*ン\)\)\|ミ\_s*ニ\|ニ\_s*ー\|ノ\_s*\%([アバ]\|ヴ\_s*ァ\|ワ\_s*ー\_s*ズ\|サ\_s*イ\_s*ド\)\|ン\_s*\%(マ\|ト\_s*\%(ル\|リ\_s*[ィー]\)\|ダ\_s*ー\)\)\)\)', + \ 'H' : '\%([ホ洞袰亡滅幌濠壕畚笨略艢檣炎焔仄朖朗塊程施滸殆幾缶熱解屠榾螢蛍骨細本※*糒恣縦擅星戟戈桙綻祠誇埃矛鉾堀頬褓鴇枋峯磅鞄峰垉篷勹皰朴抔怦棒泙棚堋呆豐麭膀舫弸蔀袍苞葬琺寳炮鵬寶繃鋒魴髣逢朋烹鳳彗箒俸焙蓬烽幇抱崩訪泡澎彷縫捧萌萠彭包胞倣邦飽庖疱奉豊硼報砲宝攴攵瀑蹼樮北哺欲譽餔保抛浦誉掘脯賞黼恍堡輔穗襃葆彫穂畝吼舖耄葡褒惚咆埔哮捕逋ほヘ謙遜篦廰廳貶胼諞篇駢褊蝙翩變∂遍返騙編扁変暼丿諛諂隔凹臍巳蛇蒂蔕瓸竡粨癖躄甓闢璧劈碧壁竝餅娉塀病閇聘坪嬖幤箆蔽并陛屏炳斃瓶幣弊併敝閉並屁折邉舳辺歴圧戸減邊へフ梺麓冬♭汾枌濆′吩賁氛雰糞褌忿墳吻紛焚扮分粉舊旧顫揮故震篩奮隹古衾襖贅燻鰒陰総惣總絃房閼鬱塞章郁艦簡補札耽鰾吭笛芬呎文罧節苳蕗淦舩艙舷舟船蒲懷懐≦≫>≧≪渊淵渕縁葢盖弍蓋双B藤潭蒸鱶楓殕瘋封諷黻怫彿髴佛憤恚慍仏F弗沸Φφ拒防蔔輹愎蝠茯箙⊃⊇嚢梟袋含⊂⊆袱覆輻復馥副複福誣孚普俯更腐坿狂不増拊鯆怖赴桴巫傅婦付訃賻振負蜉罘附吹経觸夫俘父臥践咐敷踏斧溥阜葺深仆譜符麩匐榑芙賦殖冨触孵麸柎府舗噴鋪降蹈風觝埠拭鮒郛伏俛經歩富苻畉扶趺ふヒ鶸禀蘋彬斌嬪繽殯賓擯牝貧頻瀕稟品葫怯晝飜蒜蛭昼綬胙紐鰭∝片衡鮃閃鵯辟百媛姫尋擴仭太仞展宥絋拡拓拾祐恕紘煕泰熙寛洋弘宏啓裕浩廣広冰雹俵飃凭冫髟彪驫飆馮殍飄豹漂驃慓剽嫖兵票憑評標平表燧老拈捫撚捻歪籤籖柊魃旱秀跪膝蜩羆佗攣−低隙閑暇雛髯鬚髭¬蹄潛濳潜顰密窃鬻提瓢蠡瓠匏央恒壽廂尚寿久蟆率痙蟇丙丁孤史女獨独稘斎斉均倫準等≠單偏単他仁瞳人11柆蔆拉杓柄犇◇◆菱醢醤曾蘖彦酷漬浸鶲額聖肱肘熈芒光膕控皹皸響罅僻鰉逼疋蹕畢匹篳棺柩弼櫃謐坤未羊筆必養襞饑「<【(←『左臂轡曳灯緋朏砒火日蜚妣費狒匕泌杼庇悲樋退脾挽痺卑贔紕牽避引菲檜被碑匪裨斐秘豼霏蓖丕批妃髀干昜彼秕氷鄙飛比否碾疲梭披桧魅惹俾鞴冷譬貔乾肥罷痞索扉暃毘轢皮陳鞁祕ひハ布鱧釖鉤蝟梁鍼磔針禳肚腑腸孕原拂祓払遼請温玄腹陽遙悠東遥治春頓鮠捷鶻駿疾囃林隼鈑膰磐樊潘泛畔蟠釆拌笵胖絆氾坂范凡燔楾洪瘢翻板攀゜大伴煩槃袢斑判範藩繙蕃版搬叛班阪般販犯汎帆頒反侍鯊櫨祝?硲間劇激勵烈励速蝿蠅省飯勢彈外弭筈辱逸育毓齦浮阻難掵憚幅巾柞母翅圃旛旙将側旌幟傍働鰰機叩疥畠幡籏畑旗斜鴿再鳩開秦跣膚肌裸弾薑椒壹甫馨壱弌哉一創元始鋼芳夾剪鋏螯挾挟脛萩餞贐離塙英蕚萼衄衂縹譚咄放噺話洟甚鼻華花赱迸奔枦觜艀婢梯燥箸柱走橋匣凾箪筐□繁方運匚筥箱函陌栢魄膊柏亳珀狛佰粕璞蘗岶愽擘箔舶泊搏迫帛拍圖諮測企秤謀量計図儚捗袴伯博墓髮秡癶釟溌肇廿二初椀蓮8♪鉢蜂發髪服半法醗薄白八発霈盃睥擺湃孛裴琲埴碚牌吠拜坏珮旆入沛榛杯悖―廢腓誹徘稗癈肺俳憊輩背鷂胚廃排拝敗灰配蛤濱浜吐食霽恥菠帚杷垪跛耻巴笆履脹葉爆矧帶這撥破嵌霸捌早把刎馳填生簸跳派禿碆羽果覇映晴陂端剥腫匍着穿葩爬歯膨坡佩慙芭刄菷怕榮齒刃播愧暎叭栄玻掃張貼刷羞頗琶は━─┘┛┸┷┻┴┓┐┳┬┯┰┨┫┤┥┼╋╂┿波‐フ★☆非HヒホヘハH]\|ッ\_s*[ホヘフヒハ]\|ッ\_s*[ホヘフヒハ]\|っ\_s*[ほへふひは]\|寄\_s*生\|珠\_s*鶏\|混\_s*一\_s*色\|紅\_s*[幇中]\|T\_s*r\_s*i\_s*u\_s*r\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|微\_s*[酔笑]\|子\_s*規\|時\_s*鳥\|蜀\_s*魂\|杜\_s*[宇鵑]\|上\_s*枝\|鬼\_s*灯\|酸\_s*漿\|叢\_s*祠\|和\_s*了\|鮑\_s*魚\|謗\_s*法\|黒\_s*子\|部\_s*屋\|竹\_s*\%(畚\|麦\_s*魚\)\|綜\_s*麻\|巻\_s*子\|下\_s*手\|糸\_s*瓜\|h\_s*e\_s*c\_s*t\_s*o\|霹\_s*靂\|c\_s*l\_s*a\_s*u\_s*s\_s*t\_s*r\_s*o\_s*p\_s*h\_s*o\_s*b\_s*i\_s*a\|鞦\_s*韆\|睾\_s*丸\|乱\_s*吹\|相\_s*応\|E\_s*\%(r\_s*i\_s*o\_s*c\_s*a\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\|u\_s*p\_s*t\_s*e\_s*l\_s*e\_s*a\_s*c\_s*e\_s*a\_s*e\)\|回\_s*\%(鍋\_s*肉\|回\_s*教\)\|書\_s*司\|頭\_s*垢\|鳧\_s*鐘\|菜\_s*蕗\|款\_s*冬\|f\_s*\%(o\_s*r\_s*t\_s*e\|e\_s*m\_s*t\_s*o\)\|釜\_s*[中山]\|雙\_s*葉\|渓\_s*井\|G\_s*e\_s*r\_s*a\_s*n\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|宿\_s*酔\|△\_s*△\_s*△\|×\_s*×\_s*×\|○\_s*○\_s*○\|河\_s*\%(豚\|底\_s*撈\_s*魚\)\|神\_s*[庫籬]\|肩\_s*巾\|領\_s*巾\|素\_s*見\|曹\_s*白\_s*魚\|枚\_s*[田方]\|敬\_s*昌\|幸\_s*展\|容\_s*靖\|晃\_s*道\|欧\_s*子\|宙\_s*子\|祥\_s*加\|終\_s*日\|翡\_s*翠\|曽\_s*祖\_s*父\|豪\_s*将\|偉\_s*紀\|周\_s*[行男]\|茅\_s*蜩\|向\_s*日\_s*葵\|七\_s*宗\|桶\_s*坂\|永\_s*和\|蟾\_s*蜍\|抽\_s*\%([斗出]\|き\_s*出\_s*し\)\|告\_s*天\_s*子\|雲\_s*[脂雀]\|為\_s*人\|緊\_s*[と々]\|鎮\_s*火\_s*\%(祭\|の\_s*祭\)\|A\_s*\%(s\|r\_s*s\_s*e\_s*n\_s*i\_s*c\|n\_s*g\_s*i\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\|粃\_s*糠\_s*疹\|只\_s*管\|直\_s*[向走垂隠]\|常\_s*陸\|鹿\_s*尾\_s*菜\|撲\_s*り\_s*倒\|同\_s*胞\|赦\_s*い\|青\_s*春\|哈\_s*爾\_s*浜\|美\_s*佳\|流\_s*行\|勇\_s*[樹人]\|韓\_s*流\|漢\_s*堡\|汗\_s*国\|盤\_s*陀\|R\_s*S\_s*I\|蔓\_s*延\|蝦\_s*虎\_s*魚\|沙\_s*魚\|馬\_s*銜\|狭\_s*間\|南\_s*風\|延\_s*\%(縄\|い\_s*て\)\|義\_s*母\|旅\_s*籠\|N\_s*e\_s*l\_s*u\_s*m\_s*b\_s*o\_s*n\_s*a\_s*c\_s*e\_s*a\_s*e\|黄\_s*[酒櫨]\|土\_s*[方生師]\|嘔\_s*[吐気]\|支\_s*倉\|長\_s*谷\|接\_s*ぎ\_s*合\|纏\_s*頭\|煙\_s*火\|麻\_s*疹\|階\_s*[上子]\|嘴\_s*\%(細\_s*鴉\|太\_s*鴉\)\|学\_s*胤\|2\_s*\%([人つ日]\|通\_s*り\|0\_s*日\)\|2\_s*\%([人つ日]\|0\_s*[歳日]\)\|淡\_s*竹\|8\_s*月\|客\_s*家\|P\_s*\%(t\|o\_s*t\_s*a\_s*m\_s*o\_s*g\_s*e\_s*t\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*t\_s*i\_s*n\_s*u\_s*m\)\|海\_s*\%([鞘永蘿星牙]\|拉\_s*爾\|底\_s*撈\_s*月\)\|M\_s*\%(y\_s*r\_s*t\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*c\_s*u\_s*r\_s*y\)\|色\_s*調\|呼\_s*和\_s*浩\_s*特\|ウ\_s*ー\_s*ゴ\|ユ\_s*\%(ー\|ペ\_s*ー\_s*ル\|ベ\_s*ー\_s*ル\|イ\_s*ス\_s*マ\_s*ン\_s*ス\|ゴ\_s*ー\|グ\_s*ノ\_s*ー\|マ\_s*ニ\_s*\%(テ\|ス\_s*[トム]\)\)\|現\_s*代\|十\_s*六\_s*進\_s*数\|高\_s*さ\|香\_s*港\|イ\_s*\%(ダ\_s*ル\_s*ゴ\|ス\_s*パ\_s*ニ\_s*ア\|レ\_s*ー\_s*ル\|エ\_s*ロ\)\|オ\_s*\%([ラー]\|ナ\_s*ー\|ノ\_s*レ\|ン\_s*フ\_s*ル\_s*ー\_s*ル\|ネ\_s*\%(ス\_s*\%(ト\|テ\_s*ィ\)\|ゲ\_s*ル\)\|テ\_s*ル\|ル\_s*ガ\_s*ー\|マ\_s*ー\_s*ジ\_s*ュ\)\|ア\_s*\%(ン\_s*\%(リ\|ベ\_s*ー\_s*ル\)\|ネ\_s*ス\_s*ト\|ワ\_s*ー\|ダ\_s*マ\_s*ー\_s*ル\|シ\_s*ェ\_s*ッ\_s*ト\|ビ\_s*タ\_s*シ\_s*オ\_s*ン\|ー\_s*\%(ネ\_s*ス\_s*ト\|ノ\_s*ン\_s*ク\_s*ー\_s*ル\)\)\|エ\_s*\%(デ\_s*ィ\|ン\_s*リ\_s*ケ\|レ\_s*\%(ナ\|ー\_s*ヌ\)\|ロ\_s*イ\_s*ー\_s*ズ\|ク\_s*ト\_s*ル\|ル\_s*\%(ゲ\_s*ラ\|ヴ\_s*ェ\|メ\_s*ス\|マ\_s*ン\|ミ\_s*\%(ッ\_s*ト\|ー\_s*ト\)\|ブ\_s*ラ\_s*ン\|ナ\_s*ン\_s*デ\_s*ス\|キ\_s*ュ\_s*ー\_s*ル\)\|ノ\_s*ク\|ッ\_s*チ\|イ\_s*チ\)\|水\_s*[銀平素]\)', + \ 'I' : '\%([イΗη賤鄙卑苟嫌弥薯妹藷芋夢艷鑪鈩彩鱗色鯆忽綺貸甍応答愈圦杁霪隱蚓寅氤酳胤飮韵尹茵贇蔭婬湮堙廴音飲慇韻咽淫殞姻隕院允殷隠陰窟巌巖頌祝鰛鰮鰯岩磐円¥鼾歪弑弋抱懐肬贅疣狗戌乾犬諱在坐未汝戒誡警縛今Εε曰禾稻員因蝗嘶鰍電引躄誘動忿≦鵤錨碇怒霆雷霹凧桴筏魚S菴庵彌雖家尿荊棘茨祈祷命猯豕古伍乙鎰鴪聿軼樹慈悼愴慯労格到至傷鼬頂戴病徒致鈑痛板柞砂沙些聊潔諍烈功諫勳勲勇漁諌憇=憩粹熱粋憤域閾勢勤忙急磯孰焉湶泉厳何弄苛≧鎔范啀毬訝燻息挑縷絲厭營営愛幼稚緒遑暇糸弌壹肆莓苺櫟著市碑鐓礎甃臀弩石犧牲犠池溢Y佚壱11燠鬻礇毓粥的戦戰軍幾郁育一稲否飯洟位違居姨猗斎偽噫逝医鑄痍委囲云圍ゐ挿炒彙要熨饐醫言矮往詒威懿如僞忌彜煎逶緯韋唯莞淹胃善生恚彝惟以活易蔚為猪衣已倚幃斐移鮪将可偉畏五夷李渭怡貽癒依逸井慰行爲胆射詑矣頤熬萎良凍出椅率好揖肄痿鋳謂帷亥苡意維遺鰄異去堰尉容囗い氷Йй⇒→⊂⊃▼▽伊印入∞吋∈∋∫∬∩IイИΙιи私I]\|E\_s*メ\_s*ー\_s*ル\|灼\_s*然\|祖\_s*谷\|湯\_s*文\_s*字\|文\_s*身\|郎\_s*[女子]\|刺\_s*[青草]\|蕁\_s*麻\|U\_s*r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|海\_s*[豚参]\|西\_s*表\|鸚\_s*哥\|影\_s*青\|況\_s*ん\_s*や\|所\_s*謂\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|藺\_s*草\|J\_s*u\_s*n\_s*c\_s*a\_s*l\_s*e\_s*s\|田\_s*舎\|膝\_s*行\|十\_s*六\_s*夜\|寝\_s*穢\|英\_s*\%(蘭\|吉\_s*利\)\|斑\_s*鳩\|烏\_s*賊\|玉\_s*筋\_s*魚\|硫\_s*黄\|夜\_s*来\_s*香\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|牛\_s*膝\|稜\_s*威\|常\_s*春\_s*藤\|5\_s*[つ日]\|5\_s*[つ日]\|惡\_s*戲\|甚\_s*振\|潮\_s*来\|悪\_s*戯\|交\_s*喙\|小\_s*魚\|鯨\_s*魚\|細\_s*小\_s*魚\|鶏\_s*魚\|経\_s*緯\|礒\_s*[山田]\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|和\_s*泉\|E\_s*\%(A\_s*S\_s*T\|V\_s*E\)\|気\_s*吹\|指\_s*宿\|拠\_s*所\|従\_s*[妹姉弟兄]\|公\_s*孫\_s*樹\|鴨\_s*脚\_s*樹\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|銀\_s*杏\|鳶\_s*尾\|檪\_s*本\|巫\_s*子\|神\_s*巫\|睦\_s*月\|都\_s*方\_s*流\|縊\_s*[殺死首]\|蝟\_s*[集縮]\|埋\_s*け\_s*[火炭]\|許\_s*[婚嫁]\|<\_s*=\_s*=\_s*>\|必\_s*要\_s*十\_s*分\_s*条\_s*件\|ヤ\_s*ン\|日\_s*本\_s*ア\_s*イ\_s*・\_s*ビ\_s*ー\_s*・\_s*エ\_s*ム\_s*株\_s*式\_s*会\_s*社\|国\_s*際\_s*\%(基\_s*督\_s*教\_s*大\_s*学\|標\_s*準\_s*化\_s*機\_s*構\)\|逆\_s*離\_s*散\_s*フ\_s*ー\_s*リ\_s*エ\_s*変\_s*換\|識\_s*別\_s*子\|即\_s*興\_s*曲\|な\_s*ら\_s*ば\|項\_s*目\|逐\_s*次\_s*型\|i\_s*ノ\_s*ー\_s*ド\|i\_s*\%(ア\_s*プ\_s*リ\|P\_s*o\_s*d\|モ\_s*ー\_s*ド\|M\_s*a\_s*c\|ノ\_s*ー\_s*ド\)\|誤\_s*っ\_s*た\|無\_s*\%(花\_s*果\|効\_s*な\)\|帰\_s*納\_s*法\|字\_s*下\_s*げ\|不\_s*\%([可如足]\|充\_s*分\)\|具\_s*体\_s*化\|情\_s*報\|導\_s*入\|整\_s*数\|完\_s*全\|ヨ\_s*\%(ア\_s*ン\|シ\_s*フ\|ー\_s*ド\|ウ\_s*素\)\|ア\_s*\%(イ\|ー\_s*\%(ヴ\_s*ィ\_s*ン\|ビ\_s*ン\)\|ン\_s*\%(プ\_s*ロ\_s*ン\_s*プ\_s*\%(チ\_s*ュ\|テ\_s*ュ\)\|デ\_s*パ\_s*ン\_s*ダ\_s*ン\|フ\_s*ォ\_s*ル\_s*\%(メ\_s*ル\|マ\_s*テ\_s*ィ\_s*ー\_s*ク\)\)\)\)', + \ 'J' : '\%([塩嶋縞島嶌橲衄衂宍竺舳忸軸舌喰食直凝實昵実印尻稔仭糂贐潯儘仞盡刄臣侭恁進訊俥蕁迅刃靱荏甚靭燼櫁樒塵尽尋陣腎壬人敘恕耡汝莇杼茹敍蜍洳舒縟辱褥蓐溽所抒鋤徐序絮叙助釀淨疂絛繞壌諚孃瀞襄仍蟐拯疉讓聶驤生帖仗躡穰乘塲靜繩禳蕘壤遶星滌茸嬲疊如剩娘嬢錠静醸縄女尉饒丈成擾穣烝嫋丞盛場杖條条蒸貞状攘剰畳冗定浄乗情城上常譲濡得戍就嬬鷲竪讐讎懦愀咒聚隼詢徇笋凖盾楯筍篤蓴惇洵淳閏諄恂馴旬荀潤循醇巡遵順准殉純準襦誦需戌朮孰宿塾珠熟恤術述孺呪豎儒綬樹受授壽鞣狃澀揉廿拾縱中從糅从戎澁蹂神汁獸絨縦渋柔什充十獣従住銃重岻除士染時怩至児冶璽只畤侍孳轜耳示次寿辭粫司二祀邇而慈峙爺以地塒珥迩痔死敷恃蒔磁瓷仁字尓焦膩柱似嗣子亊路史餌兒滋仕爾辞弍自茲持寺事知醤鮭搦着惹尺鉐雀寂若弱蛇闍者邪戯麝じ│┃├┝┣┠┏┌.еЕ治Яя日юЮJёЁЙジйJ]\|ッ\_s*シ\_s*゙\|ッ\_s*ジ\|っ\_s*じ\|G\_s*\%(メ\_s*ン\|パ\_s*ン\)\|D\_s*y\|G\_s*\%(メ\_s*ン\|パ\_s*ン\)\|支\_s*度\|試\_s*合\|2\_s*乗\|2\_s*乗\|祖\_s*父\_s*\%(さ\_s*ん\|祖\_s*母\)\|獅\_s*子\|甲\_s*乙\_s*丙\_s*丁\_s*戊\_s*己\_s*庚\_s*辛\_s*壬\_s*癸\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|Z\_s*\%(r\|i\_s*r\_s*c\_s*o\_s*n\_s*i\_s*u\_s*m\)\|深\_s*\%(秘\|大\_s*寺\)\|秦\_s*泉\_s*寺\|沈\_s*\%(香\|丁\_s*花\)\|晨\_s*朝\|濁\_s*世\|判\_s*官\|諍\_s*論\|長\_s*夜\|漏\_s*斗\|↑\_s*↓\_s*←\_s*→\|焼\_s*酎\|鐘\_s*石\|橈\_s*脚\_s*類\|承\_s*久\|朱\_s*里\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|絢\_s*子\|頌\_s*偈\|数\_s*珠\|入\_s*[魂牢来洛院内水棺]\|霜\_s*月\|1\_s*\%(2\|6\_s*進\|0\_s*[進月]\|1\_s*月\|8\_s*禁\)\|師\_s*走\|極\_s*月\|紐\_s*帯\|1\_s*\%(0\|1\_s*月\|8\_s*禁\|2\_s*月\)\|シ\_s*゙\|爪\_s*哇\|射\_s*礼\|砂\_s*利\|謝\_s*花\|三\_s*味\_s*線\|雑\_s*魚\|著\_s*語\|杓\_s*子\|共\_s*同\_s*企\_s*業\_s*体\|j\_s*\%(T\_s*e\_s*X\|L\_s*a\_s*T\_s*e\_s*X\|B\_s*i\_s*b\_s*T\_s*e\_s*X\)\|ゼ\_s*リ\_s*ー\|エ\_s*\%(ホ\_s*バ\|リ\_s*コ\|レ\_s*ミ\_s*ヤ\|ル\_s*サ\_s*レ\_s*ム\|ッ\_s*サ\_s*イ\)\|ヘ\_s*\%(レ\_s*ス\|ス\_s*ス\)\|ヒ\_s*メ\_s*ネ\_s*ス\|チ\_s*ゲ\|北\_s*陸\_s*先\_s*端\_s*\%(大\|科\_s*学\_s*技\_s*術\_s*大\_s*学\_s*院\_s*大\_s*学\)\|ハ\_s*\%(イ\_s*メ\|ラ\_s*ペ\_s*ー\_s*ニ\_s*ョ\)\|碧\_s*玉\|ヤ\_s*\%([リンニナー]\|イ\_s*ル\|エ\_s*ル\|ル\_s*ノ\|レ\_s*ド\|ヌ\_s*\%(ス\|シ\_s*ュ\)\|ス\_s*パ\_s*ー\_s*ス\|コ\_s*[ビブ]\|ッ\_s*ケ\)\|フ\_s*\%(ァ\_s*[ンナ]\|リ\_s*[オア]\)\|ズ\_s*ボ\_s*ン\|ユ\_s*\%([ハリダノ]\|ル\_s*ゲ\_s*ン\|ー\_s*\%([リノ]\|ゲ\_s*ン\_s*ト\|デ\_s*ィ\_s*ッ\_s*ト\)\|ン\_s*\%(グ\|カ\_s*ー\|ケ\_s*ル\)\|ピ\_s*テ\_s*ル\|ッ\_s*[カシ]\)\|イ\_s*\%(エ\_s*\%([ナス]\|ン\_s*\%(ス\|セ\_s*ン\)\|ズ\_s*ス\)\|ェ\_s*\%(ナ\|ン\_s*\%(ス\|セ\_s*ン\|ゼ\_s*ン\)\|ー\_s*ガ\_s*ー\|ル\_s*\%(ク\|サ\_s*レ\_s*ム\)\)\)\|ホ\_s*\%([タセ]\|ル\_s*ヘ\|ホ\_s*バ\|ア\_s*\%(ン\|キ\_s*ン\)\)\|ヨ\_s*\%([ブナ]\|ル\_s*\%(グ\|ダ\_s*ン\)\|エ\_s*ル\|ア\_s*\%(ヒ\_s*ム\|キ\_s*ム\)\|ゼ\_s*フ\|ー\_s*\%([トド]\|デ\_s*ル\|ゼ\_s*フ\)\|シ\_s*\%(フ\|ュ\_s*ア\)\|セ\_s*フ\|ハ\_s*[ナンネ]\)\)', + \ 'K' : '\%([コ怖旃之惟怺薦米暦轉殺壼鶤袞鯤坤狠艮琿悃很漿棍魂菎滾梱溷痕渾墾恨懇根梢杪王泥裔樸鞐熟枹醴聲声蛩凍溢零錯苔箏亊判斷諺理断盡悉尽辞詞殊事壽寿鯒礫鯉齣狛腓昆瘤鮗谺応應答茲是爰試志心凩兀笏惚榾輿甑腰拵拗鐺鏝昿仰慌袷塙頏絖冦耗亙峺衝晄覯糠匣逅閧扛湊羔礦爻壙盍洸鬨浤凰閤窖缸寇岡傚湟汞洽崗鮫伉訌誥冓敲磽倖簧鏗椌搆肓鍠矼砿犒淆呷鵁皐黌遘昴槹蚣肱肴熕胱猴扣杲蛤縞狎畊昊餃哽幌鱇峇嫦鎬隍恆倥徨啌吭釦闔藁亘絋棡遑紘稾鴿詬哮困靠皋惶紺鈩絳閘蒙冰氷郡蛟槁候楮媾溘蝗酵嚆犢稿亢哄睾慷郊岬肛項巷鑛洪佼狡昂叩勾喉滉糀晃剛晧曠宏控恍侯港皓坑皎耿膏江絞膠虹巧鴻鉱衡浩厚幸耕弘綱抗購攻講恒溝薨鋼航行肯荒高皇光好槲梏谷釛尅斛轂哭石告酷穀冴虎觚壷痼胯鼓児漉糊媚古娘冱混粉請辜湖虍放葫捏此鈷痩鴣瞽詁呼箍小錮蠱蛄粐滬估雇故沽転倒漕罟餬超込凅誇懲琥扈袴焦蝴呱乕踰弧越子孤菰跨壺楜股肥凝女戸恋兒怙瑚戀夸皷滸濾瓠濃乎仔こケ峻欅獸謇鵑愃搴劒俔儉險瞼慊圈幵釼顯剱椦黔暄劔涓臉妍劵歉獻縣蜷綣檢鉉虔愆娟權甄惓諠騫験慳捲倦遣羂嶮蹇鹸狷譴腱驗軒憲繭謙圏険硯倹献犬絢顕券劍剣見権研拳眷牽県建烟鑷言獣蓋涜吝削畩閲検貶健桁嗾竭獗偈譎碣蕨尻頡抉襭亅刔杰厥訐歇訣孑頁纈蹶桀穴傑結血煢蹊黥詣攜綮鮭絅盻挈瓊夐冂笄枅奚兮迥畦彑醯徑剄冏勍檠憬挂憇匸逕繼惠慧謦鷄系┓├┃┣┿━┻┷┸─┫┝┳┬┼┯┥╋┨┛│┠┰┏┤┴╂罫痙奎脛谿溪螢蛍渓閨憩圭携硅恵刑継勁珪計啓蹴毛褻異けク姑配椚橡檪櫪栩椡椪湫箜櫟含纐柵婚屎糞癖潛潜鵠凹窪縊跟頚軛珞頸首諄鞋履窟轡覆沓碎砕条降件頽崩屑釘莖茎陸杙杭掘崛倔鶏鐃藥擽薬樟楠梳櫛串釧與与挫籖鯀鯨籤隈熊艸嚔藾叢鏈腐鎖種Ξξ臭楔草圀邦國国髭漱嗽吻嘴唇脣梔腔φ粂裙勳熏皹桾皸醺崑燻訓勲葷委詳钁精鍬咥銜桑某暝峅昏冥眛罔鮓比闇位鞍藏暗倉廚厨涅曇蜘佝栗包俥車梍枢畔鐵玄蔵黒食孔桍窶暮焼懼駒苦区眩吁繰庫垢紅呉倶枸劬煦口瞿工吼怐喰貢惧區組句狗酌絎嶇衢刳くキ段痍疵紲絆傷築鱚嚴稷黍帛後碪砧絹兆萌刻鞫椈掬辟君牙蘗檗迄訖狐屹詰佶拮吃鞠橘菊喫.&⌒¬★!÷≠♪∫%±・。仝●|―¥Ц△‡`←¢£‰◎+ ̄〒☆ヽゞ、▽◇↓≒\;″°∝≦々℃∵†○´゛‥♭<#〇□‐_Å∞:▲ヾ♂?^,〓‖▼…〃¶゜@≫§∴′ゝ/>♀∨=≧ー−≪$♯↑■¨≡〆◆∽煙蚶更衣細后妃楸蕈茸乙雉轢杵軋岸桔汚穢北樵際裂燦煌雲嫌胆竏粁瓩浄淳澄潔清雰錐蛬吉霧檮桐箘鈞檎襟忻箟掀磬噤听瑾懃覲釁芹衿饉釿衾斤蒟径窘擒巾菌公禽筋錦欣僅琴均禁緊謹欽近勤嘘踞據苣擧渠秬鉅舉筥慶倨距歔遽鋸醵拠拒去勗蕀洫亟跼旭局挙許居巨虚轎繦羌姜篋蕎陜恊竸荊筴徼峽劫恟況棘竅僵亰狹頃筺梗誑刧襁烱洶抂卿鍄炯經竟廾况孝亨跫敬筐梟饗矯矜挾校挟拱嬌杏鞏響向興匈嚮享警競喬怯兄彊僑兢莢狂橋供郷兇驕凶叫夾匡侠狭恐経疆協境強胸驚脅共恭今教玖鬮歙舊疚笈邱赳摎恷岌貅9扱皀烋樛蚯逑厳胡翕朽泣穹糾糺及躬汲臼窮灸弓宮久柩究給丘求鳩級球休救急旧吸九基欹寄貴跂徠聞覊猗櫃煕既弃氣詭嬉效切妓跪虧卉稘尋冀暉唏姫伐喟伎畸効熙癸噐極祁匱馗旡其碁剞畿規希綺燬騎饑逵樹忌朞騏城聽棄悸肌生几季記僖紀斬決槻期起箕聴鰭崎餽倚幃瞶利晞欷毅危屓熈着汽木飢酒愾熹諱淇器羇机企麾訊著剪稀来圻來鬼揆奇羈禧譏棋黄憙己驥鑽决毀掎曁竒窺喜碕祈耆饋揮愧棊幾气徽消截岐祺麒覬嵜杞軌きカ糜癢粥痒麹輕骨業軽鰔鰈餉通瓶龜甕亀鴈獵鳫殯猟雁釀鳧鳬髢鴨躱巛側厠廁磧瓦獺翡裘皮紮→搦苧碓柄枳體軆躰躯体鴉犂烏機絡空唐榧茅揀坎澗扞莟丱拑盥嫺鑵蒄瞰淦稈康繝懽憾骭戡奐啣厂鐶讙澣羮寰羹嫻杆鸛歡豢歛罕酣陷皖篏捍瀚勸撼驩卷樌潤觀橄涵渙凵堪巫覡鉋萱簪舘艱咸翰柬悍駻燗槓浣邯攷稽宦考棺潅閂煥鉗疳癇函凾鹹顴緘桓款箝諌諫轗旱坩侃鰥 館莞橇韓患灌勧菅簡奸刊柑肝看桿干緩寒嵌廣広竿貫巻敢漢環間陥喚閑監喊歓甘寛管慣完艦乾幹官観壁椛屍姓庇鞄芳蔓鯑一勘⊃影陰蔭景*棧梯筧庚辛┘柧┐┌門廉脚癩乞∪川合’)〈《‘“”}{》〉囓柁旗鮖悴舵鰍鍛梶錺餝飾篭籠還歸卻皈孵省顧楓却帰反返督髮帋守祇韮裃雷髪紙鉦曲矩予鐘樺沫偏騙語潟刀模象仇固硬傍難容忝辱頑形方旁型肩風幽滓翳微掠綛纃絣緕擦糟鎹粕轄戞劼猾瞎恰蛞∧∩蠍擔濶筈剋蝎曷羯喝餓聒鞨黠刮蘰鬘桂闊括嘗捷豁渇担滑堅鰹割戛活暈疽鵲瘡傘嵩重襲葛笠堵硴墻牆蠣蛎柿關掲罹抱踵嬶嚊拘関係貌顏郁薫顔母感釡罐窰鴎框叺構喧竃竈釜缶蒲鎌數数槝栢膳傅瑕畏賢橿姦樫爨炊圍喞託囲鈎『鉤「』」限鍵傾禿蕪鏑頭齧気被兜敵適哉必要鼎鬲彜彝叶片悲哀愛鋺蛇鉄蜩神奏楫裹磆餅徒褐糧粮膈覺∠埆蠖貉幗隱擴寉骼癨壑咯椁嚇茖愨槨膕掴覈殼穫狢霍礁恪擱匿撹攪喀廓較郭]】【〔〕[殻挌劃閣格隠覚矍革獲馘攫核鶴拡客隔角確蠏壞畍丐獪褂恠喙峡夬觧械揩醢匯廨誡誨嵬櫂隗茴徊迴枴懈价椢榿囘蛙瑰乖浬鰄傀糴柏街鳰懷蛔蠶蚕邂蟹潰壊恢腕芥垣楷會拐悔詼諧契皆界疥魁偕改繪貝胛絵甲快灰槐晦懐介回塊解階廻戒開会怪海縢篝炬耀赫輝冠鑒鑑各屈鏡和代茄缺飼嫁華堝變狩上訶加架何啝火日菓欠苅繋稼ヶ个噛譁科跏舸賭禍支変窩課花交刈渦嚼掛呵替葭柯畫駆嘩崋化霞蝌迦顆価馨家借蝦罅駈斯賈嘉易果戈廈哥買闕且克墟靴訛驅換踝描軻嗅價嗄可彼夥香歌河珂鹿個痂書假荷耶笳咼藉糅舁搗渮袈下萪貸厦禾貨咬寡箇卦苛譌枷掻過画ヵ黴遐兼醸翔仮佳蚊懸伽賀淅勝涸苟蝸謌夏枯暇珈か京節┗└※хХ忽コ汗〜功(株Kク×金窯χキカΚКΧкケκK]\|ッ\_s*[コケクキカ]\|ッ\_s*[コケクキカ]\|っ\_s*[子こけくきか]\|蟀\_s*谷\|焜\_s*炉\|前\_s*妻\|嫡\_s*妻\|二\_s*合\_s*半\|秋\_s*桜\|牛\_s*尾\_s*魚\|庶\_s*幾\|独\_s*楽\|特\_s*牛\|粫\_s*門\|甦\_s*生\|M\_s*e\_s*t\_s*a\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|f\_s*o\_s*o\_s*t\_s* \_s*a\_s*n\_s*d\_s* \_s*m\_s*o\_s*u\_s*s\_s*e\_s* \_s*d\_s*i\_s*s\_s*e\_s*a\_s*s\_s*e\|外\_s*連\_s*味\|螻\_s*蛄\|罌\_s*粟\|滅\_s*紫\|S\_s*i\|莎\_s*草\|百\_s*[濟済]\|9\_s*[日月]\|秧\_s*鶏\|釉\_s*掛\|典\_s*薬\_s*寮\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|探\_s*湯\|誓\_s*湯\|六\_s*合\|地\_s*祇\|都\_s*子\|州\_s*光\|群\_s*衆\|慈\_s*姑\|c\_s*r\_s*e\_s*s\_s*c\|内\_s*蔵\_s*助\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|仁\_s*彦\|啄\_s*木\_s*鳥\|X\_s*e\|如\_s*月\|私\_s*市\|昨\_s*日\|素\_s*地\|布\_s*地\|欺\_s*罔\|k\_s*i\_s*l\_s*o\|聖\_s*[之子美]\|沈\_s*菜\|蟋\_s*蟀\|螽\_s*斯\|G\_s*o\_s*l\_s*d\|A\_s*\%(u\|r\_s*c\_s*h\_s*i\_s*c\_s*h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|s\_s*t\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\)\|菫\_s*青\_s*石\|槿\_s*花\|R\_s*\%(h\_s*\%(o\_s*e\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\)\|u\_s*n\_s*u\_s*n\_s*c\_s*u\_s*l\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|a\_s*n\_s*\%(u\_s*n\_s*c\_s*u\_s*l\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|a\_s*l\_s*e\_s*s\)\)\|裾\_s*礁\|脇\_s*[侍息]\|姉\_s*[妹弟]\|頬\_s*[骨筋]\|毬\_s*果\|舅\_s*姑\|厩\_s*\%([肥舎]\|務\_s*員\)\|廐\_s*舎\|離\_s*れ\_s*離\_s*れ\|掃\_s*部\|羚\_s*羊\|氈\_s*瓜\|土\_s*器\|蝙\_s*蝠\|魚\_s*狗\|為\_s*替\|連\_s*枷\|身\_s*体\|落\_s*葉\_s*松\|随\_s*神\|檻\_s*車\|T\_s*\%(h\_s*a\_s*l\_s*i\_s*c\_s*t\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|u\_s*b\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\)\|南\_s*瓜\|量\_s*子\|千\_s*典\|山\_s*\%(梔\_s*子\|陽\_s*道\)\|蜉\_s*蝣\|陽\_s*炎\|蜻\_s*蛉\|破\_s*片\|挿\_s*頭\|駕\_s*\%(籠\|輿\_s*丁\)\|槭\_s*樹\|長\_s*[月官]\|主\_s*[紀計神]\|剃\_s*刀\|天\_s*\%(牛\|鼠\_s*矢\)\|帷\_s*子\|酢\_s*漿\_s*草\|O\_s*x\_s*a\_s*l\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|飛\_s*白\|春\_s*日\|C\_s*\%([ormfda]\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\|i\_s*r\_s*c\_s*a\_s*e\_s*a\_s*s\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|u\_s*r\_s*i\_s*u\_s*m\|y\_s*p\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*c\_s*i\_s*d\_s*i\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\)\|曾\_s*て\|曽\_s*て\|松\_s*魚\|燕\_s*子\_s*花\|牡\_s*[蛎蠣]\|民\_s*部\|部\_s*曲\|E\_s*\%(b\_s*e\_s*n\_s*a\_s*l\_s*e\_s*s\|l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|案\_s*山\_s*子\|梭\_s*\%(魚\|子\_s*魚\)\|蟷\_s*螂\|螳\_s*螂\|瓜\_s*\%(田\|呂\_s*根\)\|拍\_s*手\|水\_s*[鶏母夫手]\|東\_s*\%(風\|京\_s*都\_s*立\_s*科\_s*学\_s*技\_s*術\_s*大\_s*学\)\|(\_s*株\_s*)\|称\_s*子\|贏\_s*ち\_s*得\|歩\_s*兵\|恁\_s*く\|杜\_s*\%(若\|父\_s*魚\)\|梅\_s*花\_s*皮\|頴\_s*田\|膾\_s*炙\|ノ\_s*\%([ブウ]\|ー\_s*ン\|ッ\_s*\%([トク]\|テ\_s*ィ\_s*ン\_s*グ\|カ\_s*ー\|キ\_s*ン\_s*グ\)\)\|ナ\_s*\%(ッ\_s*\%(ク\|プ\_s*\%(サ\_s*ッ\_s*ク\|ザ\_s*ッ\_s*ク\)\)\|レ\_s*ッ\_s*ジ\|イ\_s*[フトツ]\)\|ニ\_s*\%(ー\|ッ\_s*\%(ト\|テ\_s*ィ\_s*ン\_s*グ\)\)\|ホ\_s*\%(ー\_s*\%(ミ\_s*ー\|メ\_s*イ\)\|メ\_s*イ\_s*ニ\)\|フ\_s*\%(ビ\_s*ラ\_s*イ\|ル\_s*シ\_s*チ\_s*ョ\_s*フ\)\|ハ\_s*\%(ン\|ラ\_s*シ\_s*ョ\_s*ー\|ー\_s*ン\|バ\_s*ロ\_s*フ\_s*ス\_s*ク\|ル\_s*ツ\_s*ー\_s*ム\|チ\_s*ャ\_s*ト\_s*ゥ\_s*リ\_s*ア\_s*ン\)\|P\_s*\%(i\_s*p\_s*e\_s*r\_s*a\_s*\%(l\_s*e\_s*s\|c\_s*e\_s*a\_s*e\)\|a\_s*p\_s*a\_s*v\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|o\_s*\%(d\_s*o\_s*s\_s*t\_s*e\_s*m\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|t\_s*a\_s*s\_s*s\_s*i\_s*u\_s*m\)\)\)', + \ 'L' : '\%([ォォぉェェぇゥゥぅィィぃァァぁ<≪ ̄_≦李左←¬⊃∃∀∨ルL∧レラлΛ£ЛλL]\|ッ\_s*[ォェゥィァ]\|ッ\_s*[ォェゥィァ]\|っ\_s*[ぉぇぅぃぁ]\|液\_s*晶\|最\_s*小\_s*2\_s*乗\_s*法\|\.\_s*\.\_s*\.\|拉\_s*薩\|l\_s*-\_s*メ\_s*ン\_s*ト\_s*ー\_s*ル\|l\_s*i\_s*s\_s*p\_s*e\_s*r\|聯\_s*想\|補\_s*題\|檸\_s*檬\|手\_s*紙\|学\_s*習\|施\_s*錠\|局\_s*所\|論\_s*理\|ロ\_s*\%([キイアロリブボトメウスコゴグー]\|ペ\_s*ス\|ワ\_s*ー\_s*ル\|エ\_s*ベ\|ヨ\_s*ラ\|フ\_s*ト\|ル\_s*カ\|ベ\_s*リ\_s*ア\|ビ\_s*\%(ー\|ン\_s*グ\|イ\_s*\%(ス\_s*ト\|ン\_s*グ\)\)\|テ\_s*ィ\|サ\_s*ン\_s*\%(ジ\_s*ェ\_s*ル\_s*ス\|ゼ\_s*ル\_s*ス\)\|ニ\_s*ー\|ク\_s*リ\_s*ア\_s*ン\|ッ\_s*\%([ジタテトク]\|キ\_s*\%(ン\_s*グ\|ー\_s*ド\)\|カ\_s*ー\)\|カ\_s*ー\_s*ル\|ケ\_s*ー\_s*\%([トタル]\|シ\_s*ョ\_s*ン\)\|ガ\_s*ー\|ギ\_s*ン\_s*グ\|ジ\_s*\%(ー\|テ\_s*ッ\_s*ク\|ス\_s*テ\_s*ィ\_s*\%(ク\|ッ\_s*ク\)\|カ\_s*ル\|ク\_s*ー\_s*ル\|ッ\_s*[トク]\)\|ラ\_s*ン\|ン\_s*\%([ゴグダ]\|ボ\_s*\%(ク\|ッ\_s*ク\)\|バ\_s*ル\_s*デ\_s*ィ\|ズ\_s*デ\_s*ー\_s*ル\|リ\_s*[ィー]\|ジ\_s*ン\|ド\_s*ン\)\|レ\_s*\%(ア\_s*ル\|ッ\_s*タ\|ー\_s*ヌ\|イ\_s*ン\|ン\_s*\%([ソス]\|ツ\_s*ォ\)\)\)\|\\\_s*L\_s*a\_s*T\_s*e\_s*X\|研\_s*究\_s*室\|エ\_s*ル\|リ\_s*\%([ィセズザサスダポルラリマナノンヌブアー]\|ャ\_s*マ\|ヤ\_s*ド\_s*ロ\|ヨ\_s*ン\|ゾ\_s*チ\_s*ー\_s*ム\|コ\_s*\%(リ\_s*ス\|ピ\_s*ン\)\|ク\_s*ー\_s*ド\|カ\_s*\%(ー\|オ\_s*ン\)\|ジ\_s*[ンー]\|デ\_s*[ィル]\|ド\_s*カ\_s*イ\_s*ン\|プ\_s*ト\_s*ン\|パ\_s*ー\_s*ゼ\|グ\_s*\%(ニ\_s*ン\|ナ\_s*ン\)\|フ\_s*\%([エト]\|タ\_s*ー\|テ\_s*ィ\_s*ン\_s*グ\)\|テ\_s*ラ\_s*[ルシ]\|チ\_s*ウ\_s*ム\|ソ\_s*\%(ソ\_s*ー\_s*ム\|グ\_s*ラ\_s*フ\_s*ィ\)\|タ\_s*ー\|ト\_s*\%([レル]\|マ\_s*ス\|ア\_s*ニ\_s*ア\|グ\_s*ラ\_s*フ\|バ\_s*ル\_s*ス\_s*キ\_s*ー\)\|オ\_s*\%(タ\_s*ー\_s*ル\|ネ\_s*ル\)\|ミ\_s*\%(テ\_s*ッ\_s*ド\|ッ\_s*[タト]\)\|モ\_s*\%(ー\_s*ジ\_s*ュ\|ネ\_s*ン\|ン\_s*チ\_s*ェ\_s*ッ\_s*ロ\)\|ム\_s*ジ\_s*ン\|キ\_s*\%(ッ\_s*ド\|ュ\_s*ー\_s*ル\|テ\_s*ン\_s*\%(ス\_s*タ\_s*イ\_s*ン\|シ\_s*ュ\_s*タ\_s*イ\_s*ン\)\)\|エ\_s*\%(ゾ\_s*ン\|ー\_s*ジ\_s*ュ\)\|ヒ\_s*テ\_s*ン\_s*シ\_s*ュ\_s*タ\_s*イ\_s*ン\|ネ\_s*\%([アン]\|ッ\_s*ト\|ー\_s*ジ\_s*ュ\)\|ニ\_s*ア\|ベ\_s*\%([ロラ]\|リ\_s*ア\|レ\_s*ー\_s*シ\_s*ョ\_s*ン\|ル\_s*テ\)\|ビ\_s*\%([アー]\|ド\_s*ー\|ン\_s*グ\)\|ュ\_s*\%([スー]\|ブ\_s*リ\_s*ャ\_s*ー\_s*ナ\|リ\_s*ュ\|ド\_s*ミ\_s*ラ\|ク\_s*サ\_s*ン\_s*ブ\_s*ー\_s*ル\|ッ\_s*ク\|シ\_s*ア\_s*ン\|ミ\_s*エ\_s*ー\_s*ル\)\|ロ\_s*\%(イ\|ン\_s*グ\_s*ウ\_s*ェ\)\|ヴ\_s*\%(ィ\_s*ン\_s*グ\_s*ス\_s*ト\_s*ン\|ァ\_s*\%(プ\_s*ー\_s*ル\|イ\_s*ア\_s*サ\_s*ン\)\)\|バ\_s*\%(テ\_s*ィ\|タ\_s*リ\_s*ア\_s*\%(ン\|ニ\_s*ズ\_s*ム\)\|プ\_s*ー\_s*ル\|イ\_s*ア\_s*サ\_s*ン\)\|ッ\_s*\%([ドピプタクチト]\|ス\_s*ン\)\)\)', + \ 'M' : '\%([モ脆醪師諸催靄舫腿銛杜森聞捫匁紋問翫玩擡齎靠凭鵙鴃縺悶樅籾椛楓蛻潛濳艾潜殯黐餠用糯餅桃者懶專専物尤勿畚戻許悖故旧下乖求礎素基本元綟捩文默沐杢黙耗檬网莽芒罔耄朦魍艨濛曚矇亡蒙毛孟猛網糢保若望揉燃洩貰藻漏以模母裳楙姆摸茂持喪もメ麪緜眄緬麺門棉綿面蓍珎珍♀娶貭粧妾牝瞽盲娚暈繞萌慈惠恵萠暝謎溟滅姪瞑盟酩銘鳴瑪賞睨奴雌芽碼召女減めム羣榁室簇邨屯連邑叢村紫梅葎宜憤毳槿葮椋酬報尨骸躯旨難睦酷麥麦対邀百迎昔空虚鞅宗棟胸掬娘結笞鞭徒蠧蝕蠹蟲蓆寧筵席莚虫毟貉狢豸貪聟壻婿霧向无無謀武鵡夢群牟梦六剥毋噎蒸咽務矛むミ渠霙溝妊澪薨岑嶺峰峯亂紊淫婬濫妄猥乱※*◇■簔穣簑蓑醜儖慘短惨幹研耳壥廛店操陵鶚崎岬巫尊詔勅敕>」砌汀頻→』】右翠碧緑認幣蹊径倫導途通路道瞠鬟髻湖自蹼蛟瑞癸禊晦漲源鏖港湊南瞶櫁謐水調貢密甕帝蜜覩幸脉脈韭韮竓粍瓱榠螟茗名妙命冥都宮罠閔皆眠明民看彌稔靡觀盈診箕三観美充深壬實視御魅味巳己身弥みマ毬鞠紕蝮麿転稀賓客檀繭黛眉巡囘周防衞衛護守荳菽豆.・。°◯圓槫゜)(丸謾鰻縵鬘懣幡幔蹣蔓瞞卍饅漫滿慢迄笆貧幻瞼蔟疎眩回廻儲申設招繚統纒的蟶孫弯彎籬擬免猿純亮信実委罷圸壗侭飯儘継随髷任蒭芻耙紛鮪見猯塗斈學眦眥眼俎愛学斑斗枡鱒桝舛升萬蠱呪薪槙槇牧窗悗惑円窓襠甼区街町前複亦俣叉跨全瞬木胯股又鍖枕膜幕瑁詣参參妹眛哩迷枚米賄賂埋昧邁毎沫抹奉靺枩秣祀纏祭睫末大太秀勝柾弄優成盛將松匡鉞賢希将誠昌征政正雅仁媽散茉馬在増混交間放摩負枉益敗眞待未麼撒巻魔蒔俟坐嘛舞捲目磨痲先墹真満播万曲卷雑ま光月♪♭♯ム¬⌒÷⊃≠∫∠±⊇⇔∃∇√∧≒∩∬∋∝≦∵Δ⇒∞⊂⊆⊥∀≫∴×∨≧≪≡∂∈∽∪♂曼麻●◎○〇モM〒′−マ最ミメМΜμM]\|ッ\_s*[モメムミマ]\|ッ\_s*[モメムミマ]\|っ\_s*[もめむみま]\|双\_s*\%([手墨親]\|向\_s*き\|差\_s*し\)\|蜀\_s*黍\|唐\_s*土\_s*\%(書\|文\_s*字\)\|両\_s*\%([角親刃]\|差\_s*し\)\|楊\_s*梅\_s*皮\|主\_s*水\|旺\_s*角\|紅\_s*[絹染葉]\|強\_s*請\|虎\_s*落\|痘\_s*瘡\|莫\_s*斯\_s*科\|固\_s*よ\_s*り\|一\_s*徳\|O\_s*l\_s*e\_s*a\_s*l\_s*e\_s*s\|惘\_s*然\|乙\_s*張\|赤\_s*目\_s*魚\|針\_s*孔\|妻\_s*[君合沼]\|墨\_s*西\_s*哥\|鍍\_s*金\|繍\_s*眼\_s*児\|夫\_s*婦\|乳\_s*母\|布\_s*の\_s*子\|没\_s*\%([薬後入却有]\|義\_s*道\|食\_s*子\)\|B\_s*\%(e\_s*r\_s*b\_s*e\_s*r\_s*i\_s*d\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*o\_s*r\_s*r\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\)\|浮\_s*腫\|6\_s*日\|6\_s*日\|崇\_s*田\|刀\_s*背\|襁\_s*褓\|零\_s*余\_s*子\|蜈\_s*蚣\|産\_s*霊\|息\_s*子\|k\_s*\$\_s*_\_s*{\_s*i\_s*n\_s*f\_s*}\_s*\$\|蚯\_s*蚓\|A\_s*\%(b\_s*i\_s*e\_s*s\|p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*r\_s*o\_s*s\_s*t\_s*i\_s*c\_s*h\_s*u\_s*m\)\|山\_s*陵\|雎\_s*鳩\|親\_s*王\|嬰\_s*児\|亨\_s*治\|陸\_s*奥\|皇\_s*[子女國]\|3\_s*[つ日]\|3\_s*[つ日]\|角\_s*[鴟髪子]\|七\_s*寸\|鳩\_s*尾\|鷦\_s*鷯\|孤\_s*児\|凝\_s*視\|兎\_s*唇\|R\_s*u\_s*t\_s*a\_s*l\_s*e\_s*s\|神\_s*[子輿酒]\|苗\_s*字\|海\_s*[雲蘊布藻蜂松山]\|P\_s*o\_s*d\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\|土\_s*[龍竜産]\|京\_s*都\|横\_s*浜\_s*マ\_s*リ\_s*ノ\_s*ス\|肉\_s*刺\|忠\_s*実\|翻\_s*\%(筋\_s*斗\|車\_s*魚\)\|H\_s*a\_s*m\_s*a\_s*m\_s*e\_s*l\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|不\_s*\%(味\|見\_s*[点転]\)\|兇\_s*々\|凶\_s*鳥\|澗\_s*潟\|勾\_s*玉\|禍\_s*[々禍事言]\|況\_s*し\|澳\_s*門\|苧\_s*麻\|茅\_s*台\_s*酒\|丈\_s*夫\|倍\_s*達\|微\_s*[塵妙睡]\|燐\_s*寸\|驀\_s*地\|L\_s*o\_s*g\_s*a\_s*n\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|豫\_s*て\|陪\_s*臣\|売\_s*僧\|C\_s*\%(a\_s*s\_s*u\_s*a\_s*r\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|e\_s*r\_s*a\_s*t\_s*o\_s*p\_s*y\_s*l\_s*l\_s*a\_s*c\_s*e\_s*a\_s*e\)\|S\_s*\%(a\_s*p\_s*i\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|c\_s*h\_s*i\_s*s\_s*a\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|理\_s*[之元]\|允\_s*彦\|祐\_s*史\|晶\_s*子\|公\_s*[美則輝]\|斉\_s*加\_s*年\|方\_s*夫\|多\_s*言\_s*語\_s*化\|m\_s*-\_s*R\_s*N\_s*A\|ニ\_s*ー\_s*モ\_s*ニ\_s*ッ\_s*ク\|単\_s*量\_s*体\|会\_s*議\|和\_s*布\_s*[刈蕪]\|中\_s*間\_s*子\|薄\_s*荷\_s*脳\|行\_s*[幸列]\|写\_s*像\|日\_s*\%(米\_s*相\_s*互\_s*防\_s*衛\_s*援\_s*助\_s*協\_s*定\|本\_s*製\)\|m\_s*\%(u\_s*l\_s*t\_s*i\_s*l\_s*i\_s*n\_s*g\_s*u\_s*a\_s*l\_s*i\_s*z\_s*a\_s*t\_s*i\_s*o\_s*n\|i\_s*\%(c\_s*r\_s*o\|l\_s*l\_s*i\)\|e\_s*\%(g\_s*a\|z\_s*z\_s*o\_s* \_s*\%(f\_s*o\_s*r\_s*t\_s*e\|p\_s*i\_s*a\_s*n\_s*o\)\)\|a\_s*\%(k\_s*e\_s*フ\_s*ァ\_s*イ\_s*ル\|d\_s*e\_s* \_s*i\_s*n\_s* \_s*J\_s*a\_s*p\_s*a\_s*n\)\)\|計\_s*算\_s*機\|手\_s*紙\|ザ\_s*ッ\_s*ヘ\_s*ル\_s*=\_s*マ\_s*ゾ\_s*ッ\_s*ホ\|嗜\_s*虐\_s*的\_s*趣\_s*味\|被\_s*虐\_s*\%(趣\_s*味\|淫\_s*乱\_s*症\)\|修\_s*士\|仮\_s*面\|移\_s*送\|エ\_s*ム\)', + \ 'N' : '\%([ノ麕咒燧烽詛呪孔伯朔雅悳弼教糊典規矩憲範宜紀哲修惟允亘攵展順暢信則法後罵吭咽喉鑿蚤々湾宣曰覘臨稀望覗殘遺残鋸芒禾騰幟昇登上檐簷軒逸遁王瑙衲曩碯皇腦嚢膿能脳農除延熨廼退埜野飲載乘飮之伸嚥述乗呑−濃陳のネ塒姉濘檸嚀聹侫寧佞鼡鼠拗猫嫉妬希願捏熱労犒葱狙閨睡棔眠稔然棯懇拈撚燃念年涅粘値根捻嶺祢錬寝袮捩音練禰煉子寢ねヌ絖垈饅帛幣鵺主蛻拭温布沼盜偸窃盗抽擢緯糠額濡脱怒縫抜奴拔貫塗ぬニ楡蒻潦鷄鶏瀑庭繞獰女尿韭薤眈睨韮姙刄儿蒜葫刃忍∀妊認任人乳擔蜷担濁賑握俄鳰臭匂沸錵贄僞偐贋偽柔靤如苦膠霓滲虹躙廿《》◎∬』『悪憎兄螺鰊鯡錦西入新肉‖岻逃児弐二邇2貳迩煮貮迯仁尼似荷2弍丹にナ靡抔嫐嬲鯆屶釶鉈泥薺詰若慨歎嘆抛毆擲撲殴慰治癒等猶直泪波邉辺邊鍋浪某棘棗懷懐夏擦梨情懶譌艶訛鉛鮠癜鯰韲鱠膾憖怠鈍腥捺凖擬准準謎洋涙宥傾灘詠霖眺痼存乍流轅永和梛椥渚長莫毋勿半・媒仲中7斜七蔑乃尚内繩畷縄苗滑鞣惱悩就哉也斉形業徳娚垂喃∵楠尓爾汝男軟難何倣枹均柞双肄列⊃⇒→楢習竝茄啾納無那拿舐娜做涕投馴南熟並儺生凪鳴為綯奈嘗哭嚶爲狎薙萎菜魚慣泣亡失痿撫啼な┘┛│┃┨┫┤┥├┝┣┠┼╋╂┿成#∋∇名┗└日≒ニネN¬〜≠ナヌノΝНнνN]\|ッ\_s*[ノネヌニナ]\|ッ\_s*[ノネヌニナ]\|っ\_s*[のねぬにな]\|帳\_s*面\|狼\_s*[烟煙]\|惚\_s*気\|暖\_s*[簾気]\|礼\_s*江\|功\_s*晶\|祈\_s*子\|訓\_s*子\|賀\_s*子\|式\_s*部\_s*省\|記\_s*代\|倫\_s*[明子宗]\|敬\_s*之\|賭\_s*弓\|誠\_s*也\|敦\_s*子\|悦\_s*旦\|祝\_s*[女詞]\|仰\_s*け\_s*反\|盧\_s*泰\_s*愚\|逆\_s*上\|凌\_s*霄\_s*花\|姐\_s*さ\_s*ん\|杜\_s*松\|強\_s*請\|合\_s*歓\|微\_s*温\|零\_s*余\_s*子\|酸\_s*漿\|鐃\_s*鉢\|鰾\_s*膠\|I\_s*I\_s*部\|耳\_s*根\|面\_s*皰\| \_s*2\_s* \_s*次\_s*曲\_s*面\|M\_s*y\_s*r\_s*i\_s*s\_s*t\_s*i\_s*c\_s*a\_s*c\_s*e\_s*a\_s*e\|莞\_s*爾\|P\_s*b\|L\_s*e\_s*a\_s*d\|海\_s*[苔鼠]\|C\_s*\%(e\_s*l\_s*a\_s*s\_s*t\_s*r\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|a\_s*r\_s*y\_s*o\_s*p\_s*h\_s*y\_s*l\_s*l\_s*a\_s*l\_s*e\_s*s\)\|雪\_s*崩\|竹\_s*節\_s*虫\|7\_s*[日個]\|地\_s*震\|行\_s*[木方]\|大\_s*\%(蒜\|理\_s*石\)\|蛞\_s*蝓\|弱\_s*竹\|追\_s*儺\|済\_s*\%(し\_s*崩\|り\_s*物\)\|可\_s*成\|平\_s*城\|不\_s*成\|空\_s*リ\_s*ス\_s*ト\|T\_s*h\_s*e\_s* \_s*N\_s*e\_s*t\_s*w\_s*o\_s*r\_s*k\_s* \_s*I\_s*n\_s*f\_s*o\_s*r\_s*m\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*C\_s*e\_s*n\_s*t\_s*e\_s*r\|S\_s*o\_s*\%(l\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|d\_s*i\_s*u\_s*m\)\|n\_s*\%(個\|次\_s*元\|e\_s*m\_s*a\_s*c\_s*s\)\|紐\_s*育\|フ\_s*ォ\_s*ン\_s*・\_s*ノ\_s*イ\_s*マ\_s*ン\|ヤ\_s*ー\_s*ノ\_s*ッ\_s*シ\_s*ュ\_s*・\_s*フ\_s*ォ\_s*ン\_s*・\_s*ノ\_s*イ\_s*マ\_s*ン\|オ\_s*ラ\_s*ン\_s*ダ\|ア\_s*メ\_s*リ\_s*カ\_s*ネ\_s*ッ\_s*ト\_s*ワ\_s*ー\_s*ク\|番\_s*号\|節\_s*点\|夜\_s*想\_s*曲\|n\_s*\%(次\|a\_s*n\_s*o\|o\_s*t\_s* \_s*o\_s*r\)\|諾\_s*威\|正\_s*常\|窒\_s*素\|エ\_s*ヌ\)', + \ 'O' : '\%([オ俺游泳指妖在畢檻澱氈拇親愚疎颪卸念錘惟慮赴徐趣俤羈主想表重面隱瘟園Å怨♀妾温恩鈍悍臣覺溺朦朧思覚榲現朮桶踴威嚇戯縅棘駭愕驚躍踊傲奢驕嚴厳遣痴瘧怒行怠蒹補荻獺懼惧怐虞畏恐襲甥笈及綬葹仝ヾ〃ゝヽゞ々同唖繦襁鴦鴛教几忍筬收兎抑稚長幼治理収修遲檍納後遅賻饋諡贈送憶袵臆拜拝冒犯岳崗峻阜侵奇陵女陸丘岡欄斧自己各戦鬼衰劣囮頤訪貶乙♂漢音弟阿脅怯首夥誘屋膃億穩穏煽煕熈燠熾諚掟興隠沖毆姶澳秧浤凰徃枉罌殃翁鴬泓奧嚶墺悒泱閘瓮襖蓊惶鸚懊媼嫗鴎怏鏖謳旺凹鴨櫻欒樗楝殴朷甌汪横往鞅歐嘔陷陥遠奄蓋夛応果應掩蔽概欧公邑麋薤被仰扇皇狼弁鵬鴻鳳黄奥多衽覆粱凡鰲頁王居央郎措擱堕尾置麻朗怖悪追帶折塢負墜織老汚生勇小嗚夫惜起唹落男推将穂壓淤御緒墮逐下牡捺雄降桜押圧苧帯於終乎お大◎∞和∝♪∨∪開OоОο○ωΟオΩO]\|濠\_s*太\_s*剌\_s*利\|父\_s*[娘子]\|母\_s*[子娘屋]\|万\_s*年\_s*青\|本\_s*懸\_s*魚\|玩\_s*具\|沢\_s*瀉\|A\_s*l\_s*i\_s*s\_s*m\_s*a\_s*t\_s*a\_s*l\_s*e\_s*s\|厭\_s*離\|乳\_s*母\_s*日\_s*傘\|陰\_s*[陽地]\|飲\_s*[食酒]\|慍\_s*色\|婦\_s*系\_s*図\|手\_s*術\|螻\_s*蛄\|十\_s*八\_s*番\|鉄\_s*漿\|海\_s*髪\_s*海\_s*苔\|虎\_s*魚\|花\_s*魁\|美\_s*味\|含\_s*羞\_s*草\|白\_s*粉\|渡\_s*島\|通\_s*事\|訳\_s*語\|晩\_s*[稲生]\|可\_s*笑\|惡\_s*寒\|傍\_s*[目惚見]\|叔\_s*[父母]\|伯\_s*[父母]\|姨\_s*捨\|少\_s*女\|侠\_s*気\|G\_s*u\_s*t\_s*t\_s*i\_s*f\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|D\_s*i\_s*l\_s*l\_s*e\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|H\_s*y\_s*p\_s*e\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|霊\_s*屋\|蝌\_s*蚪\|飫\_s*肥\|佩\_s*物\|良\_s*人\|纓\_s*田\|C\_s*o\_s*p\_s*t\_s*i\_s*d\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|鷹\_s*揚\|椀\_s*飯\_s*振\_s*\%(舞\|る\_s*舞\)\|相\_s*知\|鶯\_s*語\|近\_s*江\|零\_s*落\|越\_s*[生訴知智度]\|彼\_s*方\|祖\_s*[神父母]\|車\_s*前\|従\_s*祖\_s*[母父]\|青\_s*[梅海木]\|太\_s*\%(田\|安\_s*万\_s*侶\|上\_s*天\_s*皇\)\|巨\_s*頭\|逢\_s*[魔瀬隈坂]\|そ\_s*の\_s*他\|承\_s*知\_s*し\_s*ま\_s*し\_s*た\_s*\.\|烏\_s*[滸龍]\|t\_s*h\_s*e\_s* \_s*O\_s*b\_s*j\_s*e\_s*c\_s*t\_s* \_s*M\_s*a\_s*n\_s*a\_s*g\_s*e\_s*m\_s*e\_s*n\_s*t\_s* \_s*G\_s*r\_s*o\_s*u\_s*p\|立\_s*石\_s*電\_s*機\|職\_s*業\|楕\_s*円\|ウ\_s*\%(ィ\|ー\_s*\%(ズ\|ロ\_s*ン\)\|ロ\_s*ボ\_s*ロ\_s*ス\)\|出\_s*力\|ア\_s*\%(ワ\|ザ\_s*ー\|ウ\_s*\%([チト]\|タ\_s*ー\)\)\|基\_s*本\_s*ソ\_s*フ\_s*ト\_s*ウ\_s*ェ\_s*ア\|一\_s*\%(昨\_s*[年日]\|対\_s*一\)\|ワ\_s*ン\|ま\_s*た\_s*は\|論\_s*理\_s*和\|聖\_s*譚\_s*曲\|水\_s*中\_s*酸\_s*素\_s*破\_s*壊\_s*剤\|蛋\_s*白\_s*石\|最\_s*適\_s*化\|歌\_s*劇\|演\_s*算\_s*子\|操\_s*作\|酸\_s*素\)', + \ 'P' : '\%([本磅椪烹砲法方報舖舗歩ぽ併閉閇蔽×遍編片邉篇辺邊屁ぺ幅服風分腐布符泌匹俵憑票品筒平日犯版搬幇板払腹發発走箱拍朴駮泊博愽包放配盃敗牌杯八破羽波播張ぱ鉛Ψψぴ±+ぷΦφ├┣∝北┴‰.P%£〒・点プポ頁)(∂¶‖ペパПΠп燐πピP]\|ッ\_s*\%(ホ\_s*゚\|ヘ\_s*゚\|フ\_s*゚\|ヒ\_s*゚\|ハ\_s*゚\)\|ッ\_s*[ポペプピパ]\|っ\_s*[ぽぺぷぴぱ]\|ホ\_s*゚\|先\_s*斗\_s*町\|ヘ\_s*゚\|祕\_s*[露魯]\|フ\_s*゚\|釜\_s*山\|普\_s*魯\_s*西\|ヒ\_s*゚\|皮\_s*蛋\|光\_s*一\|ハ\_s*゚\|麺\_s*麭\|巴\_s*\%(里\|奈\_s*馬\)\|C\_s*y\_s*c\_s*l\_s*a\_s*n\_s*t\_s*h\_s*a\_s*l\_s*e\_s*s\|S\_s*y\_s*n\_s*a\_s*n\_s*t\_s*h\_s*a\_s*e\|排\_s*骨\|B\_s*r\_s*o\_s*m\_s*e\_s*l\_s*i\_s*a\_s*l\_s*e\_s*s\|L\_s*e\_s*a\_s*d\|白\_s*[板酒金]\|シ\_s*\%(ュ\_s*ー\_s*ド\|ロ\_s*シ\_s*ビ\_s*ン\)\|サ\_s*\%(ー\_s*ム\|イ\_s*\%([ズクケコ]\|ロ\_s*シ\_s*ビ\_s*ン\|リ\_s*ウ\_s*ム\|キ\_s*ッ\_s*ク\)\)\|+\_s*α\|ホ\_s*\%(ン\|ス\_s*ゲ\_s*ン\)\|ヒ\_s*ロ\_s*ポ\_s*ン\|比\_s*\%(布\|律\_s*賓\)\|フ\_s*\%(リ\_s*ジ\_s*ア\_s*ン\|レ\_s*\%(イ\_s*ジ\_s*ン\_s*グ\|ー\_s*\%(ズ\|ジ\_s*ン\_s*グ\)\)\|タ\_s*レ\_s*イ\_s*ン\|ォ\_s*\%([ーンノト]\|ボ\_s*ス\|ビ\_s*ア\|ス\_s*フ\_s*ァ\_s*ー\|ニ\_s*ー\)\|ァ\_s*\%(イ\|ラ\_s*オ\|ー\_s*\%([ジマ]\|ミ\_s*ン\_s*グ\)\|ン\_s*\%(ト\_s*ム\|タ\_s*ズ\_s*[ムマ]\)\|ル\_s*[ツス]\|レ\_s*ノ\_s*プ\_s*シ\_s*ス\)\|ィ\_s*\%([ロル]\|ジ\_s*\%(ッ\_s*ク\_s*ス\|カ\_s*ル\)\|ー\_s*ビ\_s*ー\|ッ\_s*シ\_s*ン\_s*グ\|レ\_s*モ\_s*ン\|ラ\_s*デ\_s*ル\_s*フ\_s*ィ\_s*ア\|リ\_s*\%([スーアパ]\|ッ\_s*[プパ]\|ピ\_s*\%(ン\|ー\_s*ヌ\)\)\)\|ェ\_s*\%(ー\_s*\%([ベズ]\|ジ\_s*ン\_s*グ\)\|イ\_s*ズ\|ロ\_s*モ\_s*ン\|ニ\_s*\%(ル\|ッ\_s*ク\_s*ス\|キ\_s*ア\|ー\_s*ル\)\|ノ\_s*\%(キ\_s*シ\|ー\_s*ル\)\)\)\|述\_s*語\|証\_s*明\|タ\_s*ン\_s*パ\_s*ク\_s*質\|処\_s*理\|手\_s*続\_s*き\|進\_s*行\|算\_s*譜\|利\_s*潤\|南\_s*瓜\|宣\_s*伝\|公\_s*告\|真\_s*珠\|永\_s*続\|カ\_s*リ\_s*ウ\_s*ム\|葡\_s*萄\_s*牙\|重\_s*合\_s*体\|多\_s*相\_s*型\|バ\_s*テ\_s*レ\_s*ン\|貼\_s*り\_s*付\_s*け\|論\_s*文\|偏\_s*執\_s*[狂病]\|引\_s*数\|リ\_s*ン\|p\_s*\%(T\_s*e\_s*X\|H\_s*メ\_s*ー\_s*タ\|e\_s*\%(t\_s*a\|r\_s*l\_s*ス\_s*ク\_s*リ\_s*プ\_s*ト\)\|i\_s*\%(c\_s*o\|a\_s*n\_s*\%(o\|i\_s*s\_s*s\_s*i\_s*\%(m\_s*o\|s\_s*s\_s*i\_s*m\_s*o\)\)\)\)\)', + \ 'Q' : '\%([配椚橡檪櫪栩椡椪椢湫櫟含纐柵婚屎糞癖潛潜鵠裹凹窪馘括縊踵跟頚軛珞頸首諄鞋履窟寛狐轡覆靴沓碎砕管条降件頽崩屑葛釘莖茎陸杙株杭掘崛倔鶏鐃藥擽薬樟楠髪酒梳櫛串釧與与挫籖鯀鯨鬮籤隈熊艸嚔藾叢鏈腐鎖種Ξξ臭日茸菌楔草圀邦國国髭漱嗽吻嘴喙唇脣蛇梔腔φ劫刧 空粂裙勳熏皹桾皸醺下薫燻訓勲葷君委詳钁精企鍬加咥銜桑塊某暝晦峅競昏冥眛罔鮓較比闇位鞍藏暗倉廚厨涅々〃ゝヽゞ仝ヾ曇雲蜘栗狂包俥車曲廓郭梍枢踝畔鉄鐵★●■玄蔵黒拘食徠久孔桍窶暮焼懼駒柧苦朽区眩吁繰庫垢駆鉤紅呉倶駈汲宮枸劬矩煦驅口9瞿工悔供功吼怐喰玖貢九惧来來區組奇句狗鳩酌絎嶇躯衢屈刳クくQ‘“’”♪ケ?ク¶Q]\|ッ\_s*ク\|ッ\_s*ク\|っ\_s*く\|姑\_s*娘\|箜\_s*篌\|救\_s*世\|莎\_s*草\|傀\_s*儡\|被\_s*下\_s*度\|百\_s*[濟済]\|果\_s*物\|恭\_s*敬\|9\_s*月\|長\_s*月\|秧\_s*鶏\|究\_s*竟\|釉\_s*掛\|典\_s*薬\_s*寮\|天\_s*鼠\_s*矢\|L\_s*a\_s*u\_s*r\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|探\_s*湯\|誓\_s*湯\|球\_s*磨\|六\_s*合\|地\_s*祇\|都\_s*子\|州\_s*光\|山\_s*梔\_s*子\|崑\_s*央\|群\_s*衆\|慈\_s*姑\|旧\_s*\%(訳\|唐\_s*書\)\|c\_s*r\_s*e\_s*s\_s*c\|海\_s*月\|水\_s*[鶏母]\|内\_s*蔵\_s*助\|K\_s*r\|H\_s*e\_s*l\_s*l\_s*e\_s*b\_s*o\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|公\_s*\%([家方卿界美事文]\|出\_s*挙\)\|佝\_s*僂\_s*病\|J\_s*u\_s*g\_s*l\_s*a\_s*n\_s*d\_s*a\_s*l\_s*e\_s*s\|胡\_s*桃\|C\_s*\%(r\|h\_s*r\_s*o\_s*m\_s*i\_s*u\_s*m\)\|R\_s*h\_s*a\_s*m\_s*n\_s*a\_s*l\_s*e\_s*s\|珠\_s*穆\_s*朗\_s*瑪\|チ\_s*ョ\_s*モ\_s*ラ\_s*ン\_s*マ\|『\_s*』\|コ\_s*\%(ー\_s*ラ\_s*ン\|ン\_s*テ\_s*ィ\_s*フ\_s*ァ\_s*イ\_s*ア\)\|問\_s*合\_s*せ\|カ\_s*\%(ザ\_s*ン\|タ\_s*ー\_s*ル\|ス\_s*バ\|ー\_s*ヌ\_s*ー\_s*ン\|ナ\_s*ー\_s*ト\|ダ\_s*フ\_s*ィ\|リ\_s*テ\|ド\_s*リ\_s*ー\_s*[ルユ]\|ル\_s*\%(チ\_s*[エェ]\|テ\_s*\%(ィ\_s*エ\|ッ\_s*ト\)\)\|ン\_s*タ\_s*[ムスン]\)\|質\_s*問\|キ\_s*\%(ト\|ブ\_s*ラ\|ホ\_s*ー\_s*テ\|ハ\_s*ー\_s*ダ\|ル\_s*\%(ト\|テ\_s*ィ\_s*ン\_s*グ\)\|ー\_s*ン\|ノ\_s*ン\|ッ\_s*シ\_s*ュ\|ュ\_s*\%(ー\|エ\_s*リ\)\)\)', + \ 'R' : '\%([ロ崘侖崙堽栄論漉祿轆碌肋勒麓禄鹿6録蘢滝潦榔簍柆鑞弄咾瑯焜朖螂螻樓隴哢實臈槞僂瓏勞薐琅朧壟撈臘郎瘻廊牢浪蝋癆聾楼篭籠狼漏朗蘆顱炉髏爐櫨蕗賂艪瀘臚枦輅鹵廬櫓轤鷺驢艫櫚滷ろレ洌鴒聆蛎糲綟儷蛉砺苓唳勵〇澪犁齡蠡囹齢黎羚戻禮祈隸茘麗隷玲伶癘励零冷例冽劣烈裂列癧轣檪櫪靂鬲瀝礫轢歴瀲鎌縺嗹漣鏈匳斂濂戀奩輦簾櫺∧聨憐恋蓮煉錬攣練聯廉連れル♪路盧泪壘縲瘰誄涙羸塁累類鏤屡縷褸婁陋璢るリ犂篥葎率慄栗淕勠六戮陸律擽畧暦掠略鏐鉚窿餾畄旒瀏苙霤瑠嶐澑瘤嚠笠榴溜硫琉留立柳粒劉隆流痳鈴麟P懍躪藺鄰棆醂菻廩躙淪厘凜霖琳悋綸淋禀稟凛鱗倫吝隣林燐臨侶絽踉梠膂虜呂慮仂力緑裲鐐椋靈魎崚鬣嶺獵楞怜暸倆繆粮廖兩蓼鷯粱輌凉輛燎瞭聊陵令梁糧諒霊龍凌遼漁亮寮⇔涼繚撩綾療量竜菱僚領喨了稜寥両料閭旅離吏履裡璃理釐痢裏俐俚莅漓利驪李哩梨詈悧罹浬籬里莉りラΛλ亂儖攬覧臠覽瀾欒襴婪繿欖檻籃巒嬾纜襤懶爛藍鸞卵濫闌嵐欄乱蘭労剌溂老埓埒猟薤辣喇樂珞犖絡駱酪烙楽落洛徠蕾賚醴罍櫑擂儡耒籟莱磊癩來礼雷頼来們裸等鑼邏蘿拉螺騾良ら右→ТбуЖВоЙЗЪжзИУЯвяшфКСлЁХпОЦЭЧФЫЩъ魯Бы露ШйхМкПгдмцНЛёаиэетАГчЬюЕЮсьнщД輪根√羅ロ々RラルレリРρΡрR]\|ッ\_s*[ロレルリラ]\|ッ\_s*[ロレルリラ]\|っ\_s*[ろれるりら]\|鱸\_s*魚\|芦\_s*[有花]\|濾\_s*[胞過紙]\|6\_s*[時月]\|水\_s*無\_s*月\|檸\_s*檬\|坩\_s*堝\|A\_s*\%(c\_s*t\_s*a\_s*e\_s*a\|p\_s*o\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|C\_s*\%(a\_s*l\_s*y\_s*c\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|h\_s*o\_s*r\_s*i\_s*p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\)\|鯉\_s*[魚城]\|二\_s*\%(索\|翻\_s*縛\)\|V\_s*e\_s*r\_s*t\_s*i\_s*c\_s*i\_s*l\_s*l\_s*a\_s*t\_s*a\_s*e\|O\_s*r\_s*c\_s*h\_s*i\_s*d\_s*a\_s*l\_s*e\_s*s\|M\_s*i\_s*c\_s*r\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\|L\_s*\%([ruia]\|e\_s*i\_s*t\_s*n\_s*e\_s*r\_s*i\_s*a\_s*l\_s*e\_s*s\|A\_s*N\_s*ケ\_s*ー\_s*ブ\_s*ル\)\|海\_s*獺\|G\_s*\%(e\_s*n\_s*t\_s*i\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\|y\_s*\%(n\_s*a\_s*n\_s*d\_s*r\_s*a\_s*e\|m\_s*n\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*e\)\)\|関\_s*係\_s*デ\_s*ー\_s*タ\_s*ベ\_s*ー\_s*ス\|数\_s*理\_s*解\_s*析\_s*研\_s*究\_s*所\|京\_s*都\_s*大\_s*学\_s*数\_s*理\_s*解\_s*析\_s*研\_s*究\_s*所\|電\_s*気\_s*通\_s*信\_s*研\_s*究\_s*所\|東\_s*北\_s*大\_s*\%(学\_s*電\_s*気\_s*通\_s*信\_s*研\_s*究\_s*所\|通\_s*研\)\|限\_s*定\_s*命\_s*令\_s*セ\_s*ッ\_s*ト\_s*計\_s*算\_s*機\|範\_s*囲\|規\_s*則\|紅\_s*玉\|r\_s*u\_s*b\_s*y\_s*ス\_s*ク\_s*リ\_s*プ\_s*ト\|要\_s*求\|検\_s*索\|復\_s*帰\|返\_s*[事信]\|拒\_s*否\|反\_s*射\_s*鏡\|参\_s*\%(考\_s*文\_s*献\|照\_s*型\)\|機\_s*能\_s*回\_s*復\_s*訓\_s*練\|再\_s*帰\_s*的\|認\_s*識\|正\_s*規\_s*表\_s*現\|ア\_s*ー\_s*ル\)', + \ 'S' : '\%([ソ似杣灌傍峙毓育具供備害底苑薗園儲酘貮埆妬埣讒譏詆誹謗濡外猝率喞熄仄息足促束測側燥偬雙帚艘箒諍滝嗽剏湊蔟赱鯵抓嫂贈樔屮壯愡葱澡瀧艚勦歃叟裝竈梍蚤甑搶笊窗薮奘崢槽筝菷弉輳爭掫竃譟箱髞嗾懆瘡孀窓踪匝噪遭艙爪糟莊倉淙曹匆怱繰宋漕簇槍躁鎗箏綜喪痩藻艸葬壮操掻掃奏蹌滄争草層創蒼叢僧走惣送叛乖抑諳某橇轌艝鱒邨巽噂拵忖蹲樽孫遜存尊損囎祚租酥措踈鼡阻詛礎疏疎其蘓齟胙副鼠噌反愬蔬沿祖塑姐訴爼逸組俎徂粗麁疽甦沮咀想そセ芹鬩旃錢刋箭羶潛筌孅阡栫舩氈纎濺舛甎銛簽湶茜槧巛吮癬籤倩痊孱擶贍纖仟磚燹揃綫喘涎荐饌槫濳沾籖筅蟾牋苫專翦亘鐫僣韆箋僊殱殲闡釧賎餞羨顫甅竰糎¢陝踐銓閃潺遷銑栴川剪煽譫僉瞻践跣栓疝詮銭穿戰僭繊腺泉嬋擅淺鮮専潜扇蘚船浅線撰宣洗煎戦千忙伜倅逼蝉旋屑鱈薛椄絏洩卩泄紲攝緤褻浙竊℃窃拙摂接節楔關磧蓆晰威裼績蹐迹蹠跖跡瘠藉勣籍淅晢夕鶺潟碩惜析関席隻甥韲嘶菁瀞晟貰擠睛筬淒婿撕牲齏情萋穽躋掣腥逝惺旌蜻整靖誓制晴攻瀬急勢世競畆丗糶畝堰脊せス鯣鋭坐座李既已昴術辷全滑皇脛臑裾双英村選優営寸漱雪濯薦啌勸啜勧芒薄煤賺鼈捩筋頗亮丞甫輔佑祐介助蘇裔陶曽乃曾即則淳漁篶鑾凉漫硯雀涼鱸鮓鮨遊椙犁耒犂篦隙尽末眇縋管菅廢頽廃窘救掬尠寡粭糘菫速純鈴炭角墨隅】【鄒數陬雛芻菘嵩崇趨樞∃∵¬⌒∀÷≠Δ≫⇒∴×∨≧∫∠∇±≪∧∞≒⇔∩∂∈∬∋∝枢錘帥粹騅陲捶忰悴邃瘁翆萃榱隹誰醉遂膵燧彗綏錐穂炊翠⊥H吹粋推水酔睡棲統耡総漉饐住空寿籔醋簾棄直鋤巣栖剥磨梳擂澂掏總剃好過拗澄吸喫据壽透シ埀謐蘂蕋蕊痺褥茵鵐蔀鷸鴫霑入蔵嶌縞嶋島凋澀沫澁渋縛暫屡荵凌鎬忍簧慕舖↓襪健認啝随從从.舌扱罔虐Θθ秕粃椎椣卓尿貎肉臠猪榻黙蜆楙誠茂成繁重惻鋪陣頻閾櫁樒鹽汐潮瑟蛭疾櫛隲隰嫉蟋漆躾膝失室沒鎭沈滴雫賤鎮靜顰尓爾聢確併◇◆鹿貭叱征質卯滋撓科品鬼鍜錏錣痼凝而拉設萎栞襞吝咳爲什導怪汁験記徴著印○〇』銀城代『報調蝨濕湿七僕楚笞霜臀退斥尻冩寫舍者卸柘炙暹諜喋煮這謝鯱奢赦捨瀉妁鑠嚼抉蹟勺決釋皙爍昔斫蜥刳芍酌爵折癪笏赤灼綽石尺借赭写鷓積舎車斜釈社洙麈殳蛛娶株娵諏鬚侏繻銖卒槭蹙俶倏菽叔蓿粥戚肅淑夙粛縮取殊趣珠恤卆蟀出洲泅楸綉溲遒酬鷲駲楫緝嗅葺穐蹤繍螽讐甃萩楢逎讎鰍售岫收驟舅囚姑蓚鞦脩輯醜習羞酋聚舟秀祝袖啾拾蒐収執衆愁襲就臭蹴週終褶州宗椶棕守朱撞種修周手首狩須儁惷悛雋皴墫蕣順蠢舜旬竣峻駿逡筍春瞬俊蓁畛矧縉蔘鷏齔嗔忱譛袗譖娠疹哂脣簪怎晉鷆臻甄槙寢岑瀋箴軫榛秦襯診鉐津駸讖紳斟唇針呻蜃賑芯瞋振殿侵辛薪晨辰震宸森眞愼伸慎寝晋身進深審親臣鍼心宍信神薯墅杵岨且藷黍苜渚砠狙嶼處胥蜍苴曙背塩緒枌雎蔗庶処所書暑奬簫浹橸舂艢廂陞炒鍬庠獎梢璋將厰邵摺淞訟樅筱燮橡餉愴韶誚峭甞姓敞聲懾稍嘗腫政顳枩慯殤秤湫礁井星廠剿妝霎蛸劭觴愀升鬆樵鷦嶂醤従慫逍倡竦爿墻牆薔笙樟装肖菖≦<湘誦聳檣稱声裳)(蒋蕉嘯慴精霄鈔粧彰鏘悚蕭悄瀟哨焦憔匠鍾償瘴漿頌詔沼妾請衝唱薑庄渉奨娼床牀椒抄荘翔鉦宵傷踵銷召賞猩症昭燒猖昌少尚松晶憧紹捷象承證正笑将称焼照勝招章詳消鐘証硝掌省商昇昃禝稷寔矚謖餝稙軾嗇屬穡拭属燭贖色飾囑嘱織蝕式喰蜀殖諸初埴植食職笶姉徙誣氏思染飼祗時弑滲梔摯肢詩咨祉泗輜厶屍強貲若至師舐咫只紙施誌呰示締厮啻次賜熾趾駟漬笥贄此司如沚尸髭肆閉祀鷙諡枝篩豕滓巵始妛及弛絲浸閇斯翅緊帋揣伺為糸駛痣矢死敷恃茨旨沁嘴蚩試釶俟瓷觜廝緇祠梓址詞之使獅志歯紫雌姿柿諮占絞視嗣識子四恣阯侈幟卮凍史領竢市巳祇齒資謚耆覗脂芝痴粢孜錙耜齎自屎茲岐嗤砥仔しサ杓寤雨鮫清鞘莢騷觸触鰆椹爽騒澤沢濬掠新攫杷渫浚更士桾申白素讚戔蒜驂芟鑚爨汕潸斬餐嶄纉攅慘粲蠶跚衫彡杉秋桑…≡簒纂鯢燦珊繖棧刪卅參鑽蚕算傘3贊▼▽3参賛O散惨産酸嘸摩遉樣彷碍妨様山漣蔑貶垂鮭叫仙寞鏥寥皺淋鯆生虱鯖捌偖扨偵宿禎貞定哘誘蝎蠍授皿祥桟匙簓障囁私篠支捧笹逧迫讃鐸蛹宛真尖碕嵜前崎魁峺遮哢囀候侍核実俚説了暁達逹哲諭慧敏叡聰訓知郷恵智聡悟理杆里小棹竿紮刹箚扎皐撮搜寒捜相主盛觚柧盞盃杯榮栄倒肴魚阪界堺境酒泝逆賢坂榊猿麾挟鷺拶撒擦颯先数察薩刷札晒霽濟纔釵綵切崔砦顋樶凄靫洒衰寨悽犲碎腮哉摧灑責偲殺縡淬倖豺呵苛幸猜塞蔡栽儕采齊財臍截載孥宰済齋犀際災柴賽菜採砕妻債斎斉祭催才細鰓裁歳最埼捉縒筴簀柞辟窄咋册齪筰槊酢嘖朔柵遡溯鑿索搾昨炸冊策錯櫻桜注曝瑳冴磋搓槎刺覺莎作挿嗟紗嵯覚做削冱寂叉荒茶渣左再早避咲査嵳褪挫佐然唆蹉鎖裂醒瑣嗄螫娑砂割蓑狭狹扠些差梭射銹沙下冷捺簑插点止提柤錆乍去裟詐さ√錫す/仕指製西 ┓┐〆□■Шш上#♯щЩ添∪日⊂⊆⊃⊇文静★*☆標嗜青三聖土彩▲△悉署〜∽’‘┏┌集\探§″性セサSシソスΣсСσ秒S]\|ッ\_s*[ソセスシサ]\|ッ\_s*[ソセスシサ]\|っ\_s*[そせすしさ]\|遽\_s*走\|蕎\_s*麦\|内\_s*障\|彼\_s*杵\|諷\_s*歌\|幾\_s*許\|錚\_s*[錚々]\|十\_s*\%(路\|露\_s*盤\)\|冬\_s*青\|微\_s*風\|虚\_s*言\|宙\_s*組\|夫\_s*[夫々]\|返\_s*田\|傴\_s*僂\|U\_s*m\_s*b\_s*e\_s*l\_s*l\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|台\_s*詞\|c\_s*e\_s*n\_s*t\_s*i\|妹\_s*尾\|嘲\_s*笑\|海\_s*象\|蒸\_s*[籠篭]\|魑\_s*魅\|凡\_s*て\|典\_s*侍\|季\_s*雄\|天\_s*[皇蛾]\|蘿\_s*蔔\|V\_s*i\_s*o\_s*l\_s*a\_s*l\_s*e\_s*s\|N\_s*y\_s*m\_s*p\_s*h\_s*a\_s*e\_s*\%(a\_s*c\_s*e\_s*a\_s*e\|o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|夊\_s*繞\|隧\_s*道\|C\_s*\%(型\|言\_s*語\)\|老\_s*舗\|望\_s*潮\|飛\_s*沫\|L\_s*a\_s*\%(m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|b\_s*i\_s*a\_s*t\_s*a\_s*e\)\|埋\_s*葬\_s*虫\|幣\_s*原\|桎\_s*梏\|柳\_s*葉\_s*魚\|衣\_s*魚\|蠹\_s*魚\|汚\_s*点\|惠\_s*雄\|舗\_s*石\|磯\_s*城\|W\_s*i\_s*n\_s*t\_s*e\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|倭\_s*文\|閑\_s*[谷か]\|云\_s*[々云]\|明\_s*\%(々\_s*後\_s*日\|明\_s*後\_s*日\)\|7\_s*月\|7\_s*月\|4\_s*月\|4\_s*[分月]\|羊\_s*[齒歯]\|I\_s*\%(l\_s*l\_s*i\_s*c\_s*i\_s*a\_s*c\_s*e\_s*a\_s*e\|s\_s*o\_s*p\_s*y\_s*r\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\)\|不\_s*[忍知]\|後\_s*\%([輪口志目]\|込\_s*み\)\|軍\_s*鶏\|香\_s*菜\|吃\_s*逆\|蝦\_s*蛄\|輸\_s*[出贏]\|隼\_s*[朗郎]\|笋\_s*[干羹]\|縦\_s*容\|睫\_s*毛\|翡\_s*翠\|東\_s*\%(雲\|海\_s*林\)\|Z\_s*i\_s*n\_s*g\_s*i\_s*b\_s*e\_s*r\_s*a\_s*l\_s*e\_s*s\|続\_s*\%(日\_s*本\_s*\%(紀\|後\_s*紀\)\|後\_s*撰\_s*和\_s*歌\_s*集\)\|髑\_s*髏\|匣\_s*鉢\|復\_s*習\|百\_s*日\_s*紅\|胡\_s*孫\_s*眼\|←\_s*→\|霰\_s*弾\|弥\_s*生\|懺\_s*\%(法\|悔\_s*懺\_s*悔\)\|流\_s*[離石]\|蠑\_s*螺\|覇\_s*王\_s*樹\|C\_s*\%([se]\|y\_s*c\_s*a\_s*d\_s*\%(i\_s*d\_s*a\_s*e\|o\_s*\%(p\_s*s\_s*i\_s*d\_s*a\|f\_s*i\_s*l\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\)\|h\_s*l\_s*o\_s*r\_s*a\_s*n\_s*t\_s*h\_s*a\_s*c\_s*e\_s*a\_s*e\|言\_s*語\|D\_s*店\|型\_s*肝\_s*炎\|a\_s*\%(s\_s*s\_s*y\_s*t\_s*h\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|c\_s*t\_s*a\_s*l\_s*e\_s*s\)\)\|竹\_s*[篦刀筒]\|大\_s*角\_s*豆\|防\_s*人\|曩\_s*に\|向\_s*坂\|一\_s*昨\_s*\%(々\_s*[年日]\|昨\_s*[年日]\)\|實\_s*藤\|甘\_s*藷\|五\_s*月\|月\_s*代\|匂\_s*坂\|税\_s*所\|雑\_s*賀\|骰\_s*子\|P\_s*\%(a\_s*r\_s*i\_s*e\_s*t\_s*a\_s*l\_s*e\_s*s\|t\_s*e\_s*r\_s*i\_s*d\_s*o\_s*s\_s*p\_s*e\_s*r\_s*m\_s*\%(a\_s*l\_s*e\_s*s\|i\_s*d\_s*a\_s*e\)\|r\_s*i\_s*m\_s*u\_s*l\_s*a\_s*l\_s*e\_s*s\)\|A\_s*\%(p\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*a\_s*l\_s*e\_s*s\|n\_s*t\_s*i\_s*m\_s*o\_s*n\_s*y\)\|s\_s*f\_s*o\_s*r\_s*z\_s*a\_s*n\_s*d\_s*o\|瑞\_s*[典西]\|B\_s*\%(r\|シ\_s*ェ\_s*ル\)\|拡\_s*張\_s*子\|s\_s*u\_s*n\|部\_s*分\|置\_s*換\|ア\_s*ン\_s*チ\_s*モ\_s*ン\|構\_s*造\_s*体\|M\_s*\%(e\_s*r\_s*c\_s*u\_s*r\_s*y\|u\_s*s\_s*a\_s*l\_s*e\_s*s\|a\_s*r\_s*q\_s*u\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\)\|D\_s*o\_s*n\_s*a\_s*t\_s*i\_s*o\_s*n\_s* \_s*A\_s*l\_s*p\_s*h\_s*o\_s*n\_s*s\_s*e\_s* \_s*F\_s*r\_s*a\_s*n\_s*c\_s*o\_s*i\_s*s\_s* \_s*d\_s*e\_s* \_s*S\_s*a\_s*d\_s*e\|加\_s*\%(之\|虐\_s*\%(趣\_s*味\|淫\_s*乱\_s*症\)\)\|T\_s*\%(e\_s*t\_s*r\_s*a\_s*c\_s*e\_s*n\_s*t\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\|i\_s*n\|h\_s*e\_s* \_s*S\_s*i\_s*m\_s*p\_s*l\_s*e\_s* \_s*A\_s*P\_s*I\_s* \_s*f\_s*o\_s*r\_s* \_s*e\_s*v\_s*e\_s*n\_s*t\_s*-\_s*b\_s*a\_s*s\_s*e\_s*d\_s* \_s*X\_s*M\_s*L\_s* \_s*p\_s*a\_s*r\_s*s\_s*i\_s*n\_s*g\)\|珪\_s*素\|ケ\_s*イ\_s*素\|計\_s*測\_s*自\_s*動\_s*制\_s*御\_s*学\_s*会\|ネ\_s*ッ\_s*ト\_s*サ\_s*ー\_s*ビ\_s*ス\|ザ\_s*\%(ッ\_s*ク\|ク\_s*セ\_s*ン\|ビ\_s*ー\_s*ネ\|ウ\_s*バ\_s*ー\|ワ\_s*ー\_s*ク\_s*ラ\_s*ウ\_s*ト\|ム\_s*ザ\|ル\_s*ツ\|イ\_s*\%([ルン]\|ラ\_s*ー\|デ\_s*ル\)\|ー\_s*\%([ルラ]\|メ\_s*ン\)\)\|意\_s*味\|ゼ\_s*ミ\|ナ\_s*ト\_s*リ\_s*ウ\_s*ム\|ゾ\_s*\%(ル\|ン\_s*デ\|ー\_s*\%(ム\|リ\_s*ン\_s*ゲ\_s*ン\)\|フ\_s*ィ\_s*ー\)\|ジ\_s*\%(ム\|ー\_s*\%([グク]\|メ\_s*ン\_s*[スズ]\)\|グ\_s*ム\_s*ン\_s*ト\|ン\_s*\%(メ\_s*ル\|グ\_s*シ\_s*ュ\_s*ピ\_s*ー\_s*ル\|テ\_s*ー\_s*ゼ\)\)\|エ\_s*ス\|硫\_s*黄\)', + \ 'T' : '\%([ト乕囚寅虎瀞侶靹舮供纜燭艫朋倶鞆讐讎輩伴共友巴惇沌團団暾丼飩遯燉遁豚禽鷄酉砦塞擒俘虜豐恍惚枢乏塒迚科咎篷笘攴苫鶏伽唱稱鄰隣朿棘刺整鎖處処所床享鴟鵄扉鳶嫁訥刻秋穐晨鴇鬨斎頓幄幃帷柮杤栃閼軣轟屆届咄吶凸駿祀世暁壽繁稔寿豊歳俊利敏年牘悳犢黷慝匿督徳涜∃得特儻釖盜沓納道宕嶝涛萄嶋鬧縢帑塘搨棠樋籘閙梼罩叨夲盪酘兜溏朸稻鞜荅鞳桶黨綯迯鬥擣礑櫂剳淌纛諮棹陦檮磴蘯橦抖榻嶌竇档潼吋鐙亠篤滕讀逗螳蟷稲■鼕幢滔掏當峠読饕疼淘濤籐董悼棟搭痘套=豆燈桃韜統遠騰橈冬討祷骰藤灯島橙凍刀陶糖謄唐投答等桐鍍研鎔外採盗杜荼覩人摂脱屠賭蠧圖秉觧堵兔礪疾執蚪閇熔登畄砺解睹十菟砿溶獲渡留融泊蠹穫飛磨梳妬説録冨取問途莵汢戸図止翔兎跿富塗砥肚とテ瑛晃輝衒寺忝壥靦巓霑殄、鷏躔諂廛碾沾,鷆腆囀槙轉‥:.輾填甜奠顛纒癲恬殿纏展覘篆添梃輦咥垤餮屮銕鐡耋姪跌輟迭逖荻俶廸狄鏑糴笛覿擲迪滴轍的哲敵撤剔徹鐵鉄楴嚏幀鵜羝睇汀棣騁酲柢叮嚔酊掟遉觝釘詆渟眤碵弟碇剃蹄邸締梯悌訂程底偵遞廷逓牴抵呈艇鄭涕啼庭定低照弖てツ模幹劈聾辛列貫面汁液露冷錘舶紡系艷艶寉鉉絃橡劒釼剱劔劍剣弦蔓敦鶴幣兵鉗噤鶫償桓恆典恒常夙勉務努勤拙拐抓倹嬬撮詳審爪褄妻募角晦瞑螺円呟礫具粒辻辟罪捉把閊捕寮曹首阜丘元司官柄仕掴遣攫搏疲使窄莟蕾局壷壺坪綱繋壌蝪培霾戊己伝傳鐔翼翅鍔燕唾續約皷鼓続葛綴番栂槌縋弊費序潰終墜遂鎚椎追做殲捏殱繕傍旁創造作熟机佃蹲拒欟坏鴾槻月障砲裹躑榴謹慎愼恙筒包堤痛衝尾突尽支攣就次付椄漬點津附浸繼撞憑盡継嗣搗詰積接通告連つチ吃釁巷岐衢粽粡因杠契鵆児交腟帙膣些蟄N窒斉秩父捷矗筑築逐盟税力親邇誓迩近苣尖縮鏤塵趁碪珎鎭亭抻朕狆跛闖鴆砧椿枕鎮陳珍沈賃杖找摘茶嫡着豬儲杼潴紵竚瀦躇箸墸苧緒樗楮⊥躅陟猪捗稙飭敕勅著佻髫鼎迢膓萇脹樢吊漲趙鵈輙雕鬯聽廰窕楪挺輒齠悵塚疔糶澂廳蔦晁昶甼誂微凋帖掉停諜跳眺貼鐇澄提喋頭銚ー蝶暢帳丁牒重逃鳥張弔懲肇徴嘲兆釣聴彫潮町頂調貂庁腸超挑朝丶黜綢儔廚丑※惆肘籌寵鍮冢晝蟲胄冑紬稠酎紐鑄冲沖偸宙虫]}{[厨誅鋳紂仲註駐柱注衷籀昼抽中治池岻恥散躓置耻血値夊輊遲笞千稚黹馳家蜘禿穉地魑黐乳智癡致薙褫茅踟緻痴夂知遅ちタ便党屯架椽榱樽弛蕩膤鰔鱈盥戯俵袂保躊為樣様爲袒慱彖壇覃膽疸亶靼憺餤緞憚擔褝啗檀綻攤槫站酖殫毯猯潭鄲襌賺椴摶湍湯澹†‡蛋耽W旦痰啖坦眈反C歎嘆誕胆箪譚担淡鍛短單貪探単覊栲妙戲訊攜携尋訪比畴疇類民髱樂娯恃頼愉楽喩例譬滾激斃仆垰嵶殕倒嫋旅貍狸賛敲称讃蹈踏祟湛鬪斗戰闘戦彳佇叩疂疉疊畳箍鏨違互耕畊畉掌店棚到炭辿撻闥斬燵韃巽辰+援佐扶相輔佑弼助襷髻椨誑胤種塔龍竜糺糜爛漂維伊是理禎直貞惟忠匡徒唯只窘嗜慥確胝鱆鮹凧蛸誥嶽哮茸英豪威毅猛笋筍酣雄健丈斌武靈彈珪承賚珠霊魂卵偶適環弾球玉丹謀莨束縱|盾鬣奉楯蓼縦竪城質達館忽橘舘瀑薪滝瀧峪溪渓谿谷任尭宇亨臣集昂楼小剛恭岳洪喬嵩尚孚崇尊敬孝隆貴鷹竹篁簟寶財高寳宝但柝拆倬鈬濯魄擢擇柘戳啅鐸澤綰畜企啄磔匠巧択沢逞琢蓄度宅託卓謫托拓紿軆隶殆黛帶替靆抬體躰滯碓平駘擡逮腿当怠玳諦岱鯛對颱袋戴堆態頽苔滞待代帝貸隊褪胎帯体泰退大対矯食埀断炊闌佗長強焚岔給蛇夛足賜揉閉立發躱詫太経貯起薫耐溜絶発手它朶多他勃詑垂誰撓斷裁咤点汰建堪澑田截逹侘經たЦц〜天時×型火土→都吐東上噸瓲│┃台表第木スジ∴Θθザ正ツ¨転透▲△▼▽トチ・…試端タTТ├┸┳┨┫┝┬〒┷τ┯┤┣┻Τテ┥┰т┠┴T]\|ッ\_s*[トテツチタ]\|ッ\_s*[トテツチタ]\|っ\_s*[とてつちた]\|門\_s*渡\_s*り\|薯\_s*蕷\|船\_s*尾\_s*座\|公\_s*[暁明]\|倫\_s*[子明]\|邑\_s*中\|蜻\_s*蛉\|A\_s*c\_s*o\_s*n\_s*i\_s*t\_s*u\_s*m\|蜷\_s*局\|跡\_s*[絶切]\|蜥\_s*蜴\|舎\_s*人\|馴\_s*鹿\|野\_s*老\|瓊\_s*脂\|永\_s*[遠久]\|宿\_s*直\|朱\_s*鷺\|左\_s*見\_s*右\_s*見\|朽\_s*木\|H\_s*y\_s*d\_s*r\_s*o\_s*c\_s*h\_s*a\_s*r\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|独\_s*鈷\|季\_s*[衣道栄]\|聡\_s*[明徳]\|祈\_s*年\_s*祭\|淑\_s*[夫子]\|洞\_s*爺\|光\_s*男\|晧\_s*史\|紅\_s*娘\|瓢\_s*虫\|F\_s*e\|I\_s*r\_s*o\_s*n\|劇\_s*村\|滌\_s*除\|2\_s*×\_s*4\|石\_s*\%(蕗\|竜\_s*子\)\|心\_s*[太算]\|自\_s*\%(摸\|模\_s*和\)\|氷\_s*柱\|倩\_s*々\|黴\_s*雨\|入\_s*梅\|梅\_s*雨\|再\_s*見\|備\_s*に\|悉\_s*に\|旋\_s*[風毛]\|B\_s*a\_s*l\_s*a\_s*n\_s*o\_s*p\_s*h\_s*o\_s*r\_s*a\_s*l\_s*e\_s*s\|1\_s*\%(日\|0\_s*日\)\|1\_s*\%(日\|0\_s*日\)\|朔\_s*日\|美\_s*人\_s*局\|E\_s*\%(u\_s*p\_s*h\_s*o\_s*r\_s*b\_s*i\_s*a\_s*l\_s*e\_s*s\|r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|字\_s*\%(牌\|一\_s*色\)\|少\_s*と\|義\_s*父\|主\_s*[殿税]\|周\_s*夫\|睦\_s*子\|渠\_s*睦\_s*子\|萵\_s*苣\|身\_s*柱\|似\_s*指\|清\_s*\%(老\_s*頭\|一\_s*色\)\|青\_s*\%([幇島]\|梗\_s*菜\|椒\_s*肉\_s*絲\)\|全\_s*帯\|昌\_s*洙\|江\_s*蘇\|J\_s*i\_s*a\_s*n\_s*g\_s*s\_s*u\|焼\_s*豚\|叉\_s*焼\|察\_s*哈\_s*爾\|餃\_s*子\|雑\_s*砕\|炒\_s*[麺飯]\|北\_s*谷\|甘\_s*露\_s*子\|錯\_s*和\|総\_s*角\|一\_s*[日寸]\|植\_s*字\|金\_s*魚\_s*蝨\|魚\_s*[屋蝨]\|草\_s*石\_s*蚕\|春\_s*\%(麗\|宮\_s*坊\)\|九\_s*\%(十\_s*九\|連\_s*宝\_s*[燈灯]\)\|揺\_s*蕩\|容\_s*易\|白\_s*痴\|猶\_s*豫\|蜑\_s*民\|段\_s*銭\|蒲\_s*公\_s*英\|騨\_s*州\|M\_s*\%(e\_s*n\_s*i\_s*s\_s*p\_s*e\_s*r\_s*m\_s*a\_s*c\_s*e\_s*a\_s*e\|o\_s*n\_s*o\_s*\%(p\_s*e\_s*t\_s*a\_s*l\_s*a\_s*e\|c\_s*\%(h\_s*l\_s*a\_s*m\_s*y\_s*d\_s*e\_s*a\_s*e\|o\_s*t\_s*y\_s*l\_s*e\_s*d\_s*o\_s*n\_s*e\_s*a\_s*e\)\)\)\|仮\_s*令\|打\_s*[擲坐]\|七\_s*\%(夕\|対\_s*子\)\|活\_s*計\|方\_s*便\|無\_s*料\|黄\_s*\%(昏\|蜀\_s*葵\)\|胼\_s*胝\|章\_s*魚\|P\_s*\%(\.\_s*S\_s*\.\|o\_s*l\_s*y\_s*\%(g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|c\_s*a\_s*r\_s*p\_s*i\_s*c\_s*a\_s*e\)\|a\_s*n\_s*d\_s*a\_s*n\_s*a\_s*l\_s*e\_s*s\)\|壮\_s*聡\|煙\_s*草\|殺\_s*陣\|賢\_s*明\|性\_s*質\|怱\_s*ち\|亢\_s*ぶ\|堂\_s*子\|学\_s*聡\|能\_s*[文之]\|内\_s*匠\|松\_s*明\|奈\_s*子\|幇\_s*間\|切\_s*符\|デ\_s*ィ\_s*ス\|3\_s*r\_s*d\|閾\_s*値\|ソ\_s*\%(ー\_s*[トンプ]\|ロ\_s*ー\)\|ヘ\_s*ー\_s*グ\|ゼ\_s*[インムア]\|セ\_s*\%(オ\|ル\_s*マ\|ロ\_s*\%(ン\|ニ\_s*ア\_s*ス\)\|ラ\_s*ピ\_s*\%(ー\|ス\_s*ト\)\)\|シ\_s*\%(ン\|ッ\_s*ク\|ス\_s*ル\|ア\_s*タ\_s*ー\|ソ\_s*ー\_s*ラ\_s*ス\|オ\_s*ド\_s*ア\|ー\_s*[フタ]\)\|サ\_s*\%([イム]\|ミ\_s*ン\_s*グ\|ウ\_s*ザ\_s*ン\_s*ド\|ラ\_s*ブ\_s*レ\_s*ッ\_s*ド\|ー\_s*\%([ドモ]\|テ\_s*ィ\|ス\_s*ト\_s*ン\|ズ\_s*デ\_s*[イーィ]\|マ\_s*ル\)\|ッ\_s*チ\_s*ャ\_s*ー\|ン\_s*\%(ク\|ダ\_s*ー\|キ\_s*ュ\_s*ー\)\|リ\_s*ド\_s*マ\_s*イ\_s*ド\)\|ポ\_s*リ\_s*ペ\_s*プ\_s*チ\_s*ド\|三\_s*\%(和\_s*土\|連\_s*文\_s*字\)\|\\\_s*T\_s*e\_s*X\|教\_s*科\_s*書\|文\_s*字\_s*列\|t\_s*e\_s*\%(r\_s*a\|m\_s*p\_s*o\_s*r\_s*a\_s*r\_s*y\)\|用\_s*語\|電\_s*\%([視話]\|気\_s*通\_s*信\_s*研\_s*究\_s*所\)\)', + \ 'U' : '\%([ウ孳蛤礼敬恭洞鱗愛潤騒煩粳漆閏患慯悄騷恙愁呻楳梅嫐釉噂耘吽褞曇黄紜云繧慍薀蘊暈運錙怏麗羨卦憾怨恨占卜末嬉心裏浦糶瓜汝己畴畆畦疇畝踈疎宜諾奪姥腕莵兔驢鑿穿嗽魘唸促令項頷訴獺鷽嘯嘘蠕蠢動覘窺伺海台萼唱詠謌唄宴讌転詩謠謡謳疑歌葎鯏鴬鶯ヱゑゐヰ鶉疼堆踞蹲渦舂臼碓羅薄食筌槽朮肯凵魚巧茨廐廏厩鰻午甘秣孫餞馬旨冩遷寫蔚暎噐器移慈俯映写現虚美笂靭靱靫空鰾萍初蛆雲氏上後喪艮丑潮牛裡鬱中欝袿梁家内禹憂埋挧撃雨打宇得植請鵜熟績嫗攴有夘受茹泛生討羽胡右紆傴盂饂承菟飢烏攵于射倦芋賣卯享搏失齲撲兎売産膿迂浮う¨↑∪UυウуУΥU]\|武\_s*漢\|狼\_s*狽\|夏\_s*枯\_s*草\|蠎\_s*蛇\|蟒\_s*蛇\|譫\_s*言\|琅\_s*珠\|温\_s*[麺気州]\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|自\_s*惚\|采\_s*女\|乳\_s*母\|姨\_s*捨\_s*山\|独\_s*活\|優\_s*\%(婆\_s*[塞夷]\|曇\_s*華\)\|合\_s*格\|親\_s*族\|斥\_s*候\|泡\_s*沫\|楽\_s*官\|雅\_s*楽\_s*[頭寮]\|干\_s*莉\|維\_s*納\|太\_s*秦\|護\_s*田\_s*鳥\_s*尾\|淡\_s*\%(青\|口\_s*醤\_s*油\)\|五\_s*\%(加\|月\_s*蝿\)\|稲\_s*魂\|誓\_s*約\|石\_s*\%(女\|斑\_s*魚\)\|不\_s*生\_s*女\|味\_s*酒\|苜\_s*蓿\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|伝\_s*染\|呆\_s*気\_s*者\|茴\_s*香\|外\_s*郎\|餓\_s*\%(死\|え\_s*死\_s*に\)\|裲\_s*襠\|団\_s*扇\|イ\_s*ギ\_s*リ\_s*ス\|オ\_s*マ\_s*ル\|識\_s*別\_s*不\_s*能\|共\_s*\%(用\_s*体\|有\_s*体\)\|ア\_s*\%([スン]\|グ\_s*リ\_s*ー\|ー\_s*\%(シ\_s*ュ\_s*ラ\|ジ\_s*ェ\_s*ン\_s*ト\|バ\_s*ン\)\|ル\_s*テ\_s*ィ\_s*メ\_s*ッ\_s*ト\|ポ\_s*ン\|ッ\_s*\%(プ\|パ\_s*ー\|シ\_s*ャ\_s*ー\)\)\|単\_s*\%(位\|一\_s*化\)\|ユ\_s*\%([タニー]\|ト\_s*\%(リ\_s*ロ\|レ\_s*ヒ\_s*ト\)\|リ\_s*\%(ア\|シ\_s*ー\_s*ズ\)\|プ\_s*シ\_s*ロ\_s*ン\|ネ\_s*ス\_s*コ\|ナ\_s*\%(カ\_s*イ\_s*ト\|イ\_s*テ\_s*ッ\_s*ド\)\|ビ\_s*キ\_s*\%(タ\_s*ス\|ノ\_s*ン\)\)\)', + \ 'V' : '\%([:├値V⊥版Вв↓∨ヴV]\|ッ\_s*ウ\_s*゙\|ッ\_s*ヴ\|っ\_s*ヴ\|ウ\_s*゙\|v\_s*e\_s*r\_s*s\_s*u\_s*s\|v\_s*s\_s*.\|チ\_s*ェ\_s*ロ\|ヰ\_s*タ\| \_s*ビ\_s*ク\_s*ト\_s*ー\_s*ル\|視\_s*覚\|仮\_s*想\|ニ\_s*ス\|変\_s*数\|恒\_s*真\|ワ\_s*\%(デ\_s*ィ\_s*ム\|ギ\_s*ナ\|ニ\_s*ス\|セ\_s*リ\_s*ン\|ク\_s*チ\_s*ン\|ル\_s*キ\_s*ュ\_s*ー\_s*レ\|レ\_s*リ\_s*ー\|ー\_s*ニ\_s*ャ\)\|語\_s*彙\|ボ\_s*\%(ス\_s*ト\_s*ー\_s*ク\|ン\_s*ゴ\_s*レ\|ル\_s*\%([ガボトタ]\|テ\_s*\%(ッ\_s*ク\_s*ス\|ー\_s*[ジル]\)\)\|リ\_s*ュ\_s*ー\_s*ム\|ラ\_s*ン\_s*\%(チ\|テ\_s*ィ\_s*ア\|タ\_s*リ\_s*ー\)\|レ\_s*ー\|コ\_s*ー\_s*ダ\|ー\_s*\%([ントグ]\|ル\_s*ト\|ド\_s*ビ\_s*\%(ル\|リ\_s*ア\_s*ン\)\|パ\_s*ル\|ダ\_s*フ\_s*ォ\_s*ン\|カ\_s*\%(ル\|リ\_s*ス\_s*ト\)\)\|キ\_s*ャ\_s*ブ\_s*ラ\_s*リ\|イ\_s*\%([ドス]\|ジ\_s*ャ\_s*ー\|シ\_s*ン\_s*グ\)\)\|ヘ\_s*ッ\_s*ト\|冗\_s*長\_s*な\|垂\_s*直\|フ\_s*\%(ァ\_s*\%(ン\|ド\_s*ー\_s*ツ\)\|ォ\_s*\%(ン\|ル\_s*\%(ク\|カ\_s*ー\)\)\|ェ\_s*ル\_s*メ\_s*ー\_s*ル\)\|ウ\_s*\%(ラ\_s*\%(デ\_s*ィ\_s*ミ\_s*ー\_s*ル\|ジ\_s*\%(ミ\_s*ー\_s*ル\|ー\_s*ミ\_s*ル\|オ\_s*ス\_s*ト\_s*\%(ク\|ッ\_s*ク\)\)\)\|ィ\_s*\%(ン\_s*ナ\|ル\_s*ス\)\|ォ\_s*ッ\_s*カ\|イ\_s*\%(ル\_s*ス\|ン\_s*ナ\_s*ー\)\|ェ\_s*\%(ル\_s*ギ\_s*リ\_s*ウ\_s*ス\|ヌ\_s*ス\)\)\|ビ\_s*\%([アラブバスザ]\|ガ\_s*ー\|ハ\_s*ー\_s*ラ\|タ\_s*ミ\_s*ン\|レ\_s*\%(ッ\_s*ジ\|ロ\_s*イ\)\|ビ\_s*\%(ア\_s*ン\|ッ\_s*ド\)\|ッ\_s*\%(ク\|キ\_s*ー\)\|セ\_s*ン\_s*テ\|ク\_s*\%(タ\_s*ー\|ト\_s*\%(ル\|リ\_s*[ーア]\)\)\|シ\_s*\%(ャ\_s*ス\|ソ\_s*ワ\_s*ー\_s*ズ\)\|ン\_s*\%([チス]\|ソ\_s*ン\|テ\_s*ー\_s*ジ\|セ\_s*ン\_s*ト\)\|ネ\_s*\%(ガ\_s*ー\|グ\_s*レ\_s*ッ\_s*ト\)\|ニ\_s*\%([ール]\|リ\_s*デ\_s*ン\)\|ュ\_s*ー\|エ\_s*ン\_s*チ\_s*ャ\_s*ン\|ジ\_s*\%(ャ\|ッ\_s*ト\|タ\_s*ー\|ョ\_s*\%(ン\|ナ\_s*リ\_s*ー\)\|ュ\_s*ア\_s*\%(ル\|ラ\_s*イ\_s*\%(ズ\|ゼ\_s*ー\_s*シ\_s*ョ\_s*ン\)\)\)\|ダ\_s*ル\|デ\_s*オ\|ル\_s*\%(ゴ\|ヌ\_s*ー\_s*ブ\)\|オ\_s*ラ\|リ\_s*ジ\_s*ア\_s*ン\|ィ\_s*ー\_s*ナ\_s*ス\|ー\_s*\%(ボ\|ル\_s*ス\|ク\_s*ル\|ナ\_s*ス\)\)\|ベ\_s*\%([ガラン]\|ト\_s*ナ\_s*ム\|イ\_s*ダ\_s*ー\|ー\_s*\%(ル\|ダ\_s*ー\)\|テ\_s*ラ\_s*ン\|ッ\_s*セ\_s*ル\|ス\_s*\%([トタパ]\|ビ\_s*オ\)\|ク\_s*\%(タ\|ト\_s*ル\)\|ジ\_s*タ\_s*\%(ブ\_s*ル\|リ\_s*ア\_s*ン\)\|リ\_s*\%([ィー]\|フ\_s*ァ\_s*イ\|サ\_s*イ\_s*ン\)\|ロ\_s*\%(ナ\|シ\_s*テ\_s*ィ\|ー\_s*ナ\|ニ\_s*[カク]\)\|ル\_s*\%(デ\|ベ\_s*ッ\_s*ト\|ダ\_s*ン\|レ\_s*ー\_s*ヌ\|サ\_s*\%(ー\_s*チ\|イ\_s*ユ\)\|モ\_s*ッ\_s*ト\)\|ノ\_s*ム\|ニ\_s*[スヤア]\|ネ\_s*\%(シ\_s*ャ\_s*ン\|ツ\_s*ィ\_s*ア\|チ\_s*ア\|ズ\_s*エ\_s*ラ\)\)\|バ\_s*\%([ルン]\|イ\_s*\%([アブンオ]\|パ\_s*ー\|タ\_s*\%(ル\|リ\_s*テ\_s*ィ\)\|キ\_s*ン\_s*グ\|ザ\_s*ー\|シ\_s*ャ\)\|ッ\_s*ト\|チ\_s*カ\_s*ン\|ギ\_s*ナ\|ガ\_s*ボ\_s*ン\_s*ド\|ラ\_s*\%(ナ\_s*シ\|エ\_s*テ\_s*ィ\)\|サ\_s*ロ\|ス\_s*\%(コ\|ケ\_s*ス\)\|カ\_s*ン\_s*ス\|ケ\_s*ー\_s*シ\_s*ョ\_s*ン\|キ\_s*ュ\_s*ー\_s*ム\|ウ\_s*チ\_s*ャ\_s*ー\|リ\_s*\%(ン\|エ\_s*ー\_s*シ\_s*ョ\_s*ン\|ュ\_s*ー\|ア\_s*\%(ブ\_s*ル\|ン\_s*ト\)\|ッ\_s*ド\|デ\_s*ー\_s*シ\_s*ョ\_s*ン\)\|ヌ\_s*ア\_s*ツ\|ニ\_s*\%(ラ\|ー\_s*ユ\)\|レ\_s*\%([ラー]\|ロ\_s*ン\|リ\_s*ー\|ン\_s*\%(シ\_s*ア\|チ\_s*ノ\|タ\_s*イ\_s*ン\)\)\|ー\_s*\%([ゴグ]\|チ\_s*ャ\_s*ル\|リ\_s*ト\_s*ゥ\_s*ー\_s*ド\|バ\_s*ル\|ボ\_s*ス\|ベ\_s*ナ\|テ\_s*ィ\_s*カ\_s*ル\|サ\_s*ス\|ジ\_s*\%(ン\|ニ\_s*ア\|ョ\_s*ン\)\|ノ\_s*ン\|ニ\_s*ア\|モ\_s*ン\_s*ト\|ミ\_s*\%(リ\_s*オ\_s*ン\|キ\_s*ュ\_s*ラ\_s*イ\_s*ト\)\)\|ナ\_s*\%(キ\_s*ュ\_s*ラ\_s*ー\|ジ\_s*ウ\_s*ム\)\)\|ブ\_s*\%(イ\|ラ\_s*\%(ド\|ッ\_s*ド\)\|ー\_s*ド\_s*ゥ\_s*ー\)\)', + \ 'W' : '\%([ヲヲ女翁尾汚小惜男緒牡雄をウ孳蛤礼敬恭洞鱗愛潤騒粳漆閏慯悄騷恙愁呻楳梅嫐釉噂耘吽褞曇紜云繧慍薀蘊暈運錙怏麗羨U卦憾怨恨占卜末嬉心裏浦糶瓜汝己υΥ畴畆畦疇畝踈疎宜諾奪姥莵兔驢鑿穿嗽魘唸促令項頷訴獺鷽嘯嘘蠕蠢動覘窺伺台萼唱詠謌唄宴讌転詩謠謡謳疑歌葎鯏鴬鶯ヱゑ鶉疼堆踞蹲渦舂臼碓羅薄食筌槽朮肯凵魚巧茨廐廏厩鰻午甘秣孫餞馬旨冩遷寫蔚暎噐器移慈俯映写現虚美笂靭靱靫空鰾萍初蛆氏↑上後喪艮丑潮牛裡鬱中欝袿梁家内禹憂埋挧撃雨打宇得植請鵜熟績嫗攴有夘受茹泛生討胡右紆傴盂饂承菟飢烏攵于射倦芋賣卯享搏失齲撲兎売産膿迂浮うヰ居ゐワ叫喚÷惡悪原稿嗤妾蕨童藁鞋笑灣萬豌綰万弯彎椀雲腕碗湾横往黄皇羂罠纔毫微僅患煩術伎厄禍災態業技佗王鰐忘掖弁腋譯緜腸亙道渉航弥亘棉渡綿私薈隈賄淮脇矮猥歪轍海蟠儂∪觧解頒判訣別稚若或枠惑鷲和環吾杷啝湧我涌輪破分把萵詫訳羽沸倭割話侘琶わ幅水∧波WウワW]\|ッ\_s*[ヲヱウヰワ]\|ッ\_s*[ヲヱウヰワ]\|っ\_s*[をゑうゐわ]\|乎\_s*古\_s*止\_s*点\|武\_s*漢\|狼\_s*狽\|夏\_s*枯\_s*草\|蠎\_s*蛇\|蟒\_s*蛇\|譫\_s*言\|琅\_s*珠\|温\_s*[麺気州]\|C\_s*u\_s*c\_s*u\_s*r\_s*b\_s*i\_s*t\_s*a\_s*l\_s*e\_s*s\|自\_s*惚\|采\_s*女\|乳\_s*母\|姨\_s*捨\_s*山\|独\_s*活\|優\_s*\%(婆\_s*[塞夷]\|曇\_s*華\)\|合\_s*格\|親\_s*族\|斥\_s*候\|泡\_s*沫\|楽\_s*官\|雅\_s*楽\_s*[頭寮]\|干\_s*莉\|維\_s*納\|護\_s*田\_s*鳥\_s*尾\|淡\_s*\%(青\|口\_s*醤\_s*油\)\|五\_s*\%(加\|月\_s*蝿\)\|稲\_s*魂\|誓\_s*約\|石\_s*\%(女\|斑\_s*魚\)\|不\_s*生\_s*女\|味\_s*酒\|苜\_s*蓿\|A\_s*r\_s*i\_s*s\_s*t\_s*o\_s*l\_s*o\_s*c\_s*h\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|伝\_s*染\|呆\_s*気\_s*者\|茴\_s*香\|外\_s*郎\|餓\_s*\%(死\|え\_s*死\_s*に\)\|裲\_s*襠\|団\_s*扇\|草\_s*鞋\|(\_s*笑\_s*)\|(\_s*笑\_s*)\|戦\_s*慄\|俳\_s*優\|勿\_s*忘\_s*草\|早\_s*[生稲]\|山\_s*葵\|戯\_s*奴\|度\_s*会\|Y\_s*\%(軸\|シ\_s*ャ\_s*ツ\|染\_s*色\_s*体\)\|Y\_s*\%(軸\|シ\_s*ャ\_s*ツ\|染\_s*色\_s*体\)\|華\_s*盛\_s*頓\|裙\_s*蔕\_s*菜\|理\_s*[由解]\|公\_s*魚\|病\_s*葉\|大\_s*東\_s*亜\_s*戰\_s*爭\|太\_s*\%(秦\|平\_s*洋\_s*戦\_s*争\)\|歐\_s*州\_s*大\_s*戰\|第\_s*\%(二\_s*次\_s*世\_s*界\_s*大\_s*戦\|一\_s*次\_s*世\_s*界\_s*大\_s*戦\)\|ブ\_s*ル\_s*ツ\_s*ブ\_s*ル\_s*ク\|ロ\_s*ン\_s*グ\|レ\_s*\%(ン\|イ\_s*ス\|ッ\_s*カ\_s*ー\|ス\_s*\%(ラ\_s*ー\|リ\_s*ン\_s*グ\)\)\|リ\_s*\%(ー\_s*ス\|ン\_s*ク\_s*ル\|ス\_s*ト\)\|書\_s*き\_s*込\_s*み\|ラ\_s*\%(ッ\_s*\%([プパ]\|ピ\_s*ン\_s*グ\)\|イ\_s*\%([タト]\|テ\_s*ィ\_s*ン\_s*グ\)\)\|ボ\_s*ル\_s*フ\|フ\_s*\%([ムー]\|ァ\_s*イ\_s*ル\|ィ\_s*\%(ー\_s*ト\|ッ\_s*チ\)\)\|ホ\_s*\%(エ\_s*[イーア]\|ー\_s*ル\|イ\_s*\%(ー\_s*\%(ル\|ラ\_s*ー\)\|ッ\_s*\%(プ\|ス\_s*ル\|パ\_s*ー\|ト\_s*\%(ニ\_s*ー\|マ\_s*ン\)\)\)\|ワ\_s*\%(イ\|ッ\_s*[トツ]\)\)\|ベ\_s*ル\_s*ナ\_s*ー\|w\_s*e\_s*b\_s*サ\_s*\%(イ\_s*ト\|ー\_s*\%(バ\|ビ\_s*ス\)\)\|警\_s*告\|バ\_s*ル\_s*タ\_s*ー\|ヴ\_s*\%(ュ\_s*ル\_s*ツ\_s*ブ\_s*ル\_s*ク\|ォ\_s*ル\_s*フ\|ィ\_s*\%([ーム]\|ル\_s*\%(ム\|ヘ\_s*ル\_s*ム\)\)\|ェ\_s*\%(ン\_s*ダ\_s*ー\_s*ス\|ル\_s*ナ\_s*ー\|ー\_s*バ\_s*ー\|イ\_s*ユ\)\|ァ\_s*\%(イ\_s*[ンス]\|ー\_s*グ\_s*ナ\_s*ー\|ン\_s*ダ\|ル\_s*\%(タ\_s*ー\|キ\_s*ュ\_s*ー\_s*レ\)\)\)\|ダ\_s*ブ\_s*リ\_s*ュ\_s*ー\|タ\_s*ン\_s*グ\_s*ス\_s*テ\_s*ン\|T\_s*\%(h\_s*e\_s* \_s*W\_s*o\_s*r\_s*l\_s*d\_s* \_s*W\_s*i\_s*d\_s*e\_s* \_s*W\_s*e\_s*b\_s* \_s*C\_s*o\_s*n\_s*s\_s*o\_s*r\_s*t\_s*i\_s*u\_s*m\|u\_s*n\_s*g\_s*s\_s*t\_s*e\_s*n\)\)', + \ 'X' : '\%([ォォぉェェぇゥゥぅィィぃァァぁXхХΞ×ξX]\|ッ\_s*[ォェゥィァ]\|ッ\_s*[ォェゥィァ]\|っ\_s*[ぉぇぅぃぁ]\|シ\_s*ロ\_s*\%(ホ\_s*ン\|フ\_s*ォ\_s*ン\)\|ジ\_s*オ\_s*ン\|ゼ\_s*\%(ビ\_s*ウ\_s*ス\|ロ\_s*\%(ッ\_s*ク\_s*ス\|グ\_s*ラ\_s*フ\_s*ィ\)\)\|ハ\_s*ビ\_s*エ\_s*ル\|ザ\_s*\%(ン\|ビ\_s*エ\_s*ル\)\|キ\_s*\%(シ\_s*\%(ロ\|レ\_s*ン\|リ\_s*ト\_s*ー\_s*ル\)\|セ\_s*ノ\_s*ン\|サ\_s*ン\_s*\%(チ\_s*ン\|タ\_s*ン\)\)\|E\_s*x\_s*t\_s*e\_s*n\_s*s\_s*i\_s*b\_s*l\_s*e\_s* \_s*M\_s*a\_s*r\_s*k\_s*u\_s*p\_s* \_s*L\_s*a\_s*n\_s*g\_s*u\_s*a\_s*g\_s*e\|ク\_s*\%(シ\_s*ー\|ロ\_s*ス\_s*ポ\_s*ス\_s*ト\|セ\_s*\%(ナ\_s*キ\_s*ス\|ノ\_s*フ\_s*ォ\_s*ン\)\|ザ\_s*ヴ\_s*ィ\_s*エ\|サ\_s*\%(イ\|ン\_s*\%(ト\_s*ス\|チ\_s*ッ\_s*ペ\|テ\_s*ィ\_s*ッ\_s*ペ\)\)\|リ\_s*ス\_s*マ\_s*ス\)\|エ\_s*\%(ク\_s*ス\|ッ\_s*ク\_s*ス\)\)', + \ 'Y' : '\%([ヨ艾蒿蓬娵嫁齡齢據頼弱憙歓鎧万萬過便婚汚涎捩翊緘峪杙慾欲翌翼抑米比裝粧装澱淀縦誼祥葭悦宜克純圭禎葦慶禧美淑芳喜吉義瘍樣踴榕踊燿謠廱姚慂曄瀁瑶恙蓉遙怏雍痒珱陶孕漾昜暘甬幺癢泱癰窰慵穃鷹瓔煬邀遥拗擁瑤窯徭膺窈殀曜耀庸夭揚葉蛹腰羊熔杳沃壅様妖用溶佯謡陽洋嘉宵蘇蘓甦辟奸横豫代除譽歟喚預読誉蕷輿攀余縒呼避4世譱詠丗能予撚憑餘畭酔醉與飫舁四訓選与讀よユ潤赦弛緩聴岼閖梦努纈∴故濯檠穰豐豊倖志裄之幸雪趾梼讓譲牀縁紫浴床俑犹蚰酉莠邑攸黝熊尢蝣蕕猷悒囿佳尤佑〒右郵涌祐侑游猶湧融宥夕幽悠釉友雄憂有臾渝瘉愉征諭徃遊揺逾覦茹揄由蝓兪淘結輸諛搖揃弓楡瑜踰柚油喩汰腴ゆイΗη賤鄙卑苟嫌妹湯藷芋夢艷鑪鈩彩鱗色鯆忽綺貸甍応答愈圦杁霪隱蚓寅氤酳胤飮韵尹茵贇蔭婬湮堙吋廴I音慇韻咽淫殞姻隕院允殷隠陰窟巌巖頌祝鰛鰮鰯岩磐鼾歪弑弋抱懐肬贅疣狗戌乾犬諱在坐未汝戒誡警縛今Εε曰禾稻員因蝗印嘶鰍電引躄誘動忿≦鵤錨碇怒霆雷霹凧桴筏Ιι魚菴庵雖尿荊棘茨祈祷命猯豕古伍乙鎰鴪聿軼樹慈悼愴慯労格到至傷鼬頂戴徒致鈑痛板柞砂沙些聊潔諍烈功諫勳勲勇漁諌憇=憩粹熱粋憤域閾勢勤忙急磯孰焉湶泉厳何弄苛≧鎔范啀毬訝燻息指挑拠縷絲厭營営愛幼緒遑暇糸I弌壹肆莓苺櫟著市碑鐓礎甃臀弩石犧牲犠池溢佚壱11燠鬻礇毓粥的戦戰軍幾郁一稲許否飯洟位違居姨猗斎偽噫逝医鑄痍委囲云圍ゐ挿炒彙要熨饐醫言矮往詒威懿入如僞忌彜煎逶緯韋唯莞淹胃善生恚彝惟以活蔚為猪衣倚幃斐移鮪将可偉畏五夷李渭怡貽癒依逸井慰行伊爲胆射詑矣頤熬萎良凍出椅率好揖肄痿鋳謂帷亥苡意維遺鰄異去堰容囗いヤ稚稍飲鎗鑓槍孀寡鰥Я碼傭雇闇敗吝薮藪殕脂寄宿櫓軈軅簗梁S漸鋏刃灸和柔軟窶鱧奴僕萢優柳喧宅館舘輩族鏃龠檪≒譯籥鑰蜴繹藥葯扼益厄疫躍約役訳薬疚疾岾楊谺邪薯犲豺〈《》〉山壥邸廛豢養社鑢育廉寧尉裕恭泰易休保康安靖笶八熄演谷焼彌冶⇔也輻破辭埜痩野屋家病椰爺已矢燒⇒灼妬耶遣瘠哉罷夜殺止揶辞弥やYеЕ円¥←↓↑→ёЁ━─ユヤヨЙυイЫыйΥY]\|ッ\_s*[ヨユイヤ]\|ッ\_s*[ヨユイヤ]\|っ\_s*[よゆいや]\|欧\_s*羅\_s*巴\|歐\_s*羅\_s*巴\|尸\_s*童\|蹌\_s*踉\|蹣\_s*跚\|終\_s*夜\|4\_s*\%([項者つ日]\|番\_s*目\|種\_s*類\)\|y\_s*o\_s*\%(t\_s*t\_s*a\|c\_s*t\_s*o\)\|他\_s*所\|仁\_s*史\|隆\_s*克\|尚\_s*武\|孝\_s*高\|悌\_s*也\|賀\_s*[子悟]\|彬\_s*伯\|栄\_s*伸\|宗\_s*生\|新\_s*生\|昌\_s*[美男]\|暢\_s*[子一]\|永\_s*沈\|8\_s*日\|8\_s*日\|黄\_s*泉\|左\_s*手\|百\_s*合\|L\_s*i\_s*l\_s*i\_s*\%(o\_s*p\_s*s\_s*i\_s*d\_s*a\|a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\)\|U\_s*\%(字\|タ\_s*ー\_s*ン\)\|鞦\_s*韆\|強\_s*請\|梅\_s*桃\|桜\_s*桃\|靫\_s*負\|宙\_s*美\|礼\_s*暁\|温\_s*\%(雄\|泉\_s*津\)\|長\_s*庚\|昨\_s*夜\|又\_s*木\|木\_s*綿\|E\_s*\%(u\|メ\_s*ー\_s*ル\)\|祖\_s*谷\|文\_s*身\|郎\_s*[女子]\|刺\_s*[青草]\|蕁\_s*麻\|U\_s*\%(字\|タ\_s*ー\_s*ン\|r\_s*t\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\)\|海\_s*[豚参]\|西\_s*表\|鸚\_s*哥\|影\_s*[向青]\|況\_s*ん\_s*や\|所\_s*[以縁謂]\|D\_s*i\_s*a\_s*p\_s*e\_s*n\_s*s\_s*i\_s*a\_s*l\_s*e\_s*s\|藺\_s*草\|J\_s*u\_s*\%(l\_s*i\_s*a\_s*n\_s*i\_s*a\_s*l\_s*e\_s*s\|n\_s*c\_s*a\_s*l\_s*e\_s*s\)\|田\_s*舎\|膝\_s*行\|十\_s*六\_s*夜\|寝\_s*穢\|英\_s*\%([一桃蘭]\|吉\_s*利\)\|斑\_s*鳩\|烏\_s*賊\|玉\_s*筋\_s*魚\|硫\_s*黄\|N\_s*a\_s*j\_s*a\_s*d\_s*a\_s*l\_s*e\_s*s\|牛\_s*膝\|稜\_s*威\|常\_s*春\_s*藤\|5\_s*[つ日]\|5\_s*[つ日]\|惡\_s*戲\|甚\_s*振\|潮\_s*来\|悪\_s*戯\|交\_s*喙\|小\_s*魚\|鯨\_s*魚\|細\_s*小\_s*魚\|鶏\_s*魚\|経\_s*緯\|礒\_s*[山田]\|E\_s*\%(A\_s*S\_s*T\|V\_s*E\)\|気\_s*吹\|従\_s*[妹姉弟兄]\|公\_s*孫\_s*樹\|鴨\_s*脚\_s*樹\|G\_s*\%(l\_s*u\_s*m\_s*i\_s*f\_s*l\_s*o\_s*r\_s*a\_s*e\|r\_s*a\_s*m\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*k\_s*g\_s*o\_s*p\_s*s\_s*i\_s*d\_s*a\)\|銀\_s*杏\|鳶\_s*尾\|巫\_s*子\|神\_s*巫\|無\_s*花\_s*果\|睦\_s*月\|都\_s*方\_s*流\|縊\_s*[殺死首]\|蝟\_s*[集縮]\|埋\_s*け\_s*[火炭]\|不\_s*[可如]\|守\_s*宮\|燕\_s*龍\_s*茶\|両\_s*班\|流\_s*鏑\_s*馬\|柵\_s*原\|箭\_s*[田内]\|R\_s*a\_s*f\_s*f\_s*l\_s*e\_s*s\_s*i\_s*a\_s*\%(c\_s*e\_s*a\_s*e\|l\_s*e\_s*s\)\|自\_s*棄\|火\_s*傷\|徐\_s*ら\|M\_s*y\_s*r\_s*i\_s*c\_s*a\_s*l\_s*e\_s*s\|天\_s*蚕\|倭\_s*絵\|日\_s*本\_s*武\_s*尊\|大\_s*和\|T\_s*\%(h\_s*e\_s*l\_s*i\_s*g\_s*o\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*o\_s*c\_s*h\_s*o\_s*d\_s*e\_s*n\_s*d\_s*r\_s*a\_s*c\_s*e\_s*a\_s*e\)\|香\_s*具\_s*師\|玄\_s*孫\|A\_s*r\_s*a\_s*c\_s*a\_s*l\_s*e\_s*s\|P\_s*\%(o\_s*a\_s*l\_s*e\_s*s\|l\_s*u\_s*m\_s*b\_s*a\_s*g\_s*i\_s*n\_s*a\_s*l\_s*e\_s*s\|r\_s*\%(o\_s*t\_s*e\_s*a\_s*l\_s*e\_s*s\|i\_s*n\_s*c\_s*i\_s*p\_s*e\_s*s\)\|a\_s*l\_s*m\_s*a\_s*l\_s*e\_s*s\)\|妥\_s*子\|寿\_s*[詞男]\|エ\_s*\%(ホ\_s*バ\|フ\_s*ゲ\_s*ニ\_s*ー\|レ\_s*ヴ\_s*ァ\_s*ン\|ニ\_s*セ\_s*イ\|ー\_s*ル\)\|ワ\_s*イ\)', + \ 'Z' : '\%([空損存揃園薗底足束續屬∈∋賊続粟族俗属僧慥噌梍賍臟臧贓憎像臓贈象増造添初曾反沿曽ぞ譱然苒繕禪薇千蠕∀髯禅善漸冉前全關関蝉膳錢銭絶勢噬説筮贅脆税是攻責ぜ狡詰桷寸喘鮨附◆髓蘂膸蕋惴蕊隧隋隨瑞髄随豆廚圖付津頭酢厨好図逗鶴刷ず塩嶋縞島嶌橲衄衂宍竺舳忸軸舌祖喰食直凝日實昵印闍者鮭邪蛇麝搦着惹尺鉐雀寂若弱尻稔仭糂贐潯儘仞盡刄臣侭恁進訊俥蕁迅刃靱荏甚靭燼櫁樒塵尽尋陣腎壬人敘恕耡汝莇杼茹敍蜍洳舒縟辱褥蓐溽所抒鋤徐序絮叙助釀淨疂絛繞壌諚孃瀞襄仍蟐拯疉讓聶驤生帖仗躡穰乘塲靜繩禳蕘壤遶星滌茸嬲疊如醤剩娘嬢錠静醸縄女尉饒丈成擾穣烝嫋丞場杖條条蒸貞状攘剰畳冗定浄乗情城上常譲濡得戍就嬬鷲竪讐讎懦愀咒聚隼詢徇笋凖盾楯筍篤蓴惇洵淳閏諄恂馴旬荀潤循醇巡遵順准殉純準襦誦需戌朮孰宿塾珠熟恤術述孺呪豎儒綬樹受授壽鞣狃澀揉廿拾縱中從糅从戎澁蹂神汁獸絨縦渋柔什充十獣従住銃重岻治除士染時怩至児冶璽只畤侍孳轜耳示次寿辭粫司二祀邇而慈峙爺以地塒珥迩痔死敷恃蒔磁瓷仁字尓焦膩柱似嗣子亊路史餌兒滋仕爾辞弍自茲持寺事知じ騒沢澤猿笊晒曝皿鮫山算参鏨慘竄懴殘塹巉懺嶄讒惨暫慚慙斬残実笹酒坂盛三崎嵜桜榴雜襍棹竿雑濟才西斉済劑戝剤材財罪在冴覚左咲挫藏裂醒坐蔵差冷座戯ざ→↑ЬьЪъ↓←Жжズゾ零〇〒ザZジゼзζЗΖZ]\|ッ\_s*\%(ソ\_s*゙\|セ\_s*゙\|ス\_s*゙\|シ\_s*゙\|サ\_s*゙\)\|ッ\_s*[ゾゼズジザ]\|っ\_s*[ぞぜずじざ]\|ソ\_s*゙\|簇\_s*生\|双\_s*紙\|草\_s*[履紙子]\|セ\_s*゙\|台\_s*詞\|0\_s*次\|発\_s*条\|撥\_s*条\|發\_s*条\|z\_s*e\_s*\%(t\_s*t\_s*a\|p\_s*t\_s*o\)\|世\_s*阿\_s*弥\|ス\_s*゙\|相\_s*撲\|木\_s*菟\|修\_s*法\|杜\_s*撰\|調\_s*所\|徒\_s*[罪刑]\|螟\_s*虫\|芋\_s*茎\|F\_s*i\_s*g\_s*u\_s*r\_s*e\|シ\_s*゙\|G\_s*\%(メ\_s*ン\|パ\_s*ン\)\|D\_s*y\|G\_s*\%(メ\_s*ン\|パ\_s*ン\)\|支\_s*度\|試\_s*合\|2\_s*乗\|2\_s*乗\|J\_s*\%(I\_s*S\_s*コ\_s*ー\_s*ド\|ポ\_s*ッ\_s*プ\|R\_s*東\_s*日\_s*本\)\|獅\_s*子\|甲\_s*乙\_s*丙\_s*丁\_s*戊\_s*己\_s*庚\_s*辛\_s*壬\_s*癸\|k\_s*\$\_s*_\_s*{\_s*e\_s*f\_s*f\_s*}\_s*\$\|爪\_s*哇\|射\_s*礼\|砂\_s*利\|謝\_s*花\|著\_s*語\|杓\_s*子\|深\_s*\%(秘\|大\_s*寺\)\|秦\_s*泉\_s*寺\|沈\_s*\%(香\|丁\_s*花\)\|晨\_s*朝\|濁\_s*世\|判\_s*官\|諍\_s*論\|長\_s*夜\|漏\_s*斗\|焼\_s*酎\|鐘\_s*石\|橈\_s*脚\_s*類\|承\_s*久\|朱\_s*里\|C\_s*a\_s*b\_s*o\_s*m\_s*b\_s*o\_s*i\_s*d\_s*e\_s*a\_s*e\|J\_s*\%(リ\_s*ー\_s*グ\|ポ\_s*ッ\_s*プ\|U\_s*N\_s*K\_s*O\)\|絢\_s*子\|頌\_s*偈\|数\_s*珠\|入\_s*[魂牢来洛院内水棺]\|霜\_s*月\|1\_s*\%(2\|6\_s*進\|0\_s*[進月]\|1\_s*月\|8\_s*禁\)\|師\_s*走\|極\_s*月\|紐\_s*帯\|1\_s*\%(0\|1\_s*月\|8\_s*禁\|2\_s*月\)\|サ\_s*゙\|搾\_s*菜\|蜊\_s*蛄\|粗\_s*目\|槧\_s*本\|散\_s*切\_s*り\|沙\_s*汰\|石\_s*榴\|柘\_s*榴\|細\_s*工\|亜\_s*鉛\|サ\_s*\%(モ\_s*ラ\|ン\_s*ポ\_s*ー\_s*ニ\_s*ャ\|ラ\_s*ゴ\_s*サ\)\|シ\_s*\%(タ\_s*ー\_s*ル\|オ\_s*\%(ン\|ニ\_s*\%(ス\_s*ト\|ズ\_s*ム\)\)\)\|チ\_s*\%(ク\_s*ル\_s*ス\|ア\_s*ノ\_s*ー\_s*ゼ\|ュ\_s*ー\_s*リ\_s*\%(ヒ\|ッ\_s*ヒ\)\|ャ\_s*ル\_s*ダ\_s*ッ\_s*シ\_s*ュ\|ゴ\_s*イ\_s*ネ\_s*ル\_s*ワ\_s*イ\_s*ゼ\_s*ン\)\|ツ\_s*\%(ァ\_s*\%(ラ\_s*ト\_s*ゥ\_s*ス\_s*ト\_s*ラ\|イ\_s*ト\)\|ェ\_s*\%(ナ\_s*ー\|ッ\_s*ペ\_s*リ\_s*ン\|ル\_s*マ\_s*ッ\_s*ト\)\|ィ\_s*\%(ク\_s*ル\_s*ス\|タ\_s*ー\|ー\_s*グ\_s*ラ\_s*ー\|ン\_s*\%(バ\_s*ロ\_s*ン\|マ\_s*ー\_s*マ\_s*ン\)\|ゴ\_s*イ\_s*ネ\_s*ル\)\)\)', + \ } +endfunction diff --git a/bundle/clever-f.vim/doc/clever_f.txt b/bundle/clever-f.vim/doc/clever_f.txt new file mode 100644 index 000000000..cd56412e7 --- /dev/null +++ b/bundle/clever-f.vim/doc/clever_f.txt @@ -0,0 +1,274 @@ +*clever-f.txt* Make |f|, |F|, |t| and |T| cleverer. + +Author : rhysd +Version : 1.5 + +CONTENTS *clever-f.vim-contents* + +Introduction |clever-f.vim-introduction| +Usage |clever-f.vim-usage| +Mappings |clever-f.vim-mappings| +Variables |clever-f.vim-variables| +Special Thanks |clever-f.vim-special-thanks| +Repository Page |clever-f.vim-repository-page| +License |clever-f.vim-license| + + +============================================================================== +INTRODUCTION *clever-f.vim-introduction* + +*clever-f.vim* or *clever-f* extends |f|, |F|, |t| and |T| key mappings for more +convenience. +Instead of |;|, |f| is available to repeat after you type |f|{char} or |F|{char}. |F| +after |f|{char} and |F|{char} is also available to undo a jump. |t|{char} and +|T|{char} are ditto. This extension makes a repeat easier and makes you forget +the existence of |;|. You can use |;| for other key mapping. +In addition, many handy features (target highlighting, smartcase matching, and +so on) are provided and you can customize behavior of the mappings. +Please check |clever-f.vim-variables|. + + +============================================================================== +USAGE *clever-f.vim-usage* + +I'll show an example of usage. _ is the place of cursor, -> is a move of +cursor, alphabets above -> is input by keyboard. + +> + input: fh f f e fo f + move : _---------->_------>_---------->_->_---------------->_->_ + input: F F + move : _<-----------------------------_<-_ + text : hoge huga hoo hugu ponyo +< + +> + input: f Fh b f Fo + move : _<----------_<------_<-_<-----------------------------_<-_ + input: F F F + move : _---------->_------>_----------->_ + text : hoge huga huyo hugu ponyo +< + +> + input: th t t e to t + move : _--------->_------>_---------->_-->_--------------->_->_ + input: T T + move : _<-----------------------------__ + text : hoge huga hoo hugu ponyo +< + +============================================================================== +MAPPINGS *clever-f.vim-mappings* + *g:clever_f_not_overwrites_standard_mappings* + +If you don't set |g:clever_f_not_overwrites_standard_mappings|, |clever-f| +replaces |f|, |F|, |t|, and |T| with |(clever-f-f)|, |(clever-f-F)|, +|(clever-f-t)| and |(clever-f-T)| as default mappings. + +(clever-f-f) *(clever-f-f)* +(clever-f-F) *(clever-f-F)* +(clever-f-t) *(clever-f-t)* +(clever-f-T) *(clever-f-T)* +(clever-f-reset) *(clever-f-reset)* +(clever-f-repeat-forward) *(clever-f-repeat-forward)* +(clever-f-repeat-back) *(clever-f-repeat-back)* + + +============================================================================== +VARIABLES *clever-f.vim-variables* + +g:clever_f_across_no_line *g:clever_f_across_no_line* + + If the value is equivalent to 1, |clever-f| mappings search target + character only in the cursor line. The default value is 0. + +g:clever_f_ignore_case *g:clever_f_ignore_case* + + If the value is equivalent to 1, it makes |clever-f| mappings' search case- + insensitive. For example, if you input "fa", it matches both "a" and "A". + The default value is 0. + +g:clever_f_smart_case *g:clever_f_smart_case* + + If the value is equivalent to 1, it makes |clever-f| mappings' search + smart case. For example, if you input "fa", it matches both "a" and "A", + but if you input "fA", it matches only "A". + The default value is 0. + +g:clever_f_use_migemo *g:clever_f_use_migemo* + + If the value is equivalent to 1, migemo support is enabled. This feature + is useful in Japanese environment. |clever-f| can match multibyte Japanese + character with a alphabet input. For example, "fa" can search "あ". + This feature doesn't require |cmigemo| because |clever-f| includes regex + patterns generated by cmigemo. + Please see http://0xcc.net/migemo/ if you want to know more about migemo. + The default value of this variable is 0. +> + input: fm f f + move : _---->_---->_----------------------------------------->_ + input: F F F + move : _<----_<----_<-----------------------------------------_ + text : ビム!ビム!ビムゥぅうわぁああん!!! あぁあっあっー!ビムゥ!! +< +g:clever_f_fix_key_direction *g:clever_f_fix_key_direction* + + If the value is equivalent to 1, the directions of keys are fixed. For + example, |F| is backward search and repeating of |F| after |F| makes the + same direction search. Below is the behavior. Please compare examples of + |clever-f.vim-usage|. + The default value is 0. +> + input: F Fh b F Fo + move : _<----------_<------_<-_<-----------------------------_<-_ + input: f f f + move : _---------->_------>_----------->_ + text : hoge huga huyo hugu ponyo +< +g:clever_f_show_prompt *g:clever_f_show_prompt* + + If the value is equivalent to 1, a prompt is shown when a character is + input to search. The prompt is disposed after the input. + The default value is 0. + +g:clever_f_chars_match_any_signs *g:clever_f_chars_match_any_signs* + + The value must be string. If this variable is not empty, characters in the + value matches any signs. For example, when the value is ";:", f; and f: + matches all signs. You can jump signs whose keys are hard to press. + The default value is "". +> + input: f; f f f f f f + move : _-->_--->_--------->_>_>_------------>_>_ + text : hoge.huga( autoloads: %w{ aaa bbb ccc } ) +< +g:clever_f_mark_cursor *g:clever_f_mark_cursor* + + If the value is equivalent to 1, current cursor position will be + highlighted when waiting for {char}. This way you won't lose your focus + from the place your cursor was. + The default value is 1. + +g:clever_f_mark_cursor_color *g:clever_f_mark_cursor_color* + + Only used when |g:clever_f_mark_cursor| is enabled. Change highlight group + used to mark cursor position. + The default value is "Cursor". + + Note: + |g:clever_f_mark_cursor_color| must be set before |clever-f| is loaded. + (e.g. in your |vimrc|) + +g:clever_f_hide_cursor_on_cmdline *g:clever_f_hide_cursor_on_cmdline* + + If the value is equivalent to 1, a cursor is hidden on inputting {char}. + This feature prevents cursor from moving to command line. + The default value is 1. + +g:clever_f_timeout_ms *g:clever_f_timeout_ms* + + If the value is greater than 0, |clever-f| check the interval of previous + search and next search. If the interval is longer than the value, + |clever-f| resets its state to make you input a character. The unit of the + value is millisecond. + The default value is 0 (it means no timeout). + +g:clever_f_mark_char *g:clever_f_mark_char* + + If the value is equivalent to 1, the characters in line which you input + in |f|, |F|, |t| and |T| are highlighted until the search ends. The + highlighted characters means candidates the cursor can move to by |f|, |F|, |t| + and |T|. Highlighting is enabled in normal and visual mode. + The default value is 1. + +g:clever_f_mark_char_color *g:clever_f_mark_char_color* + + If |g:clever_f_mark_char| is enabled, |clever-f| highlights the target + characters using the highlight group which |g:clever_f_mark_char_color| + specifies. If you want to change the highlight group |clever-f| uses, set + your favorite highlight group to this variable. + The default value is "CleverFDefaultLabel", which makes characters red and + bold. If you want to make an original label highlight, define your own + highlight group.(See |:highlight|) + + Note: + |g:clever_f_mark_char_color| must be set before |clever-f| is loaded. + (e.g. in your |vimrc|) + +g:clever_f_repeat_last_char_inputs *g:clever_f_repeat_last_char_inputs* + + This is a list of string value. If one of the elements are input, + |clever-f| use the previous input instead of the input. + The default value is ["\"]. It means that previous input is used when + you input . For example, when you previously input "fa" and then + input "f", "a" will be used instead of "". + If you want to add to the element, please write below in your vimrc. +> + let g:clever_f_repeat_last_char_inputs = ["\", "\"] +< +g:clever_f_mark_direct *g:clever_f_mark_direct* + + If the value is equivalent to 1, characters to which the cursor can be + moved directly are highlighted until you input a character. Highlighting + is enabled in normal and visual mode. + The default value is 0. + +g:clever_f_mark_direct_color *g:clever_f_mark_direct_color* + + If |g:clever_f_mark_direct| is enabled, |clever-f| highlights characters + using the highlight group which |g:clever_f_mark_direct_color| specifies. + If you want to change the highlight group |clever-f| uses, set + your favorite highlight group to this variable. + The default value is "CleverFDefaultLabel", which makes characters red and + bold. If you want to make an original label highlight, define your own + highlight group.(See |:highlight|) + + Note: + |g:clever_f_mark_direct_color| must be set before |clever-f| is loaded. + (e.g. in your |vimrc|) + + +============================================================================== +SPECIAL THANKS *clever-f.vim-special-thanks* + +|(clever-f-t)|, |(clever-f-T)|, repeatability with |.|, +availability of |[count]| are the works by @thinca. Thanks! +(http://d.hatena.ne.jp/thinca/20130227/1361891993) + + +============================================================================== +REPOSITORY PAGE *clever-f.vim-repository-page* + +The latest version of |clever-f| is available at +https://github.com/rhysd/clever-f.vim + + +============================================================================== +LICENSE *clever-f.vim-license* + +|clever-f.vim| is distributed under MIT license. + + Copyright (c) 2013 rhysd + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +============================================================================== +vim:tw=78:colorcolumn=78:ts=8:ft=help:norl:et:fen:fdl=0: diff --git a/bundle/clever-f.vim/plugin/clever-f.vim b/bundle/clever-f.vim/plugin/clever-f.vim new file mode 100644 index 000000000..f8a2858bf --- /dev/null +++ b/bundle/clever-f.vim/plugin/clever-f.vim @@ -0,0 +1,28 @@ +if exists('g:loaded_clever_f') && g:loaded_clever_f + finish +endif + +noremap (clever-f-f) clever_f#find_with('f') +noremap (clever-f-F) clever_f#find_with('F') +noremap (clever-f-t) clever_f#find_with('t') +noremap (clever-f-T) clever_f#find_with('T') +noremap (clever-f-reset) clever_f#reset() +noremap (clever-f-repeat-forward) clever_f#repeat(0) +noremap (clever-f-repeat-back) clever_f#repeat(1) + +if ! exists('g:clever_f_not_overwrites_standard_mappings') + nmap f (clever-f-f) + xmap f (clever-f-f) + omap f (clever-f-f) + nmap F (clever-f-F) + xmap F (clever-f-F) + omap F (clever-f-F) + nmap t (clever-f-t) + xmap t (clever-f-t) + omap t (clever-f-t) + nmap T (clever-f-T) + xmap T (clever-f-T) + omap T (clever-f-T) +endif + +let g:loaded_clever_f = 1 diff --git a/bundle/clever-f.vim/test/.coveragerc b/bundle/clever-f.vim/test/.coveragerc new file mode 100644 index 000000000..8cddf91cc --- /dev/null +++ b/bundle/clever-f.vim/test/.coveragerc @@ -0,0 +1,3 @@ +[run] +plugins = covimerage +data_file = .coverage_covimerage diff --git a/bundle/clever-f.vim/test/.themisrc b/bundle/clever-f.vim/test/.themisrc new file mode 100644 index 000000000..2365b0f34 --- /dev/null +++ b/bundle/clever-f.vim/test/.themisrc @@ -0,0 +1,15 @@ +let g:repo_root = fnamemodify(expand(''), ':h:h') + +call themis#option('exclude', g:repo_root . '/test/README.md') +call themis#option('exclude', g:repo_root . '/test/.coveragerc') +call themis#option('exclude', g:repo_root . '/test/Guardfile') +call themis#helper('command').with(themis#helper('assert')) + +if $PROFILE_LOG !=# '' + execute 'profile' 'start' $PROFILE_LOG + execute 'profile!' 'file' g:repo_root . '/autoload/clever_f.vim' + execute 'profile!' 'file' g:repo_root . '/autoload/clever_f/helper.vim' + execute 'profile!' 'file' g:repo_root . '/plugin/*' +endif + +call themis#option('runtimepath', expand(g:repo_root)) diff --git a/bundle/clever-f.vim/test/README.md b/bundle/clever-f.vim/test/README.md new file mode 100644 index 000000000..5955fe2ba --- /dev/null +++ b/bundle/clever-f.vim/test/README.md @@ -0,0 +1,38 @@ +## How to execute tests + +It requires [vim-themis](https://github.com/thinca/vim-themis). You need to install it in advance. + +For example, following clones it locally in clever-f.vim repository. + +```console +$ cd /path/to/clever-f.vim/test +$ git clone https://github.com/thinca/vim-themis +$ ./vim-themis/bin/themis . +``` + +## How to measure code coverage + +It requires [covimerage](https://github.com/Vimjas/covimerage). + +```console +$ pip install covimerage +$ cd /path/to/clever-f.vim/test + +# Run tests with profiling +$ PROFILE_LOG=profile.txt ./vim-themis/bin/themis . + +# Create a coverage file using profile results +$ covimerage write_coverage profile.txt + +# See the coverage results in console output +$ coverage report + +# See the coverage results in test/htmlcov/index.html +$ coverage html +``` + +## CI + +CI is run in both Linux and macOS using Travis CI: https://travis-ci.org/rhysd/clever-f.vim + +Coverage is tracked with codecov.io: https://codecov.io/gh/rhysd/clever-f.vim diff --git a/bundle/clever-f.vim/test/test.vimspec b/bundle/clever-f.vim/test/test.vimspec new file mode 100644 index 000000000..692370b88 --- /dev/null +++ b/bundle/clever-f.vim/test/test.vimspec @@ -0,0 +1,1297 @@ +set encoding=utf-8 +set termencoding=utf-8 +set fileencoding=utf-8 + +scriptencoding utf-8 + +function! AddLine(str) + put! =a:str +endfunction + +function! CursorPos() + return [line('.'), col('.'), getline('.')[col('.')-1]] +endfunction + +Describe default config + It should load plugin + Assert g:loaded_clever_f + End + + It should override original mappings by default + for m in ['f', 'F', 't', 'T'] + let mapped = mapcheck(m, 'nxo') + Assert True(stridx(mapped, 'clever-f') >= 0, m . ' -> ' . mapped) + endfor + End + + It should provide variables to customize behavior + call clever_f#reset() + Assert Equals(g:clever_f_across_no_line, 0) + Assert Equals(g:clever_f_ignore_case, 0) + Assert Equals(g:clever_f_use_migemo, 0) + Assert Equals(g:clever_f_fix_key_direction, 0) + Assert Equals(g:clever_f_show_prompt, 0) + Assert Equals(g:clever_f_smart_case, 0) + Assert Equals(g:clever_f_chars_match_any_signs, '') + Assert Equals(g:clever_f_mark_cursor, 1) + Assert Equals(g:clever_f_hide_cursor_on_cmdline, 1) + Assert Equals(g:clever_f_timeout_ms, 0) + Assert Equals(g:clever_f_mark_char, 1) + Assert Equals(g:clever_f_repeat_last_char_inputs, ["\"]) + Assert Equals(g:clever_f_clean_labels_eagerly, 1) + Assert Equals(g:clever_f_mark_direct, 0) + End +End + +Describe f, F, t and T mappings + Before + new + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + End + + After + close! + End + + It should provide improved forward search like builtin f + normal! 0 + let l = line('.') + Assert Equals(CursorPos(), [l,1,'p']) + + normal fh + Assert Equals(CursorPos(), [l,6,'h']) + + normal f + Assert Equals(CursorPos(), [l,11,'h']) + + normal! e + Assert Equals(CursorPos(), [l,14,'o']) + + normal fo + Assert Equals(CursorPos(), [l,17,'o']) + + normal f + Assert Equals(CursorPos(), [l,19,'o']) + End + + It should provide improved backward search like builtin F + normal! $ + let l = line('.') + Assert Equals(CursorPos(), [l,19,'o']) + + normal Fo + Assert Equals(CursorPos(), [l,17,'o']) + + normal f + Assert Equals(CursorPos(), [l,14,'o']) + + normal! h + + normal Fh + Assert Equals(CursorPos(), [l,11,'h']) + + normal f + Assert Equals(CursorPos(), [l,6,'h']) + End + + It should provide t mapping like builtin t + normal! 0 + let l = line('.') + Assert Equals(CursorPos(), [l,1,'p']) + + normal th + Assert Equals(CursorPos(), [l,5,' ']) + + normal t + Assert Equals(CursorPos(), [l,10,' ']) + + normal! e + Assert Equals(CursorPos(), [l,14,'o']) + + normal to + Assert Equals(CursorPos(), [l,16,'p']) + + normal t + Assert Equals(CursorPos(), [l,18,'y']) + + call AddLine('ab hbge huga') + normal! gg0 + normal tb + Assert Equals(CursorPos(), [l,1,'a']) + normal t + Assert Equals(CursorPos(), [l,4,'h']) + End + + It should provide T mapping like builtin T + normal! 0 + let l = line('.') + Assert Equals(CursorPos(), [l,1,'p']) + + normal th + Assert Equals(CursorPos(), [l,5,' ']) + + normal t + Assert Equals(CursorPos(), [l,10,' ']) + + normal! e + Assert Equals(CursorPos(), [l,14,'o']) + + normal to + Assert Equals(CursorPos(), [l,16,'p']) + + normal t + Assert Equals(CursorPos(), [l,18,'y']) + + call AddLine('ab hbge huga') + normal! gg0 + normal tb + Assert Equals(CursorPos(), [l,1,'a']) + normal t + Assert Equals(CursorPos(), [l,4,'h']) + End + + It should provide improved forward search like builtin f in visual mode + normal! 0 + let l = line('.') + Assert Equals(CursorPos(), [l,1,'p']) + + normal! v + normal fh + Assert Equals(CursorPos(), [l,6,'h']) + + normal f + Assert Equals(CursorPos(), [l,11,'h']) + + normal! e + Assert Equals(CursorPos(), [l,14,'o']) + + normal fo + Assert Equals(CursorPos(), [l,17,'o']) + + normal f + Assert Equals(CursorPos(), [l,19,'o']) + End + + It should provide improved backward search like builtin F + normal! $v + let l = line('.') + Assert Equals(CursorPos(), [l,19,'o']) + + normal Fo + Assert Equals(CursorPos(), [l,17,'o']) + + normal f + Assert Equals(CursorPos(), [l,14,'o']) + + normal! h + + normal Fh + Assert Equals(CursorPos(), [l,11,'h']) + + normal f + Assert Equals(CursorPos(), [l,6,'h']) + End + + It should provide t mapping like builtin t + normal! 0v + let l = line('.') + Assert Equals(CursorPos(), [l,1,'p']) + + normal th + Assert Equals(CursorPos(), [l,5,' ']) + + normal t + Assert Equals(CursorPos(), [l,10,' ']) + + normal! e + Assert Equals(CursorPos(), [l,14,'o']) + + normal to + Assert Equals(CursorPos(), [l,16,'p']) + + normal t + Assert Equals(CursorPos(), [l,18,'y']) + + call AddLine('ab hbge huga') + normal! gg0 + normal tb + Assert Equals(CursorPos(), [l,1,'a']) + normal t + Assert Equals(CursorPos(), [l,4,'h']) + End + + It should provide T mapping like builtin T + normal! $v + let l = line('.') + Assert Equals(CursorPos(), [l,19,'o']) + + normal To + Assert Equals(CursorPos(), [l,18,'y']) + + normal t + Assert Equals(CursorPos(), [l,15,' ']) + + normal! h + + normal Th + Assert Equals(CursorPos(), [l,12,'i']) + + normal t + Assert Equals(CursorPos(), [l,7,'u']) + + call AddLine('ab hbge huga') + normal! gg$ + normal Tg + Assert Equals(CursorPos(), [l,12,'a']) + normal t + Assert Equals(CursorPos(), [l,7,'e']) + End + + It should work with Vim 8.1.0648 + normal! 0 + let l = line('.') + Assert Equals(CursorPos(), [l,1,'p']) + + normal dth + Assert Equals(CursorPos(), [l,1,'h']) + End + + It should have different context in normal mode and visual mode + let l = line('.') + Assert Equals(CursorPos(), [l, 1, 'p']) + + normal fo + Assert Equals(CursorPos(), [l, 2, 'o']) + + normal vfh + Assert Equals(CursorPos(), [l, 6, 'h']) + + normal f + Assert Equals(CursorPos(), [l, 11, 'h']) + + normal! d + Assert Equals(getline('.'), "piyo poyo") + Assert Equals(CursorPos(), [l, 2, 'i']) + + normal! dfp + Assert Equals(getline('.'), "poyo") + Assert Equals(CursorPos(), [l, 2, 'o']) + End + + It should open folding automatically + let l = getline(1) + call setline(1, ['{{{', l, '}}}']) + setl foldmethod=marker + + " Move to closed folding + normal! ggjzM + + normal fh + Assert Equals(foldclosed('.'), -1) + Assert Equals(CursorPos(), [2,6,'h']) + End + + It does not reproduce #54 + normal! 0 + let l = line('.') + + normal fh + Assert Equals(CursorPos(), [l,6,'h']) + + " Back to the position after reset + normal! 0 + " XXX: Hack! While running test, InsertEnter is not fired + " automatically. To test the event, we need to cause it manually. + doautocmd CursorMoved + + normal! 5l + Assert Equals(CursorPos(), [l,6,'h']) + + normal fo + Assert Equals(CursorPos(), [l,14,'o']) + End +End + +Describe f and F mappings' contexts + Before + new + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + End + + After + close! + End + + It should be shared + normal! 0 + let l = line('.') + + normal fh + Assert Equals(CursorPos(), [l,6,'h']) + normal f + Assert Equals(CursorPos(), [l,11,'h']) + normal F + Assert Equals(CursorPos(), [l,6,'h']) + normal f + Assert Equals(CursorPos(), [l,11,'h']) + End +End + +Describe g:clever_f_across_no_line + Before + new + let g:clever_f_across_no_line = 1 + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + call AddLine('poge huga hiyo poyo') + End + + After + let g:clever_f_across_no_line = 0 + close! + End + + It should not move cursor to next line + normal! gg0 + let l = line('.') + + normal fhf + Assert Equals(CursorPos(), [l,11,'h']) + normal f + Assert Equals(CursorPos(), [l,11,'h']) + + normal! gg0 + normal tht + Assert Equals(CursorPos(), [l,10,' ']) + normal t + Assert Equals(CursorPos(), [l,10,' ']) + End + + It should not move cursor to previous line + normal! ggj$ + let l = line('.') + + normal Fpf + Assert Equals(CursorPos(), [l,1,'p']) + normal f + Assert Equals(CursorPos(), [l,1,'p']) + + normal! ggj$ + normal Tpt + Assert Equals(CursorPos(), [l,2,'o']) + normal t + Assert Equals(CursorPos(), [l,2,'o']) + End +End + +Describe a non-existent char + Before + new + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + End + + After + close! + End + + It should do nothing + normal! 0 + let origin = CursorPos() + + normal fd + Assert Equals(CursorPos(), origin) + normal f1 + Assert Equals(CursorPos(), origin) + normal f) + Assert Equals(CursorPos(), origin) + normal f^ + Assert Equals(CursorPos(), origin) + normal fm + Assert Equals(CursorPos(), origin) + End +End + +Context target is in other line + Before + new + call AddLine('foo bar baz') + call AddLine('poge huga hiyo poyo') + call clever_f#reset() + normal! gg + End + + After + close! + End + + It should move cursor forward across lines + normal! 0 + let l = line('.') + Assert Equals(col('.'), 1) + + normal fa + Assert Equals(CursorPos(), [l, 9, 'a']) + + normal f + Assert Equals(CursorPos(), [l+1, 6, 'a']) + + normal f + Assert Equals(CursorPos(), [l+1, 10, 'a']) + + normal F + Assert Equals(CursorPos(), [l+1, 6, 'a']) + + normal F + Assert Equals(CursorPos(), [l, 9, 'a']) + End + + It should move cursor backward across lines + normal! Gk$ + let l = line('.') + Assert Equals(col('.'), 11) + + normal Fa + Assert Equals(CursorPos(), [l, 10, 'a']) + + normal f + Assert Equals(CursorPos(), [l, 6, 'a']) + + normal f + Assert Equals(CursorPos(), [l-1, 9, 'a']) + + normal F + Assert Equals(CursorPos(), [l, 6, 'a']) + + normal F + Assert Equals(CursorPos(), [l, 10, 'a']) + End +End + +Context Multibyte characters + Before + new + call AddLine('ビムかわいいよzビムx') + call AddLine('foo bar baz') + call clever_f#reset() + normal! gg + End + + After + close! + End + + It should be supported + normal! gg0 + let l = line('.') + + normal fz + Assert Equals(CursorPos(), [l, 11, 'z']) + + normal f + Assert Equals(CursorPos(), [l+1, 22, 'z']) + + normal! h + normal fx + Assert Equals(CursorPos(), [l+1, 29, 'x']) + End +End + +describe g:clever_f_ignore_case + Before + new + let g:clever_f_ignore_case = 1 + call clever_f#reset() + call AddLine('poge Guga hiyo Go;yo;') + End + + After + let g:clever_f_ignore_case = 0 + close! + End + + It should make f case insensitive + normal! gg0 + let l = line('.') + + normal fg + Assert Equals(CursorPos(), [l, 3, 'g']) + + normal f + Assert Equals(CursorPos(), [l, 6, 'G']) + + normal f + Assert Equals(CursorPos(), [l, 8, 'g']) + + normal F + Assert Equals(CursorPos(), [l, 6, 'G']) + End + + It should make no effect on searching signs + normal! 0 + normal f; + Assert Equals(col('.'), 18) + normal f + Assert Equals(col('.'), 21) + let pos = getpos('.') + normal f + Assert Equals(pos, getpos('.')) + End +End + +Describe clever_f#compat#strchars + It should return different value from strlen() when multibyte character strings given + for str in ['あいうえお', 'aiueoあ', '123ABC45'] + Assert NotEquals(clever_f#compat#strchars(str), strlen(str)) + endfor + End + + It should return the same value as strlen() when given string contains no multibyte character + for str in ['aiueo', 'this_is_a_pen', "!#$%&'()'", ''] + Assert Equals(clever_f#compat#strchars(str), strlen(str)) + endfor + End +End + +Describe clever_f#find_with() + It should raise an error when invalid map is given + Throws /Error: Invalid mapping/ clever_f#find_with('x') + End +End + +Describe migemo support + Before + new + let g:clever_f_use_migemo = 1 + let g:clever_f_across_no_line = 1 + call AddLine('はー,ビムかわいいよビム') + call clever_f#reset() + normal! gg0 + End + + After + close! + let g:clever_f_across_no_line = 0 + let g:clever_f_use_migemo = 0 + End + + It should make f and F mapping match multibyte characters + normal fb + Assert Equals(col('.'), 10) + normal f + Assert Equals(col('.'), 31) + normal F + Assert Equals(col('.'), 10) + normal $ + normal Fb + Assert Equals(col('.'), 31) + normal f + Assert Equals(col('.'), 10) + normal F + Assert Equals(col('.'), 31) + End + + It should make t and T mapping match multibyte characters + normal tb + Assert Equals(col('.'), 7) + normal t + Assert Equals(col('.'), 28) + normal T + Assert Equals(col('.'), 13) + normal $ + normal Tb + Assert Equals(col('.'), 34) + normal t + Assert Equals(col('.'), 13) + normal T + Assert Equals(col('.'), 28) + normal t + Assert Equals(col('.'), 13) + End + + It doesn't degrade issue #24 + let save = g:clever_f_across_no_line + let g:clever_f_across_no_line = 0 + call AddLine(' sOS') + call AddLine(' sOS') + call AddLine(' sOS') + normal! gg^ + normal fS + Assert Equals(CursorPos(), [1, 17, 'S']) + normal f + Assert Equals(CursorPos(), [2, 17, 'S']) + normal f + Assert Equals(CursorPos(), [3, 17, 'S']) + let g:clever_f_across_no_line = save + End +End + +Describe g:clever_f_fix_key_direction + Before + new + let g:clever_f_fix_key_direction = 1 + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + normal! gg0 + End + + After + close! + let g:clever_f_fix_key_direction = 0 + End + + It should fix the direction of search for f and F + normal fofff + Assert Equals(col('.'), 19) + normal F + Assert Equals(col('.'), 17) + normal F + Assert Equals(col('.'), 14) + normal F + Assert Equals(col('.'), 2) + normal $ + normal Fo + Assert Equals(col('.'), 17) + normal F + Assert Equals(col('.'), 14) + normal F + Assert Equals(col('.'), 2) + End + + It should fix the direction of search for t and T + normal tottt + Assert Equals(col('.'), 18) + normal T + Assert Equals(col('.'), 15) + normal T + Assert Equals(col('.'), 3) + normal $ + normal To + Assert Equals(col('.'), 18) + normal T + Assert Equals(col('.'), 15) + normal T + Assert Equals(col('.'), 3) + End +End + +Describe Special characters + Before + new + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + normal! gg0 + End + + After + close! + End + + It should not break clever-f.vim + let pos = getpos('.') + execute 'normal' "f\" + execute 'normal' "f\" + execute 'normal' "f\" + Assert Equals(pos, getpos('.')) + End +End + +Describe + Before + new + call clever_f#reset() + call AddLine("poge huga \ poyo") + normal! gg0 + End + + After + close! + End + + It should reset the state on f + let pos = getpos('.') + execute 'normal' "f\" + Assert Equals(getpos('.'), pos) + + " Check that the state is reset + normal fe + Assert Equals(col('.'), 4) + End + + It should reset the state on T + normal! $ + let pos = getpos('.') + execute 'normal' "T\" + Assert Equals(getpos('.'), pos) + + " Check that the state is reset + normal Th + Assert Equals(col('.'), 7) + End + + Context with g:clever_f_mark_direct + Before + let g:clever_f_mark_direct = 1 + highlight link CleverFDirect CleverFDefaultLabel + End + + After + let g:clever_f_mark_direct = 0 + End + + It should remove target highlights + normal! gg0 + execute 'normal' "f\" + Assert Equals(len(filter(getmatches(), 'v:val.group==#"CleverFDirect"')), 0) + End + End +End + +Describe g:clever_f_smart_case + Before + new + call clever_f#reset() + call AddLine('poHe huga Hiyo hoyo: poyo();') + normal! gg0 + let g:clever_f_smart_case = 1 + End + + After + close! + let g:clever_f_smart_case = 0 + End + + It should make f smart case + normal fh + Assert Equals(col('.'), 3) + normal f + Assert Equals(col('.'), 6) + normal f + Assert Equals(col('.'), 11) + normal f + Assert Equals(col('.'), 16) + normal F + Assert Equals(col('.'), 11) + + normal 0 + normal fH + Assert Equals(col('.'), 3) + normal f + Assert Equals(col('.'), 11) + normal f + Assert Equals(col('.'), 11) + normal F + Assert Equals(col('.'), 3) + End + + It should make t smart case + normal! $ + normal Th + Assert Equals(col('.'), 17) + normal t + Assert Equals(col('.'), 12) + normal t + Assert Equals(col('.'), 7) + normal t + Assert Equals(col('.'), 4) + normal T + Assert Equals(col('.'), 5) + + normal! $ + normal TH + Assert Equals(col('.'), 12) + normal t + Assert Equals(col('.'), 4) + normal T + Assert Equals(col('.'), 10) + End + + It should not affect searching signs + normal! 0 + normal f; + Assert Equals(col('.'), 28) + normal! 0 + let pos = getpos('.') + normal f + Assert Equals(pos, getpos('.')) + End +End + +Describe g:clever_f_chars_match_any_signs + Before + new + call AddLine(' !"#$%&''()=~|\-^\@`[]{};:+*<>,.?_/') + let g:clever_f_chars_match_any_signs = ';' + normal! gg0 + End + + After + close! + let g:clever_f_chars_match_any_signs = '' + End + + It should specify characters which match to any signs + normal f; + Assert Equals(col('.'), 2) + for i in range(3, 34) + normal f + Assert Equals(col('.'), i) + endfor + + let pos = getpos('.') + normal f + Assert Equals(pos, getpos('.')) + + for i in reverse(range(2, 33)) + normal F + Assert Equals(col('.'), i) + endfor + + let pos = getpos('.') + normal F + Assert Equals(pos, getpos('.')) + End +End + +Describe Cursor mark on user input + Before + new + let g:clever_f_mark_cursor = 1 + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + End + + After + close! + End + + It 'ensures to remove highlight of cursor properly' + normal fh + Assert Equals(filter(getmatches(), 'v:val.group=="CleverFCursor"'), []) + normal fq + Assert Equals(filter(getmatches(), 'v:val.group=="CleverFCursor"'), []) + End +End + +Describe Hiding cursor on command line + Before + new + let g:clever_f_mark_cursor = 1 + let g:clever_f_hide_cursor_on_cmdline = 1 + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + End + + After + close! + End + + it should ensure to restore highlight properly + let guicursor = &guicursor + let t_ve = &t_ve + normal fh + Assert Equals(guicursor, &guicursor) + Assert Equals(t_ve, &t_ve) + normal fq + Assert Equals(guicursor, &guicursor) + Assert Equals(t_ve, &t_ve) + End +End + +Describe g:clever_f_timeout_ms + Before + new + let g:clever_f_timeout_ms = 100 + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + normal! gg0 + End + + After + close! + let g:clever_f_timeout_ms = 0 + End + + It should reset the state if timed out + normal fhf + Assert Equals(col('.'), 11) + sleep 150m + normal fo + Assert Equals(col('.'), 14) + normal f + Assert Equals(col('.'), 17) + sleep 150m + normal Fo + Assert Equals(col('.'), 14) + End +End + +Describe g:clever_f_mark_char + Before + new + let g:clever_f_mark_char = 1 + call clever_f#reset() + call AddLine('poge huga hiyo poyo') + let old_across_no_line = g:clever_f_across_no_line + let g:clever_f_across_no_line = 0 + End + + After + close! + let g:clever_f_across_no_line = old_across_no_line + End + + It should highlight the target characters automatically + normal! gg0 + normal fh + Assert NotEquals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + normal f + Assert NotEquals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + End + + It should update the highlight if the cursor moves to another line + call AddLine('oh huh') + normal! gg0 + let l = line('.') + normal fhff + Assert NotEquals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + Assert NotEquals(stridx(getmatches()[0].pattern, l), -1) + Assert Equals(len(getmatches()), 1) + normal f + Assert NotEquals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + Assert NotEquals(stridx(getmatches()[0].pattern, l+1), -1) + Assert Equals(len(getmatches()), 1) + normal f + Assert NotEquals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + Assert NotEquals(stridx(getmatches()[0].pattern, l+1), -1) + Assert Equals(len(getmatches()), 1) + End + + It should remove highlights when moving cursor to another place + call AddLine('oh huh') + call AddLine('oh huh') + normal! gg0 + normal fhff + normal! j + " XXX: Hack! While running test, CursorMoved is not fired + " automatically. To test the event, we need to cause it manually. + doautocmd CursorMoved + Assert Equals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + End + + It should remove highlights when entering insert mode + call AddLine('oh huh') + call AddLine('oh huh') + normal! gg0 + normal fhff + " XXX: Hack! While running test, InsertEnter is not fired + " automatically. To test the event, we need to cause it manually. + doautocmd InsertEnter + Assert Equals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + End + + Describe clever_f#reset() + It should remove target highlights + call AddLine('oh huh') + normal! gg0 + let l = line('.') + normal fhff + Assert NotEquals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + call clever_f#reset() + Assert Equals(filter(getmatches(), 'v:val.group==#"CleverFChar"'), []) + End + End +End + +Describe g:clever_f_repeat_last_char_inputs + Before + new + call clever_f#reset() + call AddLine('hoge huga hiyo hoyo') + normal! gg0 + End + + After + close! + End + + It should repeat previous input again + normal fhl + Assert Equals(col('.'), 7) + execute 'normal' "f\" + Assert Equals(col('.'), 11) + normal lfyl + Assert Equals(col('.'), 14) + execute 'normal' "f\" + Assert Equals(col('.'), 18) + normal! $ + execute 'normal' "F\" + Assert Equals(col('.'), 18) + End + + It should do nothing when the specified characters are input at first + call clever_f#_reset_all() + let p = getpos('.') + execute 'normal' "f\" + Assert Equals(getpos('.'), p) + execute 'normal' "F\" + Assert Equals(getpos('.'), p) + execute 'normal' "t\" + Assert Equals(getpos('.'), p) + execute 'normal' "T\" + Assert Equals(getpos('.'), p) + End +End + +Describe Backslash + Before + new + call clever_f#reset() + call AddLine('poge\huga\hiyo\poyo') + normal! gg0 + End + + After + close! + End + + It should not cause any search errors (#35) + normal f\ + Assert Equals(col('.'), 5) + normal! $ + normal F\ + Assert Equals(col('.'), 15) + normal! gg0 + normal t\ + Assert Equals(col('.'), 4) + normal! $ + normal T\ + Assert Equals(col('.'), 16) + End +End + +Describe selection=exclusive + Before + new + call AddLine('poge huga hiyo poyo') + let s:selection = &selection + set selection=exclusive + call clever_f#reset() + normal! gg0 + End + + After + close! + let &selection = s:selection + End + + It should not change `f` behavior when not in visual mode + normal fh + Assert Equals(col('.'), 6) + normal f + Assert Equals(col('.'), 11) + + normal! 0 + + normal th + Assert Equals(col('.'), 5) + normal t + Assert Equals(col('.'), 10) + End + + It should change selection of `f` or `t` in visual mode + normal vfh + Assert Equals(col('.'), 7) + normal f + Assert Equals(col('.'), 12) + + execute 'normal!' "\0" + normal vth + Assert Equals(col('.'), 6) + normal t + Assert Equals(col('.'), 11) + End + + It should not change `T` and `F` behavior + normal! $ + normal vFh + Assert Equals(col('.'), 11) + normal f + Assert Equals(col('.'), 6) + + execute 'normal!' "\$" + normal vTh + Assert Equals(col('.'), 12) + normal t + Assert Equals(col('.'), 7) + End +End + +Describe clever_f#_mark_direct() + function! GetHighlightedPositions() + let cols = sort(map(getmatches(), 'v:val.pos1[1]'), 'n') + let chars = [] + for c in range(1, 19) + if len(cols) > 0 && cols[0] == c + let ch = '_' + call remove(cols, 0) + else + let ch = ' ' + endif + call add(chars, ch) + endfor + return join(chars, '') + endfunction + + Before + new + call clever_f#reset() + highlight link CleverFDirect CleverFDefaultLabel + call AddLine('ビムかわいいよzビムx') + call AddLine('pOge huga Hiyo pOyo') + let old_across_no_line = g:clever_f_across_no_line + let g:clever_f_across_no_line = 0 + End + + After + close! + let g:clever_f_mark_direct = 0 + let g:clever_f_across_no_line = old_across_no_line + End + + It should highlight characters to which the cursor can be moved directly + normal! gg0 + " #: cursor position, _: highlighted char + " + " #Oge huga Hiyo pOyo + let s = ' ______ _ ____ _ ' + call clever_f#_mark_direct(1, 1) + Assert Equals(GetHighlightedPositions(), s) + End + + It should highlight backward characters + normal! gg$ + " pOge huga Hiyo pOy# + let s = ' _ ____ __ _____ ' + call clever_f#_mark_direct(0, 1) + Assert Equals(GetHighlightedPositions(), s) + End + + It should highlight characters to which the cursor can be moved by one hop + normal! gg0 + " #Oge huga Hiyo pOyo + let s = ' _ _ ___' + call clever_f#_mark_direct(1, 2) + Assert Equals(GetHighlightedPositions(), s) + End + + It should not highlight multibyte characters + normal! 2gg0 + " #ムかわいいよzビムx + " _ _ + call clever_f#_mark_direct(1, 1) + let cols = [22, 29] + Assert Equals(sort(map(getmatches(), 'v:val.pos1[1]'), 'n'), cols) + End + + Context with g:clever_f_smart_case + Before + let g:clever_f_smart_case = 1 + End + + After + let g:clever_f_smart_case = 0 + End + + It should highlight characters to which the cursor can be moved directly + normal! gg0 + " #Oge huga Hiyo pOyo + let s = ' ______ _ ___ _ ' + call clever_f#_mark_direct(1, 1) + Assert Equals(GetHighlightedPositions(), s) + End + + It should highlight backward characters + normal! gg$ + " pOge huga Hiyo pOy# + let s = ' _ ___ __ ____ ' + call clever_f#_mark_direct(0, 1) + Assert Equals(GetHighlightedPositions(), s) + End + + It should highlight characters to which the cursor can be moved by one hop + normal! gg0 + " #Oge huga Hiyo pOyo + let s = ' _ __ _ __ ' + call clever_f#_mark_direct(1, 2) + Assert Equals(GetHighlightedPositions(), s) + End + End + + Context with g:clever_f_ignore_case + Before + let g:clever_f_ignore_case = 1 + End + + After + let g:clever_f_ignore_case = 0 + End + + It should highlight characters to which the cursor can be moved directly + normal! gg0 + " #Oge huga Hiyo pOyo + let s = ' ______ _ __ _ ' + call clever_f#_mark_direct(1, 1) + Assert Equals(GetHighlightedPositions(), s) + End + + It should highlight backward characters + normal! gg$ + " pOge huga Hiyo pOy# + let s = ' _ ___ __ ____ ' + call clever_f#_mark_direct(0, 1) + Assert Equals(GetHighlightedPositions(), s) + End + + It should highlight characters to which the cursor can be moved by one hop + normal! gg0 + " #Oge huga Hiyo pOyo + let s = ' _ __ _ _ ' + call clever_f#_mark_direct(1, 2) + Assert Equals(GetHighlightedPositions(), s) + End + End +End + +Describe g:clever_f_mark_direct + Before + new + let g:clever_f_mark_direct = 1 + call clever_f#reset() + highlight link CleverFDirect CleverFDefaultLabel + call AddLine('pOge huga Hiyo poyo') + let old_across_no_line = g:clever_f_across_no_line + let g:clever_f_across_no_line = 0 + End + + After + close! + let g:clever_f_mark_direct = 0 + let g:clever_f_across_no_line = old_across_no_line + End + + It should remove target highlights + normal! gg0 + normal fh + Assert Equals(len(filter(getmatches(), 'v:val.group ==# "CleverFDirect"')), 0) + End + + It should finish with no error + normal! gg$ + normal fp + Assert Equals(len(filter(getmatches(), 'v:val.group ==# "CleverFDirect"')), 0) + End +End +" vim:foldmethod=marker diff --git a/bundle/context_filetype.vim/LICENSE b/bundle/context_filetype.vim/LICENSE new file mode 100644 index 000000000..3a4b98ed8 --- /dev/null +++ b/bundle/context_filetype.vim/LICENSE @@ -0,0 +1,21 @@ +License: MIT license +AUTHOR: Shougo Matsushita + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bundle/context_filetype.vim/autoload/context_filetype.vim b/bundle/context_filetype.vim/autoload/context_filetype.vim new file mode 100644 index 000000000..3abbd3f3d --- /dev/null +++ b/bundle/context_filetype.vim/autoload/context_filetype.vim @@ -0,0 +1,679 @@ +"============================================================================= +" FILE: context_filetype.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +scriptencoding utf-8 + +let g:context_filetype#filetypes = get(g:, + \ 'context_filetype#filetypes', {}) + +let g:context_filetype#ignore_composite_filetypes = get(g:, + \ 'context_filetype#ignore_composite_filetypes', {}) + +let g:context_filetype#same_filetypes = get(g:, + \ 'context_filetype#same_filetypes', {}) + +let g:context_filetype#search_offset = get(g:, + \ 'context_filetype#search_offset', 200) + +function! context_filetype#version() abort + return str2nr(printf('%02d%02d', 1, 0)) +endfunction + + +function! context_filetype#get(...) abort + let base_filetype = get(a:, 1, &filetype) + let filetypes = context_filetype#filetypes() + let context = s:get_nest(base_filetype, filetypes) + if context.range == s:null_range && !has_key(context, 'synname') + let context.filetype = base_filetype + endif + return context +endfunction + + +function! context_filetype#get_filetype(...) abort + let base_filetype = get(a:, 1, &filetype) + return context_filetype#get(base_filetype).filetype +endfunction + +function! context_filetype#get_filetypes(...) abort + let filetype = call('context_filetype#get_filetype', a:000) + + let filetypes = [filetype] + if filetype =~ '\.' + if has_key(g:context_filetype#ignore_composite_filetypes, filetype) + let filetypes = + \ [g:context_filetype#ignore_composite_filetypes[filetype]] + else + " Set composite filetype. + let filetypes += split(filetype, '\.') + endif + endif + + for ft in copy(filetypes) + let filetypes += s:get_same_filetypes(ft) + endfor + + if len(filetypes) > 1 + let filetypes = s:uniq(filetypes) + endif + + return filetypes +endfunction + +function! context_filetype#get_same_filetypes(...) abort + let filetype = call('context_filetype#get_filetype', a:000) + + let filetypes = [] + for ft in context_filetype#get_filetypes(filetype) + let filetypes += s:get_same_filetypes(ft) + endfor + + if len(filetypes) > 1 + let filetypes = s:uniq(filetypes) + endif + + return filetypes +endfunction + + +function! context_filetype#get_range(...) abort + let base_filetype = get(a:, 1, &filetype) + return context_filetype#get(base_filetype).range +endfunction + + +function! context_filetype#default_filetypes() abort + return deepcopy(s:default_filetypes) +endfunction + +function! context_filetype#filetypes() abort + if exists('b:context_filetype_filetypes') + return deepcopy(b:context_filetype_filetypes) + endif + return extend(deepcopy(s:default_filetypes), deepcopy(g:context_filetype#filetypes)) +endfunction + + +" s:default_filetypes +let s:default_filetypes = { + \ 'c': [ + \ { + \ 'start': '_*asm_*\s\+\h\w*', + \ 'end': '$', 'filetype': 'masm', + \ }, + \ { + \ 'start': '_*asm_*\s*\%(\n\s*\)\?{', + \ 'end': '}', 'filetype': 'masm', + \ }, + \ { + \ 'start': '_*asm_*\s*\%(_*volatile_*\s*\)\?(', + \ 'end': ');', 'filetype': 'gas', + \ }, + \ ], + \ 'cpp': [ + \ { + \ 'start': '_*asm_*\s\+\h\w*', + \ 'end': '$', 'filetype': 'masm', + \ }, + \ { + \ 'start': '_*asm_*\s*\%(\n\s*\)\?{', + \ 'end': '}', 'filetype': 'masm', + \ }, + \ { + \ 'start': '_*asm_*\s*\%(_*volatile_*\s*\)\?(', + \ 'end': ');', 'filetype': 'gas', + \ }, + \ ], + \ 'd': [ + \ { + \ 'start': 'asm\s*\%(\n\s*\)\?{', + \ 'end': '}', 'filetype': 'masm', + \ }, + \ ], + \ 'eruby': [ + \ { + \ 'start': '<%[=#]\?', + \ 'end': '%>', 'filetype': 'ruby', + \ }, + \ ], + \ 'help': [ + \ { + \ 'start': '^>\|\s>$', + \ 'end': '^<\|^\S\|^$', 'filetype': 'vim', + \ }, + \ ], + \ 'html': [ + \ { + \ 'start': + \ ']*\)\? type="text/javascript"\%( [^>]*\)\?>', + \ 'end': '', 'filetype': 'javascript', + \ }, + \ { + \ 'start': + \ ']*\)\? type="text/coffeescript"\%( [^>]*\)\?>', + \ 'end': '', 'filetype': 'coffee', + \ }, + \ { + \ 'start': + \ ']*\)\?>', + \ 'end': '', 'filetype': 'javascript', + \ }, + \ { + \ 'start': + \ ']*\)\?>', + \ 'end': '', 'filetype': 'css', + \ }, + \ { + \ 'start': + \ '<[^>]\+ style=\([''"]\)', + \ 'end': '\1', 'filetype': 'css', + \ }, + \ ], + \ 'vue': [ + \ { + \ 'start': + \ ']*\)\? \%(lang="\%(\(\h\w*\)\)"\)\%( [^>]*\)\?>', + \ 'end': '', 'filetype': '\1', + \ }, + \ { + \ 'start': + \ ']*\)\?>', + \ 'end': '', 'filetype': 'html', + \ }, + \ { + \ 'start': + \ ']*\)\? \%(ts\|lang="\%(ts\|typescript\)"\)\%( [^>]*\)\?>', + \ 'end': '', 'filetype': 'typescript', + \ }, + \ { + \ 'start': + \ ']*\)\? \%(lang="\%(\(\h\w*\)\)"\)\%( [^>]*\)\?>', + \ 'end': '', 'filetype': '\1', + \ }, + \ { + \ 'start': + \ ']*\)\?>', + \ 'end': '', 'filetype': 'javascript', + \ }, + \ { + \ 'start': + \ ']*\)\? \%(lang="\%(\(\h\w*\)\)"\)\%( [^>]*\)\?>', + \ 'end': '', 'filetype': '\1', + \ }, + \ { + \ 'start': + \ ']*\)\?>', + \ 'end': '', 'filetype': 'css', + \ }, + \ { + \ 'start': + \ '<\(\h\w*\)>', + \ 'end': '', 'filetype': 'vue-\1', + \ }, + \ { + \ 'start': + \ '<\(\h\w*\) \%(lang="\%(\(\h\w*\)\)"\)\%( [^>]*\)\?>', + \ 'end': '', 'filetype': '\2', + \ }, + \ ], + \ 'int-nyaos': [ + \ { + \ 'start': '\]*\)\? type="text/javascript"\%( [^>]*\)\?>', + \ 'end': '', 'filetype': 'javascript', + \ }, + \ { + \ 'start': + \ ']*\)\? type="text/coffeescript"\%( [^>]*\)\?>', + \ 'end': '', 'filetype': 'coffee', + \ }, + \ { + \ 'start': ']*\)\? type="text/css"\%( [^>]*\)\?>', + \ 'end': '', 'filetype': 'css', + \ }, + \ ], + \ 'markdown': [ + \ { + \ 'start' : '^\s*```\s*\(\h\w*\)', + \ 'end' : '^\s*```$', 'filetype' : '\1', + \ }, + \ ], + \ 'haml': [ + \ { + \ 'start' : '^\s*-', + \ 'end' : '$', 'filetype' : 'ruby', + \ }, + \ { + \ 'start' : '^\s*\w*=', + \ 'end' : '$', 'filetype' : 'ruby', + \ }, + \ { + \ 'start' : '^:javascript$', + \ 'end' : '^\S', 'filetype' : 'javascript', + \ }, + \ { + \ 'start' : '^:css$', + \ 'end' : '^\S', 'filetype' : 'css', + \ }, + \ ], + \ 'jade': [ + \ { + \ 'start' : '^\(\s*\)script\.\s*$', + \ 'end' : '^\%(\1\s\|\s*$\)\@!', + \ 'filetype' : 'javascript', + \ }, + \ { + \ 'start' : '^\(\s*\):coffeescript\s*$', + \ 'end' : '^\%(\1\s\|\s*$\)\@!', + \ 'filetype' : 'coffee', + \ }, + \ { + \ 'start' : '^\(\s*\):\(\h\w*\)\s*$', + \ 'end' : '^\%(\1\s\|\s*$\)\@!', + \ 'filetype' : '\2', + \ }, + \ ], + \ 'toml': [ + \ { + \ 'start': '\ line('$')) ? line('$') : stopline_forward +endfunction + + +function! s:stopline_back() abort + let stopline_back = line('.') - g:context_filetype#search_offset + return (stopline_back <= 1) ? 1 : stopline_back +endfunction + + +" a <= b +function! s:pos_less_equal(a, b) abort + return a:a[0] == a:b[0] ? a:a[1] <= a:b[1] : a:a[0] <= a:b[0] +endfunction + + +function! s:is_in(start, end, pos) abort + " start <= pos && pos <= end + return s:pos_less_equal(a:start, a:pos) && s:pos_less_equal(a:pos, a:end) +endfunction + + +function! s:file_range() abort + return [[1, 1], [line('$'), len(getline('$'))+1]] +endfunction + +function! s:replace_submatch(pattern, match_list) abort + return substitute(a:pattern, '\\\@>\(\d\)', + \ {m -> a:match_list[m[1]]}, 'g') +endfunction + +function! s:replace_submatch_pattern(pattern, match_list) abort + let pattern = '' + let backref_end_prev = 0 + let backref_start = match(a:pattern, '\\\@>\d') + let backref_end = backref_start + 2 + let magic = '\m' + let magic_start = match(a:pattern, '\\\@>[vmMV]') + while 0 <= backref_start + while 0 <= magic_start && magic_start <= backref_end + let magic = a:pattern[magic_start : magic_start + 1] + let magic_start = match(a:pattern, '\\\@>[vmMV]', magic_start + 2) + if magic_start == backref_end + let backref_end += 2 + endif + endwhile + if backref_start != 0 + let pattern .= a:pattern[backref_end_prev : backref_start - 1] + endif + let pattern .= '\V' + \ . escape(a:match_list[a:pattern[backref_start + 1]], '\') + \ . magic + let backref_end_prev = backref_end + let backref_start = match(a:pattern, '\\\@>\d', backref_end_prev) + let backref_end = backref_start + 2 + endwhile + return pattern . a:pattern[backref_end_prev : -1] +endfunction + + +let s:null_pos = [0, 0] +let s:null_range = [[0, 0], [0, 0]] + + +function! s:search_range(start_pattern, end_pattern) abort + let stopline_forward = s:stopline_forward() + let stopline_back = s:stopline_back() + + let cur_text = + \ (mode() ==# 'i' ? (col('.')-1) : col('.')) >= len(getline('.')) ? + \ getline('.') : + \ matchstr(getline('.'), + \ '^.*\%' . (mode() ==# 'i' ? col('.') : col('.') - 1) + \ . 'c' . (mode() ==# 'i' ? '' : '.')) + let curline_pattern = a:start_pattern . '\ze.\{-}$' + if cur_text =~# curline_pattern + let start = [line('.'), matchend(cur_text, curline_pattern)] + else + let start = searchpos(a:start_pattern, 'bnceW', stopline_back) + endif + if start == s:null_pos + return s:null_range + endif + let start[1] += 1 + + let end_pattern = a:end_pattern + if end_pattern =~# '\\\@>\d' + let lines = getline(start[0], line('.')) + let match_list = matchlist(join(lines, "\n"), a:start_pattern) + let end_pattern = s:replace_submatch_pattern(end_pattern, match_list) + endif + + let end_forward = searchpos(end_pattern, 'ncW', stopline_forward) + if end_forward == s:null_pos + let end_forward = [line('$'), len(getline('$'))+1] + endi + + let end_backward = searchpos(end_pattern, 'bnW', stopline_back) + if s:pos_less_equal(start, end_backward) + return s:null_range + endif + let end_forward[1] -= 1 + + if mode() !=# 'i' && start[1] >= strdisplaywidth(getline(start[0])) + let start[0] += 1 + let start[1] = 1 + endif + + if end_forward[1] <= 1 + let end_forward[0] -= 1 + let len = len(getline(end_forward[0])) + let len = len ? len : 1 + let end_forward[1] = len + endif + + return [start, end_forward] +endfunction + + +let s:null_context = { +\ 'filetype' : '', +\ 'range' : s:null_range, +\} + + +function! s:get_context(filetype, context_filetypes, search_range) abort + let base_filetype = empty(a:filetype) ? 'nothing' : a:filetype + let context_filetypes = get(a:context_filetypes, base_filetype, []) + if empty(context_filetypes) + return s:null_context + endif + + let pos = [line('.'), col('.')] + + for context in context_filetypes + if has_key(context, 'synname_pattern') + for id in synstack(line('.'), col('.')) + let synname = synIDattr(id, 'name') + if synname =~# context.synname_pattern + return {'filetype' : context.filetype, 'range': s:null_range, 'synname': synname} + endif + endfor + continue + endif + + let range = s:search_range(context.start, context.end) + + " Set cursor position + let start = range[0] + let end = [range[1][0], (mode() ==# 'i') ? range[1][1]+1 : range[1][1]] + + " start <= pos && pos <= end + " search_range[0] <= start && start <= search_range[1] + " search_range[0] <= end && end <= search_range[1] + if range != s:null_range + \ && s:is_in(start, end, pos) + \ && s:is_in(a:search_range[0], a:search_range[1], range[0]) + \ && s:is_in(a:search_range[0], a:search_range[1], range[1]) + let context_filetype = context.filetype + if context.filetype =~# '\\\@>\d' + let stopline_back = s:stopline_back() + let lines = getline( + \ searchpos(context.start, 'nbW', stopline_back)[0], + \ line('.') + \ ) + let match_list = matchlist(join(lines, "\n"), context.start) + let context_filetype = s:replace_submatch(context.filetype, match_list) + endif + return {'filetype' : context_filetype, 'range' : range} + endif + endfor + + return s:null_context +endfunction + + +function! s:get_nest_impl(filetype, context_filetypes, prev_context) abort + let context = s:get_context(a:filetype, + \ a:context_filetypes, a:prev_context.range) + if context.range != s:null_range && context.filetype !=# a:filetype + return s:get_nest_impl(context.filetype, a:context_filetypes, context) + else + return a:prev_context + endif +endfunction + + +function! s:get_nest(filetype, context_filetypes) abort + let context = s:get_context(a:filetype, a:context_filetypes, s:file_range()) + return s:get_nest_impl(context.filetype, a:context_filetypes, context) +endfunction + +function! s:uniq(list) abort + let dict = {} + for item in a:list + if item != '' && !has_key(dict, item) + let dict[item] = item + endif + endfor + + return values(dict) +endfunction diff --git a/bundle/context_filetype.vim/doc/context_filetype.jax b/bundle/context_filetype.vim/doc/context_filetype.jax new file mode 100644 index 000000000..875204004 --- /dev/null +++ b/bundle/context_filetype.vim/doc/context_filetype.jax @@ -0,0 +1,232 @@ +*context_filetype.txt* Vim script の context filetype ライブラリ + +Version: 1.0 +Author : Shougo +License: MIT license + +CONTENTS *context_filetype-contents* + +概要 |context_filetype-introduction| +インターフェース |context_filetype-interface| + 変数 |context_filetype-variables| + 関数 |context_filetype-functions| +変更履歴 |context_filetype-changelog| + +============================================================================== +概要 *context_filetype-introduction* + +*context_filetype* はカーソル位置を基準とした、文脈から特定の filetype を判定す +る為の Vim script ライブラリです。 +コード中に他の言語を埋め込むような言語で利用する事が出来ます。 + +また、このプラグインは他のプラグインから使用する事を想定して作られています。 + + +============================================================================== +サポート *context_filetype-support* + +各 filetype で対応しているコンテキストの一覧です。 + +- "c" + masm + gas + +- "cpp" + masm + gas + +- "d" + masm + +- "eruby" + ruby + +- "help" + vim + +- "html" + javascript + coffee + css + +- "int-nyaos" + lua + +- "lua" + vim + +- "nyaos" + lua + +- "perl16" + pir + +- "python" + vim + +- "vim" + python + ruby + lua + +- "vimshell" + vim + +- "xhtml" + javascript + coffee + css + +- "markdown" + +- "haml" + ruby + javascript + css + + +============================================================================== +インターフェース *context_filetype-interface* + +------------------------------------------------------------------------------ +変数 *context_filetype-variables* + +g:context_filetype#filetypes *g:context_filetype#filetypes* + 各 filetype を判定する為の辞書です。 + 各 filetype に対してリストで設定する事ができます。 + + "start" : コンテキストの開始パターン + "end" : コンテキストの終了パターン + "filetype" : 判定を行う filetype + "end" または "filetype" に \1 が設定されている場 + 合は "start" にマッチした値になります。 +> + " Examples: + let g:context_filetype#filetypes = { + \ 'perl6' : [ + \ { + \ 'start' : 'Q:PIR\s*{', + \ 'end' : '}', + \ 'filetype' : 'pir', + \ } + \ ], + \ 'vim' : [ + \ { + \ 'start' : '^\s*python <<\s*\(\h\w*\)', + \ 'end' : '^\1', + \ 'filetype' : 'python', + \ } + \ ], + \ 'markdown': [ + \ { + \ 'start' : '^\s*```\s*\(\h\w*\)', + \ 'end' : '^\s*```$', + \ 'filetype' : '\1', + \ }, + \ ], + \} +< +b:context_filetype_filetypes *b:context_filetype_filetypes* + バッファ変数版の |g:context_filetype#filetypes| です。 + これが設定されている場合、|g:context_filetype#filetypes| は無 + 視されます。 + + + *g:context_filetype#same_filetypes* +g:context_filetype#same_filetypes + 各 same filetype を判定する為の辞書です。 + 各 filetype に対してカンマ区切りの文字列で設定する事ができま + す。 +> + if !exists('g:context_filetype#same_filetypes') + let g:context_filetype#same_filetypes = {} + endif + " In c buffers, completes from cpp and d buffers. + let g:context_filetype#same_filetypes.c = 'cpp,d' + " In cpp buffers, completes from c buffers. + let g:context_filetype#same_filetypes.cpp = 'c' + " In gitconfig buffers, completes from all buffers. + let g:context_filetype#same_filetypes.gitconfig = '_' + " In default, completes from all buffers. + let g:context_filetype#same_filetypes._ = '_' +< + + *g:context_filetype#ignore_composite_filetypes* +g:context_filetype#ignore_composite_filetypes + 複合 filetype を他の filetype に変換する為の辞書です。 +> + " Examples: + let g:context_filetype#ignore_composite_filetypes = { + \ 'ruby.spec' : 'ruby' + \ } +< + *g:context_filetype#search_offset* +g:context_filetype#search_offset + コンテキストを判定する時にカーソル位置からこの変数に設定され + ている行数の範囲のみを対象として判定を行います。 + バッファの行数が多くて動作が重く感じる場合はこの値を小さくし + て試してみて下さい。 +Default: > + " カーソル位置から前後 200 行の範囲で判定を行う + let g:context_filetype#search_offset = 200 +< + + +------------------------------------------------------------------------------ +関数 *context_filetype-functions* + +context_filetype#version() *context_filetype#version()* + バージョン情報を返す。 + Note: このライブラリがインストールされているかどうかの判定を + 使用する場合に利用することもできます。 +Example: > + let has_context_filetype = 0 + silent! let has_context_filetype = context_filetype#version() + if has_context_filetype + " context_filetype.vim が使用出来る場合の処理 + else + " context_filetype.vim が使用出来ない場合の処理 + endif +< + + *context_filetype#default_filetypes()* +context_filetype#default_filetypes() + デフォルトで設定されている |g:context_filetype#filetypes| の値 + を返す。 + +context_filetype#get([{filetype}]) *context_filetype#get()* + カーソル位置のコンテキスト情報を下記のようなフォーマットで返 + す。 +> + { + "filetype" : "vim", + "range" : [[3, 2], [10, 2]] + } +< + コンテキストの判定には {filetype} が使用され、{filetype} が渡 + されなければ 'filetype' の値が使用される。 + +context_filetype#get_filetype([{filetype}]) *context_filetype#get_filetype()* + カーソル位置のコンテキストの filetype を返す。 + コンテキストの判定には {filetype} が使用され、{filetype} が渡 + されなければ 'filetype' の値が使用される。 + コンテキストが見つからなかった場合は {filetype} が返される。 + + *context_filetype#get_filetypes()* +context_filetype#get_filetypes([{filetype}]) + カーソル位置のコンテキストの filetype をリスト形式で返す。 + この filetype には複合 filetype と same filetype が含まれる。 + コンテキストの判定には {filetype} が使用され、{filetype} が渡 + されなければ 'filetype' の値が使用される。 + +context_filetype#get_range([{filetype}]) *context_filetype#get_range()* + カーソル位置のコンテキストの範囲を [[{start}], [{end}]] で返す。 +> + [[3, 1], [4, 2]] +< + コンテキストの判定には {filetype} が使用され、{filetype} が渡 + されなければ 'filetype' の値が使用される。 + コンテキストが見つからなかった場合は [[0,0], [0,0]] が返される。 + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: diff --git a/bundle/context_filetype.vim/doc/context_filetype.txt b/bundle/context_filetype.vim/doc/context_filetype.txt new file mode 100644 index 000000000..f34a6a51f --- /dev/null +++ b/bundle/context_filetype.vim/doc/context_filetype.txt @@ -0,0 +1,140 @@ +*context_filetype.txt* Context filetype library for Vim script + +Version: 1.0 +Author : Shougo +License: MIT license + +CONTENTS *context_filetype-contents* + +Introduction |context_filetype-introduction| +Interface |context_filetype-interface| + Variables |context_filetype-variables| + Functions |context_filetype-functions| +Changelog |context_filetype-changelog| + +============================================================================== +INTRODUCTION *context_filetype-introduction* + +*context_filetype* provides functions to find fenced code blocks and their +filetype. +For example Javascript blocks inside of HTML. +The fenced code is detected by predefined regular expressions. + +============================================================================== +INTERFACE *context_filetype-interface* + +------------------------------------------------------------------------------ +VARIABLES *context_filetype-variables* + +g:context_filetype#filetypes *g:context_filetype#filetypes* + It is a dictionary to define context filetypes. + The item is a list of dictionaries. + + The keys and values are below. + "filetype" : includes filetype name. + "start" : filetype start pattern. + "end" : filetype end pattern. + + The patterns in "start" and "end" are always interpreted as if + 'magic' is set, ignoring the actual value of the 'magic' + option. + You can use "\0" through "\9" to refer to "start"'s match and + sub-matches in "end" and "filetype". +> + " Examples: + if !exists('g:context_filetype#filetypes') + let g:context_filetype#filetypes = {} + endif + let g:context_filetype#filetypes.perl6 = + \ [{'filetype' : 'pir', 'start' : 'Q:PIR\s*{', 'end' : '}'}] + let g:context_filetype#filetypes.vim = + \ [{'filetype' : 'python', + \ 'start' : '^\s*python <<\s*\(\h\w*\)', 'end' : '^\1'}] +< + Because it is complicated, refer to s:initialize() in + autoload/context_filetype.vim for the initial value. + +b:context_filetype_filetypes *b:context_filetype_filetypes* + It is the buffer variable version of + |g:context_filetype#filetypes|. + If you set it, |g:context_filetype#filetypes| is ignored. + + *g:context_filetype#same_filetypes* +g:context_filetype#same_filetypes + It is a dictionary to connect file type mutually. It is + effective at time to let you refer to "c" and "cpp" mutually. + The value are comma-separated filetypes. + If the value contains "_", context_filetype completes from all + buffers. If the key is "_", the value will be used for + default same filetypes. +> + if !exists('g:context_filetype#same_filetypes') + let g:context_filetype#same_filetypes = {} + endif + " In c buffers, completes from cpp and d buffers. + let g:context_filetype#same_filetypes.c = 'cpp,d' + " In cpp buffers, completes from c buffers. + let g:context_filetype#same_filetypes.cpp = 'c' + " In gitconfig buffers, completes from all buffers. + let g:context_filetype#same_filetypes.gitconfig = '_' + " In default, completes from all buffers. + let g:context_filetype#same_filetypes._ = '_' +< + Because it is complicated, refer to s:initialize() in + autoload/context_filetype.vim for the initial value. + + *g:context_filetype#ignore_composite_filetypes* +g:context_filetype#ignore_composite_filetypes + It is a dictionary to ignore composite file type. + The dictionary's key is composite filetype and value is + filetype. +> + " Examples: + let g:context_filetype#ignore_composite_filetypes = { + \ 'ruby.spec' : 'ruby' + \ } +< + If you open filetype like "ruby.spec", completion is + intended for "ruby" and "spec". + But if you only want to complete "ruby" filetype, + you can set this variable to ignore "spec". + + Default value is {}. + + *g:context_filetype#search_offset* +g:context_filetype#search_offset + It is the pattern search offset from current line. + + Default value is 200. + +------------------------------------------------------------------------------ +FUNCTIONS *context_filetype-functions* + +context_filetype#version() *context_filetype#version()* + Get version of context filetype library. + Note: It is useful for library installation check. + +context_filetype#get([{filetype}]) *context_filetype#get()* + Get completion filetype from {filetype}. + If you omit {filetype}, 'filetype' will be used. + + *context_filetype#get_filetypes()* +context_filetype#get_filetypes([{filetype}]) + Get completion filetypes from {filetype}. + They contains same filetypes and composite filetypes. + If you omit {filetype}, 'filetype' will be used. + + *context_filetype#default_filetypes()* +context_filetype#default_filetypes() + Get the dictionary of all default filetypes. + + *context_filetype#filetypes()* +context_filetype#filetypes() + Get the dictionary of all filetypes with + * |b:context_filetype_filetypes| (if defined) + * Or merged dictionary + * |context_filetype#default_filetypes()| + * |g:context_filetype#filetypes| + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: diff --git a/bundle/context_filetype.vim/test/test.vim b/bundle/context_filetype.vim/test/test.vim new file mode 100644 index 000000000..9f6340bb0 --- /dev/null +++ b/bundle/context_filetype.vim/test/test.vim @@ -0,0 +1,33 @@ +" 使い方 +" このファイルを :source する +" test_files に保存されているファイルを開き、:ContextFiletypeTest +" マッチしない filetype があれば quickfix へと出力される + +" テストファイルの作り方 +" コンテキストが書かれたコード記述する +" context_filetype#get() が返してほしい位置で filetype を `filetype` で記述する + + +function! s:checker(filename) + try + let pos = getpos(".") + let filetype_pattern = '`\w\+`' + let result = "" + + normal! gg0 + while search(filetype_pattern, 'W') + if context_filetype#get_filetype() !=# expand('') + let result .= printf("%s:%d: bad context filetype\n", a:filename, line('.')) + endif + endwhile + + cgetexpr result + cwindo + finally + call setpos(".", pos) + endtry +endfunction + +command! ContextFiletypeTest call s:checker(expand("%:p")) + + diff --git a/bundle/context_filetype.vim/test/test_files/test.html b/bundle/context_filetype.vim/test/test_files/test.html new file mode 100644 index 000000000..6de397863 --- /dev/null +++ b/bundle/context_filetype.vim/test/test_files/test.html @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + diff --git a/bundle/context_filetype.vim/test/test_files/test.md b/bundle/context_filetype.vim/test/test_files/test.md new file mode 100644 index 000000000..18034c6e9 --- /dev/null +++ b/bundle/context_filetype.vim/test/test_files/test.md @@ -0,0 +1,78 @@ + + +`markdown` + + +```cpp + +`cpp` + + +``` + + +```hoge + +`hoge` + +``` + + +```vim + +`vim` + +python << EOF + +`python` + +vim.eval("`vim`") + +EOF `vim` + + +ruby << EOF + +`ruby` + +EOF + + +``` + +```vim + +ruby << EOF + +`ruby` + +EOF + +``` + +```javascript + + + + +``` + +```cpp + +`cpp` + + ``` + +```text +`text`本日は晴天なり`text` +``` + +`markdown` + diff --git a/bundle/context_filetype.vim/test/test_files/test.ny b/bundle/context_filetype.vim/test/test_files/test.ny new file mode 100644 index 000000000..a3e10a220 --- /dev/null +++ b/bundle/context_filetype.vim/test/test_files/test.ny @@ -0,0 +1,13 @@ + +`nyaos` + +lua_e " +`lua` +" `nyaos` + +lua_e "`lua`" `nyaos` + +lua_e " +print(""`lua`"") +" `nyaos` + diff --git a/bundle/context_filetype.vim/test/test_files/test.vim b/bundle/context_filetype.vim/test/test_files/test.vim new file mode 100644 index 000000000..a57981137 --- /dev/null +++ b/bundle/context_filetype.vim/test/test_files/test.vim @@ -0,0 +1,46 @@ + +`vim` + +python << EOF + +`python` + +vim.eval("`vim`") + +EOF `vim` + + +ruby << EOF + +`ruby` + +EOF + + +lua << EOF + +`lua` + +EOF + +`vim` + + +lua << hoge + +`lua` + +hoge + +lua << hoge + +lua l = vim.eval('`vim`') + +EOF + + +ruby << EOF + +`ruby` + + diff --git a/bundle/defx-git/LICENSE b/bundle/defx-git/LICENSE new file mode 100644 index 000000000..759b17773 --- /dev/null +++ b/bundle/defx-git/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Kristijan Husak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/bundle/defx-git/README.md b/bundle/defx-git/README.md new file mode 100644 index 000000000..947353da6 --- /dev/null +++ b/bundle/defx-git/README.md @@ -0,0 +1,109 @@ +# defx-git + +Git status implementation for [defx.nvim](http://github.com/Shougo/defx.nvim). + +## Usage + +Just append `git` to your columns when starting defx: + +```viml +:Defx -columns=git:mark:filename:type +``` + +## Options + +### Indicators + +Which indicators (icons) to use for each status. These are the defaults: + +```viml +call defx#custom#column('git', 'indicators', { + \ 'Modified' : '✹', + \ 'Staged' : '✚', + \ 'Untracked' : '✭', + \ 'Renamed' : '➜', + \ 'Unmerged' : '═', + \ 'Ignored' : '☒', + \ 'Deleted' : '✖', + \ 'Unknown' : '?' + \ }) +``` + +### Column Length + +How many space should git column take. Default is `1` (Defx adds a single space between columns): + +```viml +call defx#custom#column('git', 'column_length', 1) +``` + +Missing characters to match this length are populated with spaces, which means +`✹` becomes `✹ `, etc. + +Note: Make sure indicators are not longer than the column_length + +### Show ignored + +This flag determines if ignored files should be marked with indicator. Default is `false`: + +```viml +call defx#custom#column('git', 'show_ignored', 0) +``` + +### Raw Mode + +Show git status in raw mode (Same as first two chars of `git status --porcelain` command). Default is `0`: + +```viml +call defx#custom#column('git', 'raw_mode', 0) +``` + +### Max Indicator Width + +The number of characters to pad the git column. If not specified, the default +will be the width of the longest indicator character. + +```viml +call defx#custom#column('git', 'max_indicator_width', 2) +``` + +## Highlighting + +Each indicator type can be overridden with the custom highlight. These are the defaults: + +```viml +hi Defx_git_Untracked guibg=NONE guifg=NONE ctermbg=NONE ctermfg=NONE +hi Defx_git_Ignored guibg=NONE guifg=NONE ctermbg=NONE ctermfg=NONE +hi Defx_git_Unknown guibg=NONE guifg=NONE ctermbg=NONE ctermfg=NONE +hi Defx_git_Renamed ctermfg=214 guifg=#fabd2f +hi Defx_git_Modified ctermfg=214 guifg=#fabd2f +hi Defx_git_Unmerged ctermfg=167 guifg=#fb4934 +hi Defx_git_Deleted ctermfg=167 guifg=#fb4934 +hi Defx_git_Staged ctermfg=142 guifg=#b8bb26 +``` + +To use for example red for untracked files, add this **after** your colorscheme setup: + +```viml +colorscheme gruvbox +hi Defx_git_Untracked guifg=#FF0000 +``` + +## Mappings + +There are 5 mappings: + +* `(defx-git-next)` - Goes to the next file that has a git status +* `(defx-git-prev)` - Goes to the previous file that has a git status +* `(defx-git-stage)` - Stages the file/directory under cursor +* `(defx-git-reset)` - Unstages the file/directory under cursor +* `(defx-git-discard)` - Discards all changes to file/directory under cursor + +If these are not manually mapped by the user, defaults are: +```viml +nnoremap [c (defx-git-prev) +nnoremap ]c (defx-git-next) +nnoremap ]a (defx-git-stage) +nnoremap ]r (defx-git-reset) +nnoremap ]d (defx-git-discard) +``` diff --git a/bundle/defx-git/ftplugin/defx.vim b/bundle/defx-git/ftplugin/defx.vim new file mode 100644 index 000000000..7d1924bf9 --- /dev/null +++ b/bundle/defx-git/ftplugin/defx.vim @@ -0,0 +1,83 @@ +if exists('*defx#redraw') + augroup defx_git + autocmd! + autocmd BufWritePost * call defx#redraw() + augroup END +endif + +scriptencoding utf-8 +if exists('b:defx_git_loaded') + finish +endif + +let b:defx_git_loaded = 1 + +function! s:search(dir) abort + let l:icons = get(g:, 'defx_git_indicators', {}) + let l:icons_pattern = join(values(l:icons), '\|') + + if !empty(l:icons_pattern) + let l:direction = a:dir > 0 ? 'w' : 'bw' + return search(printf('\(%s\)', l:icons_pattern), l:direction) + endif +endfunction + +function! s:git_cmd(cmd) abort + let l:actions = { + \ 'stage': '!git add', + \ 'reset': '!git reset', + \ 'discard': '!git checkout --' + \ } + let l:candidate = defx#get_candidate() + let l:path = get(l:candidate, 'action__path') + let l:word = get(l:candidate, 'word') + let l:is_dir = get(l:candidate, 'is_directory') + if empty(l:path) + return + endif + + let l:cmd = l:actions[a:cmd].' '.l:path + if a:cmd !=? 'discard' + call execute(l:cmd) + return defx#call_action('redraw') + endif + + let l:choice = confirm('Are you sure you want to discard all changes to '.l:word.'? ', "&Yes\n&No") + if l:choice !=? 1 + return + endif + let l:status = system('git status --porcelain '.l:path) + " File must be unstaged before discarding + if !empty(l:status[0]) + call execute(l:actions['reset'].' '.l:path) + endif + + call execute(l:cmd) + return defx#call_action('redraw') +endfunction + +nnoremap (defx-git-next) :call search(1) +nnoremap (defx-git-prev) :call search(-1) +nnoremap (defx-git-stage) :call git_cmd('stage') +nnoremap (defx-git-reset) :call git_cmd('reset') +nnoremap (defx-git-discard) :call git_cmd('discard') + +if !hasmapto('(defx-git-prev)') && maparg('[c', 'n') ==? '' + silent! nmap [c (defx-git-prev) +endif + +if !hasmapto('(defx-git-next)') && maparg(']c', 'n') ==? '' + silent! nmap ]c (defx-git-next) +endif + +if !hasmapto('(defx-git-stage)') && maparg(']a', 'n') ==? '' + silent! nmap ]a (defx-git-stage) +endif + +if !hasmapto('(defx-git-reset)') && maparg(']r', 'n') ==? '' + silent! nmap ]r (defx-git-reset) +endif + +if !hasmapto('(defx-git-discard)') && maparg(']d', 'n') ==? '' + silent! nmap ]d (defx-git-discard) +endif diff --git a/bundle/defx-git/rplugin/python3/defx/column/git.py b/bundle/defx-git/rplugin/python3/defx/column/git.py new file mode 100644 index 000000000..a8b2d7cf4 --- /dev/null +++ b/bundle/defx-git/rplugin/python3/defx/column/git.py @@ -0,0 +1,225 @@ +# ============================================================================ +# FILE: git.py +# AUTHOR: Kristijan Husak +# License: MIT license +# ============================================================================ + +import typing +import subprocess +from defx.base.column import Base +from defx.context import Context +from defx.view import View +from neovim import Nvim +from functools import cmp_to_key +from pathlib import PurePath + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'git' + self.vars = { + 'indicators': { + 'Modified': '✹', + 'Staged': '✚', + 'Untracked': '✭', + 'Renamed': '➜', + 'Unmerged': '═', + 'Ignored': '☒', + 'Deleted': '✖', + 'Unknown': '?' + }, + 'column_length': 1, + 'show_ignored': False, + 'raw_mode': False, + 'max_indicator_width': None + } + + custom_opts = ['indicators', 'column_length', 'show_ignored', + 'raw_mode', 'max_indicator_width'] + + for opt in custom_opts: + if 'defx_git#' + opt in self.vim.vars: + self.vars[opt] = self.vim.vars['defx_git#' + opt] + + self.cache: typing.List[str] = [] + self.git_root = '' + self.colors = { + 'Modified': { + 'color': 'guifg=#fabd2f ctermfg=214', + 'match': ' M' + }, + 'Staged': { + 'color': 'guifg=#b8bb26 ctermfg=142', + 'match': '\(M\|A\|C\).' + }, + 'Renamed': { + 'color': 'guifg=#fabd2f ctermfg=214', + 'match': 'R.' + }, + 'Unmerged': { + 'color': 'guifg=#fb4934 ctermfg=167', + 'match': '\(UU\|AA\|DD\)' + }, + 'Deleted': { + 'color': 'guifg=#fb4934 ctermfg=167', + 'match': ' D' + }, + 'Untracked': { + 'color': 'guifg=NONE guibg=NONE ctermfg=NONE ctermbg=NONE', + 'match': '??' + }, + 'Ignored': { + 'color': 'guifg=NONE guibg=NONE ctermfg=NONE ctermbg=NONE', + 'match': '!!' + }, + 'Unknown': { + 'color': 'guifg=NONE guibg=NONE ctermfg=NONE ctermbg=NONE', + 'match': 'X ' + } + } + min_column_length = 2 if self.vars['raw_mode'] else 1 + self.column_length = max(min_column_length, self.vars['column_length']) + + def on_init(self, view: View, context: Context) -> None: + # Set vim global variable for search mappings matching indicators + self.vim.vars['defx_git_indicators'] = self.vars['indicators'] + + if not self.vars.get('max_indicator_width'): + # Find longest indicator + self.vars['max_indicator_width'] = len( + max(self.vars['indicators'].values(), key=len)) + + def get(self, context: Context, candidate: dict) -> str: + default = self.format('').ljust( + self.column_length + self.vars['max_indicator_width'] - 1) + if candidate.get('is_root', False): + self.cache_status(candidate['action__path']) + return default + + if not self.cache: + return default + + entry = self.find_in_cache(candidate) + + if not entry: + return default + + return self.get_indicator(entry) + + def get_indicator(self, entry: str) -> str: + if self.vars['raw_mode']: + return self.format(entry[:2]) + + state = self.get_indicator_name(entry[0], entry[1]) + return self.format( + self.vars['indicators'][state] + ) + + def length(self, context: Context) -> int: + return self.column_length + + def syntaxes(self) -> typing.List[str]: + return [ + self.syntax_name + '_' + name for name in self.vars['indicators']] + + def highlight_commands(self) -> typing.List[str]: + commands: typing.List[str] = [] + for name, icon in self.vars['indicators'].items(): + if self.vars['raw_mode']: + commands.append(( + 'syntax match {0}_{1} /{2}/ contained containedin={0}' + ).format(self.syntax_name, name, self.colors[name]['match'])) + else: + commands.append(( + 'syntax match {0}_{1} /[{2}]/ contained containedin={0}' + ).format(self.syntax_name, name, icon)) + + commands.append('highlight default {0}_{1} {2}'.format( + self.syntax_name, name, self.colors[name]['color'] + )) + return commands + + def find_in_cache(self, candidate: dict) -> str: + action_path = PurePath(candidate['action__path']).as_posix() + path = str(action_path).replace(f'{self.git_root}/', '') + path += '/' if candidate['is_directory'] else '' + for item in self.cache: + item_path = item[3:] + if item[0] == 'R': + item_path = item_path.split(' -> ')[1] + + if item_path.startswith(path): + return item + + return '' + + def cache_status(self, path: str) -> None: + self.cache = [] + + if not self.git_root or not str(path).startswith(self.git_root): + self.git_root = PurePath(self.run_cmd( + ['git', 'rev-parse', '--show-toplevel'], path + )).as_posix() + + if not self.git_root: + return None + + cmd = ['git', 'status', '--porcelain', '-u'] + if self.vars['show_ignored']: + cmd += ['--ignored'] + + status = self.run_cmd(cmd, self.git_root) + results = [line for line in status.split('\n') if line != ''] + self.cache = sorted(results, key=cmp_to_key(self.sort)) + + def sort(self, a, b) -> int: + if a[0] == 'U' or a[1] == 'U': + return -1 + + if (a[0] == 'M' or a[1] == 'M') and not (b[0] == 'U' or b[1] == 'U'): + return -1 + + if ((a[0] == '?' and a[1] == '?') and not + (b[0] in ['M', 'U'] or b[1] in ['M', 'U'])): + return -1 + + return 1 + + def format(self, column: str) -> str: + return format(column, f'<{self.column_length}') + + def get_indicator_name(self, us: str, them: str) -> str: + if us == '?' and them == '?': + return 'Untracked' + elif us == ' ' and them == 'M': + return 'Modified' + elif us in ['M', 'A', 'C']: + return 'Staged' + elif us == 'R': + return 'Renamed' + elif us == '!': + return 'Ignored' + elif (us == 'U' or them == 'U' or us == 'A' and them == 'A' + or us == 'D' and them == 'D'): + return 'Unmerged' + elif them == 'D': + return 'Deleted' + else: + return 'Unknown' + + def run_cmd(self, cmd: typing.List[str], cwd=None) -> str: + try: + p = subprocess.run(cmd, stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, cwd=cwd) + except: + return '' + + decoded = p.stdout.decode('utf-8') + + if not decoded: + return '' + + return decoded.strip('\n') diff --git a/bundle/defx-icons/LICENSE b/bundle/defx-icons/LICENSE new file mode 100644 index 000000000..759b17773 --- /dev/null +++ b/bundle/defx-icons/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Kristijan Husak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/bundle/defx-icons/README.md b/bundle/defx-icons/README.md new file mode 100644 index 000000000..e1426342b --- /dev/null +++ b/bundle/defx-icons/README.md @@ -0,0 +1,84 @@ +# Defx icons + +Custom implementation of [vim-devicons](https://github.com/ryanoasis/vim-devicons) for [defx.nvim](https://github.com/Shougo/defx.nvim). + +![screenshot from 2018-11-22 23-39-41](https://user-images.githubusercontent.com/1782860/48923552-eeed0b80-eeaf-11e8-98e8-8f4e7ec85194.png) + +## Usage +```vimL +:Defx -columns=icons:indent:filename:type +``` +This column is a replacement for mark column. It will properly highlight selected files. + +## Configuration +This is the default configuration: + +```vimL +let g:defx_icons_enable_syntax_highlight = 1 +let g:defx_icons_column_length = 2 +let g:defx_icons_directory_icon = '' +let g:defx_icons_mark_icon = '*' +let g:defx_icons_copy_icon = '' +let g:defx_icons_move_icon = '' +let g:defx_icons_parent_icon = '' +let g:defx_icons_default_icon = '' +let g:defx_icons_directory_symlink_icon = '' +" Options below are applicable only when using "tree" feature +let g:defx_icons_root_opened_tree_icon = '' +let g:defx_icons_nested_opened_tree_icon = '' +let g:defx_icons_nested_closed_tree_icon = '' +``` + +Note: Syntax highlighting can cause some performance issues in defx window. Just disable it with the `let g:defx_icons_enable_syntax_highlight = 0` + + +## Override colors + +If you want to override some of the colors, you can do it this way: + +For gui: + +```vimL +let g:defx_icons_gui_colors = { +\ 'red': 'FFFFFF' +\ } +``` + +For term: + +```vimL +let g:defx_icons_term_colors = { +\ 'red': 2 +\ } +``` + +For directory icons these highlight groups are defined: + +```vimL +hi default link DefxIconsMarkIcon Statement +hi default link DefxIconsCopyIcon WarningMsg +hi default link DefxIconsMoveIcon ErrorMsg +hi default link DefxIconsDirectory Directory +hi default link DefxIconsParentDirectory Directory +hi default link DefxIconsSymlinkDirectory Directory +hi default link DefxIconsOpenedTreeIcon Directory +hi default link DefxIconsNestedTreeIcon Directory +hi default link DefxIconsClosedTreeIcon Directory +``` + +For example, to change color of the directory icon when it's opened in tree to red color, you would do something like this: + +```vimL +hi DefxIconsOpenedTreeIcon guifg=#FF0000 +``` + +Or link it to something else that you want: + +```vimL +hi link DefxIconsOpenedTreeIcon Error +``` + +## Thanks to + +* [vim-devicons](https://github.com/ryanoasis/vim-devicons) for icons +* [vim-nerdtree-syntax-highlight](https://github.com/tiagofumo/vim-nerdtree-syntax-highlight) for colors diff --git a/bundle/defx-icons/plugin/defx_icons.vim b/bundle/defx-icons/plugin/defx_icons.vim new file mode 100644 index 000000000..fcadbeb09 --- /dev/null +++ b/bundle/defx-icons/plugin/defx_icons.vim @@ -0,0 +1,229 @@ +scriptencoding utf-8 +if exists('g:loaded_defx_icons') + finish +endif +let g:loaded_defx_icons = 1 + +let s:enable_syntax_highlight = get(g:, 'defx_icons_enable_syntax_highlight', 1) +let s:column_length = get(g:, 'defx_icons_column_length', 1) +let s:parent_icon = get(g:, 'defx_icons_parent_icon', '') +let s:directory_icon = get(g:, 'defx_icons_directory_icon', '') +let s:mark_icon = get(g: , 'defx_icons_mark_icon', '*') +let s:default_icon = get(g:, 'defx_icons_default_icon', '') +let s:directory_symlink_icon = get(g:, 'defx_icons_directory_symlink_icon', '') +let s:root_opened_tree_icon = get(g:, 'defx_icons_root_opened_tree_icon', '') +let s:nested_closed_tree_icon = get(g: ,'defx_icons_nested_closed_tree_icon', '') +let s:nested_opened_tree_icon = get(g: ,'defx_icons_nested_opened_tree_icon', '') +let s:copy_icon = get(g:, 'defx_icons_copy_icon', '') +let s:move_icon = get(g:, 'defx_icons_move_icon', '') +let s:default_color = synIDattr(hlID('Normal'), 'fg') + +let s:gui_colors = extend({ + \ 'brown': '905532', + \ 'aqua': '3AFFDB', + \ 'blue': '689FB6', + \ 'darkBlue': '44788E', + \ 'purple': '834F79', + \ 'lightPurple': '834F79', + \ 'red': 'AE403F', + \ 'beige': 'F5C06F', + \ 'yellow': 'F09F17', + \ 'orange': 'D4843E', + \ 'darkOrange': 'F16529', + \ 'pink': 'CB6F6F', + \ 'salmon': 'EE6E73', + \ 'green': '8FAA54', + \ 'lightGreen': '31B53E', + \ 'default': s:default_color, + \ }, get(g:, 'defx_icons_gui_colors', {})) + +let s:term_colors = extend({ + \ 'brown' : 130, + \ 'aqua' : 66, + \ 'blue' : 67, + \ 'darkBlue' : 57, + \ 'purple' : 60, + \ 'lightPurple' : 103, + \ 'red' : 131, + \ 'beige' : 137, + \ 'yellow' : 229, + \ 'orange' : 208, + \ 'darkOrange' : 166, + \ 'pink' : 205, + \ 'salmon' : 209, + \ 'green' : 65, + \ 'lightGreen' : 108, + \ 'default' : 231, + \ }, get(g: ,'defx_icons_term_colors', {})) + +let s:extensions = extend({ + \ 'styl': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'sass': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'scss': {'icon': '', 'color': s:gui_colors.pink, 'term_color': s:term_colors.pink}, + \ 'htm': {'icon': '', 'color': s:gui_colors.darkOrange, 'term_color': s:term_colors.darkOrange}, + \ 'html': {'icon': '', 'color': s:gui_colors.darkOrange, 'term_color': s:term_colors.darkOrange}, + \ 'slim': {'icon': '', 'color': s:gui_colors.orange, 'term_color': s:term_colors.orange}, + \ 'ejs': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'css': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'less': {'icon': '', 'color': s:gui_colors.darkBlue, 'term_color': s:term_colors.darkBlue}, + \ 'md': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'markdown': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'rmd': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'json': {'icon': '', 'color': s:gui_colors.beige, 'term_color': s:term_colors.beige}, + \ 'js': {'icon': '', 'color': s:gui_colors.beige, 'term_color': s:term_colors.beige}, + \ 'mjs': {'icon': '', 'color': s:gui_colors.beige, 'term_color': s:term_colors.beige}, + \ 'jsx': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'rb': {'icon': '', 'color': s:gui_colors.red, 'term_color': s:term_colors.red}, + \ 'php': {'icon': '', 'color': s:gui_colors.purple, 'term_color': s:term_colors.purple}, + \ 'py': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'pyc': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'pyo': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'pyd': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'coffee': {'icon': '', 'color': s:gui_colors.brown, 'term_color': s:term_colors.brown}, + \ 'mustache': {'icon': '', 'color': s:gui_colors.orange, 'term_color': s:term_colors.orange}, + \ 'hbs': {'icon': '', 'color': s:gui_colors.orange, 'term_color': s:term_colors.orange}, + \ 'conf': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'ini': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'yml': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'yaml': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'bat': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'toml': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'jpg': {'icon': '', 'color': s:gui_colors.aqua, 'term_color': s:term_colors.aqua}, + \ 'jpeg': {'icon': '', 'color': s:gui_colors.aqua, 'term_color': s:term_colors.aqua}, + \ 'bmp': {'icon': '', 'color': s:gui_colors.aqua, 'term_color': s:term_colors.aqua}, + \ 'png': {'icon': '', 'color': s:gui_colors.aqua, 'term_color': s:term_colors.aqua}, + \ 'gif': {'icon': '', 'color': s:gui_colors.aqua, 'term_color': s:term_colors.aqua}, + \ 'ico': {'icon': '', 'color': s:gui_colors.aqua, 'term_color': s:term_colors.aqua}, + \ 'twig': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'cpp': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'cxx': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'cc': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'cp': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'c': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'h': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'hpp': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'hxx': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'hs': {'icon': '', 'color': s:gui_colors.beige, 'term_color': s:term_colors.beige}, + \ 'lhs': {'icon': '', 'color': s:gui_colors.beige, 'term_color': s:term_colors.beige}, + \ 'lua': {'icon': '', 'color': s:gui_colors.purple, 'term_color': s:term_colors.purple}, + \ 'java': {'icon': '', 'color': s:gui_colors.purple, 'term_color': s:term_colors.purple}, + \ 'sh': {'icon': '', 'color': s:gui_colors.lightPurple, 'term_color': s:term_colors.lightPurple}, + \ 'fish': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'bash': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'zsh': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'ksh': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'csh': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'awk': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'ps1': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'ml': {'icon': 'λ', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'mli': {'icon': 'λ', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'diff': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'db': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'sql': {'icon': '', 'color': s:gui_colors.darkBlue, 'term_color': s:term_colors.darkBlue}, + \ 'dump': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'clj': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'cljc': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'cljs': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'edn': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'scala': {'icon': '', 'color': s:gui_colors.red, 'term_color': s:term_colors.red}, + \ 'go': {'icon': '', 'color': s:gui_colors.beige, 'term_color': s:term_colors.beige}, + \ 'dart': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'xul': {'icon': '', 'color': s:gui_colors.darkOrange, 'term_color': s:term_colors.darkOrange}, + \ 'sln': {'icon': '', 'color': s:gui_colors.purple, 'term_color': s:term_colors.purple}, + \ 'suo': {'icon': '', 'color': s:gui_colors.purple, 'term_color': s:term_colors.purple}, + \ 'pl': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'pm': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 't': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'rss': {'icon': '', 'color': s:gui_colors.darkOrange, 'term_color': s:term_colors.darkOrange}, + \ 'fsscript': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'fsx': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'fs': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'fsi': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'rs': {'icon': '', 'color': s:gui_colors.darkOrange, 'term_color': s:term_colors.darkOrange}, + \ 'rlib': {'icon': '', 'color': s:gui_colors.darkOrange, 'term_color': s:term_colors.darkOrange}, + \ 'd': {'icon': '', 'color': s:gui_colors.red, 'term_color': s:term_colors.red}, + \ 'erl': {'icon': '', 'color': s:gui_colors.lightPurple, 'term_color': s:term_colors.lightPurple}, + \ 'ex': {'icon': '', 'color': s:gui_colors.lightPurple, 'term_color': s:term_colors.lightPurple}, + \ 'exs': {'icon': '', 'color': s:gui_colors.lightPurple, 'term_color': s:term_colors.lightPurple}, + \ 'eex': {'icon': '', 'color': s:gui_colors.lightPurple, 'term_color': s:term_colors.lightPurple}, + \ 'hrl': {'icon': '', 'color': s:gui_colors.pink, 'term_color': s:term_colors.pink}, + \ 'vim': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'ai': {'icon': '', 'color': s:gui_colors.darkOrange, 'term_color': s:term_colors.darkOrange}, + \ 'psd': {'icon': '', 'color': s:gui_colors.darkBlue, 'term_color': s:term_colors.darkBlue}, + \ 'psb': {'icon': '', 'color': s:gui_colors.darkBlue, 'term_color': s:term_colors.darkBlue}, + \ 'ts': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'tsx': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'jl': {'icon': '', 'color': s:gui_colors.purple, 'term_color': s:term_colors.purple}, + \ 'pp': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'vue': {'icon': '﵂', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ }, get(g:, 'defx_icons_extensions', {})) + +let s:exact_matches = extend({ + \ 'gruntfile.coffee': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'gruntfile.js': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'gruntfile.ls': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'gulpfile.coffee': {'icon': '', 'color': s:gui_colors.pink, 'term_color': s:term_colors.pink}, + \ 'gulpfile.js': {'icon': '', 'color': s:gui_colors.pink, 'term_color': s:term_colors.pink}, + \ 'gulpfile.ls': {'icon': '', 'color': s:gui_colors.pink, 'term_color': s:term_colors.pink}, + \ 'dropbox': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.ds_store': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.gitconfig': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.gitignore': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.bashrc': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.zshrc': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.vimrc': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.gvimrc': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '_vimrc': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '_gvimrc': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.bashprofile': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'favicon.ico': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ 'license': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'node_modules': {'icon': '', 'color': s:gui_colors.green, 'term_color': s:term_colors.green}, + \ 'react.jsx': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'procfile': {'icon': '', 'color': s:gui_colors.purple, 'term_color': s:term_colors.purple}, + \ 'dockerfile': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ 'docker-compose.yml': {'icon': '', 'color': s:gui_colors.yellow, 'term_color': s:term_colors.yellow}, + \ }, get(g:, 'defx_icons_exact_matches', {})) + +let s:pattern_matches = extend({ + \ '.*jquery.*\.js$': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ '.*angular.*\.js$': {'icon': '', 'color': s:gui_colors.red, 'term_color': s:term_colors.red}, + \ '.*backbone.*\.js$': {'icon': '', 'color': s:gui_colors.darkBlue, 'term_color': s:term_colors.darkBlue}, + \ '.*require.*\.js$': {'icon': '', 'color': s:gui_colors.blue, 'term_color': s:term_colors.blue}, + \ '.*materialize.*\.js$': {'icon': '', 'color': s:gui_colors.salmon, 'term_color': s:term_colors.salmon}, + \ '.*materialize.*\.css$': {'icon': '', 'color': s:gui_colors.salmon, 'term_color': s:term_colors.salmon}, + \ '.*mootools.*\.js$': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ '.*vimrc.*': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ 'Vagrantfile$': {'icon': '', 'color': s:gui_colors.default, 'term_color': s:term_colors.default}, + \ }, get(g:, 'defx_icon_pattern_matches', {})) + +hi default link DefxIconsMarkIcon Statement +hi default link DefxIconsCopyIcon WarningMsg +hi default link DefxIconsMoveIcon ErrorMsg +hi default link DefxIconsDirectory Directory +hi default link DefxIconsParentDirectory Directory +hi default link DefxIconsSymlinkDirectory Directory +hi default link DefxIconsOpenedTreeIcon Directory +hi default link DefxIconsNestedTreeIcon Directory +hi default link DefxIconsClosedTreeIcon Directory + +function! defx_icons#get() abort + return { + \ 'extensions': s:extensions, + \ 'exact_matches': s:exact_matches, + \ 'exact_dir_matches': get(g:, 'defx_icon_exact_dir_matches', {}), + \ 'pattern_matches': s:pattern_matches, + \ 'enable_syntax_highlight': s:enable_syntax_highlight, + \ 'column_length': s:column_length, + \ 'parent_icon': s:parent_icon, + \ 'directory_icon': s:directory_icon, + \ 'directory_symlink_icon': s:directory_symlink_icon, + \ 'mark_icon': s:mark_icon, + \ 'default_icon': s:default_icon, + \ 'root_opened_tree_icon': s:root_opened_tree_icon, + \ 'nested_closed_tree_icon': s:nested_closed_tree_icon, + \ 'nested_opened_tree_icon': s:nested_opened_tree_icon, + \ 'copy_icon': s:copy_icon, + \ 'move_icon': s:move_icon, + \ } +endfunction diff --git a/bundle/defx-icons/rplugin/python3/defx/column/icons.py b/bundle/defx-icons/rplugin/python3/defx/column/icons.py new file mode 100644 index 000000000..35457ad3a --- /dev/null +++ b/bundle/defx-icons/rplugin/python3/defx/column/icons.py @@ -0,0 +1,137 @@ +# ============================================================================ +# FILE: icons.py +# AUTHOR: Kristijan Husak +# License: MIT license +# ============================================================================ + +import re +import typing +from pathlib import Path +from defx.base.column import Base +from defx.context import Context +from defx.clipboard import ClipboardAction +from defx.view import View +from neovim import Nvim + + +class Column(Base): + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + self.vim = vim + self.name = 'icons' + self.opts = self.vim.call('defx_icons#get') + + def on_init(self, view: View, context: Context) -> None: + self._context = context + self._view = view + + def on_redraw(self, view: View, context: Context) -> None: + self._context = context + self._view = view + + def get(self, context: Context, candidate: dict) -> str: + path: Path = candidate['action__path'] + filename = path.name + if 'mark' not in context.columns and candidate['is_selected']: + return self.icon(self.opts['mark_icon']) + + if self._view and self._view._clipboard.candidates: + for clipboard_candidate in self._view._clipboard.candidates: + if str(clipboard_candidate['action__path']) == str(path): + return self.clipboard_icon() + + if candidate.get('is_root', False): + return self.icon(self.opts['parent_icon']) + + if candidate['is_directory']: + if filename in self.opts['exact_dir_matches']: + return self.icon(self.opts['exact_dir_matches'][filename]['icon']) + + if candidate.get('level', 0) > 0: + if candidate.get('is_opened_tree'): + return self.icon(self.opts['nested_opened_tree_icon']) + return self.icon(self.opts['nested_closed_tree_icon']) + + if candidate.get('is_opened_tree', False): + return self.icon(self.opts['root_opened_tree_icon']) + + if path.is_symlink(): + return self.icon(self.opts['directory_symlink_icon']) + + return self.icon(self.opts['directory_icon']) + + filename = filename.lower() + ext = path.suffix[1:].lower() + + for pattern, pattern_data in self.opts['pattern_matches'].items(): + if re.search(pattern, filename) is not None: + return self.icon(pattern_data['icon']) + + if filename in self.opts['exact_matches']: + return self.icon(self.opts['exact_matches'][filename]['icon']) + + if ext in self.opts['extensions']: + return self.icon(self.opts['extensions'][ext]['icon']) + + return self.icon(self.opts['default_icon']) + + def length(self, context: Context) -> int: + return self.opts['column_length'] + + def icon(self, icon: str) -> str: + return format(icon, f'<{self.opts["column_length"]}') + + def clipboard_icon(self) -> str: + if self._view._clipboard.action == ClipboardAction.COPY: + return self.opts['copy_icon'] + if self._view._clipboard.action == ClipboardAction.MOVE: + return self.opts['move_icon'] + return '' + + def syn_item(self, name, opt_name, hi_group_name) -> typing.List[str]: + commands: typing.List[str] = [] + commands.append(f'silent! syntax clear {self.syntax_name}_{name}') + commands.append(( + 'syntax match {0}_{1} /[{2}]/ contained containedin={0}' + ).format(self.syntax_name, name, self.opts[opt_name])) + commands.append('highlight default link {0}_{1} {2}'.format( + self.syntax_name, name, hi_group_name + )) + return commands + + def syn_list(self, opt) -> typing.List[str]: + commands: typing.List[str] = [] + for name, opts in self.opts[opt].items(): + text = re.sub('[^A-Za-z]', '', name) + commands.append(f'silent! syntax clear {self.syntax_name}_{text}') + commands.append(( + 'syntax match {0}_{1} /[{2}]/ contained containedin={0}' + ).format(self.syntax_name, text, opts['icon'])) + commands.append('highlight default {0}_{1} guifg=#{2} ctermfg={3}'.format( + self.syntax_name, text, opts['color'], opts.get('term_color', + 'NONE'))) + return commands + + def highlight_commands(self) -> typing.List[str]: + commands: typing.List[str] = [] + + if not self.opts['enable_syntax_highlight']: + return commands + + commands += self.syn_item('icon_mark', 'mark_icon', 'DefxIconsMarkIcon') + commands += self.syn_item('icon_copy', 'copy_icon', 'DefxIconsCopyIcon') + commands += self.syn_item('icon_move', 'move_icon', 'DefxIconsMoveIcon') + + commands += self.syn_item('directory', 'directory_icon', 'DefxIconsDirectory') + commands += self.syn_item('parent_directory', 'parent_icon', 'DefxIconsParentDirectory') + commands += self.syn_item('symlink_directory', 'directory_symlink_icon', 'DefxIconsSymlinkDirectory') + commands += self.syn_item('root_opened_tree_icon', 'root_opened_tree_icon', 'DefxIconsOpenedTreeIcon') + commands += self.syn_item('nested_opened_tree_icon', 'nested_opened_tree_icon', 'DefxIconsNestedTreeIcon') + commands += self.syn_item('nested_closed_tree_icon', 'nested_closed_tree_icon', 'DefxIconsClosedTreeIcon') + + commands += self.syn_list('pattern_matches') + commands += self.syn_list('exact_matches') + commands += self.syn_list('exact_dir_matches') + commands += self.syn_list('extensions') + + return commands diff --git a/bundle/defx.nvim/.github/ISSUE_TEMPLATE.md b/bundle/defx.nvim/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..f75aff7be --- /dev/null +++ b/bundle/defx.nvim/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ +**Warning: I will close the issue without the minimal init.vim and the reproduction instructions.** + +# Problems summary + + +## Expected + + +## Environment Information + + * defx version(SHA1): + + * OS: + + * neovim/Vim version: + + * `:checkhealth` or `:CheckHealth` result(neovim only): + +## Provide a minimal init.vim/vimrc with less than 50 lines (Required!) + +```vim +" Your minimal init.vim/vimrc +set runtimepath+=~/path/to/defx.nvim/ +``` + + +## The reproduce ways from neovim/Vim starting (Required!) + + 1. foo + 2. bar + 3. baz + + +## Generate a logfile if appropriate + + 1. export NVIM_PYTHON_LOG_FILE=/tmp/log + 2. export NVIM_PYTHON_LOG_LEVEL=DEBUG + 3. nvim -u minimal.vimrc + 4. some works + 5. cat /tmp/log_{PID} + + +## Screen shot (if possible) + + +## Upload the log file diff --git a/bundle/defx.nvim/.gitignore b/bundle/defx.nvim/.gitignore new file mode 100644 index 000000000..dbb114aaa --- /dev/null +++ b/bundle/defx.nvim/.gitignore @@ -0,0 +1,6 @@ +*.py[cod] +doc/tags +vim-themis +.cache +.mypy_cache/ +.pytest_cache/ diff --git a/bundle/defx.nvim/.travis.yml b/bundle/defx.nvim/.travis.yml new file mode 100644 index 000000000..eac636a70 --- /dev/null +++ b/bundle/defx.nvim/.travis.yml @@ -0,0 +1,14 @@ +dist: xenial + +language: python + +python: + - 3.6 + - 3.7 + +install: + - eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) nightly-x64" + - make install + +script: + - make --keep-going test lint diff --git a/bundle/defx.nvim/LICENSE b/bundle/defx.nvim/LICENSE new file mode 100644 index 000000000..3a4b98ed8 --- /dev/null +++ b/bundle/defx.nvim/LICENSE @@ -0,0 +1,21 @@ +License: MIT license +AUTHOR: Shougo Matsushita + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bundle/defx.nvim/Makefile b/bundle/defx.nvim/Makefile new file mode 100644 index 000000000..5773e96a1 --- /dev/null +++ b/bundle/defx.nvim/Makefile @@ -0,0 +1,31 @@ +PATH := ./vim-themis/bin:$(PATH) +export THEMIS_VIM := nvim +export THEMIS_ARGS := -e -s --headless +export THEMIS_HOME := ./vim-themis + + +install: vim-themis + pip install --upgrade -r test/requirements.txt + +install-user: vim-themis + pip install --user --upgrade -r test/requirements.txt + +lint: + vint --version + vint plugin + vint autoload + flake8 --version + flake8 rplugin + mypy --version + mypy --ignore-missing-imports --follow-imports=skip --strict rplugin/python3/defx + +test: + # themis --version + # themis test/autoload/* + pytest --version + pytest + +vim-themis: + git clone https://github.com/thinca/vim-themis vim-themis + +.PHONY: install lint test diff --git a/bundle/defx.nvim/README.md b/bundle/defx.nvim/README.md new file mode 100644 index 000000000..147666a5c --- /dev/null +++ b/bundle/defx.nvim/README.md @@ -0,0 +1,117 @@ +## About + +[![Join the chat at https://gitter.im/Shougo/defx.nvim](https://badges.gitter.im/Shougo/defx.nvim.svg)](https://gitter.im/Shougo/defx.nvim?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Defx is a dark powered plugin for Neovim/Vim to browse files. +It replaces the deprecated vimfiler plugin. + + +## Concept + +* Doesn't depend on denite.nvim + +* Vim8/neovim compatible(nvim-yarp is needed for Vim8) + +* Implemented by Python3 + +* No double filer feature + +* Column feature + +* Source feature like denite.nvim + +* Options + +* Highlight is defined by column + +* Few commands (:Defx command only?) + +* Extended rename + +* Mark + +* Windows supporters are needed + +* Maximum features dislike other file managers + + +## Installation + +**Note:** defx requires Neovim 0.3.0+ or Vim8.1+ with Python3.6.1+. See +[requirements](#requirements) if you aren't sure whether you have this. + +For vim-plug + +```viml +if has('nvim') + Plug 'Shougo/defx.nvim', { 'do': ':UpdateRemotePlugins' } +else + Plug 'Shougo/defx.nvim' + Plug 'roxma/nvim-yarp' + Plug 'roxma/vim-hug-neovim-rpc' +endif +``` + +For dein.vim + +```viml +call dein#add('Shougo/defx.nvim') +if !has('nvim') + call dein#add('roxma/nvim-yarp') + call dein#add('roxma/vim-hug-neovim-rpc') +endif +``` + +For manual installation(not recommended) + +1. Extract the files and put them in your Neovim or .vim directory + (usually `$XDG_CONFIG_HOME/nvim/`). + + +## Requirements + +defx requires Python3.6.1+ and Neovim(0.3.0+) or Vim8.1+ with if\_python3. If +`:echo has("python3")` returns `1`, then you have python 3 support; otherwise, +see below. + +You can enable Python3 interface with pip: + + pip3 install --user pynvim + +Please install nvim-yarp plugin for Vim8. +https://github.com/roxma/nvim-yarp + +Please install vim-hug-neovim-rpc plugin for Vim8. +https://github.com/roxma/vim-hug-neovim-rpc + + +## Note: Python3 must be enabled before updating remote plugins +If Defx was installed prior to Python support being added to Neovim, +`:UpdateRemotePlugins` should be executed manually. + + +## Configuration Examples + +```vim +" Todo +``` + + + +## Screenshots + +![multi root feature](https://user-images.githubusercontent.com/41495/45696476-ac9d0a80-bb9e-11e8-9ee2-120ac7d0f045.png) +![Defx -split=vertical](https://user-images.githubusercontent.com/2835826/45823772-7190f900-bcbc-11e8-9727-3dda3ce4c07c.png) +![Defx -new](https://user-images.githubusercontent.com/3047695/45927914-7f07e680-bf3b-11e8-9b36-755e1eec2a8f.png) +![Defx + neovim-qt](https://user-images.githubusercontent.com/1314340/48659914-0b4a0c00-ea9c-11e8-9953-2f2d5ca7f24a.png) +![custom icon](https://user-images.githubusercontent.com/10108377/59982828-ac93d480-9620-11e9-8c10-51909cfeaf94.png) +![custom icon2](https://user-images.githubusercontent.com/3021667/55260000-95ba2d80-523d-11e9-877c-756a080a9a28.png) +![custom icon3](https://user-images.githubusercontent.com/10397021/57774111-3f04a680-774c-11e9-852a-53c394f672ef.png) +![custom icon4](https://user-images.githubusercontent.com/12205650/58801907-d9346d80-85d9-11e9-8a2d-de4635aa1eba.png) +![custom icon5](https://user-images.githubusercontent.com/11615211/82411894-381e1b80-9aa5-11ea-9552-fd9847fe25e3.png) +![Defx on kitty](https://user-images.githubusercontent.com/8403993/51080184-d29e6b80-16b5-11e9-802b-7c2f56705e2e.png) +![Defx in SpaceVim](https://user-images.githubusercontent.com/13142418/54086225-85233f80-4382-11e9-8091-7f387319b90a.png) +![Variable column](https://user-images.githubusercontent.com/19503791/56090130-58f26580-5ed0-11e9-8b66-e684cb11b0d1.png) +![Denite action call](https://user-images.githubusercontent.com/41671631/56280845-a6bfd580-613d-11e9-857a-d81f2633eeab.png) +![Defx floating window](https://user-images.githubusercontent.com/24732170/59892964-1c823f00-9416-11e9-8369-2e21910e168c.png) +![Horizon colorscheme](https://user-images.githubusercontent.com/324519/63241202-a4fb4100-c207-11e9-9060-c3c04608ea7b.png) diff --git a/bundle/defx.nvim/autoload/defx.vim b/bundle/defx.nvim/autoload/defx.vim new file mode 100644 index 000000000..4f121ecb6 --- /dev/null +++ b/bundle/defx.nvim/autoload/defx.vim @@ -0,0 +1,83 @@ +"============================================================================= +" FILE: defx.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! defx#initialize() abort + return defx#init#_initialize() +endfunction + +function! defx#start(paths, user_context) abort + call defx#initialize() + let context = defx#init#_context(a:user_context) + let paths = a:paths + let paths = map(paths, "fnamemodify(v:val, ':p')") + call defx#util#rpcrequest('_defx_start', [paths, context], v:false) + if context['search'] !=# '' + call defx#call_action('search', [context['search']]) + endif +endfunction + +function! defx#do_action(action, ...) abort + if &l:filetype !=# 'defx' + return '' + endif + + let args = defx#util#convert2list(get(a:000, 0, [])) + return printf(":\call defx#call_action(%s, %s)\", + \ string(a:action), string(args)) +endfunction +function! defx#async_action(action, ...) abort + if &l:filetype !=# 'defx' + return '' + endif + + let args = defx#util#convert2list(get(a:000, 0, [])) + return printf(":\call defx#call_async_action(%s, %s)\", + \ string(a:action), string(args)) +endfunction +function! defx#call_action(action, ...) abort + if &l:filetype !=# 'defx' + return + endif + + let context = defx#init#_context({}) + let args = defx#util#convert2list(get(a:000, 0, [])) + call defx#util#rpcrequest( + \ '_defx_do_action', [a:action, args, context], v:false) +endfunction +function! defx#call_async_action(action, ...) abort + if &l:filetype !=# 'defx' + return + endif + + let context = defx#init#_context({}) + let args = defx#util#convert2list(get(a:000, 0, [])) + call defx#util#rpcrequest( + \ '_defx_async_action', [a:action, args, context], v:true) +endfunction +function! defx#redraw() abort + call defx#util#rpcrequest('_defx_redraw', [], v:false) +endfunction + +function! defx#get_candidate() abort + if &l:filetype !=# 'defx' + return {} + endif + + return defx#util#rpcrequest('_defx_get_candidate', [], v:false) +endfunction +function! defx#is_directory() abort + return get(defx#get_candidate(), 'is_directory', v:false) +endfunction +function! defx#is_opened_tree() abort + return get(defx#get_candidate(), 'is_opened_tree', v:false) +endfunction +function! defx#get_context() abort + if &l:filetype !=# 'defx' + return {} + endif + + return defx#util#rpcrequest('_defx_get_context', [], v:false) +endfunction diff --git a/bundle/defx.nvim/autoload/defx/custom.vim b/bundle/defx.nvim/autoload/defx/custom.vim new file mode 100644 index 000000000..5ecc7865b --- /dev/null +++ b/bundle/defx.nvim/autoload/defx/custom.vim @@ -0,0 +1,62 @@ +"============================================================================= +" FILE: custom.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! defx#custom#_get() abort + if !exists('s:custom') + call defx#custom#_init() + endif + + return s:custom +endfunction + +function! defx#custom#_init() abort + let s:custom = {} + let s:custom.column = {} + let s:custom.option = {} + let s:custom.source = {} +endfunction + +function! defx#custom#column(column_name, name_or_dict, ...) abort + let custom = defx#custom#_get().column + + for key in defx#util#split(a:column_name) + if !has_key(custom, key) + let custom[key] = {} + endif + call s:set_custom(custom[key], a:name_or_dict, get(a:000, 0, '')) + endfor +endfunction + +function! defx#custom#option(buffer_name, name_or_dict, ...) abort + let custom = defx#custom#_get().option + + for key in defx#util#split(a:buffer_name) + if !has_key(custom, key) + let custom[key] = {} + endif + + call s:set_custom(custom[key], a:name_or_dict, get(a:000, 0, '')) + endfor +endfunction + +function! defx#custom#source(source_name, name_or_dict, ...) abort + let custom = defx#custom#_get().source + + for key in defx#util#split(a:source_name) + if !has_key(custom, key) + let custom[key] = {} + endif + call s:set_custom(custom[key], a:name_or_dict, get(a:000, 0, '')) + endfor +endfunction + +function! s:set_custom(dest, name_or_dict, value) abort + if type(a:name_or_dict) == v:t_dict + call extend(a:dest, a:name_or_dict) + else + let a:dest[a:name_or_dict] = a:value + endif +endfunction diff --git a/bundle/defx.nvim/autoload/defx/exrename.vim b/bundle/defx.nvim/autoload/defx/exrename.vim new file mode 100644 index 000000000..1ab73c8a5 --- /dev/null +++ b/bundle/defx.nvim/autoload/defx/exrename.vim @@ -0,0 +1,211 @@ +"============================================================================= +" FILE: exrename.vim +" AUTHOR: Shougo Matsushita +" EDITOR: Alisue +" License: MIT license +"============================================================================= + +let s:PREFIX = has('win32') ? '[exrename]' : '*exrename*' + +function! defx#exrename#create_buffer(candidates, ...) abort + let options = extend({ + \ 'cwd': getcwd(), + \ 'bufnr': bufnr('%'), + \ 'buffer_name': '', + \ 'post_rename_callback': v:null, + \}, get(a:000, 0, {})) + if options.cwd !~# '/$' + " current working directory MUST end with a trailing slash + let options.cwd .= '/' + endif + if options.buffer_name ==# '' + let options.buffer_name = s:PREFIX + else + let options.buffer_name = s:PREFIX . ' - ' . options.buffer_name + endif + + vsplit + redraw + execute 'edit' fnameescape(options.buffer_name) + + setlocal buftype=acwrite + setlocal noswapfile + setfiletype defx_exrename + + syntax match defxExrenameModified '^.*$' + + highlight def link defxExrenameModified Todo + highlight def link defxExrenameOriginal Normal + + let b:exrename = options + + call defx#util#cd(b:exrename.cwd) + + nnoremap q :call exit(bufnr('%')) + augroup defx-exrename + autocmd! * + autocmd BufHidden call s:exit(expand('')) + autocmd BufWriteCmd call s:do_rename() + autocmd CursorMoved,CursorMovedI call s:check_lines() + augroup END + + " Clean up the screen. + silent % delete _ + silent! syntax clear defxExrenameOriginal + + " validate candidates and register + let unique_filenames = [] + let b:exrename.candidates = [] + let b:exrename.filenames = [] + let cnt = 1 + for candidate in a:candidates + " make sure that the 'action__path' is absolute path + if !s:is_absolute(candidate.action__path) + let candidate.action__path = b:exrename.cwd . candidate.action__path + endif + " make sure that the 'action__path' exists + if !filewritable(candidate.action__path) + \ && !isdirectory(candidate.action__path) + redraw + echo candidate.action__path 'does not exist. Skip.' + continue + endif + " make sure that the 'action__path' is unique + if index(unique_filenames, candidate.action__path) != -1 + redraw + echo candidate.action__path 'is duplicated. Skip.' + continue + endif + " create filename + let filename = candidate.action__path + if stridx(filename, b:exrename.cwd) == 0 + let filename = filename[len(b:exrename.cwd) :] + endif + " directory should end with a trailing slash (to distinguish easily) + if isdirectory(candidate.action__path) + let filename .= '/' + endif + + execute 'syntax match defxExrenameOriginal' + \ '/'.printf('^\%%%dl%s$', cnt, + \ escape(s:escape_pattern(filename), '/')).'/' + " register + call add(unique_filenames, candidate.action__path) + call add(b:exrename.candidates, candidate) + call add(b:exrename.filenames, filename) + let cnt += 1 + endfor + " write filenames + let [undolevels, &undolevels] = [&undolevels, -1] + try + call setline(1, b:exrename.filenames) + finally + let &undolevels = undolevels + endtry + setlocal nomodified +endfunction + +function! s:escape_pattern(str) abort + return escape(a:str, '~"\.^$[]*') +endfunction + +function! s:is_absolute(path) abort + return a:path =~# '^\%(\a\a\+:\)\|^\%(\a:\|/\)' +endfunction + +function! s:do_rename() abort + if line('$') != len(b:exrename.filenames) + echohl Error | echo 'Invalid rename buffer!' | echohl None + return + endif + + " Rename files. + let linenr = 1 + let max = line('$') + while linenr <= max + let filename = b:exrename.filenames[linenr - 1] + + redraw + echo printf('(%'.len(max).'d/%d): %s -> %s', + \ linenr, max, filename, getline(linenr)) + + if filename !=# getline(linenr) + let old_file = b:exrename.candidates[linenr - 1].action__path + let new_file = expand(getline(linenr)) + if new_file !~# '^\%(\a\a\+:\)\|^\%(\a:\|/\)' + let new_file = b:exrename.cwd . new_file + endif + + if rename(old_file, new_file) + " Rename error + continue + endif + + " update b:exrename + let b:exrename.filenames[linenr - 1] = getline(linenr) + let b:exrename.candidates[linenr - 1].action__path = new_file + endif + let linenr += 1 + endwhile + + redraw + echo 'Rename done!' + + setlocal nomodified + + if b:exrename.post_rename_callback != v:null + call b:exrename.post_rename_callback(b:exrename) + endif +endfunction + +function! s:exit(bufnr) abort + if !bufexists(a:bufnr) + return + endif + + " Switch buffer. + if winnr('$') != 1 + close + else + call s:custom_alternate_buffer() + endif + silent execute 'bdelete!' a:bufnr +endfunction + +function! s:check_lines() abort + if !exists('b:exrename') + return + endif + + if line('$') != len(b:exrename.filenames) + echohl Error | echo 'Invalid rename buffer!' | echohl None + return + endif +endfunction + +function! s:custom_alternate_buffer() abort + if bufnr('%') != bufnr('#') && buflisted(bufnr('#')) + buffer # + endif + + let cnt = 0 + let pos = 1 + let current = 0 + while pos <= bufnr('$') + if buflisted(pos) + if pos == bufnr('%') + let current = cnt + endif + + let cnt += 1 + endif + + let pos += 1 + endwhile + + if current > cnt / 2 + bprevious + else + bnext + endif +endfunction diff --git a/bundle/defx.nvim/autoload/defx/init.vim b/bundle/defx.nvim/autoload/defx/init.vim new file mode 100644 index 000000000..1696fb48e --- /dev/null +++ b/bundle/defx.nvim/autoload/defx/init.vim @@ -0,0 +1,143 @@ +"============================================================================= +" FILE: init.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! defx#init#_initialize() abort + if exists('g:defx#_channel_id') + return + endif + + call defx#init#_channel() + + augroup defx + autocmd! + augroup END + + let g:defx#_histories = [] +endfunction +function! defx#init#_channel() abort + if !has('python3') + call defx#util#print_error( + \ 'defx requires Python3 support("+python3").') + return v:true + endif + if has('nvim') && !has('nvim-0.3.0') + call defx#util#print_error('defx requires nvim 0.3.0+.') + return v:true + endif + if !has('nvim') && v:version < 801 + call defx#util#print_error('defx requires Vim 8.1+.') + return v:true + endif + + try + if defx#util#has_yarp() + let g:defx#_yarp = yarp#py3('defx') + call g:defx#_yarp.request('_defx_init') + let g:defx#_channel_id = 1 + else + " rplugin.vim may not be loaded on VimEnter + if !exists('g:loaded_remote_plugins') + runtime! plugin/rplugin.vim + endif + + call _defx_init() + endif + catch + call defx#util#print_error(v:exception) + call defx#util#print_error(v:throwpoint) + + let python_version_check = defx#init#_python_version_check() + if python_version_check + call defx#util#print_error( + \ 'defx requires Python 3.6.1+.') + endif + + if defx#util#has_yarp() + if !has('nvim') && !exists('*neovim_rpc#serveraddr') + call defx#util#print_error( + \ 'defx requires vim-hug-neovim-rpc plugin in Vim.') + endif + + if !exists('*yarp#py3') + call defx#util#print_error( + \ 'defx requires nvim-yarp plugin.') + endif + else + call defx#util#print_error( + \ 'defx failed to load. ' + \ .'Try the :UpdateRemotePlugins command and restart Neovim. ' + \ .'See also :checkhealth.') + endif + + return v:true + endtry +endfunction +function! defx#init#_check_channel() abort + return exists('g:defx#_channel_id') +endfunction + +function! defx#init#_python_version_check() abort + python3 << EOF +import vim +import sys +vim.vars['defx#_python_version_check'] = ( + sys.version_info.major, + sys.version_info.minor, + sys.version_info.micro) < (3, 6, 1) +EOF + return g:defx#_python_version_check +endfunction +function! defx#init#_user_options() abort + return { + \ 'auto_cd': v:false, + \ 'auto_recursive_level': 0, + \ 'buffer_name': 'default', + \ 'columns': 'mark:indent:icon:filename:type', + \ 'direction': '', + \ 'ignored_files': '.*', + \ 'listed': v:false, + \ 'new': v:false, + \ 'profile': v:false, + \ 'resume': v:false, + \ 'root_marker': '[in]: ', + \ 'search': '', + \ 'session_file': '', + \ 'show_ignored_files': v:false, + \ 'split': 'no', + \ 'sort': 'filename', + \ 'toggle': v:false, + \ 'wincol': &columns / 4, + \ 'winheight': 30, + \ 'winrelative': 'editor', + \ 'winrow': &lines / 3, + \ 'winwidth': 90, + \ } +endfunction +function! s:internal_options() abort + return { + \ 'cursor': line('.'), + \ 'drives': [], + \ 'prev_bufnr': bufnr('%'), + \ 'prev_last_bufnr': bufnr('#'), + \ 'prev_winid': win_getid(), + \ 'visual_start': getpos("'<")[1], + \ 'visual_end': getpos("'>")[1], + \ } +endfunction +function! defx#init#_context(user_context) abort + let buffer_name = get(a:user_context, 'buffer_name', 'default') + let context = s:internal_options() + call extend(context, defx#init#_user_options()) + let custom = defx#custom#_get() + if has_key(custom.option, '_') + call extend(context, custom.option['_']) + endif + if has_key(custom.option, buffer_name) + call extend(context, custom.option[buffer_name]) + endif + call extend(context, a:user_context) + return context +endfunction diff --git a/bundle/defx.nvim/autoload/defx/util.vim b/bundle/defx.nvim/autoload/defx/util.vim new file mode 100644 index 000000000..d2735b839 --- /dev/null +++ b/bundle/defx.nvim/autoload/defx/util.vim @@ -0,0 +1,325 @@ +"============================================================================= +" FILE: util.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +let s:is_windows = has('win32') || has('win64') +let s:is_mac = !s:is_windows && !has('win32unix') + \ && (has('mac') || has('macunix') || has('gui_macvim') || + \ (!isdirectory('/proc') && executable('sw_vers'))) + +function! defx#util#print_error(string) abort + echohl Error | echomsg '[defx] ' + \ . defx#util#string(a:string) | echohl None +endfunction +function! defx#util#print_warning(string) abort + echohl WarningMsg | echomsg '[defx] ' + \ . defx#util#string(a:string) | echohl None +endfunction +function! defx#util#print_debug(string) abort + echomsg '[defx] ' . defx#util#string(a:string) +endfunction +function! defx#util#print_message(string) abort + echo '[defx] ' . defx#util#string(a:string) +endfunction +function! defx#util#is_windows() abort + return s:is_windows +endfunction + +function! defx#util#convert2list(expr) abort + return type(a:expr) ==# type([]) ? a:expr : [a:expr] +endfunction +function! defx#util#string(expr) abort + return type(a:expr) ==# type('') ? a:expr : string(a:expr) +endfunction +function! defx#util#split(string) abort + return split(a:string, '\s*,\s*') +endfunction + +function! defx#util#has_yarp() abort + return !has('nvim') || get(g:, 'defx#enable_yarp', 0) +endfunction + +function! defx#util#execute_path(command, path) abort + try + execute a:command fnameescape(s:expand(a:path)) + catch /^Vim\%((\a\+)\)\=:E325\|^Vim:Interrupt/ + " Ignore swap file error + catch + call defx#util#print_error(v:throwpoint) + call defx#util#print_error(v:exception) + endtry +endfunction +function! s:expand(path) abort + return s:substitute_path_separator( + \ (a:path =~# '^\~') ? fnamemodify(a:path, ':p') : + \ a:path) +endfunction +function! s:expand_complete(path) abort + return s:substitute_path_separator( + \ (a:path =~# '^\~') ? fnamemodify(a:path, ':p') : + \ (a:path =~# '^\$\h\w*') ? substitute(a:path, + \ '^\$\h\w*', '\=eval(submatch(0))', '') : + \ a:path) +endfunction +function! s:substitute_path_separator(path) abort + return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path +endfunction + +function! defx#util#call_defx(command, args) abort + let [paths, context] = defx#util#_parse_options_args(a:args) + call defx#start(paths, context) +endfunction + +function! defx#util#input(prompt, ...) abort + let text = get(a:000, 0, '') + let completion = get(a:000, 1, '') + try + if completion !=# '' + return input(a:prompt, text, completion) + else + return input(a:prompt, text) + endif + catch + " ignore the errors + return '' + endtry +endfunction +function! defx#util#confirm(msg, choices, default) abort + try + return confirm(a:msg, a:choices, a:default) + catch + " ignore the errors + endtry + + return a:default +endfunction + +function! defx#util#_parse_options_args(cmdline) abort + return s:parse_options(a:cmdline) +endfunction +function! s:re_unquoted_match(match) abort + " Don't match a:match if it is located in-between unescaped single or double + " quotes + return a:match . '\v\ze([^"' . "'" . '\\]*(\\.|"([^"\\]*\\.)*[^"\\]*"|' + \ . "'" . '([^' . "'" . '\\]*\\.)*[^' . "'" . '\\]*' . "'" . '))*[^"' + \ . "'" . ']*$' +endfunction +function! s:remove_quote_pairs(s) abort + " remove leading/ending quote pairs + let s = a:s + if s[0] ==# '"' && s[len(s) - 1] ==# '"' + let s = s[1: len(s) - 2] + elseif s[0] ==# "'" && s[len(s) - 1] ==# "'" + let s = s[1: len(s) - 2] + else + let s = substitute(a:s, '\\\(.\)', "\\1", 'g') + endif + return s +endfunction +function! s:parse_options(cmdline) abort + let args = [] + let options = {} + + " Eval + let cmdline = (a:cmdline =~# '\\\@= 0 + let options[name] = value + else + call add(args, arg) + endif + endfor + + return [args, options] +endfunction +function! s:eval_cmdline(cmdline) abort + let cmdline = '' + let prev_match = 0 + let eval_pos = match(a:cmdline, '\\\@= 0 + if eval_pos - prev_match > 0 + let cmdline .= a:cmdline[prev_match : eval_pos - 1] + endif + let prev_match = matchend(a:cmdline, + \ '\\\@= 0 + let cmdline .= a:cmdline[prev_match :] + endif + + return cmdline +endfunction + +function! defx#util#complete(arglead, cmdline, cursorpos) abort + let _ = [] + + if a:arglead =~# '^-' + " Option names completion. + let bool_options = keys(filter(copy(defx#init#_user_options()), + \ 'type(v:val) == type(v:true) || type(v:val) == type(v:false)')) + let _ += map(copy(bool_options), "'-' . tr(v:val, '_', '-')") + let string_options = keys(filter(copy(defx#init#_user_options()), + \ 'type(v:val) != type(v:true) && type(v:val) != type(v:false)')) + let _ += map(copy(string_options), "'-' . tr(v:val, '_', '-') . '='") + + " Add "-no-" option names completion. + let _ += map(copy(bool_options), "'-no-' . tr(v:val, '_', '-')") + else + let arglead = s:expand_complete(a:arglead) + " Path names completion. + let files = filter(map(glob(a:arglead . '*', v:true, v:true), + \ 's:substitute_path_separator(v:val)'), + \ 'stridx(tolower(v:val), tolower(arglead)) == 0') + let files = map(filter(files, 'isdirectory(v:val)'), + \ 's:expand_complete(v:val)') + if a:arglead =~# '^\~' + let home_pattern = '^'. s:expand_complete('~') + call map(files, "substitute(v:val, home_pattern, '~/', '')") + endif + call map(files, "escape(v:val.'/', ' \\')") + let _ += files + endif + + return uniq(sort(filter(_, 'stridx(v:val, a:arglead) == 0'))) +endfunction + +function! defx#util#has_yarp() abort + return !has('nvim') +endfunction +function! defx#util#rpcrequest(method, args, is_async) abort + if !defx#init#_check_channel() + return -1 + endif + + if defx#util#has_yarp() + if g:defx#_yarp.job_is_dead + return -1 + endif + if a:is_async + return g:defx#_yarp.notify(a:method, a:args) + else + return g:defx#_yarp.request(a:method, a:args) + endif + else + if a:is_async + return rpcnotify(g:defx#_channel_id, a:method, a:args) + else + return rpcrequest(g:defx#_channel_id, a:method, a:args) + endif + endif +endfunction + +" Open a file. +function! defx#util#open(filename) abort + let filename = fnamemodify(a:filename, ':p') + + " Detect desktop environment. + if s:is_windows + " For URI only. + " Note: + " # and % required to be escaped (:help cmdline-special) + silent execute printf( + \ '!start rundll32 url.dll,FileProtocolHandler %s', + \ escape(filename, '#%'), + \) + elseif has('win32unix') + " Cygwin. + call system(printf('%s %s', 'cygstart', + \ shellescape(filename))) + elseif executable('xdg-open') + " Linux. + call system(printf('%s %s &', 'xdg-open', + \ shellescape(filename))) + elseif exists('$KDE_FULL_SESSION') && $KDE_FULL_SESSION ==# 'true' + " KDE. + call system(printf('%s %s &', 'kioclient exec', + \ shellescape(filename))) + elseif exists('$GNOME_DESKTOP_SESSION_ID') + " GNOME. + call system(printf('%s %s &', 'gnome-open', + \ shellescape(filename))) + elseif executable('exo-open') + " Xfce. + call system(printf('%s %s &', 'exo-open', + \ shellescape(filename))) + elseif s:is_mac && executable('open') + " Mac OS. + call system(printf('%s %s &', 'open', + \ shellescape(filename))) + else + " Give up. + call defx#util#print_error('Not supported.') + endif +endfunction + +function! defx#util#cd(path) abort + if exists('*chdir') + call chdir(a:path) + else + silent execute (haslocaldir() ? 'lcd' : 'cd') fnameescape(a:path) + endif +endfunction + +function! defx#util#truncate_skipping(str, max, footer_width, separator) abort + let width = strwidth(a:str) + if width <= a:max + let ret = a:str + else + let header_width = a:max - strwidth(a:separator) - a:footer_width + let ret = s:strwidthpart(a:str, header_width) . a:separator + \ . s:strwidthpart_reverse(a:str, a:footer_width) + endif + return s:truncate(ret, a:max) +endfunction +function! s:truncate(str, width) abort + " Original function is from mattn. + " http://github.com/mattn/googlereader-vim/tree/master + + if a:str =~# '^[\x00-\x7f]*$' + return len(a:str) < a:width + \ ? printf('%-' . a:width . 's', a:str) + \ : strpart(a:str, 0, a:width) + endif + + let ret = a:str + let width = strwidth(a:str) + if width > a:width + let ret = s:strwidthpart(ret, a:width) + let width = strwidth(ret) + endif + + if width < a:width + let ret .= repeat(' ', a:width - width) + endif + + return ret +endfunction +function! s:strwidthpart(str, width) abort + let str = tr(a:str, "\t", ' ') + let vcol = a:width + 2 + return matchstr(str, '.*\%<' . (vcol < 0 ? 0 : vcol) . 'v') +endfunction +function! s:strwidthpart_reverse(str, width) abort + let str = tr(a:str, "\t", ' ') + let vcol = strwidth(str) - a:width + return matchstr(str, '\%>' . (vcol < 0 ? 0 : vcol) . 'v.*') +endfunction diff --git a/bundle/defx.nvim/autoload/health/defx.vim b/bundle/defx.nvim/autoload/health/defx.vim new file mode 100644 index 000000000..37b1069af --- /dev/null +++ b/bundle/defx.nvim/autoload/health/defx.vim @@ -0,0 +1,25 @@ +"============================================================================= +" FILE: defx.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! s:check_required_python_for_defx() abort + if has('python3') + call health#report_ok('has("python3") was successful') + else + call health#report_error('has("python3") was not successful') + endif + + if defx#init#_python_version_check() + call health#report_error('Python 3.6.1+ was successful') + else + call health#report_ok('Python 3.6.1+ was successful') + endif +endfunction + +function! health#defx#check() abort + call health#report_start('defx.nvim') + + call s:check_required_python_for_defx() +endfunction diff --git a/bundle/defx.nvim/doc/defx.txt b/bundle/defx.nvim/doc/defx.txt new file mode 100644 index 000000000..46aa1076f --- /dev/null +++ b/bundle/defx.nvim/doc/defx.txt @@ -0,0 +1,824 @@ +*defx.txt* Dark powered file explorer for neovim/Vim8. + +Version: 1.0 +Author: Shougo +License: MIT license + +CONTENTS *defx-contents* + +Introduction |defx-introduction| +Install |defx-install| +Interface |defx-interface| + Commands |defx-commands| + Functions |defx-functions| + Key mappings |defx-key-mappings| + Actions |defx-actions| + Options |defx-options| + Columns |defx-columns| + External columns |defx-external-columns| + Sources |defx-sources| +Examples |defx-examples| +FAQ |defx-faq| +Compatibility |defx-compatibility| + +============================================================================== +INTRODUCTION *defx-introduction* + +*defx* is the abbreviation of "dark powered file explorer". + +============================================================================== +INSTALL *defx-install* + +Note: defx requires Neovim 0.3.0+ or Vim8.1+ with Python3.6.1+. + +Please install nvim-yarp plugin for Vim8. +https://github.com/roxma/nvim-yarp + +Please install vim-hug-neovim-rpc plugin for Vim8. +https://github.com/roxma/vim-hug-neovim-rpc + +1. Extract the files and put them in your Neovim or .vim directory + (usually `$XDG_CONFIG_HOME/nvim/`). +2. Execute the ":UpdateRemotePlugins" if Neovim. + +If ":echo has('python3')" returns `1`, then you're done; otherwise, see below. + +You can enable Python3 interface with pip: > + + pip3 install --user pynvim + +Note: defx needs pynvim ver.0.1.8+. You need update pynvim module. +> + pip3 install --user --upgrade pynvim +< +If you want to read for pynvim/python3 interface install documentation, +you should read |provider-python| and the Wiki. +https://github.com/zchee/deoplete-jedi/wiki/Setting-up-Python-for-Neovim + +You can check the Python3 installation by |:checkhealth| command in neovim. + +============================================================================== +INTERFACE *defx-interface* + +------------------------------------------------------------------------------ +COMMANDS *defx-commands* + +:Defx [{options}] {paths} *:Defx* + Creates a new Defx buffer. + +------------------------------------------------------------------------------ +FUNCTIONS *defx-functions* + +defx#async_action({action}[, {args}]) *defx#async_action()* + Fire {action} action with {args} asynchronously. You can find + the actions list in |defx-actions|. + {args} behavior depends on {action}. + Note: It is only used to define mappings. + Note: You cannot fire the next action until the previous + action is finished. + + *defx#call_action()* +defx#call_action({action}[, {args}]) + Fire {action} action with {args}. You can find the actions + list in |defx-actions|. + {args} behavior depends on {action}. + + *defx#call_async_action()* +defx#call_async_action({action}[, {args}]) + Fire {action} action with {args} asynchronously. You can find + the actions list in |defx-actions|. + {args} behavior depends on {action}. + Note: You cannot fire the next action until the previous + action is finished. + + *defx#custom#column()* +defx#custom#column({column-name}, {option-name}, {value}) +defx#custom#column({column-name}, {dict}) + Set {column-name} column specialized variable {variable-name} + to {value}. You may specify multiple sources with the + separator "," in {column-name}. > + + call defx#custom#column('icon', { + \ 'directory_icon': '▸', + \ 'opened_icon': '▾', + \ 'root_icon': ' ', + \ }) + + call defx#custom#column('filename', { + \ 'min_width': 40, + \ 'max_width': 40, + \ }) + + call defx#custom#column('mark', { + \ 'readonly_icon': '✗', + \ 'selected_icon': '✓', + \ }) +< + *defx#custom#option()* +defx#custom#option({buffer-name}, {option-name}, {value}) +defx#custom#option({buffer-name}, {dict}) + Set {option-name} option to {value} in {buffer-name} + buffer. + If {buffer-name} is "_", the options are used for all buffers. + If {dict} is available, the key is {option-name} and the value + is {value}. + Note: The all options are in |defx-options|. However, "-" is + substituted to "_", and "-" prefix is removed. > + + call defx#custom#option('_', { + \ 'columns': 'mark:indent:icon:filename:type:size:time', + \ }) +< + *defx#custom#source()* +defx#custom#source({source-name}, {var-name}, {value}) +defx#custom#source({source-name}, {dict}) + Set {source-name} source specialized variable {variable-name} + to {value}. You may specify multiple sources with the + separator "," in {source-name}. +> + function! Root(path) abort + return fnamemodify(a:path, ':t') + endfunction + + call defx#custom#source('file', { + \ 'root': 'Root', + \}) +< +defx#do_action({action}[, {args}]) *defx#do_action()* + Fire {action} action with {args}. You can find the actions + list in |defx-actions|. + {args} behavior depends on {action}. + Note: It is only used to define mappings. + +defx#get_candidate() *defx#get_candidate()* + Returns the current cursor candidate as |Dictionary|. + +defx#get_context() *defx#get_context()* + Returns the current context as |Dictionary|. + +defx#is_directory() *defx#is_directory()* + Returns |v:true| if the current cursor candidate is directory. + + Example: > + + nnoremap + \ defx#is_directory() ? + \ defx#do_action('open_directory') : + \ defx#do_action('multi', ['drop', 'quit']) + +defx#is_opened_tree() *defx#is_opened_tree()* + Returns |v:true| if the current cursor candidate is opened + directory tree. + +defx#redraw() *defx#redraw()* + Redraw all defx windows. + +------------------------------------------------------------------------------ +KEY MAPPINGS *defx-key-mappings* + +Defx does not provide any of default key mappings. +You need to define original key mappings by |defx#do_action()|. + +------------------------------------------------------------------------------ +ACTIONS *defx-actions* + +add_session *defx-action-add_session* + Add the current directory in current sessions and save to + |defx-option-session-file|. + Note: You must set to |defx-option-session-file| save current + sessions. + + Current session feature saves below states. + + * current path + * opened tree state + + Action args: + 0. session directory path + +call *defx-action-call* + Call the function. + You can get the files path as "a:context.targets". + + Action args: + 0. function name + Note: It must be string. You cannot use |Funcref| or + |lambda|. + + Example: > + + function! Test(context) abort + echomsg string(a:context.targets) + endfunction + nnoremap f + \ defx#do_action('call', 'Test') + + " or you can use SID hack + function! s:Test(context) abort + echomsg string(a:context.targets) + endfunction + function! s:SID_PREFIX() abort + return matchstr(expand(''), + \ '\d\+_\zeSID_PREFIX$') + endfunction + let g:sid = s:SID_PREFIX() + nnoremap f + \ defx#do_action('call', g:sid.'Test') + +cd *defx-action-cd* + Change the current directory. + Note: If the action args is empty, it means the home + directory. + + Action args: + 0. new current directory path + +change_vim_cwd *change_vim_cwd* + Change current working directory to the current directory. + Note: It changes global current directory if the window has + not local current directory. If you don't like the behavior, + you need to set local current directory. + +clear_select_all *defx-action-clear_select_all* + Clear the all candidates select. + +close_tree *defx-action-close_tree* + Close the directory tree. + +copy *defx-action-copy* + Copy the selected files to defx clipboard. + +drop *defx-action-drop* + Open the file like |:drop| command. + + Action args: + 0. open command(The default is |:edit|) + +execute_command *defx-action-execute_command* + Execute the command. + + Action args: + 0. command(The default is your input) + +execute_system *defx-action-execute_system* + Execute the file by system associated command. + +move *defx-action-move* + Move the selected files to defx clipboard. + +multi *defx-action-multi* + Multiple actions. + + Action args: + 0. action 1 + 1. action 2 + ... + + Example: > + + " auto quit like behavior + nnoremap + \ defx#do_action('multi', ['drop', 'quit']) + nnoremap s + \ defx#do_action('multi', [['drop', 'split'], 'quit']) + +new_directory *defx-action-new_directory* + Create a new directory. + +new_file *defx-action-new_file* + Create a new file and directory if provided. + If the input ends with "/", it means new directory. + + *defx-action-new_multiple_files* +new_multiple_files + Create new files and directories if provided. + If the input ends with "/", it means new directory. + +open *defx-action-open* + Open the selected candidates. + Note: If the candidate is directory, it is same with + |defx-action-open_directory|. + + Action args: + 0. open command(The default is |:edit|) + +open_directory *defx-action-open_directory* + Open the directory. + + Action args: + 0. open file path(The default is the selected + directory) + +open_or_close_tree *defx-action-open_or_close_tree* + It is the same with |defx-action-open_tree| with "toggle" + arg. + Note: The action is deprecated. + +open_tree *defx-action-open_tree* + Open the directory tree. + + Action args: + 0-n. options. The supported values are: + + "nested": + enable nested directory view if it has one + directory only. + "recursive": + open the directory tree recursively. + "recursive[:{level}]": + open the directory tree recursively by + max recursive {level}. + "toggle": + close the directory tree if the directory is + opened. + + +open_tree_recursive *defx-action-open_tree_recursive* + It is the same with |defx-action-open_tree| with "recursive" + arg. + Note: The action is deprecated. + +paste *defx-action-paste* + Fire the clipboard action in the current directory. + Note: It is used after |defx-action-copy| or + |defx-action-move|. + +print *defx-action-print* + Print the filename. + +quit *defx-action-quit* + Quit the buffer. + +redraw *defx-action-redraw* + Redraw the buffer. + +repeat *defx-action-repeat* + Redraw the previous action. + +rename *defx-action-rename* + Rename the file/directory under cursor or from selected list. + Note: If you select multiple files, it will be buffer-rename + mode. + +remove *defx-action-remove* + Delete the file/directory under cursor or from selected list + completely. + Note: You cannot undo the action. + + Action args: + 0. If it is "true", suppress the confirmation. + +remove_trash *defx-action-remove_trash* + Delete the file/directory under cursor or from selected list + to trashbox. + + Note: Send2Trash module is needed for the action. + https://pypi.org/project/Send2Trash/ + + Action args: + 0. If it is "true", suppress the confirmation. + +resize *defx-action-resize* + Vertical resize and redraw the current window. + + Action args: + 0. Resized window size. + +search *defx-action-search* + Search the path. + + Action args: + 0. search the path + +toggle_columns *defx-action-toggle_columns* + Toggle the current columns. + + Action args: + 0. ":" separated defx columns. + +toggle_sort *defx-action-toggle_sort* + Toggle the sort method. + + Action args: + 0. sort method. + +toggle_ignored_files *defx-action-toggle_ignored_files* + Toggle the enable state of ignored files. + +toggle_select *defx-action-toggle_select* + Toggle the cursor candidate select. + +toggle_select_all *defx-action-toggle_select_all* + Toggle the all candidates select. + +toggle_select_visual +*defx-action-toggle_select_visual* + Toggle the visual mode selected candidates select. + +yank_path *defx-action-yank_path* + Yank the all candidates path. + +------------------------------------------------------------------------------ +OPTIONS *defx-options* + + *defx-option-no-* +-no-{option-name} + Disable {option-name} flag. + Note: If you use both {option-name} and -no-{option-name} in + the same denite buffer, it is undefined. + + *defx-option-auto-cd* +-auto-cd + Change the working directory while navigating with defx. + Note: It changes global current directory if the window has + not local current directory. If you don't like the behavior, + you need to set local current directory. + + Default: false + + *defx-option-auto-recursive-level* +-auto-recursive-level={level} + The level to expand tree automatically. + Default: 0 + + *defx-option-buffer-name* +-buffer-name={buffer-name} + Specify defx buffer name. + Default: "default" + + *defx-option-columns* +-columns={columns1:columns2,...} + Specify defx columns. + Default: "mark:indent:icon:filename:type" + + *defx-option-direction* +-direction={direction} + Specify the window direction as {direction} if + |defx-option-split| is set. + You can use "topleft" or "botright". + Default: "" + + *defx-option-ignored-files* +-ignored-files={pattern} + Specify the ignored files pattern. + The pattern is comma separated. + Default: ".*" + + *defx-option-listed* +-listed + Enable 'buflisted' option in defx buffer. + + Default: false + + *defx-option-new* +-new + Create new defx buffer. + + Default: false + + *defx-option-profile* +-profile + Enable profile feature. + Note: It is for debugging. + + Default: false + + *defx-option-resume* +-resume + Resume existing defx buffer. + Note: |defx-option-listed| is needed to resume. + + Default: false + + *defx-option-root-marker* +-root-marker={marker} + Root marker. + + Default: "[in]: " + + *defx-option-search* +-search={path} + Search the {path}. + Note: It must be full path. + + Default: "" + + *defx-option-session-file* +-session-file={path} + Session file {path}. + Note: It must be full path. + + Default: "" + + *defx-option-show-ignored-files* +-show-ignored-files + Show ignored files by default. + Default: false + + *defx-options-sort* +-sort={method} + Sort method. + If the method is upper case, the order will be reversed. + + "extension": file extension sort + "filename": file name sort + "size": file size sort + "time": file modified time sort + + Default: "filename" + + *defx-option-split* +-split={direction} + Specify the split direction. + + "vertical": Split buffer vertically + "horizontal": Split buffer horizontally + "no": No split + "tab": Create the new tab + "floating": Use neovim floating window feature + + Default: "no" + + *defx-option-toggle* +-toggle + Close defx buffer window if this defx window exists. + Default: false + + *defx-option-wincol* +-wincol={window-column} + Set the column position of the Defx window if + |defx-option-split| is "floating". + + Default: &columns / 4 + + *defx-option-winheight* +-winheight={window-height} + Set the height of the window if |defx-option-split| is + "horizontal". + + Default: 30 + + *defx-option-winrelative* +-winrelative={direction} + Specify the relative position in floating window. + |nvim_open_win()| + + Default: "editor" + + *defx-option-winrow* +-winrow={window-row} + Set the row position of the Defx window if + |defx-option-split| is "floating". + + Default: &lines / 3 + + *defx-option-winwidth* +-winwidth={window-width} + Set the width of the window if |defx-option-split| is + "vertical". + + Default: 90 + +------------------------------------------------------------------------------ +COLUMNS *defx-columns* + + *defx-column-filename* +filename File name. + + variables: + min_width the minimum width of a defx buffer + (default: 40) + max_width the maximum width of a defx buffer + If it is negative value, it means: + "winwidth -max_width / 100". + Example: "-120" max_width means 120 percent + winwidth. + (default: 100) + root_marker_highlight + the root marker highlight + (default: "Constant") + + *defx-column-icon* +icon Basic icon. + + variables: + directory_icon the closed directory icon + (default: "+") + opened_icon the opened directory icon + (default: "-") + root_icon the root directory icon + (default: " ") + + *defx-column-indent* +indent Tree indentation. + Note: It depends on |defx-column-filename|. + + variables: + indent the indent marker. + (default: " ") + + *defx-column-mark* +mark File selected mark. + + variables: + length the column length + (default: 1) + readonly_icon the readonly file icon + (default: "X") + selected_icon the selected file icon + (default: "*") + + *defx-column-size* +size File size. + + *defx-column-space* +space One space column for padding. + + *defx-column-time* +time File modified time. + + variables: + format the time format + (default: "%y.%m.%d %H:%M") + + *defx-column-type* +type File type. + + variables: + types the types definition + (default: complicated) + +EXTERNAL COLUMNS *defx-external-columns* + +git Git status. + https://github.com/kristijanhusak/defx-git + +icons Nerd font icons. + https://github.com/kristijanhusak/defx-icons + +------------------------------------------------------------------------------ +SOURCES *defx-sources* + +file File + + variables: + root root function name + Note: It must be string. You cannot use + |Funcref| or |lambda|. + (default is v:null) + +============================================================================== +DENITE SOURCES *defx-denite-sources* + + *denite-source-defx/drive* +defx/drive Gather defx drives. + + Note: You can set drives like this: +> + call defx#custom#option('_', 'drives', [ + \ expand('~/Downloads'), expand('~') + \ ]) +< + *denite-source-defx/history* +defx/history Gather defx histories. + + *denite-source-defx/session* +defx/session Gather defx sessions. + +============================================================================== +EXAMPLES *defx-examples* +> + autocmd FileType defx call s:defx_my_settings() + function! s:defx_my_settings() abort + " Define mappings + nnoremap + \ defx#do_action('open') + nnoremap c + \ defx#do_action('copy') + nnoremap m + \ defx#do_action('move') + nnoremap p + \ defx#do_action('paste') + nnoremap l + \ defx#do_action('open') + nnoremap E + \ defx#do_action('open', 'vsplit') + nnoremap P + \ defx#do_action('open', 'pedit') + nnoremap o + \ defx#do_action('open_tree', 'toggle') + nnoremap K + \ defx#do_action('new_directory') + nnoremap N + \ defx#do_action('new_file') + nnoremap M + \ defx#do_action('new_multiple_files') + nnoremap C + \ defx#do_action('toggle_columns', + \ 'mark:indent:icon:filename:type:size:time') + nnoremap S + \ defx#do_action('toggle_sort', 'time') + nnoremap d + \ defx#do_action('remove') + nnoremap r + \ defx#do_action('rename') + nnoremap ! + \ defx#do_action('execute_command') + nnoremap x + \ defx#do_action('execute_system') + nnoremap yy + \ defx#do_action('yank_path') + nnoremap . + \ defx#do_action('toggle_ignored_files') + nnoremap ; + \ defx#do_action('repeat') + nnoremap h + \ defx#do_action('cd', ['..']) + nnoremap ~ + \ defx#do_action('cd') + nnoremap q + \ defx#do_action('quit') + nnoremap + \ defx#do_action('toggle_select') . 'j' + nnoremap * + \ defx#do_action('toggle_select_all') + nnoremap j + \ line('.') == line('$') ? 'gg' : 'j' + nnoremap k + \ line('.') == 1 ? 'G' : 'k' + nnoremap + \ defx#do_action('redraw') + nnoremap + \ defx#do_action('print') + nnoremap cd + \ defx#do_action('change_vim_cwd') + endfunction +< +============================================================================== +FREQUENTLY ASKED QUESTIONS (FAQ) *defx-faq* + +Q: I want to explore the folder where the current file is. + +A: > + Defx `expand('%:p:h')` -search=`expand('%:p')` + +Q: I want to open defx window like explorer. + +A: > + Defx -split=vertical -winwidth=50 -direction=topleft + +Q: I want to open file like vimfiler explorer mode. + +A: > + nnoremap defx#do_action('drop') + +Q: I want to disable root marker. + +A: > + call defx#custom#option('_', { + \ 'root_marker': ':', + \ }) + call defx#custom#column('filename', { + \ 'root_marker_highlight': 'Ignore', + \ }) + +Q: I want to resize defx window dynamically. + +A: > + nnoremap > defx#do_action('resize', + \ defx#get_context().winwidth + 10) + nnoremap < defx#do_action('resize', + \ defx#get_context().winwidth - 10) + + +Q: I want to update defx status automatically when changing file. + +A: > + autocmd BufWritePost * call defx#redraw() + +Q: I want to open defx when running `:e /some/directory/` like netrw. + +A: https://github.com/Shougo/defx.nvim/issues/175 + +Q: I want to open file by double click. + +A: > + nnoremap <2-LeftMouse> defx#do_action('open') + +============================================================================== +COMPATIBILITY *defx-compatibility* + +2020-05-04 +* "open_tree_recursive" and "open_or_close_tree" actions are deprecated. + +2019-03-10 +* Move "directory_icon", "opened_icon" and "root_icon" to filename column. + +2019-02-14 +* Change column "highlight" method to "highlight_commands" method. + +2019-01-02 +* Remove "fnamewidth" option. + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: diff --git a/bundle/defx.nvim/plugin/defx.vim b/bundle/defx.nvim/plugin/defx.vim new file mode 100644 index 000000000..d99c472f3 --- /dev/null +++ b/bundle/defx.nvim/plugin/defx.vim @@ -0,0 +1,14 @@ +"============================================================================= +" FILE: defx.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +if exists('g:loaded_defx') + finish +endif +let g:loaded_defx = 1 + +command! -nargs=* -range -bar -complete=customlist,defx#util#complete + \ Defx + \ call defx#util#call_defx('Defx', ) diff --git a/bundle/defx.nvim/rplugin/python3/defx/__init__.py b/bundle/defx.nvim/rplugin/python3/defx/__init__.py new file mode 100644 index 000000000..4d264792c --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/__init__.py @@ -0,0 +1,82 @@ +# ============================================================================ +# FILE: __init__.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import typing + +from importlib.util import find_spec +from defx.rplugin import Rplugin + + +if find_spec('yarp'): + import vim +else: + import pynvim as vim + +Args = typing.List[typing.Any] + +if hasattr(vim, 'plugin'): + # Neovim only + + @vim.plugin + class DefxHandlers: + + def __init__(self, vim: vim.Nvim) -> None: + self._rplugin = Rplugin(vim) + + @vim.function('_defx_init', sync=True) # type: ignore + def init_channel(self, args: Args) -> None: + self._rplugin.init_channel() + + @vim.rpc_export('_defx_start', sync=True) # type: ignore + def start(self, args: Args) -> None: + self._rplugin.start(args) + + @vim.rpc_export('_defx_do_action', sync=True) # type: ignore + def do_action(self, args: Args) -> None: + self._rplugin.do_action(args) + + @vim.rpc_export('_defx_async_action', sync=False) # type: ignore + def async_action(self, args: Args) -> None: + self._rplugin.do_action(args) + + @vim.rpc_export('_defx_get_candidate', sync=True) # type: ignore + def get_candidate(self, args: Args + ) -> typing.Dict[str, typing.Union[str, bool]]: + return self._rplugin.get_candidate() + + @vim.rpc_export('_defx_get_context', sync=True) # type: ignore + def get_context(self, args: Args) -> typing.Dict[str, typing.Any]: + return self._rplugin.get_context() + + @vim.rpc_export('_defx_redraw', sync=True) # type: ignore + def redraw(self, args: Args) -> None: + return self._rplugin.redraw(self._rplugin._views) + +if find_spec('yarp'): + + global_rplugin = Rplugin(vim) + + def _defx_init() -> None: + pass + + def _defx_start(args: Args) -> None: + global_rplugin.start(args) + + def _defx_do_action(args: Args) -> None: + global_rplugin.do_action(args) + + def _defx_async_action(args: Args) -> None: + global_rplugin.do_action(args) + + def _defx_get_candidate(args: Args + ) -> typing.Dict[str, typing.Union[str, bool]]: + return global_rplugin.get_candidate() + + def _defx_get_context(args: Args) -> typing.Dict[str, typing.Any]: + return global_rplugin.get_context() + + def _defx_redraw(args: Args) -> None: + return global_rplugin.redraw(global_rplugin._views) diff --git a/bundle/defx.nvim/rplugin/python3/defx/action.py b/bundle/defx.nvim/rplugin/python3/defx/action.py new file mode 100644 index 000000000..8e27e3d4c --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/action.py @@ -0,0 +1,74 @@ +# ============================================================================ +# FILE: __init__.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from enum import auto, IntFlag +import typing + +from defx.context import Context +from defx.defx import Defx +from defx.view import View + + +class ActionAttr(IntFlag): + REDRAW = auto() + MARK = auto() + NO_TAGETS = auto() + CURSOR_TARGET = auto() + TREE = auto() + NONE = 0 + + +class ActionTable(typing.NamedTuple): + func: typing.Callable[[View, Defx, Context], None] + attr: ActionAttr = ActionAttr.NONE + + +def do_action(view: View, defx: Defx, + action_name: str, context: Context) -> bool: + """ + Do "action_name" action. + """ + actions: typing.Dict[str, ActionTable] = defx._source.kind.get_actions() + + if action_name not in actions: + return True + + action = actions[action_name] + + selected_candidates = [x for x in view._candidates if x['is_selected']] + if (selected_candidates and + ActionAttr.NO_TAGETS not in action.attr and + ActionAttr.TREE not in action.attr): + # Clear marks + for candidate in selected_candidates: + candidate['is_selected'] = False + view.redraw() + + if ActionAttr.CURSOR_TARGET in action.attr: + # Use cursor candidate only + cursor_candidate = view.get_cursor_candidate(context.cursor) + if not cursor_candidate: + return True + context = context._replace( + targets=[cursor_candidate], + ) + + action.func(view, defx, context) + + if action_name != 'repeat': + view._prev_action = action_name + + if ActionAttr.MARK in action.attr: + # Update marks + view.update_candidates() + view.redraw() + elif ActionAttr.TREE in action.attr: + view.update_candidates() + view.redraw() + elif ActionAttr.REDRAW in action.attr: + # Redraw + view.redraw(True) + return False diff --git a/bundle/defx.nvim/rplugin/python3/defx/base/__init__.py b/bundle/defx.nvim/rplugin/python3/defx/base/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/defx.nvim/rplugin/python3/defx/base/column.py b/bundle/defx.nvim/rplugin/python3/defx/base/column.py new file mode 100644 index 000000000..1cd1b9cc6 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/base/column.py @@ -0,0 +1,56 @@ +# ============================================================================ +# FILE: column.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import typing + +from abc import abstractmethod + +from defx.context import Context +from defx.util import Nvim +from defx.util import error +from defx.view import View + + +class Base: + + def __init__(self, vim: Nvim) -> None: + self.vim: Nvim = vim + self.name: str = 'base' + self.syntax_name: str = '' + self.start: int = -1 + self.end: int = -1 + self.vars: typing.Dict[str, typing.Any] = {} + self.is_start_variable: bool = False + self.is_stop_variable: bool = False + self.is_within_variable: bool = False + + def on_init(self, view: View, context: Context) -> None: + pass + + def on_redraw(self, view: View, context: Context) -> None: + pass + + def get(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + return '' + + def get_with_variable_text( + self, context: Context, variable_text: str, + candidate: typing.Dict[str, typing.Any]) -> str: + return '' + + @abstractmethod + def length(self, context: Context) -> int: + pass + + def syntaxes(self) -> typing.List[str]: + return [] + + def highlight_commands(self) -> typing.List[str]: + return [] + + def debug(self, expr: typing.Any) -> None: + error(self.vim, expr) diff --git a/bundle/defx.nvim/rplugin/python3/defx/base/kind.py b/bundle/defx.nvim/rplugin/python3/defx/base/kind.py new file mode 100644 index 000000000..7f3ea92eb --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/base/kind.py @@ -0,0 +1,332 @@ +# ============================================================================ +# FILE: kind.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import json +import re +import typing +from pathlib import Path + +from defx.action import ActionAttr +from defx.action import ActionTable +from defx.action import do_action +from defx.context import Context +from defx.defx import Defx +from defx.session import Session +from defx.util import Nvim +from defx.view import View + +_action_table: typing.Dict[str, ActionTable] = {} + +ACTION_FUNC = typing.Callable[[View, Defx, Context], None] + + +def action(name: str, attr: ActionAttr = ActionAttr.NONE + ) -> typing.Callable[[ACTION_FUNC], ACTION_FUNC]: + def wrapper(func: ACTION_FUNC) -> ACTION_FUNC: + _action_table[name] = ActionTable(func=func, attr=attr) + + def inner_wrapper(view: View, defx: Defx, context: Context) -> None: + return func(view, defx, context) + return inner_wrapper + return wrapper + + +class Base: + + def __init__(self, vim: Nvim) -> None: + self.vim = vim + self.name = 'base' + + def get_actions(self) -> typing.Dict[str, ActionTable]: + return _action_table + + +@action(name='add_session', attr=ActionAttr.NO_TAGETS) +def _add_session(view: View, defx: Defx, context: Context) -> None: + path = context.args[0] if context.args else defx._cwd + if path[-1] == '/': + # Remove the last slash + path = path[: -1] + + opened_candidates = [] if context.args else list(defx._opened_candidates) + opened_candidates.sort() + + session: Session + if path in view._sessions: + old_session = view._sessions[path] + session = Session( + name=old_session.name, path=old_session.path, + opened_candidates=opened_candidates) + else: + name = Path(path).name + session = Session( + name=name, path=path, + opened_candidates=opened_candidates) + view.print_msg(f'session "{name}" is created') + + view._sessions[session.path] = session + + _save_session(view, defx, context) + + +@action(name='call', attr=ActionAttr.REDRAW) +def _call(view: View, defx: Defx, context: Context) -> None: + """ + Call the function. + """ + function = context.args[0] if context.args else None + if not function: + return + + dict_context = context._asdict() + dict_context['cwd'] = defx._cwd + dict_context['targets'] = [ + str(x['action__path']) for x in context.targets] + view._vim.call(function, dict_context) + + +@action(name='clear_select_all', attr=ActionAttr.MARK | ActionAttr.NO_TAGETS) +def _clear_select_all(view: View, defx: Defx, context: Context) -> None: + for candidate in [x for x in view._candidates + if x['_defx_index'] == defx._index]: + candidate['is_selected'] = False + + +@action(name='close_tree', attr=ActionAttr.TREE | ActionAttr.CURSOR_TARGET) +def _close_tree(view: View, defx: Defx, context: Context) -> None: + for target in context.targets: + if target['is_directory'] and target['is_opened_tree']: + view.close_tree(target['action__path'], defx._index) + else: + view.close_tree(target['action__path'].parent, defx._index) + view.search_file(target['action__path'].parent, defx._index) + + +@action(name='delete_session', attr=ActionAttr.NO_TAGETS) +def _delete_session(view: View, defx: Defx, context: Context) -> None: + if not context.args: + return + + session_name = context.args[0] + if session_name not in view._sessions: + return + view._sessions.pop(session_name) + + _save_session(view, defx, context) + + +@action(name='load_session', attr=ActionAttr.NO_TAGETS) +def _load_session(view: View, defx: Defx, context: Context) -> None: + session_file = Path(context.session_file) + if not context.session_file or not session_file.exists(): + return + + loaded_session = json.loads(session_file.read_text()) + if 'sessions' not in loaded_session: + return + + view._sessions = {} + for path, session in loaded_session['sessions'].items(): + view._sessions[path] = Session(**session) + + view._vim.current.buffer.vars['defx#_sessions'] = [ + x._asdict() for x in view._sessions.values() + ] + + +@action(name='multi') +def _multi(view: View, defx: Defx, context: Context) -> None: + for arg in context.args: + args: typing.List[str] + if isinstance(arg, list): + args = arg + else: + args = [arg] + do_action(view, defx, args[0], context._replace(args=args[1:])) + + +@action(name='check_redraw', attr=ActionAttr.NO_TAGETS) +def _nop(view: View, defx: Defx, context: Context) -> None: + pass + + +@action(name='open_tree', attr=ActionAttr.TREE | ActionAttr.CURSOR_TARGET) +def _open_tree(view: View, defx: Defx, context: Context) -> None: + nested = False + recursive_level = 0 + toggle = False + for arg in context.args: + if arg == 'nested': + nested = True + elif arg == 'recursive': + recursive_level = 20 + elif re.search(r'recursive:\d+', arg): + recursive_level = int(arg.split(':')[1]) + elif arg == 'toggle': + toggle = True + + for target in [x for x in context.targets if x['is_directory']]: + if toggle and not target['is_directory'] or target['is_opened_tree']: + _close_tree(view, defx, context._replace(targets=[target])) + else: + view.open_tree(target['action__path'], + defx._index, nested, recursive_level) + + +@action(name='open_tree_recursive', + attr=ActionAttr.TREE | ActionAttr.CURSOR_TARGET) +def _open_tree_recursive(view: View, defx: Defx, context: Context) -> None: + level = context.args[0] if context.args else '20' + _open_tree(view, defx, context._replace( + args=context.args + ['recursive:' + level])) + + +@action(name='open_or_close_tree', + attr=ActionAttr.TREE | ActionAttr.CURSOR_TARGET) +def _open_or_close_tree(view: View, defx: Defx, context: Context) -> None: + _open_tree(view, defx, context._replace(args=context.args + ['toggle'])) + + +@action(name='print') +def _print(view: View, defx: Defx, context: Context) -> None: + for target in context.targets: + view.print_msg(str(target['action__path'])) + + +@action(name='quit', attr=ActionAttr.NO_TAGETS) +def _quit(view: View, defx: Defx, context: Context) -> None: + view.quit() + + +@action(name='redraw', attr=ActionAttr.NO_TAGETS) +def _redraw(view: View, defx: Defx, context: Context) -> None: + view.redraw(True) + + +@action(name='repeat', attr=ActionAttr.MARK) +def _repeat(view: View, defx: Defx, context: Context) -> None: + do_action(view, defx, view._prev_action, context) + + +@action(name='resize', attr=ActionAttr.NO_TAGETS) +def _resize(view: View, defx: Defx, context: Context) -> None: + if not context.args: + return + + view._context = view._context._replace(winwidth=int(context.args[0])) + view._resize_window() + view.redraw(True) + + +@action(name='save_session', attr=ActionAttr.NO_TAGETS) +def _save_session(view: View, defx: Defx, context: Context) -> None: + view._vim.current.buffer.vars['defx#_sessions'] = [ + x._asdict() for x in view._sessions.values() + ] + + if not context.session_file: + return + + session_file = Path(context.session_file) + session_file.write_text(json.dumps({ + 'version': view._session_version, + 'sessions': {x: y._asdict() for x, y in view._sessions.items()} + })) + + +@action(name='search', attr=ActionAttr.NO_TAGETS) +def _search(view: View, defx: Defx, context: Context) -> None: + if not context.args or not context.args[0]: + return + + search_path = context.args[0] + path = Path(search_path) + parents: typing.List[Path] = [] + while view.get_candidate_pos( + path, defx._index) < 0 and path.parent != path: + path = path.parent + parents.append(path) + + for parent in reversed(parents): + view.open_tree(parent, defx._index, False, 0) + + view.update_candidates() + view.redraw() + view.search_file(Path(search_path), defx._index) + + +@action(name='toggle_columns', attr=ActionAttr.REDRAW) +def _toggle_columns(view: View, defx: Defx, context: Context) -> None: + """ + Toggle the current columns. + """ + columns = (context.args[0] if context.args else '').split(':') + if not columns: + return + current_columns = [x.name for x in view._columns] + if columns == current_columns: + # Use default columns + columns = context.columns.split(':') + view._init_columns(columns) + + +@action(name='toggle_ignored_files', attr=ActionAttr.REDRAW) +def _toggle_ignored_files(view: View, defx: Defx, context: Context) -> None: + defx._enabled_ignored_files = not defx._enabled_ignored_files + + +@action(name='toggle_select', attr=ActionAttr.MARK | ActionAttr.NO_TAGETS) +def _toggle_select(view: View, defx: Defx, context: Context) -> None: + candidate = view.get_cursor_candidate(context.cursor) + if not candidate: + return + + candidate['is_selected'] = not candidate['is_selected'] + + +@action(name='toggle_select_all', attr=ActionAttr.MARK | ActionAttr.NO_TAGETS) +def _toggle_select_all(view: View, defx: Defx, context: Context) -> None: + for candidate in [x for x in view._candidates + if not x['is_root'] and + x['_defx_index'] == defx._index]: + candidate['is_selected'] = not candidate['is_selected'] + + +@action(name='toggle_select_visual', + attr=ActionAttr.MARK | ActionAttr.NO_TAGETS) +def _toggle_select_visual(view: View, defx: Defx, context: Context) -> None: + if context.visual_start <= 0 or context.visual_end <= 0: + return + + start = context.visual_start - 1 + end = min([context.visual_end, len(view._candidates)]) + for candidate in [x for x in view._candidates[start:end] + if not x['is_root'] and + x['_defx_index'] == defx._index]: + candidate['is_selected'] = not candidate['is_selected'] + + +@action(name='toggle_sort', attr=ActionAttr.MARK | ActionAttr.NO_TAGETS) +def _toggle_sort(view: View, defx: Defx, context: Context) -> None: + """ + Toggle the current sort method. + """ + sort = context.args[0] if context.args else '' + if sort == defx._sort_method: + # Use default sort method + defx._sort_method = context.sort + else: + defx._sort_method = sort + + +@action(name='yank_path') +def _yank_path(view: View, defx: Defx, context: Context) -> None: + yank = '\n'.join([str(x['action__path']) for x in context.targets]) + view._vim.call('setreg', '"', yank) + if (view._vim.call('has', 'clipboard') or + view._vim.call('has', 'xterm_clipboard')): + view._vim.call('setreg', '+', yank) + view.print_msg('Yanked:\n' + yank) diff --git a/bundle/defx.nvim/rplugin/python3/defx/base/source.py b/bundle/defx.nvim/rplugin/python3/defx/base/source.py new file mode 100644 index 000000000..0995da3cf --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/base/source.py @@ -0,0 +1,40 @@ +# ============================================================================ +# FILE: source.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import typing + +from abc import ABC, abstractmethod +from defx.context import Context +from defx.util import Nvim +from defx.util import error +from pathlib import Path + + +class Base(ABC): + + def __init__(self, vim: Nvim) -> None: + self.vim = vim + self.name = 'base' + + from defx.base.kind import Base as Kind + self.kind: Kind = Kind(self.vim) + + self.vars: typing.Dict[str, typing.Any] = {} + + @abstractmethod + def get_root_candidate( + self, context: Context, path: Path + ) -> typing.Dict[str, typing.Any]: + pass + + @abstractmethod + def gather_candidates( + self, context: Context, path: Path + ) -> typing.List[typing.Dict[str, typing.Any]]: + pass + + def debug(self, expr: typing.Any) -> None: + error(self.vim, expr) diff --git a/bundle/defx.nvim/rplugin/python3/defx/clipboard.py b/bundle/defx.nvim/rplugin/python3/defx/clipboard.py new file mode 100644 index 000000000..8883c8357 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/clipboard.py @@ -0,0 +1,22 @@ +# ============================================================================ +# FILE: clipboard.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from enum import auto, Enum +import typing + + +class ClipboardAction(Enum): + MOVE = auto() + COPY = auto() + + +class Clipboard(): + def __init__(self, + action: ClipboardAction = ClipboardAction.COPY, + candidates: + typing.List[typing.Dict[str, typing.Any]] = []) -> None: + self.action = action + self.candidates = candidates diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/__init__.py b/bundle/defx.nvim/rplugin/python3/defx/column/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/filename.py b/bundle/defx.nvim/rplugin/python3/defx/column/filename.py new file mode 100644 index 000000000..59d3738c0 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/column/filename.py @@ -0,0 +1,134 @@ +# ============================================================================ +# FILE: filename.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.base.column import Base +from defx.context import Context +from defx.util import Nvim +from defx.view import View + +import typing + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'filename' + self.vars = { + 'min_width': 40, + 'max_width': 100, + 'root_marker_highlight': 'Constant', + } + self.is_stop_variable = True + + self._current_length = 0 + self._syntaxes = [ + 'directory', + 'directory_marker', + 'hidden', + 'root', + 'root_marker', + ] + self._context: Context = Context() + self._directory_marker = '**' + self._file_marker = '||' + + def on_init(self, view: View, context: Context) -> None: + self._context = context + + def get_with_variable_text( + self, context: Context, variable_text: str, + candidate: typing.Dict[str, typing.Any]) -> str: + marker = (self._directory_marker + if candidate['is_directory'] and not candidate['is_root'] + else self._file_marker) + return self._truncate(variable_text + marker + candidate['word']) + + def length(self, context: Context) -> int: + max_fnamewidth = max([self._strwidth(x['word']) + for x in context.targets]) + max_fnamewidth += context.variable_length + max_fnamewidth += len(self._file_marker) + max_width = int(self.vars['max_width']) + if max_width < 0: + max_width = int(-max_width * context.winwidth / 100) + self._current_length = max( + min(max_fnamewidth, max_width), + int(self.vars['min_width'])) + return self._current_length + + def syntaxes(self) -> typing.List[str]: + return [self.syntax_name + '_' + x for x in self._syntaxes] + + def highlight_commands(self) -> typing.List[str]: + commands: typing.List[str] = [] + + directory_marker = self.vim.call( + 'escape', self._directory_marker, r'~/\.^$[]*') + commands.append( + r'syntax match {0}_{1} /{2}/ conceal contained ' + 'containedin={0}_directory'.format( + self.syntax_name, 'directory_marker', directory_marker)) + commands.append( + r'syntax match {0}_{1} /{2}\%(.{3}[{4}/]\)\+/ ' + 'contained containedin={0}'.format( + self.syntax_name, 'directory', directory_marker, r'\{-}', + '\\' if self.vim.call('defx#util#is_windows') else '')) + + file_marker = self.vim.call( + 'escape', self._file_marker, r'~/\.^$[]*') + commands.append( + r'syntax match {0}_{1} /{2}/ conceal contained ' + 'containedin={0}_file'.format( + self.syntax_name, 'file_marker', file_marker)) + commands.append( + r'syntax match {0}_{1} /{2}.{3}/ ' + 'contained containedin={0}'.format( + self.syntax_name, 'file', file_marker, r'\{-}')) + + root_marker = self.vim.call( + 'escape', self._context.root_marker, r'~/\.^$[]*') + commands.append( + r'syntax match {0}_{1} /{2}/ contained ' + 'containedin={0}_root'.format( + self.syntax_name, 'root_marker', root_marker)) + commands.append( + r'syntax match {0}_{1} /{2}.*/ contained ' + 'containedin={0}'.format( + self.syntax_name, 'root', root_marker)) + + commands.append( + 'highlight default link {}_{} {}'.format( + self.syntax_name, 'directory', 'PreProc')) + commands.append( + 'highlight default link {}_{} {}'.format( + self.syntax_name, 'hidden', 'Comment')) + commands.append( + 'highlight default link {}_{} {}'.format( + self.syntax_name, 'root_marker', + self.vars['root_marker_highlight'])) + commands.append( + 'highlight default link {}_{} {}'.format( + self.syntax_name, 'root', 'Identifier')) + + return commands + + def _strwidth(self, word: str) -> int: + return (int(self.vim.call('strwidth', word)) + if len(word) != len(bytes(word, 'utf-8', + 'surrogatepass')) else len(word)) + + def _truncate(self, word: str) -> str: + width = self._strwidth(word) + max_length = self._current_length + if (width > max_length or + len(word) != len(bytes(word, 'utf-8', 'surrogatepass'))): + return str(self.vim.call( + 'defx#util#truncate_skipping', + word, max_length, int(max_length / 3), '...')) + + return word + ' ' * (max_length - width) diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/icon.py b/bundle/defx.nvim/rplugin/python3/defx/column/icon.py new file mode 100644 index 000000000..d72952e84 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/column/icon.py @@ -0,0 +1,68 @@ +# ============================================================================ +# FILE: icon.py +# AUTHOR: GuoPan Zhao +# Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.base.column import Base +from defx.context import Context +from defx.util import Nvim + +import typing + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'icon' + self.vars = { + 'length': 1, + 'directory_icon': '+', + 'opened_icon': '-', + 'root_icon': ' ', + } + self._syntaxes = [ + 'directory_icon', + 'opened_icon', + 'root_icon', + ] + + def get(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + icon: str = ' ' + if candidate['is_opened_tree']: + icon = self.vars['opened_icon'] + elif candidate['is_root']: + icon = self.vars['root_icon'] + elif candidate['is_directory']: + icon = self.vars['directory_icon'] + + return icon + + def length(self, context: Context) -> int: + return typing.cast(int, self.vars['length']) + + def syntaxes(self) -> typing.List[str]: + return [self.syntax_name + '_' + x for x in self._syntaxes] + + def highlight_commands(self) -> typing.List[str]: + commands: typing.List[str] = [] + for icon, highlight in { + 'directory': 'Special', + 'opened': 'Special', + 'root': 'Identifier', + }.items(): + commands.append( + ('syntax match {0}_{1}_icon /[{2}]{3}/ ' + + 'contained containedin={0}').format( + self.syntax_name, icon, self.vars[icon + '_icon'], + ' ' if self.is_within_variable else '' + )) + commands.append( + 'highlight default link {}_{}_icon {}'.format( + self.syntax_name, icon, highlight)) + + return commands diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/indent.py b/bundle/defx.nvim/rplugin/python3/defx/column/indent.py new file mode 100644 index 000000000..f6577cc77 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/column/indent.py @@ -0,0 +1,31 @@ +# ============================================================================ +# FILE: indent.py +# AUTHOR: GuoPan Zhao +# Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.base.column import Base +from defx.context import Context +from defx.util import Nvim + +import typing + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'indent' + self.vars = { + 'indent': ' ', + } + self.is_start_variable = True + + def get(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + return str(self.vars['indent'] * candidate['level']) + + def length(self, context: Context) -> int: + return int(max([x['level'] for x in context.targets])) diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/mark.py b/bundle/defx.nvim/rplugin/python3/defx/column/mark.py new file mode 100644 index 000000000..7d9f6c868 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/column/mark.py @@ -0,0 +1,61 @@ +# ============================================================================ +# FILE: mark.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.base.column import Base +from defx.context import Context +from defx.util import Nvim + +import os +import typing + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'mark' + self.vars = { + 'length': 1, + 'readonly_icon': 'X', + 'selected_icon': '*', + } + self._syntaxes = [ + 'directory', + 'opened', + 'readonly', + 'selected', + ] + + def get(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + icon: str = ' ' * self.vars['length'] + if candidate['is_selected']: + icon = self.vars['selected_icon'] + elif not os.access(str(candidate['action__path']), os.W_OK): + icon = self.vars['readonly_icon'] + return icon + + def length(self, context: Context) -> int: + return typing.cast(int, self.vars['length']) + + def syntaxes(self) -> typing.List[str]: + return [self.syntax_name + '_' + x for x in self._syntaxes] + + def highlight_commands(self) -> typing.List[str]: + commands: typing.List[str] = [] + for icon, highlight in { + 'readonly': 'Comment', + 'selected': 'Statement', + }.items(): + commands.append( + ('syntax match {0}_{1} /[{2}]/ ' + + 'contained containedin={0}').format( + self.syntax_name, icon, self.vars[icon + '_icon'])) + commands.append( + 'highlight default link {}_{} {}'.format( + self.syntax_name, icon, highlight)) + return commands diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/size.py b/bundle/defx.nvim/rplugin/python3/defx/column/size.py new file mode 100644 index 000000000..ae67bc948 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/column/size.py @@ -0,0 +1,47 @@ +# ============================================================================ +# FILE: size.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.base.column import Base +from defx.context import Context +from defx.util import Nvim, readable + +import typing + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'size' + + def get(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + path = candidate['action__path'] + if not readable(path) or path.is_dir(): + return ' ' * 9 + size = self._get_size(path.stat().st_size) + return '{:>6s}{:>3s}'.format(size[0], size[1]) + + def _get_size(self, size: float) -> typing.Tuple[str, str]: + multiple = 1024 + suffixes = ['KB', 'MB', 'GB', 'TB'] + if size < multiple: + return (str(size), 'B') + for suffix in suffixes: + size /= multiple + if size < multiple: + return ('{:.1f}'.format(size), suffix) + return ('INF', '') + + def length(self, context: Context) -> int: + return 9 + + def highlight_commands(self) -> typing.List[str]: + commands: typing.List[str] = [] + commands.append( + f'highlight default link {self.syntax_name} Constant') + return commands diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/space.py b/bundle/defx.nvim/rplugin/python3/defx/column/space.py new file mode 100644 index 000000000..2a0150951 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/column/space.py @@ -0,0 +1,26 @@ +# ============================================================================ +# FILE: space.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.base.column import Base +from defx.context import Context +from defx.util import Nvim + +import typing + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'space' + + def get(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + return ' ' + + def length(self, context: Context) -> int: + return 1 diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/time.py b/bundle/defx.nvim/rplugin/python3/defx/column/time.py new file mode 100644 index 000000000..9a6f60b55 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/column/time.py @@ -0,0 +1,46 @@ +# ============================================================================ +# FILE: time.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.base.column import Base +from defx.context import Context +from defx.util import Nvim, readable +from defx.view import View + +import time +import typing + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'time' + self._length = 0 + self.vars = { + 'format': '%y.%m.%d %H:%M', + } + + def on_init(self, view: View, context: Context) -> None: + self._length = self.vim.call('strwidth', + time.strftime(self.vars['format'])) + + def get(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + path = candidate['action__path'] + if not readable(path): + return str(' ' * self._length) + return time.strftime(self.vars['format'], + time.localtime(path.stat().st_mtime)) + + def length(self, context: Context) -> int: + return self._length + + def highlight_commands(self) -> typing.List[str]: + commands: typing.List[str] = [] + commands.append( + f'highlight default link {self.syntax_name} Identifier') + return commands diff --git a/bundle/defx.nvim/rplugin/python3/defx/column/type.py b/bundle/defx.nvim/rplugin/python3/defx/column/type.py new file mode 100644 index 000000000..66d2b9f41 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/column/type.py @@ -0,0 +1,74 @@ +# ============================================================================ +# FILE: type.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.base.column import Base +from defx.context import Context +from defx.util import Nvim +from defx.view import View + +import re +import typing + + +class Column(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'type' + types = [ + { + 'name': 'text', 'globs': ['*.txt'], + 'icon': '[T]', 'highlight': 'Constant' + }, + { + 'name': 'image', 'globs': ['*.jpg'], + 'icon': '[I]', 'highlight': 'Type' + }, + { + 'name': 'archive', 'globs': ['*.zip'], + 'icon': '[A]', 'highlight': 'Special' + }, + { + 'name': 'executable', 'globs': ['*.exe'], + 'icon': '[X]', 'highlight': 'Statement' + }, + ] + self.vars = { + 'types': types, + } + self._length: int = 0 + + def on_init(self, view: View, context: Context) -> None: + self._length = max([self.vim.call('strwidth', x['icon']) + for x in self.vars['types']]) + + def get(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + for t in self.vars['types']: + for glob in t['globs']: + if candidate['action__path'].match(glob): + return str(t['icon']) + return ' ' * self._length + + def length(self, context: Context) -> int: + return self._length + + def syntaxes(self) -> typing.List[str]: + return [self.syntax_name + '_' + x['name'] for x + in self.vars['types']] + + def highlight_commands(self) -> typing.List[str]: + commands: typing.List[str] = [] + for t in self.vars['types']: + commands.append( + ('syntax match {0}_{1} /{2}/ ' + + 'contained containedin={0}').format( + self.syntax_name, t['name'], re.escape(t['icon']))) + commands.append( + 'highlight default link {}_{} {}'.format( + self.syntax_name, t['name'], t['highlight'])) + return commands diff --git a/bundle/defx.nvim/rplugin/python3/defx/context.py b/bundle/defx.nvim/rplugin/python3/defx/context.py new file mode 100644 index 000000000..a2ff6d06d --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/context.py @@ -0,0 +1,42 @@ +# ============================================================================ +# FILE: context.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import typing + + +class Context(typing.NamedTuple): + args: typing.List[str] = [] + auto_cd: bool = False + auto_recursive_level: int = 0 + buffer_name: str = 'default' + columns: str = '' + cursor: int = 0 + direction: str = '' + drives: typing.List[str] = [] + ignored_files: str = '' + listed: bool = False + new: bool = False + prev_bufnr: int = 0 + prev_last_bufnr: int = 0 + prev_winid: int = 0 + profile: bool = False + resume: bool = False + root_marker: str = '' + search: str = '' + session_file: str = '' + sort: str = '' + show_ignored_files: bool = False + split: str = 'no' + toggle: bool = False + targets: typing.List[typing.Dict[str, typing.Any]] = [] + variable_length: int = 0 + visual_start: int = 0 + visual_end: int = 0 + wincol: int = 0 + winheight: int = 0 + winrelative: str = 'editor' + winrow: int = 0 + winwidth: int = 0 diff --git a/bundle/defx.nvim/rplugin/python3/defx/defx.py b/bundle/defx.nvim/rplugin/python3/defx/defx.py new file mode 100644 index 000000000..db7a25f81 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/defx.py @@ -0,0 +1,127 @@ +# ============================================================================ +# FILE: defx.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import typing + +from defx.source.file import Source as File +from defx.context import Context +from defx.sort import sort +from defx.util import Nvim +from defx.util import cd, error +from pathlib import Path + + +Candidate = typing.Dict[str, typing.Any] + + +class Defx(object): + + def __init__(self, vim: Nvim, context: Context, + cwd: str, index: int) -> None: + self._vim = vim + self._context = context + self._cwd = self._vim.call('getcwd') + self.cd(cwd) + self._source: File = File(self._vim) + self._index = index + self._enabled_ignored_files = not context.show_ignored_files + self._ignored_files = context.ignored_files.split(',') + self._cursor_history: typing.Dict[str, Path] = {} + self._sort_method: str = self._context.sort + self._mtime: int = -1 + self._opened_candidates: typing.Set[str] = set() + self._selected_candidates: typing.Set[str] = set() + + self._init_source() + + def _init_source(self) -> None: + custom = self._vim.call('defx#custom#_get')['source'] + name = self._source.name + if name in custom: + self._source.vars.update(custom[name]) + + def debug(self, expr: typing.Any) -> None: + error(self._vim, expr) + + def cd(self, path: str) -> None: + self._cwd = str(Path(self._cwd).joinpath(path)) + + if self._context.auto_cd: + cd(self._vim, path) + + def get_root_candidate(self) -> Candidate: + """ + Returns root candidate + """ + root = self._source.get_root_candidate(self._context, Path(self._cwd)) + root['is_root'] = True + root['is_opened_tree'] = False + root['is_selected'] = False + root['level'] = 0 + root['word'] = self._context.root_marker + root['word'] + + return root + + def tree_candidates( + self, path: str, base_level: int, max_level: int + ) -> typing.List[Candidate]: + gathered_candidates = self.gather_candidates_recursive( + path, base_level, max_level) + + if self._opened_candidates: + candidates = [] + for candidate in gathered_candidates: + candidates.append(candidate) + candidate['level'] = base_level + candidate_path = str(candidate['action__path']) + + if (candidate_path in self._opened_candidates and + not candidate['is_opened_tree']): + candidate['is_opened_tree'] = True + candidates += self.tree_candidates( + candidate_path, base_level + 1, max_level) + else: + candidates = gathered_candidates + + return candidates + + def gather_candidates_recursive( + self, path: str, base_level: int, max_level: int + ) -> typing.List[Candidate]: + + candidates = self._gather_candidates(path, base_level) + if base_level >= max_level: + return candidates + + ret = [] + for candidate in candidates: + ret.append(candidate) + if candidate['is_directory']: + candidate['is_opened_tree'] = True + ret += self.gather_candidates_recursive( + str(candidate['action__path']), base_level + 1, max_level) + return ret + + def _gather_candidates( + self, path: str, base_level: int = 0) -> typing.List[Candidate]: + """ + Returns file candidates + """ + candidates = self._source.gather_candidates( + self._context, Path(path)) + + if self._enabled_ignored_files: + for glob in self._ignored_files: + candidates = [x for x in candidates + if not x['action__path'].match(glob)] + + for candidate in candidates: + candidate['is_opened_tree'] = False + candidate['is_root'] = False + candidate['is_selected'] = False + candidate['level'] = base_level + + return sort(self._sort_method, candidates) diff --git a/bundle/defx.nvim/rplugin/python3/defx/kind/__init__.py b/bundle/defx.nvim/rplugin/python3/defx/kind/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/defx.nvim/rplugin/python3/defx/kind/file.py b/bundle/defx.nvim/rplugin/python3/defx/kind/file.py new file mode 100644 index 000000000..0ccd9499b --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/kind/file.py @@ -0,0 +1,481 @@ +# ============================================================================ +# FILE: file.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import copy +import importlib +from pathlib import Path +import shutil +import time +import typing + +from defx.action import ActionAttr +from defx.action import ActionTable +from defx.base.kind import Base +from defx.clipboard import ClipboardAction +from defx.context import Context +from defx.defx import Defx +from defx.util import cd, cwd_input, confirm, error +from defx.util import readable, Nvim +from defx.view import View + +_action_table: typing.Dict[str, ActionTable] = {} + +ACTION_FUNC = typing.Callable[[View, Defx, Context], None] + + +def action(name: str, attr: ActionAttr = ActionAttr.NONE + ) -> typing.Callable[[ACTION_FUNC], ACTION_FUNC]: + def wrapper(func: ACTION_FUNC) -> ACTION_FUNC: + _action_table[name] = ActionTable(func=func, attr=attr) + + def inner_wrapper(view: View, defx: Defx, context: Context) -> None: + return func(view, defx, context) + return inner_wrapper + return wrapper + + +class Kind(Base): + + def __init__(self, vim: Nvim) -> None: + self.vim = vim + self.name = 'file' + + def get_actions(self) -> typing.Dict[str, ActionTable]: + actions = copy.copy(super().get_actions()) + actions.update(_action_table) + return actions + + +def check_overwrite(view: View, dest: Path, src: Path) -> Path: + s_stat = src.stat() + s_mtime = s_stat.st_mtime + view.print_msg(f' src: {src} {s_stat.st_size} bytes') + view.print_msg(f' {time.strftime("%c", time.localtime(s_mtime))}') + d_stat = dest.stat() + d_mtime = d_stat.st_mtime + view.print_msg(f'dest: {dest} {d_stat.st_size} bytes') + view.print_msg(f' {time.strftime("%c", time.localtime(d_mtime))}') + + choice: int = view._vim.call('defx#util#confirm', + f'{dest} already exists. Overwrite?', + '&Force\n&No\n&Rename\n&Time\n&Underbar', 0) + ret: Path = Path('') + if choice == 1: + ret = dest + elif choice == 2: + ret = Path('') + elif choice == 3: + ret = Path(view._vim.call('input', f'{src} -> ', str(dest), + ('dir' if src.is_dir() else 'file'))) + elif choice == 4 and d_mtime < s_mtime: + ret = src + elif choice == 5: + ret = Path(str(dest) + '_') + return ret + + +@action(name='cd') +def _cd(view: View, defx: Defx, context: Context) -> None: + """ + Change the current directory. + """ + path = Path(context.args[0]) if context.args else Path.home() + path = Path(defx._cwd).joinpath(path).resolve() + if not readable(path) or not path.is_dir(): + error(view._vim, f'{path} is not readable directory') + return + + prev_cwd = defx._cwd + view.cd(defx, str(path), context.cursor) + if context.args and context.args[0] == '..': + view.search_file(Path(prev_cwd), defx._index) + + +@action(name='change_vim_cwd', attr=ActionAttr.NO_TAGETS) +def _change_vim_cwd(view: View, defx: Defx, context: Context) -> None: + """ + Change the current working directory. + """ + cd(view._vim, defx._cwd) + + +@action(name='check_redraw', attr=ActionAttr.NO_TAGETS) +def _check_redraw(view: View, defx: Defx, context: Context) -> None: + root = defx.get_root_candidate()['action__path'] + if not root.exists(): + return + mtime = root.stat().st_mtime + if mtime != defx._mtime: + view.redraw(True) + + +@action(name='copy') +def _copy(view: View, defx: Defx, context: Context) -> None: + if not context.targets: + return + + message = 'Copy to the clipboard: {}'.format( + str(context.targets[0]['action__path']) + if len(context.targets) == 1 + else str(len(context.targets)) + ' files') + view.print_msg(message) + + view._clipboard.action = ClipboardAction.COPY + view._clipboard.candidates = context.targets + + +@action(name='drop') +def _drop(view: View, defx: Defx, context: Context) -> None: + """ + Open like :drop. + """ + cwd = view._vim.call('getcwd') + command = context.args[0] if context.args else 'edit' + + for target in context.targets: + path = target['action__path'] + + if path.is_dir(): + view.cd(defx, str(path), context.cursor) + continue + + bufnr = view._vim.call('bufnr', f'^{path}$') + winids = view._vim.call('win_findbuf', bufnr) + + if winids: + view._vim.call('win_gotoid', winids[0]) + else: + if context.prev_winid != view._winid and view._vim.call( + 'win_id2win', context.prev_winid): + view._vim.call('win_gotoid', context.prev_winid) + else: + view._vim.command('wincmd w') + try: + path = path.relative_to(cwd) + except ValueError: + pass + view._vim.call('defx#util#execute_path', command, str(path)) + + +@action(name='execute_command', attr=ActionAttr.NO_TAGETS) +def _execute_command(view: View, defx: Defx, context: Context) -> None: + """ + Execute the command. + """ + save_cwd = view._vim.call('getcwd') + cd(view._vim, defx._cwd) + + command = context.args[0] if context.args else view._vim.call( + 'input', 'Command: ', '', 'shellcmd') + + output = view._vim.call('system', command) + if output: + view.print_msg(output) + + cd(view._vim, save_cwd) + + +@action(name='execute_system') +def _execute_system(view: View, defx: Defx, context: Context) -> None: + """ + Execute the file by system associated command. + """ + for target in context.targets: + view._vim.call('defx#util#open', str(target['action__path'])) + + +@action(name='move') +def _move(view: View, defx: Defx, context: Context) -> None: + if not context.targets: + return + + message = 'Move to the clipboard: {}'.format( + str(context.targets[0]['action__path']) + if len(context.targets) == 1 + else str(len(context.targets)) + ' files') + view.print_msg(message) + + view._clipboard.action = ClipboardAction.MOVE + view._clipboard.candidates = context.targets + + +@action(name='new_directory') +def _new_directory(view: View, defx: Defx, context: Context) -> None: + """ + Create a new directory. + """ + candidate = view.get_cursor_candidate(context.cursor) + if not candidate: + return + + if candidate['is_opened_tree'] or candidate['is_root']: + cwd = str(candidate['action__path']) + else: + cwd = str(Path(candidate['action__path']).parent) + + new_filename = cwd_input( + view._vim, cwd, + 'Please input a new directory name: ', '', 'file') + if not new_filename: + return + filename = Path(cwd).joinpath(new_filename) + + if not filename: + return + if filename.exists(): + error(view._vim, f'{filename} already exists') + return + + filename.mkdir(parents=True) + view.redraw(True) + view.search_file(filename, defx._index) + + +@action(name='new_file') +def _new_file(view: View, defx: Defx, context: Context) -> None: + """ + Create a new file and it's parent directories. + """ + candidate = view.get_cursor_candidate(context.cursor) + if not candidate: + return + + if candidate['is_opened_tree'] or candidate['is_root']: + cwd = str(candidate['action__path']) + else: + cwd = str(Path(candidate['action__path']).parent) + + new_filename = cwd_input( + view._vim, cwd, + 'Please input a new filename: ', '', 'file') + if not new_filename: + return + isdir = new_filename[-1] == '/' + filename = Path(cwd).joinpath(new_filename) + + if not filename: + return + if filename.exists(): + error(view._vim, f'{filename} already exists') + return + + if isdir: + filename.mkdir(parents=True) + else: + filename.parent.mkdir(parents=True, exist_ok=True) + filename.touch() + + view.redraw(True) + view.search_file(filename, defx._index) + + +@action(name='new_multiple_files') +def _new_multiple_files(view: View, defx: Defx, context: Context) -> None: + """ + Create multiple files. + """ + candidate = view.get_cursor_candidate(context.cursor) + if not candidate: + return + + if candidate['is_opened_tree'] or candidate['is_root']: + cwd = str(candidate['action__path']) + else: + cwd = str(Path(candidate['action__path']).parent) + + save_cwd = view._vim.call('getcwd') + cd(view._vim, cwd) + + str_filenames: str = view._vim.call( + 'input', 'Please input new filenames: ', '', 'file') + cd(view._vim, save_cwd) + + if not str_filenames: + return None + + for name in str_filenames.split(): + is_dir = name[-1] == '/' + + filename = Path(cwd).joinpath(name) + if filename.exists(): + error(view._vim, f'{filename} already exists') + continue + + if is_dir: + filename.mkdir(parents=True) + else: + if not filename.parent.exists(): + filename.parent.mkdir(parents=True) + filename.touch() + + view.redraw(True) + view.search_file(filename, defx._index) + + +@action(name='open') +def _open(view: View, defx: Defx, context: Context) -> None: + """ + Open the file. + """ + cwd = view._vim.call('getcwd') + command = context.args[0] if context.args else 'edit' + for target in context.targets: + path = target['action__path'] + + if path.is_dir(): + view.cd(defx, str(path), context.cursor) + continue + + try: + path = path.relative_to(cwd) + except ValueError: + pass + view._vim.call('defx#util#execute_path', command, str(path)) + + +@action(name='open_directory') +def _open_directory(view: View, defx: Defx, context: Context) -> None: + """ + Open the directory. + """ + if context.args: + path = Path(context.args[0]) + else: + for target in context.targets: + path = target['action__path'] + + if path.is_dir(): + view.cd(defx, str(path), context.cursor) + + +@action(name='paste', attr=ActionAttr.NO_TAGETS) +def _paste(view: View, defx: Defx, context: Context) -> None: + candidate = view.get_cursor_candidate(context.cursor) + if not candidate: + return + + if candidate['is_opened_tree'] or candidate['is_root']: + cwd = str(candidate['action__path']) + else: + cwd = str(Path(candidate['action__path']).parent) + + action = view._clipboard.action + dest = None + for index, candidate in enumerate(view._clipboard.candidates): + path = candidate['action__path'] + dest = Path(cwd).joinpath(path.name) + if dest.exists(): + overwrite = check_overwrite(view, dest, path) + if overwrite == Path(''): + continue + dest = overwrite + + if path == dest: + continue + + view.print_msg( + f'[{index + 1}/{len(view._clipboard.candidates)}] {path}') + if action == ClipboardAction.COPY: + if path.is_dir(): + shutil.copytree(str(path), dest) + else: + shutil.copy2(str(path), dest) + elif action == ClipboardAction.MOVE: + shutil.move(str(path), cwd) + view._vim.command('redraw') + view._vim.command('echo') + + view.redraw(True) + if dest: + view.search_file(dest, defx._index) + + +@action(name='remove', attr=ActionAttr.REDRAW) +def _remove(view: View, defx: Defx, context: Context) -> None: + """ + Delete the file or directory. + """ + if not context.targets: + return + + force = context.args[0] == 'force' if context.args else False + if not force: + message = 'Are you sure you want to delete {}?'.format( + str(context.targets[0]['action__path']) + if len(context.targets) == 1 + else str(len(context.targets)) + ' files') + if not confirm(view._vim, message): + return + + for target in context.targets: + path = target['action__path'] + + if path.is_dir(): + shutil.rmtree(str(path)) + else: + path.unlink() + + +@action(name='remove_trash') +def _remove_trash(view: View, defx: Defx, context: Context) -> None: + """ + Delete the file or directory. + """ + if not context.targets: + return + + if not importlib.util.find_spec('send2trash'): + error(view._vim, '"Send2Trash" is not installed') + return + + force = context.args[0] == 'force' if context.args else False + if not force: + message = 'Are you sure you want to delete {}?'.format( + str(context.targets[0]['action__path']) + if len(context.targets) == 1 + else str(len(context.targets)) + ' files') + if not confirm(view._vim, message): + return + + import send2trash + for target in context.targets: + send2trash.send2trash(str(target['action__path'])) + view.redraw(True) + + +@action(name='rename') +def _rename(view: View, defx: Defx, context: Context) -> None: + """ + Rename the file or directory. + """ + + if len(context.targets) > 1: + # ex rename + view._vim.call('defx#exrename#create_buffer', + [{'action__path': str(x['action__path'])} + for x in context.targets], + {'buffer_name': 'defx'}) + return + + for target in context.targets: + old = target['action__path'] + new_filename = cwd_input( + view._vim, defx._cwd, + f'Old name: {old}\nNew name: ', str(old), 'file') + view._vim.command('redraw') + if not new_filename: + return + new = Path(defx._cwd).joinpath(new_filename) + if not new or new == old: + continue + if str(new).lower() != str(old).lower() and new.exists(): + error(view._vim, f'{new} already exists') + continue + + old.rename(new) + + view.redraw(True) + view.search_file(new, defx._index) diff --git a/bundle/defx.nvim/rplugin/python3/defx/rplugin.py b/bundle/defx.nvim/rplugin/python3/defx/rplugin.py new file mode 100644 index 000000000..c875bb491 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/rplugin.py @@ -0,0 +1,74 @@ +# ============================================================================ +# FILE: rplugin.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import typing + +from defx.clipboard import Clipboard +from defx.view import View +from defx.util import Nvim + + +class Rplugin: + + def __init__(self, vim: Nvim) -> None: + self._vim = vim + self._views: typing.List[View] = [] + self._clipboard = Clipboard() + + def init_channel(self) -> None: + self._vim.vars['defx#_channel_id'] = self._vim.channel_id + + def start(self, args: typing.List[typing.Any]) -> None: + [paths, context] = args + views = [x for x in self._views + if context['buffer_name'] == x._context.buffer_name] + if not views or context['new']: + view = View(self._vim, len(self._views)) + views = [view] + self._views.append(view) + views[0].init(paths, context, self._clipboard) + + def do_action(self, args: typing.List[typing.Any]) -> None: + views = [x for x in self._views + if x._bufnr == self._vim.current.buffer.number] + if not views: + return + view = views[0] + + prev_paths = [x._cwd for x in view._defxs] + prev_candidates = view._candidates + + view.do_action(args[0], args[1], args[2]) + + paths = [x._cwd for x in view._defxs] + if paths == prev_paths and view._candidates != prev_candidates: + self.redraw([x for x in self._views if x != view]) + + def get_candidate(self) -> typing.Dict[str, typing.Union[str, bool]]: + cursor = self._vim.call('line', '.') + for view in [x for x in self._views + if x._bufnr == self._vim.current.buffer.number]: + candidate = view.get_cursor_candidate(cursor) + return { + 'word': candidate['word'], + 'is_directory': candidate['is_directory'], + 'is_opened_tree': candidate['is_opened_tree'], + 'level': candidate['level'], + 'action__path': str(candidate['action__path']), + } + return {} + + def get_context(self) -> typing.Dict[str, typing.Any]: + for view in [x for x in self._views + if x._bufnr == self._vim.current.buffer.number]: + return view._context._asdict() + return {} + + def redraw(self, views: typing.List[View]) -> None: + call = self._vim.call + for view in [x for x in views + if call('bufwinnr', x._bufnr) > 0]: + view.redraw(True) diff --git a/bundle/defx.nvim/rplugin/python3/defx/session.py b/bundle/defx.nvim/rplugin/python3/defx/session.py new file mode 100644 index 000000000..90e2e88ba --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/session.py @@ -0,0 +1,13 @@ +# ============================================================================ +# FILE: session.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import typing + + +class Session(typing.NamedTuple): + name: str = '' + path: str = '' + opened_candidates: typing.List[str] = [] diff --git a/bundle/defx.nvim/rplugin/python3/defx/sort.py b/bundle/defx.nvim/rplugin/python3/defx/sort.py new file mode 100644 index 000000000..d8c80742a --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/sort.py @@ -0,0 +1,75 @@ +# ============================================================================ +# FILE: sort.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import re +import typing + +from defx.util import readable + + +def sort( + method: str, candidates: typing.List[typing.Dict[str, typing.Any]] +) -> typing.List[typing.Dict[str, typing.Any]]: + dirs = _sort_method( + method, [x for x in candidates if x['is_directory']]) + files = _sort_method( + method, [x for x in candidates if not x['is_directory']]) + return dirs + files + + +def _sort_method( + method: str, candidates: typing.List[typing.Dict[str, typing.Any]] +) -> typing.List[typing.Dict[str, typing.Any]]: + key = method.lower() + if key not in SORT_METHODS: + return candidates + + candidates = SORT_METHODS[key](candidates) + if re.match(r'[A-Z]', method): + candidates = list(reversed(candidates)) + return candidates + + +def _extension( + candidates: typing.List[typing.Dict[str, typing.Any]] +) -> typing.List[typing.Dict[str, typing.Any]]: + return sorted(candidates, key=lambda x: x['action__path'].suffix) + + +def _filename( + candidates: typing.List[typing.Dict[str, typing.Any]] +) -> typing.List[typing.Dict[str, typing.Any]]: + + def numeric_key(v: str) -> typing.List[typing.Any]: + keys = re.split(r'(\d+)', v) + keys[1::2] = [int(x) for x in keys[1::2]] # type: ignore + return keys + + return sorted(candidates, key=lambda x: numeric_key(x['word'].lower())) + + +def _size( + candidates: typing.List[typing.Dict[str, typing.Any]] +) -> typing.List[typing.Dict[str, typing.Any]]: + return sorted(candidates, key=(lambda x: + x['action__path'].stat().st_size + if readable(x['action__path']) else -1)) + + +def _time( + candidates: typing.List[typing.Dict[str, typing.Any]] +) -> typing.List[typing.Dict[str, typing.Any]]: + return sorted(candidates, key=(lambda x: + x['action__path'].stat().st_mtime + if readable(x['action__path']) else 0)) + + +SORT_METHODS = { + 'extension': _extension, + 'filename': _filename, + 'size': _size, + 'time': _time, +} diff --git a/bundle/defx.nvim/rplugin/python3/defx/source/__init__.py b/bundle/defx.nvim/rplugin/python3/defx/source/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/defx.nvim/rplugin/python3/defx/source/file.py b/bundle/defx.nvim/rplugin/python3/defx/source/file.py new file mode 100644 index 000000000..c00cbd7a1 --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/source/file.py @@ -0,0 +1,61 @@ +# ============================================================================ +# FILE: file.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from pathlib import Path +import typing + +from defx.base.source import Base +from defx.context import Context +from defx.util import error, readable, safe_call, Nvim + + +class Source(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'file' + + from defx.kind.file import Kind + self.kind: Kind = Kind(self.vim) + + self.vars = { + 'root': None, + } + + def get_root_candidate( + self, context: Context, path: Path + ) -> typing.Dict[str, typing.Any]: + word = self.vim.call('fnamemodify', str(path), ':~') + if self.vim.call('defx#util#is_windows'): + word = word.replace('\\', '/') + if word[-1:] != '/': + word += '/' + if self.vars['root']: + word = self.vim.call(self.vars['root'], str(path)) + word = word.replace('\n', '\\n') + + return { + 'word': word, + 'is_directory': True, + 'action__path': path, + } + + def gather_candidates( + self, context: Context, path: Path + ) -> typing.List[typing.Dict[str, typing.Any]]: + candidates = [] + if not readable(path) or not path.is_dir(): + error(self.vim, f'"{path}" is not readable directory.') + return [] + for entry in path.iterdir(): + candidates.append({ + 'word': entry.name.replace('\n', '\\n') + ( + '/' if safe_call(entry.is_dir, False) else ''), + 'is_directory': safe_call(entry.is_dir, False), + 'action__path': entry, + }) + return candidates diff --git a/bundle/defx.nvim/rplugin/python3/defx/util.py b/bundle/defx.nvim/rplugin/python3/defx/util.py new file mode 100644 index 000000000..ecf57604d --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/util.py @@ -0,0 +1,90 @@ +# ============================================================================ +# FILE: util.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import importlib.util +import os +import typing +from pathlib import Path +from pynvim import Nvim + +UserContext = typing.Dict[str, typing.Any] +Candidate = typing.Dict[str, typing.Any] +Candidates = typing.List[Candidate] + + +def cd(vim: Nvim, path: str) -> None: + vim.call('defx#util#cd', path) + + +def cwd_input(vim: Nvim, cwd: str, prompt: str, + text: str = '', completion: str = '') -> str: + """ + Returns the absolute input path in cwd. + """ + save_cwd = vim.call('getcwd') + cd(vim, cwd) + + filename: str = str(vim.call('defx#util#input', prompt, text, completion)) + filename = filename.strip() + + cd(vim, save_cwd) + + return filename + + +def error(vim: Nvim, expr: typing.Any) -> None: + """ + Prints the error messages to Vim/Nvim's :messages buffer. + """ + vim.call('defx#util#print_error', expr) + + +def confirm(vim: Nvim, question: str) -> bool: + """ + Confirm action + """ + option: int = vim.call('defx#util#confirm', + question, '&Yes\n&No\n&Cancel', 2) + return option == 1 + + +def import_plugin(path: Path, source: str, + classname: str) -> typing.Any: + """Import defx plugin source class. + + If the class exists, add its directory to sys.path. + """ + module_name = 'defx.%s.%s' % (source, path.stem) + + spec = importlib.util.spec_from_file_location(module_name, str(path)) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) # type: ignore + cls = getattr(module, classname, None) + return cls + + +def readable(path: Path) -> bool: + """ + Check {path} is readable. + """ + try: + if os.access(str(path), os.R_OK) and path.stat(): + return True + else: + return False + except Exception: + return False + + +def safe_call(fn: typing.Callable[..., typing.Any], + fallback: typing.Optional[bool] = None) -> typing.Any: + """ + Ignore OSError when calling {fn} + """ + try: + return fn() + except OSError: + return fallback diff --git a/bundle/defx.nvim/rplugin/python3/defx/view.py b/bundle/defx.nvim/rplugin/python3/defx/view.py new file mode 100644 index 000000000..f77a5dfae --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/defx/view.py @@ -0,0 +1,678 @@ +# ============================================================================ +# FILE: view.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import copy +import time +import typing +from pynvim.api import Buffer +from pathlib import Path + +from defx.clipboard import Clipboard +from defx.context import Context +from defx.defx import Defx +from defx.session import Session +from defx.util import error, import_plugin, safe_call, Nvim + + +class View(object): + + def __init__(self, vim: Nvim, index: int) -> None: + self._vim: Nvim = vim + self._defxs: typing.List[Defx] = [] + self._candidates: typing.List[typing.Dict[str, typing.Any]] = [] + self._clipboard = Clipboard() + self._bufnr = -1 + self._prev_bufnr = -1 + self._winid = -1 + self._index = index + self._bufname = '[defx]' + self._buffer: Buffer = None + self._prev_action = '' + self._prev_syntaxes: typing.List[str] = [] + self._prev_highlight_commands: typing.List[str] = [] + self._winrestcmd = '' + self._session_version = '1.0' + self._sessions: typing.Dict[str, Session] = {} + + def init(self, paths: typing.List[str], + context: typing.Dict[str, typing.Any], + clipboard: Clipboard + ) -> None: + self._context = self._init_context(context) + self._bufname = f'[defx] {self._context.buffer_name}-{self._index}' + self._winrestcmd = self._vim.call('winrestcmd') + self._prev_wininfo = self._get_wininfo() + self._prev_bufnr = self._context.prev_bufnr + + if not self._init_defx(paths, clipboard): + # Skipped initialize + self._winid = self._vim.call('win_getid') + if paths and self._vim.call('bufnr', '%') == self._bufnr: + self._update_defx(paths) + self._init_columns(self._context.columns.split(':')) + self.redraw(True) + + def do_action(self, action_name: str, + action_args: typing.List[str], + new_context: typing.Dict[str, typing.Any]) -> None: + """ + Do "action" action. + """ + cursor = new_context['cursor'] + visual_start = new_context['visual_start'] + visual_end = new_context['visual_end'] + + defx_targets = { + x._index: self.get_selected_candidates(cursor, x._index) + for x in self._defxs} + all_targets: typing.List[typing.Dict[str, typing.Any]] = [] + for targets in defx_targets.values(): + all_targets += targets + + import defx.action as action + for defx in [x for x in self._defxs + if not all_targets or defx_targets[x._index]]: + context = self._context._replace( + args=action_args, + cursor=cursor, + targets=defx_targets[defx._index], + visual_start=visual_start, + visual_end=visual_end, + ) + ret = action.do_action(self, defx, action_name, context) + if ret: + error(self._vim, 'Invalid action_name:' + action_name) + return + + def debug(self, expr: typing.Any) -> None: + error(self._vim, expr) + + def print_msg(self, expr: typing.Any) -> None: + self._vim.call('defx#util#print_message', expr) + + def quit(self) -> None: + winnr = self._vim.call('bufwinnr', self._bufnr) + if winnr < 0: + return + + if winnr != self._vim.call('winnr'): + # Use current window + self._context = self._context._replace( + prev_winid=self._vim.call('win_getid')) + + self._vim.command(f'{winnr}wincmd w') + + if (self._context.split not in ['no', 'tab'] and + self._vim.call('winnr', '$') != 1): + self._vim.command('close') + self._vim.call('win_gotoid', self._context.prev_winid) + elif self._check_bufnr(self._prev_bufnr): + self._vim.command('buffer ' + str(self._prev_bufnr)) + elif self._check_bufnr(self._context.prev_last_bufnr): + self._vim.command('buffer ' + + str(self._context.prev_last_bufnr)) + else: + self._vim.command('enew') + + if self._get_wininfo() and self._get_wininfo() == self._prev_wininfo: + self._vim.command(self._winrestcmd) + + def redraw(self, is_force: bool = False) -> None: + """ + Redraw defx buffer. + """ + + start = time.time() + + [info] = self._vim.call('getbufinfo', self._bufnr) + prev_linenr = info['lnum'] + prev = self.get_cursor_candidate(prev_linenr) + + if is_force: + self._init_candidates() + self._init_column_length() + + for column in self._columns: + column.on_redraw(self, self._context) + + lines = [ + self._get_columns_text(self._context, x) + for x in self._candidates + ] + + self._buffer.options['modifiable'] = True + + # NOTE: Different len of buffer line replacement cause cursor jump + if len(lines) >= len(self._buffer): + self._buffer[:] = lines[:len(self._buffer)] + self._buffer.append(lines[len(self._buffer):]) + else: + self._buffer[len(lines):] = [] + self._buffer[:] = lines + + self._buffer.options['modifiable'] = False + self._buffer.options['modified'] = False + + # TODO: How to set cursor position for other buffer when + # stay in current buffer + if self._buffer == self._vim.current.buffer: + self._vim.call('cursor', [prev_linenr, 0]) + if prev: + self.search_file(prev['action__path'], prev['_defx_index']) + if is_force: + self._init_column_syntax() + + if self._context.profile: + error(self._vim, f'redraw time = {time.time() - start}') + + def get_cursor_candidate( + self, cursor: int) -> typing.Dict[str, typing.Any]: + if len(self._candidates) < cursor: + return {} + else: + return self._candidates[cursor - 1] + + def get_selected_candidates( + self, cursor: int, index: int + ) -> typing.List[typing.Dict[str, typing.Any]]: + if not self._candidates: + return [] + + candidates = [x for x in self._candidates if x['is_selected']] + if not candidates: + candidates = [self.get_cursor_candidate(cursor)] + return [x for x in candidates if x.get('_defx_index', -1) == index] + + def get_candidate_pos(self, path: Path, index: int) -> int: + for [pos, candidate] in enumerate(self._candidates): + if (candidate['_defx_index'] == index and + candidate['action__path'] == path): + return pos + return -1 + + def cd(self, defx: Defx, path: str, cursor: int) -> None: + history = defx._cursor_history + + # Save previous cursor position + candidate = self.get_cursor_candidate(cursor) + if candidate: + history[defx._cwd] = candidate['action__path'] + + global_histories = self._vim.vars['defx#_histories'] + global_histories.append(defx._cwd) + self._vim.vars['defx#_histories'] = global_histories + + defx.cd(path) + self.redraw(True) + + self._check_session(defx._index, path) + + self._init_cursor(defx) + if path in history: + self.search_file(history[path], defx._index) + + self._update_paths(defx._index, path) + + def search_file(self, path: Path, index: int) -> bool: + target = str(path) + if target and target[-1] == '/': + target = target[:-1] + pos = self.get_candidate_pos(Path(target), index) + if pos < 0: + return False + + self._vim.call('cursor', [pos + 1, 1]) + return True + + def update_candidates(self) -> None: + # Update opened/selected state + for defx in self._defxs: + defx._opened_candidates = set() + defx._selected_candidates = set() + for [i, candidate] in [x for x in enumerate(self._candidates) + if x[1]['is_opened_tree']]: + defx = self._defxs[candidate['_defx_index']] + defx._opened_candidates.add(str(candidate['action__path'])) + for [i, candidate] in [x for x in enumerate(self._candidates) + if x[1]['is_selected']]: + defx = self._defxs[candidate['_defx_index']] + defx._selected_candidates.add(str(candidate['action__path'])) + + def open_tree(self, path: Path, index: int, enable_nested: bool, + max_level: int = 0) -> None: + # Search insert position + pos = self.get_candidate_pos(path, index) + if pos < 0: + return + + target = self._candidates[pos] + if (not target['is_directory'] or + target['is_opened_tree'] or target['is_root']): + return + + target['is_opened_tree'] = True + base_level = target['level'] + 1 + + defx = self._defxs[index] + children = defx.gather_candidates_recursive( + str(path), base_level, base_level + max_level) + if not children: + return + + if (enable_nested and len(children) == 1 + and children[0]['is_directory']): + # Merge child. + target['action__path'] = children[0]['action__path'] + target['word'] += children[0]['word'] + target['is_opened_tree'] = False + return self.open_tree(target['action__path'], + index, enable_nested, max_level) + + for candidate in children: + candidate['_defx_index'] = index + + self._candidates = (self._candidates[: pos + 1] + + children + self._candidates[pos + 1:]) + + def close_tree(self, path: Path, index: int) -> None: + # Search insert position + pos = self.get_candidate_pos(path, index) + if pos < 0: + return + + target = self._candidates[pos] + if not target['is_opened_tree'] or target['is_root']: + return + + target['is_opened_tree'] = False + + start = pos + 1 + base_level = target['level'] + end = start + for candidate in self._candidates[start:]: + if candidate['level'] <= base_level: + break + end += 1 + + self._candidates = (self._candidates[: start] + + self._candidates[end:]) + + def _init_context( + self, context: typing.Dict[str, typing.Any]) -> Context: + # Convert to int + for attr in [x[0] for x in Context()._asdict().items() + if isinstance(x[1], int) and x[0] in context]: + context[attr] = int(context[attr]) + + return Context(**context) + + def _resize_window(self) -> None: + window_options = self._vim.current.window.options + if (self._context.split == 'vertical' + and self._context.winwidth > 0): + window_options['winfixwidth'] = True + self._vim.command(f'vertical resize {self._context.winwidth}') + elif (self._context.split == 'horizontal' and + self._context.winheight > 0): + window_options['winfixheight'] = True + self._vim.command(f'resize {self._context.winheight}') + + def _check_session(self, index: int, path: str) -> None: + if path not in self._sessions: + return + + # restore opened_candidates + session = self._sessions[path] + for opened_path in session.opened_candidates: + self.open_tree(Path(opened_path), index, False) + self.update_candidates() + self.redraw() + + def _init_defx(self, + paths: typing.List[str], + clipboard: Clipboard) -> bool: + if not self._switch_buffer(): + return False + + self._buffer = self._vim.current.buffer + self._bufnr = self._buffer.number + self._winid = self._vim.call('win_getid') + + if not paths: + paths = [self._vim.call('getcwd')] + + self._buffer.vars['defx'] = { + 'context': self._context._asdict(), + 'paths': paths, + } + + # Note: Have to use setlocal instead of "current.window.options" + # "current.window.options" changes global value instead of local in + # neovim. + self._vim.command('setlocal colorcolumn=') + self._vim.command('setlocal conceallevel=2') + self._vim.command('setlocal concealcursor=nc') + self._vim.command('setlocal nocursorcolumn') + self._vim.command('setlocal nofoldenable') + self._vim.command('setlocal foldcolumn=0') + self._vim.command('setlocal nolist') + self._vim.command('setlocal nonumber') + self._vim.command('setlocal norelativenumber') + self._vim.command('setlocal nospell') + self._vim.command('setlocal nowrap') + self._vim.command('setlocal signcolumn=no') + if self._context.split == 'floating': + self._vim.command('setlocal nocursorline') + + self._resize_window() + + buffer_options = self._buffer.options + if not self._context.listed: + buffer_options['buflisted'] = False + buffer_options['buftype'] = 'nofile' + buffer_options['bufhidden'] = 'hide' + buffer_options['swapfile'] = False + buffer_options['modeline'] = False + buffer_options['modifiable'] = False + buffer_options['modified'] = False + buffer_options['filetype'] = 'defx' + + if not self._vim.call('has', 'nvim'): + # In Vim8, FileType autocmd is not fired after set filetype option. + self._vim.command('silent doautocmd FileType defx') + + self._vim.command('autocmd! defx * ') + self._vim.command('autocmd defx ' + 'CursorHold,FocusGained ' + 'call defx#call_async_action("check_redraw")') + self._vim.command('autocmd defx FileType ' + 'call defx#call_action("redraw")') + + self._prev_highlight_commands = [] + + # Initialize defx state + self._candidates = [] + self._clipboard = clipboard + self._defxs = [] + self._update_defx(paths) + + self._init_all_columns() + self._init_columns(self._context.columns.split(':')) + + self.redraw(True) + + if self._context.session_file: + self.do_action('load_session', [], + self._vim.call('defx#init#_context', {})) + for [index, path] in enumerate(paths): + self._check_session(index, path) + + for defx in self._defxs: + self._init_cursor(defx) + + self._vim.vars['defx#_drives'] = self._context.drives + + return True + + def _switch_buffer(self) -> bool: + if self._context.split == 'tab': + self._vim.command('tabnew') + + winnr = self._vim.call('bufwinnr', self._bufnr) + if winnr > 0: + self._vim.command(f'{winnr}wincmd w') + if self._context.toggle: + self.quit() + else: + self._resize_window() + return False + + if (self._vim.current.buffer.options['modified'] and + not self._vim.options['hidden'] and + self._context.split == 'no'): + self._context = self._context._replace(split='vertical') + + if (self._context.split == 'floating' + and self._vim.call('exists', '*nvim_open_win')): + # Use floating window + self._vim.call( + 'nvim_open_win', + self._vim.call('bufnr', '%'), True, { + 'relative': self._context.winrelative, + 'row': self._context.winrow, + 'col': self._context.wincol, + 'width': self._context.winwidth, + 'height': self._context.winheight, + }) + + # Create new buffer + vertical = 'vertical' if self._context.split == 'vertical' else '' + no_split = self._context.split in ['no', 'tab', 'floating'] + if self._vim.call('bufloaded', self._bufnr): + command = ('buffer' if no_split else 'sbuffer') + self._vim.command( + 'silent keepalt %s %s %s %s' % ( + self._context.direction, + vertical, + command, + self._bufnr, + ) + ) + if self._context.resume: + self._resize_window() + return False + elif self._vim.call('exists', 'bufadd'): + bufnr = self._vim.call('bufadd', self._bufname) + command = ('buffer' if no_split else 'sbuffer') + self._vim.command( + 'silent keepalt %s %s %s %s' % ( + self._context.direction, + vertical, + command, + bufnr, + ) + ) + else: + command = ('edit' if no_split else 'new') + self._vim.call( + 'defx#util#execute_path', + 'silent keepalt %s %s %s ' % ( + self._context.direction, + vertical, + command, + ), + self._bufname) + return True + + def _init_all_columns(self) -> None: + from defx.base.column import Base as Column + self._all_columns: typing.Dict[str, Column] = {} + + for path_column in self._load_custom_columns(): + column = import_plugin(path_column, 'column', 'Column') + if not column: + continue + + column = column(self._vim) + if column.name not in self._all_columns: + self._all_columns[column.name] = column + + def _init_columns(self, columns: typing.List[str]) -> None: + from defx.base.column import Base as Column + custom = self._vim.call('defx#custom#_get')['column'] + self._columns: typing.List[Column] = [ + copy.copy(self._all_columns[x]) + for x in columns if x in self._all_columns + ] + for column in self._columns: + if column.name in custom: + column.vars.update(custom[column.name]) + column.on_init(self, self._context) + + def _init_column_length(self) -> None: + from defx.base.column import Base as Column + within_variable = False + within_variable_columns: typing.List[Column] = [] + start = 1 + for [index, column] in enumerate(self._columns): + column.syntax_name = f'Defx_{column.name}_{index}' + + if within_variable and not column.is_stop_variable: + within_variable_columns.append(column) + continue + + # Calculate variable_length + variable_length = 0 + if column.is_stop_variable: + for variable_column in within_variable_columns: + variable_length += variable_column.length( + self._context._replace(targets=self._candidates)) + + # Note: for "' '.join(variable_texts)" length + if within_variable_columns: + variable_length += len(within_variable_columns) - 1 + + length = column.length( + self._context._replace(targets=self._candidates, + variable_length=variable_length)) + + column.start = start + column.end = start + length + + if column.is_start_variable: + within_variable = True + within_variable_columns.append(column) + else: + column.is_within_variable = False + start += length + 1 + + if column.is_stop_variable: + for variable_column in within_variable_columns: + # Overwrite syntax_name + variable_column.syntax_name = column.syntax_name + variable_column.is_within_variable = True + within_variable = False + + def _init_column_syntax(self) -> None: + commands: typing.List[str] = [] + + for syntax in self._prev_syntaxes: + commands.append( + 'silent! syntax clear ' + syntax) + + self._prev_syntaxes = [] + for column in self._columns: + source_highlights = column.highlight_commands() + if source_highlights: + if (not column.is_within_variable and + column.start > 0 and column.end > 0): + commands.append( + 'syntax region ' + column.syntax_name + + r' start=/\%' + str(column.start) + r'v/ end=/\%' + + str(column.end) + 'v/ keepend oneline') + self._prev_syntaxes += [column.syntax_name] + + commands += source_highlights + self._prev_syntaxes += column.syntaxes() + + syntax_list = commands + [self._vim.call('execute', 'syntax list')] + if syntax_list == self._prev_highlight_commands: + # Skip highlights + return + + self._execute_commands(commands) + self._prev_highlight_commands = commands + [ + self._vim.call('execute', 'syntax list')] + + def _execute_commands(self, commands: typing.List[str]) -> None: + # Note: If commands are too huge, vim.command() will fail. + threshold = 15 + cnt = 0 + while cnt < len(commands): + self._vim.command(' | '.join(commands[cnt: cnt + threshold])) + cnt += threshold + + def _init_candidates(self) -> None: + self._candidates = [] + for defx in self._defxs: + root = defx.get_root_candidate() + defx._mtime = root['action__path'].stat().st_mtime + + candidates = [root] + candidates += defx.tree_candidates( + defx._cwd, 0, self._context.auto_recursive_level) + for candidate in candidates: + candidate['_defx_index'] = defx._index + self._candidates += candidates + + def _get_columns_text(self, context: Context, + candidate: typing.Dict[str, typing.Any]) -> str: + texts: typing.List[str] = [] + variable_texts: typing.List[str] = [] + for column in self._columns: + if column.is_stop_variable: + if variable_texts: + variable_texts.append('') + text = column.get_with_variable_text( + context, ' '.join(variable_texts), candidate) + texts.append(text) + + variable_texts = [] + else: + text = column.get(context, candidate) + if column.is_start_variable or column.is_within_variable: + if text: + variable_texts.append(text) + else: + texts.append(text) + return ' '.join(texts) + + def _update_paths(self, index: int, path: str) -> None: + var_defx = self._buffer.vars['defx'] + if len(var_defx['paths']) <= index: + var_defx['paths'].append(path) + else: + var_defx['paths'][index] = path + self._buffer.vars['defx'] = var_defx + + def _init_cursor(self, defx: Defx) -> None: + self.search_file(Path(defx._cwd), defx._index) + + # Move to next + self._vim.call('cursor', [self._vim.call('line', '.') + 1, 1]) + + def _get_wininfo(self) -> typing.List[str]: + return [ + self._vim.options['columns'], self._vim.options['lines'], + self._vim.call('win_getid'), self._vim.call('tabpagebuflist') + ] + + def _load_custom_columns(self) -> typing.List[Path]: + rtp_list = self._vim.options['runtimepath'].split(',') + result: typing.List[Path] = [] + + for path in rtp_list: + column_path = Path(path).joinpath( + 'rplugin', 'python3', 'defx', 'column') + if safe_call(column_path.is_dir): + result += column_path.glob('*.py') + + return result + + def _update_defx(self, paths: typing.List[str]) -> None: + self._defxs = self._defxs[:len(paths)] + + for [index, path] in enumerate(paths): + if index >= len(self._defxs): + self._defxs.append( + Defx(self._vim, self._context, path, index)) + else: + self.cd(self._defxs[index], path, self._context.cursor) + self._update_paths(index, path) + + def _check_bufnr(self, bufnr: int) -> bool: + return (bool(self._vim.call('bufexists', bufnr)) and + bufnr != self._vim.call('bufnr', '%')) diff --git a/bundle/defx.nvim/rplugin/python3/denite/source/defx/__init__.py b/bundle/defx.nvim/rplugin/python3/denite/source/defx/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/defx.nvim/rplugin/python3/denite/source/defx/drive.py b/bundle/defx.nvim/rplugin/python3/denite/source/defx/drive.py new file mode 100644 index 000000000..c426f605f --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/denite/source/defx/drive.py @@ -0,0 +1,36 @@ +# ============================================================================ +# FILE: defx/drive.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from pathlib import Path +import typing + +from defx.util import Nvim, UserContext, Candidates +from denite.source.base import Base + + +class Source(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'defx/drive' + self.kind = 'command' + self._drives: typing.List[str] = [] + + def on_init(self, context: UserContext) -> None: + options = self.vim.current.buffer.options + if 'filetype' not in options or options['filetype'] != 'defx': + return + + self._drives = self.vim.vars['defx#_drives'] + + def gather_candidates(self, context: UserContext) -> Candidates: + return [{ + 'word': x, + 'abbr': x + '/', + 'action__command': f"call defx#call_action('cd', ['{x}'])", + 'action__path': x, + } for x in self._drives if Path(x).exists()] diff --git a/bundle/defx.nvim/rplugin/python3/denite/source/defx/history.py b/bundle/defx.nvim/rplugin/python3/denite/source/defx/history.py new file mode 100644 index 000000000..94e2d3dce --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/denite/source/defx/history.py @@ -0,0 +1,35 @@ +# ============================================================================ +# FILE: defx/history.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +import typing + +from defx.util import Nvim, UserContext, Candidates +from denite.source.base import Base + + +class Source(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'defx/history' + self.kind = 'command' + self._histories: typing.List[str] = [] + + def on_init(self, context: UserContext) -> None: + options = self.vim.current.buffer.options + if 'filetype' not in options or options['filetype'] != 'defx': + return + + self._histories = reversed(self.vim.vars['defx#_histories']) + + def gather_candidates(self, context: UserContext) -> Candidates: + return [{ + 'word': x, + 'abbr': x + '/', + 'action__command': f"call defx#call_action('cd', ['{x}'])", + 'action__path': x, + } for x in self._histories] diff --git a/bundle/defx.nvim/rplugin/python3/denite/source/defx/session.py b/bundle/defx.nvim/rplugin/python3/denite/source/defx/session.py new file mode 100644 index 000000000..666d9645e --- /dev/null +++ b/bundle/defx.nvim/rplugin/python3/denite/source/defx/session.py @@ -0,0 +1,58 @@ +# ============================================================================ +# FILE: defx/session.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from defx.util import Nvim, UserContext, Candidates +from denite.kind.command import Kind as Command +from denite.source.base import Base + + +class Source(Base): + + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'defx/session' + self.kind = Kind(vim) + + def on_init(self, context: UserContext) -> None: + self._winid = self.vim.call('win_getid') + self._bufnr = self.vim.call('bufnr', '%') + + def gather_candidates(self, context: UserContext) -> Candidates: + sessions = self.vim.call( + 'getbufvar', self._bufnr, 'defx#_sessions', []) + if not sessions: + return [] + + max_name = max([self.vim.call('strwidth', x['name']) + for x in sessions]) + word_format = '{0:<' + str(max_name) + '} - {1}' + return [{ + 'word': word_format.format(x['name'], x['path']), + 'action__command': "call defx#call_action('cd', '{}')".format( + x['path']), + 'action__path': x['path'], + 'source__winid': self._winid, + } for x in sessions] + + +class Kind(Command): + def __init__(self, vim: Nvim) -> None: + super().__init__(vim) + + self.name = 'defx/session' + self.persist_actions += ['delete'] + self.redraw_actions += ['delete'] + + def action_delete(self, context: UserContext) -> Candidates: + winid = self.vim.call('win_getid') + + for candidate in context['targets']: + self.vim.call('win_gotoid', candidate['source__winid']) + self.vim.call('defx#call_action', 'delete_session', + candidate['action__path']) + + self.vim.call('win_gotoid', winid) diff --git a/bundle/defx.nvim/test/autoload/defx/custom.vim b/bundle/defx.nvim/test/autoload/defx/custom.vim new file mode 100644 index 000000000..8fcdb8417 --- /dev/null +++ b/bundle/defx.nvim/test/autoload/defx/custom.vim @@ -0,0 +1,29 @@ +" set verbose=1 + +let s:suite = themis#suite('custom') +let s:assert = themis#helper('assert') + +function! s:suite.before_each() abort + call defx#custom#_init() +endfunction + +function! s:suite.custom_column() abort + let custom = defx#custom#_get().column + call defx#custom#column( + \ 'mark', 'selected_icon', 'O') + call s:assert.equals(custom.mark.selected_icon, 'O') +endfunction + +function! s:suite.custom_option() abort + let custom = defx#custom#_get().option + + call defx#custom#option('default', 'columns', 'mark') + call s:assert.equals(custom.default.columns, 'mark') +endfunction + +function! s:suite.custom_source() abort + let custom = defx#custom#_get().source + + call defx#custom#source('file', 'root', 'mark') + call s:assert.equals(custom.file.root, 'mark') +endfunction diff --git a/bundle/defx.nvim/test/conftest.py b/bundle/defx.nvim/test/conftest.py new file mode 100644 index 000000000..51ad03a2a --- /dev/null +++ b/bundle/defx.nvim/test/conftest.py @@ -0,0 +1,7 @@ +import sys + +from pathlib import Path + + +BASE_DIR = Path(__file__).parent.parent +sys.path.insert(0, str(BASE_DIR.joinpath('rplugin/python3'))) diff --git a/bundle/defx.nvim/test/requirements.txt b/bundle/defx.nvim/test/requirements.txt new file mode 100644 index 000000000..ce23018fd --- /dev/null +++ b/bundle/defx.nvim/test/requirements.txt @@ -0,0 +1,5 @@ +pynvim +pytest +flake8 +mypy +vim-vint diff --git a/bundle/defx.nvim/test/rplugin/python3/defx/test_defx.py b/bundle/defx.nvim/test/rplugin/python3/defx/test_defx.py new file mode 100644 index 000000000..a24654dcd --- /dev/null +++ b/bundle/defx.nvim/test/rplugin/python3/defx/test_defx.py @@ -0,0 +1,17 @@ +import pytest + +from defx.view import View +from pynvim import Nvim +from unittest.mock import create_autospec +from unittest.mock import MagicMock + + +def test_view(): + vim = create_autospec(Nvim) + vim.channel_id = 0 + vim.vars = {} + vim.call.return_value = '' + vim.current = MagicMock() + + context = {} + defx = View(vim, 0) diff --git a/bundle/dein.vim/.github/ISSUE_TEMPLATE.md b/bundle/dein.vim/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..e95aba15c --- /dev/null +++ b/bundle/dein.vim/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,38 @@ +**Warning: I will close the bug issue without the minimal init.vim and the reproduce ways.** + +# Problems summary + + +## Expected + + +## Environment Information (Required!) + + * dein.vim version(SHA1): + + * OS: + + * Vim/neovim version: + + +## Provide a minimal .vimrc with less than 50 lines (Required!) + +```vim +" Your minimal .vimrc +set runtimepath^=~/path/to/dein.nvim/ +call dein#begin(path) +call dein#end() +``` + + +## The reproduce ways from Vim starting (Required!) + + 1. foo + 2. bar + 3. baz + + +## Screen shot (if possible) + + +## Upload the log messages by `:redir` and `:message` (if errored) diff --git a/bundle/dein.vim/.gitignore b/bundle/dein.vim/.gitignore new file mode 100644 index 000000000..f136e7d02 --- /dev/null +++ b/bundle/dein.vim/.gitignore @@ -0,0 +1,4 @@ +doc/tags +.cache +*.py[cod] +vim-themis/ diff --git a/bundle/dein.vim/.travis.yml b/bundle/dein.vim/.travis.yml new file mode 100644 index 000000000..6e0cd1459 --- /dev/null +++ b/bundle/dein.vim/.travis.yml @@ -0,0 +1,13 @@ +dist: xenial + +language: python + +python: + - 3.7 + +install: + - eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) nightly-x64" + - make install + +script: + - make --keep-going test diff --git a/bundle/dein.vim/LICENSE b/bundle/dein.vim/LICENSE new file mode 100644 index 000000000..3a4b98ed8 --- /dev/null +++ b/bundle/dein.vim/LICENSE @@ -0,0 +1,21 @@ +License: MIT license +AUTHOR: Shougo Matsushita + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bundle/dein.vim/Makefile b/bundle/dein.vim/Makefile new file mode 100644 index 000000000..7e8bcc86f --- /dev/null +++ b/bundle/dein.vim/Makefile @@ -0,0 +1,24 @@ +PATH := ./vim-themis/bin:$(PATH) +export THEMIS_VIM := nvim +export THEMIS_ARGS := -e -s --headless +export THEMIS_HOME := ./vim-themis + + +install: vim-themis + pip install --upgrade -r test/requirements.txt + +install-user: vim-themis + pip install --user --upgrade -r test/requirements.txt + +lint: + vint --version + vint autoload + +test: + themis --version + themis test/ + +vim-themis: + git clone https://github.com/thinca/vim-themis vim-themis + +.PHONY: install lint test diff --git a/bundle/dein.vim/README.md b/bundle/dein.vim/README.md new file mode 100644 index 000000000..8085be3bb --- /dev/null +++ b/bundle/dein.vim/README.md @@ -0,0 +1,138 @@ +# dein.vim + +[![Join the chat at https://gitter.im/Shougo/dein.vim](https://badges.gitter.im/Shougo/dein.vim.svg)](https://gitter.im/Shougo/dein.vim?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/Shougo/dein.vim.svg?branch=master)](https://travis-ci.org/Shougo/dein.vim) + +Dein.vim is a dark powered Vim/Neovim plugin manager. + + + +- [Requirements](#requirements) +- [Quick start](#quick-start) + - [Unix/Linux or Mac OS X](#unixlinux-or-mac-os-x) +- [Features](#features) +- [Future works (TODO)](#future-works-todo) + - [Options](#options) + + + + +## Requirements + +- Vim 8.0 or above or NeoVim. +- "xcopy" command in $PATH (Windows) +- "git" command in $PATH (if you want to install github or vim.org plugins) + +Note: If you use Vim 7.4, please use dein.vim ver.1.5 instead. + +If you need vim-plug like install UI, you can use dein-ui.vim. +https://github.com/wsdjeg/dein-ui.vim + + +## Quick start + +**Note**: You must define the installation directory before to use dein. The +directory that you will want to use depends on your usage. + +For example, `~/.vim/bundles` or `~/.cache/dein` or `~/.local/share/dein`. +dein.vim does not define a default installation directory. +You must **not** set the installation directory as `~/.vim/plugin` or +`~/.config/nvim/plugin`. + +1. Run below script. + +For Unix/Linux or Mac OS X + +```sh +curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh +# For example, we just use `~/.cache/dein` as installation directory +sh ./installer.sh ~/.cache/dein +``` + +For Windows(PowerShell) + +```powershell +Invoke-WebRequest https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.ps1 -OutFile installer.ps1 +# Allow to run third-party script +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +# For example, we just use `~/.cache/dein` as installation directory +./installer.ps1 ~/.cache/dein +``` + +2. Edit your .vimrc like this. + +```vim +if &compatible + set nocompatible +endif +" Add the dein installation directory into runtimepath +set runtimepath+=~/.cache/dein/repos/github.com/Shougo/dein.vim + +if dein#load_state('~/.cache/dein') + call dein#begin('~/.cache/dein') + + call dein#add('~/.cache/dein/repos/github.com/Shougo/dein.vim') + call dein#add('Shougo/deoplete.nvim') + if !has('nvim') + call dein#add('roxma/nvim-yarp') + call dein#add('roxma/vim-hug-neovim-rpc') + endif + + call dein#end() + call dein#save_state() +endif + +filetype plugin indent on +syntax enable +``` + +3. Open vim and install dein + +```vim +:call dein#install() +``` + + +## Features + +- Faster than NeoBundle + +- Simple + +- No commands, Functions only to simplify the implementation + +- Easy to test and maintain + +- No Vundle/NeoBundle compatibility + +- neovim/Vim8 asynchronous API installation support + +- Local plugin support + +- Non github plugins support + +- Go like clone directory name ex:"github.com/{user}/{repository}" + +- Merge the plugins directories automatically to avoid long 'runtimepath' + + +## Future works (TODO) + +- Other types support (zip, svn, hg, ...) + +- Metadata repository support + + +### Options + +Some common options. For a more detailed list, run `:h dein-options` + +| Option | Type | Description | +| -------- | -------------------- | ------------------------------------------------------------------------------------- | +| `name` | `string` | The name for a plugin. If it is omitted, the tail of the repository name will be used | +| `rev` | `string` | The revision number or branch/tag name for the repo | +| `build` | `string` | Command to run after the plugin is installed | +| `on_ft` | `string` or `list` | Load a plugin for the current filetype | +| `on_cmd` | `string` or `list` | Load the plugin for these commands | +| `rtp` | `string` | You can use this option when the repository has the Vim plugin in a subdirectory | +| `if` | `string` or `number` | If it is String, dein will eval it. | +| `merged` | `number` | If set to 0, dein doesn't merge the plugin directory. | diff --git a/bundle/dein.vim/autoload/dein.vim b/bundle/dein.vim/autoload/dein.vim new file mode 100644 index 000000000..20c6a6e2b --- /dev/null +++ b/bundle/dein.vim/autoload/dein.vim @@ -0,0 +1,204 @@ +"============================================================================= +" FILE: dein.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! dein#_init() abort + let g:dein#_cache_version = 150 + let g:dein#_merged_format = + \ "{'repo': v:val.repo, 'rev': get(v:val, 'rev', '')}" + let g:dein#_merged_length = 3 + let g:dein#name = '' + let g:dein#plugin = {} + let g:dein#_plugins = {} + let g:dein#_base_path = '' + let g:dein#_cache_path = '' + let g:dein#_runtime_path = '' + let g:dein#_hook_add = '' + let g:dein#_ftplugin = {} + let g:dein#_off1 = '' + let g:dein#_off2 = '' + let g:dein#_vimrcs = [] + let g:dein#_block_level = 0 + let g:dein#_event_plugins = {} + let g:dein#_is_sudo = $SUDO_USER !=# '' && $USER !=# $SUDO_USER + \ && $HOME !=# expand('~'.$USER) + \ && $HOME ==# expand('~'.$SUDO_USER) + let g:dein#_progname = fnamemodify(v:progname, ':r') + let g:dein#_init_runtimepath = &runtimepath + + augroup dein + autocmd! + autocmd FuncUndefined * call dein#autoload#_on_func(expand('')) + autocmd BufRead *? call dein#autoload#_on_default_event('BufRead') + autocmd BufNew,BufNewFile *? call dein#autoload#_on_default_event('BufNew') + autocmd VimEnter *? call dein#autoload#_on_default_event('VimEnter') + autocmd FileType *? call dein#autoload#_on_default_event('FileType') + autocmd BufWritePost *.vim,*.toml,vimrc,.vimrc + \ call dein#util#_check_vimrcs() + augroup END + augroup dein-events | augroup END + + if !exists('##CmdUndefined') | return | endif + autocmd dein CmdUndefined * + \ call dein#autoload#_on_pre_cmd(expand('')) +endfunction +function! dein#load_cache_raw(vimrcs) abort + let g:dein#_vimrcs = a:vimrcs + let cache = get(g:, 'dein#cache_directory', g:dein#_base_path) + \ .'/cache_' . g:dein#_progname + let time = getftime(cache) + if !empty(filter(map(copy(g:dein#_vimrcs), + \ 'getftime(expand(v:val))'), 'time < v:val')) + return [{}, {}] + endif + let list = readfile(cache) + if len(list) != 3 || string(g:dein#_vimrcs) !=# list[0] + return [{}, {}] + endif + return [json_decode(list[1]), json_decode(list[2])] +endfunction +function! dein#load_state(path, ...) abort + if !exists('#dein') + call dein#_init() + endif + let sourced = a:0 > 0 ? a:1 : has('vim_starting') && + \ (!exists('&loadplugins') || &loadplugins) + if (g:dein#_is_sudo || !sourced) | return 1 | endif + let g:dein#_base_path = expand(a:path) + + let state = get(g:, 'dein#cache_directory', g:dein#_base_path) + \ . '/state_' . g:dein#_progname . '.vim' + if !filereadable(state) | return 1 | endif + try + execute 'source' fnameescape(state) + catch + if v:exception !=# 'Cache loading error' + call dein#util#_error('Loading state error: ' . v:exception) + endif + call dein#clear_state() + return 1 + endtry +endfunction + +function! dein#tap(name) abort + if !has_key(g:dein#_plugins, a:name) + \ || !isdirectory(g:dein#_plugins[a:name].path) | return 0 | endif + let g:dein#name = a:name + let g:dein#plugin = g:dein#_plugins[a:name] + return 1 +endfunction +function! dein#is_sourced(name) abort + return has_key(g:dein#_plugins, a:name) + \ && isdirectory(g:dein#_plugins[a:name].path) + \ && g:dein#_plugins[a:name].sourced +endfunction +function! dein#begin(path, ...) abort + return dein#util#_begin(a:path, (empty(a:000) ? [] : a:1)) +endfunction +function! dein#end() abort + return dein#util#_end() +endfunction +function! dein#add(repo, ...) abort + return dein#parse#_add(a:repo, get(a:000, 0, {})) +endfunction +function! dein#local(dir, ...) abort + return dein#parse#_local(a:dir, get(a:000, 0, {}), get(a:000, 1, ['*'])) +endfunction +function! dein#get(...) abort + return empty(a:000) ? copy(g:dein#_plugins) : get(g:dein#_plugins, a:1, {}) +endfunction +function! dein#source(...) abort + return call('dein#autoload#_source', a:000) +endfunction +function! dein#check_install(...) abort + return dein#util#_check_install(get(a:000, 0, [])) +endfunction +function! dein#check_clean() abort + return dein#util#_check_clean() +endfunction +function! dein#install(...) abort + return dein#install#_update(get(a:000, 0, []), + \ 'install', dein#install#_is_async()) +endfunction +function! dein#update(...) abort + return dein#install#_update(get(a:000, 0, []), + \ 'update', dein#install#_is_async()) +endfunction +function! dein#check_update(...) abort + return dein#install#_update(get(a:000, 0, []), + \ 'check_update', dein#install#_is_async()) +endfunction +function! dein#direct_install(repo, ...) abort + call dein#install#_direct_install(a:repo, (a:0 ? a:1 : {})) +endfunction +function! dein#get_direct_plugins_path() abort + return get(g:, 'dein#cache_directory', g:dein#_base_path) + \ .'/direct_install.vim' +endfunction +function! dein#reinstall(plugins) abort + call dein#install#_reinstall(a:plugins) +endfunction +function! dein#rollback(date, ...) abort + call dein#install#_rollback(a:date, (a:0 ? a:1 : [])) +endfunction +function! dein#save_rollback(rollbackfile, ...) abort + call dein#install#_save_rollback(a:rollbackfile, (a:0 ? a:1 : [])) +endfunction +function! dein#load_rollback(rollbackfile, ...) abort + call dein#install#_load_rollback(a:rollbackfile, (a:0 ? a:1 : [])) +endfunction +function! dein#remote_plugins() abort + return dein#install#_remote_plugins() +endfunction +function! dein#recache_runtimepath() abort + call dein#install#_recache_runtimepath() +endfunction +function! dein#call_hook(hook_name, ...) abort + return call('dein#util#_call_hook', [a:hook_name] + a:000) +endfunction +function! dein#check_lazy_plugins() abort + return dein#util#_check_lazy_plugins() +endfunction +function! dein#load_toml(filename, ...) abort + return dein#parse#_load_toml(a:filename, get(a:000, 0, {})) +endfunction +function! dein#load_dict(dict, ...) abort + return dein#parse#_load_dict(a:dict, get(a:000, 0, {})) +endfunction +function! dein#get_log() abort + return join(dein#install#_get_log(), "\n") +endfunction +function! dein#get_updates_log() abort + return join(dein#install#_get_updates_log(), "\n") +endfunction +function! dein#get_progress() abort + return dein#install#_get_progress() +endfunction +function! dein#each(command, ...) abort + return dein#install#_each(a:command, (a:0 ? a:1 : [])) +endfunction +function! dein#build(...) abort + return dein#install#_build(a:0 ? a:1 : []) +endfunction +function! dein#plugins2toml(plugins) abort + return dein#parse#_plugins2toml(a:plugins) +endfunction +function! dein#disable(names) abort + return dein#util#_disable(a:names) +endfunction +function! dein#config(arg, ...) abort + return type(a:arg) != v:t_list ? + \ dein#util#_config(a:arg, get(a:000, 0, {})) : + \ map(copy(a:arg), 'dein#util#_config(v:val, a:1)') +endfunction +function! dein#set_hook(plugins, hook_name, hook) abort + return dein#util#_set_hook(a:plugins, a:hook_name, a:hook) +endfunction +function! dein#save_state() abort + return dein#util#_save_state(has('vim_starting')) +endfunction +function! dein#clear_state() abort + return dein#util#_clear_state() +endfunction diff --git a/bundle/dein.vim/autoload/dein/autoload.vim b/bundle/dein.vim/autoload/dein/autoload.vim new file mode 100644 index 000000000..fa7fed12d --- /dev/null +++ b/bundle/dein.vim/autoload/dein/autoload.vim @@ -0,0 +1,364 @@ +"============================================================================= +" FILE: autoload.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! dein#autoload#_source(...) abort + let plugins = empty(a:000) ? values(g:dein#_plugins) : + \ dein#util#_convert2list(a:1) + if empty(plugins) + return + endif + + if type(plugins[0]) != v:t_dict + let plugins = map(dein#util#_convert2list(a:1), + \ 'get(g:dein#_plugins, v:val, {})') + endif + + let rtps = dein#util#_split_rtp(&runtimepath) + let index = index(rtps, dein#util#_get_runtime_path()) + if index < 0 + return 1 + endif + + let sourced = [] + for plugin in filter(plugins, + \ "!empty(v:val) && !v:val.sourced && v:val.rtp !=# ''") + call s:source_plugin(rtps, index, plugin, sourced) + endfor + + let filetype_before = dein#util#_redir('autocmd FileType') + let &runtimepath = dein#util#_join_rtp(rtps, &runtimepath, '') + + call dein#call_hook('source', sourced) + + " Reload script files. + for plugin in sourced + for directory in filter(['plugin', 'after/plugin'], + \ "isdirectory(plugin.rtp.'/'.v:val)") + for file in dein#util#_globlist(plugin.rtp.'/'.directory.'/**/*.vim') + execute 'source' fnameescape(file) + endfor + endfor + + if !has('vim_starting') + let augroup = get(plugin, 'augroup', plugin.normalized_name) + let events = ['VimEnter', 'BufRead', 'BufEnter', + \ 'BufWinEnter', 'WinEnter'] + if has('gui_running') && &term ==# 'builtin_gui' + call add(events, 'GUIEnter') + endif + for event in events + if exists('#'.augroup.'#'.event) + silent execute 'doautocmd' augroup event + endif + endfor + endif + endfor + + let filetype_after = dein#util#_redir('autocmd FileType') + + let is_reset = s:is_reset_ftplugin(sourced) + if is_reset + call s:reset_ftplugin() + endif + + if (is_reset || filetype_before !=# filetype_after) && &filetype !=# '' + " Recall FileType autocmd + let &filetype = &filetype + endif + + if !has('vim_starting') + call dein#call_hook('post_source', sourced) + endif +endfunction + +function! dein#autoload#_on_default_event(event) abort + let lazy_plugins = dein#util#_get_lazy_plugins() + let plugins = [] + + let path = expand('') + " For ":edit ~". + if fnamemodify(path, ':t') ==# '~' + let path = '~' + endif + let path = dein#util#_expand(path) + + for filetype in split(&l:filetype, '\.') + let plugins += filter(copy(lazy_plugins), + \ "index(get(v:val, 'on_ft', []), filetype) >= 0") + endfor + + let plugins += filter(copy(lazy_plugins), + \ "!empty(filter(copy(get(v:val, 'on_path', [])), + \ 'path =~? v:val'))") + let plugins += filter(copy(lazy_plugins), + \ "!has_key(v:val, 'on_event') + \ && has_key(v:val, 'on_if') && eval(v:val.on_if)") + + call s:source_events(a:event, plugins) +endfunction +function! dein#autoload#_on_event(event, plugins) abort + let lazy_plugins = filter(dein#util#_get_plugins(a:plugins), + \ '!v:val.sourced') + if empty(lazy_plugins) + execute 'autocmd! dein-events' a:event + return + endif + + let plugins = filter(copy(lazy_plugins), + \ "!has_key(v:val, 'on_if') || eval(v:val.on_if)") + call s:source_events(a:event, plugins) +endfunction +function! s:source_events(event, plugins) abort + if empty(a:plugins) + return + endif + + let prev_autocmd = execute('autocmd ' . a:event) + + call dein#autoload#_source(a:plugins) + + let new_autocmd = execute('autocmd ' . a:event) + + if a:event ==# 'InsertCharPre' + " Queue this key again + call feedkeys(v:char) + let v:char = '' + else + if exists('#BufReadCmd') && a:event ==# 'BufNew' + " For BufReadCmd plugins + silent doautocmd BufReadCmd + endif + if exists('#' . a:event) && prev_autocmd !=# new_autocmd + execute 'doautocmd ' a:event + elseif exists('#User#' . a:event) + execute 'doautocmd User' a:event + endif + endif +endfunction + +function! dein#autoload#_on_func(name) abort + let function_prefix = substitute(a:name, '[^#]*$', '', '') + if function_prefix =~# '^dein#' + \ || function_prefix =~# '^vital#' + \ || has('vim_starting') + return + endif + + call dein#autoload#_source(filter(dein#util#_get_lazy_plugins(), + \ "stridx(function_prefix, v:val.normalized_name.'#') == 0 + \ || (index(get(v:val, 'on_func', []), a:name) >= 0)")) +endfunction + +function! dein#autoload#_on_pre_cmd(name) abort + call dein#autoload#_source( + \ filter(dein#util#_get_lazy_plugins(), + \ "index(map(copy(get(v:val, 'on_cmd', [])), + \ 'tolower(v:val)'), a:name) >= 0 + \ || stridx(tolower(a:name), + \ substitute(tolower(v:val.normalized_name), + \ '[_-]', '', 'g')) == 0")) +endfunction + +function! dein#autoload#_on_cmd(command, name, args, bang, line1, line2) abort + call dein#source(a:name) + + if exists(':' . a:command) != 2 + call dein#util#_error(printf('command %s is not found.', a:command)) + return + endif + + let range = (a:line1 == a:line2) ? '' : + \ (a:line1 == line("'<") && a:line2 == line("'>")) ? + \ "'<,'>" : a:line1.','.a:line2 + + try + execute range.a:command.a:bang a:args + catch /^Vim\%((\a\+)\)\=:E481/ + " E481: No range allowed + execute a:command.a:bang a:args + endtry +endfunction + +function! dein#autoload#_on_map(mapping, name, mode) abort + let cnt = v:count > 0 ? v:count : '' + + let input = s:get_input() + + call dein#source(a:name) + + if a:mode ==# 'v' || a:mode ==# 'x' + call feedkeys('gv', 'n') + elseif a:mode ==# 'o' && v:operator !=# 'c' + " TODO: omap + " v:prevcount? + " Cancel waiting operator mode. + call feedkeys(v:operator, 'm') + endif + + call feedkeys(cnt, 'n') + + if a:mode ==# 'o' && v:operator ==# 'c' + " Note: This is the dirty hack. + execute matchstr(s:mapargrec(a:mapping . input, a:mode), + \ ':\zs.*\ze') + else + let mapping = a:mapping + while mapping =~# '<[[:alnum:]_-]\+>' + let mapping = substitute(mapping, '\c', + \ get(g:, 'mapleader', '\'), 'g') + let mapping = substitute(mapping, '\c', + \ get(g:, 'maplocalleader', '\'), 'g') + let ctrl = matchstr(mapping, '<\zs[[:alnum:]_-]\+\ze>') + execute 'let mapping = substitute( + \ mapping, "<' . ctrl . '>", "\<' . ctrl . '>", "")' + endwhile + call feedkeys(mapping . input, 'm') + endif + + return '' +endfunction + +function! dein#autoload#_dummy_complete(arglead, cmdline, cursorpos) abort + let command = matchstr(a:cmdline, '\h\w*') + if exists(':'.command) == 2 + " Remove the dummy command. + silent! execute 'delcommand' command + endif + + " Load plugins + call dein#autoload#_on_pre_cmd(tolower(command)) + + if exists(':'.command) == 2 + " Print the candidates + call feedkeys("\", 'n') + endif + + return [a:arglead] +endfunction + +function! s:source_plugin(rtps, index, plugin, sourced) abort + if a:plugin.sourced || index(a:sourced, a:plugin) >= 0 + return + endif + + call add(a:sourced, a:plugin) + + let index = a:index + + " Load dependencies + for name in get(a:plugin, 'depends', []) + if !has_key(g:dein#_plugins, name) + call dein#util#_error(printf( + \ 'Plugin name "%s" is not found.', name)) + continue + endif + + if !a:plugin.lazy && g:dein#_plugins[name].lazy + call dein#util#_error(printf( + \ 'Not lazy plugin "%s" depends lazy "%s" plugin.', + \ a:plugin.name, name)) + continue + endif + + if s:source_plugin(a:rtps, index, g:dein#_plugins[name], a:sourced) + let index += 1 + endif + endfor + + let a:plugin.sourced = 1 + + for on_source in filter(dein#util#_get_lazy_plugins(), + \ "index(get(v:val, 'on_source', []), a:plugin.name) >= 0") + if s:source_plugin(a:rtps, index, on_source, a:sourced) + let index += 1 + endif + endfor + + if has_key(a:plugin, 'dummy_commands') + for command in a:plugin.dummy_commands + silent! execute 'delcommand' command[0] + endfor + let a:plugin.dummy_commands = [] + endif + + if has_key(a:plugin, 'dummy_mappings') + for map in a:plugin.dummy_mappings + silent! execute map[0].'unmap' map[1] + endfor + let a:plugin.dummy_mappings = [] + endif + + if !a:plugin.merged || get(a:plugin, 'local', 0) + call insert(a:rtps, a:plugin.rtp, index) + if isdirectory(a:plugin.rtp.'/after') + call dein#util#_add_after(a:rtps, a:plugin.rtp.'/after') + endif + endif +endfunction +function! s:reset_ftplugin() abort + let filetype_state = dein#util#_redir('filetype') + + if exists('b:did_indent') || exists('b:did_ftplugin') + filetype plugin indent off + endif + + if filetype_state =~# 'plugin:ON' + silent! filetype plugin on + endif + + if filetype_state =~# 'indent:ON' + silent! filetype indent on + endif +endfunction +function! s:get_input() abort + let input = '' + let termstr = '' + + call feedkeys(termstr, 'n') + + while 1 + let char = getchar() + let input .= (type(char) == v:t_number) ? nr2char(char) : char + + let idx = stridx(input, termstr) + if idx >= 1 + let input = input[: idx - 1] + break + elseif idx == 0 + let input = '' + break + endif + endwhile + + return input +endfunction + +function! s:is_reset_ftplugin(plugins) abort + if &filetype ==# '' + return 0 + endif + + for plugin in a:plugins + let ftplugin = plugin.rtp . '/ftplugin/' . &filetype + let after = plugin.rtp . '/after/ftplugin/' . &filetype + if !empty(filter(['ftplugin', 'indent', + \ 'after/ftplugin', 'after/indent',], + \ "filereadable(printf('%s/%s/%s.vim', + \ plugin.rtp, v:val, &filetype))")) + \ || isdirectory(ftplugin) || isdirectory(after) + \ || glob(ftplugin. '_*.vim') !=# '' || glob(after . '_*.vim') !=# '' + return 1 + endif + endfor + return 0 +endfunction +function! s:mapargrec(map, mode) abort + let arg = maparg(a:map, a:mode) + while maparg(arg, a:mode) !=# '' + let arg = maparg(arg, a:mode) + endwhile + return arg +endfunction diff --git a/bundle/dein.vim/autoload/dein/install.vim b/bundle/dein.vim/autoload/dein/install.vim new file mode 100644 index 000000000..df6d70683 --- /dev/null +++ b/bundle/dein.vim/autoload/dein/install.vim @@ -0,0 +1,1435 @@ +"============================================================================= +" FILE: install.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +" Variables +let s:global_context = {} +let s:log = [] +let s:updates_log = [] +let s:progress = '' + +" Global options definition. +let g:dein#install_max_processes = + \ get(g:, 'dein#install_max_processes', 8) +let g:dein#install_progress_type = + \ get(g:, 'dein#install_progress_type', 'echo') +let g:dein#install_message_type = + \ get(g:, 'dein#install_message_type', 'echo') +let g:dein#install_process_timeout = + \ get(g:, 'dein#install_process_timeout', 120) +let g:dein#install_log_filename = + \ get(g:, 'dein#install_log_filename', '') + +function! s:get_job() abort + if !exists('s:Job') + let s:Job = vital#dein#import('System.Job') + endif + return s:Job +endfunction + +function! dein#install#_update(plugins, update_type, async) abort + if g:dein#_is_sudo + call s:error('update/install is disabled in sudo session.') + return + endif + + let plugins = dein#util#_get_plugins(a:plugins) + + if a:update_type ==# 'install' + let plugins = filter(plugins, '!isdirectory(v:val.path)') + elseif a:update_type ==# 'check_update' + let plugins = filter(plugins, 'isdirectory(v:val.path)') + endif + + if a:async && !empty(s:global_context) && + \ confirm('The installation has not finished. Cancel now?', + \ "yes\nNo", 2) != 1 + return + endif + + " Set context. + let context = s:init_context(plugins, a:update_type, a:async) + + call s:init_variables(context) + + if empty(plugins) + if a:update_type !=# 'check_update' + call s:notify('Target plugins are not found.') + call s:notify('You may have used the wrong plugin name,'. + \ ' or all of the plugins are already installed.') + endif + let s:global_context = {} + return + endif + + call s:start() + + if !a:async || has('vim_starting') + return s:update_loop(context) + endif + + augroup dein-install + autocmd! + augroup END + + if exists('s:timer') + call timer_stop(s:timer) + unlet s:timer + endif + + let s:timer = timer_start(1000, + \ {-> dein#install#_polling()}, {'repeat': -1}) +endfunction +function! s:update_loop(context) abort + let errored = 0 + try + if has('vim_starting') + while !empty(s:global_context) + let errored = s:install_async(a:context) + sleep 50ms + redraw + endwhile + else + let errored = s:install_blocking(a:context) + endif + catch + call s:error(v:exception) + call s:error(v:throwpoint) + return 1 + endtry + + return errored +endfunction + +function! dein#install#_reinstall(plugins) abort + let plugins = dein#util#_get_plugins(a:plugins) + + for plugin in plugins + " Remove the plugin + if plugin.type ==# 'none' + \ || get(plugin, 'local', 0) + \ || (plugin.sourced && + \ index(['dein'], plugin.normalized_name) >= 0) + call dein#util#_error( + \ printf('|%s| Cannot reinstall the plugin!', plugin.name)) + continue + endif + + " Reinstall. + call s:print_progress_message(printf('|%s| Reinstalling...', plugin.name)) + + if isdirectory(plugin.path) + call dein#install#_rm(plugin.path) + endif + endfor + + call dein#install#_update(dein#util#_convert2list(a:plugins), + \ 'install', 0) +endfunction +function! dein#install#_direct_install(repo, options) abort + let options = copy(a:options) + let options.merged = 0 + + let plugin = dein#add(a:repo, options) + if empty(plugin) + return + endif + + call dein#install#_update(plugin.name, 'install', 0) + call dein#source(plugin.name) + + " Add to direct_install.vim + let file = dein#get_direct_plugins_path() + let line = printf('call dein#add(%s, %s)', + \ string(a:repo), string(options)) + if !filereadable(file) + call writefile([line], file) + else + call writefile(add(readfile(file), line), file) + endif +endfunction +function! dein#install#_rollback(date, plugins) abort + let glob = s:get_rollback_directory() . '/' . a:date . '*' + let rollbacks = reverse(sort(dein#util#_globlist(glob))) + if empty(rollbacks) + return + endif + + call dein#install#_load_rollback(rollbacks[0], a:plugins) +endfunction + +function! dein#install#_recache_runtimepath() abort + if g:dein#_is_sudo + return + endif + + " Clear runtime path. + call s:clear_runtimepath() + + let plugins = values(dein#get()) + + let merged_plugins = filter(copy(plugins), 'v:val.merged') + + call s:copy_files(filter(copy(merged_plugins), 'v:val.lazy'), '') + " Remove plugin directory + call dein#install#_rm(dein#util#_get_runtime_path() . '/plugin') + call dein#install#_rm(dein#util#_get_runtime_path() . '/after/plugin') + + call s:copy_files(filter(copy(merged_plugins), '!v:val.lazy'), '') + + call s:helptags() + + call s:generate_ftplugin() + + " Clear ftdetect and after/ftdetect directories. + call dein#install#_rm( + \ dein#util#_get_runtime_path().'/ftdetect') + call dein#install#_rm( + \ dein#util#_get_runtime_path().'/after/ftdetect') + + call s:merge_files(plugins, 'ftdetect') + call s:merge_files(plugins, 'after/ftdetect') + + silent call dein#remote_plugins() + + call dein#call_hook('post_source') + + call dein#util#_save_merged_plugins() + + call dein#install#_save_rollback( + \ s:get_rollback_directory() . '/' . strftime('%Y%m%d%H%M%S'), []) + + call dein#clear_state() + + call s:log(strftime('Runtimepath updated: (%Y/%m/%d %H:%M:%S)')) +endfunction +function! s:clear_runtimepath() abort + if dein#util#_get_cache_path() ==# '' + call dein#util#_error('Invalid base path.') + return + endif + + let runtimepath = dein#util#_get_runtime_path() + + " Remove runtime path + call dein#install#_rm(runtimepath) + + if !isdirectory(runtimepath) + " Create runtime path + call mkdir(runtimepath, 'p') + endif +endfunction +function! s:helptags() abort + if g:dein#_runtime_path ==# '' || g:dein#_is_sudo + return '' + endif + + try + let tags = dein#util#_get_runtime_path() . '/doc' + if !isdirectory(tags) + call mkdir(tags, 'p') + endif + call s:copy_files(filter( + \ values(dein#get()), '!v:val.merged'), 'doc') + silent execute 'helptags' fnameescape(tags) + catch /^Vim(helptags):E151:/ + " Ignore an error that occurs when there is no help file + catch + call s:error('Error generating helptags:') + call s:error(v:exception) + call s:error(v:throwpoint) + endtry +endfunction +function! s:copy_files(plugins, directory) abort + let directory = (a:directory ==# '' ? '' : '/' . a:directory) + let srcs = filter(map(copy(a:plugins), 'v:val.rtp . directory'), + \ 'isdirectory(v:val)') + let stride = 50 + for start in range(0, len(srcs), stride) + call dein#install#_copy_directories(srcs[start : start + stride-1], + \ dein#util#_get_runtime_path() . directory) + endfor +endfunction +function! s:merge_files(plugins, directory) abort + let files = [] + for plugin in a:plugins + for file in filter(split(globpath( + \ plugin.rtp, a:directory.'/**', 1), '\n'), + \ '!isdirectory(v:val)') + let files += readfile(file, ':t') + endfor + endfor + + if !empty(files) + call dein#util#_writefile(printf('.dein/%s/%s.vim', + \ a:directory, a:directory), files) + endif +endfunction +function! s:list_directory(directory) abort + return dein#util#_globlist(a:directory . '/*') +endfunction +function! dein#install#_save_rollback(rollbackfile, plugins) abort + let revisions = {} + for plugin in filter(dein#util#_get_plugins(a:plugins), + \ 's:check_rollback(v:val)') + let rev = s:get_revision_number(plugin) + if rev !=# '' + let revisions[plugin.name] = rev + endif + endfor + + call writefile([json_encode(revisions)], expand(a:rollbackfile)) +endfunction +function! dein#install#_load_rollback(rollbackfile, plugins) abort + let revisions = json_decode(readfile(a:rollbackfile)[0]) + + let plugins = dein#util#_get_plugins(a:plugins) + call filter(plugins, "has_key(revisions, v:val.name) + \ && has_key(dein#util#_get_type(v:val.type), + \ 'get_rollback_command') + \ && s:check_rollback(v:val) + \ && s:get_revision_number(v:val) !=# revisions[v:val.name]") + if empty(plugins) + return + endif + + for plugin in plugins + let type = dein#util#_get_type(plugin.type) + let cmd = type.get_rollback_command( + \ dein#util#_get_type(plugin.type), revisions[plugin.name]) + call dein#install#_each(cmd, plugin) + endfor + + call dein#recache_runtimepath() + call s:error('Rollback to '.fnamemodify(a:rollbackfile, ':t').' version.') +endfunction +function! s:get_rollback_directory() abort + let parent = printf('%s/rollbacks/%s', + \ dein#util#_get_cache_path(), g:dein#_progname) + if !isdirectory(parent) + call mkdir(parent, 'p') + endif + + return parent +endfunction +function! s:check_rollback(plugin) abort + return !has_key(a:plugin, 'local') + \ && !get(a:plugin, 'frozen', 0) + \ && get(a:plugin, 'rev', '') ==# '' +endfunction + +function! dein#install#_get_default_ftplugin() abort + return [ + \ 'if exists("g:did_load_ftplugin")', + \ ' finish', + \ 'endif', + \ 'let g:did_load_ftplugin = 1', + \ '', + \ 'augroup filetypeplugin', + \ ' autocmd FileType * call s:ftplugin()', + \ 'augroup END', + \ '', + \ 'function! s:ftplugin()', + \ ' if exists("b:undo_ftplugin")', + \ ' silent! execute b:undo_ftplugin', + \ ' unlet! b:undo_ftplugin b:did_ftplugin', + \ ' endif', + \ '', + \ ' let filetype = expand("")', + \ ' if filetype !=# ""', + \ ' if &cpoptions =~# "S" && exists("b:did_ftplugin")', + \ ' unlet b:did_ftplugin', + \ ' endif', + \ ' for ft in split(filetype, ''\.'')', + \ ' execute "runtime! ftplugin/" . ft . ".vim"', + \ ' \ "ftplugin/" . ft . "_*.vim"', + \ ' \ "ftplugin/" . ft . "/*.vim"', + \ ' endfor', + \ ' endif', + \ ' call s:after_ftplugin()', + \ 'endfunction', + \ '', + \] +endfunction +function! s:generate_ftplugin() abort + " Create after/ftplugin + let after = dein#util#_get_runtime_path() . '/after/ftplugin' + if !isdirectory(after) + call mkdir(after, 'p') + endif + + " Merge g:dein#_ftplugin + let ftplugin = {} + for [key, string] in items(g:dein#_ftplugin) + for ft in (key ==# '_' ? ['_'] : split(key, '_')) + if !has_key(ftplugin, ft) + let ftplugin[ft] = (ft ==# '_') ? [] : [ + \ "if exists('b:undo_ftplugin')", + \ " let b:undo_ftplugin .= '|'", + \ 'else', + \ " let b:undo_ftplugin = ''", + \ 'endif', + \ ] + endif + let ftplugin[ft] += split(string, '\n') + endfor + endfor + + " Generate ftplugin.vim + call writefile(dein#install#_get_default_ftplugin() + [ + \ 'function! s:after_ftplugin()', + \ ] + get(ftplugin, '_', []) + ['endfunction'], + \ dein#util#_get_runtime_path() . '/ftplugin.vim') + + " Generate after/ftplugin + for [filetype, list] in filter(items(ftplugin), "v:val[0] !=# '_'") + call writefile(list, printf('%s/%s.vim', after, filetype)) + endfor +endfunction + +function! dein#install#_is_async() abort + return g:dein#install_max_processes > 1 +endfunction + +function! dein#install#_polling() abort + if exists('+guioptions') + " Note: guioptions-! does not work in async state + let save_guioptions = &guioptions + set guioptions-=! + endif + + call s:install_async(s:global_context) + + if exists('+guioptions') + let &guioptions = save_guioptions + endif +endfunction + +function! dein#install#_remote_plugins() abort + if !has('nvim') + return + endif + + if has('vim_starting') + " Note: UpdateRemotePlugins is not defined in vim_starting + autocmd dein VimEnter * silent call dein#remote_plugins() + return + endif + + if exists(':UpdateRemotePlugins') != 2 + return + endif + + " Load not loaded neovim remote plugins + let remote_plugins = filter(values(dein#get()), + \ "isdirectory(v:val.rtp . '/rplugin') && !v:val.sourced") + + call dein#autoload#_source(remote_plugins) + + call s:log('loaded remote plugins: ' . + \ string(map(copy(remote_plugins), 'v:val.name'))) + + let &runtimepath = dein#util#_join_rtp(dein#util#_uniq( + \ dein#util#_split_rtp(&runtimepath)), &runtimepath, '') + + let result = execute('UpdateRemotePlugins', '') + call s:log(result) +endfunction + +function! dein#install#_each(cmd, plugins) abort + let plugins = filter(dein#util#_get_plugins(a:plugins), + \ 'isdirectory(v:val.path)') + + let global_context_save = s:global_context + + let context = s:init_context(plugins, 'each', 0) + call s:init_variables(context) + + let cwd = getcwd() + let error = 0 + try + for plugin in plugins + call dein#install#_cd(plugin.path) + + if dein#install#_execute(a:cmd) + let error = 1 + endif + endfor + catch + call s:error(v:exception . ' ' . v:throwpoint) + return 1 + finally + let s:global_context = global_context_save + call dein#install#_cd(cwd) + endtry + + return error +endfunction +function! dein#install#_build(plugins) abort + let error = 0 + for plugin in filter(dein#util#_get_plugins(a:plugins), + \ "isdirectory(v:val.path) && has_key(v:val, 'build')") + call s:print_progress_message('Building: ' . plugin.name) + if dein#install#_each(plugin.build, plugin) + let error = 1 + endif + endfor + return error +endfunction + +function! dein#install#_get_log() abort + return s:log +endfunction +function! dein#install#_get_updates_log() abort + return s:updates_log +endfunction +function! dein#install#_get_context() abort + return s:global_context +endfunction +function! dein#install#_get_progress() abort + return s:progress +endfunction + +function! s:get_progress_message(plugin, number, max) abort + return printf('(%'.len(a:max).'d/%'.len(a:max).'d) [%s%s] %s', + \ a:number, a:max, + \ repeat('+', (a:number*20/a:max)), + \ repeat('-', 20 - (a:number*20/a:max)), + \ a:plugin.name) +endfunction +function! s:get_plugin_message(plugin, number, max, message) abort + return printf('(%'.len(a:max).'d/%d) |%-20s| %s', + \ a:number, a:max, a:plugin.name, a:message) +endfunction +function! s:get_short_message(plugin, number, max, message) abort + return printf('(%'.len(a:max).'d/%d) %s', a:number, a:max, a:message) +endfunction +function! s:get_sync_command(plugin, update_type, number, max) abort "{{{i + let type = dein#util#_get_type(a:plugin.type) + + if a:update_type ==# 'check_update' + \ && has_key(type, 'get_fetch_remote_command') + let cmd = type.get_fetch_remote_command(a:plugin) + elseif has_key(type, 'get_sync_command') + let cmd = type.get_sync_command(a:plugin) + else + return ['', ''] + endif + + if empty(cmd) + return ['', ''] + endif + + let message = s:get_plugin_message(a:plugin, a:number, a:max, string(cmd)) + + return [cmd, message] +endfunction +function! s:get_revision_number(plugin) abort + let type = dein#util#_get_type(a:plugin.type) + + if !isdirectory(a:plugin.path) + \ || !has_key(type, 'get_revision_number_command') + return '' + endif + + let cmd = type.get_revision_number_command(a:plugin) + if empty(cmd) + return '' + endif + + let rev = s:system_cd(cmd, a:plugin.path) + + " If rev contains spaces, it is error message + if rev =~# '\s' + call s:error(a:plugin.name) + call s:error('Error revision number: ' . rev) + return '' + elseif rev ==# '' + call s:error(a:plugin.name) + call s:error('Empty revision number: ' . rev) + return '' + endif + return rev +endfunction +function! s:get_revision_remote(plugin) abort + let type = dein#util#_get_type(a:plugin.type) + + if !isdirectory(a:plugin.path) + \ || !has_key(type, 'get_revision_remote_command') + return '' + endif + + let cmd = type.get_revision_remote_command(a:plugin) + if empty(cmd) + return '' + endif + + let rev = s:system_cd(cmd, a:plugin.path) + " If rev contains spaces, it is error message + return (rev !~# '\s') ? rev : '' +endfunction +function! s:get_updated_log_message(plugin, new_rev, old_rev) abort + let type = dein#util#_get_type(a:plugin.type) + + let cmd = has_key(type, 'get_log_command') ? + \ type.get_log_command(a:plugin, a:new_rev, a:old_rev) : '' + let log = empty(cmd) ? '' : s:system_cd(cmd, a:plugin.path) + return log !=# '' ? log : + \ (a:old_rev == a:new_rev) ? '' + \ : printf('%s -> %s', a:old_rev, a:new_rev) +endfunction +function! s:lock_revision(process, context) abort + let num = a:process.number + let max = a:context.max_plugins + let plugin = a:process.plugin + + let plugin.new_rev = s:get_revision_number(plugin) + + let type = dein#util#_get_type(plugin.type) + if !has_key(type, 'get_revision_lock_command') + return 0 + endif + + let cmd = type.get_revision_lock_command(plugin) + + if empty(cmd) || plugin.new_rev ==# get(plugin, 'rev', '') + " Skipped. + return 0 + elseif type(cmd) == v:t_string && cmd =~# '^E: ' + " Errored. + call s:error(plugin.path) + call s:error(cmd[3:]) + return -1 + endif + + if get(plugin, 'rev', '') !=# '' + call s:log(s:get_plugin_message(plugin, num, max, 'Locked')) + endif + + let result = s:system_cd(cmd, plugin.path) + let status = dein#install#_status() + + if status + call s:error(plugin.path) + call s:error(result) + return -1 + endif +endfunction +function! s:get_updated_message(context, plugins) abort + if empty(a:plugins) + return '' + endif + + return "Updated plugins:\n". + \ join(map(copy(a:plugins), + \ "' ' . v:val.name . (v:val.commit_count == 0 ? '' + \ : printf('(%d change%s)', + \ v:val.commit_count, + \ (v:val.commit_count == 1 ? '' : 's'))) + \ . ((a:context.update_type !=# 'check_update' + \ && v:val.old_rev !=# '' + \ && v:val.uri =~# '^\\h\\w*://github.com/') ? \"\\n\" + \ . printf(' %s/compare/%s...%s', + \ substitute(substitute(v:val.uri, '\\.git$', '', ''), + \ '^\\h\\w*:', 'https:', ''), + \ v:val.old_rev, v:val.new_rev) : '')") + \ , "\n") +endfunction +function! s:get_errored_message(plugins) abort + if empty(a:plugins) + return '' + endif + + let msg = "Error installing plugins:\n".join( + \ map(copy(a:plugins), "' ' . v:val.name"), "\n") + let msg .= "\n" + let msg .= "Please read the error message log with the :message command.\n" + + return msg +endfunction + + +" Helper functions +function! dein#install#_cd(path) abort + if !isdirectory(a:path) + return + endif + + try + noautocmd execute (haslocaldir() ? 'lcd' : 'cd') fnameescape(a:path) + catch + call s:error('Error cd to: ' . a:path) + call s:error('Current directory: ' . getcwd()) + call s:error(v:exception) + call s:error(v:throwpoint) + endtry +endfunction +function! dein#install#_system(command) abort + " Todo: use job API instead for Vim8/neovim only + " let job = s:Job.start() + " let exitval = job.wait() + + if !has('nvim') && type(a:command) == v:t_list + " system() does not support List arguments in Vim. + let command = s:args2string(a:command) + else + let command = a:command + endif + + let command = s:iconv(command, &encoding, 'char') + let output = s:iconv(system(command), 'char', &encoding) + return substitute(output, '\n$', '', '') +endfunction +function! dein#install#_status() abort + return v:shell_error +endfunction +function! s:system_cd(command, path) abort + let cwd = getcwd() + try + call dein#install#_cd(a:path) + return dein#install#_system(a:command) + finally + call dein#install#_cd(cwd) + endtry + return '' +endfunction + +function! dein#install#_execute(command) abort + return s:job_execute.execute(a:command) +endfunction +let s:job_execute = {} +function! s:job_execute.on_out(data) abort + for line in a:data + echo line + endfor + + let candidates = s:job_execute.candidates + if empty(candidates) + call add(candidates, a:data[0]) + else + let candidates[-1] .= a:data[0] + endif + let candidates += a:data[1:] +endfunction +function! s:job_execute.execute(cmd) abort + let self.candidates = [] + + let job = s:get_job().start( + \ s:convert_args(a:cmd), + \ {'on_stdout': self.on_out}) + + return job.wait(g:dein#install_process_timeout * 1000) +endfunction + +function! dein#install#_rm(path) abort + if !isdirectory(a:path) && !filereadable(a:path) + return + endif + + " Todo: use :python3 instead. + + " Note: delete rf is broken + " if has('patch-7.4.1120') + " try + " call delete(a:path, 'rf') + " catch + " call s:error('Error deleting directory: ' . a:path) + " call s:error(v:exception) + " call s:error(v:throwpoint) + " endtry + " return + " endif + + " Note: In Windows, ['rmdir', '/S', '/Q'] does not work. + " After Vim 8.0.928, double quote escape does not work in job. Too bad. + let cmdline = ' "' . a:path . '"' + if dein#util#_is_windows() + " Note: In rm command, must use "\" instead of "/". + let cmdline = substitute(cmdline, '/', '\\\\', 'g') + endif + + let rm_command = dein#util#_is_windows() ? 'cmd /C rmdir /S /Q' : 'rm -rf' + let cmdline = rm_command . cmdline + let result = system(cmdline) + if v:shell_error + call dein#util#_error(result) + endif + + " Error check. + if getftype(a:path) !=# '' + call dein#util#_error(printf('"%s" cannot be removed.', a:path)) + call dein#util#_error(printf('cmdline is "%s".', cmdline)) + endif +endfunction + +function! dein#install#_copy_directories(srcs, dest) abort + if empty(a:srcs) + return 0 + endif + + let status = 0 + if dein#util#_is_windows() + if !executable('robocopy') + call dein#util#_error('robocopy command is needed.') + return 1 + endif + + let temp = tempname() . '.bat' + let exclude = tempname() + + try + let lines = ['@echo off'] + let format ='robocopy.exe %s /E /NJH /NJS /NDL /NC /NS /MT /XO /XD ".git"' + for src in a:srcs + call add(lines, printf(format, + \ substitute(printf('"%s" "%s"', src, a:dest), + \ '/', '\\', 'g'))) + endfor + call writefile(lines, temp) + let result = dein#install#_system(temp) + finally + call delete(temp) + endtry + + " For some baffling reason robocopy almost always returns between 1 and 3 + " upon success + let status = dein#install#_status() + let status = (status > 3) ? status : 0 + + if status + call dein#util#_error('copy command failed.') + call dein#util#_error(s:iconv(result, 'char', &encoding)) + call dein#util#_error('cmdline: ' . temp) + call dein#util#_error('tempfile: ' . string(lines)) + endif + else " Not Windows + let srcs = map(filter(copy(a:srcs), + \ 'len(s:list_directory(v:val))'), 'shellescape(v:val . ''/'')') + let is_rsync = executable('rsync') + if is_rsync + let cmdline = printf("rsync -a -q --exclude '/.git/' %s %s", + \ join(srcs), shellescape(a:dest)) + let result = dein#install#_system(cmdline) + let status = dein#install#_status() + else + for src in srcs + let cmdline = printf('cp -Ra %s* %s', src, shellescape(a:dest)) + let result = dein#install#_system(cmdline) + let status = dein#install#_status() + if status + break + endif + endfor + endif + if status + call dein#util#_error('copy command failed.') + call dein#util#_error(result) + call dein#util#_error('cmdline: ' . cmdline) + endif + endif + + return status +endfunction + +function! s:install_blocking(context) abort + try + while 1 + call s:check_loop(a:context) + + if empty(a:context.processes) + \ && a:context.number == a:context.max_plugins + break + endif + endwhile + finally + call s:done(a:context) + endtry + + + return len(a:context.errored_plugins) +endfunction +function! s:install_async(context) abort + if empty(a:context) + return + endif + + call s:check_loop(a:context) + + if empty(a:context.processes) + \ && a:context.number == a:context.max_plugins + call s:done(a:context) + elseif a:context.number != a:context.prev_number + \ && a:context.number < len(a:context.plugins) + let plugin = a:context.plugins[a:context.number] + call s:print_progress_message( + \ s:get_progress_message(plugin, + \ a:context.number, a:context.max_plugins)) + let a:context.prev_number = a:context.number + endif + + return len(a:context.errored_plugins) +endfunction +function! s:check_loop(context) abort + while a:context.number < a:context.max_plugins + \ && len(a:context.processes) < g:dein#install_max_processes + + let plugin = a:context.plugins[a:context.number] + call s:sync(plugin, a:context) + + if !a:context.async + call s:print_progress_message( + \ s:get_progress_message(plugin, + \ a:context.number, a:context.max_plugins)) + endif + endwhile + + for process in a:context.processes + call s:check_output(a:context, process) + endfor + + " Filter eof processes. + call filter(a:context.processes, '!v:val.eof') +endfunction +function! s:restore_view(context) abort + if a:context.progress_type ==# 'tabline' + let &g:showtabline = a:context.showtabline + let &g:tabline = a:context.tabline + elseif a:context.progress_type ==# 'title' + let &g:title = a:context.title + let &g:titlestring = a:context.titlestring + endif +endfunction +function! s:init_context(plugins, update_type, async) abort + let context = {} + let context.update_type = a:update_type + let context.async = a:async + let context.synced_plugins = [] + let context.errored_plugins = [] + let context.processes = [] + let context.number = 0 + let context.prev_number = -1 + let context.plugins = a:plugins + let context.max_plugins = len(context.plugins) + let context.progress_type = (has('vim_starting') + \ && g:dein#install_progress_type !=# 'none') ? + \ 'echo' : g:dein#install_progress_type + if !has('nvim') && context.progress_type ==# 'title' + let context.progress_type = 'echo' + endif + let context.message_type = (has('vim_starting') + \ && g:dein#install_message_type !=# 'none') ? + \ 'echo' : g:dein#install_message_type + let context.laststatus = &g:laststatus + let context.showtabline = &g:showtabline + let context.tabline = &g:tabline + let context.title = &g:title + let context.titlestring = &g:titlestring + return context +endfunction +function! s:init_variables(context) abort + let s:progress = '' + let s:global_context = a:context + let s:log = [] + let s:updates_log = [] +endfunction +function! s:convert_args(args) abort + let args = s:iconv(a:args, &encoding, 'char') + if type(args) != v:t_list + let args = split(&shell) + split(&shellcmdflag) + [args] + endif + return args +endfunction +function! s:start() abort + call s:notify(strftime('Update started: (%Y/%m/%d %H:%M:%S)')) +endfunction +function! s:done(context) abort + call s:restore_view(a:context) + + if !has('vim_starting') + call s:notify(s:get_updated_message(a:context, a:context.synced_plugins)) + call s:notify(s:get_errored_message(a:context.errored_plugins)) + endif + + if a:context.update_type !=# 'check_update' + call dein#install#_recache_runtimepath() + endif + + if !empty(a:context.synced_plugins) + call dein#call_hook('done_update', a:context.synced_plugins) + call dein#source(map(copy(a:context.synced_plugins), 'v:val.name')) + endif + + call s:notify(strftime('Done: (%Y/%m/%d %H:%M:%S)')) + + " Disable installation handler + let s:global_context = {} + let s:progress = '' + augroup dein-install + autocmd! + augroup END + if exists('s:timer') + call timer_stop(s:timer) + unlet s:timer + endif +endfunction + +function! s:sync(plugin, context) abort + let a:context.number += 1 + + let num = a:context.number + let max = a:context.max_plugins + + if isdirectory(a:plugin.path) && get(a:plugin, 'frozen', 0) + " Skip frozen plugin + call s:log(s:get_plugin_message(a:plugin, num, max, 'is frozen.')) + return + endif + + let [cmd, message] = s:get_sync_command( + \ a:plugin, a:context.update_type, + \ a:context.number, a:context.max_plugins) + + if empty(cmd) + " Skip + call s:log(s:get_plugin_message(a:plugin, num, max, message)) + return + endif + + if type(cmd) == v:t_string && cmd =~# '^E: ' + " Errored. + + call s:print_progress_message(s:get_plugin_message( + \ a:plugin, num, max, 'Error')) + call s:error(cmd[3:]) + call add(a:context.errored_plugins, + \ a:plugin) + return + endif + + if !a:context.async + call s:print_progress_message(message) + endif + + let process = s:init_process(a:plugin, a:context, cmd) + if !empty(process) + call add(a:context.processes, process) + endif +endfunction +function! s:init_process(plugin, context, cmd) abort + let process = {} + + let cwd = getcwd() + let lang_save = $LANG + let prompt_save = $GIT_TERMINAL_PROMPT + try + let $LANG = 'C' + " Disable git prompt (git version >= 2.3.0) + let $GIT_TERMINAL_PROMPT = 0 + + call dein#install#_cd(a:plugin.path) + + let rev = s:get_revision_number(a:plugin) + + let process = { + \ 'number': a:context.number, + \ 'max_plugins': a:context.max_plugins, + \ 'rev': rev, + \ 'plugin': a:plugin, + \ 'output': '', + \ 'status': -1, + \ 'eof': 0, + \ 'installed': isdirectory(a:plugin.path), + \ } + + if isdirectory(a:plugin.path) + \ && !get(a:plugin, 'local', 0) + let rev_save = get(a:plugin, 'rev', '') + try + " Force checkout HEAD revision. + " The repository may be checked out. + let a:plugin.rev = '' + + call s:lock_revision(process, a:context) + finally + let a:plugin.rev = rev_save + endtry + endif + + call s:init_job(process, a:context, a:cmd) + finally + let $LANG = lang_save + let $GIT_TERMINAL_PROMPT = prompt_save + call dein#install#_cd(cwd) + endtry + + return process +endfunction +function! s:init_job(process, context, cmd) abort + let a:process.start_time = localtime() + + if !a:context.async + let a:process.output = dein#install#_system(a:cmd) + let a:process.status = dein#install#_status() + return + endif + + let a:process.async = {'eof': 0} + function! a:process.async.job_handler(data) abort + if !has_key(self, 'candidates') + let self.candidates = [] + endif + let candidates = self.candidates + if empty(candidates) + call add(candidates, a:data[0]) + else + let candidates[-1] .= a:data[0] + endif + + let candidates += a:data[1:] + endfunction + + function! a:process.async.on_exit(exitval) abort + let self.exitval = a:exitval + endfunction + + function! a:process.async.get(process) abort + " Check job status + let status = -1 + if has_key(a:process.job, 'exitval') + let self.eof = 1 + let status = a:process.job.exitval + endif + + let candidates = get(a:process.job, 'candidates', []) + let output = join((self.eof ? candidates : candidates[: -2]), "\n") + if output !=# '' + let a:process.output .= output + let a:process.start_time = localtime() + call s:log(s:get_short_message( + \ a:process.plugin, a:process.number, + \ a:process.max_plugins, output)) + endif + let self.candidates = self.eof ? [] : candidates[-1:] + + let is_timeout = (localtime() - a:process.start_time) + \ >= get(a:process.plugin, 'timeout', + \ g:dein#install_process_timeout) + + if self.eof + let is_timeout = 0 + let is_skip = 0 + else + let is_skip = 1 + endif + + if is_timeout + call a:process.job.stop() + let status = -1 + endif + + return [is_timeout, is_skip, status] + endfunction + + let a:process.job = s:get_job().start( + \ s:convert_args(a:cmd), { + \ 'on_stdout': a:process.async.job_handler, + \ 'on_stderr': a:process.async.job_handler, + \ 'on_exit': a:process.async.on_exit, + \ }) + let a:process.id = a:process.job.pid() + let a:process.job.candidates = [] +endfunction +function! s:check_output(context, process) abort + if a:context.async + let [is_timeout, is_skip, status] = a:process.async.get(a:process) + else + let [is_timeout, is_skip, status] = [0, 0, a:process.status] + endif + + if is_skip && !is_timeout + return + endif + + let num = a:process.number + let max = a:context.max_plugins + let plugin = a:process.plugin + + if isdirectory(plugin.path) + \ && get(plugin, 'rev', '') !=# '' + \ && !get(plugin, 'local', 0) + " Restore revision. + call s:lock_revision(a:process, a:context) + endif + + let new_rev = (a:context.update_type ==# 'check_update') ? + \ s:get_revision_remote(plugin) : + \ s:get_revision_number(plugin) + + if is_timeout || status + call s:log(s:get_plugin_message(plugin, num, max, 'Error')) + call s:error(plugin.path) + if !a:process.installed + if !isdirectory(plugin.path) + call s:error('Maybe wrong username or repository.') + elseif isdirectory(plugin.path) + call s:error('Remove the installed directory:' . plugin.path) + call dein#install#_rm(plugin.path) + endif + endif + + call s:error((is_timeout ? + \ strftime('Process timeout: (%Y/%m/%d %H:%M:%S)') : + \ split(a:process.output, '\n') + \ )) + + call add(a:context.errored_plugins, + \ plugin) + elseif a:process.rev ==# new_rev + \ || (a:context.update_type ==# 'check_update' && new_rev ==# '') + if a:context.update_type !=# 'check_update' + call s:log(s:get_plugin_message( + \ plugin, num, max, 'Same revision')) + endif + else + call s:log(s:get_plugin_message(plugin, num, max, 'Updated')) + + if a:context.update_type !=# 'check_update' + let log_messages = split(s:get_updated_log_message( + \ plugin, new_rev, a:process.rev), '\n') + let plugin.commit_count = len(log_messages) + call s:log(map(log_messages, + \ 's:get_short_message(plugin, num, max, v:val)')) + else + let plugin.commit_count = 0 + endif + + let plugin.old_rev = a:process.rev + let plugin.new_rev = new_rev + + let type = dein#util#_get_type(plugin.type) + let plugin.uri = has_key(type, 'get_uri') ? + \ type.get_uri(plugin.repo, plugin) : '' + + let cwd = getcwd() + try + call dein#install#_cd(plugin.path) + + call dein#call_hook('post_update', plugin) + finally + call dein#install#_cd(cwd) + endtry + + if dein#install#_build([plugin.name]) + call s:log(s:get_plugin_message(plugin, num, max, 'Build failed')) + call s:error(plugin.path) + " Remove. + call add(a:context.errored_plugins, plugin) + else + call add(a:context.synced_plugins, plugin) + endif + endif + + let a:process.eof = 1 +endfunction + +function! s:iconv(expr, from, to) abort + if a:from ==# '' || a:to ==# '' || a:from ==? a:to + return a:expr + endif + + if type(a:expr) == v:t_list + return map(copy(a:expr), 'iconv(v:val, a:from, a:to)') + else + let result = iconv(a:expr, a:from, a:to) + return result !=# '' ? result : a:expr + endif +endfunction +function! s:print_progress_message(msg) abort + let msg = dein#util#_convert2list(a:msg) + let context = s:global_context + if empty(msg) || empty(context) + return + endif + + let progress_type = context.progress_type + if progress_type ==# 'tabline' + set showtabline=2 + let &g:tabline = join(msg, "\n") + elseif progress_type ==# 'title' + set title + let &g:titlestring = join(msg, "\n") + elseif progress_type ==# 'echo' + call s:echo(msg, 'echo') + endif + + call s:log(msg) + + let s:progress = join(msg, "\n") +endfunction +function! s:error(msg) abort + let msg = dein#util#_convert2list(a:msg) + if empty(msg) + return + endif + + call s:echo(msg, 'error') + + call s:updates_log(msg) +endfunction +function! s:notify(msg) abort + let msg = dein#util#_convert2list(a:msg) + let context = s:global_context + if empty(msg) || empty(context) + return + endif + + if context.message_type ==# 'echo' + call dein#util#_notify(a:msg) + endif + + call s:updates_log(msg) + let s:progress = join(msg, "\n") +endfunction +function! s:updates_log(msg) abort + let msg = dein#util#_convert2list(a:msg) + + let s:updates_log += msg + call s:log(msg) +endfunction +function! s:log(msg) abort + let msg = dein#util#_convert2list(a:msg) + let s:log += msg + call s:append_log_file(msg) +endfunction +function! s:append_log_file(msg) abort + let logfile = dein#util#_expand(g:dein#install_log_filename) + if logfile ==# '' + return + endif + + let msg = a:msg + " Appends to log file. + if filereadable(logfile) + let msg = readfile(logfile) + msg + endif + + let dir = fnamemodify(logfile, ':h') + if !isdirectory(dir) + call mkdir(dir, 'p') + endif + call writefile(msg, logfile) +endfunction + + +function! s:echo(expr, mode) abort + let msg = map(filter(dein#util#_convert2list(a:expr), "v:val !=# ''"), + \ "'[dein] ' . v:val") + if empty(msg) + return + endif + + let more_save = &more + let showcmd_save = &showcmd + let ruler_save = &ruler + try + set nomore + set noshowcmd + set noruler + + let height = max([1, &cmdheight]) + echo '' + for i in range(0, len(msg)-1, height) + redraw + + let m = join(msg[i : i+height-1], "\n") + call s:echo_mode(m, a:mode) + if has('vim_starting') + echo '' + endif + endfor + finally + let &more = more_save + let &showcmd = showcmd_save + let &ruler = ruler_save + endtry +endfunction +function! s:echo_mode(m, mode) abort + for m in split(a:m, '\r\?\n', 1) + if !has('vim_starting') && a:mode !=# 'error' + let m = s:truncate_skipping(m, &columns - 1, &columns/3, '...') + endif + + if a:mode ==# 'error' + echohl WarningMsg | echomsg m | echohl None + elseif a:mode ==# 'echomsg' + echomsg m + else + echo m + endif + endfor +endfunction + +function! s:truncate_skipping(str, max, footer_width, separator) abort + let width = strwidth(a:str) + if width <= a:max + let ret = a:str + else + let header_width = a:max - strwidth(a:separator) - a:footer_width + let ret = s:strwidthpart(a:str, header_width) . a:separator + \ . s:strwidthpart_reverse(a:str, a:footer_width) + endif + + return ret +endfunction +function! s:strwidthpart(str, width) abort + if a:width <= 0 + return '' + endif + let ret = a:str + let width = strwidth(a:str) + while width > a:width + let char = matchstr(ret, '.$') + let ret = ret[: -1 - len(char)] + let width -= strwidth(char) + endwhile + + return ret +endfunction +function! s:strwidthpart_reverse(str, width) abort + if a:width <= 0 + return '' + endif + let ret = a:str + let width = strwidth(a:str) + while width > a:width + let char = matchstr(ret, '^.') + let ret = ret[len(char) :] + let width -= strwidth(char) + endwhile + + return ret +endfunction + +function! s:args2string(args) abort + return type(a:args) == v:t_string ? a:args : + \ dein#util#_is_windows() ? + \ dein#install#_args2string_windows(a:args) : + \ dein#install#_args2string_unix(a:args) +endfunction + +function! dein#install#_args2string_windows(args) abort + if empty(a:args) + return '' + endif + let str = (a:args[0] =~# ' ') ? '"' . a:args[0] . '"' : a:args[0] + if len(a:args) > 1 + let str .= ' ' + let str .= join(map(copy(a:args[1:]), '''"'' . v:val . ''"''')) + endif + return str +endfunction +function! dein#install#_args2string_unix(args) abort + return join(map(copy(a:args), 'string(v:val)')) +endfunction diff --git a/bundle/dein.vim/autoload/dein/parse.vim b/bundle/dein.vim/autoload/dein/parse.vim new file mode 100644 index 000000000..1f656f102 --- /dev/null +++ b/bundle/dein.vim/autoload/dein/parse.vim @@ -0,0 +1,411 @@ +"============================================================================= +" FILE: parse.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +" Global options definition." +let g:dein#enable_name_conversion = + \ get(g:, 'dein#enable_name_conversion', 0) + + +let s:git = dein#types#git#define() + +function! dein#parse#_add(repo, options) abort + let plugin = dein#parse#_dict(dein#parse#_init(a:repo, a:options)) + if (has_key(g:dein#_plugins, plugin.name) + \ && g:dein#_plugins[plugin.name].sourced) + \ || !get(plugin, 'if', 1) + " Skip already loaded or not enabled plugin. + return {} + endif + + if plugin.lazy && plugin.rtp !=# '' + call s:parse_lazy(plugin) + endif + + if has_key(g:dein#_plugins, plugin.name) + \ && g:dein#_plugins[plugin.name].sourced + let plugin.sourced = 1 + endif + let g:dein#_plugins[plugin.name] = plugin + if has_key(plugin, 'hook_add') + call dein#util#_execute_hook(plugin, plugin.hook_add) + endif + if has_key(plugin, 'ftplugin') + call s:merge_ftplugin(plugin.ftplugin) + endif + return plugin +endfunction +function! dein#parse#_init(repo, options) abort + let repo = dein#util#_expand(a:repo) + let plugin = has_key(a:options, 'type') ? + \ dein#util#_get_type(a:options.type).init(repo, a:options) : + \ s:git.init(repo, a:options) + if empty(plugin) + let plugin = s:check_type(repo, a:options) + endif + call extend(plugin, a:options) + let plugin.repo = repo + if !empty(a:options) + let plugin.orig_opts = deepcopy(a:options) + endif + return plugin +endfunction +function! dein#parse#_dict(plugin) abort + let plugin = { + \ 'rtp': '', + \ 'sourced': 0, + \ } + call extend(plugin, a:plugin) + + if !has_key(plugin, 'name') + let plugin.name = dein#parse#_name_conversion(plugin.repo) + endif + + if !has_key(plugin, 'normalized_name') + let plugin.normalized_name = substitute( + \ fnamemodify(plugin.name, ':r'), + \ '\c^n\?vim[_-]\|[_-]n\?vim$', '', 'g') + endif + + if !has_key(a:plugin, 'name') && g:dein#enable_name_conversion + " Use normalized name. + let plugin.name = plugin.normalized_name + endif + + if !has_key(plugin, 'path') + let plugin.path = (plugin.repo =~# '^/\|^\a:[/\\]') ? + \ plugin.repo : dein#util#_get_base_path().'/repos/'.plugin.name + endif + + let plugin.path = dein#util#_chomp(dein#util#_expand(plugin.path)) + if get(plugin, 'rev', '') !=# '' + " Add revision path + let plugin.path .= '_' . substitute( + \ plugin.rev, '[^[:alnum:].-]', '_', 'g') + endif + + " Check relative path + if (!has_key(a:plugin, 'rtp') || a:plugin.rtp !=# '') + \ && plugin.rtp !~# '^\%([~/]\|\a\+:\)' + let plugin.rtp = plugin.path.'/'.plugin.rtp + endif + if plugin.rtp[0:] ==# '~' + let plugin.rtp = dein#util#_expand(plugin.rtp) + endif + let plugin.rtp = dein#util#_chomp(plugin.rtp) + if g:dein#_is_sudo && !get(plugin, 'trusted', 0) + let plugin.rtp = '' + endif + + if has_key(plugin, 'script_type') + " Add script_type. + let plugin.path .= '/' . plugin.script_type + endif + + if has_key(plugin, 'depends') && type(plugin.depends) != v:t_list + let plugin.depends = [plugin.depends] + endif + + " Deprecated check. + for key in filter(['directory', 'base'], 'has_key(plugin, v:val)') + call dein#util#_error('plugin name = ' . plugin.name) + call dein#util#_error(string(key) . ' is deprecated.') + endfor + + if !has_key(plugin, 'lazy') + let plugin.lazy = + \ has_key(plugin, 'on_i') + \ || has_key(plugin, 'on_idle') + \ || has_key(plugin, 'on_ft') + \ || has_key(plugin, 'on_cmd') + \ || has_key(plugin, 'on_func') + \ || has_key(plugin, 'on_map') + \ || has_key(plugin, 'on_path') + \ || has_key(plugin, 'on_if') + \ || has_key(plugin, 'on_event') + \ || has_key(plugin, 'on_source') + endif + + if !has_key(a:plugin, 'merged') + let plugin.merged = !plugin.lazy + \ && plugin.normalized_name !=# 'dein' + \ && !has_key(plugin, 'local') + \ && !has_key(plugin, 'build') + \ && !has_key(plugin, 'if') + \ && stridx(plugin.rtp, dein#util#_get_base_path()) == 0 + endif + + if has_key(plugin, 'if') && type(plugin.if) == v:t_string + let plugin.if = eval(a:plugin.if) + endif + + " Hooks + for hook in filter([ + \ 'hook_add', 'hook_source', + \ 'hook_post_source', 'hook_post_update', + \ ], 'has_key(plugin, v:val) && type(plugin[v:val]) == v:t_string') + let plugin[hook] = substitute(plugin[hook], + \ '\n\s*\\\|\%(^\|\n\)\s*"[^\n]*', '', 'g') + endfor + + return plugin +endfunction +function! dein#parse#_load_toml(filename, default) abort + try + let toml = dein#toml#parse_file(dein#util#_expand(a:filename)) + catch /Text.TOML:/ + call dein#util#_error('Invalid toml format: ' . a:filename) + call dein#util#_error(v:exception) + return 1 + endtry + if type(toml) != v:t_dict + call dein#util#_error('Invalid toml file: ' . a:filename) + return 1 + endif + + " Parse. + if has_key(toml, 'hook_add') + let pattern = '\n\s*\\\|\%(^\|\n\)\s*"[^\n]*' + let g:dein#_hook_add .= "\n" . substitute( + \ toml.hook_add, pattern, '', 'g') + endif + if has_key(toml, 'ftplugin') + call s:merge_ftplugin(toml.ftplugin) + endif + + if has_key(toml, 'plugins') + for plugin in toml.plugins + if !has_key(plugin, 'repo') + call dein#util#_error('No repository plugin data: ' . a:filename) + return 1 + endif + + let options = extend(plugin, a:default, 'keep') + call dein#add(plugin.repo, options) + endfor + endif + + " Add to g:dein#_vimrcs + call add(g:dein#_vimrcs, dein#util#_expand(a:filename)) +endfunction +function! dein#parse#_plugins2toml(plugins) abort + let toml = [] + + let default = dein#parse#_dict(dein#parse#_init('', {})) + let default.if = '' + let default.frozen = 0 + let default.local = 0 + let default.depends = [] + let default.on_i = 0 + let default.on_idle = 0 + let default.on_ft = [] + let default.on_cmd = [] + let default.on_func = [] + let default.on_map = [] + let default.on_path = [] + let default.on_source = [] + let default.build = '' + let default.hook_add = '' + let default.hook_source = '' + let default.hook_post_source = '' + let default.hook_post_update = '' + + let skip_default = { + \ 'type': 1, + \ 'path': 1, + \ 'rtp': 1, + \ 'sourced': 1, + \ 'orig_opts': 1, + \ 'repo': 1, + \ } + + for plugin in dein#util#_sort_by(a:plugins, 'v:val.repo') + let toml += ['[[plugins]]', + \ 'repo = ' . string(plugin.repo)] + + for key in filter(sort(keys(default)), + \ '!has_key(skip_default, v:val) && has_key(plugin, v:val) + \ && (type(plugin[v:val]) !=# type(default[v:val]) + \ || plugin[v:val] !=# default[v:val])') + let val = plugin[key] + if key =~# '^hook_' + call add(toml, key . " = '''") + let toml += split(val, '\n') + call add(toml, "'''") + else + call add(toml, key . ' = ' . string( + \ (type(val) == v:t_list && len(val) == 1) ? val[0] : val)) + endif + unlet! val + endfor + + call add(toml, '') + endfor + + return toml +endfunction +function! dein#parse#_load_dict(dict, default) abort + for [repo, options] in items(a:dict) + call dein#add(repo, extend(copy(options), a:default, 'keep')) + endfor +endfunction +function! dein#parse#_local(localdir, options, includes) abort + let base = fnamemodify(dein#util#_expand(a:localdir), ':p') + let directories = [] + for glob in a:includes + let directories += map(filter(dein#util#_globlist(base . glob), + \ 'isdirectory(v:val)'), " + \ substitute(dein#util#_substitute_path( + \ fnamemodify(v:val, ':p')), '/$', '', '')") + endfor + + for dir in dein#util#_uniq(directories) + let options = extend({ + \ 'repo': dir, 'local': 1, 'path': dir, + \ 'name': fnamemodify(dir, ':t') + \ }, a:options) + + if has_key(g:dein#_plugins, options.name) + call dein#config(options.name, options) + else + call dein#add(dir, options) + endif + endfor +endfunction +function! s:parse_lazy(plugin) abort + " Auto convert2list. + for key in filter([ + \ 'on_ft', 'on_path', 'on_cmd', 'on_func', 'on_map', + \ 'on_source', 'on_event', + \ ], 'has_key(a:plugin, v:val) + \ && type(a:plugin[v:val]) != v:t_list + \ && type(a:plugin[v:val]) != v:t_dict + \') + let a:plugin[key] = [a:plugin[key]] + endfor + + if get(a:plugin, 'on_i', 0) + let a:plugin.on_event = ['InsertEnter'] + endif + if get(a:plugin, 'on_idle', 0) + let a:plugin.on_event = ['FocusLost', 'CursorHold'] + endif + if has_key(a:plugin, 'on_event') + for event in a:plugin.on_event + if !has_key(g:dein#_event_plugins, event) + let g:dein#_event_plugins[event] = [a:plugin.name] + else + call add(g:dein#_event_plugins[event], a:plugin.name) + let g:dein#_event_plugins[event] = dein#util#_uniq( + \ g:dein#_event_plugins[event]) + endif + endfor + endif + + if has_key(a:plugin, 'on_cmd') + call s:generate_dummy_commands(a:plugin) + endif + if has_key(a:plugin, 'on_map') + call s:generate_dummy_mappings(a:plugin) + endif +endfunction +function! s:generate_dummy_commands(plugin) abort + let a:plugin.dummy_commands = [] + for name in a:plugin.on_cmd + " Define dummy commands. + let raw_cmd = 'command ' + \ . '-complete=customlist,dein#autoload#_dummy_complete' + \ . ' -bang -bar -range -nargs=* '. name + \ . printf(" call dein#autoload#_on_cmd(%s, %s, , + \ expand(''), expand(''), expand(''))", + \ string(name), string(a:plugin.name)) + + call add(a:plugin.dummy_commands, [name, raw_cmd]) + silent! execute raw_cmd + endfor +endfunction +function! s:generate_dummy_mappings(plugin) abort + let a:plugin.dummy_mappings = [] + let items = type(a:plugin.on_map) == v:t_dict ? + \ map(items(a:plugin.on_map), + \ "[split(v:val[0], '\\zs'), dein#util#_convert2list(v:val[1])]") : + \ map(copy(a:plugin.on_map), + \ "type(v:val) == v:t_list ? + \ [split(v:val[0], '\\zs'), v:val[1:]] : + \ [['n', 'x'], [v:val]]") + for [modes, mappings] in items + if mappings ==# [''] + " Use plugin name. + let mappings = ['(' . a:plugin.normalized_name] + if stridx(a:plugin.normalized_name, '-') >= 0 + " The plugin mappings may use "_" instead of "-". + call add(mappings, '(' . + \ substitute(a:plugin.normalized_name, '-', '_', 'g')) + endif + endif + + for mapping in mappings + " Define dummy mappings. + let prefix = printf('dein#autoload#_on_map(%s, %s,', + \ string(substitute(mapping, '<', '', 'g')), + \ string(a:plugin.name)) + for mode in modes + let raw_map = mode.'noremap '.mapping + \ . (mode ==# 'c' ? " \=" : + \ mode ==# 'i' ? " \:call " : " :\call ") . prefix + \ . string(mode) . ')' + call add(a:plugin.dummy_mappings, [mode, mapping, raw_map]) + silent! execute raw_map + endfor + endfor + endfor +endfunction +function! s:merge_ftplugin(ftplugin) abort + let pattern = '\n\s*\\\|\%(^\|\n\)\s*"[^\n]*' + for [ft, val] in items(a:ftplugin) + if !has_key(g:dein#_ftplugin, ft) + let g:dein#_ftplugin[ft] = val + else + let g:dein#_ftplugin[ft] .= "\n" . val + endif + endfor + call map(g:dein#_ftplugin, "substitute(v:val, pattern, '', 'g')") +endfunction + +function! dein#parse#_get_types() abort + if !exists('s:types') + " Load types. + let s:types = {} + for type in filter(map(split(globpath(&runtimepath, + \ 'autoload/dein/types/*.vim', 1), '\n'), + \ "dein#types#{fnamemodify(v:val, ':t:r')}#define()"), + \ '!empty(v:val)') + let s:types[type.name] = type + endfor + endif + return s:types +endfunction +function! s:check_type(repo, options) abort + let plugin = {} + for type in values(dein#parse#_get_types()) + let plugin = type.init(a:repo, a:options) + if !empty(plugin) + break + endif + endfor + + if empty(plugin) + let plugin.type = 'none' + let plugin.local = 1 + let plugin.path = isdirectory(a:repo) ? a:repo : '' + endif + + return plugin +endfunction + +function! dein#parse#_name_conversion(path) abort + return fnamemodify(get(split(a:path, ':'), -1, ''), + \ ':s?/$??:t:s?\c\.git\s*$??') +endfunction diff --git a/bundle/dein.vim/autoload/dein/toml.vim b/bundle/dein.vim/autoload/dein/toml.vim new file mode 100644 index 000000000..73b175e87 --- /dev/null +++ b/bundle/dein.vim/autoload/dein/toml.vim @@ -0,0 +1,358 @@ +" Based on @kamichidu code + +" +" public api +" +function! dein#toml#parse(text) abort + let input = { + \ 'text': a:text, + \ 'p': 0, + \ 'length': strlen(a:text), + \} + return s:_parse(input) +endfunction + +function! dein#toml#parse_file(filename) abort + if !filereadable(a:filename) + throw printf("Text.TOML: No such file `%s'.", a:filename) + endif + + let text = join(readfile(a:filename), "\n") + " fileencoding is always utf8 + return dein#toml#parse(iconv(text, 'utf8', &encoding)) +endfunction + +" +" private api +" +" work around: '[^\r\n]*' doesn't work well in old-vim, but "[^\r\n]*" works well +let s:skip_pattern = '\C^\%(\_s\+\|' . "#[^\r\n]*" . '\)' +let s:table_name_pattern = '\%([^ [:tab:]#.[\]=]\+\)' +let s:table_key_pattern = s:table_name_pattern + +function! s:_skip(input) abort + while s:_match(a:input, '\%(\_s\|#\)') + let a:input.p = matchend(a:input.text, s:skip_pattern, a:input.p) + endwhile +endfunction + +" XXX: old engine is faster than NFA engine (in this context). +if exists('+regexpengine') + let s:regex_prefix = '\%#=1\C^' +else + let s:regex_prefix = '\C^' +endif + +function! s:_consume(input, pattern) abort + call s:_skip(a:input) + let end = matchend(a:input.text, s:regex_prefix . a:pattern, a:input.p) + + if end == -1 + call s:_error(a:input) + elseif end == a:input.p + return '' + endif + + let matched = strpart(a:input.text, a:input.p, end - a:input.p) + let a:input.p = end + return matched +endfunction + +function! s:_match(input, pattern) abort + return match(a:input.text, s:regex_prefix . a:pattern, a:input.p) != -1 +endfunction + +function! s:_eof(input) abort + return a:input.p >= a:input.length +endfunction + +function! s:_error(input) abort + let buf = [] + let offset = 0 + while (a:input.p + offset) < a:input.length && a:input.text[a:input.p + offset] !~# "[\r\n]" + let buf += [a:input.text[a:input.p + offset]] + let offset += 1 + endwhile + + throw printf("Text.TOML: Illegal toml format at L%d:`%s':%d.", + \ len(split(a:input.text[: a:input.p], "\n", 1)), + \ join(buf, ''), a:input.p) +endfunction + +function! s:_parse(input) abort + let data = {} + + call s:_skip(a:input) + while !s:_eof(a:input) + if s:_match(a:input, '[^ [:tab:]#.[\]]') + let key = s:_key(a:input) + call s:_equals(a:input) + let value = s:_value(a:input) + + call s:_put_dict(data, key, value) + + unlet value + elseif s:_match(a:input, '\[\[') + let [key, value] = s:_array_of_tables(a:input) + + call s:_put_array(data, key, value) + + unlet value + elseif s:_match(a:input, '\[') + let [key, value] = s:_table(a:input) + + call s:_put_dict(data, key, value) + + unlet value + else + call s:_error(a:input) + endif + call s:_skip(a:input) + endwhile + + return data +endfunction + +function! s:_key(input) abort + let s = s:_consume(a:input, s:table_key_pattern) + return s +endfunction + +function! s:_equals(input) abort + call s:_consume(a:input, '=') + return '=' +endfunction + +function! s:_value(input) abort + call s:_skip(a:input) + + if s:_match(a:input, '"\{3}') + return s:_multiline_basic_string(a:input) + elseif s:_match(a:input, '"\{1}') + return s:_basic_string(a:input) + elseif s:_match(a:input, "'\\{3}") + return s:_multiline_literal(a:input) + elseif s:_match(a:input, "'\\{1}") + return s:_literal(a:input) + elseif s:_match(a:input, '\[') + return s:_array(a:input) + elseif s:_match(a:input, '\%(true\|false\)') + return s:_boolean(a:input) + elseif s:_match(a:input, '\d\{4}-') + return s:_datetime(a:input) + elseif s:_match(a:input, '[+-]\?\%(\d\+\.\d\|\d\+\%(\.\d\+\)\?[eE]\)') + return s:_float(a:input) + elseif s:_match(a:input, '{') + return s:_inline_table(a:input) + else + return s:_integer(a:input) + endif +endfunction + +" +" String +" +function! s:_basic_string(input) abort + let s = s:_consume(a:input, '"\%(\\"\|[^"]\)*"') + let s = s[1 : -2] + return s:_unescape(s) +endfunction + +function! s:_multiline_basic_string(input) abort + let s = s:_consume(a:input, '"\{3}\_.\{-}"\{3}') + let s = s[3 : -4] + let s = substitute(s, "^\n", '', '') + let s = substitute(s, '\\' . "\n" . '\_s*', '', 'g') + return s:_unescape(s) +endfunction + +function! s:_literal(input) abort + let s = s:_consume(a:input, "'[^']*'") + return s[1 : -2] +endfunction + +function! s:_multiline_literal(input) abort + let s = s:_consume(a:input, "'\\{3}.\\{-}'\\{3}") + let s = s[3 : -4] + let s = substitute(s, "^\n", '', '') + return s +endfunction + +" +" Integer +" +function! s:_integer(input) abort + let s = s:_consume(a:input, '[+-]\?\d\+') + return str2nr(s) +endfunction + +" +" Float +" +function! s:_float(input) abort + if s:_match(a:input, '[+-]\?[0-9.]\+[eE][+-]\?\d\+') + return s:_exponent(a:input) + else + return s:_fractional(a:input) + endif +endfunction + +function! s:_fractional(input) abort + let s = s:_consume(a:input, '[+-]\?[0-9.]\+') + return str2float(s) +endfunction + +function! s:_exponent(input) abort + let s = s:_consume(a:input, '[+-]\?[0-9.]\+[eE][+-]\?\d\+') + return str2float(s) +endfunction + +" +" Boolean +" +function! s:_boolean(input) abort + let s = s:_consume(a:input, '\%(true\|false\)') + return (s ==# 'true') ? 1 : 0 +endfunction + +" +" Datetime +" +function! s:_datetime(input) abort + let s = s:_consume(a:input, '\d\{4}-\d\{2}-\d\{2}T\d\{2}:\d\{2}:\d\{2}\%(Z\|-\?\d\{2}:\d\{2}\|\.\d\+-\d\{2}:\d\{2}\)') + return s +endfunction + +" +" Array +" +function! s:_array(input) abort + let ary = [] + let _ = s:_consume(a:input, '\[') + call s:_skip(a:input) + while !s:_eof(a:input) && !s:_match(a:input, '\]') + let ary += [s:_value(a:input)] + call s:_consume(a:input, ',\?') + call s:_skip(a:input) + endwhile + let _ = s:_consume(a:input, '\]') + return ary +endfunction + +" +" Table +" +function! s:_table(input) abort + let tbl = {} + let name = s:_consume(a:input, '\[\s*' . s:table_name_pattern . '\%(\s*\.\s*' . s:table_name_pattern . '\)*\s*\]') + let name = name[1 : -2] + call s:_skip(a:input) + " while !s:_eof(a:input) && !s:_match(a:input, '\[\{1,2}[a-zA-Z0-9.]\+\]\{1,2}') + while !s:_eof(a:input) && !s:_match(a:input, '\[') + let key = s:_key(a:input) + call s:_equals(a:input) + let value = s:_value(a:input) + + let tbl[key] = value + + unlet value + call s:_skip(a:input) + endwhile + return [name, tbl] +endfunction + +" +" Inline Table +" +function! s:_inline_table(input) abort + let tbl = {} + let _ = s:_consume(a:input, '{') + call s:_skip(a:input) + while !s:_eof(a:input) && !s:_match(a:input, '}') + let key = s:_key(a:input) + call s:_equals(a:input) + let tbl[key] = s:_value(a:input) + call s:_consume(a:input, ',\?') + call s:_skip(a:input) + endwhile + let _ = s:_consume(a:input, '}') + return tbl +endfunction + +" +" Array of tables +" +function! s:_array_of_tables(input) abort + let tbl = {} + let name = s:_consume(a:input, '\[\[\s*' . s:table_name_pattern . '\%(\s*\.\s*' . s:table_name_pattern . '\)*\s*\]\]') + let name = name[2 : -3] + call s:_skip(a:input) + " while !s:_eof(a:input) && !s:_match(a:input, '\[\{1,2}[a-zA-Z0-9.]\+\]\{1,2}') + while !s:_eof(a:input) && !s:_match(a:input, '\[') + let key = s:_key(a:input) + call s:_equals(a:input) + let value = s:_value(a:input) + + let tbl[key] = value + + unlet value + call s:_skip(a:input) + endwhile + return [name, [tbl]] +endfunction + +function! s:_unescape(text) abort + let text = a:text + let text = substitute(text, '\\"', '"', 'g') + let text = substitute(text, '\\b', "\b", 'g') + let text = substitute(text, '\\t', "\t", 'g') + let text = substitute(text, '\\n', "\n", 'g') + let text = substitute(text, '\\f', "\f", 'g') + let text = substitute(text, '\\r', "\r", 'g') + let text = substitute(text, '\\/', '/', 'g') + let text = substitute(text, '\\\\', '\', 'g') + let text = substitute(text, '\C\\u\(\x\{4}\)', '\=s:_nr2char("0x" . submatch(1))', 'g') + let text = substitute(text, '\C\\U\(\x\{8}\)', '\=s:_nr2char("0x" . submatch(1))', 'g') + return text +endfunction + +function! s:_nr2char(nr) abort + return iconv(nr2char(a:nr), &encoding, 'utf8') +endfunction + +function! s:_put_dict(dict, key, value) abort + let keys = split(a:key, '\.') + + let ref = a:dict + for key in keys[ : -2] + if has_key(ref, key) && type(ref[key]) == v:t_dict + let ref = ref[key] + elseif has_key(ref, key) && type(ref[key]) == v:t_list + let ref = ref[key][-1] + else + let ref[key] = {} + let ref = ref[key] + endif + endfor + + let ref[keys[-1]] = a:value +endfunction + +function! s:_put_array(dict, key, value) abort + let keys = split(a:key, '\.') + + let ref = a:dict + for key in keys[ : -2] + let ref[key] = get(ref, key, {}) + + if type(ref[key]) == v:t_list + let ref = ref[key][-1] + else + let ref = ref[key] + endif + endfor + + let ref[keys[-1]] = get(ref, keys[-1], []) + a:value +endfunction + +" vim:set et ts=2 sts=2 sw=2 tw=0: diff --git a/bundle/dein.vim/autoload/dein/types/git.vim b/bundle/dein.vim/autoload/dein/types/git.vim new file mode 100644 index 000000000..2a10c7444 --- /dev/null +++ b/bundle/dein.vim/autoload/dein/types/git.vim @@ -0,0 +1,300 @@ +"============================================================================= +" FILE: git.vim +" AUTHOR: Shougo Matsushita +" Robert Nelson +" License: MIT license +"============================================================================= + +" Global options definition. +call dein#util#_set_default( + \ 'g:dein#types#git#command_path', 'git') +call dein#util#_set_default( + \ 'g:dein#types#git#default_protocol', 'https') +call dein#util#_set_default( + \ 'g:dein#types#git#clone_depth', 0) +call dein#util#_set_default( + \ 'g:dein#types#git#pull_command', 'pull --ff --ff-only') + + +function! dein#types#git#define() abort + return s:type +endfunction + +let s:type = { + \ 'name': 'git', + \ 'command': g:dein#types#git#command_path, + \ 'executable': executable(g:dein#types#git#command_path), + \ } + +function! s:type.init(repo, options) abort + if !self.executable + return {} + endif + + if a:repo =~# '^/\|^\a:[/\\]' && s:is_git_dir(a:repo.'/.git') + " Local repository. + return { 'type': 'git', 'local': 1 } + elseif a:repo =~# + \ '//\%(raw\|gist\)\.githubusercontent\.com/\|/archive/[^/]\+\.zip$' + return {} + endif + + let uri = self.get_uri(a:repo, a:options) + if uri ==# '' + return {} + endif + + let directory = substitute(uri, '\.git$', '', '') + let directory = substitute(directory, '^https:/\+\|^git@', '', '') + let directory = substitute(directory, ':', '/', 'g') + + return { 'type': 'git', + \ 'path': dein#util#_get_base_path().'/repos/'.directory } +endfunction +function! s:type.get_uri(repo, options) abort + if a:repo =~# '^/\|^\a:[/\\]' + return s:is_git_dir(a:repo.'/.git') ? a:repo : '' + endif + + if a:repo =~# '^git@' + " Parse "git@host:name" pattern + let protocol = 'ssh' + let host = matchstr(a:repo[4:], '[^:]*') + let name = a:repo[4 + len(host) + 1 :] + else + let protocol = matchstr(a:repo, '^.\{-}\ze://') + let rest = a:repo[len(protocol):] + let name = substitute(rest, '^://[^/]*/', '', '') + let host = substitute(matchstr(rest, '^://\zs[^/]*\ze/'), + \ ':.*$', '', '') + endif + if host ==# '' + let host = 'github.com' + endif + + if protocol ==# '' + \ || a:repo =~# '\<\%(gh\|github\|bb\|bitbucket\):\S\+' + \ || has_key(a:options, 'type__protocol') + let protocol = get(a:options, 'type__protocol', + \ g:dein#types#git#default_protocol) + endif + + if protocol !=# 'https' && protocol !=# 'ssh' + call dein#util#_error( + \ printf('Repo: %s The protocol "%s" is unsecure and invalid.', + \ a:repo, protocol)) + return '' + endif + + if a:repo !~# '/' + call dein#util#_error( + \ printf('vim-scripts.org is deprecated.' + \ . ' You can use "vim-scripts/%s" instead.', a:repo)) + return '' + else + let uri = (protocol ==# 'ssh' && + \ (host ==# 'github.com' || host ==# 'bitbucket.com' || + \ host ==# 'bitbucket.org')) ? + \ 'git@' . host . ':' . name : + \ protocol . '://' . host . '/' . name + endif + + return uri +endfunction + +function! s:type.get_sync_command(plugin) abort + if !isdirectory(a:plugin.path) + let commands = [] + + call add(commands, self.command) + call add(commands, 'clone') + call add(commands, '--recursive') + + let depth = get(a:plugin, 'type__depth', + \ g:dein#types#git#clone_depth) + if depth > 0 && get(a:plugin, 'rev', '') ==# '' + \ && self.get_uri(a:plugin.repo, a:plugin) !~# '^git@' + call add(commands, '--depth=' . depth) + endif + + call add(commands, self.get_uri(a:plugin.repo, a:plugin)) + call add(commands, a:plugin.path) + + return commands + else + let git = self.command + + let cmd = g:dein#types#git#pull_command + let submodule_cmd = git . ' submodule update --init --recursive' + if dein#util#_is_powershell() + let cmd .= '; if ($?) { ' . submodule_cmd . ' }' + else + let and = dein#util#_is_fish() ? '; and ' : ' && ' + let cmd .= and . submodule_cmd + endif + + return git . ' ' . cmd + endif +endfunction + +function! s:type.get_revision_number_command(plugin) abort + if !self.executable + return [] + endif + + return [self.command, 'rev-parse', 'HEAD'] +endfunction +function! s:type.get_log_command(plugin, new_rev, old_rev) abort + if !self.executable || a:new_rev ==# '' || a:old_rev ==# '' + return [] + endif + + " Note: If the a:old_rev is not the ancestor of two branchs. Then do not use + " %s^. use %s^ will show one commit message which already shown last time. + let is_not_ancestor = dein#install#_system( + \ self.command . ' merge-base ' + \ . a:old_rev . ' ' . a:new_rev) ==# a:old_rev + return printf(self.command . + \ ' log %s%s..%s --graph --no-show-signature' . + \ ' --pretty=format:"%%h [%%cr] %%s"', + \ a:old_rev, (is_not_ancestor ? '' : '^'), a:new_rev) +endfunction +function! s:type.get_revision_lock_command(plugin) abort + if !self.executable + return [] + endif + + let rev = get(a:plugin, 'rev', '') + if rev =~# '*' + " Use the released tag (git 1.9.2 or above required) + let rev = get(split(dein#install#_system( + \ [self.command, 'tag', '--list', + \ escape(rev, '*'), '--sort', '-version:refname']), + \ "\n"), 0, '') + endif + if rev ==# '' + " Fix detach HEAD. + " Use symbolic-ref feature (git 1.8.7 or above required) + let rev = dein#install#_system([ + \ self.command, 'symbolic-ref', '--short', 'HEAD' + \ ]) + if rev =~# 'fatal: ' + " Fix "fatal: ref HEAD is not a symbolic ref" error + let rev = 'master' + endif + endif + + return [self.command, 'checkout', rev, '--'] +endfunction +function! s:type.get_rollback_command(plugin, rev) abort + if !self.executable + return [] + endif + + return [self.command, 'reset', '--hard', a:rev] +endfunction +function! s:type.get_revision_remote_command(plugin) abort + if !self.executable + return [] + endif + + let rev = get(a:plugin, 'rev', '') + if rev ==# '' + let rev = 'HEAD' + endif + + return [self.command, 'ls-remote', 'origin', rev] +endfunction +function! s:type.get_fetch_remote_command(plugin) abort + if !self.executable + return [] + endif + + return [self.command, 'fetch', 'origin'] +endfunction + +function! s:is_git_dir(path) abort + if isdirectory(a:path) + let git_dir = a:path + elseif filereadable(a:path) + " check if this is a gitdir file + " File starts with "gitdir: " and all text after this string is treated + " as the path. Any CR or NLs are stripped off the end of the file. + let buf = join(readfile(a:path, 'b'), "\n") + let matches = matchlist(buf, '\C^gitdir: \(\_.*[^\r\n]\)[\r\n]*$') + if empty(matches) + return 0 + endif + let path = fnamemodify(a:path, ':h') + if fnamemodify(a:path, ':t') ==# '' + " if there's no tail, the path probably ends in a directory separator + let path = fnamemodify(path, ':h') + endif + let git_dir = s:join_paths(path, matches[1]) + if !isdirectory(git_dir) + return 0 + endif + else + return 0 + endif + + " Git only considers it to be a git dir if a few required files/dirs exist + " and are accessible inside the directory. + " Note: we can't actually test file permissions the way we'd like to, since + " getfperm() gives the mode string but doesn't tell us whether the user or + " group flags apply to us. Instead, just check if dirname/. is a directory. + " This should also check if we have search permissions. + " I'm assuming here that dirname/. works on windows, since I can't test. + " Note: Git also accepts having the GIT_OBJECT_DIRECTORY env var set instead + " of using .git/objects, but we don't care about that. + for name in ['objects', 'refs'] + if !isdirectory(s:join_paths(git_dir, name)) + return 0 + endif + endfor + + " Git also checks if HEAD is a symlink or a properly-formatted file. + " We don't really care to actually validate this, so let's just make + " sure the file exists and is readable. + " Note: it may also be a symlink, which can point to a path that doesn't + " necessarily exist yet. + let head = s:join_paths(git_dir, 'HEAD') + if !filereadable(head) && getftype(head) !=# 'link' + return 0 + endif + + " Sure looks like a git directory. There's a few subtleties where we'll + " accept a directory that git itself won't, but I think we can safely ignore + " those edge cases. + return 1 +endfunction + +let s:is_windows = dein#util#_is_windows() + +function! s:join_paths(path1, path2) abort + " Joins two paths together, handling the case where the second path + " is an absolute path. + if s:is_absolute(a:path2) + return a:path2 + endif + if a:path1 =~ (s:is_windows ? '[\\/]$' : '/$') || + \ a:path2 =~ (s:is_windows ? '^[\\/]' : '^/') + " the appropriate separator already exists + return a:path1 . a:path2 + else + " note: I'm assuming here that '/' is always valid as a directory + " separator on Windows. I know Windows has paths that start with \\?\ that + " diasble behavior like that, but I don't know how Vim deals with that. + return a:path1 . '/' . a:path2 + endif +endfunction + +if s:is_windows + function! s:is_absolute(path) abort + return a:path =~# '^[\\/]\|^\a:' + endfunction +else + function! s:is_absolute(path) abort + return a:path =~# '^/' + endfunction +endif diff --git a/bundle/dein.vim/autoload/dein/types/raw.vim b/bundle/dein.vim/autoload/dein/types/raw.vim new file mode 100644 index 000000000..02d0e3854 --- /dev/null +++ b/bundle/dein.vim/autoload/dein/types/raw.vim @@ -0,0 +1,38 @@ +"============================================================================= +" FILE: raw.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! dein#types#raw#define() abort + return s:type +endfunction + +let s:type = { + \ 'name': 'raw', + \ } + +function! s:type.init(repo, options) abort + " No auto detect. + if a:repo !~# '^https://.*\.vim$' || !has_key(a:options, 'script_type') + return {} + endif + + let directory = substitute(fnamemodify(a:repo, ':h'), '\.git$', '', '') + let directory = substitute(directory, '^https:/\+\|^git@', '', '') + let directory = substitute(directory, ':', '/', 'g') + + return { 'name': dein#parse#_name_conversion(a:repo), 'type' : 'raw', + \ 'path': dein#util#_get_base_path().'/repos/'.directory } +endfunction + +function! s:type.get_sync_command(plugin) abort + let path = a:plugin.path + if !isdirectory(path) + " Create script type directory. + call mkdir(path, 'p') + endif + + let outpath = path . '/' . fnamemodify(a:plugin.repo, ':t') + return dein#util#_download(a:plugin.repo, outpath) +endfunction diff --git a/bundle/dein.vim/autoload/dein/util.vim b/bundle/dein.vim/autoload/dein/util.vim new file mode 100644 index 000000000..ccf603556 --- /dev/null +++ b/bundle/dein.vim/autoload/dein/util.vim @@ -0,0 +1,753 @@ +"============================================================================= +" FILE: util.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +let s:is_windows = has('win32') || has('win64') + +function! dein#util#_init() abort +endfunction + +function! dein#util#_set_default(var, val, ...) abort + if !exists(a:var) || type({a:var}) != type(a:val) + let alternate_var = get(a:000, 0, '') + + let {a:var} = exists(alternate_var) ? + \ {alternate_var} : a:val + endif +endfunction + +function! dein#util#_is_windows() abort + return s:is_windows +endfunction +function! dein#util#_is_mac() abort + return !s:is_windows && !has('win32unix') + \ && (has('mac') || has('macunix') || has('gui_macvim') || + \ (!isdirectory('/proc') && executable('sw_vers'))) +endfunction + +function! dein#util#_get_base_path() abort + return g:dein#_base_path +endfunction +function! dein#util#_get_runtime_path() abort + if g:dein#_runtime_path !=# '' + return g:dein#_runtime_path + endif + + let g:dein#_runtime_path = dein#util#_get_cache_path() . '/.dein' + if !isdirectory(g:dein#_runtime_path) + call mkdir(g:dein#_runtime_path, 'p') + endif + return g:dein#_runtime_path +endfunction +function! dein#util#_get_cache_path() abort + if g:dein#_cache_path !=# '' + return g:dein#_cache_path + endif + + let g:dein#_cache_path = get(g:, + \ 'dein#cache_directory', g:dein#_base_path) + \ . '/.cache/' . fnamemodify(dein#util#_get_myvimrc(), ':t') + if !isdirectory(g:dein#_cache_path) + call mkdir(g:dein#_cache_path, 'p') + endif + return g:dein#_cache_path +endfunction +function! dein#util#_get_vimrcs(vimrcs) abort + return !empty(a:vimrcs) ? + \ map(dein#util#_convert2list(a:vimrcs), 'expand(v:val)') : + \ [dein#util#_get_myvimrc()] +endfunction +function! dein#util#_get_myvimrc() abort + let vimrc = $MYVIMRC !=# '' ? $MYVIMRC : + \ matchstr(split(dein#util#_redir('scriptnames'), '\n')[0], + \ '^\s*\d\+:\s\zs.*') + return dein#util#_substitute_path(vimrc) +endfunction + +function! dein#util#_error(msg) abort + for mes in s:msg2list(a:msg) + echohl WarningMsg | echomsg '[dein] ' . mes | echohl None + endfor +endfunction +function! dein#util#_notify(msg) abort + call dein#util#_set_default( + \ 'g:dein#enable_notification', 0) + call dein#util#_set_default( + \ 'g:dein#notification_icon', '') + call dein#util#_set_default( + \ 'g:dein#notification_time', 2) + + if !g:dein#enable_notification || a:msg ==# '' || has('vim_starting') + call dein#util#_error(a:msg) + return + endif + + let icon = dein#util#_expand(g:dein#notification_icon) + + let title = '[dein]' + let cmd = '' + if executable('notify-send') + let cmd = printf('notify-send --expire-time=%d', + \ g:dein#notification_time * 1000) + if icon !=# '' + let cmd .= ' --icon=' . string(icon) + endif + let cmd .= ' ' . string(title) . ' ' . string(a:msg) + elseif dein#util#_is_windows() && executable('Snarl_CMD') + let cmd = printf('Snarl_CMD snShowMessage %d "%s" "%s"', + \ g:dein#notification_time, title, a:msg) + if icon !=# '' + let cmd .= ' "' . icon . '"' + endif + elseif dein#util#_is_mac() + let cmd = '' + if executable('terminal-notifier') + let cmd .= 'terminal-notifier -title ' + \ . string(title) . ' -message ' . string(a:msg) + if icon !=# '' + let cmd .= ' -appIcon ' . string(icon) + endif + else + let cmd .= printf("osascript -e 'display notification " + \ ."\"%s\" with title \"%s\"'", a:msg, title) + endif + endif + + if cmd !=# '' + call dein#install#_system(cmd) + endif +endfunction + +function! dein#util#_chomp(str) abort + return a:str !=# '' && a:str[-1:] ==# '/' ? a:str[: -2] : a:str +endfunction + +function! dein#util#_uniq(list) abort + let list = copy(a:list) + let i = 0 + let seen = {} + while i < len(list) + let key = list[i] + if key !=# '' && has_key(seen, key) + call remove(list, i) + else + if key !=# '' + let seen[key] = 1 + endif + let i += 1 + endif + endwhile + return list +endfunction + +function! dein#util#_is_fish() abort + return dein#install#_is_async() && fnamemodify(&shell, ':t:r') ==# 'fish' +endfunction +function! dein#util#_is_powershell() abort + return dein#install#_is_async() && fnamemodify(&shell, ':t:r') =~? 'powershell\|pwsh' +endfunction +function! dein#util#_has_job() abort + return (has('nvim') && exists('v:t_list')) + \ || (has('patch-8.0.0027') && has('job')) +endfunction + +function! dein#util#_check_lazy_plugins() abort + return map(filter(dein#util#_get_lazy_plugins(), + \ "isdirectory(v:val.rtp) + \ && !get(v:val, 'local', 0) + \ && get(v:val, 'hook_source', '') ==# '' + \ && get(v:val, 'hook_add', '') ==# '' + \ && !isdirectory(v:val.rtp . '/plugin') + \ && !isdirectory(v:val.rtp . '/after/plugin')"), + \ 'v:val.name') +endfunction +function! dein#util#_check_clean() abort + let plugins_directories = map(values(dein#get()), 'v:val.path') + let path = dein#util#_substitute_path( + \ globpath(dein#util#_get_base_path(), 'repos/*/*/*')) + return filter(split(path, "\n"), + \ "isdirectory(v:val) && fnamemodify(v:val, ':t') !=# 'dein.vim' + \ && index(plugins_directories, v:val) < 0") +endfunction + +function! dein#util#_writefile(path, list) abort + if g:dein#_is_sudo || !filewritable(dein#util#_get_cache_path()) + return 1 + endif + + let path = dein#util#_get_cache_path() . '/' . a:path + let dir = fnamemodify(path, ':h') + if !isdirectory(dir) + call mkdir(dir, 'p') + endif + + return writefile(a:list, path) +endfunction + +function! dein#util#_get_type(name) abort + return get(dein#parse#_get_types(), a:name, {}) +endfunction + +function! dein#util#_save_cache(vimrcs, is_state, is_starting) abort + if dein#util#_get_cache_path() ==# '' || !a:is_starting + " Ignore + return 1 + endif + + let plugins = deepcopy(dein#get()) + + for plugin in values(plugins) + if !a:is_state + let plugin.sourced = 0 + endif + if has_key(plugin, 'orig_opts') + call remove(plugin, 'orig_opts') + endif + + " Hooks + for hook in filter([ + \ 'hook_add', 'hook_source', + \ 'hook_post_source', 'hook_post_update', + \ ], 'has_key(plugin, v:val) + \ && type(plugin[v:val]) == v:t_func') + call remove(plugin, hook) + endfor + endfor + + if !isdirectory(g:dein#_base_path) + call mkdir(g:dein#_base_path, 'p') + endif + + call writefile([string(a:vimrcs), + \ json_encode(plugins), json_encode(g:dein#_ftplugin)], + \ get(g:, 'dein#cache_directory', g:dein#_base_path) + \ .'/cache_' . g:dein#_progname) +endfunction +function! dein#util#_check_vimrcs() abort + let time = getftime(dein#util#_get_runtime_path()) + let ret = !empty(filter(map(copy(g:dein#_vimrcs), 'getftime(expand(v:val))'), + \ 'time < v:val')) + if !ret + return 0 + endif + + call dein#clear_state() + + if get(g:, 'dein#auto_recache', 0) + silent execute 'source' dein#util#_get_myvimrc() + + if dein#util#_get_merged_plugins() !=# dein#util#_load_merged_plugins() + call dein#util#_notify('auto recached') + call dein#recache_runtimepath() + endif + endif + + return ret +endfunction +function! dein#util#_load_merged_plugins() abort + let path = dein#util#_get_cache_path() . '/merged' + if !filereadable(path) + return [] + endif + let merged = readfile(path) + if len(merged) != g:dein#_merged_length + return [] + endif + sandbox return merged[: g:dein#_merged_length - 2] + eval(merged[-1]) +endfunction +function! dein#util#_save_merged_plugins() abort + let merged = dein#util#_get_merged_plugins() + call writefile(merged[: g:dein#_merged_length - 2] + + \ [string(merged[g:dein#_merged_length - 1 :])], + \ dein#util#_get_cache_path() . '/merged') +endfunction +function! dein#util#_get_merged_plugins() abort + let ftplugin_len = 0 + for ftplugin in values(g:dein#_ftplugin) + let ftplugin_len += len(ftplugin) + endfor + return [g:dein#_merged_format, string(ftplugin_len)] + + \ sort(map(values(g:dein#_plugins), g:dein#_merged_format)) +endfunction + +function! dein#util#_save_state(is_starting) abort + if g:dein#_block_level != 0 + call dein#util#_error('Invalid dein#save_state() usage.') + return 1 + endif + + if dein#util#_get_cache_path() ==# '' || !a:is_starting + " Ignore + return 1 + endif + + let g:dein#_vimrcs = dein#util#_uniq(g:dein#_vimrcs) + let &runtimepath = dein#util#_join_rtp(dein#util#_uniq( + \ dein#util#_split_rtp(&runtimepath)), &runtimepath, '') + + call dein#util#_save_cache(g:dein#_vimrcs, 1, a:is_starting) + + " Version check + + let lines = [ + \ 'if g:dein#_cache_version !=# ' . g:dein#_cache_version . ' || ' . + \ 'g:dein#_init_runtimepath !=# ' . string(g:dein#_init_runtimepath) . + \ ' | throw ''Cache loading error'' | endif', + \ 'let [plugins, ftplugin] = dein#load_cache_raw('. + \ string(g:dein#_vimrcs) .')', + \ "if empty(plugins) | throw 'Cache loading error' | endif", + \ 'let g:dein#_plugins = plugins', + \ 'let g:dein#_ftplugin = ftplugin', + \ 'let g:dein#_base_path = ' . string(g:dein#_base_path), + \ 'let g:dein#_runtime_path = ' . string(g:dein#_runtime_path), + \ 'let g:dein#_cache_path = ' . string(g:dein#_cache_path), + \ 'let &runtimepath = ' . string(&runtimepath), + \ ] + + if g:dein#_off1 !=# '' + call add(lines, g:dein#_off1) + endif + if g:dein#_off2 !=# '' + call add(lines, g:dein#_off2) + endif + + " Add dummy mappings/commands + for plugin in dein#util#_get_lazy_plugins() + for command in get(plugin, 'dummy_commands', []) + call add(lines, 'silent! ' . command[1]) + endfor + for mapping in get(plugin, 'dummy_mappings', []) + call add(lines, 'silent! ' . mapping[2]) + endfor + endfor + + " Add hooks + if !empty(g:dein#_hook_add) + let lines += s:skipempty(g:dein#_hook_add) + endif + for plugin in dein#util#_tsort(values(dein#get())) + if has_key(plugin, 'hook_add') && type(plugin.hook_add) == v:t_string + let lines += s:skipempty(plugin.hook_add) + endif + endfor + + " Add events + for [event, plugins] in filter(items(g:dein#_event_plugins), + \ "exists('##' . v:val[0])") + call add(lines, printf('autocmd dein-events %s call ' + \. 'dein#autoload#_on_event("%s", %s)', + \ (exists('##' . event) ? event . ' *' : 'User ' . event), + \ event, string(plugins))) + endfor + + call writefile(lines, get(g:, 'dein#cache_directory', g:dein#_base_path) + \ .'/state_' . g:dein#_progname . '.vim') +endfunction +function! dein#util#_clear_state() abort + let base = get(g:, 'dein#cache_directory', g:dein#_base_path) + for cache in dein#util#_globlist(base.'/state_*.vim') + \ + dein#util#_globlist(base.'/cache_*') + call delete(cache) + endfor +endfunction + +function! dein#util#_begin(path, vimrcs) abort + if !exists('#dein') + call dein#_init() + endif + + " Reset variables + if has('vim_starting') + let g:dein#_plugins = {} + let g:dein#_event_plugins = {} + endif + let g:dein#_ftplugin = {} + let g:dein#_hook_add = '' + + if !dein#util#_has_job() + call dein#util#_error('Does not work in the Vim (' . v:version . ').') + return 1 + endif + + if a:path ==# '' || g:dein#_block_level != 0 + call dein#util#_error('Invalid begin/end block usage.') + return 1 + endif + + let g:dein#_block_level += 1 + let g:dein#_base_path = dein#util#_expand(a:path) + if g:dein#_base_path[-1:] ==# '/' + let g:dein#_base_path = g:dein#_base_path[: -2] + endif + call dein#util#_get_runtime_path() + call dein#util#_get_cache_path() + let g:dein#_vimrcs = dein#util#_get_vimrcs(a:vimrcs) + let g:dein#_hook_add = '' + + if has('vim_starting') + " Filetype off + if exists('g:did_load_filetypes') || has('nvim') + let g:dein#_off1 = 'filetype off' + execute g:dein#_off1 + endif + if exists('b:did_indent') || exists('b:did_ftplugin') + let g:dein#_off2 = 'filetype plugin indent off' + execute g:dein#_off2 + endif + else + execute 'set rtp-='.fnameescape(g:dein#_runtime_path) + execute 'set rtp-='.fnameescape(g:dein#_runtime_path.'/after') + endif + + " Insert dein runtimepath to the head in 'runtimepath'. + let rtps = dein#util#_split_rtp(&runtimepath) + let idx = index(rtps, $VIMRUNTIME) + if idx < 0 + call dein#util#_error('Invalid runtimepath.') + return 1 + endif + if fnamemodify(a:path, ':t') ==# 'plugin' + \ && index(rtps, fnamemodify(a:path, ':h')) >= 0 + call dein#util#_error('You must not set the installation directory' + \ .' under "&runtimepath/plugin"') + return 1 + endif + call insert(rtps, g:dein#_runtime_path, idx) + call dein#util#_add_after(rtps, g:dein#_runtime_path.'/after') + let &runtimepath = dein#util#_join_rtp(rtps, + \ &runtimepath, g:dein#_runtime_path) +endfunction +function! dein#util#_end() abort + if g:dein#_block_level != 1 + call dein#util#_error('Invalid begin/end block usage.') + return 1 + endif + + let g:dein#_block_level -= 1 + + if !has('vim_starting') + call dein#source(filter(values(g:dein#_plugins), + \ "!v:val.lazy && !v:val.sourced && v:val.rtp !=# ''")) + endif + + " Add runtimepath + let rtps = dein#util#_split_rtp(&runtimepath) + let index = index(rtps, g:dein#_runtime_path) + if index < 0 + call dein#util#_error('Invalid runtimepath.') + return 1 + endif + + let depends = [] + let sourced = has('vim_starting') && + \ (!exists('&loadplugins') || &loadplugins) + for plugin in filter(values(g:dein#_plugins), + \ "!v:val.lazy && !v:val.sourced && v:val.rtp !=# ''") + " Load dependencies + if has_key(plugin, 'depends') + let depends += plugin.depends + endif + + if !plugin.merged + call insert(rtps, plugin.rtp, index) + if isdirectory(plugin.rtp.'/after') + call dein#util#_add_after(rtps, plugin.rtp.'/after') + endif + endif + + let plugin.sourced = sourced + endfor + let &runtimepath = dein#util#_join_rtp(rtps, &runtimepath, '') + + if !empty(depends) + call dein#source(depends) + endif + + if g:dein#_hook_add !=# '' + call dein#util#_execute_hook({}, g:dein#_hook_add) + endif + + for [event, plugins] in filter(items(g:dein#_event_plugins), + \ "exists('##' . v:val[0])") + execute printf('autocmd dein-events %s call ' + \. 'dein#autoload#_on_event("%s", %s)', + \ (exists('##' . event) ? event . ' *' : 'User ' . event), + \ event, string(plugins)) + endfor + + if !has('vim_starting') + call dein#call_hook('add') + call dein#call_hook('source') + call dein#call_hook('post_source') + endif +endfunction +function! dein#util#_config(arg, dict) abort + let name = type(a:arg) == v:t_dict ? + \ g:dein#name : a:arg + let dict = type(a:arg) == v:t_dict ? + \ a:arg : a:dict + if !has_key(g:dein#_plugins, name) + \ || g:dein#_plugins[name].sourced + return {} + endif + + let plugin = g:dein#_plugins[name] + let options = extend({'repo': plugin.repo}, dict) + if has_key(plugin, 'orig_opts') + call extend(options, copy(plugin.orig_opts), 'keep') + endif + return dein#parse#_add(options.repo, options) +endfunction + +function! dein#util#_call_hook(hook_name, ...) abort + let hook = 'hook_' . a:hook_name + let plugins = filter(dein#util#_get_plugins((a:0 ? a:1 : [])), + \ "((a:hook_name !=# 'source' + \ && a:hook_name !=# 'post_source') || v:val.sourced) + \ && has_key(v:val, hook) && isdirectory(v:val.path)") + + for plugin in filter(dein#util#_tsort(plugins), + \ 'has_key(v:val, hook)') + call dein#util#_execute_hook(plugin, plugin[hook]) + endfor +endfunction +function! dein#util#_execute_hook(plugin, hook) abort + try + let g:dein#plugin = a:plugin + + if type(a:hook) == v:t_string + call s:execute(a:hook) + else + call call(a:hook, []) + endif + catch + call dein#util#_error( + \ 'Error occurred while executing hook: ' . + \ get(a:plugin, 'name', '')) + call dein#util#_error(v:exception) + endtry +endfunction +function! dein#util#_set_hook(plugins, hook_name, hook) abort + let names = empty(a:plugins) ? keys(dein#get()) : + \ dein#util#_convert2list(a:plugins) + for name in names + if !has_key(g:dein#_plugins, name) + call dein#util#_error(name . ' is not found.') + return 1 + endif + let plugin = g:dein#_plugins[name] + let plugin[a:hook_name] = + \ type(a:hook) != v:t_string ? a:hook : + \ substitute(a:hook, '\n\s*\\\|\%(^\|\n\)\s*"[^\n]*', '', 'g') + if a:hook_name ==# 'hook_add' + call dein#util#_execute_hook(plugin, plugin[a:hook_name]) + endif + endfor +endfunction + +function! dein#util#_sort_by(list, expr) abort + let pairs = map(a:list, printf('[v:val, %s]', a:expr)) + return map(s:sort(pairs, + \ 'a:a[1] ==# a:b[1] ? 0 : a:a[1] ># a:b[1] ? 1 : -1'), 'v:val[0]') +endfunction +function! dein#util#_tsort(plugins) abort + let sorted = [] + let mark = {} + for target in a:plugins + call s:tsort_impl(target, mark, sorted) + endfor + + return sorted +endfunction + +function! dein#util#_split_rtp(runtimepath) abort + if stridx(a:runtimepath, '\,') < 0 + return split(a:runtimepath, ',') + endif + + let split = split(a:runtimepath, '\\\@ res + silent! execute a:cmd + redir END + let [&verbose, &verbosefile] = [save_verbose, save_verbosefile] + return res + endif +endfunction + +function! dein#util#_get_lazy_plugins() abort + return filter(values(g:dein#_plugins), + \ "!v:val.sourced && v:val.rtp !=# ''") +endfunction + +function! dein#util#_get_plugins(plugins) abort + return empty(a:plugins) ? + \ values(dein#get()) : + \ filter(map(dein#util#_convert2list(a:plugins), + \ 'type(v:val) == v:t_dict ? v:val : dein#get(v:val)'), + \ '!empty(v:val)') +endfunction + +function! dein#util#_disable(names) abort + for plugin in map(filter(dein#util#_convert2list(a:names), + \ 'has_key(g:dein#_plugins, v:val) + \ && !g:dein#_plugins[v:val].sourced'), 'g:dein#_plugins[v:val]') + if has_key(plugin, 'dummy_commands') + for command in plugin.dummy_commands + silent! execute 'delcommand' command[0] + endfor + let plugin.dummy_commands = [] + endif + + if has_key(plugin, 'dummy_mappings') + for map in plugin.dummy_mappings + silent! execute map[0].'unmap' map[1] + endfor + let plugin.dummy_mappings = [] + endif + + call remove(g:dein#_plugins, plugin.name) + endfor +endfunction + +function! dein#util#_download(uri, outpath) abort + if !exists('g:dein#download_command') + let g:dein#download_command = + \ executable('curl') ? + \ 'curl --silent --location --output' : + \ executable('wget') ? + \ 'wget -q -O' : '' + endif + if g:dein#download_command !=# '' + return printf('%s "%s" "%s"', + \ g:dein#download_command, a:outpath, a:uri) + elseif dein#util#_is_windows() + " Use powershell + " Todo: Proxy support + let pscmd = printf("(New-Object Net.WebClient).DownloadFile('%s', '%s')", + \ a:uri, a:outpath) + return printf('powershell -Command "%s"', pscmd) + else + return 'E: curl or wget command is not available!' + endif +endfunction + +function! s:tsort_impl(target, mark, sorted) abort + if empty(a:target) || has_key(a:mark, a:target.name) + return + endif + + let a:mark[a:target.name] = 1 + if has_key(a:target, 'depends') + for depend in a:target.depends + call s:tsort_impl(dein#get(depend), a:mark, a:sorted) + endfor + endif + + call add(a:sorted, a:target) +endfunction + +function! dein#util#_check_install(plugins) abort + if !empty(a:plugins) + let invalids = filter(dein#util#_convert2list(a:plugins), + \ 'empty(dein#get(v:val))') + if !empty(invalids) + call dein#util#_error('Invalid plugins: ' . + \ string(map(invalids, 'v:val'))) + return -1 + endif + endif + let plugins = empty(a:plugins) ? values(dein#get()) : + \ map(dein#util#_convert2list(a:plugins), 'dein#get(v:val)') + let plugins = filter(plugins, '!isdirectory(v:val.path)') + if empty(plugins) | return 0 | endif + call dein#util#_notify('Not installed plugins: ' . + \ string(map(plugins, 'v:val.name'))) + return 1 +endfunction + +function! s:msg2list(expr) abort + return type(a:expr) ==# v:t_list ? a:expr : split(a:expr, '\n') +endfunction +function! s:skipempty(string) abort + return filter(split(a:string, '\n'), "v:val !=# ''") +endfunction + +function! s:escape(path) abort + " Escape a path for runtimepath. + return substitute(a:path, ',\|\\,\@=', '\\\0', 'g') +endfunction + +function! s:sort(list, expr) abort + if type(a:expr) == v:t_func + return sort(a:list, a:expr) + endif + let s:expr = a:expr + return sort(a:list, 's:_compare') +endfunction +function! s:_compare(a, b) abort + return eval(s:expr) +endfunction + +function! s:execute(expr) abort + if exists('*execute') + return execute(split(a:expr, '\n'), '') + endif + + let dummy = '_dein_dummy_' . + \ substitute(reltimestr(reltime()), '\W', '_', 'g') + execute 'function! '.dummy."() abort\n" + \ . a:expr . "\nendfunction" + call {dummy}() + execute 'delfunction' dummy +endfunction + +function! s:neovim_version() abort + return str2float(matchstr(execute('version'), 'NVIM v\zs\d\.\d\.\d')) +endfunction diff --git a/bundle/dein.vim/autoload/unite/kinds/dein.vim b/bundle/dein.vim/autoload/unite/kinds/dein.vim new file mode 100644 index 000000000..45c89ad58 --- /dev/null +++ b/bundle/dein.vim/autoload/unite/kinds/dein.vim @@ -0,0 +1,50 @@ +"============================================================================= +" FILE: dein.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! unite#kinds#dein#define() abort + return s:kind +endfunction + +let s:kind = { + \ 'name': 'dein', + \ 'action_table': {}, + \ 'parents': ['uri', 'directory'], + \ 'default_action': 'lcd', + \} + +" Actions +let s:kind.action_table.preview = { + \ 'description': 'view the plugin documentation', + \ 'is_quit': 0, + \ } +function! s:kind.action_table.preview.func(candidate) abort + " Search help files. + let readme = get(split(globpath( + \ a:candidate.action__path, 'doc/*.?*', 1), '\n'), 0, '') + + if readme ==# '' + " Search README files. + let readme = get(split(globpath( + \ a:candidate.action__path, 'README*', 1), '\n'), 0, '') + if readme ==# '' + return + endif + endif + + let buflisted = buflisted( + \ unite#util#escape_file_searching(readme)) + + execute 'pedit' fnameescape(readme) + + " Open folds. + normal! zv + normal! zt + + if !buflisted + call unite#add_previewed_buffer_list( + \ bufnr(unite#util#escape_file_searching(readme))) + endif +endfunction diff --git a/bundle/dein.vim/autoload/unite/sources/dein.vim b/bundle/dein.vim/autoload/unite/sources/dein.vim new file mode 100644 index 000000000..d5cb361ee --- /dev/null +++ b/bundle/dein.vim/autoload/unite/sources/dein.vim @@ -0,0 +1,108 @@ +"============================================================================= +" FILE: dein.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! unite#sources#dein#define() abort + return s:source +endfunction + +let s:source = { + \ 'name': 'dein', + \ 'description': 'candidates from dein plugins', + \ 'hooks': {}, + \ } + +function! s:source.hooks.on_init(args, context) abort + let a:context.source__bang = index(a:args, '!') >= 0 + let a:context.source__plugins = values(dein#get()) +endfunction + +" Filters +function! s:source.source__converter(candidates, context) abort + for candidate in a:candidates + let type = dein#util#_get_type(candidate.source__type) + let candidate.source__uri = has_key(type, 'get_uri') ? + \ type.get_uri(candidate.action__plugin.repo, + \ candidate.action__plugin) : '' + if candidate.source__uri =~# + \ '^\%(https\?\|git\)://github.com/' + let candidate.action__uri = candidate.source__uri + let candidate.action__uri = + \ substitute(candidate.action__uri, '^git://', 'https://', '') + let candidate.action__uri = + \ substitute(candidate.action__uri, '.git$', '', '') + endif + endfor + + return a:candidates +endfunction + +let s:source.converters = s:source.source__converter + + +function! s:source.gather_candidates(args, context) abort + let _ = map(copy(a:context.source__plugins), "{ + \ 'word': substitute(v:val.repo, + \ '^\%(https\?\|git\)://\%(github.com/\)\?', '', ''), + \ 'kind': 'dein', + \ 'action__path': v:val.path, + \ 'action__directory': v:val.path, + \ 'action__plugin': v:val, + \ 'action__plugin_name': v:val.name, + \ 'source__type': v:val.type, + \ 'source__is_sourced': v:val.sourced, + \ 'source__is_installed': isdirectory(v:val.path), + \ 'is_multiline': 1, + \ } + \") + + let max = max(map(copy(_), 'len(v:val.word)')) + + call unite#print_source_message( + \ '#: not sourced, X: not installed', self.name) + + for candidate in _ + let candidate.abbr = + \ !candidate.source__is_installed ? 'X' : + \ candidate.source__is_sourced ? ' ' : '#' + let candidate.abbr .= ' ' . unite#util#truncate(candidate.word, max) + + if a:context.source__bang + let status = s:get_commit_status(candidate.action__plugin) + if status !=# '' + let candidate.abbr .= "\n " . status + endif + endif + endfor + + return _ +endfunction + +function! s:get_commit_status(plugin) abort + if !isdirectory(a:plugin.path) + return 'Not installed' + endif + + let type = dein#types#git#define() + let cmd = type.get_revision_number_command(a:plugin) + if cmd ==# '' + return '' + endif + + let cwd = getcwd() + try + call dein#install#_cd(a:plugin.path) + let output = dein#install#_system(cmd) + finally + call dein#install#_cd(cwd) + endtry + + if dein#install#_get_last_status() + return printf('Error(%d) occurred when executing "%s"', + \ dein#install#_get_last_status(), cmd) + endif + + return output +endfunction diff --git a/bundle/dein.vim/autoload/unite/sources/dein_log.vim b/bundle/dein.vim/autoload/unite/sources/dein_log.vim new file mode 100644 index 000000000..1b6dc0e02 --- /dev/null +++ b/bundle/dein.vim/autoload/unite/sources/dein_log.vim @@ -0,0 +1,53 @@ +"============================================================================= +" FILE: dein/log.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! unite#sources#dein_log#define() abort + return s:source +endfunction + +let s:source = { + \ 'name' : 'dein/log', + \ 'description' : 'print previous dein install logs', + \ 'syntax' : 'uniteSource__deinLog', + \ 'hooks' : {}, + \ } + +function! s:source.hooks.on_syntax(args, context) abort + syntax match uniteSource__deinLog_Message /.*/ + \ contained containedin=uniteSource__deinLog + highlight default link uniteSource__deinLog_Message Comment + syntax match uniteSource__deinLog_Progress /(.\{-}):\s*.*/ + \ contained containedin=uniteSource__deinLog + highlight default link uniteSource__deinLog_Progress String + syntax match uniteSource__deinLog_Source /|.\{-}|/ + \ contained containedin=uniteSource__deinLog_Progress + highlight default link uniteSource__deinLog_Source Type + syntax match uniteSource__deinLog_URI /-> diff URI/ + \ contained containedin=uniteSource__deinLog + highlight default link uniteSource__deinLog_URI Underlined +endfunction + +function! s:source.gather_candidates(args, context) abort + let a:context.source__is_bang = + \ (get(a:args, 0, '') ==# '!') + let a:context.source__log = [] + return [] +endfunction +function! s:source.async_gather_candidates(args, context) abort + if empty(dein#install#_get_context()) + let a:context.is_async = 0 + endif + let log = a:context.source__is_bang ? + \ dein#install#_get_updates_log() + \ : dein#install#_get_log() + let candidates = map(copy(log[len(a:context.source__log):]), "{ + \ 'word' : (v:val =~# '^\\s*\\h\\w*://' ? ' -> diff URI' : v:val), + \ 'kind' : (v:val =~# '^\\s*\\h\\w*://' ? 'uri' : 'word'), + \ 'action__uri' : substitute(v:val, '^\\s\\+', '', ''), + \ }") + let a:context.source__log = copy(log) + return candidates +endfunction diff --git a/bundle/dein.vim/autoload/vital/_dein.vim b/bundle/dein.vim/autoload/vital/_dein.vim new file mode 100644 index 000000000..55104952e --- /dev/null +++ b/bundle/dein.vim/autoload/vital/_dein.vim @@ -0,0 +1,9 @@ +let s:_plugin_name = expand(':t:r') + +function! vital#{s:_plugin_name}#new() abort + return vital#{s:_plugin_name[1:]}#new() +endfunction + +function! vital#{s:_plugin_name}#function(funcname) abort + silent! return function(a:funcname) +endfunction diff --git a/bundle/dein.vim/autoload/vital/_dein/System/Job.vim b/bundle/dein.vim/autoload/vital/_dein/System/Job.vim new file mode 100644 index 000000000..3503766c6 --- /dev/null +++ b/bundle/dein.vim/autoload/vital/_dein/System/Job.vim @@ -0,0 +1,61 @@ +" ___vital___ +" NOTE: lines between '" ___vital___' is generated by :Vitalize. +" Do not mofidify the code nor insert new lines before '" ___vital___' +function! s:_SID() abort + return matchstr(expand(''), '\zs\d\+\ze__SID$') +endfunction +execute join(['function! vital#_dein#System#Job#import() abort', printf("return map({'_vital_depends': '', '_vital_healthcheck': '', 'is_available': '', 'start': '', '_vital_loaded': ''}, \"vital#_dein#function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") +delfunction s:_SID +" ___vital___ +let s:t_string = type('') +let s:t_list = type([]) + +function! s:_vital_loaded(V) abort + if has('nvim') + let s:Job = a:V.import('System.Job.Neovim') + else + let s:Job = a:V.import('System.Job.Vim') + endif +endfunction + +function! s:_vital_depends() abort + return [ + \ 'System.Job.Vim', + \ 'System.Job.Neovim', + \] +endfunction + +function! s:_vital_healthcheck() abort + if has('patch-8.0.0027') || has('nvim-0.2.0') + return + endif + return 'This module requires Vim 8.0.0027 or Neovim 0.2.0' +endfunction + + +" Note: +" Vim does not raise E902 on Unix system even the prog is not found so use a +" custom exception instead to make the method compatible. +" Note: +" Vim/Neovim treat String a bit differently so prohibit String as well +function! s:_validate_args(args) abort + if type(a:args) != s:t_list + throw 'vital: System.Job: Argument requires to be a List instance.' + endif + if len(a:args) == 0 + throw 'vital: System.Job: Argument vector must have at least one item.' + endif + let prog = a:args[0] + if !executable(prog) + throw printf('vital: System.Job: "%s" is not an executable', prog) + endif +endfunction + +function! s:is_available() abort + return s:Job.is_available() +endfunction + +function! s:start(args, ...) abort + call s:_validate_args(a:args) + return s:Job.start(a:args, a:0 ? a:1 : {}) +endfunction diff --git a/bundle/dein.vim/autoload/vital/_dein/System/Job/Neovim.vim b/bundle/dein.vim/autoload/vital/_dein/System/Job/Neovim.vim new file mode 100644 index 000000000..0b6ab30a3 --- /dev/null +++ b/bundle/dein.vim/autoload/vital/_dein/System/Job/Neovim.vim @@ -0,0 +1,133 @@ +" ___vital___ +" NOTE: lines between '" ___vital___' is generated by :Vitalize. +" Do not mofidify the code nor insert new lines before '" ___vital___' +function! s:_SID() abort + return matchstr(expand(''), '\zs\d\+\ze__SID$') +endfunction +execute join(['function! vital#_dein#System#Job#Neovim#import() abort', printf("return map({'is_available': '', 'start': ''}, \"vital#_dein#function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") +delfunction s:_SID +" ___vital___ +" http://vim-jp.org/blog/2016/03/23/take-care-of-patch-1577.html +function! s:is_available() abort + return has('nvim') && has('nvim-0.2.0') +endfunction + +function! s:start(args, options) abort + let job = extend(copy(s:job), a:options) + let job_options = {} + if has_key(a:options, 'cwd') + let job_options.cwd = a:options.cwd + endif + if has_key(job, 'on_stdout') + let job_options.on_stdout = function('s:_on_stdout', [job]) + endif + if has_key(job, 'on_stderr') + let job_options.on_stderr = function('s:_on_stderr', [job]) + endif + if has_key(job, 'on_exit') + let job_options.on_exit = function('s:_on_exit', [job]) + else + let job_options.on_exit = function('s:_on_exit_raw', [job]) + endif + let job.__job = jobstart(a:args, job_options) + let job.__exitval = v:null + let job.args = a:args + return job +endfunction + +function! s:_on_stdout(job, job_id, data, event) abort + call a:job.on_stdout(a:data) +endfunction + +function! s:_on_stderr(job, job_id, data, event) abort + call a:job.on_stderr(a:data) +endfunction + +function! s:_on_exit(job, job_id, exitval, event) abort + let a:job.__exitval = a:exitval + call a:job.on_exit(a:exitval) +endfunction + +function! s:_on_exit_raw(job, job_id, exitval, event) abort + let a:job.__exitval = a:exitval +endfunction + +" Instance ------------------------------------------------------------------- +function! s:_job_id() abort dict + if &verbose + echohl WarningMsg + echo 'vital: System.Job: job.id() is deprecated. Use job.pid() instead.' + echohl None + endif + return self.pid() +endfunction + +function! s:_job_pid() abort dict + return jobpid(self.__job) +endfunction + +function! s:_job_status() abort dict + try + sleep 1m + call jobpid(self.__job) + return 'run' + catch /^Vim\%((\a\+)\)\=:E900/ + return 'dead' + endtry +endfunction + +if exists('*chansend') " Neovim 0.2.3 + function! s:_job_send(data) abort dict + return chansend(self.__job, a:data) + endfunction +else + function! s:_job_send(data) abort dict + return jobsend(self.__job, a:data) + endfunction +endif + +if exists('*chanclose') " Neovim 0.2.3 + function! s:_job_close() abort dict + call chanclose(self.__job, 'stdin') + endfunction +else + function! s:_job_close() abort dict + call jobclose(self.__job, 'stdin') + endfunction +endif + +function! s:_job_stop() abort dict + try + call jobstop(self.__job) + catch /^Vim\%((\a\+)\)\=:E900/ + " NOTE: + " Vim does not raise exception even the job has already closed so fail + " silently for 'E900: Invalid job id' exception + endtry +endfunction + +function! s:_job_wait(...) abort dict + let timeout = a:0 ? a:1 : v:null + let exitval = timeout is# v:null + \ ? jobwait([self.__job])[0] + \ : jobwait([self.__job], timeout)[0] + if exitval != -3 + return exitval + endif + " Wait until 'on_exit' callback is called + while self.__exitval is# v:null + sleep 1m + endwhile + return self.__exitval +endfunction + +" To make debug easier, use funcref instead. +let s:job = { + \ 'id': function('s:_job_id'), + \ 'pid': function('s:_job_pid'), + \ 'status': function('s:_job_status'), + \ 'send': function('s:_job_send'), + \ 'close': function('s:_job_close'), + \ 'stop': function('s:_job_stop'), + \ 'wait': function('s:_job_wait'), + \} diff --git a/bundle/dein.vim/autoload/vital/_dein/System/Job/Vim.vim b/bundle/dein.vim/autoload/vital/_dein/System/Job/Vim.vim new file mode 100644 index 000000000..73e65570e --- /dev/null +++ b/bundle/dein.vim/autoload/vital/_dein/System/Job/Vim.vim @@ -0,0 +1,147 @@ +" ___vital___ +" NOTE: lines between '" ___vital___' is generated by :Vitalize. +" Do not mofidify the code nor insert new lines before '" ___vital___' +function! s:_SID() abort + return matchstr(expand(''), '\zs\d\+\ze__SID$') +endfunction +execute join(['function! vital#_dein#System#Job#Vim#import() abort', printf("return map({'is_available': '', 'start': ''}, \"vital#_dein#function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") +delfunction s:_SID +" ___vital___ +" https://github.com/neovim/neovim/blob/f629f83/src/nvim/event/process.c#L24-L26 +let s:KILL_TIMEOUT_MS = 2000 + +function! s:is_available() abort + return !has('nvim') && has('patch-8.0.0027') +endfunction + +function! s:start(args, options) abort + let job = extend(copy(s:job), a:options) + let job_options = { + \ 'mode': 'raw', + \ 'timeout': 0, + \} + if has_key(job, 'on_stdout') + let job_options.out_cb = function('s:_out_cb', [job]) + else + let job_options.out_io = 'null' + endif + if has_key(job, 'on_stderr') + let job_options.err_cb = function('s:_err_cb', [job]) + else + let job_options.err_io = 'null' + endif + if has_key(job, 'on_exit') + let job_options.exit_cb = function('s:_exit_cb', [job]) + endif + if has_key(job, 'cwd') && has('patch-8.0.0902') + let job_options.cwd = job.cwd + endif + let job.__job = job_start(a:args, job_options) + let job.args = a:args + return job +endfunction + +function! s:_out_cb(job, channel, msg) abort + call a:job.on_stdout(split(a:msg, "\n", 1)) +endfunction + +function! s:_err_cb(job, channel, msg) abort + call a:job.on_stderr(split(a:msg, "\n", 1)) +endfunction + +function! s:_exit_cb(job, channel, exitval) abort + " Make sure on_stdout/on_stderr are called prior to on_exit. + if has_key(a:job, 'on_stdout') + let options = {'part': 'out'} + while ch_status(a:channel, options) ==# 'open' + sleep 1m + endwhile + while ch_status(a:channel, options) ==# 'buffered' + call s:_out_cb(a:job, a:channel, ch_readraw(a:channel, options)) + endwhile + endif + if has_key(a:job, 'on_stderr') + let options = {'part': 'err'} + while ch_status(a:channel, options) ==# 'open' + sleep 1m + endwhile + while ch_status(a:channel, options) ==# 'buffered' + call s:_err_cb(a:job, a:channel, ch_readraw(a:channel, options)) + endwhile + endif + call a:job.on_exit(a:exitval) +endfunction + + +" Instance ------------------------------------------------------------------- +function! s:_job_id() abort dict + if &verbose + echohl WarningMsg + echo 'vital: System.Job: job.id() is deprecated. Use job.pid() instead.' + echohl None + endif + return self.pid() +endfunction + +function! s:_job_pid() abort dict + return job_info(self.__job).process +endfunction + +" NOTE: +" On Unix a non-existing command results in "dead" instead +" So returns "dead" instead of "fail" even in non Unix. +function! s:_job_status() abort dict + let status = job_status(self.__job) + return status ==# 'fail' ? 'dead' : status +endfunction + +" NOTE: +" A Null character (\0) is used as a terminator of a string in Vim. +" Neovim can send \0 by using \n splitted list but in Vim. +" So replace all \n in \n splitted list to '' +function! s:_job_send(data) abort dict + let data = type(a:data) == v:t_list + \ ? join(map(a:data, 'substitute(v:val, "\n", '''', ''g'')'), "\n") + \ : a:data + return ch_sendraw(self.__job, data) +endfunction + +function! s:_job_close() abort dict + call ch_close_in(self.__job) +endfunction + +function! s:_job_stop() abort dict + call job_stop(self.__job) + call timer_start(s:KILL_TIMEOUT_MS, { -> job_stop(self.__job, 'kill') }) +endfunction + +function! s:_job_wait(...) abort dict + let timeout = a:0 ? a:1 : v:null + let timeout = timeout is# v:null ? v:null : timeout / 1000.0 + let start_time = reltime() + let job = self.__job + try + while timeout is# v:null || timeout > reltimefloat(reltime(start_time)) + let status = job_status(job) + if status !=# 'run' + return status ==# 'dead' ? job_info(job).exitval : -3 + endif + sleep 1m + endwhile + catch /^Vim:Interrupt$/ + call self.stop() + return -2 + endtry + return -1 +endfunction + +" To make debug easier, use funcref instead. +let s:job = { + \ 'id': function('s:_job_id'), + \ 'pid': function('s:_job_pid'), + \ 'status': function('s:_job_status'), + \ 'send': function('s:_job_send'), + \ 'close': function('s:_job_close'), + \ 'stop': function('s:_job_stop'), + \ 'wait': function('s:_job_wait'), + \} diff --git a/bundle/dein.vim/autoload/vital/dein.vim b/bundle/dein.vim/autoload/vital/dein.vim new file mode 100644 index 000000000..eb8aeb606 --- /dev/null +++ b/bundle/dein.vim/autoload/vital/dein.vim @@ -0,0 +1,328 @@ +let s:plugin_name = expand(':t:r') +let s:vital_base_dir = expand(':h') +let s:project_root = expand(':h:h:h') +let s:is_vital_vim = s:plugin_name is# 'vital' + +let s:loaded = {} +let s:cache_sid = {} + +" function() wrapper +if v:version > 703 || v:version == 703 && has('patch1170') + function! s:_function(fstr) abort + return function(a:fstr) + endfunction +else + function! s:_SID() abort + return matchstr(expand(''), '\zs\d\+\ze__SID$') + endfunction + let s:_s = '' . s:_SID() . '_' + function! s:_function(fstr) abort + return function(substitute(a:fstr, 's:', s:_s, 'g')) + endfunction +endif + +function! vital#{s:plugin_name}#new() abort + return s:new(s:plugin_name) +endfunction + +function! vital#{s:plugin_name}#import(...) abort + if !exists('s:V') + let s:V = s:new(s:plugin_name) + endif + return call(s:V.import, a:000, s:V) +endfunction + +let s:Vital = {} + +function! s:new(plugin_name) abort + let base = deepcopy(s:Vital) + let base._plugin_name = a:plugin_name + return base +endfunction + +function! s:vital_files() abort + if !exists('s:vital_files') + let s:vital_files = map( + \ s:is_vital_vim ? s:_global_vital_files() : s:_self_vital_files(), + \ 'fnamemodify(v:val, ":p:gs?[\\\\/]?/?")') + endif + return copy(s:vital_files) +endfunction +let s:Vital.vital_files = s:_function('s:vital_files') + +function! s:import(name, ...) abort dict + let target = {} + let functions = [] + for a in a:000 + if type(a) == type({}) + let target = a + elseif type(a) == type([]) + let functions = a + endif + unlet a + endfor + let module = self._import(a:name) + if empty(functions) + call extend(target, module, 'keep') + else + for f in functions + if has_key(module, f) && !has_key(target, f) + let target[f] = module[f] + endif + endfor + endif + return target +endfunction +let s:Vital.import = s:_function('s:import') + +function! s:load(...) abort dict + for arg in a:000 + let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg] + let target = split(join(as, ''), '\W\+') + let dict = self + let dict_type = type({}) + while !empty(target) + let ns = remove(target, 0) + if !has_key(dict, ns) + let dict[ns] = {} + endif + if type(dict[ns]) == dict_type + let dict = dict[ns] + else + unlet dict + break + endif + endwhile + if exists('dict') + call extend(dict, self._import(name)) + endif + unlet arg + endfor + return self +endfunction +let s:Vital.load = s:_function('s:load') + +function! s:unload() abort dict + let s:loaded = {} + let s:cache_sid = {} + unlet! s:vital_files +endfunction +let s:Vital.unload = s:_function('s:unload') + +function! s:exists(name) abort dict + if a:name !~# '\v^\u\w*%(\.\u\w*)*$' + throw 'vital: Invalid module name: ' . a:name + endif + return s:_module_path(a:name) isnot# '' +endfunction +let s:Vital.exists = s:_function('s:exists') + +function! s:search(pattern) abort dict + let paths = s:_extract_files(a:pattern, self.vital_files()) + let modules = sort(map(paths, 's:_file2module(v:val)')) + return s:_uniq(modules) +endfunction +let s:Vital.search = s:_function('s:search') + +function! s:plugin_name() abort dict + return self._plugin_name +endfunction +let s:Vital.plugin_name = s:_function('s:plugin_name') + +function! s:_self_vital_files() abort + let builtin = printf('%s/__%s__/', s:vital_base_dir, s:plugin_name) + let installed = printf('%s/_%s/', s:vital_base_dir, s:plugin_name) + let base = builtin . ',' . installed + return split(globpath(base, '**/*.vim', 1), "\n") +endfunction + +function! s:_global_vital_files() abort + let pattern = 'autoload/vital/__*__/**/*.vim' + return split(globpath(&runtimepath, pattern, 1), "\n") +endfunction + +function! s:_extract_files(pattern, files) abort + let tr = {'.': '/', '*': '[^/]*', '**': '.*'} + let target = substitute(a:pattern, '\.\|\*\*\?', '\=tr[submatch(0)]', 'g') + let regexp = printf('autoload/vital/[^/]\+/%s.vim$', target) + return filter(a:files, 'v:val =~# regexp') +endfunction + +function! s:_file2module(file) abort + let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?') + let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$') + return join(split(tail, '[\\/]\+'), '.') +endfunction + +" @param {string} name e.g. Data.List +function! s:_import(name) abort dict + if has_key(s:loaded, a:name) + return copy(s:loaded[a:name]) + endif + let module = self._get_module(a:name) + if has_key(module, '_vital_created') + call module._vital_created(module) + endif + let export_module = filter(copy(module), 'v:key =~# "^\\a"') + " Cache module before calling module.vital_loaded() to avoid cyclic + " dependences but remove the cache if module._vital_loaded() fails. + " let s:loaded[a:name] = export_module + let s:loaded[a:name] = export_module + if has_key(module, '_vital_loaded') + try + call module._vital_loaded(vital#{s:plugin_name}#new()) + catch + unlet s:loaded[a:name] + throw 'vital: fail to call ._vital_loaded(): ' . v:exception + endtry + endif + return copy(s:loaded[a:name]) +endfunction +let s:Vital._import = s:_function('s:_import') + +" s:_get_module() returns module object wihch has all script local functions. +function! s:_get_module(name) abort dict + let funcname = s:_import_func_name(self.plugin_name(), a:name) + try + return call(funcname, []) + catch /^Vim\%((\a\+)\)\?:E117/ + return s:_get_builtin_module(a:name) + endtry +endfunction + +function! s:_get_builtin_module(name) abort + return s:sid2sfuncs(s:_module_sid(a:name)) +endfunction + +if s:is_vital_vim + " For vital.vim, we can use s:_get_builtin_module directly + let s:Vital._get_module = s:_function('s:_get_builtin_module') +else + let s:Vital._get_module = s:_function('s:_get_module') +endif + +function! s:_import_func_name(plugin_name, module_name) abort + return printf('vital#_%s#%s#import', a:plugin_name, s:_dot_to_sharp(a:module_name)) +endfunction + +function! s:_module_sid(name) abort + let path = s:_module_path(a:name) + if !filereadable(path) + throw 'vital: module not found: ' . a:name + endif + let vital_dir = s:is_vital_vim ? '__\w\+__' : printf('_\{1,2}%s\%%(__\)\?', s:plugin_name) + let base = join([vital_dir, ''], '[/\\]\+') + let p = base . substitute('' . a:name, '\.', '[/\\\\]\\+', 'g') + let sid = s:_sid(path, p) + if !sid + call s:_source(path) + let sid = s:_sid(path, p) + if !sid + throw printf('vital: cannot get from path: %s', path) + endif + endif + return sid +endfunction + +function! s:_module_path(name) abort + return get(s:_extract_files(a:name, s:vital_files()), 0, '') +endfunction + +function! s:_module_sid_base_dir() abort + return s:is_vital_vim ? &rtp : s:project_root +endfunction + +function! s:_dot_to_sharp(name) abort + return substitute(a:name, '\.', '#', 'g') +endfunction + +function! s:_source(path) abort + execute 'source' fnameescape(a:path) +endfunction + +" @vimlint(EVL102, 1, l:_) +" @vimlint(EVL102, 1, l:__) +function! s:_sid(path, filter_pattern) abort + let unified_path = s:_unify_path(a:path) + if has_key(s:cache_sid, unified_path) + return s:cache_sid[unified_path] + endif + for line in filter(split(s:_execute(':scriptnames'), "\n"), 'v:val =~# a:filter_pattern') + let [_, sid, path; __] = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$') + if s:_unify_path(path) is# unified_path + let s:cache_sid[unified_path] = sid + return s:cache_sid[unified_path] + endif + endfor + return 0 +endfunction + +" We want to use a execute() builtin function instead of s:_execute(), +" however there is a bug in execute(). +" execute() returns empty string when it is called in +" completion function of user defined ex command. +" https://github.com/vim-jp/issues/issues/1129 +function! s:_execute(cmd) abort + let [save_verbose, save_verbosefile] = [&verbose, &verbosefile] + set verbose=0 verbosefile= + redir => res + silent! execute a:cmd + redir END + let [&verbose, &verbosefile] = [save_verbose, save_verbosefile] + return res +endfunction + +if filereadable(expand(':r') . '.VIM') " is case-insensitive or not + let s:_unify_path_cache = {} + " resolve() is slow, so we cache results. + " Note: On windows, vim can't expand path names from 8.3 formats. + " So if getting full path via and $HOME was set as 8.3 format, + " vital load duplicated scripts. Below's :~ avoid this issue. + function! s:_unify_path(path) abort + if has_key(s:_unify_path_cache, a:path) + return s:_unify_path_cache[a:path] + endif + let value = tolower(fnamemodify(resolve(fnamemodify( + \ a:path, ':p')), ':~:gs?[\\/]?/?')) + let s:_unify_path_cache[a:path] = value + return value + endfunction +else + function! s:_unify_path(path) abort + return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?')) + endfunction +endif + +" copied and modified from Vim.ScriptLocal +let s:SNR = join(map(range(len("\")), '"[\\x" . printf("%0x", char2nr("\"[v:val])) . "]"'), '') +function! s:sid2sfuncs(sid) abort + let fs = split(s:_execute(printf(':function /^%s%s_', s:SNR, a:sid)), "\n") + let r = {} + let pattern = printf('\m^function\s%d_\zs\w\{-}\ze(', a:sid) + for fname in map(fs, 'matchstr(v:val, pattern)') + let r[fname] = function(s:_sfuncname(a:sid, fname)) + endfor + return r +endfunction + +"" Return funcname of script local functions with SID +function! s:_sfuncname(sid, funcname) abort + return printf('%s_%s', a:sid, a:funcname) +endfunction + +if exists('*uniq') + function! s:_uniq(list) abort + return uniq(a:list) + endfunction +else + function! s:_uniq(list) abort + let i = len(a:list) - 1 + while 0 < i + if a:list[i] ==# a:list[i - 1] + call remove(a:list, i) + endif + let i -= 1 + endwhile + return a:list + endfunction +endif diff --git a/bundle/dein.vim/autoload/vital/dein.vital b/bundle/dein.vim/autoload/vital/dein.vital new file mode 100644 index 000000000..bf5569f8b --- /dev/null +++ b/bundle/dein.vim/autoload/vital/dein.vital @@ -0,0 +1,4 @@ +dein +bc0bd9ae0d48bb12f3909056b311cb489bd9c494 + +System.Job diff --git a/bundle/dein.vim/bin/installer.ps1 b/bundle/dein.vim/bin/installer.ps1 new file mode 100644 index 000000000..49604f9c7 --- /dev/null +++ b/bundle/dein.vim/bin/installer.ps1 @@ -0,0 +1,71 @@ +param( + [Parameter(Mandatory=$true)][String]$PluginDir +) + +$DeinVimRepo = "https://github.com/Shougo/dein.vim" + +# Convert the installation directory to absolute path and create plugin directory +$PluginDir = (New-Item -Type Directory -Force $PluginDir).FullName + +$InstallDir = Join-Path $PluginDir "repos/github.com/Shougo/dein.vim" +Write-Output "Install to `"$InstallDir`"..." +if (Test-Path $InstallDir) { + Write-Output "`"$InstallDir`" already exists!" +} + +# check git command +if (!(Get-Command git -ErrorAction SilentlyContinue -OutVariable $_)) { + throw 'Please install git or update your path to include the git executable!' +} +Write-Output "" + +# make plugin dir and fetch dein +Write-Output "Begin fetching dein..." +git clone $DeinVimRepo $InstallDir +Write-Output "Done.`n" + +Write-Host -ForegroundColor Yellow "Please add the following settings for dein to the top of your vimrc (Vim) or init.vim (NeoVim) file:" + +Write-Output "" +Write-Output "" +Write-Output "`"dein Scripts-----------------------------" +Write-Output "if &compatible" +Write-Output " set nocompatible `" Be iMproved" +Write-Output "endif" +Write-Output "" +Write-Output "`" Required:" +Write-Output "set runtimepath+=$InstallDir" +Write-Output "" +Write-Output "`" Required:" +Write-Output "if dein#load_state('$PluginDir')" +Write-Output " call dein#begin('$PluginDir')" +Write-Output "" +Write-Output " `" Let dein manage dein" +Write-Output " `" Required:" +Write-Output " call dein#add('$InstallDir')" +Write-Output "" +Write-Output " `" Add or remove your plugins here like this:" +Write-Output " `"call dein#add('Shougo/neosnippet.vim')" +Write-Output " `"call dein#add('Shougo/neosnippet-snippets')" +Write-Output "" +Write-Output " `" Required:" +Write-Output " call dein#end()" +Write-Output " call dein#save_state()" +Write-Output "endif" +Write-Output "" +Write-Output "`" Required:" +Write-Output "filetype plugin indent on" +Write-Output "syntax enable" +Write-Output "" +Write-Output "`" If you want to install not installed plugins on startup." +Write-Output "`"if dein#check_install()" +Write-Output "`" call dein#install()" +Write-Output "`"endif" +Write-Output "" +Write-Output "`"End dein Scripts-------------------------" +Write-Output "" +Write-Output "" + +Write-Output "Done." + +Write-Output "Complete setup dein!" diff --git a/bundle/dein.vim/bin/installer.sh b/bundle/dein.vim/bin/installer.sh new file mode 100644 index 000000000..de8c093e2 --- /dev/null +++ b/bundle/dein.vim/bin/installer.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# Standalone installer for Unixs +# Original version is created by shoma2da +# https://github.com/shoma2da/neobundle_installer + +if [ $# -ne 1 ]; then + echo "You must specify the installation directory!" + exit 1 +fi + +# Convert the installation directory to absolute path +case $1 in + /*) PLUGIN_DIR=$1;; + *) PLUGIN_DIR=$PWD/$1;; +esac +INSTALL_DIR="${PLUGIN_DIR}/repos/github.com/Shougo/dein.vim" +echo "Install to \"$INSTALL_DIR\"..." +if [ -e "$INSTALL_DIR" ]; then + echo "\"$INSTALL_DIR\" already exists!" +fi + +echo "" + +# check git command +type git || { + echo 'Please install git or update your path to include the git executable!' + exit 1 +} +echo "" + +# make plugin dir and fetch dein +if ! [ -e "$INSTALL_DIR" ]; then + echo "Begin fetching dein..." + mkdir -p "$PLUGIN_DIR" + git clone https://github.com/Shougo/dein.vim "$INSTALL_DIR" + echo "Done." + echo "" +fi + +# write initial setting for .vimrc +echo "Please add the following settings for dein to the top of your vimrc (Vim) or init.vim (NeoVim) file:" +{ + echo "" + echo "" + echo "\"dein Scripts-----------------------------" + echo "if &compatible" + echo " set nocompatible \" Be iMproved" + echo "endif" + echo "" + echo "\" Required:" + echo "set runtimepath+=$INSTALL_DIR" + echo "" + echo "\" Required:" + echo "if dein#load_state('$PLUGIN_DIR')" + echo " call dein#begin('$PLUGIN_DIR')" + echo "" + echo " \" Let dein manage dein" + echo " \" Required:" + echo " call dein#add('$INSTALL_DIR')" + echo "" + echo " \" Add or remove your plugins here like this:" + echo " \"call dein#add('Shougo/neosnippet.vim')" + echo " \"call dein#add('Shougo/neosnippet-snippets')" + echo "" + echo " \" Required:" + echo " call dein#end()" + echo " call dein#save_state()" + echo "endif" + echo "" + echo "\" Required:" + echo "filetype plugin indent on" + echo "syntax enable" + echo "" + echo "\" If you want to install not installed plugins on startup." + echo "\"if dein#check_install()" + echo "\" call dein#install()" + echo "\"endif" + echo "" + echo "\"End dein Scripts-------------------------" + echo "" + echo "" +} + +echo "Done." + +echo "Complete setup dein!" diff --git a/bundle/dein.vim/doc/dein.txt b/bundle/dein.vim/doc/dein.txt new file mode 100644 index 000000000..d529568a6 --- /dev/null +++ b/bundle/dein.vim/doc/dein.txt @@ -0,0 +1,1250 @@ +*dein.txt* Dark powered Vim/Neovim plugin manager + +Version: 2.1 +Author: Shougo +License: MIT license + +============================================================================== +CONTENTS *dein-contents* + +Introduction |dein-introduction| +Usage |dein-usage| +Install |dein-install| +Interface |dein-interface| + Functions |dein-functions| + Variables |dein-variables| + Options |dein-options| + Toml |dein-toml| +Unite Sources |dein-unite-sources| +Denite Sources |dein-denite-sources| +Configuration Examples |dein-examples| +FAQ |dein-faq| +Compatibility |dein-compatibility| + + +============================================================================== +INTRODUCTION *dein-introduction* + +*dein* is the dark powered Vim package manager. It is created from full +scratch. + +Concepts are: + +* Faster than NeoBundle + +* Simple + +* No commands, Functions only to simplify the implementation + +* Easy to test and maintain + +* No Vundle/NeoBundle compatibility + +* neovim/Vim8 asynchronous API installation support + +* Local plugin support + +* Non github plugins support + +* Go like clone directory name ex:"github.com/{user}/{repository}" + +* Merge the plugins directories automatically to avoid long 'runtimepath' + + +============================================================================== +USAGE *dein-usage* + +Refer to the example: +|dein-examples| + +Run this command to update your plugins: +> + :call dein#update() +< +Note: The plugins are not updated automatically. + +============================================================================== +INSTALL *dein-install* + +Requirements: +* Vim 8.0 or above or NeoVim. +* "git" command in $PATH (if you want to install github or vim.org plugins) + +Note: If you use Vim 7.4, please use dein.vim ver.1.5 instead. + +First of all, git clone the repository. + +Note: You must define the installation directory before to use dein. It +depends on your usage. +For example, "~/.vim/bundles" or "~/.cache/dein" or "~/.local/share/dein". +dein.vim does not define the default installation directory. +You must not set the installation directory under "~/.vim/plugin" or +"~/.config/nvim/plugin". + +Note: You need to have git installed. +> + $ mkdir -p ~/.vim/bundle/repos/github.com/Shougo/dein.vim + $ git clone https://github.com/Shougo/dein.vim \ + ~/.vim/bundle/repos/github.com/Shougo/dein.vim +< +And set up a path to the repository directory. +> + set runtimepath+={path to dein directory} +< +Example: +> + set runtimepath+=~/.vim/bundle/repos/github.com/Shougo/dein.vim +< +Now configure your bundles. (Refer to |dein-examples|) + +Call |dein#update()| function to install your plugins. +> +If you need vim-plug like install UI, you can use dein-ui.vim. +https://github.com/wsdjeg/dein-ui.vim + + +============================================================================== +INTERFACE *dein-interface* + + +------------------------------------------------------------------------------ +FUNCTIONS *dein-functions* + + *dein#add()* +dein#add({repo}[, {options}]) + Initialize a plugin. + {repo} is the repository URI or local repository directory + path. If {repo} starts with github user name (ex: + "Shougo/dein.vim"), dein will install github plugins. + See |dein-options| for what to set in {options}. + Note: You must call it in |dein#begin()| block. + + *dein#begin()* +dein#begin({base-path}, [{vimrcs}]) + Initialize dein.vim and start plugins configuration + block. + {base-path} is where your downloaded plugins will be placed. + For example, "Shougo/dein.vim" will be downloaded in + "{base-path}/repos/github.com/Shougo/dein.vim" directory. + {vimrcs} is a list of compared .vimrc and/or other + configuration(TOML) files. The default is |$MYVIMRC|. + The typical {base-path} is "~/.cache/dein" or + "~/.local/share/dein". + + Note: You must not call the function inside a + "has('vim_starting')" block. + + Note: It executes ":filetype off" automatically. + + *dein#build()* +dein#build([{plugins}]) + Build for {plugins}. + {plugins} is the plugins name list. + + *dein#call_hook()* +dein#call_hook({hook-name}) + Calls the hook {hook-name}. + Note: If {hook-name} is "source", dein will call "source" + hooks in sourced plugins. + + *dein#check_install()* +dein#check_install({plugins}) + Check the plugins installation. + If {plugins} are not installed, it will return non-zero. + If {plugins} are invalid, it will return -1. + {plugins} are the plugins name list or the plugin name to + check. + If you omit it, dein will check all plugins installation. + Note: You can disable the message by |:silent|. + + *dein#check_lazy_plugins()* +dein#check_lazy_plugins() + Check the no meaning lazy plugins. These plugins don't have + "plugin/" directory. + + *dein#check_update()* +dein#check_update([{plugins}]) + Check the plugins update asynchronously. + {plugins} is the plugins name list to check. + If you omit it, dein will check all plugins update. + Note: It does not return value instead of + |dein#check_install()|. + + *dein#check_clean()* +dein#check_clean() + Returns the non-used plugins directories. You can write the + wrap command to remove them. + + *dein#clear_state()* +dein#clear_state() + Clear the state file manually. + + *dein#config()* +dein#config({plugin-name}, {options}) +dein#config({options}) + Change plugin options for {plugin-name}. + It you omit {plugin-name}, it uses |g:dein#name| variable. + If {plugin-name} is list, you can change the options in the + multiple plugins. + If {plugin-name} is already loaded or invalid, it will be + ignored. + + Note: You must call it within |dein#begin()| / |dein#end()| + block. +> + call dein#add('Shougo/deoplete.nvim') + call dein#config('deoplete.nvim', { + \ 'lazy' : 1, 'on_i' : 1, + \ }) +< + *dein#direct_install()* +dein#direct_install({repo}[, {options}]) + Direct install a plugin without editing the configuration. + The arguments are same with |dein#add()|. + It installs and sources the plugin. + Note: The direct installed plugins configuration is saved in + |dein#get_direct_plugins_path()|. You can load or edit it. > + + " Try deoplete without the configuration. + call dein#direct_install('Shougo/deoplete.nvim') +< + *dein#disable()* +dein#disable({plugins}) + Disables plugins specified by {plugins}. + {plugins} is the plugins name list. + Note: This command must be executed before dein loads + the plugins. + + *dein#each()* +dein#each({command}[, {plugins}]) + Execute {command} for {plugins}. + {plugins} is the plugins name list. + You can execute "git gc" command for the plugins. + + *dein#end()* +dein#end() + End dein configuration block. + You must not use the plugins in |dein#begin()| block. + If you enable |g:dein#auto_recache|, it executes + |dein#recache_runtimepath()| automatically. + Note: 'runtimepath' is changed after |dein#end()|. + + *dein#get()* +dein#get([{plugin-name}]) + Get the plugin options dictionary for {plugin-name}. + If you omit {plugin-name}, dein will return the plugins + dictionary. The key is the plugin name. The value is the + plugin dictionary. + + *dein#get_direct_plugins_path()* +dein#get_direct_plugins_path() + Get the direct installed plugins script path. + + *dein#get_log()* +dein#get_log() + Get all previous install logs. + + *dein#get_progress()* +dein#get_progress() + Get current update progress message. + + *dein#get_updates_log()* +dein#get_updates_log() + Print previous update logs. + + *dein#install()* +dein#install([{plugins}]) + Install the plugins asynchronously. + {plugins} is the plugins name list. + If you omit it, dein will install all plugins. + + *dein#is_sourced()* +dein#is_sourced({plugin-name}) + Return non-zero if {plugin-name} exists and is sourced. + See |dein#source()| and |dein#tap()| as well. + + *dein#load_dict()* +dein#load_dict({dict}, [{options}]) + Load the plugin configuration from {dict}. {dict} is the + |Dictionary|. The key is the repository URI and the value is + the |dein-options| dictionary. See |dein-options| for keys to + set in {options}. > + + call dein#load_dict({ + \ 'Shougo/denite.nvim': {}, + \ 'Shougo/deoplete.nvim': {'name': 'deoplete'} + \ }) +< + *dein#load_rollback()* +dein#load_rollback({rollbackfile}[, {plugins}]) + Rollback {plugins} from {rollbackfile}. + Note: It is the dangerous command. + + *dein#load_state()* +dein#load_state({base-path}) + Load dein's state from the cache script, + which is located in `dein#util#_get_runtime_path() . '/state_' + . fnamemodify(v:progname, ':r') . '.vim'`. + {base-path} is where your downloaded plugins will be placed. + Note: You must call it before |dein#begin()|. It clears dein + all configuration. + Note: It overwrites your 'runtimepath' completely, you must + not call it after change 'runtimepath' dynamically. + Note: The block is skipped if dein's state is loaded. + + It returns 1, if the cache script is old or invalid or not + found. +> + if dein#load_state(path) + call dein#begin(path) + " My plugins here: + " ... + call dein#end() + call dein#save_state() + endif +< + *dein#load_toml()* +dein#load_toml({filename}, [{options}]) + Load TOML plugin configuration from {filename}. See + |dein-options| for keys to set in {options}. + Note: TOML parser is slow. You should use it with + |dein#load_state()| and |dein#save_state()|. + Note: You need to specify toml files in |dein#begin()| + argument. + + For toml file formats: |dein-toml| +> + let s:toml = '~/test_vim/lazy.toml' + if dein#load_state('~/test_vim/.cache/dein', [$MYVIMRC, s:toml]) + call dein#begin('~/test_vim/.cache/dein') + + call dein#load_toml(s:toml, {'lazy': 1}) + + call dein#end() + call dein#save_state() + endif +< + *dein#local()* +dein#local({directory}, [{options}, [{names}]]) + Add the subdirectories in {directory} to 'runtimepath', like + "pathogen" does. See |dein-options| for keys to set in + {options}. + If {names} is given, {names} directories are only loaded. + {names} is |wildcards| list. +> + " Load plugin from "~/.vim/bundle". + call dein#local("~/.vim/bundle") + " Load plugin1 and plugin2 from "~/.vim/bundle". + call dein#local("~/.vim/bundle", {}, + \ ['plugin1', 'plugin2', 'vim-*', '*.vim']) +< + *dein#update()* +dein#update([{plugins}]) + Install/Update the plugins. + {plugins} is the plugins name list. + If you omit it, dein will update all plugins. + Note: If you are using neovim or Vim 8.0+, it runs + asynchronously. + + *dein#plugins2toml()* +dein#plugins2toml({plugins}) + Returns the toml configurations for {plugins} + {plugins} is the plugins dictionary from |dein#get()|. + + *dein#reinstall()* +dein#reinstall({plugins}) + Reinstall the plugins. + {plugins} is the plugins name list. + + *dein#remote_plugins()* +dein#remote_plugins() + Load not loaded neovim |remote-plugin| and execute + ":UpdateRemotePlugins" command. + It is better than ":UpdateRemotePlugins" for dein. + Note: It is valid only in neovim. + + *dein#rollback()* +dein#rollback({date}[, {plugins}]) + Rollback to the latest matched {date} revisions for {plugins}. + If {date} is "", it rollbacks to the latest revisions. + {plugins} is the plugins name list. + Note: It is the dangerous command. + + *dein#recache_runtimepath()* +dein#recache_runtimepath() + Re-make the dein runtimepath cache and execute |:helptags|. + It is called automatically after the installation. + + *dein#save_rollback()* +dein#save_rollback({rollbackfile}[, {plugins}]) + Save {plugins} rollback information to {rollbackfile}. + + *dein#save_state()* +dein#save_state() + Save dein's state in the cache script. + It must be after |dein#end()|. + Note: It is available when loading .vimrc. + Note: It saves your 'runtimepath' completely, you must not + call it after change 'runtimepath' dynamically. + + *dein#set_hook()* +dein#set_hook({plugins}, {hook-name}, {hook}) + {plugins} is the plugins name list. + If it is empty list, it means all plugins. + Set hook {hook} as {hook-name} in {plugins}. + It can be called after |dein#begin()| / |dein#end()| block. + Note: If it is |Funcref|, it does not work in + |dein#load_state()| / |dein#save_state()| block. +> + call dein#add('Shougo/neosnippet.vim', {'lazy': 1}) + function! Foo() abort + endfunction + " Does not work for dein#load_state()/dein#save_state() block + call dein#set_hook('neosnippet.vim', 'hook_source', function('Foo')) + " Does work for dein#load_state()/dein#save_state() block + call dein#set_hook('neosnippet.vim', 'hook_source', 'echomsg "foo"') +< + *dein#source()* +dein#source([{plugins}]) + |:source| the plugins specified by {plugins}. + {plugins} is the plugins name list. + If you omit it, dein will source all plugins. + + *dein#tap()* +dein#tap({plugin-name}) + Return non-zero if {plugin-name} exists and isn't + disabled. + It initializes |g:dein#name| and |g:dein#plugin| variables. + +------------------------------------------------------------------------------ +VARIABLES *dein-variables* + + *g:dein#auto_recache* +g:dein#auto_recache + If you set it to 1, call |dein#recache_runtimepath()| + automatically if necessary when saving the vimrc, toml file. + Note: It reloads your $MYVIMRC. + + Default: 0 + + *g:dein#cache_directory* +g:dein#cache_directory + The cache directory to use. + + Default: Under the base directory you have already specified + by |dein#begin()|. + + *g:dein#download_command* +g:dein#download_command + The default download command. + + Default: "curl --silent --location --output" or "wget -q -O" + or use PowerShell. + + *g:dein#enable_name_conversion* +g:dein#enable_name_conversion + If you set it to 1 and omit plugin name, + |dein-options-normalized_name| is used as plugin name. + It is useful for absorbing difference of repository name. + + Defaults: "0" + + *g:dein#enable_notification* +g:dein#enable_notification + If you set it to 1, dein uses the notification feature. + You need the following commands to use it. + + In Windows: "Snarl" and "Snarl_CMD" commands +http://snarl.fullphat.net/ +https://www.tlhan-ghun.de/projects/snarl-command-line-tools/snarl_cmd-exe/ + + In Mac: "terminal-notifier" or "osascript" command +https://github.com/julienXX/terminal-notifier + Note: "reattach-to-user-namespace" command is needed in tmux. + + In Linux: "notify-send" command + + Defaults: "0" + + *g:dein#install_max_processes* +g:dein#install_max_processes + The max number of processes used for dein/install source + asynchronous update. + If it is less than equal 1, this feature is disabled. + + Defaults: "8" + + *g:dein#install_process_timeout* +g:dein#install_process_timeout + The time of timeout seconds when updating/installing plugins. + + Defaults: "120" + + *g:dein#install_progress_type* +g:dein#install_progress_type + The output type of the progress bar in the installer. + Note: If you want to display the progress in the 'statusline', + you should use |dein#get_progress()| . + + "none": + Disabled. + "echo": + Displayed in the echo area. + "tabline": + Displayed in the 'tabline'. + "title": + Displayed in the 'titlestring'. + Note: It is neovim only support + + Defaults: "echo" + + *g:dein#install_message_type* +g:dein#install_message_type + The output type of the messages in the installer. + + "none": + Disabled. + "echo": + Displayed in the echo area. + + *g:dein#install_log_filename* +g:dein#install_log_filename + The log filename. Set it to "" to disable logging. + + Default: "" + + *g:dein#name* +g:dein#name + Current plugin name. + You can only use it in |dein#tap()| block. + Note: The variable is deprecated. + + *g:dein#notification_icon* +g:dein#notification_icon + The notification icon path. + + Default: "" + + *g:dein#notification_time* +g:dein#notification_time + This is the time the notification should be displayed in + seconds. For Linux and Windows only. + + Default: 2 + + *g:dein#plugin* +g:dein#plugin + Current plugin. + You can use it in |dein#tap()| block or |dein-hooks|. + + *g:dein#types#git#clone_depth* +g:dein#types#git#clone_depth + The default history depth for "git clone". + If it is 1, dein will use shallow clone feature. + See |dein-options-type__depth|. + + Default: 0 + + *g:dein#types#git#command_path* +g:dein#types#git#command_path + The "git" command path used for git type. + + Default: "git" + + *g:dein#types#git#default_protocol* +g:dein#types#git#default_protocol + The default protocol used for git (github). + Note: It only accepts "https" or "ssh". + + Default: "https" + + *g:dein#types#git#pull_command* +g:dein#types#git#pull_command + The git command used to pull updates. + + Default: "pull --ff --ff-only" + +------------------------------------------------------------------------------ +OPTIONS *dein-options* + The {options} accepts the following keys: + + *dein-options-augroup* +augroup (String) + An augroup name that the plugin uses for |VimEnter| or + |GUIEnter| autocmd events. + + *dein-options-build* +build (String) + Specify the build script. + This command is executed by |system()| in the plugin + runtimepath. + Note: In previous versions of dein, build could also be of + type dictionary, but that is now deprecated. + dictionary, but that is now deprecated. + Please use |dein-options-hook_post_update| instead. + + Example: +> + call dein#add('Shougo/vimproc.vim', {'build': 'make'}) +< + Note: The command is executed in plugin top directory. + If you need cd command, you must use "sh -c". > + call dein#add('wincent/command-t', { + \ 'build': + \ 'sh -c "cd ruby/command-t && ruby extconf.rb && make"' + \ }) + *dein-options-depends* +depends (List or String) + Specify a list of plugins a plugin depends on. + List items are '{plugin-name}'. + Those specified in the list are NOT installed automatically. + Note: The loading order is not guaranteed in non lazy plugins. + + *dein-options-frozen* +frozen (Number) + If set to 1, dein doesn't update it automatically. It is + useful for outdated plugins that can no longer be updated. + + *dein-options-ftplugin* +ftplugin (Dictionary) + "_" key is executed after all ftplugin. + "{filetype}" key is executed {filetype} ftplugin. + + *dein-options-if* +if (Number) or (String) + If set to zero, dein doesn't register the plugin, i.e. the + plugin will be disabled. + If it is String, dein will eval it. + If you don't set it, dein will register (enable) the plugin. + + *dein-options-lazy* +lazy (Number) + If set to non-zero, dein doesn't add the path to 'runtimepath' + automatically. + If you don't set it, dein will set it automatically when the + conditions are met. + Note: You should not specify the plugins which have no + "plugin/" directory as lazy load plugins. It is meaningless + and just increases the overhead. You can get the no meaning + lazy plugins by |dein#check_lazy_plugins()|. + + *dein-options-merged* +merged (Number) + If set to 0, dein doesn't merge the plugin directory. It is + useful for the plugin files conflicts. + + *dein-options-name* +name (String) + Specify the name of the plugin. This is used for dein + management and other functions. If it is omitted, the tail of + the repository name will be used. + Note: Must be unique across the all plugin. If the plugin + name conflicts with another plugin, dein will overwrite the + previous settings with the new one. If the repo tail is bound + to conflict, you can set the "name" option manually to prevent + overwriting an existing plugin setting. + + *dein-options-normalized_name* +normalized_name (String) + Specify the normalized name of the plugin. If omitted, dein + will normalize the tail of the repository name. + Note: Must be unique across all plugins. + Normalized name example: + name : normalized name +> + denite.nvim denite + dein.vim dein + vim-quickrun quickrun +< + *dein-options-on_cmd* +on_cmd (List) or (String) + If it is matched to the executed command, dein will call + |dein#source()|. + + *dein-options-on_event* +on_event (String) or (List) + dein will call |dein#source()| on the events. + + *dein-options-on_func* +on_func (List) or (String) + If it is matched to the called function, dein will call + |dein#source()|. + + *dein-options-on_ft* +on_ft (List) or (String) + If it is matched to 'filetype', dein will call + |dein#source()|. + + *dein-options-on_i* +on_i (Number) + If set to non-zero, dein will call |dein#source()| on + |InsertEnter| autocmd. + Note: This is deprecated option. You should use + |dein-options-on_event| instead. + + *dein-options-on_idle* +on_idle (Number) + If set to non-zero, dein will call |dein#source()| on + |FocusLost| or |CursorHold| autocmd. + Note: This is deprecated option. You should use + |dein-options-on_event| instead. + + *dein-options-on_if* +on_if (String) + If it is evaluated and it is non-zero, dein will call + |dein#source()|. + The default evaluate timings are "BufRead", "BufNewFile", + "VimEnter" and "FileType". + If |dein-options-on_event| exists, it is evaluated when + |dein-options-on_event|. + + For example: > + call dein#add('blueyed/vim-diminactive', + \ {'on_event': 'WinEnter', 'on_if': 'winnr("$") > 1'}) +< + *dein-options-on_map* +on_map (Dictionary) or (List) or (String) + If it is the Dictionary, the key is {mode} and the items are + {mapping} or [{mapping1}, {mapping2}, ...]. + If it is the List, the items are {mapping} or [{mode}, + {mapping1}, [{mapping2}, ...]]. + If {mode} is omitted, "nx" is used. + Note: You can use plugin prefix mappings. + For example, you can use "(ref-" instead of + "(ref-back)" and so on. + For example: > + call dein#add('Shougo/deol.nvim', + \ { 'on_map': {'n': ''} }) +< + Note: You can use "" keyword as {mapping}. If + {mapping} is "", "(normalized_name" is + used. + For example: > + " It is same as "'mappings': '(anzu' + call dein#add('osyo-manga/vim-anzu', {'on_map': ''}) +< + Note: You cannot use lazy mappings twice. + For example: > + call dein#add('osyo-manga/vim-anzu', + \ {'on_map': '(anzu-'} + " Not working!! + nmap n (anzu-jump-n)(anzu-echo-search-status)zv + nmap N (anzu-jump-N)(anzu-echo-search-status)zv +< + *dein-options-on_path* +on_path (List) or (String) + If set to ".*", dein will call |dein#source()| on editing all + files. Otherwise, dein will call |dein#source()| if the + buffer name is matched to the string pattern. + Note: It is useful for explorer behavior plugins. + + *dein-options-on_source* +on_source (List) or (String) + Load the plugin before the listed plugins are loaded. + Note: The plugins must be lazy loaded plugins. + + *dein-options-path* +path (String) + Specify the plugin downloaded path. + + *dein-options-rev* +rev (String) + Specify a revision number or branch/tag name. + If it is "*" in "git" type, dein will use latest released tag. + You can specify the wildcards like "0.*". + Note: If the type is "raw", rev must be hash number. + + Example: +> + call dein#add('Shougo/deol.nvim', { 'rev': 'a1b5108fd5' }) +< + *dein-options-rtp* +rtp (String) + Specify the runtime path. + You can use it when the repository has the Vim plugin in a + subdirectory. + For example: https://github.com/rstacruz/sparkup + If it is empty string, dein will not add the path to + 'runtimepath' + + Example: +> + call dein#add('rstacruz/sparkup', {'rtp': 'vim'}) +< + *dein-options-script_type* +script_type (String) + Specify the script type. It is useful for non-official + categorized plugins. + For example: "indent", "plugin", "ftplugin", ... + Note: You must not specify it for categorized plugins. + Example: +> + call dein#add( + \ 'https://raw.githubusercontent.com/Shougo/' + \ . 'shougo-s-github/master/vim/colors/candy.vim', + \ {'script_type' : 'colors'}) + call dein#add( + \ 'https://github.com/bronzehedwick/impactjs-colorscheme', + \ {'script_type' : 'colors'}) +< + *dein-options-timeout* +timeout (Number) + The time of timeout seconds when updating/installing plugins. + If omit it, |g:dein#install_process_timeout| will be used. + + *dein-options-trusted* +trusted (Number) + If set to non-zero, dein will load the plugin in "sudo" mode. + If you don't set it, dein won't load it. + + *dein-options-type* +type (String) + Specify the repository type. If it is omitted, a guess is made + based on {repository}. + + The available types: + "none" : None repository + "raw" : Raw plugin file ("script_type" attribute is + needed) + "git" : Git + + *dein-options-type__depth* +type__depth (Number) + The history depth for "git clone". + If omitted, |g:dein#types#git#clone_depth| is used. + If it is than 0, dein clones the repository by shallow + clone. Shallow clone feature saves your repository clone time. + But it has problems in some repository. + + See below issues: + https://github.com/Shougo/neobundle.vim/issues/81 + https://github.com/Homebrew/homebrew/issues/12024 + + Note: This attribute is available in git type only. + +------------------------------------------------------------------------------ +HOOKS *dein-hooks* + + The string will be split by the lines. + It is useful for the plugins initialization. + Note: The Function hooks cannot be cached. You must + initialize it. + + Note: You can use |g:dein#plugin| in the hooks. + Note: The loading order is not guaranteed in non lazy plugins. + Note: The string is executed as Ex commands. + + *dein-options-hook_add* +hook_add (String) or (Function) + It is executed after the line is parsed. + Note: You cannot call plugin function in "hook_add". + Because the plugin is not sourced when "hook_add". +> + call dein#add('Shougo/defx.nvim', { + \ 'hook_add': 'nnoremap [Space]v + \ :Defx' + \ }) + call dein#add('kana/vim-niceblock', { + \ 'hook_add': join(['xmap I (niceblock-I)', + 'xmap A (niceblock-A)'], "\n") + \ }) + call dein#add('godlygeek/csapprox', { + \ 'hook_add': " + \ let g:CSApprox_konsole = 1\n + \ let g:CSApprox_attr_map = + \ { 'bold' : 'bold', 'italic' : '', 'sp' : '' }\n + \ "}) +< + *dein-options-hook_done_update* +hook_done_update (String) or (Function) + It is executed after the all plugins are updated. + + *dein-options-hook_post_source* +hook_post_source (String) or (Function) + It is executed after plugins are sourced. + + Note: In Vim initializing, you must call the + "hook_post_source" hooks manually in |VimEnter| if needed. +> + autocmd VimEnter * call dein#call_hook('post_source') +< + *dein-options-hook_post_update* +hook_post_update (String) or (Function) + It is executed after the plugins are updated. + + *dein-options-hook_source* +hook_source (String) or (Function) + It is executed before plugins are sourced. + Note: The "sourced" means after |dein#end()| or when + |VimEnter| or autoloaded. +> + call dein#add('artur-shaik/vim-javacomplete2') + call dein#config('artur-shaik/vim-javacomplete2', { + \ 'hook_source': 'autocmd FileType java + \ setlocal omnifunc=javacomplete#Complete' + \ }) + function! Func() abort + autocmd FileType qf nnoremap r :Qfreplace + endfunction + call dein#source('thinca/vim-qfreplace', + \ 'hook_source': function('Func')) +< + Note: non lazy plugins' |dein-options-hook_source| cannot be + called. You must call it by |dein#call_hook()| if needed. +> + call dein#begin() + ... + call dein#end() + call dein#call_hook('source') +< +------------------------------------------------------------------------------ +TOML *dein-toml* + + TOML file format specification: + https://github.com/toml-lang/toml + Note: Original TOML parser is created by kamichidu. + https://github.com/kamichidu + + *dein-toml-ftplugin* + ftplugin (Dictionary) + "_" key is executed after all ftplugin. + "{filetype}" key is executed {filetype} ftplugin. + You can define multiple filetypes by "{filetype1}_{filetype2}" + key. "b:undo_ftplugin" is defined automatically. + + *dein-toml-hook_add* + hook_add (String) + It is the global |dein-options-hook_add|. + It is executed in |dein#end()|. + + *dein-toml-plugins* + plugins (Dictionary) + It is converted to |dein#add()|. + "repo" key is needed. + + *dein-toml-example* + + TOML file sample is here: +> + # TOML sample + hook_add = 'let g:foo = 0' + + [ftplugin] + # Execute after ftplugin. + _ = ''' + setl formatoptions-=ro | setl formatoptions+=mMBl + ''' + html = ''' + setlocal includeexpr=substitute(v:fname,'^\\/','','') + setlocal path+=./;/ + ''' + + [[plugins]] + repo = 'Shougo/neosnippet.vim' + on_i = 1 + on_ft = 'snippet' + + [[plugins]] + repo = 'rhysd/accelerated-jk' + on_map = '' + hook_add = ''' + nmap j (accelerated_jk_gj) + nmap k (accelerated_jk_gk) + ''' + [plugins.ftplugin] + python = ''' + let b:undo_ftplugin .= 'setlocal foldmethod<' + setlocal foldmethod=indent + ''' + +============================================================================== +UNITE SOURCES *dein-unite-sources* + +Here let me explain about a source for |unite| provided in dein. + + *dein-unite-source-dein* +dein + Nominates dein plugins as candidates. + + Note: + If argument is bang(!), print plugins status. + + *dein-unite-source-dein_log* +dein_log + Print previous dein install logs. + And you can jump the diff URI in github. + + If argument 1 is "!", the updated logs are displayed. + + Source arguments: + 1. "!" + +============================================================================== +DENITE SOURCES *dein-denite-sources* + +Here let me explain about a source for |denite| provided in dein. + + *dein-denite-source-dein* +dein + Nominates dein plugins as candidates. + + *dein-denite-source-dein-log* +dein/log + Print previous dein install logs. + And you can jump the diff URI in github. + + If argument 1 is "!", the updated logs are displayed. + + Source arguments: + 1. "!" + +============================================================================== +EXAMPLES *dein-examples* +> + if &compatible + set nocompatible + endif + set runtimepath+={path to dein.vim directory} + + if dein#load_state({path to plugin base path directory}) + call dein#begin({path to plugin base path directory}) + + call dein#add({path to dein.vim directory}) + call dein#add('Shougo/deoplete.nvim') + if !has('nvim') + call dein#add('roxma/nvim-yarp') + call dein#add('roxma/vim-hug-neovim-rpc') + endif + ... + + call dein#end() + call dein#save_state() + endif + + filetype plugin indent on + syntax enable +< +============================================================================== +FAQ *dein-faq* + +Q: How to donate money to you? + +A: I don't get the donation, but if you want to donate, please support neovim +project. My plugins depends on neovim development. + +https://salt.bountysource.com/teams/neovim + +Q: Where is ":NeoBundleFetch" in dein features? + +A: You can use |dein-options-rtp|. +> + call dein#add('Shougo/dein.vim', {'rtp': ''}) +< + Note: It does not generate |:helptags| file. + +Q: vimproc does not work when manually build it. +https://github.com/Shougo/dein.vim/issues/11 + +A: You should not build it manually. Please use |dein-options-build| feature. +> + call dein#add('Shougo/vimproc.vim', {'build': 'make'}) +< +Q: Where is ":NeoBundleCheck" in dein features? + +A: You can use |dein#check_install()|. +> + if dein#check_install() + call dein#install() + endif +< +Q: I want to disable plugins. + +A: Please use |dein-options-if|. + +Q: Cannot load colorscheme when reloading .vimrc. + +A: You must write |:colorscheme| lines after |dein#end()|. +> + call dein#add('tomasr/molokai', {'merged': 0}) + ... + + call dein#end() + colorscheme molokai +< +Or you can use |dein#source()| for it. +> + call dein#add('tomasr/molokai', {'merged': 0}) + call dein#source('molokai') + colorscheme molokai +< +Q: There is the conflict between "jedi-vim" and "vim-pyenv" "initialize.py" +file. + +A: It is the plugins problem. The plugins should not create the conflited +name file. But you can avoid the problem by |dein-options-merged|. + +Q: How to remove the disabled plugins? + +A: You can remove them like below. +Note: You must call |dein#recache_runtimepath()| after the remove. +> + call map(dein#check_clean(), "delete(v:val, 'rf')") + call dein#recache_runtimepath() +< +Q: How to use the script functions for hooks feature? + +A: You can use them like this. +Note: You cannot use the script functions for cached plugins. +The SID will be changed in the next run. +> + function s:SID() + return matchstr(expand(''), '\zs\d\+_\zeSID$') + endfun + function! s:test() + endfunction + call dein#add('Shougo/deoplete.nvim', + \ {'hook_source': 'call ' . s:SID() . 'test()'}) +< +Or you can execute the autocmd manually. +> + autocmd User dein#source#deoplete.nvim call s:test() + call dein#add('Shougo/deoplete.nvim', { + \ 'hook_source': + \ 'execute "doautocmd User" "dein#source#". + \ g:dein#plugin.name' + \ }) +< +But you must define the autocmd. + +Q: I don't want to call |dein#recache_runtimepath()| manually. +A: Please specify your vimrc path to |dein#begin()| 2nd argument. +It detects the vimrc changes. +> + call dein#begin(path, [expand('')]) +< +Q: I need the wrapper commands for dein.vim. + +A: You can use it. +https://github.com/haya14busa/dein-command.vim + +Q: Why the install script does not use "curl | bash" ? +https://github.com/Shougo/neobundle.vim/pull/515 + +A: +https://www.idontplaydarts.com/2016/04/detecting-curl-pipe-bash-server-side/ + +Q: I want to use "git" or "http" protocol instead of "https". + +A: No, you cannot. + +Q: Why dein.vim only accepts "https" or "ssh"? + +A: https://glyph.twistedmatrix.com/2015/11/editor-malware.html + +Q: YouCompleteMe installation is failed. +https://github.com/Shougo/dein.vim/issues/144 + +A: Please check |:messages| result. +If you have found "Process timeout" error, you should increase +|g:dein#install_process_timeout| value. + +Q: YouCompleteMe does not work. I have built YouCompleteMe manually. + +A: dein.vim has merge feature. It copys the plugins into the merge directory. +So dein.vim does not know the manually built binary. It does not be copied. +You should disable the merge feature manually. > + call dein#add('Valloric/YouCompleteMe', {'merged': 0}) + +or > + call dein#add('Valloric/YouCompleteMe', {'build': './install.py'}) + +Q: I have got "Invalid range error" when plugin updating. + +A: It is Vim/neovim |delete()| implementation bug. +It uses |glob()| internally. +If the directory has contains "[]" files, it will be errored. +For example, vimtex has the file. +https://github.com/lervag/vimtex/tree/master/test/issues/237/ + +You can disable the merge feature to prevent the error. > + call dein#add('lervag/vimtex', {'merged': 0}) + + +Q: I have got prompted for my github username and I have to kill the editor... + +A: You have specified wrong/removed repository name. You should check the +repository. + +Q: Why dein.vim merges the plugins directories automatically? + +A: To avoid long 'runtimepath'. If 'runtimepath' is long, Vim/neovim loading +performance will be bad. + +Q: I want to update from shell. + +A: > + $ vim -c "try | call dein#update() | finally | qall! | endtry" \ + -N -u $VIMRC -U NONE -i NONE -V1 -e -s + +Q: I want to change the environment variable when build. +A: > + call dein#add('nixprime/cpsm', + \ {'build': 'sh -c "PY3=ON ./install.sh"'}) + + +Q: dein.vim does not load plugin in sudo session. +https://github.com/SpaceVim/SpaceVim/issues/1660 +https://github.com/Shougo/dein.vim/issues/274 + +A: +It is intended behavior for security reason. +In sudo session, installed plugin can do anything in root permission. +It is very dangerous. +But you can load trusted plugins using |dein-options-trusted|. + +Q: I want to uninstall dein.vim. + +A: Please remove |dein#begin()|'s argument directory. +For example, if you use below configuration: > + call dein#begin('~/.cache/dein') +Please remove "~/.cache/dein" directory. + +Q: I want to update dein.vim from shell command line. + +A: Please execute the command line like this. > + vim -N -u ~/.vim/init.vim -c \ + "try | call dein#update() | finally | qall! | endtry" -V1 -es + +Q: I want to set build conditions. + +A: Please use |dein-options-hook_post_update|. > + + [[plugins]] + repo = 'autozimu/LanguageClient-neovim' + hook_post_update = ''' + if has('win32') || has('win64') + call system( + \ 'powershell -executionpolicy bypass -File install.ps1') + else + call system('bash install.sh') + endif + ''' + +Q: Why I need to call |dein#recache_runtimepath()| manually after removing +plugins? +https://github.com/Shougo/dein.vim/issues/357 + +A: You can use |g:dein#auto_recache| option instead. +Dein.vim has merge feature. It copys the plugins into the merge directory. +You can disable the feature by |dein-options-merged|. It is like other plugin +managers behavior. +Why dein.vim has the feature? It is for loading performance. +Other plugin manager adds 'runtimepath' to load external plugins. +But if 'runtimepath' is very big, plugin loading is slower. Because Vim needs +to search all huge 'runtimepath' to load it. Dein.vim has not the problem. + +============================================================================== +COMPATIBILITY *dein-compatibility* + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen: diff --git a/bundle/dein.vim/rplugin/python3/denite/source/dein.py b/bundle/dein.vim/rplugin/python3/denite/source/dein.py new file mode 100644 index 000000000..132c97e5b --- /dev/null +++ b/bundle/dein.vim/rplugin/python3/denite/source/dein.py @@ -0,0 +1,56 @@ +# ============================================================================ +# FILE: dein.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from .base import Base +import re +import os + + +URL_PATTERN = re.compile('^(https?|git)://(github.com/)?') +REF_PATTERN = re.compile('^ref: (refs/heads/(.*))$') + + +class Source(Base): + + def __init__(self, vim): + Base.__init__(self, vim) + + self.name = 'dein' + self.kind = 'directory' + self.default_action = 'cd' + + def gather_candidates(self, context): + return [ + _build_candidate(plugin_context) + for plugin_context in self.vim.eval('values(dein#get())') + ] + + +def _build_candidate(plugin_context): + name = URL_PATTERN.sub('', plugin_context['repo']) + path = plugin_context['path'] + # Find git revision + try: + revision, branch = _resolve_ref(os.path.join(path, '.git'), 'HEAD') + except Exception: + # Fail silently + revision = '' + branch = None + rev = revision if branch is None else '%s (%s)' % (branch, revision[:7]) + return { + 'word': name.strip(), + 'abbr': name.strip() if not rev else '%s -- %s' % (name.strip(), rev.strip()), + 'action__path': path, + } + + +def _resolve_ref(git, ref, branch=None): + with open(os.path.join(git, ref)) as fi: + content = fi.readline() + m = REF_PATTERN.match(content) + if not m: + return (content, branch) + return _resolve_ref(git, m.group(1), m.group(2)) diff --git a/bundle/dein.vim/rplugin/python3/denite/source/dein_log.py b/bundle/dein.vim/rplugin/python3/denite/source/dein_log.py new file mode 100644 index 000000000..bb3dc9b73 --- /dev/null +++ b/bundle/dein.vim/rplugin/python3/denite/source/dein_log.py @@ -0,0 +1,60 @@ +# ============================================================================ +# FILE: dein_log.py +# AUTHOR: delphinus +# License: MIT license +# ============================================================================ + +import re +from .base import Base + +HEADER_RE = re.compile(r'^\s*[a-zA-Z_]\w*://') +SPACE_RE = re.compile(r'^\s+') +DEIN_LOG_SYNTAX_HIGHLIGHT = [ + {'name': 'Progress', 're': r'\[[ =]\+\]', 'link': 'String'}, + {'name': 'Source', 're': r'|.\{-}|', 'link': 'Type'}, + {'name': 'URI', 're': r'-> diff URI', 'link': 'Underlined'}, + ] + + +class Source(Base): + + def __init__(self, vim): + super().__init__(vim) + + self.name = 'dein/log' + + def on_init(self, context): + context['__source_log'] = [] + + def gather_candidates(self, context): + dein_context = self.vim.call('dein#install#_get_context') + context['is_async'] = bool(dein_context) + if context['args'] and context['args'][0] == '!': + log_func = 'dein#install#_get_updates_log' + else: + log_func = 'dein#install#_get_log' + logs = self.vim.call(log_func) + + def make_candidates(row): + return { + 'word': ' -> diff URI', + 'kind': 'file', + 'action__path': SPACE_RE.sub('', row), + } if HEADER_RE.match(row) else {'word': row, 'kind': 'word'} + + rows = len(context['__source_log']) + candidates = list(map(make_candidates, logs[rows:])) + context['__source_log'] = logs + + # Needs wait to call Vim output handlers + self.vim.command('sleep 100m') + return candidates + + def highlight(self): + for syn in DEIN_LOG_SYNTAX_HIGHLIGHT: + self.vim.command( + 'syntax match {0}_{1} /{2}/ contained containedin={0}' + .format(self.syntax_name, syn['name'], syn['re'])) + self.vim.command( + 'highlight default link {0}_{1} {2}' + .format(self.syntax_name, syn['name'], syn['link'])) diff --git a/bundle/dein.vim/test/base.vim b/bundle/dein.vim/test/base.vim new file mode 100644 index 000000000..6042dc22c --- /dev/null +++ b/bundle/dein.vim/test/base.vim @@ -0,0 +1,75 @@ +" set verbose=1 + +let s:suite = themis#suite('base') +let s:assert = themis#helper('assert') + +let s:path = tempname() + +function! s:suite.before_each() abort + call dein#_init() +endfunction + +function! s:suite.block_normal() abort + call s:assert.equals(dein#begin(s:path), 0) + call s:assert.equals(dein#end(), 0) + + call s:assert.equals(dein#begin(s:path), 0) + call s:assert.equals(dein#end(), 0) +endfunction + +function! s:suite.begin_invalid() abort + call s:assert.equals(dein#begin(s:path), 0) + call s:assert.equals(dein#begin(s:path), 1) + + call dein#_init() + call s:assert.equals(dein#end(), 1) + + call s:assert.equals(dein#end(), 1) + + call s:assert.equals(dein#begin(getcwd() . '/plugin'), 1) +endfunction + +function! s:suite.end_invalid() abort + call s:assert.equals(dein#end(), 1) +endfunction + +function! s:suite.add_normal() abort + call s:assert.equals(dein#begin(s:path), 0) + + call dein#add('foo', {}) + call s:assert.equals(g:dein#_plugins.foo.name, 'foo') + call dein#add('bar') + call s:assert.equals(g:dein#_plugins.bar.name, 'bar') + + call s:assert.equals(dein#end(), 0) +endfunction + +function! s:suite.add_overwrite() abort + call s:assert.equals(dein#begin(s:path), 0) + + call dein#add('foo', {}) + call s:assert.equals(g:dein#_plugins.foo.sourced, 0) + + call dein#add('foo', { 'sourced': 1 }) + call s:assert.equals(g:dein#_plugins.foo.sourced, 1) + + call s:assert.equals(dein#end(), 0) +endfunction + +function! s:suite.get() abort + let plugins = { 'foo': {'name': 'bar'} } + + call dein#begin(s:path) + call dein#add('foo', { 'name': 'bar' }) + call s:assert.equals(dein#get('bar').name, 'bar') + call dein#add('foo') + call s:assert.equals(dein#get('foo').name, 'foo') + call dein#end() +endfunction + +function! s:suite.expand() abort + call s:assert.equals(dein#util#_expand('~'), + \ dein#util#_substitute_path(fnamemodify('~', ':p'))) + call s:assert.equals(dein#util#_expand('$HOME'), + \ dein#util#_substitute_path($HOME)) +endfunction diff --git a/bundle/dein.vim/test/git.vim b/bundle/dein.vim/test/git.vim new file mode 100644 index 000000000..b46d4aae1 --- /dev/null +++ b/bundle/dein.vim/test/git.vim @@ -0,0 +1,87 @@ +let s:suite = themis#suite('git') +let s:assert = themis#helper('assert') + +let s:type = dein#types#git#define() +let s:path = tempname() +let s:base = s:path . '/repos/' + +function! s:suite.protocol() abort + call dein#begin(s:path) + " Protocol errors + call s:assert.equals(s:type.init( + \ 'http://github.com/Shougo/dein.vim', {}), + \ {}) + + call s:assert.equals(s:type.init( + \ 'foo://github.com/Shougo/dein.vim', {}), + \ {}) + + call s:assert.equals(s:type.init( + \ 'https://github.com/vim/vim/archive/master.zip', {}), + \ {}) + + call s:assert.equals(s:type.init( + \ 'test.zip', {}), + \ {}) + call dein#end() +endfunction + +function! s:suite.init() abort + call dein#begin(s:path) + call s:assert.equals(s:type.init( + \ 'https://github.com/Shougo/dein.vim', {}), + \ { 'type': 'git', + \ 'path': s:base.'github.com/Shougo/dein.vim' }) + call s:assert.equals(s:type.get_uri( + \ 'https://github.com/Shougo/dein.vim', {}), + \ 'https://github.com/Shougo/dein.vim') + call s:assert.equals(s:type.init( + \ 'Shougo/dein.vim', {}), + \ { 'type': 'git', + \ 'path': s:base.'github.com/Shougo/dein.vim' }) + call s:assert.equals(s:type.get_uri( + \ 'Shougo/dein.vim', {}), + \ 'https://github.com/Shougo/dein.vim') + call s:assert.equals(s:type.init( + \ 'https://github.com:80/Shougo/dein.vim', {}), + \ { 'type': 'git', + \ 'path': s:base.'github.com/Shougo/dein.vim' }) + call s:assert.equals(s:type.get_uri( + \ 'https://github.com:80/Shougo/dein.vim', {}), + \ 'https://github.com/Shougo/dein.vim') + + call s:assert.equals(s:type.init('L9', {}), {}) + + call s:assert.equals(s:type.init( + \ 'https://bitbucket.org/mortonfox/twitvim.git', {}), + \ { 'type': 'git', + \ 'path': s:base.'bitbucket.org/mortonfox/twitvim' }) + call s:assert.equals(s:type.get_uri( + \ 'https://bitbucket.org/mortonfox/twitvim.git', {}), + \ 'https://bitbucket.org/mortonfox/twitvim.git') + call s:assert.equals(s:type.init( + \ 'https://git.code.sf.net/p/atp-vim/code', {'type': 'git'}), + \ { 'type': 'git', + \ 'path': s:base.'git.code.sf.net/p/atp-vim/code' }) + call s:assert.equals(s:type.get_uri( + \ 'https://git.code.sf.net/p/atp-vim/code', {'type': 'git'}), + \ 'https://git.code.sf.net/p/atp-vim/code') + + call s:assert.equals(s:type.get_uri( + \ 'git@bitbucket.com:vim/snippets', {}), + \ 'git@bitbucket.com:vim/snippets') + call s:assert.equals(s:type.get_uri( + \ 'ssh://git.company.com/gitroot/devtools/vim-company.git', {}), + \ 'ssh://git.company.com/gitroot/devtools/vim-company.git') + + let g:dein#types#git#default_protocol = 'ssh' + + call s:assert.equals(s:type.init('Shougo/dein.vim', {}), + \ { 'type': 'git', + \ 'path': s:base.'github.com/Shougo/dein.vim' }) + call s:assert.equals(s:type.get_uri('Shougo/dein.vim', {}), + \ 'git@github.com:Shougo/dein.vim') + + let g:dein#types#git#default_protocol = 'https' + call dein#end() +endfunction diff --git a/bundle/dein.vim/test/install.vim b/bundle/dein.vim/test/install.vim new file mode 100644 index 000000000..e937ace3c --- /dev/null +++ b/bundle/dein.vim/test/install.vim @@ -0,0 +1,776 @@ +" set verbose=1 + +let s:suite = themis#suite('install') +let s:assert = themis#helper('assert') + +let s:path = fnamemodify('.cache', ':p') +if s:path !~ '/$' + let s:path .= '/' +endif +let s:runtimepath_save = &runtimepath +let s:filetype_save = &l:filetype + +let s:this_script = fnamemodify(expand(''), ':p') + + +let s:merged_format = "{'repo': v:val.repo, 'rev': get(v:val, 'rev', '')}" + +function! s:dein_install() abort + call dein#util#_save_merged_plugins() + return dein#install#_update([], 'install', 0) +endfunction + +function! s:dein_update() abort + return dein#install#_update([], 'update', 0) +endfunction + +function! s:dein_check_update() abort + return dein#install#_update([], 'check_update', 0) +endfunction + +function! s:suite.before_each() abort + call dein#_init() + let &runtimepath = s:runtimepath_save + let &l:filetype = s:filetype_save + let g:temp = tempname() + let g:dein#install_progress_type = 'echo' + let g:dein#enable_notification = 0 +endfunction + +function! s:suite.install() abort + let g:dein#install_progress_type = 'title' + let g:dein#enable_notification = 1 + + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim') + call dein#add('Shougo/deol.nvim') + call dein#add('Shougo/neosnippet.vim') + call dein#add('Shougo/neopairs.vim') + call dein#add('Shougo/defx.nvim') + call dein#add('Shougo/denite.nvim') + + call dein#end() + + call s:assert.equals(s:dein_install(), 0) + + let plugin = dein#get('deoplete.nvim') + call s:assert.true(isdirectory(plugin.rtp)) + call s:assert.equals(dein#each('git gc'), 0) + + call s:assert.equals(dein#util#_get_merged_plugins(), + \ dein#util#_load_merged_plugins()) +endfunction + +function! s:suite.tap() abort + call dein#begin(s:path) + call s:assert.equals(dein#tap('deoplete.nvim'), 0) + call dein#add('Shougo/deoplete.nvim') + call dein#add('Shougo/denite.nvim', {'if': 0}) + call s:assert.equals(s:dein_install(), 0) + call s:assert.equals(dein#tap('deoplete.nvim'), 1) + call s:assert.equals(dein#tap('denite.nvim'), 0) + call dein#end() +endfunction + +function! s:suite.reinstall() abort + let g:dein#install_progress_type = 'none' + + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim') + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + call s:assert.equals(dein#reinstall('deoplete.nvim'), 0) +endfunction + +function! s:suite.direct_install() abort + let g:dein#install_progress_type = 'none' + call dein#begin(s:path) + call dein#end() + + call s:assert.equals(dein#direct_install('Shougo/deoplete.nvim'), 0) + call s:assert.equals(dein#get('deoplete.nvim').sourced, 1) +endfunction + +function! s:suite.update() abort + let g:dein#install_progress_type = 'echo' + + call dein#begin(s:path) + + call dein#add('Shougo/neopairs.vim', {'frozen': 1}) + + call s:assert.equals(s:dein_update(), 0) + + let plugin = dein#get('neopairs.vim') + let plugin2 = dein#get('neobundle.vim') + + call s:assert.equals(plugin.rtp, + \ s:path.'repos/github.com/Shougo/neopairs.vim') + + call s:assert.true(isdirectory(plugin.rtp)) + + call dein#end() +endfunction + +function! s:suite.check_install() abort + let g:dein#install_progress_type = 'tabline' + + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim') + + call s:assert.equals(s:dein_install(), 0) + + call s:assert.false(dein#check_install()) + call s:assert.equals(dein#check_install(['hoge']), -1) + + call dein#end() +endfunction + +function! s:suite.fetch() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', { 'rtp': '' }) + + call s:assert.equals(s:dein_install(), 0) + + let plugin = dein#get('deoplete.nvim') + + call s:assert.equals(plugin.rtp, '') + + call dein#end() + + call s:assert.equals(plugin.sourced, 0) +endfunction + +function! s:suite.reload() abort + " 1st load + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim') + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + " 2nd load + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim') + + call dein#end() + + let plugin = dein#get('deoplete.nvim') +endfunction + +function! s:suite.if() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', {'if': 0, 'on_cmd': 'FooBar'}) + + call s:assert.equals(dein#get('deoplete.nvim'), {}) + call s:assert.false(exists(':FooBar')) + + call dein#end() + + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', {'if': '1+1'}) + + call s:assert.equals(dein#get('deoplete.nvim').if, 2) + + call dein#end() +endfunction + +function! s:suite.lazy_manual() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', { 'lazy': 1 }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('deoplete.nvim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + call s:assert.equals(dein#source(['deoplete.nvim']), 0) + + call s:assert.equals(plugin.sourced, 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.lazy_on_i() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', { 'on_i': 1 }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + call s:assert.equals(g:dein#_event_plugins, + \ {'InsertEnter': ['deoplete.nvim']}) +endfunction + +function! s:suite.lazy_on_ft() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', { 'on_ft': 'cpp' }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('deoplete.nvim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + set filetype=c + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + set filetype=cpp + + call s:assert.equals(plugin.sourced, 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.lazy_on_path() abort + call dein#begin(s:path) + + call dein#add('Shougo/deol.nvim', { 'on_path': '.*' }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('deol.nvim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + execute 'edit' tempname() + + call s:assert.equals(plugin.sourced, 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.lazy_on_if() abort + call dein#begin(s:path) + + let temp = tempname() + call dein#add('Shougo/deol.nvim', + \ { 'on_if': '&filetype ==# "foobar"' }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('deol.nvim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + set filetype=foobar + + call s:assert.equals(plugin.lazy, 1) + call s:assert.equals(plugin.sourced, 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.lazy_on_source() abort + call dein#begin(s:path) + + call dein#add('Shougo/neopairs.vim', + \ { 'on_source': ['deol.nvim'] }) + call dein#add('Shougo/deol.nvim', { 'lazy': 1 }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('neopairs.vim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + call dein#source('deol.nvim') + + call s:assert.equals(plugin.sourced, 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.lazy_on_func() abort + call dein#begin(s:path) + + call dein#add('Shougo/neosnippet.vim', { 'lazy': 1 }) + call dein#add('Shougo/deoplete.nvim', + \ { 'on_func': 'deoplete#initialize' }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('deoplete.nvim') + let plugin2 = dein#get('neosnippet.vim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin2.rtp')), 0) + + call dein#autoload#_on_func('deoplete#initialize') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin2.rtp')), 0) + + call neosnippet#expandable() + + call s:assert.equals(plugin.sourced, 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin2.rtp')), 1) +endfunction + +function! s:suite.lazy_on_cmd() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', + \ { 'on_cmd': 'NeoCompleteDisable' }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('deoplete.nvim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + NeoCompleteDisable + + call s:assert.equals(plugin.sourced, 1) +endfunction + +function! s:suite.lazy_on_map() abort + call dein#begin(s:path) + + call dein#add('Shougo/deol.nvim', { 'on_map': {'n': ''} }) + call dein#add('Shougo/neosnippet.vim', { 'on_map': {'n': ''} }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin1 = dein#get('deol.nvim') + let plugin2 = dein#get('neosnippet.vim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin1.rtp')), 0) + + call dein#autoload#_on_map('', 'deol.nvim', 'n') + call dein#autoload#_on_map('', 'neosnippet.vim', 'n') + + call s:assert.equals(plugin1.sourced, 1) + call s:assert.equals(plugin2.sourced, 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin1.rtp')), 1) +endfunction + +function! s:suite.lazy_on_pre_cmd() abort + call dein#begin(s:path) + + call dein#add('Shougo/deol.nvim', { 'lazy': 1 }) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('deol.nvim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + call dein#autoload#_on_pre_cmd('Deol') + + call s:assert.equals(plugin.sourced, 1) + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.lazy_on_idle() abort + call dein#begin(s:path) + + call dein#add('Shougo/defx.nvim', { 'on_idle': 1}) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + call s:assert.equals(g:dein#_event_plugins, + \ {'CursorHold': ['defx.nvim'], 'FocusLost': ['defx.nvim']}) + + let plugin = dein#get('defx.nvim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + doautocmd CursorHold + + call s:assert.equals(plugin.sourced, 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.depends() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', { 'depends': 'deol.nvim' }) + call dein#add('Shougo/deol.nvim', {'merged': 0}) + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + let plugin = dein#get('deol.nvim') + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.depends_lazy() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', + \ { 'depends': 'deol.nvim', 'lazy': 1 }) + call dein#add('Shougo/deol.nvim', { 'lazy': 1 }) + + let plugin = dein#get('deol.nvim') + + call s:assert.equals(s:dein_install(), 0) + + call dein#end() + + call s:assert.equals(plugin.sourced, 0) + call s:assert.equals(isdirectory(plugin.rtp), 1) + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 0) + + call s:assert.equals(dein#source(['deoplete.nvim']), 0) + + call s:assert.equals(plugin.sourced, 1) + + call s:assert.equals( + \ len(filter(dein#util#_split_rtp(&runtimepath), + \ 'v:val ==# plugin.rtp')), 1) +endfunction + +function! s:suite.depends_error_lazy() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim', + \ { 'depends': 'defx.nvim' }) + + call s:assert.equals(s:dein_install(), 0) + + call s:assert.equals(dein#end(), 0) + + call s:assert.equals(dein#source(['deoplete.nvim']), 0) + + call dein#begin(s:path) + + call dein#add('Shougo/defx.nvim', { 'lazy': 1 }) + call dein#add('Shougo/deoplete.nvim', + \ { 'depends': 'defx.nvim' }) + + call s:assert.equals(s:dein_install(), 0) + + call s:assert.equals(dein#end(), 0) + + call s:assert.equals(dein#source(['deoplete.nvim']), 0) +endfunction + +function! s:suite.hooks() abort + call dein#begin(s:path) + + let g:dein#_hook_add = 'let g:foo = 0' + + function! Foo() abort + endfunction + call dein#add('Shougo/deoplete.nvim', { + \ 'hook_source': + \ join(['let g:foobar = 2'], "\n"), + \ 'hook_post_source': + \ join(['if 1', 'let g:bar = 3', 'endif'], "\n"), + \ }) + call dein#add('Shougo/neosnippet.vim', { + \ 'hook_add': function('Foo'), + \ 'hook_post_source': function('Foo'), + \ }) + call dein#set_hook('neosnippet.vim', 'hook_source', function('Foo')) + call dein#set_hook(['deoplete.nvim'], 'hook_add', 'let g:foobar = 1') + call dein#set_hook([], 'hook_add', 'let g:baz = 3') + + call s:assert.equals(g:foobar, 1) + + call s:assert.equals(s:dein_install(), 0) + + call s:assert.equals(dein#end(), 0) + call s:assert.equals(g:foo, 0) + + call dein#call_hook('source') + call s:assert.equals(g:foobar, 2) + call dein#call_hook('post_source') + call s:assert.equals(g:bar, 3) + call s:assert.equals(g:baz, 3) +endfunction + +function! s:suite.no_toml() abort + call dein#begin(s:path) + + call writefile([ + \ 'foobar' + \ ], g:temp) + call s:assert.equals(dein#load_toml(g:temp, {}), 1) + + call s:assert.equals(dein#end(), 0) +endfunction + +function! s:suite.no_plugins() abort + call dein#begin(s:path) + + call writefile([], g:temp) + call s:assert.equals(dein#load_toml(g:temp), 0) + + call s:assert.equals(dein#end(), 0) +endfunction + +function! s:suite.no_repository() abort + call dein#begin(s:path) + + call writefile([ + \ "[[plugins]]", + \ "filetypes = 'all'", + \ "[[plugins]]", + \ "filetypes = 'all'" + \ ], g:temp) + call s:assert.equals(dein#load_toml(g:temp), 1) + + call s:assert.equals(dein#end(), 0) +endfunction + +function! s:suite.normal() abort + call dein#begin(s:path) + + call writefile([ + \ "[[plugins]]", + \ "repo = 'Shougo/deoplete.nvim'", + \ "on_ft = 'all'", + \ ], g:temp) + call s:assert.equals(dein#load_toml(g:temp, {'frozen': 1}), 0) + + let plugin = dein#get('deoplete.nvim') + call s:assert.equals(plugin.frozen, 1) + call s:assert.equals(plugin.on_ft, ['all']) + + call s:assert.equals(dein#end(), 0) +endfunction + +function! s:suite.local() abort + call dein#begin(s:path) + + call dein#add('Shougo/neopairs.vim', {'frozen': 1}) + call dein#local(s:path.'repos/github.com/Shougo/', {'timeout': 1}) + + call s:assert.equals(dein#get('neopairs.vim').sourced, 0) + call s:assert.equals(dein#get('neopairs.vim').timeout, 1) + + call s:assert.equals(dein#end(), 0) + + let plugin2 = dein#get('neopairs.vim') + + call s:assert.equals(plugin2.rtp, + \ s:path.'repos/github.com/Shougo/neopairs.vim') +endfunction + +function! s:suite.clean() abort + call dein#begin(s:path) + + call s:assert.equals(dein#end(), 0) + + call s:assert.true(!empty(dein#check_clean())) +endfunction + +function! s:suite.local_nongit() abort + let temp = tempname() + call mkdir(temp.'/plugin', 'p') + call dein#begin(s:path) + + call dein#local(temp, {}, ['plugin']) + + call s:assert.equals(dein#end(), 0) + + call s:assert.equals(dein#get('plugin').type, 'none') + + call s:assert.equals(s:dein_update(), 0) +endfunction + +function! s:suite.build() abort + call dein#begin(tempname()) + + call dein#add('Shougo/vimproc.vim', { + \ 'build': 'make', + \ 'hook_add': + \ 'let g:foobar = 1', + \ 'hook_post_update': + \ 'let g:foobar = 4', + \ }) + + call dein#end() + + call s:assert.equals(g:foobar, 1) + + call s:assert.true(dein#check_install()) + call s:assert.true(dein#check_install(['vimproc.vim'])) + + call s:assert.equals(s:dein_install(), 0) + call s:assert.equals(s:dein_check_update(), 0) + + call s:assert.equals(g:foobar, 4) + + call vimproc#version() + call s:assert.true(filereadable(g:vimproc#dll_path)) +endfunction + +function! s:suite.rollback() abort + call dein#begin(tempname()) + + call dein#add('Shougo/deoplete.nvim') + + call dein#end() + + call s:assert.equals(s:dein_install(), 0) + + let plugin = dein#get('deoplete.nvim') + + let old_rev = s:get_revision(plugin) + + " Change the revision manually + let new_rev = 'bc7e8124d9c412fb3b0a6112baabde75a854d7b5' + let cwd = getcwd() + try + call dein#install#_cd(plugin.path) + call system('git reset --hard ' . new_rev) + finally + call dein#install#_cd(cwd) + endtry + + call s:assert.equals(s:get_revision(plugin), new_rev) + + call dein#rollback('', ['deoplete.nvim']) + + call s:assert.equals(s:get_revision(plugin), old_rev) +endfunction + +function! s:suite.script_type() abort + call dein#begin(s:path) + + call dein#add( + \ 'https://github.com/bronzehedwick/impactjs-colorscheme', + \ {'script_type' : 'colors'}) + + call dein#add( + \ 'https://raw.githubusercontent.com/Shougo/' + \ . 'shougo-s-github/master/vim/colors/candy.vim', + \ {'script_type' : 'colors'}) + call s:assert.equals(dein#get('candy.vim').type, 'raw') + + call s:assert.equals(dein#end(), 0) + + call s:assert.equals(s:dein_update(), 0) + + call s:assert.true(filereadable( + \ dein#get('impactjs-colorscheme').rtp . '/colors/impactjs.vim')) + call s:assert.true(filereadable( + \ dein#get('candy.vim').rtp . '/colors/candy.vim')) +endfunction + +function! s:get_revision(plugin) abort + let cwd = getcwd() + try + execute 'lcd' fnameescape(a:plugin.path) + + let rev = substitute(system('git rev-parse HEAD'), '\n$', '', '') + + return (rev !~ '\s') ? rev : '' + finally + execute 'lcd' fnameescape(cwd) + endtry +endfunction + +function! s:suite.ftplugin() abort + call dein#begin(tempname()) + + let g:dein#_ftplugin = { + \ '_': 'echo 5555', + \ 'python': 'setlocal foldmethod=indent', + \ } + + call dein#add('Shougo/echodoc.vim') + call dein#end() + + call dein#recache_runtimepath() + + call s:assert.equals( + \ readfile(dein#util#_get_runtime_path() . '/ftplugin.vim'), + \ dein#install#_get_default_ftplugin() + [ + \ 'function! s:after_ftplugin()', + \ ] + split(get(g:dein#_ftplugin, '_', []), '\n') + ['endfunction']) + + let python = readfile(dein#util#_get_runtime_path() + \ . '/after/ftplugin/python.vim') + call s:assert.equals(python[-1], g:dein#_ftplugin['python']) + call s:assert.false(filereadable(dein#util#_get_runtime_path() + \ . '/after/ftplugin/_.vim')) +endfunction diff --git a/bundle/dein.vim/test/install_base.vim b/bundle/dein.vim/test/install_base.vim new file mode 100644 index 000000000..9b36b339b --- /dev/null +++ b/bundle/dein.vim/test/install_base.vim @@ -0,0 +1,46 @@ +" set verbose=1 + +let s:suite = themis#suite('install_base') +let s:assert = themis#helper('assert') + +function! s:suite.rm() abort + let temp = tempname() + call writefile([], temp) + + call dein#install#_rm(temp) + + call s:assert.equals(filereadable(temp), 0) +endfunction + +function! s:suite.copy_directories() abort + let temp = tempname() + let temp2 = tempname() + let temp3 = tempname() + + call mkdir(temp) + call mkdir(temp2) + call mkdir(temp3) + call writefile([], temp.'/foo') + call writefile([], temp3.'/bar') + call s:assert.true(filereadable(temp.'/foo')) + call s:assert.true(filereadable(temp3.'/bar')) + + call dein#install#_copy_directories([temp, temp3], temp2) + + call s:assert.true(isdirectory(temp2)) + call s:assert.true(filereadable(temp2.'/foo')) + call s:assert.true(filereadable(temp2.'/bar')) +endfunction + +function! s:suite.args2string() abort + call s:assert.equals( + \ dein#install#_args2string_unix(['foo', 'bar']), "'foo' 'bar'") + call s:assert.equals( + \ dein#install#_args2string_windows([]), '') + call s:assert.equals( + \ dein#install#_args2string_windows(['foo']), 'foo') + call s:assert.equals( + \ dein#install#_args2string_windows(['foo', 'bar']), 'foo "bar"') + call s:assert.equals( + \ dein#install#_args2string_windows(['fo o', 'bar']), '"fo o" "bar"') +endfunction diff --git a/bundle/dein.vim/test/parse.vim b/bundle/dein.vim/test/parse.vim new file mode 100644 index 000000000..31cef1cba --- /dev/null +++ b/bundle/dein.vim/test/parse.vim @@ -0,0 +1,205 @@ +" set verbose=1 + +let s:suite = themis#suite('parse') +let s:assert = themis#helper('assert') + +let s:path = tempname() + +function! s:suite.before_each() abort + call dein#_init() +endfunction + +function! s:suite.after_each() abort +endfunction + +function! s:suite.parse_dict() abort + call dein#begin(s:path) + + let plugin = {'name': 'baz'} + let parsed_plugin = dein#parse#_dict(dein#parse#_init('', plugin)) + call s:assert.equals(parsed_plugin.name, 'baz') + + let plugin = {'name': 'baz', 'if': '1'} + let parsed_plugin = dein#parse#_dict(dein#parse#_init('', plugin)) + call s:assert.equals(parsed_plugin.merged, 0) + + let plugin = {'name': 'baz', 'rev': 'foo'} + let parsed_plugin = dein#parse#_dict(dein#parse#_init('foo', plugin)) + call s:assert.equals(parsed_plugin.path, '_foo') + + let plugin = {'name': 'baz', 'rev': 'foo/bar'} + let parsed_plugin = dein#parse#_dict(dein#parse#_init('foo', plugin)) + call s:assert.equals(parsed_plugin.path, '_foo_bar') + + let $BAZDIR = '/baz' + let repo = '$BAZDIR/foo' + let plugin = {'repo': repo} + let parsed_plugin = dein#parse#_dict(dein#parse#_init(repo, plugin)) + call s:assert.equals(parsed_plugin.repo, '/baz/foo') + + call dein#end() +endfunction + +function! s:suite.name_conversion() abort + let g:dein#enable_name_conversion = 1 + + let plugin = dein#parse#_dict( + \ {'repo': 'https://github.com/Shougo/dein.vim.git'}) + call s:assert.equals(plugin.name, 'dein') + + let plugin = dein#parse#_dict( + \ {'repo': 'https://bitbucket.org/kh3phr3n/vim-qt-syntax.git'}) + call s:assert.equals(plugin.name, 'qt-syntax') + + let plugin = dein#parse#_dict( + \ {'repo': 'https://bitbucket.org/kh3phr3n/qt-syntax-vim.git'}) + call s:assert.equals(plugin.name, 'qt-syntax') + + let plugin = dein#parse#_dict( + \ {'repo': 'https://bitbucket.org/kh3phr3n/vim-qt-syntax.git', + \ 'name': 'vim-qt-syntax'}) + call s:assert.equals(plugin.name, 'vim-qt-syntax') + + let g:dein#enable_name_conversion = 0 +endfunction + +function! s:suite.load_toml() abort + let toml = tempname() + call writefile([ + \ '# TOML sample', + \ 'hook_add = "let g:foo = 0"', + \ '', + \ '[ftplugin]', + \ 'c = "let g:bar = 0"', + \ '', + \ '[[plugins]]', + \ '# repository name is required.', + \ "repo = 'Shougo/denite.nvim'", + \ "on_map = ''", + \ '[[plugins]]', + \ "repo = 'Shougo/neosnippet.vim'", + \ 'on_i = 1', + \ "on_ft = 'snippet'", + \ "hook_add = '''", + \ '"echo', + \ '"comment', + \ "echo", + \ "'''", + \ "hook_source = '''", + \ "echo", + \ '\', + \ "echo", + \ "'''", + \ '[plugins.ftplugin]', + \ 'c = "let g:bar = 0"', + \ ], toml) + + call dein#begin(s:path) + call s:assert.equals(g:dein#_hook_add, '') + call s:assert.equals(g:dein#_ftplugin, {}) + call s:assert.equals(dein#load_toml(toml), 0) + call s:assert.equals(g:dein#_hook_add, "\nlet g:foo = 0") + call s:assert.equals(g:dein#_ftplugin, + \ {'c': "let g:bar = 0\nlet g:bar = 0"}) + call dein#end() + + call s:assert.equals(dein#get('neosnippet.vim').on_i, 1) + call s:assert.equals(dein#get('neosnippet.vim').hook_add, + \ "\necho\n") + call s:assert.equals(dein#get('neosnippet.vim').hook_source, + \ "echo\necho\n") +endfunction + +function! s:suite.error_toml() abort + let toml = tempname() + call writefile([ + \ '# TOML sample', + \ '[[plugins]]', + \ '# repository name is required.', + \ "on_map = ''", + \ '[[plugins]]', + \ 'on_i = 1', + \ "on_ft = 'snippet'", + \ ], toml) + + call dein#begin(s:path) + call s:assert.equals(dein#load_toml(toml), 1) + call dein#end() +endfunction + +function! s:suite.load_dict() abort + call dein#begin(s:path) + call s:assert.equals(dein#load_dict({ + \ 'Shougo/denite.nvim': {}, + \ 'Shougo/deoplete.nvim': {'name': 'deoplete'} + \ }, {'lazy': 1}), 0) + call dein#end() + + call s:assert.not_equals(dein#get('denite.nvim'), {}) + call s:assert.equals(dein#get('deoplete').lazy, 1) +endfunction + +function! s:suite.disable() abort + call dein#begin(s:path) + call dein#load_dict({ + \ 'Shougo/denite.nvim': {'on_cmd': 'Unite'} + \ }) + call s:assert.false(!exists(':Unite')) + call dein#disable('denite.nvim') + call s:assert.false(exists(':Unite')) + call dein#end() + + call s:assert.equals(dein#get('denite.nvim'), {}) +endfunction + +function! s:suite.config() abort + call dein#begin(s:path) + call dein#load_dict({ + \ 'Shougo/denite.nvim': {} + \ }) + let g:dein#name = 'denite.nvim' + call dein#config({'on_i': 1}) + call dein#end() + call dein#config('unite', {'on_i': 0}) + + call s:assert.equals(dein#get('denite.nvim').on_i, 1) +endfunction + +function! s:suite.plugins2toml() abort + let parsed_plugin = dein#parse#_init('Shougo/denite.nvim', {}) + let parsed_plugin2 = dein#parse#_init('Shougo/deoplete.nvim', + \ {'on_ft': ['vim'], 'hook_add': "hoge\npiyo"}) + let parsed_plugin3 = dein#parse#_init('Shougo/deoppet.nvim', + \ {'on_map': {'n': ['a', 'b']}}) + call s:assert.equals(dein#plugins2toml( + \ [parsed_plugin, parsed_plugin2, parsed_plugin3]), [ + \ "[[plugins]]", + \ "repo = 'Shougo/denite.nvim'", + \ "", + \ "[[plugins]]", + \ "repo = 'Shougo/deoplete.nvim'", + \ "hook_add = '''", + \ "hoge", + \ "piyo", + \ "'''", + \ "on_ft = 'vim'", + \ "", + \ "[[plugins]]", + \ "repo = 'Shougo/deoppet.nvim'", + \ "on_map = {'n': ['a', 'b']}", + \ "", + \ ]) +endfunction + +function! s:suite.trusted() abort + let sudo = g:dein#_is_sudo + let g:dein#_is_sudo = 1 + + let parsed_plugin = dein#parse#_add('Shougo/denite.nvim', {}) + call s:assert.equals(parsed_plugin.rtp, '') + + let parsed_plugin = dein#parse#_add('Shougo/denite.nvim', {'trusted': 1}) + call s:assert.not_equals(parsed_plugin.rtp, '') + + let g:dein#_is_sudo = sudo +endfunction diff --git a/bundle/dein.vim/test/raw.vim b/bundle/dein.vim/test/raw.vim new file mode 100644 index 000000000..84e0b89d1 --- /dev/null +++ b/bundle/dein.vim/test/raw.vim @@ -0,0 +1,27 @@ +" set verbose=1 +let s:suite = themis#suite('raw') +let s:assert = themis#helper('assert') + +let s:type = dein#types#raw#define() +let s:path = tempname() +let s:base = s:path . '/repos/' + +function! s:suite.protocol() abort + " Protocol errors + call s:assert.equals(s:type.init( + \ 'http://raw.githubusercontent.com/Shougo/' + \ . 'shougo-s-github/master/vim/colors/candy.vim', {}), + \ {}) +endfunction + +function! s:suite.init() abort + call dein#begin(s:path) + call s:assert.equals(s:type.init( + \ 'https://raw.githubusercontent.com/Shougo/' + \ . 'shougo-s-github/master/vim/colors/candy.vim', + \ {'script_type': 'colors'}), + \ { 'type': 'raw', 'name': 'candy.vim', + \ 'path': s:base . 'raw.githubusercontent.com/Shougo/' + \ . 'shougo-s-github/master/vim/colors' }) + call dein#end() +endfunction diff --git a/bundle/dein.vim/test/requirements.txt b/bundle/dein.vim/test/requirements.txt new file mode 100644 index 000000000..ce23018fd --- /dev/null +++ b/bundle/dein.vim/test/requirements.txt @@ -0,0 +1,5 @@ +pynvim +pytest +flake8 +mypy +vim-vint diff --git a/bundle/dein.vim/test/state.vim b/bundle/dein.vim/test/state.vim new file mode 100644 index 000000000..70110670f --- /dev/null +++ b/bundle/dein.vim/test/state.vim @@ -0,0 +1,49 @@ +" set verbose=1 + +let s:suite = themis#suite('state') +let s:assert = themis#helper('assert') + +let s:runtimepath_save = &runtimepath +let s:path = fnamemodify('.cache', ':p') . '/' +let s:filetype_save = &l:filetype + +function! s:suite.before_each() abort + call dein#_init() + let &runtimepath = s:runtimepath_save + let &l:filetype = s:filetype_save + let g:temp = tempname() + let g:dein#install_progress_type = 'echo' +endfunction + +function! s:suite.state() abort + call delete(s:path.'/state_'.g:dein#_progname.'.vim') + + call dein#begin(s:path) + + function! Test() abort + endfunction + + call dein#add('Shougo/deoplete.nvim', + \ {'hook_source': function('Test')}) + call s:assert.equals(dein#end(), 0) + + let plugins = deepcopy(g:dein#_plugins) + + call s:assert.equals(dein#util#_save_state(1), 0) + + let runtimepath = &runtimepath + + let &runtimepath = s:runtimepath_save + + " call s:assert.equals(dein#load_state(s:path, 1), 0) + + "call s:assert.equals(&runtimepath, runtimepath) + "call s:assert.equals(dein#_plugins, plugins) +endfunction + +function! s:suite.state_error() abort + call dein#begin(s:path) + + call dein#add('Shougo/deoplete.nvim') + call s:assert.equals(dein#save_state(), 1) +endfunction diff --git a/bundle/dein.vim/test/toml.vim b/bundle/dein.vim/test/toml.vim new file mode 100644 index 000000000..d961507ff --- /dev/null +++ b/bundle/dein.vim/test/toml.vim @@ -0,0 +1,39 @@ +let s:suite = themis#suite('toml') +let s:assert = themis#helper('assert') + +function! s:suite.before_each() abort + let g:temp = tempname() +endfunction + +function! s:suite.after_each() abort + call delete(g:temp) +endfunction + +function! s:suite.normal() abort + call writefile([ + \ '# This is a TOML document.', + \ '', + \ 'title = "TOML Example"', + \ 'foo = {i = ''Plug''}', + \ 'map = {i = "Plug", c = "Plug"}', + \ '', + \ '[owner]', + \ 'name = "Tom Preston-Werner"', + \ 'dob = 1979 # First class dates', + \ ], g:temp) + call s:assert.equals(dein#toml#parse_file(g:temp), { + \ 'title': 'TOML Example', + \ 'foo': {'i': 'Plug'}, + \ 'map': {'i': 'Plug', 'c': 'Plug'}, + \ 'owner': {'name': 'Tom Preston-Werner', 'dob': 1979} + \ }) + call writefile([ + \ '[[foo]]', + \ '[[foo]]', + \ '[foo.ftplugin]', + \ 'c = "let g:bar = 0"', + \ ], g:temp) + call s:assert.equals(dein#toml#parse_file(g:temp), { + \ 'foo': [{}, {'ftplugin': {'c': 'let g:bar = 0'}}] + \ }) +endfunction diff --git a/bundle/delimitMate/.gitignore b/bundle/delimitMate/.gitignore new file mode 100644 index 000000000..53c0b3756 --- /dev/null +++ b/bundle/delimitMate/.gitignore @@ -0,0 +1,12 @@ +*.sw? +*.un? +*.vba +*.vmb +*.zip +*.gz +vimball.txt +*.orig +tags +test/build +test/*.tap +test/*.msgout diff --git a/bundle/delimitMate/Makefile b/bundle/delimitMate/Makefile new file mode 100644 index 000000000..697f79dc8 --- /dev/null +++ b/bundle/delimitMate/Makefile @@ -0,0 +1,81 @@ +PLUGIN = $(wildcard plugin/*.vim) +SOURCES = $(PLUGIN) +LIB = $(wildcard autoload/*.vim) +SOURCES += $(LIB) +DOC = $(wildcard doc/*.txt) +SOURCES += $(DOC) +NAME = delimitMate +VERSION = $(shell $(SED) -n -e '/Current \+release/{s/^ \+\([0-9.]\+\).*/\1/;p;}' $(firstword $(DOC))) +FILENAME = $(NAME)-$(VERSION) +DESTDIR = $(HOME)/.vim +VIM = vim +SED = $(shell command -v gsed || command -v sed) +PERL = perl +comma := , +empty := +space := $(empty) $(empty) + +.PHONY: version clean distclean undo release test install uninstall + +all: zip gzip +dist: version all +vimball: $(FILENAME).vmb +zip: $(FILENAME).zip $(FILENAME).vmb.zip +gzip: $(FILENAME).tar.gz $(FILENAME).vmb.gz + +clean: + rm -f */*.orig *.~* .VimballRecord *.zip *.gz *.vmb + +distclean: clean + -zsh -c 'setopt extendedglob; rm -f ^(README.md|Makefile|basic_vimrc)(.)' + -zsh -c 'setopt extendedglob; rm -f .^(git|README.md|Makefile|basic_vimrc)*' + +undo: + for i in */*.orig; do mv -f "$$i" "$${i%.*}"; done + +version: + $(PERL) -i.orig -pne 'if (/^"\sVersion:/) {s/(\d+\.\S+)/$(VERSION)/}' $(PLUGIN) $(LIB) + $(PERL) -i.orig -pne \ + 'if (/let\sdelimitMate_version/) {s/"(\d+\.\S+)"/"$(VERSION)"/}' $(PLUGIN) + $(PERL) -i.orig -pne 'if (/beasts/) {s/(v\d+\.\S+)/v$(VERSION)/}' $(DOC) + $(PERL) -i.orig -MPOSIX -pne \ + 'if (/^"\sModified:/) {$$now_string = strftime "%F", localtime; s/(\d+-\d+-\d+)/$$now_string/e}' \ + $(PLUGIN) $(LIB) + $(PERL) -i.orig -MPOSIX -pne \ + 'if (/^\s+$(VERSION)\s+\d+-\d+-\d+\s+\*/) {$$now_string = strftime "%F", localtime; s/(\d+-\d+-\d+)/$$now_string/}' \ + $(DOC) + +test: + $(MAKE) -C test + +install: $(SOURCES) + for dir in $(^D);\ + do install -d -m 0755 $(DESTDIR)$(PREFIX)/$$dir;\ +done;\ +for file in $^;\ + do install -m 0644 $$file $(DESTDIR)$(PREFIX)/$$file;\ +done; + +uninstall: + for file in $(SOURCES);\ + do rm -f $(DESTDIR)$(PREFIX)/$$file;\ +done; + +%.vmb: $(SOURCES) + $(VIM) -N -es -u NORC \ + -c 'call setline(1,["$(subst $(space),"$(comma)",$^)"])'\ + -c "%MkVimball! $(basename $@) ." -c 'q!' + +%.vmb.zip: vimball + zip $@ $(basename $@) + +%.zip: $(SOURCES) + zip $@ $^ + +%.vmb.gz: vimball + gzip -f < $(basename $@) > $@ + +%.tar.gz: $(SOURCES) + tar -cvzf $@ $^ + +# vim:ts=2:sw=2 diff --git a/bundle/delimitMate/README.md b/bundle/delimitMate/README.md new file mode 100644 index 000000000..fb7b494fd --- /dev/null +++ b/bundle/delimitMate/README.md @@ -0,0 +1,6 @@ +This plug-in provides automatic closing of quotes, parenthesis, brackets, etc., besides some other related features that +should make your time in insert mode a little bit easier, like syntax awareness (will not insert the closing delimiter +in comments and other configurable regions), and expansions (off by default), and some more. + +Most of the features can be modified or disabled permanently, using global variables, or on a FileType basis, using +:autocmd. diff --git a/bundle/delimitMate/autoload/delimitMate.vim b/bundle/delimitMate/autoload/delimitMate.vim new file mode 100644 index 000000000..3d9a7209f --- /dev/null +++ b/bundle/delimitMate/autoload/delimitMate.vim @@ -0,0 +1,667 @@ +" File: autoload/delimitMate.vim +" Version: 2.7 +" Modified: 2013-07-15 +" Description: This plugin provides auto-completion for quotes, parens, etc. +" Maintainer: Israel Chauca F. +" Manual: Read ":help delimitMate". +" ============================================================================ + +"let delimitMate_loaded = 1 + +if !exists('s:options') + let s:options = {} +endif + +function! s:set(name, value, ...) "{{{ + let scope = a:0 ? a:1 : 's' + let bufnr = bufnr('%') + if !exists('s:options[bufnr]') + let s:options[bufnr] = {} + endif + if scope == 's' + let name = 's:options.' . bufnr . '.' . a:name + else + let name = scope . ':delimitMate_' . a:name + if exists('name') + exec 'unlet! ' . name + endif + endif + exec 'let ' . name . ' = a:value' +endfunction "}}} + +function! s:get(name, ...) "{{{ + if a:0 == 2 + return deepcopy(get(a:2, 'delimitMate_' . a:name, a:1)) + elseif a:0 == 1 + let bufoptions = get(s:options, bufnr('%'), {}) + return deepcopy(get(bufoptions, a:name, a:1)) + else + return deepcopy(eval('s:options.' . bufnr('%') . '.' . a:name)) + endif +endfunction "}}} + +function! s:exists(name, ...) "{{{ + let scope = a:0 ? a:1 : 's' + if scope == 's' + let bufnr = bufnr('%') + let name = 'options.' . bufnr . '.' . a:name + else + let name = 'delimitMate_' . a:name + endif + return exists(scope . ':' . name) +endfunction "}}} + +function! s:is_jump(...) "{{{ + " Returns 1 if the next character is a closing delimiter. + let char = s:get_char(0) + let list = s:get('right_delims') + s:get('quotes_list') + + " Closing delimiter on the right. + if (!a:0 && index(list, char) > -1) + \ || (a:0 && char == a:1) + return 1 + endif + + " Closing delimiter with space expansion. + let nchar = s:get_char(1) + if !a:0 && s:get('expand_space') && char == " " + if index(list, nchar) > -1 + return 2 + endif + elseif a:0 && s:get('expand_space') && nchar == a:1 && char == ' ' + return 3 + endif + + if !s:get('jump_expansion') + return 0 + endif + + " Closing delimiter with CR expansion. + let uchar = matchstr(getline(line('.') + 1), '^\s*\zs\S') + if !a:0 && s:get('expand_cr') && char == "" + if index(list, uchar) > -1 + return 4 + endif + elseif a:0 && s:get('expand_cr') && uchar == a:1 + return 5 + endif + return 0 +endfunction "}}} + +function! s:rquote(char) "{{{ + let pos = matchstr(getline('.')[col('.') : ], escape(a:char, '[]*.^$\'), 1) + let i = 0 + while s:get_char(i) ==# a:char + let i += 1 + endwhile + return i +endfunction "}}} + +function! s:lquote(char) "{{{ + let i = 0 + while s:get_char(i - 1) ==# a:char + let i -= 1 + endwhile + return i * -1 +endfunction "}}} + +function! s:get_char(...) "{{{ + let idx = col('.') - 1 + if !a:0 || (a:0 && a:1 >= 0) + " Get char from cursor. + let line = getline('.')[idx :] + let pos = a:0 ? a:1 : 0 + return matchstr(line, '^'.repeat('.', pos).'\zs.') + endif + " Get char behind cursor. + let line = getline('.')[: idx - 1] + let pos = 0 - (1 + a:1) + return matchstr(line, '.\ze'.repeat('.', pos).'$') +endfunction "s:get_char }}} + +function! s:is_cr_expansion(...) " {{{ + let nchar = getline(line('.')-1)[-1:] + let schar = matchstr(getline(line('.')+1), '^\s*\zs\S') + let isEmpty = a:0 ? getline('.') =~ '^\s*$' : empty(getline('.')) + if index(s:get('left_delims'), nchar) > -1 + \ && index(s:get('left_delims'), nchar) + \ == index(s:get('right_delims'), schar) + \ && isEmpty + return 1 + elseif index(s:get('quotes_list'), nchar) > -1 + \ && index(s:get('quotes_list'), nchar) + \ == index(s:get('quotes_list'), schar) + \ && isEmpty + return 1 + else + return 0 + endif +endfunction " }}} s:is_cr_expansion() + +function! s:is_space_expansion() " {{{ + if col('.') > 2 + let pchar = s:get_char(-2) + let nchar = s:get_char(1) + let isSpaces = + \ (s:get_char(-1) + \ == s:get_char(0) + \ && s:get_char(-1) == " ") + + if index(s:get('left_delims'), pchar) > -1 && + \ index(s:get('left_delims'), pchar) + \ == index(s:get('right_delims'), nchar) && + \ isSpaces + return 1 + elseif index(s:get('quotes_list'), pchar) > -1 && + \ index(s:get('quotes_list'), pchar) + \ == index(s:get('quotes_list'), nchar) && + \ isSpaces + return 1 + endif + endif + return 0 +endfunction " }}} IsSpaceExpansion() + +function! s:is_empty_matchpair() "{{{ + " get char before the cursor. + let open = s:get_char(-1) + let idx = index(s:get('left_delims'), open) + if idx == -1 + return 0 + endif + let close = get(s:get('right_delims'), idx, '') + return close ==# s:get_char(0) +endfunction "}}} + +function! s:is_empty_quotes() "{{{ + " get char before the cursor. + let quote = s:get_char(-1) + let idx = index(s:get('quotes_list'), quote) + if idx == -1 + return 0 + endif + return quote ==# s:get_char(0) +endfunction "}}} + +function! s:cursor_idx() "{{{ + let idx = len(split(getline('.')[: col('.') - 1], '\zs')) - 1 + return idx +endfunction "delimitMate#CursorCol }}} + +function! s:get_syn_name() "{{{ + let col = col('.') + if col == col('$') + let col = col - 1 + endif + return synIDattr(synIDtrans(synID(line('.'), col, 1)), 'name') +endfunction " }}} + +function! s:is_excluded_ft(ft) "{{{ + if !exists("g:delimitMate_excluded_ft") + return 0 + endif + return index(split(g:delimitMate_excluded_ft, ','), a:ft, 0, 1) >= 0 +endfunction "}}} + +function! s:is_forbidden(char) "{{{ + if s:is_excluded_ft(&filetype) + return 1 + endif + if !s:get('excluded_regions_enabled') + return 0 + endif + let region = s:get_syn_name() + return index(s:get('excluded_regions_list'), region) >= 0 +endfunction "}}} + +function! s:balance_matchpairs(char) "{{{ + " Returns: + " = 0 => Parens balanced. + " > 0 => More opening parens. + " < 0 => More closing parens. + + let line = getline('.') + let col = s:cursor_idx() - 1 + let col = col >= 0 ? col : 0 + let list = split(line, '\zs') + let left = s:get('left_delims')[index(s:get('right_delims'), a:char)] + let right = a:char + let opening = 0 + let closing = 0 + + " If the cursor is not at the beginning, count what's behind it. + if col > 0 + " Find the first opening paren: + let start = index(list, left) + " Must be before cursor: + let start = start < col ? start : col - 1 + " Now count from the first opening until the cursor, this will prevent + " extra closing parens from being counted. + let opening = count(list[start : col - 1], left) + let closing = count(list[start : col - 1], right) + " I don't care if there are more closing parens than opening parens. + let closing = closing > opening ? opening : closing + endif + + " Evaluate parens from the cursor to the end: + let opening += count(list[col :], left) + let closing += count(list[col :], right) + + " Return the found balance: + return opening - closing +endfunction "}}} + +function! s:is_smart_quote(char) "{{{ + " TODO: Allow using a:char in the pattern. + let tmp = s:get('smart_quotes') + if empty(tmp) + return 0 + endif + let regex = matchstr(tmp, '^!\?\zs.*') + " Flip matched value if regex starts with ! + let mod = tmp =~ '^!' ? [1, 0] : [0, 1] + let matched = search(regex, 'ncb', line('.')) > 0 + let noescaped = substitute(getline('.'), '\\.', '', 'g') + let odd = (count(split(noescaped, '\zs'), a:char) % 2) + let result = mod[matched] || odd + return result +endfunction "delimitMate#SmartQuote }}} + +function! delimitMate#Set(...) "{{{ + return call('s:set', a:000) +endfunction "}}} + +function! delimitMate#Get(...) "{{{ + return call('s:get', a:000) +endfunction "}}} + +function! delimitMate#ShouldJump(...) "{{{ + return call('s:is_jump', a:000) +endfunction "}}} + +function! delimitMate#IsEmptyPair(str) "{{{ + if strlen(substitute(a:str, ".", "x", "g")) != 2 + return 0 + endif + let idx = index(s:get('left_delims'), matchstr(a:str, '^.')) + if idx > -1 && + \ s:get('right_delims')[idx] == matchstr(a:str, '.$') + return 1 + endif + let idx = index(s:get('quotes_list'), matchstr(a:str, '^.')) + if idx > -1 && + \ s:get('quotes_list')[idx] == matchstr(a:str, '.$') + return 1 + endif + return 0 +endfunction "}}} + +function! delimitMate#WithinEmptyPair() "{{{ + " if cursor is at column 1 return 0 + if col('.') == 1 + return 0 + endif + " get char before the cursor. + let char1 = s:get_char(-1) + " get char under the cursor. + let char2 = s:get_char(0) + return delimitMate#IsEmptyPair( char1.char2 ) +endfunction "}}} + +function! delimitMate#SkipDelim(char) "{{{ + if s:is_forbidden(a:char) + return a:char + endif + let col = col('.') - 1 + let line = getline('.') + if col > 0 + let cur = s:get_char(0) + let pre = s:get_char(-1) + else + let cur = s:get_char(0) + let pre = "" + endif + if pre == "\\" + " Escaped character + return a:char + elseif cur == a:char + " Exit pair + return a:char . "\" + elseif delimitMate#IsEmptyPair( pre . a:char ) + " Add closing delimiter and jump back to the middle. + return a:char . s:joinUndo() . "\" + else + " Nothing special here, return the same character. + return a:char + endif +endfunction "}}} + +function! delimitMate#ParenDelim(right) " {{{ + let left = s:get('left_delims')[index(s:get('right_delims'),a:right)] + if s:is_forbidden(a:right) + return left + endif + " Try to balance matchpairs + if s:get('balance_matchpairs') && + \ s:balance_matchpairs(a:right) < 0 + return left + endif + let line = getline('.') + let col = col('.')-2 + if s:get('smart_matchpairs') != '' + let smart_matchpairs = substitute(s:get('smart_matchpairs'), '\\!', left, 'g') + let smart_matchpairs = substitute(smart_matchpairs, '\\#', a:right, 'g') + if line[col+1:] =~ smart_matchpairs + return left + endif + endif + if len(line) == (col + 1) && s:get('insert_eol_marker') == 1 + let tail = s:get('eol_marker') + else + let tail = '' + endif + return left . a:right . tail . repeat(s:joinUndo() . "\", len(split(tail, '\zs')) + 1) +endfunction " }}} + +function! delimitMate#QuoteDelim(char) "{{{ + if s:is_forbidden(a:char) + return a:char + endif + let char_at = s:get_char(0) + let char_before = s:get_char(-1) + let nesting_on = index(s:get('nesting_quotes'), a:char) > -1 + let left_q = nesting_on ? s:lquote(a:char) : 0 + if nesting_on && left_q > 1 + " Nesting quotes. + let right_q = s:rquote(a:char) + let quotes = right_q > left_q + 1 ? 0 : left_q - right_q + 2 + let lefts = quotes - 1 + return repeat(a:char, quotes) . repeat(s:joinUndo() . "\", lefts) + elseif char_at == a:char + " Inside an empty pair, jump out + return a:char . "\" + elseif a:char == '"' && index(split(&ft, '\.'), "vim") != -1 && getline('.') =~ '^\s*$' + " If we are in a vim file and it looks like we're starting a comment, do + " not add a closing char. + return a:char + elseif s:is_smart_quote(a:char) + " Seems like a smart quote, insert a single char. + return a:char + elseif (char_before == a:char && char_at != a:char) + \ && !empty(s:get('smart_quotes')) + " Seems like we have an unbalanced quote, insert one quotation + " mark and jump to the middle. + return a:char . s:joinUndo() . "\" + else + " Insert a pair and jump to the middle. + let sufix = '' + if !empty(s:get('eol_marker')) && col('.') - 1 == len(getline('.')) + let idx = len(s:get('eol_marker')) * -1 + let marker = getline('.')[idx : ] + let has_marker = marker == s:get('eol_marker') + let sufix = !has_marker ? s:get('eol_marker') : '' + endif + return a:char . a:char . s:joinUndo() . "\" + endif +endfunction "}}} + +function! delimitMate#JumpOut(char) "{{{ + if s:is_forbidden(a:char) + return a:char + endif + let jump = s:is_jump(a:char) + if jump == 1 + " HACK: Instead of , we remove the char to be jumped over and + " insert it again. This will trigger re-indenting via 'indentkeys'. + " Ref: https://github.com/Raimondi/delimitMate/issues/168 + return "\".a:char + elseif jump == 3 + return s:joinUndo() . "\" . s:joinUndo() . "\" + elseif jump == 5 + return "\\I" . s:joinUndo() . "\" + else + return a:char + endif +endfunction " }}} + +function! delimitMate#JumpAny(...) " {{{ + if s:is_forbidden('') + return '' + endif + if !s:is_jump() + return '' + endif + " Let's get the character on the right. + let char = s:get_char(0) + if char == " " + " Space expansion. + return s:joinUndo() . "\" . s:joinUndo() . "\" + elseif char == "" + " CR expansion. + return "\" . getline(line('.') + 1)[0] . "\\" + else + return s:joinUndo() . "\" + endif +endfunction " delimitMate#JumpAny() }}} + +function! delimitMate#JumpMany() " {{{ + let line = split(getline('.')[col('.') - 1 : ], '\zs') + let rights = "" + let found = 0 + for char in line + if index(s:get('quotes_list'), char) >= 0 || + \ index(s:get('right_delims'), char) >= 0 + let rights .= s:joinUndo() . "\" + let found = 1 + elseif found == 0 + let rights .= s:joinUndo() . "\" + else + break + endif + endfor + if found == 1 + return rights + else + return '' + endif +endfunction " delimitMate#JumpMany() }}} + +function! delimitMate#ExpandReturn() "{{{ + if s:is_forbidden("") + return "\" + endif + let escaped = s:cursor_idx() >= 2 + \ && s:get_char(-2) == '\' + let expand_right_matchpair = s:get('expand_cr') == 2 + \ && index(s:get('right_delims'), s:get_char(0)) > -1 + let expand_inside_quotes = s:get('expand_inside_quotes') + \ && s:is_empty_quotes() + \ && !escaped + let is_empty_matchpair = s:is_empty_matchpair() + if !pumvisible( ) + \ && ( is_empty_matchpair + \ || expand_right_matchpair + \ || expand_inside_quotes) + let val = "\a" + if is_empty_matchpair && s:get('insert_eol_marker') == 2 + \ && !search(escape(s:get('eol_marker'), '[]\.*^$').'$', 'cnW', '.') + let tail = getline('.')[col('.') - 1 : ] + let times = len(split(tail, '\zs')) + let val .= repeat(s:joinUndo() . "\", times) . s:get('eol_marker') . repeat(s:joinUndo() . "\", times + 1) + endif + let val .= "\" + if &smartindent && !&cindent && !&indentexpr + \ && s:get_char(0) == '}' + " indentation is controlled by 'smartindent', and the first character on + " the new line is '}'. If this were typed manually it would reindent to + " match the current line. Let's reproduce that behavior. + let shifts = indent('.') / &sw + let spaces = indent('.') - (shifts * &sw) + let val .= "^\".repeat("\", shifts).repeat(' ', spaces) + endif + " Expand: + " XXX zv prevents breaking expansion with syntax folding enabled by + " InsertLeave. + let val .= "\zvO" + return val + else + return "\" + endif +endfunction "}}} + +function! delimitMate#ExpandSpace() "{{{ + if s:is_forbidden("\") + return "\" + endif + let escaped = s:cursor_idx() >= 2 + \ && s:get_char(-2) == '\' + let expand_inside_quotes = s:get('expand_inside_quotes') + \ && s:is_empty_quotes() + \ && !escaped + if s:is_empty_matchpair() || expand_inside_quotes + " Expand: + return "\\" . s:joinUndo() . "\" + else + return "\" + endif +endfunction "}}} + +function! delimitMate#BS() " {{{ + if s:is_forbidden("") + let extra = '' + elseif &bs !~ 'start\|2' + let extra = '' + elseif delimitMate#WithinEmptyPair() + let extra = "\" + elseif s:is_space_expansion() + let extra = "\" + elseif s:is_cr_expansion() + let extra = repeat("\", + \ len(matchstr(getline(line('.') + 1), '^\s*\S'))) + else + let extra = '' + endif + return "\" . extra +endfunction " }}} delimitMate#BS() + +function! delimitMate#Test() "{{{ + %d _ + " Check for script options: + let result = [ + \ 'delimitMate Report', + \ '==================', + \ '', + \ '* Options: ( ) default, (g) global, (b) buffer', + \ ''] + for option in sort(keys(s:options[bufnr('%')])) + if s:exists(option, 'b') + let scope = '(b)' + elseif s:exists(option, 'g') + let scope = '(g)' + else + let scope = '( )' + endif + call add(result, + \ scope . ' delimitMate_' . option + \ . ' = ' + \ . string(s:get(option))) + endfor + call add(result, '') + + let option = 'delimitMate_excluded_ft' + call add(result, + \(exists('g:'.option) ? '(g) ' : '( ) g:') . option . ' = ' + \. string(get(g:, option, ''))) + + call add(result, '--------------------') + call add(result, '') + + " Check if mappings were set. + let left_delims = s:get('autoclose') ? s:get('left_delims') : [] + let special_keys = ['', '', '', 'g'] + if s:get('expand_cr') + call add(special_keys, '') + endif + if s:get('expand_space') + call add(special_keys, '') + endif + let maps = + \ s:get('right_delims') + \ + left_delims + \ + s:get('quotes_list') + \ + s:get('apostrophes_list') + \ + special_keys + + call add(result, '* Mappings:') + call add(result, '') + for map in maps + let output = '' + if map == '|' + let map = '' + endif + redir => output | execute "verbose imap ".map | redir END + call extend(result, split(output, '\n')) + endfor + + call add(result, '--------------------') + call add(result, '') + call add(result, '* Showcase:') + call add(result, '') + call setline(1, result) + call s:test_mappings(s:get('left_delims'), 1) + call s:test_mappings(s:get('quotes_list'), 0) + + let result = [] + redir => setoptions + echo " * Vim configuration:\" + filetype + echo "" + set + version + redir END + call extend(result, split(setoptions,"\n")) + call add(result, '--------------------') + setlocal nowrap + call append('$', result) + call feedkeys("\\", 'n') +endfunction "}}} + +function! s:test_mappings(list, is_matchpair) "{{{ + let prefix = "normal Go0\" + let last = "|" + let open = s:get('autoclose') ? 'Open: ' : 'Open & close: ' + for s in a:list + if a:is_matchpair + let pair = s:get('right_delims')[index(s:get('left_delims'), s)] + else + let pair = s + endif + if !s:get('autoclose') + let s .= pair + endif + exec prefix . open . s . last + exec prefix . "Delete: " . s . "\" . last + exec prefix . "Exit: " . s . pair . last + if s:get('expand_space') + \ && (a:is_matchpair || s:get('expand_inside_quotes')) + exec prefix . "Space: " . s . " " . last + exec prefix . "Delete space: " . s . " \" . last + endif + if s:get('expand_cr') + \ && (a:is_matchpair || s:get('expand_inside_quotes')) + exec prefix . "Car return: " . s . "\" . last + exec prefix . "Delete car return: " . s . "\0\\" . last + endif + call append('$', '') + endfor +endfunction "}}} + +function! s:joinUndo() "{{{ + if v:version < 704 + \ || ( v:version == 704 && !has('patch849') ) + return '' + endif + return "\U" +endfunction "}}} + +" vim:foldmethod=marker:foldcolumn=4:ts=2:sw=2 diff --git a/bundle/delimitMate/basic_vimrc b/bundle/delimitMate/basic_vimrc new file mode 100644 index 000000000..2dcf6271e --- /dev/null +++ b/bundle/delimitMate/basic_vimrc @@ -0,0 +1,4 @@ +so ./test/_setup.vim +let delimitMate_expand_cr = 1 +filetype indent plugin on + diff --git a/bundle/delimitMate/doc/delimitMate.txt b/bundle/delimitMate/doc/delimitMate.txt new file mode 100644 index 000000000..267880966 --- /dev/null +++ b/bundle/delimitMate/doc/delimitMate.txt @@ -0,0 +1,943 @@ +*delimitMate.txt* Trying to keep those beasts at bay! v2.7 *delimitMate* + + + + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM + MMMM MMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMM MMMMM MMMMMMMMMMMMMMMMMMMMM ~ + MMMM MMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMM MMM MMMMMMMMMMMMMMMMMMMMM + MMMM MMMMMMMMM MMMMMMMMMMMMMMMMMMMMM MMM M M MMMMMMMMMM MMMMMMMMM ~ + MMMM MMM MMM MM MM M M MMM MM MM MM MM MMM MMM MMM MM + MM MM M MM MMMMMM MMMMMMM MMM MMMMM MM M MMM MMM M M ~ + M M MM MM MM MM M M MM MMM MMM MMMMM MMMMM MMM MMM M + M M MM MMMMM MM MM M M MM MMM MMM MMMMM MMM MMM MMM MMMM ~ + M M MM M MM MM MM M M MM MMM MMM MMMMM MM M MMM MMM M M + MM MMM MMM MM MM M M MM MMM MM MMMMM MMM MMM MMM MM ~ + MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM + + + +============================================================================== + 0.- CONTENTS *delimitMate-contents* + + 1. Introduction____________________________|delimitMateIntro| + 2. Customization___________________________|delimitMateOptions| + 2.1 Options summary____________________|delimitMateOptionSummary| + 2.2 Options details____________________|delimitMateOptionDetails| + 3. Functionality___________________________|delimitMateFunctionality| + 3.1 Automatic closing & exiting________|delimitMateAutoClose| + 3.2 Expansion of space and CR__________|delimitMateExpansion| + 3.3 Backspace__________________________|delimitMateBackspace| + 3.4 Smart Quotes_______________________|delimitMateSmartQuotes| + 3.5 Balancing matching pairs___________|delimitMateBalance| + 3.6 FileType based configuration_______|delimitMateFileType| + 3.7 Syntax awareness___________________|delimitMateSyntax| + 4. Commands________________________________|delimitMateCommands| + 5. Mappings________________________________|delimitMateMappings| + 6. Functions_______________________________|delimitMateFunctions| + 7. Autocommands____________________________|delimitMateAutocmds| + 8. TODO list_______________________________|delimitMateTodo| + 9. Maintainer______________________________|delimitMateMaintainer| + 10. Credits_________________________________|delimitMateCredits| + 11. History_________________________________|delimitMateHistory| + +============================================================================== + 1.- INTRODUCTION *delimitMateIntro* + +This plug-in provides automatic closing of quotes, parenthesis, brackets, +etc.; besides some other related features that should make your time in insert +mode a little bit easier. + +Most of the features can be modified or disabled permanently, using global +variables, or on a FileType basis, using autocommands. + +NOTE 1: If you have any trouble with this plugin, please run |:DelimitMateTest| +in a new buffer to see what is not working. + +NOTE 2: Abbreviations set with |:iabbrev| will not be expanded by delimiters +used on delimitMate, you should use (read |i_CTRL-]|) to expand them on +the go. + +============================================================================== + 2. CUSTOMIZATION *delimitMateOptions* + +You can create your own mappings for some features using the global functions. +Read |delimitMateFunctions| for more info. + +------------------------------------------------------------------------------ + 2.1 OPTIONS SUMMARY *delimitMateOptionSummary* + +The behaviour of this script can be customized setting the following options +in your vimrc file. You can use local options to set the configuration for +specific file types, see |delimitMateOptionDetails| for examples. + +|'loaded_delimitMate'| Turns off the script. + +|'delimitMate_autoclose'| Tells delimitMate whether to automagically + insert the closing delimiter. + +|'delimitMate_matchpairs'| Tells delimitMate which characters are + matching pairs. + +|'delimitMate_quotes'| Tells delimitMate which quotes should be + used. + +|'delimitMate_nesting_quotes'| Tells delimitMate which quotes should be + allowed to be nested. + +|'delimitMate_expand_cr'| Turns on/off the expansion of . + +|'delimitMate_expand_space'| Turns on/off the expansion of . + +|'delimitMate_jump_expansion'| Turns on/off jumping over expansions. + +|'delimitMate_smart_quotes'| Turns on/off the "smart quotes" feature. + +|'delimitMate_smart_matchpairs'| Turns on/off the "smart matchpairs" feature. + +|'delimitMate_balance_matchpairs'|Turns on/off the "balance matching pairs" + feature. + +|'delimitMate_excluded_regions'| Turns off the script for the given regions or + syntax group names. + +|'delimitMate_excluded_ft'| Turns off the script for the given file types. + +|'delimitMate_eol_marker'| Determines what to insert after the closing + matchpair when typing an opening matchpair on + the end of the line. + +|'delimitMate_apostrophes'| Tells delimitMate how it should "fix" + balancing of single quotes when used as + apostrophes. NOTE: Not needed any more, kept + for compatibility with older versions. + +------------------------------------------------------------------------------ + 2.2 OPTIONS DETAILS *delimitMateOptionDetails* + +Add the shown lines to your vimrc file in order to set the below options. +Buffer variables take precedence over global ones and can be used along with +autocmd to modify delimitMate's behavior for specific file types, read more in +|delimitMateFileType|. + +Note: Use buffer variables only to set options for specific file types using +:autocmd, use global variables to set options for all buffers. Read more in +|g:var| and |b:var|. + +------------------------------------------------------------------------------ + *'loaded_delimitMate'* + *'b:loaded_delimitMate'* +This option prevents delimitMate from loading. +e.g.: > + let loaded_delimitMate = 1 + au FileType mail let b:loaded_delimitMate = 1 +< +------------------------------------------------------------------------------ + *'delimitMate_offByDefault'* +Values: 0 or 1.~ +Default: 0~ + +If this option is set to 1, delimitMate will load, but will not take +effect in any buffer unless |:DelimitMateSwitch| is called in that +buffer. + +------------------------------------------------------------------------------ + *'delimitMate_autoclose'* + *'b:delimitMate_autoclose'* +Values: 0 or 1. ~ +Default: 1 ~ + +If this option is set to 0, delimitMate will not add a closing delimiter +automagically. See |delimitMateAutoClose| for details. +e.g.: > + let delimitMate_autoclose = 0 + au FileType mail let b:delimitMate_autoclose = 0 +< +------------------------------------------------------------------------------ + *'delimitMate_matchpairs'* + *'b:delimitMate_matchpairs'* +Values: A string with |'matchpairs'| syntax, plus support for multi-byte~ + characters.~ +Default: &matchpairs ~ + +Use this option to tell delimitMate which characters should be considered +matching pairs. Read |delimitMateAutoClose| for details. +e.g: > + let delimitMate_matchpairs = "(:),[:],{:},<:>" + au FileType vim,html let b:delimitMate_matchpairs = "(:),[:],{:},<:>" +< +------------------------------------------------------------------------------ + *'delimitMate_quotes'* + *'b:delimitMate_quotes'* +Values: A string of characters separated by spaces. ~ +Default: "\" ' `" ~ + +Use this option to tell delimitMate which characters should be considered as +quotes. Read |delimitMateAutoClose| for details. +e.g.: > + let delimitMate_quotes = "\" ' ` *" + au FileType html let b:delimitMate_quotes = "\" '" +< +------------------------------------------------------------------------------ + *'delimitMate_nesting_quotes'* + *'b:delimitMate_nesting_quotes'* +Values: A list of quotes. ~ +Default: [] ~ + +When adding a third quote listed in this option is inserted, three quotes will +be inserted to the right of the cursor and the cursor will stay in the middle. +If more quotes are inserted the number of quotes on both sides of the cursor +will stay balanced. +e.g.: > + let delimitMate_nesting_quotes = ['"','`'] + au FileType python let b:delimitMate_nesting_quotes = ['"'] +< +------------------------------------------------------------------------------ + *'delimitMate_expand_cr'* + *'b:delimitMate_expand_cr'* +Values: 0, 1 or 2 ~ +Default: 0 ~ + +This option turns on/off the expansion of . Read |delimitMateExpansion| +for details. NOTE This feature requires that 'backspace' is either set to 2 or +has "eol" and "start" as part of its value. +e.g.: > + let delimitMate_expand_cr = 1 + au FileType mail let b:delimitMate_expand_cr = 1 +< +------------------------------------------------------------------------------ + *'delimitMate_expand_space'* + *'b:delimitMate_expand_space'* +Values: 1 or 0 ~ +Default: 0 ~ +This option turns on/off the expansion of . Read |delimitMateExpansion| +for details. +e.g.: > + let delimitMate_expand_space = 1 + au FileType tcl let b:delimitMate_expand_space = 1 +< +------------------------------------------------------------------------------ + *'delimitMate_expand_inside_quotes'* + *'b:delimitMate_expand_inside_quotes'* +Values: 1 or 0 ~ +Default: 0 ~ +When this option is set to 1 the expansion of space and cr will also be +applied to quotes. Read |delimitMateExpansion| for details. + +e.g.: > + let delimitMate_expand_inside_quotes = 1 + au FileType mail let b:delimitMate_expand_inside_quotes = 1 +< +------------------------------------------------------------------------------ + *'delimitMate_jump_expansion'* + *'b:delimitMate_jump_expansion'* +Values: 1 or 0 ~ +Default: 0 ~ +This option turns on/off the jumping over and expansions when +inserting closing matchpairs. Read |delimitMateExpansion| for details. +e.g.: > + let delimitMate_jump_expansion = 1 + au FileType tcl let b:delimitMate_jump_expansion = 1 +< +------------------------------------------------------------------------------ + *'delimitMate_smart_quotes'* + *'b:delimitMate_smart_quotes'* +Values: String with an optional ! at the beginning followed by a regexp ~ +Default:~ +'\%(\w\|[^[:punct:][:space:]]\|\%(\\\\\)*\\\)\%#\|\%#\%(\w\|[^[:space:][:punct:]]\)' ~ + +A bang (!) at the beginning is removed and used to "negate" the pattern. The +remaining text is used as a regexp to be matched on the current line. A single +quote is inserted when the pattern matches and a bang is not present. The bang +changes that, so a single quote is inserted only if the regexp does not match. + +This feature is disabled when the variable is set to an empty string, with the +exception of apostrophes. + +Note that you need to use '\%#' to match the position of the cursor. Keep in +mind that '\%#' matches with zero width, so if you need to match the char +under the cursor (which would be the one to the right on insert mode) use +something like '\%#.'. + +e.g.: > + let delimitMate_smart_quotes = '\w\%#' + au FileType tcl let b:delimitMate_smart_quotes = '!\s\%#\w' +< +------------------------------------------------------------------------------ + *'delimitMate_smart_matchpairs'* + *'b:delimitMate_smart_matchpairs'* +Values: Regexp ~ +Default: '^\%(\w\|\!\|[£$]\|[^[:space:][:punct:]]\)' ~ + +This regex is matched against the text to the right of cursor, if it's not +empty and there is a match delimitMate will not autoclose the pair. At the +moment to match the text, an escaped bang (\!) in the regex will be replaced +by the character being inserted, while an escaped number symbol (\#) will be +replaced by the closing pair. +e.g.: > + let delimitMate_smart_matchpairs = '' + au FileType tcl let b:delimitMate_smart_matchpairs = '^\%(\w\|\$\)' +< +------------------------------------------------------------------------------ + *'delimitMate_balance_matchpairs'* + *'b:delimitMate_balance_matchpairs'* +Values: 1 or 0 ~ +Default: 0 ~ + +This option turns on/off the balancing of matching pairs. Read +|delimitMateBalance| for details. +e.g.: > + let delimitMate_balance_matchpairs = 1 + au FileType tcl let b:delimitMate_balance_matchpairs = 1 +< +------------------------------------------------------------------------------ + *'delimitMate_excluded_regions'* +Values: A string of syntax group names names separated by single commas. ~ +Default: Comment ~ + +This options turns delimitMate off for the listed regions, read |group-name| +for more info about what is a region. +e.g.: > + let delimitMate_excluded_regions = "Comment,String" +< +------------------------------------------------------------------------------ + *'delimitMate_excluded_ft'* +Values: A string of file type names separated by single commas. ~ +Default: Empty. ~ + +This options turns delimitMate off for the listed file types, use this option +only if you don't want any of the features it provides on those file types. +e.g.: > + let delimitMate_excluded_ft = "mail,txt" +< +------------------------------------------------------------------------------ + *'delimitMate_insert_eol_marker'* +Values: Integer ~ +Default: 1 ~ + +Whether to insert the eol marker (EM) or not. The EM is inserted following +rules: + +0 -> never +1 -> when inserting any matchpair +2 -> when expanding car return in matchpair + +e.g.: > + au FileType c,perl let b:delimitMate_insert_eol_marker = 2 +< +------------------------------------------------------------------------------ + *'delimitMate_eol_marker'* +Values: String. ~ +Default: Empty. ~ + +The contents of this string will be inserted after the closing matchpair or +quote when the respective opening matchpair or quote is inserted at the end +of the line. +e.g.: > + au FileType c,perl let b:delimitMate_eol_marker = ";" +< +------------------------------------------------------------------------------ + *'delimitMate_apostrophes'* +Values: Strings separated by ":". ~ +Default: No longer used. ~ + +NOTE: This feature is turned off by default, it's been kept for compatibility +with older version, read |delimitMateSmartQuotes| for details. +If auto-close is enabled, this option tells delimitMate how to try to fix the +balancing of single quotes when used as apostrophes. The values of this option +are strings of text where a single quote would be used as an apostrophe (e.g.: +the "n't" of wouldn't or can't) separated by ":". Set it to an empty string to +disable this feature. +e.g.: > + let delimitMate_apostrophes = "" + au FileType tcl let delimitMate_apostrophes = "" +< +============================================================================== + 3. FUNCTIONALITY *delimitMateFunctionality* + +------------------------------------------------------------------------------ + 3.1 AUTOMATIC CLOSING AND EXITING *delimitMateAutoClose* + +With automatic closing enabled, if an opening delimiter is inserted the plugin +inserts the closing delimiter and places the cursor between the pair. With +automatic closing disabled, no closing delimiters is inserted by delimitMate, +but when a pair of delimiters is typed, the cursor is placed in the middle. + +When the cursor is inside an empty pair or located next to the left of a +closing delimiter, the cursor is placed outside the pair to the right of the +closing delimiter. + +When |'delimitMate_smart_matchpairs'| is not empty and it matches the text to +the right of the cursor, delimitMate will not automatically insert the closing +pair. + +Unless |'delimitMate_matchpairs'| or |'delimitMate_quotes'| are set, this +script uses the values in '&matchpairs' to identify the pairs, and ", ' and ` +for quotes respectively. + + will jump over a single closing delimiter or quote, g will jump +over contiguous delimiters and/or quotes. + +The following table shows the behaviour, this applies to quotes too (the final +position of the cursor is represented by a "|"): + +With auto-close: > + Type | You get + ======================= + ( | (|) + -----------|----------- + () | ()| + -----------|----------- + ( | ()| + -----------|----------- + {("g | {("")}| +< +Without auto-close: > + + Type | You get + ========================= + () | (|) + --------------|---------- + ()) | ()| + --------------|---------- + () | ()| + --------------|---------- + {}()""g | {("")}| +< +NOTE: Abbreviations will not be expanded by delimiters used on delimitMate, +you should use (read |i_CTRL-]|) to expand them on the go. + +------------------------------------------------------------------------------ + 3.2 EXPANSION OF SPACE AND CAR RETURN *delimitMateExpansion* + +When the cursor is inside an empty pair of any matchpair, and can be +expanded, see |'delimitMate_expand_space'| and +|'delimitMate_expand_cr'|: + +Expand to: > + + You start with | You get + ============================== + (|) | ( | ) +< +Expand to: > + + You start with | You get + ============================== + (|) | ( + | | + | ) +< + +When you have |'delimitMate_jump_expansion'| enabled, if there is an existing +closing paren/bracket/etc. on the next line, delimitMate will make the cursor +jump over any whitespace/ and place it after the existing closing +delimiter instead of inserting a new one. + +When |'delimitMate_expand_cr'| is set to 2, the following will also happen: > + + You start with | You get + ============================== + (foo|) | (foo + | | + | ) +< + +Since and are used everywhere, I have made the functions involved +in expansions global, so they can be used to make custom mappings. Read +|delimitMateFunctions| for more details. + +------------------------------------------------------------------------------ + 3.3 BACKSPACE *delimitMateBackspace* + +If you press backspace inside an empty pair, both delimiters are deleted. When +expansions are enabled, will also delete the expansions. + +If you type (shift + backspace) instead, only the closing delimiter +will be deleted. NOTE that this will not usually work when using Vim from the +terminal, see 'delimitMate#JumpAny()' below to see how to fix it. + +e.g. typing at the "|": > + + What | Before | After + ============================================== + | call expand(|) | call expand| + ---------|-------------------|----------------- + | call expand( | ) | call expand(|) + ---------|-------------------|----------------- + | call expand( | call expand(|) + | | | + | ) | + ---------|-------------------|----------------- + | call expand(|) | call expand(| +< + +------------------------------------------------------------------------------ + 3.4 SMART QUOTES *delimitMateSmartQuotes* + +Only one quote will be inserted following a quote, a "\", following or +preceding a keyword character, or when the number of quotes in the current +line is odd. This should cover closing quotes after a string, opening quotes +before a string, escaped quotes and apostrophes. See more details about +customizing this feature on |'delimitMate_smart_quotes'|. + +e.g. typing at the "|": > + + What | Before | After + ======================================= + " | Text | | Text "|" + " | "String| | "String"| + " | let i = "| | let i = "|" + 'm | I| | I'm| +< +------------------------------------------------------------------------------ + 3.4 SMART MATCHPAIRS *delimitMateSmartMatchpairs* + +This is similar to "smart quotes", but applied to the characters in +|'delimitMate_matchpairs'|. The difference is that delimitMate will not +auto-close the pair when the regex matches the text on the right of the +cursor. See |'delimitMate_smart_matchpairs'| for more details. + + +e.g. typing at the "|": > + + What | Before | After + ======================================= + ( | function| | function(|) + ( | |var | (|var +< +------------------------------------------------------------------------------ + 3.5 BALANCING MATCHING PAIRS *delimitMateBalance* + +When inserting an opening paren and |'delimitMate_balance_matchpairs'| is +enabled, delimitMate will try to balance the closing pairs in the current +line. + +e.g. typing at the "|": > + + What | Before | After + ======================================= + ( | | | (|) + ( | |) | (|) + (( | |) | ((|)) +< +------------------------------------------------------------------------------ + 3.6 FILE TYPE BASED CONFIGURATION *delimitMateFileType* + +delimitMate options can be set globally for all buffers using global +("regular") variables in your |vimrc| file. But |:autocmd| can be used to set +options for specific file types (see |'filetype'|) using buffer variables in +the following way: > + + au FileType mail,text let b:delimitMate_autoclose = 0 + ^ ^ ^ ^ ^ + | | | | | + | | | | - Option value. + | | | - Option name. + | | - Buffer variable. + | - File types for which the option will be set. + - Don't forget to put this event. +< +NOTE that you should use buffer variables (|b:var|) only to set options with +|:autocmd|, for global options use regular variables (|g:var|) in your vimrc. + +------------------------------------------------------------------------------ + 3.7 SYNTAX AWARENESS *delimitMateSyntax* + +The features of this plug-in might not be always helpful, comments and strings +usualy don't need auto-completion. delimitMate monitors which region is being +edited and if it detects that the cursor is in a comment it'll turn itself off +until the cursor leaves the comment. The excluded regions can be set using the +option |'delimitMate_excluded_regions'|. Read |group-name| for a list of +regions or syntax group names. + +NOTE that this feature relies on a proper syntax file for the current file +type, if the appropiate syntax file doesn't define a region, delimitMate won't +know about it. + +============================================================================== + 4. COMMANDS *delimitMateCommands* + +------------------------------------------------------------------------------ +:DelimitMateReload *:DelimitMateReload* + +Re-sets all the mappings used for this script, use it if any option has been +changed or if the filetype option hasn't been set yet. + +------------------------------------------------------------------------------ +:DelimitMateOn *:DelimitMateOn* + +Enable delimitMate mappings. + +------------------------------------------------------------------------------ +:DelimitMateOff *:DelimitMateOff* + +Disable delimitMate mappings. + +------------------------------------------------------------------------------ +:DelimitMateSwitch *:DelimitMateSwitch* + +Switches the plug-in on and off. + +------------------------------------------------------------------------------ +:DelimitMateTest *:DelimitMateTest* + +This command tests every mapping set-up for this script, useful for testing +custom configurations. + +The following output corresponds to the default values, it will be different +depending on your configuration. "Open & close:" represents the final result +when the closing delimiter has been inserted, either manually or +automatically, see |delimitMateExpansion|. "Delete:" typing backspace in an +empty pair, see |delimitMateBackspace|. "Exit:" typing a closing delimiter +inside a pair of delimiters, see |delimitMateAutoclose|. "Space:" the +expansion, if any, of space, see |delimitMateExpansion|. "Visual-L", +"Visual-R" and "Visual" shows visual wrapping, see +|delimitMateVisualWrapping|. "Car return:" the expansion of car return, see +|delimitMateExpansion|. The cursor's position at the end of every test is +represented by an "|": > + + * AUTOCLOSE: + Open & close: (|) + Delete: | + Exit: ()| + Space: ( |) + Visual-L: (v) + Visual-R: (v) + Car return: ( + |) + + Open & close: {|} + Delete: | + Exit: {}| + Space: { |} + Visual-L: {v} + Visual-R: {v} + Car return: { + |} + + Open & close: [|] + Delete: | + Exit: []| + Space: [ |] + Visual-L: [v] + Visual-R: [v] + Car return: [ + |] + + Open & close: "|" + Delete: | + Exit: ""| + Space: " |" + Visual: "v" + Car return: " + |" + + Open & close: '|' + Delete: | + Exit: ''| + Space: ' |' + Visual: 'v' + Car return: ' + |' + + Open & close: `|` + Delete: | + Exit: ``| + Space: ` |` + Visual: `v` + Car return: ` + |` +< + +============================================================================== + 5. MAPPINGS *delimitMateMappings* + +delimitMate doesn't override any existing map, so you may encounter that it +doesn't work as expected because a mapping is missing. In that case, the +conflicting mappings should be resolved by either disabling the conflicting +mapping or creating a custom mappings. + +In order to make custom mappings easier and prevent overwritting existing +ones, delimitMate uses the || + |hasmapto()| (|usr_41.txt|) construct +for its mappings. + +These are the default mappings for the extra features: + + is mapped to delimitMateBS + is mapped to delimitMateS-BS + is mapped to delimitMateS-Tab +g is mapped to delimitMateJumpMany + +The rest of the mappings correspond to parens, quotes, CR, Space, etc. and they +depend on the values of the delimitMate options, they have the following form: + +delimitMate + char + +e.g.: for "(": + +( is mapped to delimitMate( + +e.g.: If you have expansion enabled, you might want to skip it on pop-up +menus: + + imap pumvisible() + \ ? "\" + \ : "delimitMateCR" + + +============================================================================== + 6. FUNCTIONS *delimitMateFunctions* + +------------------------------------------------------------------------------ +delimitMate#WithinEmptyPair() *delimitMate#WithinEmptyPair()* + +Returns 1 if the cursor is inside an empty pair, 0 otherwise. +e.g.: > + + inoremap delimitMate#WithinEmptyPair() ? + \ "delimitMateCR" : + \ "external_mapping" +< + +------------------------------------------------------------------------------ +delimitMate#ShouldJump() *delimitMate#ShouldJump()* + +Returns 1 if there is a closing delimiter or a quote to the right of the +cursor, 0 otherwise. + +------------------------------------------------------------------------------ +delimitMate#JumpAny() *delimitMate#JumpAny()* + +This function returns a mapping that will make the cursor jump to the right +when delimitMate#ShouldJump() returns 1, returns the argument "key" otherwise. +e.g.: You can use this to create your own mapping to jump over any delimiter. +> + inoremap delimitMate#JumpAny() +< +============================================================================== + 7. AUTOCOMMANDS *delimitMateAutocmds* + +delimitMate emits 2 |User| autocommands to make it easier for users to +leverage delimitMate's support for per-filetype customization. + +------------------------------------------------------------------------------ +delimitMate_map *delimitMate_map* + +This |User| event is emittted just prior to delimitMate defining its +buffer-local key mappings. You can use this command to define your own +mappings that are disabled when delimitMate is turned off or excludes the +current filetype. +> + au User delimitMate_map call s:delimitMate_map() + function s:delimitMate_map() + imap delimitMate#JumpAny() + endfunction +< +------------------------------------------------------------------------------ +delimitMate_unmap *delimitMate_unmap* + +This |User| event is emitted just after delimitMate clears its buffer-local +key mappings. You can use this command to clear your own mappings that you set +in response to |delimitMate_map|. +> + au User delimitMate_unmap call s:delimitMate_unmap() + function s:delimitMate_unmap() + silent! iunmap + endfunction +< +Note: This event may be emitted before |delimitMate_map|, and may be emitted +multiple times in a row without any intervening |delimitMate_map| events. + +============================================================================== + 8. TODO LIST *delimitMateTodo* + +- Automatic set-up by file type. +- Make block-wise visual wrapping work on un-even regions. + +============================================================================== + 9. MAINTAINER *delimitMateMaintainer* + +Hi there! My name is Israel Chauca F. and I can be reached at: + mailto:israelchauca@gmail.com + +Feel free to send me any suggestions and/or comments about this plugin, I'll +be very pleased to read them. + +============================================================================== + 10. CREDITS *delimitMateCredits* + +Contributors: ~ + + - Kim Silkebækken ~ + Fixed mappings being echoed in the terminal. + + - Eric Van Dewoestine ~ + Implemented smart matchpairs. + +Some of the code that makes this script was modified or just shamelessly +copied from the following sources: + + - Ian McCracken ~ + Post titled: Vim, Part II: Matching Pairs: + http://concisionandconcinnity.blogspot.com/ + + - Aristotle Pagaltzis ~ + From the comments on the previous blog post and from: + http://gist.github.com/144619 + + - Karl Guertin ~ + AutoClose: + http://www.vim.org/scripts/script.php?script_id=1849 + + - Thiago Alves ~ + AutoClose: + http://www.vim.org/scripts/script.php?script_id=2009 + + - Edoardo Vacchi ~ + ClosePairs: + http://www.vim.org/scripts/script.php?script_id=2373 + +This script was inspired by the auto-completion of delimiters on TextMate. + +============================================================================== + 11. HISTORY *delimitMateHistory* + + Version Date Release notes ~ +|---------|------------|-----------------------------------------------------| + 2.8 2013-07-15 * Current release: + - Add :DelimitMateOn & :DelimitMateOff. +|---------|------------|-----------------------------------------------------| + 2.7 2013-07-15 * - Lots of bug fixes. + - Add delimitMate_offByDefault. + - Add delimitMate_eol_marker. + - Reduce the number of mappings. + - Stop using setline(). + - Better handling of nested quotes. + - Allow a custom pattern for smart_quotes. +|---------|------------|-----------------------------------------------------| + 2.6 2011-01-14 * - Add smart_matchpairs feature. + - Add mapping to jump over contiguous delimiters. + - Fix behaviour of b:loaded_delimitMate. +|---------|------------|-----------------------------------------------------| + 2.5.1 2010-09-30 * - Remove visual wrapping. Surround.vim offers a much + better implementation. + - Minor mods to DelimitMateTest. +|---------|------------|-----------------------------------------------------| + 2.5 2010-09-22 * - Better handling of mappings. + - Add report for mappings in |:DelimitMateTest|. + - Allow the use of "|" and multi-byte characters in + |'delimitMate_quotes'| and |'delimitMate_matchpairs'|. + - Allow commands to be concatenated using |. +|---------|------------|-----------------------------------------------------| + 2.4.1 2010-07-31 * - Fix problem with and . + - Add missing doc on |'delimitMate_smart_quotes'|, + |delimitMateBalance| and + |'delimitMate_balance_matchpairs'|. +|---------|------------|-----------------------------------------------------| + 2.4 2010-07-29 * - Unbalanced parens: see :help delimitMateBalance. + - Visual wrapping now works on block-wise visual + with some limitations. + - Arrow keys didn't work on terminal. + - Added option to allow nested quotes. + - Expand Smart Quotes to look for a string on the + right of the cursor. + +|---------|------------|-----------------------------------------------------| + 2.3.1 2010-06-06 * - Fix: an extra is inserted after + expansion. + +|---------|------------|-----------------------------------------------------| + 2.3 2010-06-06 * - Syntax aware: Will turn off when editing comments + or other regions, customizable. + - Changed format of most mappings. + - Fix: expansion doesn't break automatic + indentation adjustments anymore. + - Fix: Arrow keys would insert A, B, C or D instead + of moving the cursor when using Vim on a terminal. + +|---------|------------|-----------------------------------------------------| + 2.2 2010-05-16 * - Added command to switch the plug-in on and off. + - Fix: some problems with , and . + - Fix: A small problem when inserting a delimiter at + the beginning of the line. + +|---------|------------|-----------------------------------------------------| + 2.1 2010-05-10 * - Most of the functions have been moved to an + autoload script to avoid loading unnecessary ones. + - Fixed a problem with the redo command. + - Many small fixes. + +|---------|------------|-----------------------------------------------------| + 2.0 2010-04-01 * New features: + - All features are redo/undo-wise safe. + - A single quote typed after an alphanumeric + character is considered an apostrophe and one + single quote is inserted. + - A quote typed after another quote inserts a single + quote and the cursor jumps to the middle. + - jumps out of any empty pair. + - and expansions are fixed, but the + functions used for it are global and can be used in + custom mappings. The previous system is still + active if you have any of the expansion options + set. + - deletes the closing delimiter. + * Fixed bug: + - s:vars were being used to store buffer options. + +|---------|------------|-----------------------------------------------------| + 1.6 2009-10-10 * Now delimitMate tries to fix the balancing of single + quotes when used as apostrophes. You can read + |delimitMate_apostrophes| for details. + Fixed an error when |b:delimitMate_expand_space| + wasn't set but |delimitMate_expand_space| wasn't. + +|---------|------------|-----------------------------------------------------| + 1.5 2009-10-05 * Fix: delimitMate should work correctly for files + passed as arguments to Vim. Thanks to Ben Beuchler + for helping to nail this bug. + +|---------|------------|-----------------------------------------------------| + 1.4 2009-09-27 * Fix: delimitMate is now enabled on new buffers even + if they don't have set the file type option or were + opened directly from the terminal. + +|---------|------------|-----------------------------------------------------| + 1.3 2009-09-24 * Now local options can be used along with autocmd + for specific file type configurations. + Fixes: + - Unnamed register content is not lost on visual + mode. + - Use noremap where appropiate. + - Wrapping a single empty line works as expected. + +|---------|------------|-----------------------------------------------------| + 1.2 2009-09-07 * Fixes: + - When inside nested empty pairs, deleting the + innermost left delimiter would delete all right + contiguous delimiters. + - When inside an empty pair, inserting a left + delimiter wouldn't insert the right one, instead + the cursor would jump to the right. + - New buffer inside the current window wouldn't + have the mappings set. + +|---------|------------|-----------------------------------------------------| + 1.1 2009-08-25 * Fixed an error that ocurred when mapleader wasn't + set and added support for GetLatestScripts + auto-detection. + +|---------|------------|-----------------------------------------------------| + 1.0 2009-08-23 * Initial upload. + +|---------|------------|-----------------------------------------------------| + + + `\|||/´ MMM \|/ www __^__ ~ + (o o) (o o) @ @ (O-O) /(o o)\\ ~ +ooO_(_)_Ooo__ ooO_(_)_Ooo___oOO_(_)_OOo___oOO__(_)__OOo___oOO__(_)__OOo_____ ~ +_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|____ ~ +__|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_ ~ +_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|____ ~ + +vim:tw=78:et:ts=8:sw=2:ft=help:norl:formatoptions+=tcroqn:autoindent: diff --git a/bundle/delimitMate/plugin/delimitMate.vim b/bundle/delimitMate/plugin/delimitMate.vim new file mode 100644 index 000000000..cf16fe84c --- /dev/null +++ b/bundle/delimitMate/plugin/delimitMate.vim @@ -0,0 +1,402 @@ +" File: plugin/delimitMate.vim +" Version: 2.7 +" Modified: 2013-07-15 +" Description: This plugin provides auto-completion for quotes, parens, etc. +" Maintainer: Israel Chauca F. +" Manual: Read ":help delimitMate". +" ============================================================================ + +" Initialization: {{{ + +if exists("g:loaded_delimitMate") || &cp + " User doesn't want this plugin or compatible is set, let's get out! + finish +endif +let g:loaded_delimitMate = 1 +let save_cpo = &cpo +set cpo&vim + +if v:version < 700 + echoerr "delimitMate: this plugin requires vim >= 7!" + finish +endif + +let s:loaded_delimitMate = 1 +let delimitMate_version = "2.8" + +"}}} + +" Functions: {{{ + +function! s:option_init(name, default) "{{{ + let b = exists("b:delimitMate_" . a:name) + let g = exists("g:delimitMate_" . a:name) + " Find value to use. + if !b && !g + let value = a:default + elseif b + exec "let value = b:delimitMate_" . a:name + else + exec "let value = g:delimitMate_" . a:name + endif + call s:set(a:name, value) +endfunction "}}} + +function! s:init() "{{{ +" Initialize variables: + " autoclose + call s:option_init("autoclose", 1) + " matchpairs + call s:option_init("matchpairs", string(&matchpairs)[1:-2]) + call s:option_init("matchpairs_list", map(split(s:get('matchpairs'), '.:.\zs,\ze.:.'), 'split(v:val, ''^.\zs:\ze.$'')')) + let pairs = s:get('matchpairs_list') + if len(filter(pairs, 'v:val[0] ==# v:val[1]')) + echohl ErrorMsg + echom 'delimitMate: each member of a pair in delimitMate_matchpairs must be different from each other.' + echom 'delimitMate: invalid pairs: ' . join(map(pairs, 'join(v:val, ":")'), ', ') + echohl Normal + return 0 + endif + call s:option_init("left_delims", map(copy(s:get('matchpairs_list')), 'v:val[0]')) + call s:option_init("right_delims", map(copy(s:get('matchpairs_list')), 'v:val[1]')) + " quotes + call s:option_init("quotes", "\" ' `") + call s:option_init("quotes_list",split(s:get('quotes'), '\s\+')) + " nesting_quotes + call s:option_init("nesting_quotes", []) + " excluded_regions + call s:option_init("excluded_regions", "Comment") + call s:option_init("excluded_regions_list", split(s:get('excluded_regions'), ',\s*')) + let enabled = len(s:get('excluded_regions_list')) > 0 + call s:option_init("excluded_regions_enabled", enabled) + " expand_space + if exists("b:delimitMate_expand_space") && type(b:delimitMate_expand_space) == type("") + echom "b:delimitMate_expand_space is '".b:delimitMate_expand_space."' but it must be either 1 or 0!" + echom "Read :help 'delimitMate_expand_space' for more details." + unlet b:delimitMate_expand_space + let b:delimitMate_expand_space = 1 + endif + if exists("g:delimitMate_expand_space") && type(g:delimitMate_expand_space) == type("") + echom "delimitMate_expand_space is '".g:delimitMate_expand_space."' but it must be either 1 or 0!" + echom "Read :help 'delimitMate_expand_space' for more details." + unlet g:delimitMate_expand_space + let g:delimitMate_expand_space = 1 + endif + call s:option_init("expand_space", 0) + " expand_cr + if exists("b:delimitMate_expand_cr") && type(b:delimitMate_expand_cr) == type("") + echom "b:delimitMate_expand_cr is '".b:delimitMate_expand_cr."' but it must be either 1 or 0!" + echom "Read :help 'delimitMate_expand_cr' for more details." + unlet b:delimitMate_expand_cr + let b:delimitMate_expand_cr = 1 + endif + if exists("g:delimitMate_expand_cr") && type(g:delimitMate_expand_cr) == type("") + echom "delimitMate_expand_cr is '".g:delimitMate_expand_cr."' but it must be either 1 or 0!" + echom "Read :help 'delimitMate_expand_cr' for more details." + unlet g:delimitMate_expand_cr + let g:delimitMate_expand_cr = 1 + endif + if ((&backspace !~ 'eol' || &backspace !~ 'start') && &backspace != 2) && + \ ((exists('b:delimitMate_expand_cr') && b:delimitMate_expand_cr == 1) || + \ (exists('g:delimitMate_expand_cr') && g:delimitMate_expand_cr == 1)) + echom "delimitMate: There seems to be some incompatibility with your settings that may interfer with the expansion of . See :help 'delimitMate_expand_cr' for details." + endif + call s:option_init("expand_cr", 0) + " expand_in_quotes + call s:option_init('expand_inside_quotes', 0) + " jump_expansion + call s:option_init("jump_expansion", 0) + " smart_matchpairs + call s:option_init("smart_matchpairs", '^\%(\w\|\!\|[£$]\|[^[:punct:][:space:]]\)') + " smart_quotes + " XXX: backward compatibility. Ugly, should go the way of the dodo soon. + let quotes = escape(join(s:get('quotes_list'), ''), '\-^[]') + let default_smart_quotes = '\%(\w\|[^[:punct:][:space:]' . quotes . ']\|\%(\\\\\)*\\\)\%#\|\%#\%(\w\|[^[:space:][:punct:]' . quotes . ']\)' + if exists('g:delimitMate_smart_quotes') && type(g:delimitMate_smart_quotes) == type(0) + if g:delimitMate_smart_quotes + unlet g:delimitMate_smart_quotes + else + unlet g:delimitMate_smart_quotes + let g:delimitMate_smart_quotes = '' + endif + endif + if exists('b:delimitMate_smart_quotes') && type(b:delimitMate_smart_quotes) == type(0) + if b:delimitMate_smart_quotes + unlet b:delimitMate_smart_quotes + if exists('g:delimitMate_smart_quotes') && type(g:delimitMate_smart_quotes) && g:delimitMate_smart_quotes + let b:delimitMate_smart_quotes = default_smart_quotes + endif + else + unlet b:delimitMate_smart_quotes + let b:delimitMate_smart_quotes = '' + endif + endif + call s:option_init("smart_quotes", default_smart_quotes) + " apostrophes + call s:option_init("apostrophes", "") + call s:option_init("apostrophes_list", split(s:get('apostrophes'), ":\s*")) + " tab2exit + call s:option_init("tab2exit", 1) + " balance_matchpairs + call s:option_init("balance_matchpairs", 0) + " eol marker + call s:option_init("insert_eol_marker", 1) + call s:option_init("eol_marker", "") + " Everything is fine. + return 1 +endfunction "}}} Init() + +function! s:get(...) " {{{ + return call('delimitMate#Get', a:000) +endfunction " }}} + +function! s:set(...) " {{{ + return call('delimitMate#Set', a:000) +endfunction " }}} + +function! s:Map() "{{{ + " Set mappings: + try + let save_keymap = &keymap + let save_iminsert = &iminsert + let save_imsearch = &imsearch + let save_cpo = &cpo + set keymap= + set cpo&vim + silent! doautocmd User delimitMate_map + if s:get('autoclose') + call s:AutoClose() + else + call s:NoAutoClose() + endif + call s:ExtraMappings() + finally + let &cpo = save_cpo + let &keymap = save_keymap + let &iminsert = save_iminsert + let &imsearch = save_imsearch + endtry + + let b:delimitMate_enabled = 1 +endfunction "}}} Map() + +function! s:Unmap() " {{{ + let imaps = + \ s:get('right_delims', []) + + \ s:get('left_delims', []) + + \ s:get('quotes_list', []) + + \ s:get('apostrophes_list', []) + + \ ['', '', '', '', '', '', '', ''] + + \ ['', '', '', '', '', ''] + + \ ['', ''] + + \ ['', '', '', '', '', '', 'g'] + + for map in imaps + if maparg(map, "i") =~# '^delimitMate' + if map == '|' + let map = '' + endif + exec 'silent! iunmap ' . map + endif + endfor + silent! doautocmd User delimitMate_unmap + let b:delimitMate_enabled = 0 +endfunction " }}} s:Unmap() + +function! s:test() "{{{ + if &modified + let confirm = input("Modified buffer, type \"yes\" to write and proceed " + \ . "with test: ") ==? 'yes' + if !confirm + return + endif + endif + call delimitMate#Test() + g/\%^$/d + 0 +endfunction "}}} + +function! s:setup(...) "{{{ + let swap = a:0 && a:1 == 2 + let enable = a:0 && a:1 + let disable = a:0 && !a:1 + " First, remove all magic, if needed: + if get(b:, 'delimitMate_enabled', 0) + call s:Unmap() + " Switch + if swap + echo "delimitMate is disabled." + return + endif + endif + if disable + " Just disable the mappings. + return + endif + if !a:0 + " Check if this file type is excluded: + if exists("g:delimitMate_excluded_ft") && + \ index(split(g:delimitMate_excluded_ft, ','), &filetype, 0, 1) >= 0 + " Finish here: + return 1 + endif + " Check if user tried to disable using b:loaded_delimitMate + if exists("b:loaded_delimitMate") + return 1 + endif + endif + " Initialize settings: + if ! s:init() + " Something went wrong. + return + endif + if enable || swap || !get(g:, 'delimitMate_offByDefault', 0) + " Now, add magic: + call s:Map() + if a:0 + echo "delimitMate is enabled." + endif + endif +endfunction "}}} + +function! s:TriggerAbb() "{{{ + if v:version < 703 + \ || ( v:version == 703 && !has('patch489') ) + \ || pumvisible() + return '' + endif + return "\" +endfunction "}}} + +function! s:NoAutoClose() "{{{ + " inoremap ) =delimitMate#SkipDelim('\)') + for delim in s:get('right_delims') + s:get('quotes_list') + if delim == '|' + let delim = '' + endif + exec 'inoremap delimitMate' . delim . ' =TriggerAbb().delimitMate#SkipDelim("' . escape(delim,'"') . '")' + exec 'silent! imap '.delim.' delimitMate'.delim + endfor +endfunction "}}} + +function! s:AutoClose() "{{{ + " Add matching pair and jump to the midle: + " inoremap ( () + let i = 0 + while i < len(s:get('matchpairs_list')) + let ld = s:get('left_delims')[i] == '|' ? '' : s:get('left_delims')[i] + let rd = s:get('right_delims')[i] == '|' ? '' : s:get('right_delims')[i] + exec 'inoremap delimitMate' . ld + \. ' TriggerAbb().delimitMate#ParenDelim("' . escape(rd, '|') . '")' + exec 'silent! imap '.ld + \.' delimitMate'.ld + let i += 1 + endwhile + + " Exit from inside the matching pair: + for delim in s:get('right_delims') + let delim = delim == '|' ? '' : delim + exec 'inoremap delimitMate' . delim + \. ' TriggerAbb().delimitMate#JumpOut("\' . delim . '")' + exec 'silent! imap ' . delim + \. ' delimitMate'. delim + endfor + + " Add matching quote and jump to the midle, or exit if inside a pair of matching quotes: + " inoremap " =delimitMate#QuoteDelim("\"") + for delim in s:get('quotes_list') + if delim == '|' + let delim = '' + endif + exec 'inoremap delimitMate' . delim + \. ' TriggerAbb()."=delimitMate#QuoteDelim(\"\\\' . delim . '\")"' + exec 'silent! imap ' . delim + \. ' delimitMate' . delim + endfor + + " Try to fix the use of apostrophes (kept for backward compatibility): + " inoremap n't n't + for map in s:get('apostrophes_list') + exec "inoremap " . map . " " . map + exec 'silent! imap ' . map . ' delimitMate' . map + endfor +endfunction "}}} + +function! s:ExtraMappings() "{{{ + " If pair is empty, delete both delimiters: + inoremap delimitMateBS =delimitMate#BS() + if !hasmapto('delimitMateBS','i') + if empty(maparg('', 'i')) + silent! imap delimitMateBS + endif + if empty(maparg('', 'i')) + silent! imap delimitMateBS + endif + endif + " If pair is empty, delete closing delimiter: + inoremap delimitMateS-BS delimitMate#WithinEmptyPair() ? "\" : "\" + if !hasmapto('delimitMateS-BS','i') && maparg('', 'i') == '' + silent! imap delimitMateS-BS + endif + " Expand return if inside an empty pair: + inoremap delimitMateCR TriggerAbb()."\=delimitMate#ExpandReturn()\" + if s:get('expand_cr') && !hasmapto('delimitMateCR', 'i') && maparg('', 'i') == '' + silent! imap delimitMateCR + endif + " Expand space if inside an empty pair: + inoremap delimitMateSpace TriggerAbb()."\=delimitMate#ExpandSpace()\" + if s:get('expand_space') && !hasmapto('delimitMateSpace', 'i') && maparg('', 'i') == '' + silent! imap delimitMateSpace + endif + " Jump over any delimiter: + inoremap delimitMateS-Tab TriggerAbb()."\=delimitMate#JumpAny()\" + if s:get('tab2exit') && !hasmapto('delimitMateS-Tab', 'i') && maparg('', 'i') == '' + silent! imap delimitMateS-Tab + endif + " Jump over next delimiters + inoremap delimitMateJumpMany TriggerAbb()."\=delimitMate#JumpMany()\" + if !hasmapto('delimitMateJumpMany', 'i') && maparg("g", 'i') == '' + imap g delimitMateJumpMany + endif +endfunction "}}} + +"}}} + +" Commands: {{{ + +" Let me refresh without re-loading the buffer: +command! -bar DelimitMateReload call s:setup(1) +" Quick test: +command! -bar DelimitMateTest call s:test() +" Switch On/Off: +command! -bar DelimitMateSwitch call s:setup(2) +" Enable mappings: +command! -bar DelimitMateOn call s:setup(1) +" Disable mappings: +command! -bar DelimitMateOff call s:setup(0) + +"}}} + +" Autocommands: {{{ + +augroup delimitMate + au! + " Run on file type change. + au FileType * call setup() + + " Run on new buffers. + au BufNewFile,BufRead,BufEnter,CmdwinEnter * + \ if !exists('b:delimitMate_was_here') | + \ call setup() | + \ let b:delimitMate_was_here = 1 | + \ endif +augroup END + +"}}} + +" This is for the default buffer when it does not have a filetype. +call s:setup() + +let &cpo = save_cpo +" GetLatestVimScripts: 2754 1 :AutoInstall: delimitMate.vim +" vim:foldmethod=marker:foldcolumn=4:ts=2:sw=2 diff --git a/bundle/delimitMate/test/Makefile b/bundle/delimitMate/test/Makefile new file mode 100644 index 000000000..62f57dddf --- /dev/null +++ b/bundle/delimitMate/test/Makefile @@ -0,0 +1,9 @@ +all: build/runVimTests + build/runVimTests/bin/runVimTests.sh -0 . + +build/runVimTests: build/VimTAP + git clone https://github.com/inkarkat/runVimTests $@ + +# Use VimTAP as directory name, as used with runVimTestsSetup.vim. +build/VimTAP: + git clone https://github.com/inkarkat/vimtap $@ diff --git a/bundle/delimitMate/test/README.md b/bundle/delimitMate/test/README.md new file mode 100644 index 000000000..55a39906b --- /dev/null +++ b/bundle/delimitMate/test/README.md @@ -0,0 +1,18 @@ +# Automatic test setup +You can use `make` (or `make test` from the top level directory) to run the +tests. + +# Manual test setup instructions +The plugins [runVimTests](http://www.vim.org/scripts/script.php?script_id=2565) +and [VimTAP](http://www.vim.org/scripts/script.php?script_id=2213) are needed +to run these tests. + +Besides the `_setup.vim` configuration file present in this repo you need to +create a global one and place it in the same dir where the runVimTests +executable is located. Assuming the executable is at '~/bin/runVimTests' this +global configuration file should be '~/bin/runVimTestsSetup.vim' and should +have something like the following lines inside of it: + + " Prepend tests repos to &rtp + let &runtimepath = '/path/to/runVimTests_dir,' . &rtp + let &runtimepath = '/path/to/vimTAP_dir,' . &rtp diff --git a/bundle/delimitMate/test/_setup.vim b/bundle/delimitMate/test/_setup.vim new file mode 100644 index 000000000..7d0a31f13 --- /dev/null +++ b/bundle/delimitMate/test/_setup.vim @@ -0,0 +1,12 @@ +let &rtp = expand(':p:h:h') . ',' . &rtp . ',' . expand(':p:h:h') . '/after' +set bs=2 +ru plugin/delimitMate.vim +let runVimTests = expand(':p:h').'/build/runVimTests' +if isdirectory(runVimTests) + let &rtp = runVimTests . ',' . &rtp +endif +let vimTAP = expand(':p:h').'/build/VimTAP' +if isdirectory(vimTAP) + let &rtp = vimTAP . ',' . &rtp +endif + diff --git a/bundle/delimitMate/test/autoclose_matchpairs.txt b/bundle/delimitMate/test/autoclose_matchpairs.txt new file mode 100644 index 000000000..df5f61b24 --- /dev/null +++ b/bundle/delimitMate/test/autoclose_matchpairs.txt @@ -0,0 +1,51 @@ +let g:delimitMate_autoclose = 1 +"(x" "(x)" +"(\x" "x" +"()x" "()x" +"((\gx" "(())x" +"(x\u" "" +"@(x" "@(x)" +"@#\(x" "@(x)#" +"(\x" "()x" +let g:delimitMate_autoclose = 0 +"(x" "(x" +"()x" "(x)" +"())x" "()x" +"()\x" "x" +"@()x" "@(x)" +"@#\()x" "@(x)#" +let g:delimitMate_expand_space = 1 +let g:delimitMate_autoclose = 1 +"(\x" "( x )" +"(\\x" "(x)" +let g:delimitMate_autoclose = 0 +"()\\x" "(x)" +let g:delimitMate_autoclose = 1 +# Handle backspace gracefully. +set backspace= +"(\a\x" "(x)" +set bs=2 +# closing parens removes characters. #133 +"(a\i)" "()a)" + +# Add semicolon next to the closing paren. Issue #77. +new +let b:delimitMate_eol_marker = ';' +"abc(x" "abc(x);" +%d +# BS should behave accordingly. +"abc(\" "abc;" +# Expand iabbreviations +unlet b:delimitMate_eol_marker +iabb def ghi +"def(" "ghi()" +iunabb def + +"abc а\(" "abc (а" +"abc ñ\(" "abc (ñ" +"abc $\(" "abc ($" +"abc £\(" "abc (£" +"abc d\(" "abc (d" +"abc \(\(" "abc ((" +"abc .\(" "abc ()." +"abc \(" "abc () " diff --git a/bundle/delimitMate/test/autoclose_matchpairs.vim b/bundle/delimitMate/test/autoclose_matchpairs.vim new file mode 100644 index 000000000..faa69a99d --- /dev/null +++ b/bundle/delimitMate/test/autoclose_matchpairs.vim @@ -0,0 +1,42 @@ +let g:delimitMate_matchpairs = '(:),{:},[:],<:>,¿:?,¡:!,,::' +let lines = readfile(expand(':t:r').'.txt') +call vimtest#StartTap() +let testsnumber = len(filter(copy(lines), 'v:val =~ ''^"''')) +let itemsnumber = len(split(g:delimitMate_matchpairs, '.:.\zs,\ze.:.')) +call vimtap#Plan(testsnumber * itemsnumber) +let tcount = 1 +let reload = 1 +for item in lines + if item =~ '^#\|^\s*$' + " A comment or empty line. + continue + endif + if item !~ '^"' + " A command. + exec item + call vimtap#Diag(item) + let reload = 1 + continue + endif + if reload + DelimitMateReload + call vimtap#Diag('DelimitMateReload') + let reload = 0 + endif + let [input, output] = split(item, '"\%(\\.\|[^\\"]\)*"\zs\s*\ze"\%(\\.\|[^\\"]\)*"') + for [s:l,s:r] in map(split(g:delimitMate_matchpairs, '.:.\zs,\ze.:.'), 'split(v:val, ''.\zs:\ze.'')') + let input2 = substitute(input, '(', s:l, 'g') + let input2 = substitute(input2, ')', s:r, 'g') + let output2 = substitute(output, '(', s:l, 'g') + let output2 = substitute(output2, ')', s:r, 'g') + %d + exec 'normal i'.eval(input2)."\" + let line = getline('.') + let passed = line == eval(output2) + call vimtap#Is(line, eval(output2), input2) + ", input2 . ' => ' . string(line) . + " \ (passed ? ' =' : ' !') . '= ' . string(eval(output2))) + let tcount += 1 + endfor +endfor +call vimtest#Quit() diff --git a/bundle/delimitMate/test/autoclose_quotes.txt b/bundle/delimitMate/test/autoclose_quotes.txt new file mode 100644 index 000000000..02c002b43 --- /dev/null +++ b/bundle/delimitMate/test/autoclose_quotes.txt @@ -0,0 +1,73 @@ +let g:delimitMate_autoclose = 1 +"'x" "'x'" +"'x\u" "" +"''x" "''x" +"'\x" "x" +"'\gx" "''x" +# This will fail for double quote. +"'\"x" "'\"x\"'" +"@'x" "@'x'" +"@#\'x" "@'x'#" +"'\x" "''x" +"abc'" "abc'" +"abc\\'x" "abc\\'x" +"u'Привет'" "u'Привет'" +"u'string'" "u'string'" +let g:delimitMate_autoclose = 0 +"'x" "'x" +"''x" "'x'" +"'''x" "''x" +"''\x" "x" +"@''x" "@'x'" +"@#\''x" "@'x'#" +let g:delimitMate_expand_space = 1 +let g:delimitMate_autoclose = 1 +"'\x" "' x'" +let g:delimitMate_expand_inside_quotes = 1 +"'\x" "' x '" +"'\\x" "'x'" +"abc\\''\x" "abc\\' x'" +let g:delimitMate_autoclose = 0 +"''\\x" "'x'" +let g:delimitMate_autoclose = 1 +# Handle backspace gracefully. +set backspace= +"'\a\x" "'x'" +set backspace=2 +set cpo=ces$ +"'x" "'x'" +# Make sure smart quote works beyond first column. +" 'x" " 'x'" +# smart quote, check fo char on the right. +"a\b\'" "a 'b" +# Make sure we jump over a quote on the right. #89. +"('test'x" "('test'x)" +# Duplicate whole line when inserting quote at bol #105 +"}\'" "''}" +"'\abc '" "'abc '" +"''abc '" "''abc ''" +# Nesting quotes: +let g:delimitMate_nesting_quotes = split(g:delimitMate_quotes, '\s\+') +"'''x" "'''x'''" +"''''x" "''''x''''" +"''x" "''x" +"'x" "'x'" +unlet g:delimitMate_nesting_quotes +# expand iabbreviations +iabb def ghi +"def'" "ghi'" +let g:delimitMate_smart_quotes = '\w\%#\_.' +"xyz'x" "xyz'x" +"xyz 'x" "xyz 'x'" +let g:delimitMate_smart_quotes = '\s\%#\_.' +"abc'x" "abc'x'" +"abc 'x" "abc 'x" +# let's try the negated form +let g:delimitMate_smart_quotes = '!\w\%#\_.' +"cba'x" "cba'x'" +"cba 'x" "cba 'x" +let g:delimitMate_smart_quotes = '!\s\%#\_.' +"zyx'x" "zyx'x" +"zyx 'x" "zyx 'x'" +unlet g:delimitMate_smart_quotes +"'\\" "''" diff --git a/bundle/delimitMate/test/autoclose_quotes.vim b/bundle/delimitMate/test/autoclose_quotes.vim new file mode 100644 index 000000000..e80c60c4c --- /dev/null +++ b/bundle/delimitMate/test/autoclose_quotes.vim @@ -0,0 +1,47 @@ +"let g:delimitMate_quotes = '" '' ` ” « |' +let g:delimitMate_quotes = '" '' ` « |' +let lines = readfile(expand(':t:r').'.txt') +call vimtest#StartTap() +let testsnumber = len(filter(copy(lines), 'v:val =~ ''^"''')) +let itemsnumber = len(split(g:delimitMate_quotes, ' ')) +call vimtap#Plan(testsnumber * itemsnumber) +let reload = 1 +let tcount = 1 +let linenr = 0 +for item in lines + let linenr += 1 + if item =~ '^#\|^\s*$' + " A comment or empty line. + continue + endif + if item !~ '^"' + " A command. + exec item + call vimtap#Diag(item) + let reload = 1 + continue + endif + if reload + DelimitMateReload + call vimtap#Diag('DelimitMateReload') + let reload = 0 + endif + let quotes = split(g:delimitMate_quotes, '\s') + for quote in quotes + if vimtap#Skip(1, tcount != 26, "This test is invalid for double quote.") + let tcount += 1 + continue + endif + let [input, output] = split(item, '"\%(\\.\|[^\\"]\)*"\zs\s*\ze"\%(\\.\|[^\\"]\)*"') + let input_q = substitute(input,"'" , escape(escape(quote, '"'), '\'), 'g') + let output_q = substitute(output,"'" , escape(escape(quote, '"'), '\'), 'g') + %d + exec 'normal i'.eval(input_q)."\" + if quote == '”' + call vimtap#Todo(1) + endif + call vimtap#Is(getline('.'), eval(output_q), 'Line '.linenr.': '.eval(substitute(input_q, '\\<', '<','g'))) + let tcount += 1 + endfor +endfor +call vimtest#Quit() diff --git a/bundle/delimitMate/test/eol_marker.vim b/bundle/delimitMate/test/eol_marker.vim new file mode 100644 index 000000000..d41435576 --- /dev/null +++ b/bundle/delimitMate/test/eol_marker.vim @@ -0,0 +1,44 @@ +let g:delimitMate_expand_cr = 1 +let g:delimitMate_eol_marker = ';' +call vimtest#StartTap() +call vimtap#Plan(8) +" NOTE: Do not forget to update the plan ^ +let g:delimitMate_insert_eol_marker = 0 +DelimitMateReload +normal i( +call vimtap#Is(getline(1), '()', 'value = 1, case 1') +%d _ +exec "normal i(\x" +call vimtap#Like(join(getline(1,line('$')), "\"), + \ '^(\n\s*x\n)$', ' "normal i(\x", Value = 2, case 2') +let g:delimitMate_insert_eol_marker = 1 +DelimitMateReload +%d _ +normal i( +call vimtap#Is(getline(1), '();', '"normal i(", value = 1, case 1') +%d _ +exec "normal i(\x" +call vimtap#Like(join(getline(1,line('$')), "\"), + \ '^(\n\s*x\n);$', '"normal i(\x", Value = 2, case 2') +%d _ +let g:delimitMate_insert_eol_marker = 2 +DelimitMateReload +normal i( +call vimtap#Is(getline(1), '()', '"normal i(", Value = 2, case 1') +%d _ +exec "normal i(\x" +call vimtap#Like(join(getline(1,line('$')), "\"), + \ '^(\n\s*x\n);$', '"normal i(\x", Value = 2, case 2') + +%d _ +exec "normal i{(\x" +call vimtap#Like(join(getline(1,line('$')), "\"), + \ '^{(\n\s*x\n)};$', ' "normal i{(\x", Value = 2, case 3') + +%d _ +exec "normal i;\I{(\x" +call vimtap#Like(join(getline(1,line('$')), "\"), + \ '^{(\n\s*x\n)};$', ' "normal i{(\x", Value = 2, case 4') + +" End: quit vim. +call vimtest#Quit() diff --git a/bundle/delimitMate/test/expand_cr.txt b/bundle/delimitMate/test/expand_cr.txt new file mode 100644 index 000000000..b7aa982a0 --- /dev/null +++ b/bundle/delimitMate/test/expand_cr.txt @@ -0,0 +1,96 @@ +# +%d +filetype indent on +set bs=2 et sts=4 sw=4 ft=javascript +call setline(1, '$(document).ready(function() {})') +DelimitMateReload +exec "normal 31|i\x\" +================================================================================ +$(document).ready(function() { + x +}) +-------------------------------------------------------------------------------- +# Issue #95 +new +let b:delimitMate_jump_expansion = 1 +DelimitMateReload +exec "normal i(\test)x" +================================================================================ +( +test +)x +-------------------------------------------------------------------------------- +# Remove CR expansion on BS +%d +exec "normal i(\\x" +================================================================================ +(x) +-------------------------------------------------------------------------------- +# Consider indentation with BS inside an empty CR expansion. +%d +exec "normal i( \\\x" +================================================================================ +(x) +-------------------------------------------------------------------------------- +# Conflict with indentation settings (cindent). Issue #95 +se cindent +call setline(1, ['sub foo {',' while (1) {', ' ', ' }', '}']) +call cursor(3, 8) +normal a}x +================================================================================ +sub foo { + while (1) { + + }x +} +-------------------------------------------------------------------------------- +%d +call setline(1, '"{bracketed}') +normal A"x +================================================================================ +"{bracketed}"x +-------------------------------------------------------------------------------- +# Syntax folding enabled by autocmd breaks expansion. But ti can't be tested +# with :normal +new +autocmd InsertEnter * let w:fdm=&foldmethod | setl foldmethod=manual +autocmd InsertLeave * let &foldmethod = w:fdm +set foldmethod=marker +set foldmarker={,} +set foldlevel=0 +set backspace=2 +exec "normal iabc {\x" +================================================================================ +abc { + x +} +-------------------------------------------------------------------------------- +# expand_cr != 2 +%d_ +call setline(1, 'abc(def)') +exec "normal $i\x" +================================================================================ +abc(def + x) +-------------------------------------------------------------------------------- +# expand_cr == 2 +%d_ +let delimitMate_expand_cr = 2 +DelimitMateReload +call setline(1, 'abc(def)') +exec "normal $i\x" +================================================================================ +abc(def + x + ) +-------------------------------------------------------------------------------- +# Play nice with smartindent +%d_ +set all& +set smartindent +exec "normal $i{\x" +================================================================================ +{ + x +} +-------------------------------------------------------------------------------- diff --git a/bundle/delimitMate/test/expand_cr.vim b/bundle/delimitMate/test/expand_cr.vim new file mode 100644 index 000000000..bd4e32a49 --- /dev/null +++ b/bundle/delimitMate/test/expand_cr.vim @@ -0,0 +1,55 @@ +let g:delimitMate_expand_cr = 1 +"DelimitMateReload +let lines = readfile(expand(':t:r').'.txt') +call vimtest#StartTap() +let testsnumber = len(filter(copy(lines), 'v:val =~ ''^=\{80}$''')) +call vimtap#Plan(testsnumber) +let tcount = 1 +let expect = 0 +let evaluate = 0 +let commands = [] +let header = '' +for item in lines + if item =~ '^=\{80}$' + let expect = 1 + let expected = [] + continue + endif + + if item =~ '^#' && expect == 0 + " A comment. + let header = empty(header) ? item[1:] : 'Lines should match.' + continue + endif + if item =~ '^\s*$' && expect == 0 + " An empty line. + continue + endif + if ! expect + " A command. + call add(commands, item) + exec item + "call vimtap#Diag(item) + continue + endif + if item =~ '^-\{80}$' + let expect = 0 + endif + if expect + call add(expected, item) + continue + endif + let lines = getline(1, line('$')) + let passed = lines == expected + echom string(lines) + echom string(expected) + call vimtap#Is(lines, expected, header) + echom string(commands) + for cmd in commands + call vimtap#Diag(cmd) + endfor + let commands = [] + let header = '' + let tcount += 1 +endfor +call vimtest#Quit() diff --git a/bundle/delimitMate/test/expand_space.txt b/bundle/delimitMate/test/expand_space.txt new file mode 100644 index 000000000..39f8748d8 --- /dev/null +++ b/bundle/delimitMate/test/expand_space.txt @@ -0,0 +1,8 @@ +# Issue #95 +new +let b:delimitMate_jump_expansion = 1 +DelimitMateReload +exec "normal i( test)x" +================================================================================ +( test )x +-------------------------------------------------------------------------------- diff --git a/bundle/delimitMate/test/expand_space.vim b/bundle/delimitMate/test/expand_space.vim new file mode 100644 index 000000000..d306721a3 --- /dev/null +++ b/bundle/delimitMate/test/expand_space.vim @@ -0,0 +1,42 @@ +let g:delimitMate_expand_space = 1 +"DelimitMateReload +let lines = readfile(expand(':t:r').'.txt') +call vimtest#StartTap() +let testsnumber = len(filter(copy(lines), 'v:val =~ ''^=\{80}$''')) +call vimtap#Plan(testsnumber) +let tcount = 1 +let expect = 0 +let evaluate = 0 +for item in lines + if item =~ '^=\{80}$' + let expect = 1 + let expected = [] + continue + endif + + if item =~ '^#\|^\s*$' && expect == 0 + " A comment or empty line. + continue + endif + if ! expect + " A command. + exec item + call vimtap#Diag(item) + continue + endif + if item =~ '^-\{80}$' + let expect = 0 + endif + if expect + call add(expected, item) + continue + endif + let lines = getline(1, line('$')) + let passed = lines == expected + echom string(lines) + echom string(expected) + call vimtap#Ok(passed, string(expected) . + \ (passed ? ' =' : ' !') . '= ' . string(lines)) + let tcount += 1 +endfor +call vimtest#Quit() diff --git a/bundle/delimitMate/test/first_buffer_no_ft.vim b/bundle/delimitMate/test/first_buffer_no_ft.vim new file mode 100644 index 000000000..dc5225c3d --- /dev/null +++ b/bundle/delimitMate/test/first_buffer_no_ft.vim @@ -0,0 +1,8 @@ +let g:delimitMate_expand_cr = 1 +let g:delimitMate_eol_marker = ';' +call vimtest#StartTap() +call vimtap#Plan(1) +call vimtap#Like(maparg('(', 'i'), 'delimitMate(', 'Mappings defined for the first buffer without filetype set.') +call vimtest#Quit() + + diff --git a/bundle/deoplete-dictionary/LICENSE b/bundle/deoplete-dictionary/LICENSE new file mode 100644 index 000000000..dafdb025c --- /dev/null +++ b/bundle/deoplete-dictionary/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Shougo Matsushita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/bundle/deoplete-dictionary/README.md b/bundle/deoplete-dictionary/README.md new file mode 100644 index 000000000..e35646c09 --- /dev/null +++ b/bundle/deoplete-dictionary/README.md @@ -0,0 +1,29 @@ +# deoplete-dictionary +deoplete source for dictionary + +## Description +This source collects "keyword_patterns" keywords from 'dictionary'. + +Note: It uses buffer-local 'dictionary' set up. + +Note: It also supports directory. + +rank: 100 + +## Configuration examples + +```vim +" Sample configuration for dictionary source with multiple +" dictionary files. +setlocal dictionary+=/usr/share/dict/words +setlocal dictionary+=/usr/share/dict/american-english +" Remove this if you'd like to use fuzzy search +call deoplete#custom#source( +\ 'dictionary', 'matchers', ['matcher_head']) +" If dictionary is already sorted, no need to sort it again. +call deoplete#custom#source( +\ 'dictionary', 'sorters', []) +" Do not complete too short words +call deoplete#custom#source( +\ 'dictionary', 'min_pattern_length', 4) +``` diff --git a/bundle/deoplete-dictionary/rplugin/python3/deoplete/source/dictionary.py b/bundle/deoplete-dictionary/rplugin/python3/deoplete/source/dictionary.py new file mode 100644 index 000000000..c882d57ce --- /dev/null +++ b/bundle/deoplete-dictionary/rplugin/python3/deoplete/source/dictionary.py @@ -0,0 +1,65 @@ +# ============================================================================ +# FILE: dictionary.py +# AUTHOR: Shougo Matsushita +# License: MIT license +# ============================================================================ + +from os import scandir +from os.path import getmtime, exists, isdir +from collections import namedtuple + +from deoplete.base.source import Base +from deoplete.util import expand + +DictCacheItem = namedtuple('DictCacheItem', 'mtime candidates') + + +class Source(Base): + + def __init__(self, vim): + super().__init__(vim) + + self.name = 'dictionary' + self.mark = '[D]' + self.events = ['InsertEnter'] + + self._cache = {} + + def on_event(self, context): + self._make_cache(context) + + def gather_candidates(self, context): + if not self._cache: + self._make_cache(context) + + candidates = [] + for filename in [x for x in self._get_dictionaries(context) + if x in self._cache]: + candidates.append(self._cache[filename].candidates) + return {'sorted_candidates': candidates} + + def _make_cache(self, context): + for filename in self._get_dictionaries(context): + mtime = getmtime(filename) + if filename in self._cache and self._cache[ + filename].mtime == mtime: + continue + with open(filename, 'r', errors='replace') as f: + self._cache[filename] = DictCacheItem( + mtime, [{'word': x} for x in sorted( + (x.strip() for x in f), key=str.lower)] + ) + + def _get_dictionaries(self, context): + dict_opt = self.get_buf_option('dictionary') + if not dict_opt: + return [] + + dicts = [] + for d in [expand(x) for x in dict_opt.split(',') if exists(x)]: + if isdir(d): + with scandir(d) as it: + dicts += [x.path for x in it if x.is_file()] + else: + dicts.append(d) + return dicts diff --git a/bundle/editorconfig-vim/.appveyor.yml b/bundle/editorconfig-vim/.appveyor.yml new file mode 100644 index 000000000..630fc2f46 --- /dev/null +++ b/bundle/editorconfig-vim/.appveyor.yml @@ -0,0 +1,107 @@ +# appveyor.yml for editorconfig-vim. Currently only tests the core. +# Modified from https://github.com/ppalaga/ec4j/commit/1c849658fb189cd95bc41af95acd43b4f0d75a48 +# +# Copyright (c) 2017--2019 Angelo Zerr and other contributors as +# indicated by the @author tags. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @author Chris White (cxw42) - Adapted to editorconfig-vim + +# === When to build === +# See https://www.appveyor.com/docs/how-to/filtering-commits/ + +skip_commits: + message: /\[minor\]/ + files: + - '**/*.md' + +# === Build matrix === + +# Win is default; Ubuntu is override. See +# https://www.appveyor.com/blog/2018/04/25/specialized-build-matrix-configuration-in-appveyor/ +image: + - Visual Studio 2013 + - Ubuntu1604 + +# === How to build === + +cache: + - C:\vim -> .appveyor.yml, tests\fetch-vim.bat + +environment: + VIM_EXE: C:\vim\vim\vim80\vim.exe + +for: + # Don't run the Windows build if the commit message includes "[ci-linux]" + - + matrix: + only: + - image: Visual Studio 2013 + skip_commits: + message: /\[ci-linux\]/ + + # Platform-specific configuration for Ubuntu + - + matrix: + only: + - image: Ubuntu1604 + # $APPVEYOR_BUILD_FOLDER isn't expanded in the environment section + # here, so I can't set $VIM_EXE the way I want to. Instead, + # I set $VIM_EXE in the sh-specific install steps below. + environment: + VIM_EXE: UNDEFINED + cache: + - $APPVEYOR_BUILD_FOLDER/vim -> .appveyor.yml, tests/fetch-vim.sh + + # Plus, don't run Ubuntu if the commit message includes [ci-win] + skip_commits: + message: /\[ci-win\]/ + +install: + # Ubuntu-specific setup. These carry forward to the build_script. + - sh: export VIM_EXE="$APPVEYOR_BUILD_FOLDER/vim/bin/vim" + - sh: export PATH="$PATH":$APPVEYOR_BUILD_FOLDER/vim/bin + - sh: echo "$VIM_EXE , $PATH" + + # Cross-platform - test the core + - cmake --version + - git submodule update --init --recursive + - cmd: tests\fetch-vim + - sh: tests/fetch-vim.sh + +build_script: + # Build the core tests + - cd tests + - cd core + - mkdir build + - cd build + - cmake .. + +# Note on multicore testing: +# Two cores are available per https://help.appveyor.com/discussions/questions/11179-how-many-cores-and-threads-can-be-used-in-free-appveyor-build . +# However, using -j2 seems to make each job take much longer. + +test_script: + # Run the core tests + - ctest . --output-on-failure -C Debug + + # CTestCustom specifies skipping UTF-8 tests on Windows. + - cmd: echo "Reminder - did not try UTF-8" + - sh: echo "Reminder - tried UTF-8" + +on_failure: + - echo "failed" + - cmd: type tests\core\build\Testing\Temporary\LastTest.log + - sh: cat tests/core/build/Testing/Temporary/LastTest.log + diff --git a/bundle/editorconfig-vim/.editorconfig b/bundle/editorconfig-vim/.editorconfig new file mode 100644 index 000000000..7eed9e111 --- /dev/null +++ b/bundle/editorconfig-vim/.editorconfig @@ -0,0 +1,27 @@ +root = true + +[*] +end_of_line = lf +charset = utf-8 +max_line_length = 80 + +[*.{vim,sh}] +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 80 + +[*.rb] +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 120 + +[*.yml] +indent_style = space +indent_size = 2 + +[*.{bat,vbs,ps1}] +end_of_line = CRLF diff --git a/bundle/editorconfig-vim/.gitignore b/bundle/editorconfig-vim/.gitignore new file mode 100644 index 000000000..1d86f15e1 --- /dev/null +++ b/bundle/editorconfig-vim/.gitignore @@ -0,0 +1,8 @@ +tags +tests/**/build +tests/**/.bundle + +# Editor backup files +*.swp +*~ +~* diff --git a/bundle/editorconfig-vim/.gitmodules b/bundle/editorconfig-vim/.gitmodules new file mode 100644 index 000000000..8cf01bc40 --- /dev/null +++ b/bundle/editorconfig-vim/.gitmodules @@ -0,0 +1,6 @@ +[submodule "plugin_tests"] + path = tests/plugin/spec/plugin_tests + url = https://github.com/editorconfig/editorconfig-plugin-tests.git +[submodule "core_tests"] + path = tests/core/tests + url = https://github.com/editorconfig/editorconfig-core-test.git diff --git a/bundle/editorconfig-vim/.travis.yml b/bundle/editorconfig-vim/.travis.yml new file mode 100644 index 000000000..1eaad3b34 --- /dev/null +++ b/bundle/editorconfig-vim/.travis.yml @@ -0,0 +1,30 @@ +# Make sure xvfb works - https://docs.travis-ci.com/user/gui-and-headless-browsers/#using-xvfb-directly +dist: trusty + +matrix: + include: + - name: "plugin" + env: TEST_WHICH=plugin + language: ruby + rvm: + - 2.2.4 + gemfile: tests/plugin/Gemfile + - name: "core" + env: TEST_WHICH=core + +addons: + apt: + packages: + - vim-gtk + +before_script: + - "export DISPLAY=:99.0" + - "sh -e /etc/init.d/xvfb start" + +script: + ./tests/travis-test.sh + +notifications: + email: + on_success: change + on_failure: always diff --git a/bundle/editorconfig-vim/CONTRIBUTORS b/bundle/editorconfig-vim/CONTRIBUTORS new file mode 100644 index 000000000..b799668c8 --- /dev/null +++ b/bundle/editorconfig-vim/CONTRIBUTORS @@ -0,0 +1,6 @@ +Contributors to the EditorConfig Vim Plugin: + +Hong Xu +Trey Hunner +Kent Frazier +Chris White diff --git a/bundle/editorconfig-vim/LICENSE b/bundle/editorconfig-vim/LICENSE new file mode 100644 index 000000000..ed9286e0a --- /dev/null +++ b/bundle/editorconfig-vim/LICENSE @@ -0,0 +1,26 @@ +Unless otherwise stated, all files are distributed under the Simplified BSD +license included below. + +Copyright (c) 2011-2019 EditorConfig Team +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/bundle/editorconfig-vim/LICENSE.PSF b/bundle/editorconfig-vim/LICENSE.PSF new file mode 100644 index 000000000..36eb8e0d3 --- /dev/null +++ b/bundle/editorconfig-vim/LICENSE.PSF @@ -0,0 +1,53 @@ +Some code in editorconfig-vim is derived from code licensed under the +PSF license. The following is the text of that license, retrieved 2019-05-05 +from https://docs.python.org/2.6/license.html#terms-and-conditions-for-accessing-or-otherwise-using-python + +PSF LICENSE AGREEMENT FOR PYTHON 2.6.9 + +1. This LICENSE AGREEMENT is between the Python Software Foundation +(``PSF''), and the Individual or Organization (``Licensee'') accessing and +otherwise using Python 2.6.9 software in source or binary form and its +associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 2.6.9 +alone or in any derivative version, provided, however, that PSF's +License Agreement and PSF's notice of copyright, i.e., ``Copyright (c) +2001-2010 Python Software Foundation; All Rights Reserved'' are +retained in Python 2.6.9 alone or in any derivative version prepared +by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 2.6.9 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 2.6.9. + +4. PSF is making Python 2.6.9 available to Licensee on an ``AS IS'' +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. +BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY +REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY +PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.6.9 WILL NOT INFRINGE +ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +2.6.9 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.6.9, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python 2.6.9, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + +# vi: set ft=: diff --git a/bundle/editorconfig-vim/README.md b/bundle/editorconfig-vim/README.md new file mode 100644 index 000000000..9631f3e5b --- /dev/null +++ b/bundle/editorconfig-vim/README.md @@ -0,0 +1,133 @@ +# EditorConfig Vim Plugin + +[![Travis Build Status](https://img.shields.io/travis/cxw42/editorconfig-vim.svg?logo=travis)](https://travis-ci.org/editorconfig/editorconfig-vim) +[![Appveyor Build Status](https://img.shields.io/appveyor/ci/cxw42/editorconfig-vim.svg?logo=appveyor)](https://ci.appveyor.com/project/cxw42/editorconfig-vim) + +This is an [EditorConfig][] plugin for Vim. This plugin can be found on both +[GitHub][] and [Vim online][]. + +## Installation + +To install this plugin, you can use one of the following ways: + +### Install with the archive + +Download the [archive][] and extract it into your Vim runtime directory +(`~/.vim` on UNIX/Linux and `$VIM_INSTALLATION_FOLDER\vimfiles` on windows). +You should have 3 sub-directories in this runtime directory now: "autoload", +"doc" and "plugin". + +### Install as Vim8 plugin + +Install as a Vim 8 plugin. Note `local` can be any name, but some path +element must be present. On Windows, instead of `~/.vim` use +`$VIM_INSTALLATION_FOLDER\vimfiles`. +```shell +mkdir -p ~/.vim/pack/local/start +cd ~/.vim/pack/local/start +git clone https://github.com/editorconfig/editorconfig-vim.git +``` + +### Install with [pathogen][] + +Use pathogen (the git repository of this plugin is +https://github.com/editorconfig/editorconfig-vim.git) + +### Install with [Vundle][] + +Use Vundle by adding to your `.vimrc` Vundle plugins section: + +```viml +Plugin 'editorconfig/editorconfig-vim' +``` + +Then remember to call `:PluginInstall`. + +### Install with [vim-plug][] + +Use vim-plug by adding to your `.vimrc` in your plugin section: + +```viml +Plug 'editorconfig/editorconfig-vim' +``` + +Then remember to call `:PlugInstall`. + +### No external editorconfig core library is required + +Previous versions of this plugin also required a Python "core". +The core included the code to parse `.editorconfig` files. +This plugin **includes** the core, so you don't need to download the +core separately. + +## Supported properties + +The EditorConfig Vim plugin supports the following EditorConfig [properties][]: + +* `indent_style` +* `indent_size` +* `tab_width` +* `end_of_line` +* `charset` +* `insert_final_newline` (Feature +fixendofline (available on Vim 7.4.785+) or [PreserveNoEOL][] is required for this property) +* `trim_trailing_whitespace` +* `max_line_length` +* `root` (only used by EditorConfig core) + +## Recommended Options + +All of the options which are supported are documented in [editorconfig.txt][] +and can be viewed by executing the following: `:help editorconfig`. You may +need to execute `:helptags ALL` so that Vim is aware of editorconfig.txt. + +#### Excluded patterns. + +To ensure that this plugin works well with [Tim Pope's fugitive][], use the +following patterns array: + +```viml +let g:EditorConfig_exclude_patterns = ['fugitive://.*'] +``` + +If you wanted to avoid loading EditorConfig for any remote files over ssh: + +```viml +let g:EditorConfig_exclude_patterns = ['scp://.*'] +``` + +Of course these two items could be combined into the following: + +```viml +let g:EditorConfig_exclude_patterns = ['fugitive://.*', 'scp://.*'] +``` + +#### Disable rules + +You might want to override some project-specific EditorConfig rules in global +or local vimrc in some cases, e.g., to resolve conflicts of trailing whitespace +trimming and buffer autosaving. + +```viml +let g:EditorConfig_disable_rules = ['trim_trailing_whitespace'] +``` + +You are able to disable any supported EditorConfig properties. + +## Bugs and Feature Requests + +Feel free to submit bugs, feature requests, and other issues to the +[issue tracker][]. Be sure you have read the [contribution guideline][]! + +[EditorConfig]: http://editorconfig.org +[GitHub]: https://github.com/editorconfig/editorconfig-vim +[PreserveNoEOL]: http://www.vim.org/scripts/script.php?script_id=4550 +[Tim Pope's fugitive]: https://github.com/tpope/vim-fugitive +[Vim online]: http://www.vim.org/scripts/script.php?script_id=3934 +[Vundle]: https://github.com/gmarik/Vundle.vim +[archive]: https://github.com/editorconfig/editorconfig-vim/archive/master.zip +[contribution guideline]: https://github.com/editorconfig/editorconfig/blob/master/CONTRIBUTING.md#submitting-an-issue +[issue tracker]: https://github.com/editorconfig/editorconfig-vim/issues +[pathogen]: https://github.com/tpope/vim-pathogen +[properties]: http://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties +[editorconfig.txt]: https://github.com/editorconfig/editorconfig-vim/blob/master/doc/editorconfig.txt +[vim-plug]: https://github.com/junegunn/vim-plug diff --git a/bundle/editorconfig-vim/autoload/editorconfig.vim b/bundle/editorconfig-vim/autoload/editorconfig.vim new file mode 100644 index 000000000..1f61a3300 --- /dev/null +++ b/bundle/editorconfig-vim/autoload/editorconfig.vim @@ -0,0 +1,60 @@ +" autoload/editorconfig.vim: EditorConfig native Vimscript plugin +" Copyright (c) 2011-2019 EditorConfig Team +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" 1. Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" 2. Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. +" + +if v:version < 700 + finish +endif + +let s:saved_cpo = &cpo +set cpo&vim + +" {{{1 variables +let s:hook_list = [] + +function! editorconfig#AddNewHook(func) " {{{1 + " Add a new hook + + call add(s:hook_list, a:func) +endfunction + +function! editorconfig#ApplyHooks(config) abort " {{{1 + " apply hooks + + for Hook in s:hook_list + let l:hook_ret = Hook(a:config) + + if type(l:hook_ret) != type(0) && l:hook_ret != 0 + " TODO print some debug info here + endif + endfor +endfunction + +" }}} + +let &cpo = s:saved_cpo +unlet! s:saved_cpo + +" vim: fdm=marker fdc=3 diff --git a/bundle/editorconfig-vim/autoload/editorconfig_core.vim b/bundle/editorconfig-vim/autoload/editorconfig_core.vim new file mode 100644 index 000000000..6885e17cf --- /dev/null +++ b/bundle/editorconfig-vim/autoload/editorconfig_core.vim @@ -0,0 +1,147 @@ +" autoload/editorconfig_core.vim: top-level functions for +" editorconfig-core-vimscript and editorconfig-vim. + +" Copyright (c) 2018-2020 EditorConfig Team, including Chris White {{{1 +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" 1. Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" 2. Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. }}}1 + +let s:saved_cpo = &cpo +set cpo&vim + +" Variables {{{1 + +" Note: we create this variable in every script that accesses it. Normally, I +" would put this in plugin/editorconfig.vim. However, in some of my tests, +" the command-line testing environment did not load plugin/* in the normal +" way. Therefore, I do the check everywhere so I don't have to special-case +" the command line. + +if !exists('g:editorconfig_core_vimscript_debug') + let g:editorconfig_core_vimscript_debug = 0 +endif +" }}}1 + +" The latest version of the specification that we support. +" See discussion at https://github.com/editorconfig/editorconfig/issues/395 +function! editorconfig_core#version() + return [0,13,0] +endfunction + +" === CLI =============================================================== {{{1 + +" For use from the command line. Output settings for in_name to +" the buffer named out_name. If an optional argument is provided, it is the +" name of the config file to use (default '.editorconfig'). +" TODO support multiple files +" +" filename (if any) +" @param names {Dictionary} The names of the files to use for this run +" - output [required] Where the editorconfig settings should be written +" - target [required] A string or list of strings to process. Each +" must be a full path. +" - dump [optional] If present, write debug info to this file +" @param job {Dictionary} What to do - same format as the input of +" editorconfig_core#handler#get_configurations(), +" except without the target member. + +function! editorconfig_core#currbuf_cli(names, job) " out_name, in_name, ... + let l:output = [] + + " Preprocess the job + let l:job = deepcopy(a:job) + + if has_key(l:job, 'version') " string to list + let l:ver = split(editorconfig_core#util#strip(l:job.version), '\v\.') + for l:idx in range(len(l:ver)) + let l:ver[l:idx] = str2nr(l:ver[l:idx]) + endfor + + let l:job.version = l:ver + endif + + " TODO provide version output from here instead of the shell script +" if string(a:names) ==? 'version' +" return +" endif +" + if type(a:names) != type({}) || type(a:job) != type({}) + throw 'Need two Dictionary arguments' + endif + + if has_key(a:names, 'dump') + execute 'redir! > ' . fnameescape(a:names.dump) + echom 'Names: ' . string(a:names) + echom 'Job: ' . string(l:job) + let g:editorconfig_core_vimscript_debug = 1 + endif + + if type(a:names['target']) == type([]) + let l:targets = a:names.target + else + let l:targets = [a:names.target] + endif + + for l:target in l:targets + + " Pre-process quoting weirdness so we are more flexible in the face + " of CMake+CTest+BAT+Powershell quoting. + + " Permit wrapping in double-quotes + let l:target = substitute(l:target, '\v^"(.*)"$', '\1', '') + + " Permit empty ('') entries in l:targets + if strlen(l:target)<1 + continue + endif + + if has_key(a:names, 'dump') + echom 'Trying: ' . string(l:target) + endif + + let l:job.target = l:target + let l:options = editorconfig_core#handler#get_configurations(l:job) + + if has_key(a:names, 'dump') + echom 'editorconfig_core#currbuf_cli result: ' . string(l:options) + endif + + if len(l:targets) > 1 + let l:output += [ '[' . l:target . ']' ] + endif + + for [ l:key, l:value ] in items(l:options) + let l:output += [ l:key . '=' . l:value ] + endfor + + endfor "foreach target + + " Write the output file + call writefile(l:output, a:names.output) +endfunction "editorconfig_core#currbuf_cli + +" }}}1 + +let &cpo = s:saved_cpo +unlet! s:saved_cpo + +" vi: set fdm=marker fo-=ro: diff --git a/bundle/editorconfig-vim/autoload/editorconfig_core/fnmatch.vim b/bundle/editorconfig-vim/autoload/editorconfig_core/fnmatch.vim new file mode 100644 index 000000000..6f60db5d0 --- /dev/null +++ b/bundle/editorconfig-vim/autoload/editorconfig_core/fnmatch.vim @@ -0,0 +1,465 @@ +" autoload/editorconfig_core/fnmatch.vim: Globbing for +" editorconfig-vim. Ported from the Python core's fnmatch.py. + +" Copyright (c) 2012-2019 EditorConfig Team {{{1 +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" 1. Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" 2. Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. }}}1 + +"Filename matching with shell patterns. +" +"fnmatch(FILENAME, PATH, PATTERN) matches according to the local convention. +"fnmatchcase(FILENAME, PATH, PATTERN) always takes case in account. +" +"The functions operate by translating the pattern into a regular +"expression. They cache the compiled regular expressions for speed. +" +"The function translate(PATTERN) returns a regular expression +"corresponding to PATTERN. (It does not compile it.) + +let s:saved_cpo = &cpo +set cpo&vim + +" variables {{{1 +if !exists('g:editorconfig_core_vimscript_debug') + let g:editorconfig_core_vimscript_debug = 0 +endif +" }}}1 +" === Regexes =========================================================== {{{1 +let s:LEFT_BRACE = '\v%(^|[^\\])\{' +"LEFT_BRACE = re.compile( +" r""" +" +" (?: ^ | [^\\] ) # Beginning of string or a character besides "\" +" +" \{ # "{" +" +" """, re.VERBOSE +") + +let s:RIGHT_BRACE = '\v%(^|[^\\])\}' +"RIGHT_BRACE = re.compile( +" r""" +" +" (?: ^ | [^\\] ) # Beginning of string or a character besides "\" +" +" \} # "}" +" +" """, re.VERBOSE +") + +let s:NUMERIC_RANGE = '\v([+-]?\d+)' . '\.\.' . '([+-]?\d+)' +"NUMERIC_RANGE = re.compile( +" r""" +" ( # Capture a number +" [+-] ? # Zero or one "+" or "-" characters +" \d + # One or more digits +" ) +" +" \.\. # ".." +" +" ( # Capture a number +" [+-] ? # Zero or one "+" or "-" characters +" \d + # One or more digits +" ) +" """, re.VERBOSE +") + +" }}}1 +" === Internal functions ================================================ {{{1 + +" Dump the bytes of a:text. For debugging use. +function! s:dump_bytes(text) + let l:idx=0 + while l:idx < strlen(a:text) + let l:byte_val = char2nr(a:text[l:idx]) + echom printf('%10s%-5d%02x %s', '', l:idx, l:byte_val, + \ a:text[l:idx]) + let l:idx+=1 + endwhile +endfunction "s:dump_bytes + +" Dump the characters of a:text and their codepoints. For debugging use. +function! s:dump_chars(text) + let l:chars = split(a:text, '\zs') + let l:idx = 0 + let l:out1 = '' + let l:out2 = '' + while l:idx < len(l:chars) + let l:char = l:chars[l:idx] + let l:out1 .= printf('%5s', l:char) + let l:out2 .= printf('%5x', char2nr(l:char)) + let l:idx+=1 + endwhile + + echom l:out1 + echom l:out2 +endfunction "s:dump_chars + +" }}}1 +" === Translating globs to patterns ===================================== {{{1 + +" Used by s:re_escape: backslash-escape any character below U+0080; +" replace all others with a %U escape. +" See https://vi.stackexchange.com/a/19617/1430 by yours truly +" (https://vi.stackexchange.com/users/1430/cxw). +unlockvar s:replacement_expr +let s:replacement_expr = + \ '\=' . + \ '((char2nr(submatch(1)) >= 128) ? ' . + \ 'printf("%%U%08x", char2nr(submatch(1))) : ' . + \ '("\\" . submatch(1))' . + \ ')' +lockvar s:replacement_expr + +" Escaper for very-magic regexes +function! s:re_escape(text) + return substitute(a:text, '\v([^0-9a-zA-Z_])', s:replacement_expr, 'g') +endfunction + +"def translate(pat, nested=0): +" Translate a shell PATTERN to a regular expression. +" There is no way to quote meta-characters. +function! editorconfig_core#fnmatch#translate(pat, ...) + let l:nested = 0 + if a:0 + let l:nested = a:1 + endif + + if g:editorconfig_core_vimscript_debug + echom '- fnmatch#translate: pattern ' . a:pat + echom printf( + \ '- %d chars', strlen(substitute(a:pat, ".", "x", "g"))) + call s:dump_chars(a:pat) + endif + + let l:pat = a:pat " TODO remove if we wind up not needing this + + " Note: the Python sets MULTILINE and DOTALL, but Vim has \_. + " instead of DOTALL, and \_^ / \_$ instead of MULTILINE. + + let l:is_escaped = 0 + + " Find out whether the pattern has balanced braces. + let l:left_braces=[] + let l:right_braces=[] + call substitute(l:pat, s:LEFT_BRACE, '\=add(l:left_braces, 1)', 'g') + call substitute(l:pat, s:RIGHT_BRACE, '\=add(l:right_braces, 1)', 'g') + " Thanks to http://jeromebelleman.gitlab.io/posts/productivity/vimsub/ + let l:matching_braces = (len(l:left_braces) == len(l:right_braces)) + + " Unicode support (#2). Indexing l:pat[l:index] returns bytes, per + " https://github.com/neovim/neovim/issues/68#issue-28114985 . + " Instead, use split() per vimdoc to break the input string into an + " array of *characters*, and process that. + let l:characters = split(l:pat, '\zs') + + let l:index = 0 " character index + let l:length = len(l:characters) + let l:brace_level = 0 + let l:in_brackets = 0 + + let l:result = '' + let l:numeric_groups = [] + while l:index < l:length + let l:current_char = l:characters[l:index] + let l:index += 1 + +" if g:editorconfig_core_vimscript_debug +" echom ' - fnmatch#translate: ' . l:current_char . '@' . +" \ (l:index-1) . '; result ' . l:result +" endif + + if l:current_char ==# '*' + let l:pos = l:index + if l:pos < l:length && l:characters[l:pos] ==# '*' + let l:result .= '\_.*' + let l:index += 1 " skip the second star + else + let l:result .= '[^/]*' + endif + + elseif l:current_char ==# '?' + let l:result .= '\_[^/]' + + elseif l:current_char ==# '[' + if l:in_brackets + let l:result .= '\[' + else + let l:pos = l:index + let l:has_slash = 0 + while l:pos < l:length && l:characters[l:pos] != ']' + if l:characters[l:pos] ==# '/' && l:characters[l:pos-1] !=# '\' + let has_slash = 1 + break + endif + let l:pos += 1 + endwhile + if l:has_slash + " POSIX IEEE 1003.1-2017 sec. 2.13.3: '/' cannot occur + " in a bracket expression, so [/] matches a literal + " three-character string '[' . '/' . ']'. + let l:result .= '\[' + \ . s:re_escape(join(l:characters[l:index : l:pos-1], '')) + \ . '\/' + " escape the slash + let l:index = l:pos + 1 + " resume after the slash + else + if l:index < l:length && l:characters[l:index] =~# '\v%(\^|\!)' + let l:index += 1 + let l:result .= '[^' + else + let l:result .= '[' + endif + let l:in_brackets = 1 + endif + endif + + elseif l:current_char ==# '-' + if l:in_brackets + let l:result .= l:current_char + else + let l:result .= '\' . l:current_char + endif + + elseif l:current_char ==# ']' + if l:in_brackets && !l:is_escaped + let l:result .= ']' + let l:in_brackets = 0 + elseif l:is_escaped + let l:result .= '\]' + let l:is_escaped = 0 + else + let l:result .= '\]' + endif + + elseif l:current_char ==# '{' + let l:pos = l:index + let l:has_comma = 0 + while l:pos < l:length && (l:characters[l:pos] !=# '}' || l:is_escaped) + if l:characters[l:pos] ==# ',' && ! l:is_escaped + let l:has_comma = 1 + break + endif + let l:is_escaped = l:characters[l:pos] ==# '\' && ! l:is_escaped + let l:pos += 1 + endwhile + if ! l:has_comma && l:pos < l:length + let l:num_range = + \ matchlist(join(l:characters[l:index : l:pos-1], ''), + \ s:NUMERIC_RANGE) + if len(l:num_range) > 0 " Remember the ranges + call add(l:numeric_groups, [ 0+l:num_range[1], 0+l:num_range[2] ]) + let l:result .= '([+-]?\d+)' + else + let l:inner_xlat = editorconfig_core#fnmatch#translate( + \ join(l:characters[l:index : l:pos-1], ''), 1) + let l:inner_result = l:inner_xlat[0] + let l:inner_groups = l:inner_xlat[1] + let l:result .= '\{' . l:inner_result . '\}' + let l:numeric_groups += l:inner_groups + endif + let l:index = l:pos + 1 + elseif l:matching_braces + let l:result .= '%(' + let l:brace_level += 1 + else + let l:result .= '\{' + endif + + elseif l:current_char ==# ',' + if l:brace_level > 0 && ! l:is_escaped + let l:result .= '|' + else + let l:result .= '\,' + endif + + elseif l:current_char ==# '}' + if l:brace_level > 0 && ! l:is_escaped + let l:result .= ')' + let l:brace_level -= 1 + else + let l:result .= '\}' + endif + + elseif l:current_char ==# '/' + if join(l:characters[l:index : (l:index + 2)], '') ==# '**/' + let l:result .= '%(/|/\_.*/)' + let l:index += 3 + else + let l:result .= '\/' + endif + + elseif l:current_char != '\' + let l:result .= s:re_escape(l:current_char) + endif + + if l:current_char ==# '\' + if l:is_escaped + let l:result .= s:re_escape(l:current_char) + endif + let l:is_escaped = ! l:is_escaped + else + let l:is_escaped = 0 + endif + + endwhile + + if ! l:nested + let l:result .= '\_$' + endif + + return [l:result, l:numeric_groups] +endfunction " #editorconfig_core#fnmatch#translate + +let s:_cache = {} +function! s:cached_translate(pat) + if ! has_key(s:_cache, a:pat) + "regex = re.compile(res) + let s:_cache[a:pat] = + \ editorconfig_core#fnmatch#translate(a:pat) + " we don't compile the regex + endif + return s:_cache[a:pat] +endfunction " cached_translate + +" }}}1 +" === Matching functions ================================================ {{{1 + +function! editorconfig_core#fnmatch#fnmatch(name, path, pattern) +"def fnmatch(name, pat): +" """Test whether FILENAME matches PATH/PATTERN. +" +" Patterns are Unix shell style: +" +" - ``*`` matches everything except path separator +" - ``**`` matches everything +" - ``?`` matches any single character +" - ``[seq]`` matches any character in seq +" - ``[!seq]`` matches any char not in seq +" - ``{s1,s2,s3}`` matches any of the strings given (separated by commas) +" +" An initial period in FILENAME is not special. +" Both FILENAME and PATTERN are first case-normalized +" if the operating system requires it. +" If you don't want this, use fnmatchcase(FILENAME, PATTERN). +" """ +" + " Note: This throws away the backslash in '\.txt' on Cygwin, but that + " makes sense since it's Windows under the hood. + " We don't care about shellslash since we're going to change backslashes + " to slashes in just a moment anyway. + let l:localname = fnamemodify(a:name, ':p') + + if editorconfig_core#util#is_win() " normalize + let l:localname = substitute(tolower(l:localname), '\v\\', '/', 'g') + let l:path = substitute(tolower(a:path), '\v\\', '/', 'g') + let l:pattern = tolower(a:pattern) + else + let l:localname = l:localname + let l:path = a:path + let l:pattern = a:pattern + endif + + if g:editorconfig_core_vimscript_debug + echom '- fnmatch#fnmatch testing <' . l:localname . '> against <' . + \ l:pattern . '> wrt <' . l:path . '>' + endif + + return editorconfig_core#fnmatch#fnmatchcase(l:localname, l:path, l:pattern) +endfunction " fnmatch + +function! editorconfig_core#fnmatch#fnmatchcase(name, path, pattern) +"def fnmatchcase(name, pat): +" """Test whether FILENAME matches PATH/PATTERN, including case. +" +" This is a version of fnmatch() which doesn't case-normalize +" its arguments. +" """ +" + let [regex, num_groups] = s:cached_translate(a:pattern) + + let l:escaped_path = s:re_escape(a:path) + let l:regex = '\v' . l:escaped_path . l:regex + + if g:editorconfig_core_vimscript_debug + echom '- fnmatch#fnmatchcase: regex ' . l:regex + call s:dump_chars(l:regex) + echom '- fnmatch#fnmatchcase: checking ' . a:name + call s:dump_chars(a:name) + endif + + let l:match_groups = matchlist(a:name, l:regex)[1:] " [0] = full match + + if g:editorconfig_core_vimscript_debug + echom printf(' Got %d matches', len(l:match_groups)) + endif + + if len(l:match_groups) == 0 + return 0 + endif + + " Check numeric ranges + let pattern_matched = 1 + for l:idx in range(0,len(l:match_groups)) + let l:num = l:match_groups[l:idx] + if l:num ==# '' + break + endif + + let [min_num, max_num] = num_groups[l:idx] + if (min_num > (0+l:num)) || ((0+l:num) > max_num) + let pattern_matched = 0 + break + endif + + " Reject leading zeros without sign. This is very odd --- + " see editorconfig/editorconfig#371. + if match(l:num, '\v^0') != -1 + let pattern_matched = 0 + break + endif + endfor + + if g:editorconfig_core_vimscript_debug + echom '- fnmatch#fnmatchcase: ' . (pattern_matched ? 'matched' : 'did not match') + endif + + return pattern_matched +endfunction " fnmatchcase + +" }}}1 +" === Copyright notices ================================================= {{{1 +" Based on code from fnmatch.py file distributed with Python 2.6. +" Portions Copyright (c) 2001-2010 Python Software Foundation; +" All Rights Reserved. Licensed under PSF License (see LICENSE.PSF file). +" +" Changes to original fnmatch: +" +" - translate function supports ``*`` and ``**`` similarly to fnmatch C library +" }}}1 + +let &cpo = s:saved_cpo +unlet! s:saved_cpo + +" vi: set fdm=marker: diff --git a/bundle/editorconfig-vim/autoload/editorconfig_core/handler.vim b/bundle/editorconfig-vim/autoload/editorconfig_core/handler.vim new file mode 100644 index 000000000..c9a66e169 --- /dev/null +++ b/bundle/editorconfig-vim/autoload/editorconfig_core/handler.vim @@ -0,0 +1,183 @@ +" autoload/editorconfig_core/handler.vim: Main worker for +" editorconfig-core-vimscript and editorconfig-vim. +" Modified from the Python core's handler.py. + +" Copyright (c) 2012-2019 EditorConfig Team {{{1 +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" 1. Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" 2. Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. }}}1 + +let s:saved_cpo = &cpo +set cpo&vim + +" Return full filepath for filename in each directory in and above path. {{{1 +" Input path must be an absolute path. +" TODO shellslash/shellescape? +function! s:get_filenames(path, config_filename) + let l:path = a:path + let l:path_list = [] + while 1 + call add(l:path_list, editorconfig_core#util#path_join(l:path, a:config_filename)) + let l:newpath = fnamemodify(l:path, ':h') + if l:path ==? l:newpath || !strlen(l:path) + break + endif + let l:path = l:newpath + endwhile + return l:path_list +endfunction " get_filenames + +" }}}1 +" === Main ============================================================== {{{1 + +" Find EditorConfig files and return all options matching target_filename. +" Throws on failure. +" @param job {Dictionary} required 'target'; optional 'config' and 'version' +function! editorconfig_core#handler#get_configurations(job) + " TODO? support VERSION checks? + +" Special exceptions that may be raised by this function include: +" - ``VersionError``: self.version is invalid EditorConfig version +" - ``PathError``: self.filepath is not a valid absolute filepath +" - ``ParsingError``: improperly formatted EditorConfig file found + + let l:job = deepcopy(a:job) + if has_key(l:job, 'config') + let l:config_filename = l:job.config + else + let l:config_filename = '.editorconfig' + let l:job.config = l:config_filename + endif + + if has_key(l:job, 'version') + let l:version = l:job.version + else + let l:version = editorconfig_core#version() + let l:job.version = l:version + endif + + let l:target_filename = l:job.target + + "echom 'Beginning job ' . string(l:job) + if !s:check_assertions(l:job) + throw "Assertions failed" + endif + + let l:fullpath = fnamemodify(l:target_filename,':p') + let l:path = fnamemodify(l:fullpath, ':h') + let l:conf_files = s:get_filenames(l:path, l:config_filename) + + " echom 'fullpath ' . l:fullpath + " echom 'path ' . l:path + + let l:retval = {} + + " Attempt to find and parse every EditorConfig file in filetree + for l:conf_fn in l:conf_files + "echom 'Trying ' . l:conf_fn + let l:parsed = editorconfig_core#ini#read_ini_file(l:conf_fn, l:target_filename) + if !has_key(l:parsed, 'options') + continue + endif + " echom ' Has options' + + " Merge new EditorConfig file's options into current options + let l:old_options = l:retval + let l:retval = l:parsed.options + " echom 'Old options ' . string(l:old_options) + " echom 'New options ' . string(l:retval) + call extend(l:retval, l:old_options, 'force') + + " Stop parsing if parsed file has a ``root = true`` option + if l:parsed.root + break + endif + endfor + + call s:preprocess_values(l:job, l:retval) + return l:retval +endfunction " get_configurations + +function! s:check_assertions(job) +" TODO +" """Raise error if filepath or version have invalid values""" + +" # Raise ``PathError`` if filepath isn't an absolute path +" if not os.path.isabs(self.filepath): +" raise PathError("Input file must be a full path name.") + + " Throw if version specified is greater than current + let l:v = a:job.version + let l:us = editorconfig_core#version() + " echom 'Comparing requested version ' . string(l:v) . + " \ ' to our version ' . string(l:us) + if l:v[0] > l:us[0] || l:v[1] > l:us[1] || l:v[2] > l:us[2] + throw 'Required version ' . string(l:v) . + \ ' is greater than the current version ' . string(l:us) + endif + + return 1 " All OK if we got here +endfunction " check_assertions + +" }}}1 + +" Preprocess option values for consumption by plugins. {{{1 +" Modifies its argument in place. +function! s:preprocess_values(job, opts) + + " Lowercase option value for certain options + for l:name in ['end_of_line', 'indent_style', 'indent_size', + \ 'insert_final_newline', 'trim_trailing_whitespace', + \ 'charset'] + if has_key(a:opts, l:name) + let a:opts[l:name] = tolower(a:opts[l:name]) + endif + endfor + + " Set indent_size to "tab" if indent_size is unspecified and + " indent_style is set to "tab", provided we are at least v0.10.0. + if get(a:opts, 'indent_style', '') ==? "tab" && + \ !has_key(a:opts, 'indent_size') && + \ ( a:job.version[0]>0 || a:job.version[1] >=10 ) + let a:opts['indent_size'] = 'tab' + endif + + " Set tab_width to indent_size if indent_size is specified and + " tab_width is unspecified + if has_key(a:opts, 'indent_size') && !has_key(a:opts, 'tab_width') && + \ get(a:opts, 'indent_size', '') !=? "tab" + let a:opts['tab_width'] = a:opts['indent_size'] + endif + + " Set indent_size to tab_width if indent_size is "tab" + if has_key(a:opts, 'indent_size') && has_key(a:opts, 'tab_width') && + \ get(a:opts, 'indent_size', '') ==? "tab" + let a:opts['indent_size'] = a:opts['tab_width'] + endif +endfunction " preprocess_values + +" }}}1 + +let &cpo = s:saved_cpo +unlet! s:saved_cpo + +" vi: set fdm=marker fdl=1: diff --git a/bundle/editorconfig-vim/autoload/editorconfig_core/ini.vim b/bundle/editorconfig-vim/autoload/editorconfig_core/ini.vim new file mode 100644 index 000000000..279b381d3 --- /dev/null +++ b/bundle/editorconfig-vim/autoload/editorconfig_core/ini.vim @@ -0,0 +1,273 @@ +" autoload/editorconfig_core/ini.vim: Config-file parser for +" editorconfig-core-vimscript and editorconfig-vim. +" Modifed from the Python core's ini.py. + +" Copyright (c) 2012-2019 EditorConfig Team {{{2 +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" 1. Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" 2. Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. }}}2 + +let s:saved_cpo = &cpo +set cpo&vim + +" variables {{{2 +if !exists('g:editorconfig_core_vimscript_debug') + let g:editorconfig_core_vimscript_debug = 0 +endif +" }}}2 +" === Constants, including regexes ====================================== {{{2 +" Regular expressions for parsing section headers and options. +" Allow ``]`` and escaped ``;`` and ``#`` characters in section headers. +" In fact, allow \ to escape any single character - it needs to cover at +" least \ * ? [ ! ] { }. +unlockvar s:SECTCRE s:OPTCRE s:MAX_SECTION_NAME s:MAX_PROPERTY_NAME s:MAX_PROPERTY_VALUE +let s:SECTCRE = '\v^\s*\[(%([^\\#;]|\\.)+)\]' + +" Regular expression for parsing option name/values. +" Allow any amount of whitespaces, followed by separator +" (either ``:`` or ``=``), followed by any amount of whitespace and then +" any characters to eol +let s:OPTCRE = '\v\s*([^:=[:space:]][^:=]*)\s*([:=])\s*(.*)$' + +let s:MAX_SECTION_NAME = 4096 +let s:MAX_PROPERTY_NAME = 50 +let s:MAX_PROPERTY_VALUE = 255 + +lockvar s:SECTCRE s:OPTCRE s:MAX_SECTION_NAME s:MAX_PROPERTY_NAME s:MAX_PROPERTY_VALUE + +" }}}2 +" === Main ============================================================== {{{1 + +" Read \p config_filename and return the options applicable to +" \p target_filename. This is the main entry point in this file. +function! editorconfig_core#ini#read_ini_file(config_filename, target_filename) + let l:oldenc = &encoding + + if !filereadable(a:config_filename) + return {} + endif + + try " so &encoding will always be reset + let &encoding = 'utf-8' " so readfile() will strip BOM + let l:lines = readfile(a:config_filename) + let result = s:parse(a:config_filename, a:target_filename, l:lines) + catch + let &encoding = l:oldenc + " rethrow, but with a prefix since throw 'Vim...' fails. + throw 'Could not read editorconfig file at ' . v:throwpoint . ': ' . string(v:exception) + endtry + + let &encoding = l:oldenc + return result +endfunction + +function! s:parse(config_filename, target_filename, lines) +" Parse a sectioned setup file. +" The sections in setup file contains a title line at the top, +" indicated by a name in square brackets (`[]'), plus key/value +" options lines, indicated by `name: value' format lines. +" Continuations are represented by an embedded newline then +" leading whitespace. Blank lines, lines beginning with a '#', +" and just about everything else are ignored. + + let l:in_section = 0 + let l:matching_section = 0 + let l:optname = '' + let l:lineno = 0 + let l:e = [] " Errors, if any + + let l:options = {} " Options applicable to this file + let l:is_root = 0 " Whether a:config_filename declares root=true + + while 1 + if l:lineno == len(a:lines) + break + endif + + let l:line = a:lines[l:lineno] + let l:lineno = l:lineno + 1 + + " comment or blank line? + if editorconfig_core#util#strip(l:line) ==# '' + continue + endif + if l:line =~# '\v^[#;]' + continue + endif + + " is it a section header? + if g:editorconfig_core_vimscript_debug + echom "Header? <" . l:line . ">" + endif + + let l:mo = matchlist(l:line, s:SECTCRE) + if len(l:mo) + let l:sectname = l:mo[1] + let l:in_section = 1 + if strlen(l:sectname) > s:MAX_SECTION_NAME + " Section name too long => ignore the section + let l:matching_section = 0 + else + let l:matching_section = s:matches_filename( + \ a:config_filename, a:target_filename, l:sectname) + endif + + if g:editorconfig_core_vimscript_debug + echom 'In section ' . l:sectname . ', which ' . + \ (l:matching_section ? 'matches' : 'does not match') + \ ' file ' . a:target_filename . ' (config ' . + \ a:config_filename . ')' + endif + + " So sections can't start with a continuation line + let l:optname = '' + + " Is it an option line? + else + let l:mo = matchlist(l:line, s:OPTCRE) + if len(l:mo) + let l:optname = mo[1] + let l:optval = mo[3] + + if g:editorconfig_core_vimscript_debug + echom printf('Saw raw opt <%s>=<%s>', l:optname, l:optval) + endif + + if l:optval =~# '\v[;#]' + " ';' and '#' are comment delimiters only if + " preceded by a spacing character + let l:m = matchlist(l:optval, '\v(.{-})\s[;#]') + if len(l:m) + let l:optval = l:m[1] + endif + + " ; and # can be escaped with backslash. + let l:optval = substitute(l:optval, '\v\\([;#])', '\1', 'g') + + endif + let l:optval = editorconfig_core#util#strip(l:optval) + " allow empty values + if l:optval ==? '""' + let l:optval = '' + endif + let l:optname = s:optionxform(l:optname) + if !l:in_section && optname ==? 'root' + let l:is_root = (optval ==? 'true') + endif + if g:editorconfig_core_vimscript_debug + echom printf('Saw opt <%s>=<%s>', l:optname, l:optval) + endif + + if l:matching_section && + \ strlen(l:optname) <= s:MAX_PROPERTY_NAME && + \ strlen(l:optval) <= s:MAX_PROPERTY_VALUE + let l:options[l:optname] = l:optval + endif + else + " a non-fatal parsing error occurred. set up the + " exception but keep going. the exception will be + " raised at the end of the file and will contain a + " list of all bogus lines + call add(e, "Parse error in '" . a:config_filename . "' at line " . + \ l:lineno . ": '" . l:line . "'") + endif + endif + endwhile + + " if any parsing errors occurred, raise an exception + if len(l:e) + throw string(l:e) + endif + + return {'root': l:is_root, 'options': l:options} +endfunction! + +" }}}1 +" === Helpers =========================================================== {{{1 + +" Preprocess option names +function! s:optionxform(optionstr) + let l:result = substitute(a:optionstr, '\v\s+$', '', 'g') " rstrip + return tolower(l:result) +endfunction + +" Return true if \p glob matches \p target_filename +function! s:matches_filename(config_filename, target_filename, glob) +" config_dirname = normpath(dirname(config_filename)).replace(sep, '/') + let l:config_dirname = fnamemodify(a:config_filename, ':p:h') . '/' + + if editorconfig_core#util#is_win() + " Regardless of whether shellslash is set, make everything slashes + let l:config_dirname = + \ tolower(substitute(l:config_dirname, '\v\\', '/', 'g')) + endif + + let l:glob = substitute(a:glob, '\v\\([#;])', '\1', 'g') + + " Take account of the path to the editorconfig file. + " editorconfig-core-c/src/lib/editorconfig.c says: + " "Pattern would be: /dir/of/editorconfig/file[double_star]/[section] if + " section does not contain '/', or /dir/of/editorconfig/file[section] + " if section starts with a '/', or /dir/of/editorconfig/file/[section] if + " section contains '/' but does not start with '/'." + + if stridx(l:glob, '/') != -1 " contains a slash + if l:glob[0] ==# '/' + let l:glob = l:glob[1:] " trim leading slash + endif +" This will be done by fnmatch +" let l:glob = l:config_dirname . l:glob + else " does not contain a slash + let l:config_dirname = l:config_dirname[:-2] + " Trim trailing slash + let l:glob = '**/' . l:glob + endif + + if g:editorconfig_core_vimscript_debug + echom '- ini#matches_filename: checking <' . a:target_filename . + \ '> against <' . l:glob . '> with respect to config file <' . + \ a:config_filename . '>' + echom '- ini#matches_filename: config_dirname is ' . l:config_dirname + endif + + return editorconfig_core#fnmatch#fnmatch(a:target_filename, + \ l:config_dirname, l:glob) +endfunction " matches_filename + +" }}}1 +" === Copyright notices ================================================= {{{2 +" Based on code from ConfigParser.py file distributed with Python 2.6. +" Portions Copyright (c) 2001-2010 Python Software Foundation; +" All Rights Reserved. Licensed under PSF License (see LICENSE.PSF file). +" +" Changes to original ConfigParser: +" +" - Special characters can be used in section names +" - Octothorpe can be used for comments (not just at beginning of line) +" - Only track INI options in sections that match target filename +" - Stop parsing files with when ``root = true`` is found +" }}}2 + +let &cpo = s:saved_cpo +unlet! s:saved_cpo + +" vi: set fdm=marker fdl=1: diff --git a/bundle/editorconfig-vim/autoload/editorconfig_core/util.vim b/bundle/editorconfig-vim/autoload/editorconfig_core/util.vim new file mode 100644 index 000000000..c4df04af1 --- /dev/null +++ b/bundle/editorconfig-vim/autoload/editorconfig_core/util.vim @@ -0,0 +1,84 @@ +" util.vim: part of editorconfig-core-vimscript and editorconfig-vim. +" Copyright (c) 2018-2019 EditorConfig Team, including Chris White {{{1 +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" 1. Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" 2. Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. }}}1 + +let s:saved_cpo = &cpo +set cpo&vim + +" A verbatim copy of ingo#fs#path#Separator() {{{1 +" from https://github.com/vim-scripts/ingo-library/blob/558132e2221db3af26dc2f2c6756d092d48a459f/autoload/ingo/fs/path.vim +" distributed under the Vim license. +function! editorconfig_core#util#Separator() + return (exists('+shellslash') && ! &shellslash ? '\' : '/') +endfunction " }}}1 + +" path_join(): ('a','b')->'a/b'; ('a/','b')->'a/b'. {{{1 +function! editorconfig_core#util#path_join(a, b) + " TODO shellescape/shellslash? + "echom 'Joining <' . a:a . '> and <' . a:b . '>' + "echom 'Length is ' . strlen(a:a) + "echom 'Last char is ' . char2nr(a:a[-1]) + if a:a !~# '\v%(\/|\\)$' + return a:a . editorconfig_core#util#Separator() . a:b + else + return a:a . a:b + endif +endfunction " }}}1 + +" is_win() by xolox {{{1 +" The following function is modified from +" https://github.com/xolox/vim-misc/blob/master/autoload/xolox/misc/os.vim +" Copyright (c) 2015 Peter Odding +" +" Permission is hereby granted, free of charge, to any person obtaining a copy +" of this software and associated documentation files (the "Software"), to deal +" in the Software without restriction, including without limitation the rights +" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +" copies of the Software, and to permit persons to whom the Software is +" furnished to do so, subject to the following conditions: +" +" The above copyright notice and this permission notice shall be included in all +" copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +" SOFTWARE. +function! editorconfig_core#util#is_win() + " Returns 1 (true) when on Microsoft Windows, 0 (false) otherwise. + return has('win16') || has('win32') || has('win64') +endfunction " }}}1 + +" strip() {{{1 +function! editorconfig_core#util#strip(s) + return substitute(a:s, '\v^\s+|\s+$','','g') +endfunction " }}}1 + +let &cpo = s:saved_cpo +unlet! s:saved_cpo + +" vi: set fdm=marker: diff --git a/bundle/editorconfig-vim/doc/editorconfig.txt b/bundle/editorconfig-vim/doc/editorconfig.txt new file mode 100644 index 000000000..aef577cca --- /dev/null +++ b/bundle/editorconfig-vim/doc/editorconfig.txt @@ -0,0 +1,190 @@ +*editorconfig.txt* + +File: editorconfig.txt +Version: 1.1.1 +Maintainer: EditorConfig Team +Description: EditorConfig vim plugin + +License: + Copyright (c) 2011-2019 EditorConfig Team + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + +CONTENTS~ + *editorconfig-contents* +---------------------------------------------------------------------------- +1. Overview |editorconfig-overview| +2. Installation |editorconfig-installation| +3. Commands |editorconfig-commands| +4. Settings |editorconfig-settings| +5. Advanced |editorconfig-advanced| + + +OVERVIEW~ + *editorconfig-overview* +---------------------------------------------------------------------------- +This is the EditorConfig plugin for vim. + + +INSTALLATION~ + *editorconfig-installation* +---------------------------------------------------------------------------- +Follow the instructions in the README.md file to install this plugin. + +COMMANDS~ + *editorconfig-commands* +---------------------------------------------------------------------------- + + *:EditorConfigReload* +Command: + :EditorConfigReload + +Reload the EditorConfig conf files. When `.editorconfig` files are modified, +this command could prevent you to reload the current edited file to load the +new configuration. + +SETTINGS~ + *editorconfig-settings* +---------------------------------------------------------------------------- + *g:EditorConfig_core_mode* +Specify the mode of EditorConfig core. Generally it is OK to leave this option +empty. Currently, the supported modes are "vim_core" (default) and +"external_command". + + vim_core: Use the included VimScript EditorConfig Core. + external_command: Run external EditorConfig Core. + +If "g:EditorConfig_core_mode" is not specified, this plugin will automatically +choose "vim_core". + +If you choose "external_command" mode, you must also set +|g:EditorConfig_exec_path|. + +Changes to "g:EditorConfig_core_mode" will not take effect until Vim +is restarted. + + *g:EditorConfig_exclude_patterns* +This is a list contains file path patterns which will be ignored by +EditorConfig plugin. When the path of the opened buffer (i.e. +"expand('%:p')") matches any of the patterns in the list, EditorConfig will +not load for this file. The default is an empty list. + +Example: Avoid loading EditorConfig for any remote files over ssh +> + let g:EditorConfig_exclude_patterns = ['scp://.*'] +< + + *g:EditorConfig_exec_path* +The file path to the EditorConfig core executable. You can set this value in +your |vimrc| like this: +> + let g:EditorConfig_exec_path = 'Path to your EditorConfig Core executable' +< +The default value is empty. + +If "g:EditorConfig_exec_path" is not set, the plugin will use the "vim_core" +mode regardless of the setting of |g:EditorConfig_core_mode|. + +Changes to "g:EditorConfig_exec_path" will not take effect until Vim +is restarted. + + *g:EditorConfig_max_line_indicator* +The way to show the line where the maximal length is reached. Accepted values +are "line", "fill", otherwise there will be no max line indicator. + + "line": the right column of the max line length column will be + highlighted, made possible by setting 'colorcolumn' to + "max_line_length + 1". + + "fill": all the columns to the right of the max line length column + will be highlighted, made possible by setting 'colorcolumn' + to a list of numbers starting from "max_line_length + 1" to + the number of columns on the screen. + + "exceeding": the right column of the max line length column will be + highlighted on lines that exceed the max line length, made + possible by adding a match for the ColorColumn group. + + "none": no max line length indicator will be shown. This is the + recommended value when you do not want any indicator to be + shown, but values other than "line" or "fill" would also work + as "none". + +To set this option, add any of the following lines to your |vimrc| file: +> + let g:EditorConfig_max_line_indicator = "line" + let g:EditorConfig_max_line_indicator = "fill" + let g:EditorConfig_max_line_indicator = "exceeding" + let g:EditorConfig_max_line_indicator = "none" +< +The default value is "line". + + *g:EditorConfig_preserve_formatoptions* +Set this to 1 if you don't want your formatoptions modified when +max_line_length is set: +> + let g:EditorConfig_preserve_formatoptions = 1 +< +This option defaults to 0. + + *g:EditorConfig_verbose* +Set this to 1 if you want debug info printed: +> + let g:EditorConfig_verbose = 1 +< + +ADVANCED~ + *editorconfig-advanced* +---------------------------------------------------------------------------- + *editorconfig-hook* + *EditorConfig#AddNewHook()* +While this plugin offers several builtin supported properties (as mentioned +here: https://github.com/editorconfig/editorconfig-vim#supported-properties), +we are also able to add our own hooks to support additional EditorConfig +properties, including those not in the EditorConfig standard. For example, we +are working on an Objective-C project, and all our "*.m" files should be +Objective-C source files. However, vim sometimes detect "*.m" files as MATLAB +source files, which causes incorrect syntax highlighting, code indentation, +etc. To solve the case, we could write the following code into the |vimrc| +file: +> + function! FiletypeHook(config) + if has_key(a:config, 'vim_filetype') + let &filetype = a:config['vim_filetype'] + endif + + return 0 " Return 0 to show no error happened + endfunction + + call editorconfig#AddNewHook(function('FiletypeHook')) +< +And add the following code to your .editorconfig file: +> + [*.m] + vim_filetype = objc +< +Then try to open an Objective-C file, you will find the |filetype| is set to +"objc". + +vim:ft=help:tw=78 diff --git a/bundle/editorconfig-vim/mkzip.sh b/bundle/editorconfig-vim/mkzip.sh new file mode 100644 index 000000000..811724ca2 --- /dev/null +++ b/bundle/editorconfig-vim/mkzip.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +zip -r editorconfig-vim-$*.zip plugin/* autoload/* doc/* diff --git a/bundle/editorconfig-vim/plugin/editorconfig.vim b/bundle/editorconfig-vim/plugin/editorconfig.vim new file mode 100644 index 000000000..de218de83 --- /dev/null +++ b/bundle/editorconfig-vim/plugin/editorconfig.vim @@ -0,0 +1,514 @@ +" plugin/editorconfig.vim: EditorConfig native Vimscript plugin file +" Copyright (c) 2011-2019 EditorConfig Team +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" 1. Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" 2. Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. +" + +if v:version < 700 + finish +endif + +" check whether this script is already loaded +if exists("g:loaded_EditorConfig") + finish +endif +let g:loaded_EditorConfig = 1 + +let s:saved_cpo = &cpo +set cpo&vim + +" variables {{{1 + +" Make sure the globals all exist +if !exists('g:EditorConfig_exec_path') + let g:EditorConfig_exec_path = '' +endif + +if !exists('g:EditorConfig_verbose') + let g:EditorConfig_verbose = 0 +endif + +if !exists('g:EditorConfig_preserve_formatoptions') + let g:EditorConfig_preserve_formatoptions = 0 +endif + +if !exists('g:EditorConfig_max_line_indicator') + let g:EditorConfig_max_line_indicator = 'line' +endif + +if !exists('g:EditorConfig_exclude_patterns') + let g:EditorConfig_exclude_patterns = [] +endif + +if !exists('g:EditorConfig_disable_rules') + let g:EditorConfig_disable_rules = [] +endif + +" Copy some of the globals into script variables --- changes to these +" globals won't affect the plugin until the plugin is reloaded. +if exists('g:EditorConfig_core_mode') && !empty(g:EditorConfig_core_mode) + let s:editorconfig_core_mode = g:EditorConfig_core_mode +else + let s:editorconfig_core_mode = '' +endif + +if exists('g:EditorConfig_exec_path') && !empty(g:EditorConfig_exec_path) + let s:editorconfig_exec_path = g:EditorConfig_exec_path +else + let s:editorconfig_exec_path = '' +endif + +let s:initialized = 0 + +" }}}1 + +" shellslash handling {{{1 +function! s:DisableShellSlash() " {{{2 + " disable shellslash for proper escaping of Windows paths + + " In Windows, 'shellslash' also changes the behavior of 'shellescape'. + " It makes 'shellescape' behave like in UNIX environment. So ':setl + " noshellslash' before evaluating 'shellescape' and restore the + " settings afterwards when 'shell' does not contain 'sh' somewhere. + if has('win32') && empty(matchstr(&shell, 'sh')) + let s:old_shellslash = &l:shellslash + setlocal noshellslash + endif +endfunction " }}}2 + +function! s:ResetShellSlash() " {{{2 + " reset shellslash to the user-set value, if any + if exists('s:old_shellslash') + let &l:shellslash = s:old_shellslash + unlet! s:old_shellslash + endif +endfunction " }}}2 +" }}}1 + +" Mode initialization functions {{{1 + +function! s:InitializeVimCore() +" Initialize vim core. Returns 1 on failure; 0 on success +" At the moment, all we need to do is to check that it is installed. + try + let l:vim_core_ver = editorconfig_core#version() + catch + return 1 + endtry + return 0 +endfunction + +function! s:InitializeExternalCommand() +" Initialize external_command mode + + if empty(s:editorconfig_exec_path) + echo 'Please specify a g:EditorConfig_exec_path' + return 1 + endif + + if g:EditorConfig_verbose + echo 'Checking for external command ' . s:editorconfig_exec_path . ' ...' + endif + + if !executable(s:editorconfig_exec_path) + echo 'File ' . s:editorconfig_exec_path . ' is not executable.' + return 1 + endif + + return 0 +endfunction +" }}}1 + +function! s:Initialize() " Initialize the plugin. {{{1 + " Returns truthy on error, falsy on success. + + if empty(s:editorconfig_core_mode) + let s:editorconfig_core_mode = 'vim_core' " Default core choice + endif + + if s:editorconfig_core_mode ==? 'external_command' + if s:InitializeExternalCommand() + echohl WarningMsg + echo 'EditorConfig: Failed to initialize external_command mode. ' . + \ 'Falling back to vim_core mode.' + echohl None + let s:editorconfig_core_mode = 'vim_core' + endif + endif + + if s:editorconfig_core_mode ==? 'vim_core' + if s:InitializeVimCore() + echohl ErrorMsg + echo 'EditorConfig: Failed to initialize vim_core mode. ' . + \ 'The plugin will not function.' + echohl None + return 1 + endif + + elseif s:editorconfig_core_mode ==? 'external_command' + " Nothing to do here, but this elseif is required to avoid + " external_command falling into the else clause. + + else " neither external_command nor vim_core + echohl ErrorMsg + echo "EditorConfig: I don't know how to use mode " . s:editorconfig_core_mode + echohl None + return 1 + endif + + let s:initialized = 1 + return 0 +endfunction " }}}1 + +function! s:GetFilenames(path, filename) " {{{1 +" Yield full filepath for filename in each directory in and above path + + let l:path_list = [] + let l:path = a:path + while 1 + let l:path_list += [l:path . '/' . a:filename] + let l:newpath = fnamemodify(l:path, ':h') + if l:path == l:newpath + break + endif + let l:path = l:newpath + endwhile + return l:path_list +endfunction " }}}1 + +function! s:UseConfigFiles() abort " Apply config to the current buffer {{{1 + let l:buffer_name = expand('%:p') + " ignore buffers without a name + if empty(l:buffer_name) + return + endif + + " Check if any .editorconfig does exist + let l:conf_files = s:GetFilenames(expand('%:p:h'), '.editorconfig') + let l:conf_found = 0 + for conf_file in conf_files + if filereadable(conf_file) + let l:conf_found = 1 + break + endif + endfor + if !l:conf_found + return + endif + + if !s:initialized + if s:Initialize() + return + endif + endif + + if g:EditorConfig_verbose + echo 'Applying EditorConfig ' . s:editorconfig_core_mode . + \ ' on file "' . l:buffer_name . '"' + endif + + " Ignore specific patterns + for pattern in g:EditorConfig_exclude_patterns + if l:buffer_name =~ pattern + return + endif + endfor + + if s:editorconfig_core_mode ==? 'vim_core' + call s:UseConfigFiles_VimCore() + elseif s:editorconfig_core_mode ==? 'external_command' + call s:UseConfigFiles_ExternalCommand() + else + echohl Error | + \ echo "Unknown EditorConfig Core: " . + \ s:editorconfig_core_mode | + \ echohl None + endif +endfunction " }}}1 + +" Custom commands, and autoloading {{{1 + +" Autocommands, and function to enable/disable the plugin {{{2 +function! s:EditorConfigEnable(should_enable) + augroup editorconfig + autocmd! + if a:should_enable + autocmd BufNewFile,BufReadPost,BufFilePost * call s:UseConfigFiles() + endif + augroup END +endfunction + +" }}}2 + +" Commands {{{2 +command! EditorConfigEnable call s:EditorConfigEnable(1) +command! EditorConfigDisable call s:EditorConfigEnable(0) + +command! EditorConfigReload call s:UseConfigFiles() " Reload EditorConfig files +" }}}2 + +" On startup, enable the autocommands +call s:EditorConfigEnable(1) + +" Always set the filetype for .editorconfig files +augroup editorconfig_dosini + autocmd! + autocmd BufNewFile,BufRead .editorconfig set filetype=dosini +augroup END + +" }}}1 + +" UseConfigFiles function for different modes {{{1 + +function! s:UseConfigFiles_VimCore() +" Use the vimscript EditorConfig core + try + let l:config = editorconfig_core#handler#get_configurations( + \ { 'target': expand('%:p') } ) + call s:ApplyConfig(l:config) + return 0 " success + catch + return 1 " failure + endtry +endfunction + +function! s:UseConfigFiles_ExternalCommand() +" Use external EditorConfig core (e.g., the C core) + + call s:DisableShellSlash() + let l:exec_path = shellescape(s:editorconfig_exec_path) + call s:ResetShellSlash() + + call s:SpawnExternalParser(l:exec_path) +endfunction + +function! s:SpawnExternalParser(cmd) " {{{2 +" Spawn external EditorConfig. Used by s:UseConfigFiles_ExternalCommand() + + let l:cmd = a:cmd + + if empty(l:cmd) + throw 'No cmd provided' + endif + + let l:config = {} + + call s:DisableShellSlash() + let l:cmd = l:cmd . ' ' . shellescape(expand('%:p')) + call s:ResetShellSlash() + + let l:parsing_result = split(system(l:cmd), '\v[\r\n]+') + + " if editorconfig core's exit code is not zero, give out an error + " message + if v:shell_error != 0 + echohl ErrorMsg + echo 'Failed to execute "' . l:cmd . '". Exit code: ' . + \ v:shell_error + echo '' + echo 'Message:' + echo l:parsing_result + echohl None + return + endif + + if g:EditorConfig_verbose + echo 'Output from EditorConfig core executable:' + echo l:parsing_result + endif + + for one_line in l:parsing_result + let l:eq_pos = stridx(one_line, '=') + + if l:eq_pos == -1 " = is not found. Skip this line + continue + endif + + let l:eq_left = strpart(one_line, 0, l:eq_pos) + if l:eq_pos + 1 < strlen(one_line) + let l:eq_right = strpart(one_line, l:eq_pos + 1) + else + let l:eq_right = '' + endif + + let l:config[l:eq_left] = l:eq_right + endfor + + call s:ApplyConfig(l:config) +endfunction " }}}2 + +" }}}1 + +function! s:ApplyConfig(config) abort " Set the buffer options {{{1 + " Only process normal buffers (do not treat help files as '.txt' files) + if !empty(&buftype) + return + endif + + if g:EditorConfig_verbose + echo 'Options: ' . string(a:config) + endif + + if s:IsRuleActive('indent_style', a:config) + if a:config["indent_style"] == "tab" + setl noexpandtab + elseif a:config["indent_style"] == "space" + setl expandtab + endif + endif + + if s:IsRuleActive('tab_width', a:config) + let &l:tabstop = str2nr(a:config["tab_width"]) + endif + + if s:IsRuleActive('indent_size', a:config) + " if indent_size is 'tab', set shiftwidth to tabstop; + " if indent_size is a positive integer, set shiftwidth to the integer + " value + if a:config["indent_size"] == "tab" + let &l:shiftwidth = &l:tabstop + let &l:softtabstop = &l:shiftwidth + else + let l:indent_size = str2nr(a:config["indent_size"]) + if l:indent_size > 0 + let &l:shiftwidth = l:indent_size + let &l:softtabstop = &l:shiftwidth + endif + endif + + endif + + if s:IsRuleActive('end_of_line', a:config) && + \ &l:modifiable + if a:config["end_of_line"] == "lf" + setl fileformat=unix + elseif a:config["end_of_line"] == "crlf" + setl fileformat=dos + elseif a:config["end_of_line"] == "cr" + setl fileformat=mac + endif + endif + + if s:IsRuleActive('charset', a:config) && + \ &l:modifiable + if a:config["charset"] == "utf-8" + setl fileencoding=utf-8 + setl nobomb + elseif a:config["charset"] == "utf-8-bom" + setl fileencoding=utf-8 + setl bomb + elseif a:config["charset"] == "latin1" + setl fileencoding=latin1 + setl nobomb + elseif a:config["charset"] == "utf-16be" + setl fileencoding=utf-16be + setl bomb + elseif a:config["charset"] == "utf-16le" + setl fileencoding=utf-16le + setl bomb + endif + endif + + augroup editorconfig_trim_trailing_whitespace + autocmd! BufWritePre + if s:IsRuleActive('trim_trailing_whitespace', a:config) && + \ get(a:config, 'trim_trailing_whitespace', 'false') ==# 'true' + autocmd BufWritePre call s:TrimTrailingWhitespace() + endif + augroup END + + if s:IsRuleActive('insert_final_newline', a:config) + if exists('+fixendofline') + if a:config["insert_final_newline"] == "false" + setl nofixendofline + else + setl fixendofline + endif + elseif exists(':SetNoEOL') == 2 + if a:config["insert_final_newline"] == "false" + silent! SetNoEOL " Use the PreserveNoEOL plugin to accomplish it + endif + endif + endif + + " highlight the columns following max_line_length + if s:IsRuleActive('max_line_length', a:config) && + \ a:config['max_line_length'] != 'off' + let l:max_line_length = str2nr(a:config['max_line_length']) + + if l:max_line_length >= 0 + let &l:textwidth = l:max_line_length + if g:EditorConfig_preserve_formatoptions == 0 + setlocal formatoptions+=tc + endif + endif + + if exists('+colorcolumn') + if l:max_line_length > 0 + if g:EditorConfig_max_line_indicator == 'line' + let &l:colorcolumn = l:max_line_length + 1 + elseif g:EditorConfig_max_line_indicator == 'fill' && + \ l:max_line_length < &l:columns + " Fill only if the columns of screen is large enough + let &l:colorcolumn = join( + \ range(l:max_line_length+1,&l:columns),',') + elseif g:EditorConfig_max_line_indicator == 'exceeding' + let &l:colorcolumn = '' + for l:match in getmatches() + if get(l:match, 'group', '') == 'ColorColumn' + call matchdelete(get(l:match, 'id')) + endif + endfor + call matchadd('ColorColumn', + \ '\%' . (l:max_line_length + 1) . 'v.', 100) + endif + endif + endif + endif + + call editorconfig#ApplyHooks(a:config) +endfunction + +" }}}1 + +function! s:TrimTrailingWhitespace() " {{{1 + if &l:modifiable + " don't lose user position when trimming trailing whitespace + let s:view = winsaveview() + try + silent! keeppatterns %s/\s\+$//e + finally + call winrestview(s:view) + endtry + endif +endfunction " }}}1 + +function! s:IsRuleActive(name, config) " {{{1 + return index(g:EditorConfig_disable_rules, a:name) < 0 && + \ has_key(a:config, a:name) +endfunction "}}}1 + +let &cpo = s:saved_cpo +unlet! s:saved_cpo + +" vim: fdm=marker fdc=3 diff --git a/bundle/editorconfig-vim/tests/core/CMakeLists.txt b/bundle/editorconfig-vim/tests/core/CMakeLists.txt new file mode 100644 index 000000000..2c124403b --- /dev/null +++ b/bundle/editorconfig-vim/tests/core/CMakeLists.txt @@ -0,0 +1,53 @@ +# CMakeLists.txt for core testing in +# editorconfig-core-vimscript and editorconfig-vim. + +# Copyright (c) 2011-2019 EditorConfig Team +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# To perform the test, from the root of the project tree, run +# mkdir build +# cd build +# cmake .. +# ctest . + +cmake_minimum_required(VERSION 3.5) +#set(CMAKE_LEGACY_CYGWIN_WIN32 0) + +# Do not check any compiler +project(editorconfig-core-vimscript NONE) + +enable_testing() + +# The test executable to use +if(NOT WIN32) + set(EDITORCONFIG_CMD "${CMAKE_SOURCE_DIR}/editorconfig") +else() + set(EDITORCONFIG_CMD "${CMAKE_SOURCE_DIR}/editorconfig.bat") +endif() +set(EDITORCONFIG_CMD_IS_TARGET FALSE) + +add_subdirectory(tests) + +# CTestCustom.cmake contains platform-specific test configuration. +configure_file(CTestCustom.cmake ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) diff --git a/bundle/editorconfig-vim/tests/core/CTestCustom.cmake b/bundle/editorconfig-vim/tests/core/CTestCustom.cmake new file mode 100644 index 000000000..5452f751e --- /dev/null +++ b/bundle/editorconfig-vim/tests/core/CTestCustom.cmake @@ -0,0 +1,34 @@ +# CTestCustom.cmake: Skip UTF-8 tests +# Part of editorconfig-vim + +# Copyright (c) 2011-2019 EditorConfig Team +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# Skip UTF8 tests on Windows for now per +# https://github.com/editorconfig/editorconfig-core-c/pull/31#issue-154810185 +if(WIN32 AND (NOT "$ENV{RUN_UTF8}")) + message(WARNING "Skipping UTF-8 tests on this platform") + set(CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} g_utf_8_char) + set(CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} utf_8_char) +endif() diff --git a/bundle/editorconfig-vim/tests/core/ecvbslib.vbs b/bundle/editorconfig-vim/tests/core/ecvbslib.vbs new file mode 100644 index 000000000..a1e05d241 --- /dev/null +++ b/bundle/editorconfig-vim/tests/core/ecvbslib.vbs @@ -0,0 +1,171 @@ +' ecvbslib.vbs: VBScript routines for use in +' editorconfig-core-vimscript and editorconfig-vim. +' Copyright (c) 2018--2019 Chris White. All rights reserved. +' Licensed CC-BY-SA, version 3.0 or any later version, at your option. + +' Remove CR and LF in a string +function nocrlf(strin) + nocrlf = Replace(Replace(strin, vbCr, ""), vbLf, "") +end function + +' === Base64 ================================================================ +' from https://stackoverflow.com/a/40118072/2877364 by +' https://stackoverflow.com/users/45375/mklement0 + +' Base64-encodes the specified string. +' Parameter fAsUtf16LE determines how the input text is encoded at the +' byte level before Base64 encoding is applied. +' * Pass False to use UTF-8 encoding. +' * Pass True to use UTF-16 LE encoding. +Function Base64Encode(ByVal sText, ByVal fAsUtf16LE) + + ' Use an aux. XML document with a Base64-encoded element. + ' Assigning the byte stream (array) returned by StrToBytes() to .NodeTypedValue + ' automatically performs Base64-encoding, whose result can then be accessed + ' as the element's text. + With CreateObject("Msxml2.DOMDocument").CreateElement("aux") + .DataType = "bin.base64" + if fAsUtf16LE then + .NodeTypedValue = StrToBytes(sText, "utf-16le", 2) + else + .NodeTypedValue = StrToBytes(sText, "utf-8", 3) + end if + Base64Encode = nocrlf(.Text) ' No line breaks; MSXML adds them. + End With + +End Function + +' Decodes the specified Base64-encoded string. +' If the decoded string's original encoding was: +' * UTF-8, pass False for fIsUtf16LE. +' * UTF-16 LE, pass True for fIsUtf16LE. +Function Base64Decode(ByVal sBase64EncodedText, ByVal fIsUtf16LE) + + Dim sTextEncoding + if fIsUtf16LE Then sTextEncoding = "utf-16le" Else sTextEncoding = "utf-8" + + ' Use an aux. XML document with a Base64-encoded element. + ' Assigning the encoded text to .Text makes the decoded byte array + ' available via .nodeTypedValue, which we can pass to BytesToStr() + With CreateObject("Msxml2.DOMDocument").CreateElement("aux") + .DataType = "bin.base64" + .Text = sBase64EncodedText + Base64Decode = BytesToStr(.NodeTypedValue, sTextEncoding) + End With + +End Function + +' Returns a binary representation (byte array) of the specified string in +' the specified text encoding, such as "utf-8" or "utf-16le". +' Pass the number of bytes that the encoding's BOM uses as iBomByteCount; +' pass 0 to include the BOM in the output. +function StrToBytes(ByVal sText, ByVal sTextEncoding, ByVal iBomByteCount) + + ' Create a text string with the specified encoding and then + ' get its binary (byte array) representation. + With CreateObject("ADODB.Stream") + ' Create a stream with the specified text encoding... + .Type = 2 ' adTypeText + .Charset = sTextEncoding + .Open + .WriteText sText + ' ... and convert it to a binary stream to get a byte-array + ' representation. + .Position = 0 + .Type = 1 ' adTypeBinary + .Position = iBomByteCount ' skip the BOM + StrToBytes = .Read + .Close + End With + +end function + +' Returns a string that corresponds to the specified byte array, interpreted +' with the specified text encoding, such as "utf-8" or "utf-16le". +function BytesToStr(ByVal byteArray, ByVal sTextEncoding) + + If LCase(sTextEncoding) = "utf-16le" then + ' UTF-16 LE happens to be VBScript's internal encoding, so we can + ' take a shortcut and use CStr() to directly convert the byte array + ' to a string. + BytesToStr = CStr(byteArray) + Else ' Convert the specified text encoding to a VBScript string. + ' Create a binary stream and copy the input byte array to it. + With CreateObject("ADODB.Stream") + .Type = 1 ' adTypeBinary + .Open + .Write byteArray + ' Now change the type to text, set the encoding, and output the + ' result as text. + .Position = 0 + .Type = 2 ' adTypeText + .CharSet = sTextEncoding + BytesToStr = .ReadText + .Close + End With + End If + +end function + +' === Runner ================================================================ + +' Run a command, copy its stdout/stderr to ours, and return its exit +' status. +' Modified from https://stackoverflow.com/a/32493083/2877364 by +' https://stackoverflow.com/users/3191599/nate-barbettini . +' See also https://www.vbsedit.com/html/4c5b06ac-dc45-4ec2-aca1-f168bab75483.asp +function RunCommandAndEcho(strCommand) + Const WshRunning = 0 + Const WshFinished = 1 + Const WshFailed = 2 + + Set WshShell = CreateObject("WScript.Shell") + 'WScript.Echo "Running >>" & strCommand & "<<..." + Set WshShellExec = WshShell.Exec(strCommand) + + Do While WshShellExec.Status = WshRunning + 'WScript.Echo "Waiting..." + WScript.Sleep 100 + Loop + + if not WshShellExec.StdOut.AtEndOfStream then + WScript.StdOut.Write(WshShellExec.StdOut.ReadAll()) + end if + + if not WshShellExec.StdErr.AtEndOfStream then + WScript.StdErr.Write(WshShellExec.StdErr.ReadAll()) + end if + + RunCommandAndEcho = WshShellExec.ExitCode +end function + +' === Argument processing =================================================== + +function MakeY64Args(args) + + dim b64args(100) ' 100 = arbitrary max + + ' Make Y64-flavored base64 versions of each arg so we don't have to + ' worry about quoting issues while executing PowerShell. + + idx=0 + For Each arg In args + b64args(idx) = Base64Encode(nocrlf(arg), False) + ' Y64 flavor of Base64 + b64args(idx) = replace( _ + replace( _ + replace(b64args(idx), "+", "."), _ + "/", "_" ), _ + "=", "-") + 'Wscript.Echo cstr(idx) & ": >" & arg & "< = >" & b64args(idx) & "<" + 'Wscript.Echo b64args(idx) + idx = idx+1 + Next + + MakeY64Args = b64args +end function + +Function QuoteForShell(strIn) + QuoteForShell = """" & _ + replace(strIn, """", """""") & """" +End Function diff --git a/bundle/editorconfig-vim/tests/core/ecvimlib.ps1 b/bundle/editorconfig-vim/tests/core/ecvimlib.ps1 new file mode 100644 index 000000000..45387d5aa --- /dev/null +++ b/bundle/editorconfig-vim/tests/core/ecvimlib.ps1 @@ -0,0 +1,140 @@ +# ecvimlib.ps1: Editorconfig Vimscript core CLI, PowerShell version, +# library routines. +# Copyright (c) 2018--2019 Chris White. All rights reserved. +# Licensed CC-BY-SA, version 3.0 or any later version, at your option. +# +# N.B.: debug output uses Warning only because those are displayed by default. + +#Requires -Version 3 + +# Get the directory of this script. From +# https://stackoverflow.com/a/5466355/2877364 by +# https://stackoverflow.com/users/23283/jaredpar + +$global:DIR = $PSScriptRoot + +### Set up debugging output ============================================ + +$global:debug=$env:EDITORCONFIG_DEBUG # Debug filename + +if($global:debug -and ($global:debug -notmatch '^/')) { + # Relative to this script unless it starts with a slash. This is because + # cwd is usually not $DIR when testing. + $global:debug="${DIR}/${global:debug}" +} + +### Process args ======================================================= + +function de64_args($argv) { + $argv | % { + $b64 = $_ -replace '-','=' -replace '_','/' -replace '\.','+' + [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($b64)) + } +} + +### Helpers ============================================================ + +# Append a string to $debug in UTF-8 rather than the default UTF-16 +filter global:D($file = $debug) { + if($debug) { + echo $_ | Out-File -FilePath $file -Encoding utf8 -Append + } +} + +# Escape a string for Vim +function global:vesc($str) { + return "'" + ($str -replace "'","''") + "'" +} + +# Escape a string for a command-line argument. +# See https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.arguments?view=netframework-4.7.2 +function global:argesc($arg) { + return '"' + ($arg -replace '"','"""') + '"' +} + +### Find the Vim EXE =================================================== + +function global:Find-Vim +{ + if($env:VIM_EXE) { + if($debug) { echo "Using env Vim $($env:VIM_EXE)" | D } + return $env:VIM_EXE + } + + $vims = @(get-childitem 'c:\program files*\vim\**\vim.exe' | ` + sort LastWriteTime -Descending) # @() => always array + + # write-host ($vims | format-table | out-string) # DEBUG + # write-host ($vims | get-member | out-string) + if($vims.count -gt 0) { + if($debug) { echo "Using found Vim $($vims[0].FullName)" | D } + return $vims[0].FullName + } + + throw "Could not find vim.exe. Please set VIM_EXE to the path to your Vim." +} #Find-Vim + +### Runner ============================================================= + +# Run a process with the given arguments. +function global:run_process +{ + param( + [Parameter(Mandatory=$true, Position=0)][string]$run, + [string]$extrapath, + [string]$stdout, # Redirect stdout to this file + [string]$stderr, # Redirect stderr to this file + [string[]]$argv # Arguments to $run + ) + $si = new-object Diagnostics.ProcessStartInfo + if($extrapath) { + $si.EnvironmentVariables['path']+=";${extrapath}" + } + $si.FileName=$run + + # Stringify the arguments (blech) + $argstr = $argv | % { (argesc $_) + ' ' } + $si.Arguments = $argstr; + + if($debug) { echo "Running process $run with arguments >>$argstr<<" | D } + + $si.UseShellExecute=$false + # DEBUG $si.RedirectStandardInput=$true + if($stdout) { + if($debug) { echo "Saving stdout to ${stdout}" | D } + $si.RedirectStandardOutput=$true; + } + if($stderr) { + if($debug) { echo "Saving stderr to ${stderr}" | D } + $si.RedirectStandardError=$true; + } + + $p = [Diagnostics.Process]::Start($si) + # DEBUG $p.StandardInput.Close() # < /dev/null + + $p.WaitForExit() + $retval = $p.ExitCode + + if($stdout) { + echo "Standard output:" | D $stdout + $p.StandardOutput.ReadToEnd() | ` + Out-File -FilePath $stdout -Encoding utf8 -Append + } + + if($stderr) { + echo "Standard error:" | D $stderr + $p.StandardError.ReadToEnd() | ` + Out-File -FilePath $stderr -Encoding utf8 -Append + } + + $p.Close() + + return $retval +} + +if($debug) { + echo "======================================================" | D + Get-Date -format F | D +} + +$global:VIM = Find-Vim diff --git a/bundle/editorconfig-vim/tests/core/editorconfig b/bundle/editorconfig-vim/tests/core/editorconfig new file mode 100644 index 000000000..bdb5971d6 --- /dev/null +++ b/bundle/editorconfig-vim/tests/core/editorconfig @@ -0,0 +1,219 @@ +#!/bin/bash +# editorconfig: Editorconfig Vimscript core CLI +# Copyright (c) 2018--2019 Chris White. All rights reserved. +# Licensed CC-BY-SA, version 3.0 or any later version, at your option. + +# Documentation {{{1 +helpstr=$(cat<<'EOF' +editorconfig: command-line invoker for the Vimscript editorconfig core + +Normal usage: + editorconfig [-f ] [-b ] + [-x ] + +The default is ".editorconfig". +If -b is given, behave as . +If -x is given, the is included in the debug-output file. + +Other options: + editorconfig -h, --help Show this help + editorconfig -v, --version Show version information + +Environment variables: + VIM_EXE File/path of vim (default "vim") + EDITORCONFIG_DEBUG File/path to which to append debug output + +EOF +) + +# }}}1 + +# Get the directory of this script into $this_script_dir. {{{1 +# From https://stackoverflow.com/a/246128/2877364 by +# https://stackoverflow.com/users/407731 et al. + +this_script_dir= +function get_dir() +{ + local script_source_path="${BASH_SOURCE[0]}" + while [ -h "$script_source_path" ]; do + # resolve $script_source_path until the file is no longer a symlink + this_script_dir="$( cd -P "$( dirname "$script_source_path" )" >/dev/null && pwd )" + script_source_path="$(readlink "$script_source_path")" + [[ $script_source_path != /* ]] && script_source_path="$this_script_dir/$script_source_path" + # if $script_source_path was a relative symlink, we need to resolve + # it relative to the path where the symlink file was located + done + this_script_dir="$( cd -P "$( dirname "$script_source_path" )" >/dev/null && pwd )" +} #get_dir() + +get_dir + +# }}}1 + +# Setup debug output, if $EDITORCONFIG_DEBUG is given {{{1 +debug="${EDITORCONFIG_DEBUG}" # Debug filename +if [[ $debug && $debug != /* ]]; then # Relative to this script unless it + debug="${this_script_dir}/${debug}" # starts with a slash. This is because +fi # cwd is usually not $this_script_dir when testing. +if [[ $debug ]] && ! touch "$debug"; then + echo "Could not write file '$debug' - aborting" 1>&2 + exit 1 +fi + +[[ $debug ]] && echo "$(date) ==================================" >> "$debug" + +# }}}1 + +# Option processing {{{1 + +# Use a manually-specified Vim, if any +if [[ $VIM_EXE ]]; then + vim_pgm="$VIM_EXE" +else + vim_pgm="vim" +fi + +# Command-line options +confname= +ver= +print_ver= +extra_info= + +while getopts 'hvf:b:-:x:' opt ; do + case "$opt" in + (v) print_ver=1 + ;; + + (f) confname="$OPTARG" + ;; + + (b) ver="$OPTARG" + ;; + + (-) case "$OPTARG" in # hacky long-option processing + version) print_ver=1 + ;; + dummy) # A dummy option so that I can test + # list-valued EDITORCONFIG_CMD + ;; + help) echo "$helpstr" + exit 0 + ;; + esac + ;; + + (h) echo "$helpstr" + exit 0 + ;; + + # A way to put the test name into the log + (x) extra_info="$OPTARG" + ;; + + esac +done + +shift $(( $OPTIND - 1 )) + +if [[ $print_ver ]]; then + echo "EditorConfig VimScript Core Version 0.12.2" + exit 0 +fi + +if (( "$#" < 1 )); then + exit 1 +fi + +if [[ $1 = '-' ]]; then + echo "Reading filenames from stdin not yet supported" 1>&2 # TODO + exit 1 +fi + +# }}}1 + +# Build the Vim command line {{{1 + +fn="$(mktemp)" # Vim will write the settings into here. ~stdout. +script_output_fn="${debug:+$(mktemp)}" # Vim's :messages. ~stderr. + +cmd="call editorconfig_core#currbuf_cli({" + +# Names +cmd+="'output':'${fn//\'/\'\'}', " + # filename to put the settings in +[[ $debug ]] && cmd+=" 'dump':'${script_output_fn//\'/\'\'}', " + # where to put debug info + +# Filenames to get the settings for +cmd+="'target':[" +for f in "$@" ; do + cmd+="'${f//\'/\'\'}', " +done +cmd+="]," + # filename to get the settings for + +# Job +cmd+="}, {" +[[ $confname ]] && cmd+="'config':'${confname//\'/\'\'}', " + # config name (e.g., .editorconfig) +[[ $ver ]] && cmd+="'version':'${ver//\'/\'\'}', " + # version number we should behave as +cmd+="})" + +vim_args=( + -c "set runtimepath+=$this_script_dir/../.." + -c "$cmd" +) + +# }}}1 + +# Run the editorconfig core through Vim {{{1 +# Thanks for options to +# http://vim.wikia.com/wiki/Vim_as_a_system_interpreter_for_vimscript . +# Add -V1 to the below for debugging output. +# Do not output anything to stdout or stderr, +# since it messes up ctest's interpretation +# of the results. + +"$vim_pgm" -nNes -i NONE -u NONE -U NONE \ + "${vim_args[@]}" \ + > "${debug:-/dev/null}" +vimstatus="$?" +if [[ $vimstatus -eq 0 ]]; then + cat "$fn" +fi + +# }}}1 + +# Produce debug output {{{1 +# Debug output cannot be included on stdout or stderr, because +# ctest's regex check looks both of those places. Therefore, dump to a +# separate debugging file. +if [[ $debug ]] +then + [[ $extra_info ]] && echo "--- $extra_info ---" >> "$debug" + echo "Vim in $vim_pgm" >> "$debug" + echo "Current directory: $(pwd)" >> "$debug" + echo "Script directory: $this_script_dir" >> "$debug" + echo Vim args: "${vim_args[@]}" >> "$debug" + #od -c <<<"${vim_args[@]}" >> "$debug" + echo "Vim returned $vimstatus" >> "$debug" + echo "Vim messages were: " >> "$debug" + cat "$script_output_fn" >> "$debug" + echo "Output was:" >> "$debug" + od -c "$fn" >> "$debug" + + rm -f "$script_output_fn" +fi + +# }}}1 + +# Cleanup {{{1 + +rm -f "$fn" + +# }}}1 + +exit "$vimstatus" # forward the Vim exit status to the caller +# vi: set ft=sh fdm=marker: diff --git a/bundle/editorconfig-vim/tests/core/editorconfig.bat b/bundle/editorconfig-vim/tests/core/editorconfig.bat new file mode 100644 index 000000000..77b544700 --- /dev/null +++ b/bundle/editorconfig-vim/tests/core/editorconfig.bat @@ -0,0 +1,11 @@ +@echo off +:: editorconfig.bat: First-level invoker for editorconfig-core-vimscript +:: and editorconfig-vim. +:: Just passes the full command line to editorconfig1.vbs, since VBScript +:: applies very simple quoting rules when it parses a command line. +:: Copyright (c) 2018--2019 Chris White. All rights reserved. +:: Licensed CC-BY-SA, version 3.0 or any later version, at your option. +set here=%~dp0 + +cscript //Nologo "%here%editorconfig1.vbs" %* +:: %* has the whole command line diff --git a/bundle/editorconfig-vim/tests/core/editorconfig1.vbs b/bundle/editorconfig-vim/tests/core/editorconfig1.vbs new file mode 100644 index 000000000..488411fcf --- /dev/null +++ b/bundle/editorconfig-vim/tests/core/editorconfig1.vbs @@ -0,0 +1,39 @@ +' editorconfig1.vbs: run by editorconfig.bat +' runs editorconfig2.ps1 +' Part of editorconfig-core-vimscript and editorconfig-vim. +' +' Copyright (c) 2018--2019 Chris White. All rights reserved. +' Licensed CC-BY-SA, version 3.0 or any later version, at your option. +' +' Modified from +' https://stackoverflow.com/a/2470557/2877364 by +' https://stackoverflow.com/users/2441/aphoria + +' Thanks to https://www.geekshangout.com/vbs-script-to-get-the-location-of-the-current-script/ +currentScriptPath = Replace(WScript.ScriptFullName, WScript.ScriptName, "") + +' Load our common library. Thanks to https://stackoverflow.com/a/316169/2877364 +With CreateObject("Scripting.FileSystemObject") + executeGlobal .openTextFile(currentScriptPath & "ecvbslib.vbs").readAll() +End With + +' === MAIN ================================================================== + +' Encode all the arguments as modified base64 so there will be no quoting +' issues when we invoke powershell. +b64args = MakeY64Args(Wscript.Arguments) + +' Quote script name just in case +ps1name = QuoteForShell(currentScriptPath & "editorconfig2.ps1") +'Wscript.Echo "Script is in " & ps1name + +if True then + retval = RunCommandAndEcho( "powershell.exe" & _ + " -executionpolicy bypass -file " & ps1name & " " & join(b64args) _ + ) + ' add -noexit to leave window open so you can see error messages + + WScript.Quit retval +end if + +' vi: set ts=4 sts=4 sw=4 et ai: diff --git a/bundle/editorconfig-vim/tests/core/editorconfig2.ps1 b/bundle/editorconfig-vim/tests/core/editorconfig2.ps1 new file mode 100644 index 000000000..0bc3602a1 --- /dev/null +++ b/bundle/editorconfig-vim/tests/core/editorconfig2.ps1 @@ -0,0 +1,218 @@ +# editorconfig2.ps1: Editorconfig Vimscript core CLI, PowerShell version +# Copyright (c) 2018--2019 Chris White. All rights reserved. +# Licensed CC-BY-SA, version 3.0 or any later version, at your option. +# Thanks to https://cecs.wright.edu/~pmateti/Courses/233/Labs/Scripting/bashVsPowerShellTable.html +# by Gallagher and Mateti. + +#Requires -Version 3 + +. "$PSScriptRoot\ecvimlib.ps1" + +# Argument parsing =================================================== {{{1 + +$argv = @(de64_args($args)) + +# Defaults +$report_version = $false +$set_version = '' +$config_name = '.editorconfig' +$extra_info = '' +$files=@() + +# Hand-parse - pretend we're sort of like getopt. +$idx = 0 +while($idx -lt $argv.count) { + $a = $argv[$idx] + + switch -CaseSensitive -Regex ($a) { + '^(-v|--version)$' { $report_version = $true } + + '^--dummy$' { + # A dummy option so that I can test list-valued EDITORCONFIG_CMD + } + + '^-f$' { + if($idx -eq ($argv.count-1)) { + throw '-f : no filename provided' + } else { + ++$idx + $config_name = $argv[$idx] + } + } #-f + + '^-b$' { + if($idx -eq ($argv.count-1)) { + throw '-b : no version provided' + } else { + ++$idx + $set_version = $argv[$idx] + } + } #-b + + '^-x$' { + if($idx -eq ($argv.count-1)) { + throw '-x : no info provided' + } else { + ++$idx + $extra_info = $argv[$idx] + } + } #-x + + '^--$' { # End of options, so capture the rest as filenames + ++$idx; + while($idx -lt $argv.count) { + $files += $argv[$idx] + } + } + + default { $files += $a } + } + + ++$idx +} # end foreach argument + +# }}}1 +# Argument processing ================================================ {{{1 + +if($debug) { + if($extra_info -ne '') { + echo "--- $extra_info --- " | D + } + + echo "Running in $DIR" | D + echo "Vim executable: $VIM" | D + echo "report version? $report_version" | D + echo "set version to: $set_version" | D + echo "config filename: $config_name" | D + echo "Filenames: $files" | D + echo "Args: $args" | D + echo "Decoded args: $argv" | D +} + +if($report_version) { + echo "EditorConfig VimScript Core Version 0.12.2" + exit +} + +if($files.count -lt 1) { + exit +} + +if($files[0] -eq '-') { + echo "Reading filenames from stdin not yet supported" # TODO + exit 1 +} + +$fn=[System.IO.Path]::GetTempFileName(); + # Vim will write the settings into here. Sort of like stdout. +$script_output_fn = '' +if($debug) { + $script_output_fn = [System.IO.Path]::GetTempFileName() +} + +# Permit throwing in setup commands +$cmd = '' +if($env:EDITORCONFIG_EXTRA) { + $cmd += $env:EDITORCONFIG_EXTRA + ' | ' +} + +# }}}1 +# Build Vim command line ============================================= {{{1 +$cmd += 'call editorconfig_core#currbuf_cli({' + +# Names +$cmd += "'output':" + (vesc($fn)) + ", " + # filename to put the settings in +if($debug) { + $cmd += " 'dump':" + (vesc($script_output_fn)) + ", " + # where to put debug info +} + +# Filenames to get the settings for +$cmd += "'target':[" +ForEach ($item in $files) { + $cmd += (vesc($item)) + ", " +} +$cmd += "]," + +# Job +$cmd += "}, {" +if($config_name) { $cmd += "'config':" + (vesc($config_name)) + ", " } + # config name (e.g., .editorconfig) +if($set_version) { $cmd += "'version':" + (vesc($set_version)) + ", " } + # version number we should behave as +$cmd += "})" + +#$cmd =':q!' # DEBUG +if($debug) { echo "Using Vim command ${cmd}" | D } +$vim_args = @( + '-c', "set runtimepath+=${DIR}\..\..", + '-c', $cmd, + '-c', 'quit!' # TODO write a wrapper that will cquit on exception +) + +# Run editorconfig. Thanks for options to +# http://vim.wikia.com/wiki/Vim_as_a_system_interpreter_for_vimscript . +# Add -V1 to the below for debugging output. +# Do not output anything to stdout or stderr, +# since it messes up ctest's interpretation +# of the results. + +$basic_args = '-nNes','-i','NONE','-u','NONE','-U','NONE' #, '-V1' + +# }}}1 +# Run Vim ============================================================ {{{1 + +if($debug) { echo "Running vim ${VIM}" | D } +$vimstatus = run_process $VIM -stdout $debug -stderr $debug ` + -argv ($basic_args+$vim_args) +if($debug) { echo "Done running vim" | D } + +if($vimstatus -eq 0) { + cat $fn +} + +# }}}1 +# Produce debug output =============================================== {{{1 + +# Debug output cannot be included on stdout or stderr, because +# ctest's regex check looks both of those places. Therefore, dump to a +# separate debugging file. + +if($debug) { + echo "Current directory:" | D + (get-item -path '.').FullName | D + echo "Script directory: $DIR" | D +### echo Vim args: "${vim_args[@]}" >> "$debug" +### #od -c <<<"${vim_args[@]}" >> "$debug" + echo "Vim returned $vimstatus" | D + echo "Vim messages were: " | D + cat $script_output_fn | D + echo "Output was:" | D + + # Modified from https://www.itprotoday.com/powershell/get-hex-dumps-files-powershell + Get-Content $script_output_fn -Encoding Byte -ReadCount 16 | ` + ForEach-Object { + $output = "" + $chars = '' + foreach ( $byte in $_ ) { + $output += "{0:X2} " -f $byte + if( ($byte -ge 32) -and ($byte -le 127) ) { + $chars += [char]$byte + } else { + $chars += '.' + } + } + $output + ' ' + $chars + } | D + + del -Force $script_output_fn +} #endif $debug + +# }}}1 + +del -Force $fn + +exit $vimstatus + +# vi: set fdm=marker: diff --git a/bundle/editorconfig-vim/tests/fetch-vim.bat b/bundle/editorconfig-vim/tests/fetch-vim.bat new file mode 100644 index 000000000..c834fd745 --- /dev/null +++ b/bundle/editorconfig-vim/tests/fetch-vim.bat @@ -0,0 +1,12 @@ +:: fetch-vim.bat: Fetch vim if necessary +:: For use in the editorconfig-vim Appveyor build +:: Copyright (c) 2018--2019 Chris White. All rights reserved. +:: Licensed Apache 2.0, or any later version, at your option. + +:: If it's already been loaded from the cache, we're done +if exist C:\vim\vim\vim80\vim.exe exit + +:: Otherwise, download and unzip it. +appveyor DownloadFile https://github.com/cxw42/editorconfig-core-vimscript/releases/download/v0.1.0/vim.7z + +7z x vim.7z -oC:\vim diff --git a/bundle/editorconfig-vim/tests/fetch-vim.sh b/bundle/editorconfig-vim/tests/fetch-vim.sh new file mode 100644 index 000000000..22e7912aa --- /dev/null +++ b/bundle/editorconfig-vim/tests/fetch-vim.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# fetch-vim.bat: Fetch vim if necessary +# For use in the editorconfig-vim Appveyor build +# Copyright (c) 2018--2019 Chris White. All rights reserved. +# Licensed Apache 2.0, or any later version, at your option. + +# Debugging +set -x +set -o nounset +#set -o errexit + +# Basic system info +uname -a +pwd +ls -l + +echo "VIM_EXE: $VIM_EXE" +set + +# If it's already been loaded from the cache, we're done +if [[ -x "$VIM_EXE" ]]; then + echo Vim found in cache at "$VIM_EXE" + exit 0 +fi + +# Otherwise, clone and build it +WHITHER="$APPVEYOR_BUILD_FOLDER/vim" + +git clone https://github.com/vim/vim-appimage.git +cd vim-appimage +git submodule update --init --recursive + +cd vim/src +./configure --with-features=huge --prefix="$WHITHER" --enable-fail-if-missing +make -j2 # Free tier provides two cores +make install +./vim --version +cd $APPVEYOR_BUILD_FOLDER +find . -type f -name vim -exec ls -l {} + + +echo Done fetching and installing vim diff --git a/bundle/editorconfig-vim/tests/plugin/.gitignore b/bundle/editorconfig-vim/tests/plugin/.gitignore new file mode 100644 index 000000000..cee07667f --- /dev/null +++ b/bundle/editorconfig-vim/tests/plugin/.gitignore @@ -0,0 +1,2 @@ +# Where bundler installs local Gemfile dependencies +/vendor/ diff --git a/bundle/editorconfig-vim/tests/plugin/Gemfile b/bundle/editorconfig-vim/tests/plugin/Gemfile new file mode 100644 index 000000000..49270e490 --- /dev/null +++ b/bundle/editorconfig-vim/tests/plugin/Gemfile @@ -0,0 +1,5 @@ +source 'https://rubygems.org' + +gem 'rake', '~> 12.3.3' +gem 'rspec', '~> 3.4.0' +gem 'vimrunner', '~> 0.3.1' diff --git a/bundle/editorconfig-vim/tests/plugin/Gemfile.lock b/bundle/editorconfig-vim/tests/plugin/Gemfile.lock new file mode 100644 index 000000000..5d1c3f47c --- /dev/null +++ b/bundle/editorconfig-vim/tests/plugin/Gemfile.lock @@ -0,0 +1,27 @@ +GEM + remote: https://rubygems.org/ + specs: + diff-lcs (1.2.5) + rake (12.3.3) + rspec (3.4.0) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) + rspec-core (3.4.1) + rspec-support (~> 3.4.0) + rspec-expectations (3.4.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-mocks (3.4.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-support (3.4.1) + vimrunner (0.3.1) + +PLATFORMS + ruby + +DEPENDENCIES + rake (~> 12.3.3) + rspec (~> 3.4.0) + vimrunner (~> 0.3.1) diff --git a/bundle/editorconfig-vim/tests/plugin/Rakefile b/bundle/editorconfig-vim/tests/plugin/Rakefile new file mode 100644 index 000000000..3119d82ea --- /dev/null +++ b/bundle/editorconfig-vim/tests/plugin/Rakefile @@ -0,0 +1,8 @@ +# +# run `rake` to run tests + +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) + +task :default => :spec diff --git a/bundle/editorconfig-vim/tests/plugin/spec/.editorconfig b/bundle/editorconfig-vim/tests/plugin/spec/.editorconfig new file mode 100644 index 000000000..834f0eb3f --- /dev/null +++ b/bundle/editorconfig-vim/tests/plugin/spec/.editorconfig @@ -0,0 +1,4 @@ +[*.rb] +indent_style = space +indent_size = 2 +end_of_line = lf diff --git a/bundle/editorconfig-vim/tests/plugin/spec/editorconfig_spec.rb b/bundle/editorconfig-vim/tests/plugin/spec/editorconfig_spec.rb new file mode 100644 index 000000000..0b3e654b6 --- /dev/null +++ b/bundle/editorconfig-vim/tests/plugin/spec/editorconfig_spec.rb @@ -0,0 +1,161 @@ +require 'vimrunner' + +def create_vim(*initial_commands) + vim = Vimrunner.start + initial_commands.each do |cmd| + vim.command cmd + end + vim.add_plugin(File.expand_path('../../../..', __FILE__), 'plugin/editorconfig.vim') + return vim +end + +# The base path of the testing files +BASE_PATH = File.expand_path('../plugin_tests/test_files/', __FILE__) + +# file_name is the file name that should be open by Vim +# expected_values is a Hash that contains all the Vim options we need to test +def test_editorconfig(vim, file_name, expected_values) + vim.edit(File.join(BASE_PATH, file_name)) + + expected_values.each do |key, val| + expect(vim.echo("&l:#{key}")).to eq(val) + end + + vim.command 'bd!' +end + +def test_instance(vim) + describe 'plugin/editorconfig.vim' do + after(:all) do + vim.kill + end + + describe '#all' do + it '3_space.py' do + test_editorconfig vim, '3_space.txt', + expandtab: '1', + shiftwidth: '3', + tabstop: '3' + end + end + + it '4_space.py' do + test_editorconfig vim, '4_space.py', + expandtab: '1', + shiftwidth: '4', + tabstop: '8' + end + + it 'space.txt' do + test_editorconfig vim, 'space.txt', + expandtab: '1', + shiftwidth: vim.echo('&l:tabstop') + end + + it 'tab.txt' do + test_editorconfig vim, 'tab.txt', + expandtab: '0' + end + + it '4_tab.txt' do + test_editorconfig vim, '4_tab.txt', + expandtab: '0', + shiftwidth: '4', + tabstop: '4' + end + + it '4_tab_width_of_8' do + test_editorconfig vim, '4_tab_width_of_8.txt', + expandtab: '0', + shiftwidth: '4', + tabstop: '8' + end + + it 'lf.txt' do + test_editorconfig vim, 'lf.txt', + fileformat: 'unix' + end + + it 'crlf.txt' do + test_editorconfig vim, 'crlf.txt', + fileformat: 'dos' + end + + it 'cr.txt' do + test_editorconfig vim, 'cr.txt', + fileformat: 'mac' + end + + it 'utf-8.txt' do + test_editorconfig vim, 'utf-8.txt', + fileencoding: 'utf-8', + bomb: '0' + end + + it 'utf-8-bom.txt' do + test_editorconfig vim, 'utf-8-bom.txt', + fileencoding: 'utf-8', + bomb: '1' + end + + it 'utf-16be.txt' do + test_editorconfig vim, 'utf-16be.txt', + fileencoding: 'utf-16' + end + + it 'utf-16le.txt' do + test_editorconfig vim, 'utf-16le.txt', + fileencoding: 'utf-16le' + end + + it 'latin1.txt' do + test_editorconfig vim, 'latin1.txt', + fileencoding: 'latin1' + end + + # insert_final_newline by PreserveNoEOL tests are omitted, since they are not supported + if vim.echo("exists('+fixendofline')") == '1' + it 'with_newline.txt' do + test_editorconfig vim, 'with_newline.txt', + fixendofline: '1' + end + + it 'without_newline.txt' do + test_editorconfig vim, 'without_newline.txt', + fixendofline: '0' + end + end + end +end + +# Test the vim core +(lambda do + puts 'Testing default' + vim = create_vim + test_instance vim +end).call + +# Test the vim core with an express setting +(lambda do + puts 'Testing with express vim_core mode' + vim = create_vim("let g:EditorConfig_core_mode='vim_core'") + test_instance vim +end).call + +# Test with external-core mode, but no external core defined +(lambda do + puts 'Testing with fallback to vim_core mode' + vim = create_vim("let g:EditorConfig_core_mode='external_command'") + test_instance vim +end).call + +# Test with an external core, if desired +extcore = ENV['EDITORCONFIG_VIM_EXTERNAL_CORE'] +if extcore + puts "Testing with external_command #{extcore}" + vim = create_vim( + "let g:EditorConfig_core_mode='external_command'", + "let g:EditorConfig_exec_path='#{extcore}'", + ) + test_instance vim +end diff --git a/bundle/editorconfig-vim/tests/travis-test.sh b/bundle/editorconfig-vim/tests/travis-test.sh new file mode 100644 index 000000000..76022a039 --- /dev/null +++ b/bundle/editorconfig-vim/tests/travis-test.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# travis-test.sh: Script for running editorconfig-vim tests under Travis CI. +# Copyright (c) 2019 Chris White. All rights reserved. +# Licensed Apache, version 2.0 or any later version, at your option. + +# Error exit; debug output +set -vxEeuo pipefail + +# Permit `travis-test.sh plugin` if TEST_WHICH is unset +if [[ ( ! "${TEST_WHICH:-}" ) && "${1:-}" ]]; then + export TEST_WHICH="$1" +fi + +if [[ "$TEST_WHICH" = 'plugin' ]]; then # test plugin + + # If not running from Travis, do what Travis would have + # done for us. + if [[ ! "${BUNDLE_GEMFILE:-}" ]]; then + here="$(cd "$(dirname "$0")" &>/dev/null ; pwd)" + export BUNDLE_GEMFILE="${here}/plugin/Gemfile" + # Install into tests/plugin/vendor. Don't clear it first, + # since you can clear it yourself if you're running from a + # dev environment. + bundle install --jobs=3 --retry=3 --deployment + fi + + # Use the standalone Vimscript EditorConfig core to test the plugin's + # external_command mode + export EDITORCONFIG_VIM_EXTERNAL_CORE=tests/core/editorconfig + + bundle exec rspec tests/plugin/spec/editorconfig_spec.rb + +elif [[ "$TEST_WHICH" = 'core' ]]; then # test core + cd tests/core + mkdir -p build # May already exist if running from a dev env + cd build + cmake .. + ctest . --output-on-failure -VV -C Debug + # -C Debug: for Visual Studio builds, you have to specify + # a configuration. + +else + echo 'Invalid TEST_WHICH value' 1>&2 + exit 1 +fi diff --git a/bundle/fcitx.vim/README.md b/bundle/fcitx.vim/README.md new file mode 100644 index 000000000..5f8f551d6 --- /dev/null +++ b/bundle/fcitx.vim/README.md @@ -0,0 +1,33 @@ +Keep and restore fcitx state for each buffer separately when leaving/re-entering insert mode. Like always typing English in normal mode, but Chinese in insert mode. + +Requires: fcitx 3.6 or later, 4.0 or later will be better. + +Settings: environment variable `$FCITX_SOCKET` specifies a socket to connect instead of figuring out itself. This can be an abstract socket address starting with `@` from version 1.2.4 on. + +* [git repo](https://github.com/lilydjwg/fcitx.vim) +* [www.vim.org](https://www.vim.org/scripts/script.php?script_id=3764) + +Warning: + +1. It will be faster and better with Python (3 or 2) enabled Vim. But some old version Vim enabled both Python 2 & 3 may have some issues. +2. If you use Vim in terminal, to avoid the Esc delay, please set `'ttimeoutlen'` to 100 or some other value. And check screen's `maptimeout` or tmux's `escape-time` option if you use it too. + +For Mac OS X users, you can use a "fcitx-remote" [here](https://github.com/CodeFalling/fcitx-remote-for-osx), together with the VimL version (the `so/fcitx.vim` file). + +在离开或重新进入插入模式时自动记录和恢复每个缓冲区各自的输入法状态,以便在普通模式下始终是英文输入模式,切换回插入模式时恢复离开前的输入法输入模式。 + +要求: fcitx 版本 3.6 以上,建议 fcitx 4.0 以上。 + +配置:环境变量 `$FCITX_SOCKET` 指定要连接的套接字路径,而非默认的。自版本 1.2.4 起,此变量若以 `@` 字符开头,则被认为是抽象套接字地址。 + +* [git 仓库](https://github.com/lilydjwg/fcitx.vim) +* [www.vim.org](https://www.vim.org/scripts/script.php?script_id=3764) + +注意事项: + +1. Vim 如有 Python 3或2 支持可以获得更快更好的效果。但对于较旧的 Vim 版本,如果同时编译了 Python 2 & 3 支持,因为此 Vim 不能同时运行两个版本的 Python,而本脚本首先检查 Python 3,所以会导致出错或者 Python 2 不可用。 +2. 终端下请设置 Vim `'ttimeoutlen'` 选项为较小值(如100),否则退出插入模式时会有较严重的延迟。同样会造成延迟的还有 screen 的 `maptimeout` 选项以及 tmux 的 `escape-time` 选项。 + +如果你想跨主机使用 fcitx.vim,请参考此文:[fcitx-remote 接口通过 socat 跨主机使用](https://blog.lilydjwg.me/2012/7/27/using-fcitx-remote-interface-remotely-via-socat.34729.html)。 + +Mac OS X 用户可以使用[此项目](https://github.com/CodeFalling/fcitx-remote-for-osx)提供的 fcitx-remote 命令,配合本软件的 VimL 版(`so/fcitx.vim` 文件)来使用。 diff --git a/bundle/fcitx.vim/plugin/fcitx.py b/bundle/fcitx.vim/plugin/fcitx.py new file mode 100644 index 000000000..59d815953 --- /dev/null +++ b/bundle/fcitx.vim/plugin/fcitx.py @@ -0,0 +1,78 @@ +# vim:fileencoding=utf-8 + +import os +import vim +import socket +import struct +import contextlib + +fcitxsocketfile = vim.eval('s:fcitxsocketfile') + +class FcitxComm(object): + STATUS = struct.pack('i', 0) + ACTIVATE = struct.pack('i', 1 | (1 << 16)) + DEACTIVATE = struct.pack('i', 1) + INT_SIZE = struct.calcsize('i') + + def __init__(self, socketfile): + if socketfile[0] == '@': # abstract socket + socketfile = '\x00' + socketfile[1:] + self.socketfile = socketfile + self.sock = None + + def status(self): + return self._with_socket(self._status) == 2 + + def activate(self): + self._with_socket(self._command, self.ACTIVATE) + + def deactivate(self): + self._with_socket(self._command, self.DEACTIVATE) + + def _error(self, e): + estr = str(e).replace('"', r'\"') + file = self.socketfile.replace('"', r'\"') + vim.command('echohl WarningMsg | echo "fcitx.vim: socket %s error: %s" | echohl NONE' % (file, estr)) + + def _connect(self): + self.sock = sock = socket.socket(socket.AF_UNIX) + sock.settimeout(0.5) + try: + sock.connect(self.socketfile) + return True + except (socket.error, socket.timeout) as e: + self._error(e) + return False + + def _with_socket(self, func, *args, **kwargs): + # fcitx doesn't support connection reuse + if not self._connect(): + return + + with contextlib.closing(self.sock): + try: + return func(*args, **kwargs) + except (socket.error, socket.timeout, struct.error) as e: + self._error(e) + + def _status(self): + self.sock.send(self.STATUS) + return struct.unpack('i', self.sock.recv(self.INT_SIZE))[0] + + def _command(self, cmd): + self.sock.send(cmd) + +Fcitx = FcitxComm(fcitxsocketfile) + +def fcitx2en(): + if Fcitx.status(): + vim.command('let b:inputtoggle = 1') + Fcitx.deactivate() + +def fcitx2zh(): + if vim.eval('exists("b:inputtoggle")') == '1': + if vim.eval('b:inputtoggle') == '1': + Fcitx.activate() + vim.command('let b:inputtoggle = 0') + else: + vim.command('let b:inputtoggle = 0') diff --git a/bundle/fcitx.vim/plugin/fcitx.vim b/bundle/fcitx.vim/plugin/fcitx.vim new file mode 100644 index 000000000..258e2f232 --- /dev/null +++ b/bundle/fcitx.vim/plugin/fcitx.vim @@ -0,0 +1,67 @@ +scriptencoding utf-8 +" fcitx.vim remember fcitx's input state for each buffer +" Author: lilydjwg +" Version: 1.2.6 +" URL: https://www.vim.org/scripts/script.php?script_id=3764 +" --------------------------------------------------------------------- +" Load Once: +if &cp || exists("g:loaded_fcitx") || ( + \ (!exists('$DISPLAY') || exists('$SSH_TTY') || has('gui_macvim')) + \ && !exists('$FCITX_SOCKET')) + finish +endif +if executable('fcitx5-remote') + " currently python version does not support fcitx5 + let g:fcitx_remote = 'fcitx5-remote' + runtime so/fcitx.vim + finish +else + let g:fcitx_remote = 'fcitx-remote' +endif +if has("python3") + let python3 = 1 +elseif has("python") + let python3 = 0 +else + runtime so/fcitx.vim + finish +endif +let s:keepcpo = &cpo +set cpo&vim +" this is quicker than expand() +if exists('$FCITX_SOCKET') + let s:fcitxsocketfile = $FCITX_SOCKET +else + let s:fcitxsocketfile = '/tmp/fcitx-socket-' . $DISPLAY + if !filewritable(s:fcitxsocketfile) "try again + if strridx(s:fcitxsocketfile, '.') > 0 + let s:fcitxsocketfile = strpart(s:fcitxsocketfile, 0, + \ strridx(s:fcitxsocketfile, '.')) + else + let s:fcitxsocketfile = s:fcitxsocketfile . '.0' + if !filewritable(s:fcitxsocketfile) + echohl WarningMsg + echomsg "socket file of fcitx not found, fcitx.vim not loaded." + echohl None + finish + endif + endif + endif +endif +let g:loaded_fcitx = 1 +let pyfile = expand(':r') . '.py' +if python3 + exe 'py3file' pyfile + au InsertLeave * py3 fcitx2en() + au InsertEnter * py3 fcitx2zh() +else + exe 'pyfile' pyfile + au InsertLeave * py fcitx2en() + au InsertEnter * py fcitx2zh() +endif +" --------------------------------------------------------------------- +" Restoration And Modelines: +unlet python3 +unlet pyfile +let &cpo=s:keepcpo +unlet s:keepcpo diff --git a/bundle/fcitx.vim/so/fcitx.vim b/bundle/fcitx.vim/so/fcitx.vim new file mode 100644 index 000000000..45a85a8c5 --- /dev/null +++ b/bundle/fcitx.vim/so/fcitx.vim @@ -0,0 +1,47 @@ +" fcitx.vim 记住插入模式小企鹅输入法的状态 +" Author: lilydjwg +" Maintainer: lilydjwg +" Note: 另有使用 Python3 接口的新版本 +" --------------------------------------------------------------------- +" Load Once: +if (has("win32") || has("win95") || has("win64") || has("win16")) + " Windows 下不要载入 + finish +endif +if !(exists('$DISPLAY') || has('gui_macvim')) || exists('$SSH_TTY') + finish +endif +if &cp || exists("g:loaded_fcitx") || !executable(g:fcitx_remote) + finish +endif +let s:keepcpo = &cpo +let g:loaded_fcitx = 1 +set cpo&vim +" --------------------------------------------------------------------- +" Functions: +function Fcitx2en() + let inputstatus = system(g:fcitx_remote) + if inputstatus == 2 + let b:inputtoggle = 1 + call system(g:fcitx_remote . ' -c') + endif +endfunction +function Fcitx2zh() + try + if b:inputtoggle == 1 + call system(g:fcitx_remote . ' -o') + let b:inputtoggle = 0 + endif + catch /inputtoggle/ + let b:inputtoggle = 0 + endtry +endfunction +" --------------------------------------------------------------------- +" Autocmds: +au InsertLeave * call Fcitx2en() +au InsertEnter * call Fcitx2zh() +" --------------------------------------------------------------------- +" Restoration And Modelines: +let &cpo=s:keepcpo +unlet s:keepcpo +" vim:fdm=expr:fde=getline(v\:lnum-1)=~'\\v"\\s*-{20,}'?'>1'\:1 diff --git a/bundle/gruvbox/CHANGELOG.md b/bundle/gruvbox/CHANGELOG.md new file mode 100644 index 000000000..90fd3a291 --- /dev/null +++ b/bundle/gruvbox/CHANGELOG.md @@ -0,0 +1,117 @@ +# Change Log + +## [Unreleased](https://github.com/morhetz/gruvbox/tree/HEAD) + +[Full Changelog](https://github.com/morhetz/gruvbox/compare/v1.3.5...HEAD) + +**Fixed bugs:** + +- Lighter background on terminal [\#8](https://github.com/morhetz/gruvbox/issues/8) + +**Closed issues:** + +- Installation issue. [\#54](https://github.com/morhetz/gruvbox/issues/54) + +- Italic font in terminal\(urxvt\) [\#49](https://github.com/morhetz/gruvbox/issues/49) + +- Unable to log in when sourcing the palette shellscript [\#48](https://github.com/morhetz/gruvbox/issues/48) + +- How can i modify multiple comment scheme [\#46](https://github.com/morhetz/gruvbox/issues/46) + +- Remove comment highlight in iterm [\#44](https://github.com/morhetz/gruvbox/issues/44) + +- Comments looking strange withing tmux [\#43](https://github.com/morhetz/gruvbox/issues/43) + +- comments are reverse-video in xterm [\#41](https://github.com/morhetz/gruvbox/issues/41) + +- What font are you using in the screenshots? [\#39](https://github.com/morhetz/gruvbox/issues/39) + +- vim-signature crashes when I use gruvbox [\#38](https://github.com/morhetz/gruvbox/issues/38) + +- Color of statusbar in inactive windows [\#37](https://github.com/morhetz/gruvbox/issues/37) + +- Go method and struct highlighting missing [\#36](https://github.com/morhetz/gruvbox/issues/36) + +- gruvbox\_256palette.sh doesn't work for Konsole [\#35](https://github.com/morhetz/gruvbox/issues/35) + +- Contrast in jekyll markdown files [\#33](https://github.com/morhetz/gruvbox/issues/33) + +- Pentadactyl Gruvbox Theme [\#32](https://github.com/morhetz/gruvbox/issues/32) + +- make vertsplit better [\#31](https://github.com/morhetz/gruvbox/issues/31) + +- Console support. [\#30](https://github.com/morhetz/gruvbox/issues/30) + +- How can I change the background color? [\#29](https://github.com/morhetz/gruvbox/issues/29) + +- Some words are not bold [\#28](https://github.com/morhetz/gruvbox/issues/28) + +- Terminal theme on base gruvbox [\#25](https://github.com/morhetz/gruvbox/issues/25) + +- Markdown has inverted colors when using \* [\#24](https://github.com/morhetz/gruvbox/issues/24) + +- how install it on mac osx [\#23](https://github.com/morhetz/gruvbox/issues/23) + +- Comments color for Terminal Vim [\#22](https://github.com/morhetz/gruvbox/issues/22) + +- Move palette files to gruvbox-generalized [\#20](https://github.com/morhetz/gruvbox/issues/20) + +- Maybe add Gruvbox Airline theme? [\#19](https://github.com/morhetz/gruvbox/issues/19) + +- For Sublime text [\#18](https://github.com/morhetz/gruvbox/issues/18) + +**Merged pull requests:** + +- Fix the 256 palette script failed login issue [\#53](https://github.com/morhetz/gruvbox/pull/53) ([jonasmalacofilho](https://github.com/jonasmalacofilho)) + +- add minimal coloring for gitcommit highlighting [\#52](https://github.com/morhetz/gruvbox/pull/52) ([daniely](https://github.com/daniely)) + +- For terminals, turn off italics by default. [\#47](https://github.com/morhetz/gruvbox/pull/47) ([ryanmjacobs](https://github.com/ryanmjacobs)) + +- Change color of vertical/horizontal seperators between split windows [\#45](https://github.com/morhetz/gruvbox/pull/45) ([deshtop](https://github.com/deshtop)) + +- Improve gruvbox with C code [\#34](https://github.com/morhetz/gruvbox/pull/34) ([gladiac](https://github.com/gladiac)) + +- Fix for linux console [\#27](https://github.com/morhetz/gruvbox/pull/27) ([vyp](https://github.com/vyp)) + +- Colors for plugin vimshell.vim [\#21](https://github.com/morhetz/gruvbox/pull/21) ([joelmo](https://github.com/joelmo)) + +## [v1.3.5](https://github.com/morhetz/gruvbox/tree/v1.3.5) (2014-03-19) + +[Full Changelog](https://github.com/morhetz/gruvbox/compare/v0.0.8...v1.3.5) + +**Implemented enhancements:** + +- Better selection colors [\#15](https://github.com/morhetz/gruvbox/issues/15) + +- When hlsearch is on, the cursor inverts the search color and not visible [\#2](https://github.com/morhetz/gruvbox/issues/2) + +**Fixed bugs:** + +- Problem with changing between dark and light on 256 color terminal [\#7](https://github.com/morhetz/gruvbox/issues/7) + +- IndentGuides coloring doesn't show up [\#1](https://github.com/morhetz/gruvbox/issues/1) + +**Closed issues:** + +- Requesting rxvt-unicode theme [\#17](https://github.com/morhetz/gruvbox/issues/17) + +- gruvbox\_256palette.sh gets reset \(gnome-terminal on Ubuntu\) [\#13](https://github.com/morhetz/gruvbox/issues/13) + +- Powerline colors [\#12](https://github.com/morhetz/gruvbox/issues/12) + +- Info necessary for making a port of this colorscheme [\#10](https://github.com/morhetz/gruvbox/issues/10) + +**Merged pull requests:** + +- Fix GNU screen detection for \*-bce [\#16](https://github.com/morhetz/gruvbox/pull/16) ([blueyed](https://github.com/blueyed)) + +- Added iTerm2 dark theme [\#11](https://github.com/morhetz/gruvbox/pull/11) ([Greduan](https://github.com/Greduan)) + +- Fix typo in Readme [\#5](https://github.com/morhetz/gruvbox/pull/5) ([ViViDboarder](https://github.com/ViViDboarder)) + +## [v0.0.8](https://github.com/morhetz/gruvbox/tree/v0.0.8) (2012-12-08) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/bundle/gruvbox/README.md b/bundle/gruvbox/README.md new file mode 100644 index 000000000..cd07e486f --- /dev/null +++ b/bundle/gruvbox/README.md @@ -0,0 +1,113 @@ +

+ +gruvbox is heavily inspired by [badwolf][], [jellybeans][] and [solarized][]. + +Designed as a bright theme with pastel 'retro groove' colors and light/dark mode switching in the way of [solarized][]. The main focus when developing gruvbox is to keep colors easily distinguishable, contrast enough and still pleasant for the eyes. + + [badwolf]: https://github.com/sjl/badwolf + [jellybeans]: https://github.com/nanotech/jellybeans.vim + [solarized]: http://ethanschoonover.com/solarized + +Attention +--------- + +1. [Read this first](https://github.com/morhetz/gruvbox/wiki/Terminal-specific) +2. Typeface from gallery is [Fantasque Sans Mono](https://github.com/belluzj/fantasque-sans) +3. Typeface from screenshots below is [Fira Mono](https://mozilla.github.io/Fira/) + +Screenshots +----------- + +Refer [Gallery][] for more syntax-specific screenshots. + + [Gallery]: https://github.com/morhetz/gruvbox/wiki/Gallery + +### Dark mode + +![Screenshot Dark](http://i.imgur.com/GkIl8Fn.png) + +### Light mode + +![Screenshot Light](http://i.imgur.com/X75niEa.png) + +### Airline theme + +![Screenshot Airline](http://i.imgur.com/wRQceUR.png) + +Palette +------- + +### Dark mode + +![Palette Dark](http://i.imgur.com/wa666xg.png) + +### Light mode + +![Palette Light](http://i.imgur.com/49qKyYW.png) + +Contrast options +---------------- + +Refer [wiki section][] for contrast configuration and other options. + + [wiki section]: https://github.com/morhetz/gruvbox/wiki/Configuration#ggruvbox_contrast_dark + +![Contrast Options](http://i.imgur.com/5MSbe6T.png) + +Documentation +------------- + +Please check [wiki][] for installation details, terminal-specific setup, troubleshooting, configuration options and others. + + [wiki]: https://github.com/morhetz/gruvbox/wiki + +Features +-------- + +* Lots of style-customization options (contrast, color invertion, italics usage etc.) +* Extended filetype highlighting: Html, Xml, Vim, Clojure, C, Python, JavaScript, TypeScript, PureScript, CoffeeScript, Ruby, Objective-C, Go, Lua, MoonScript, Java, Markdown, Haskell, Elixir +* Supported plugins: [EasyMotion][], [vim-sneak][], [Indent Guides][], [indentLine][], [Rainbow Parentheses][], [Airline][], [Lightline][], [GitGutter][], [Signify][], [ShowMarks][], [Signature][], [Syntastic][], [Ale][], [CtrlP][], [Startify][], [NERDTree][], [Dirvish][] + + [EasyMotion]: https://github.com/Lokaltog/vim-easymotion + [vim-sneak]: https://github.com/justinmk/vim-sneak + [Indent Guides]: https://github.com/nathanaelkane/vim-indent-guides + [indentLine]: https://github.com/Yggdroot/indentLine + [Rainbow Parentheses]: https://github.com/kien/rainbow_parentheses.vim + [Airline]: https://github.com/bling/vim-airline + [Lightline]: https://github.com/itchyny/lightline.vim + [GitGutter]: https://github.com/airblade/vim-gitgutter + [Signify]: https://github.com/mhinz/vim-signify + [ShowMarks]: http://www.vim.org/scripts/script.php?script_id=152 + [Signature]: https://github.com/kshenoy/vim-signature + [Syntastic]: https://github.com/scrooloose/syntastic + [Ale]: https://github.com/w0rp/ale + [CtrlP]: https://github.com/kien/ctrlp.vim + [Startify]: https://github.com/mhinz/vim-startify + [NERDTree]: https://github.com/scrooloose/nerdtree + [Dirvish]: https://github.com/justinmk/vim-dirvish + +Contributions +------------- + +See [gruvbox-contrib][] repo for contributions, ports and extras. + +[gruvbox-contrib]: https://github.com/morhetz/gruvbox-contrib + +ToDo +---- + +* Filetype syntax highlighting (R, TeX, Swift, Erlang) +* Plugin support (Tagbar, VimPlug) + +Self-Promotion +-------------- + +If you like gruvbox follow the repository on +[GitHub](https://github.com/morhetz/gruvbox) and vote for it on +[vim.org](http://www.vim.org/scripts/script.php?script_id=4349). + +License +------- +[MIT/X11][] + + [MIT/X11]: https://en.wikipedia.org/wiki/MIT_License diff --git a/bundle/gruvbox/autoload/airline/themes/gruvbox.vim b/bundle/gruvbox/autoload/airline/themes/gruvbox.vim new file mode 100644 index 000000000..6862a8185 --- /dev/null +++ b/bundle/gruvbox/autoload/airline/themes/gruvbox.vim @@ -0,0 +1,79 @@ +" ----------------------------------------------------------------------------- +" File: gruvbox.vim +" Description: Retro groove color scheme for Airline +" Author: morhetz +" Source: https://github.com/morhetz/gruvbox +" Last Modified: 12 Aug 2017 +" ----------------------------------------------------------------------------- + +let g:airline#themes#gruvbox#palette = {} + +function! airline#themes#gruvbox#refresh() + + let M0 = airline#themes#get_highlight('Identifier') + let accents_group = airline#themes#get_highlight('Special') + let modified_group = [M0[0], '', M0[2], '', ''] + let warning_group = airline#themes#get_highlight2(['Normal', 'bg'], ['Question', 'fg']) + let error_group = airline#themes#get_highlight2(['Normal', 'bg'], ['WarningMsg', 'fg']) + + let s:N1 = airline#themes#get_highlight2(['Normal', 'bg'], ['StatusLineNC', 'bg']) + let s:N2 = airline#themes#get_highlight2(['StatusLineNC', 'bg'], ['Pmenu', 'bg']) + let s:N3 = airline#themes#get_highlight2(['StatusLineNC', 'bg'], ['CursorLine', 'bg']) + let g:airline#themes#gruvbox#palette.normal = airline#themes#generate_color_map(s:N1, s:N2, s:N3) + let g:airline#themes#gruvbox#palette.normal_modified = { 'airline_c': modified_group } + let g:airline#themes#gruvbox#palette.normal.airline_warning = warning_group + let g:airline#themes#gruvbox#palette.normal_modified.airline_warning = warning_group + let g:airline#themes#gruvbox#palette.normal.airline_error = error_group + let g:airline#themes#gruvbox#palette.normal_modified.airline_error = error_group + + let s:I1 = airline#themes#get_highlight2(['Normal', 'bg'], ['Identifier', 'fg']) + let s:I2 = s:N2 + let s:I3 = airline#themes#get_highlight2(['Normal', 'fg'], ['Pmenu', 'bg']) + let g:airline#themes#gruvbox#palette.insert = airline#themes#generate_color_map(s:I1, s:I2, s:I3) + let g:airline#themes#gruvbox#palette.insert_modified = g:airline#themes#gruvbox#palette.normal_modified + let g:airline#themes#gruvbox#palette.insert.airline_warning = g:airline#themes#gruvbox#palette.normal.airline_warning + let g:airline#themes#gruvbox#palette.insert_modified.airline_warning = g:airline#themes#gruvbox#palette.normal_modified.airline_warning + let g:airline#themes#gruvbox#palette.insert.airline_error = g:airline#themes#gruvbox#palette.normal.airline_error + let g:airline#themes#gruvbox#palette.insert_modified.airline_error = g:airline#themes#gruvbox#palette.normal_modified.airline_error + + let s:R1 = airline#themes#get_highlight2(['Normal', 'bg'], ['Structure', 'fg']) + let s:R2 = s:I2 + let s:R3 = s:I3 + let g:airline#themes#gruvbox#palette.replace = airline#themes#generate_color_map(s:R1, s:R2, s:R3) + let g:airline#themes#gruvbox#palette.replace_modified = g:airline#themes#gruvbox#palette.normal_modified + let g:airline#themes#gruvbox#palette.replace.airline_warning = g:airline#themes#gruvbox#palette.normal.airline_warning + let g:airline#themes#gruvbox#palette.replace_modified.airline_warning = g:airline#themes#gruvbox#palette.normal_modified.airline_warning + let g:airline#themes#gruvbox#palette.replace.airline_error = g:airline#themes#gruvbox#palette.normal.airline_error + let g:airline#themes#gruvbox#palette.replace_modified.airline_error = g:airline#themes#gruvbox#palette.normal_modified.airline_error + + let s:V1 = airline#themes#get_highlight2(['Normal', 'bg'], ['Question', 'fg']) + let s:V2 = s:N2 + let s:V3 = airline#themes#get_highlight2(['Normal', 'bg'], ['TabLine', 'fg']) + let g:airline#themes#gruvbox#palette.visual = airline#themes#generate_color_map(s:V1, s:V2, s:V3) + let g:airline#themes#gruvbox#palette.visual_modified = { 'airline_c': [ s:V3[0], '', s:V3[2], '', '' ] } + let g:airline#themes#gruvbox#palette.visual.airline_warning = g:airline#themes#gruvbox#palette.normal.airline_warning + let g:airline#themes#gruvbox#palette.visual_modified.airline_warning = g:airline#themes#gruvbox#palette.normal_modified.airline_warning + let g:airline#themes#gruvbox#palette.visual.airline_error = g:airline#themes#gruvbox#palette.normal.airline_error + let g:airline#themes#gruvbox#palette.visual_modified.airline_error = g:airline#themes#gruvbox#palette.normal_modified.airline_error + + let s:IA = airline#themes#get_highlight2(['TabLine', 'fg'], ['CursorLine', 'bg']) + let g:airline#themes#gruvbox#palette.inactive = airline#themes#generate_color_map(s:IA, s:IA, s:IA) + let g:airline#themes#gruvbox#palette.inactive_modified = { 'airline_c': modified_group } + + let g:airline#themes#gruvbox#palette.accents = { 'red': accents_group } + + let s:TF = airline#themes#get_highlight2(['Normal', 'bg'], ['Normal', 'bg']) + let g:airline#themes#gruvbox#palette.tabline = { + \ 'airline_tab': s:N2, + \ 'airline_tabsel': s:N1, + \ 'airline_tabtype': s:V1, + \ 'airline_tabfill': s:TF, + \ 'airline_tabhid': s:IA, + \ 'airline_tabmod': s:I1 + \ } + +endfunction + +call airline#themes#gruvbox#refresh() + +" vim: set sw=2 ts=2 sts=2 et tw=80 ft=vim fdm=marker: diff --git a/bundle/gruvbox/autoload/gruvbox.vim b/bundle/gruvbox/autoload/gruvbox.vim new file mode 100644 index 000000000..44bec6e1e --- /dev/null +++ b/bundle/gruvbox/autoload/gruvbox.vim @@ -0,0 +1,41 @@ +" ----------------------------------------------------------------------------- +" File: gruvbox.vim +" Description: Retro groove color scheme for Vim +" Author: morhetz +" Source: https://github.com/morhetz/gruvbox +" Last Modified: 09 Apr 2014 +" ----------------------------------------------------------------------------- + +function! gruvbox#invert_signs_toggle() + if g:gruvbox_invert_signs == 0 + let g:gruvbox_invert_signs=1 + else + let g:gruvbox_invert_signs=0 + endif + + colorscheme gruvbox +endfunction + +" Search Highlighting {{{ + +function! gruvbox#hls_show() + set hlsearch + call GruvboxHlsShowCursor() +endfunction + +function! gruvbox#hls_hide() + set nohlsearch + call GruvboxHlsHideCursor() +endfunction + +function! gruvbox#hls_toggle() + if &hlsearch + call gruvbox#hls_hide() + else + call gruvbox#hls_show() + endif +endfunction + +" }}} + +" vim: set sw=2 ts=2 sts=2 et tw=80 ft=vim fdm=marker: diff --git a/bundle/gruvbox/autoload/lightline/colorscheme/gruvbox.vim b/bundle/gruvbox/autoload/lightline/colorscheme/gruvbox.vim new file mode 100644 index 000000000..4730c094c --- /dev/null +++ b/bundle/gruvbox/autoload/lightline/colorscheme/gruvbox.vim @@ -0,0 +1,57 @@ +" ----------------------------------------------------------------------------- +" File: gruvbox.vim +" Description: Gruvbox colorscheme for Lightline (itchyny/lightline.vim) +" Author: gmoe +" Source: https://github.com/morhetz/gruvbox +" Last Modified: 20 Sep 2017 +" ----------------------------------------------------------------------------- + +function! s:getGruvColor(group) + let guiColor = synIDattr(hlID(a:group), "fg", "gui") + let termColor = synIDattr(hlID(a:group), "fg", "cterm") + return [ guiColor, termColor ] +endfunction + +if exists('g:lightline') + + let s:bg0 = s:getGruvColor('GruvboxBg0') + let s:bg1 = s:getGruvColor('GruvboxBg1') + let s:bg2 = s:getGruvColor('GruvboxBg2') + let s:bg4 = s:getGruvColor('GruvboxBg4') + let s:fg1 = s:getGruvColor('GruvboxFg1') + let s:fg4 = s:getGruvColor('GruvboxFg4') + + let s:yellow = s:getGruvColor('GruvboxYellow') + let s:blue = s:getGruvColor('GruvboxBlue') + let s:aqua = s:getGruvColor('GruvboxAqua') + let s:orange = s:getGruvColor('GruvboxOrange') + let s:green = s:getGruvColor('GruvboxGreen') + + let s:p = {'normal':{}, 'inactive':{}, 'insert':{}, 'replace':{}, 'visual':{}, 'tabline':{}, 'terminal':{}} + let s:p.normal.left = [ [ s:bg0, s:fg4, 'bold' ], [ s:fg4, s:bg2 ] ] + let s:p.normal.right = [ [ s:bg0, s:fg4 ], [ s:fg4, s:bg2 ] ] + let s:p.normal.middle = [ [ s:fg4, s:bg1 ] ] + let s:p.inactive.right = [ [ s:bg4, s:bg1 ], [ s:bg4, s:bg1 ] ] + let s:p.inactive.left = [ [ s:bg4, s:bg1 ], [ s:bg4, s:bg1 ] ] + let s:p.inactive.middle = [ [ s:bg4, s:bg1 ] ] + let s:p.insert.left = [ [ s:bg0, s:blue, 'bold' ], [ s:fg1, s:bg2 ] ] + let s:p.insert.right = [ [ s:bg0, s:blue ], [ s:fg1, s:bg2 ] ] + let s:p.insert.middle = [ [ s:fg4, s:bg2 ] ] + let s:p.terminal.left = [ [ s:bg0, s:green, 'bold' ], [ s:fg1, s:bg2 ] ] + let s:p.terminal.right = [ [ s:bg0, s:green ], [ s:fg1, s:bg2 ] ] + let s:p.terminal.middle = [ [ s:fg4, s:bg2 ] ] + let s:p.replace.left = [ [ s:bg0, s:aqua, 'bold' ], [ s:fg1, s:bg2 ] ] + let s:p.replace.right = [ [ s:bg0, s:aqua ], [ s:fg1, s:bg2 ] ] + let s:p.replace.middle = [ [ s:fg4, s:bg2 ] ] + let s:p.visual.left = [ [ s:bg0, s:orange, 'bold' ], [ s:bg0, s:bg4 ] ] + let s:p.visual.right = [ [ s:bg0, s:orange ], [ s:bg0, s:bg4 ] ] + let s:p.visual.middle = [ [ s:fg4, s:bg1 ] ] + let s:p.tabline.left = [ [ s:fg4, s:bg2 ] ] + let s:p.tabline.tabsel = [ [ s:bg0, s:fg4 ] ] + let s:p.tabline.middle = [ [ s:bg0, s:bg0 ] ] + let s:p.tabline.right = [ [ s:bg0, s:orange ] ] + let s:p.normal.error = [ [ s:bg0, s:orange ] ] + let s:p.normal.warning = [ [ s:bg2, s:yellow ] ] + + let g:lightline#colorscheme#gruvbox#palette = lightline#colorscheme#flatten(s:p) +endif diff --git a/bundle/gruvbox/colors/gruvbox.vim b/bundle/gruvbox/colors/gruvbox.vim new file mode 100644 index 000000000..66246fba2 --- /dev/null +++ b/bundle/gruvbox/colors/gruvbox.vim @@ -0,0 +1,1418 @@ +" ----------------------------------------------------------------------------- +" File: gruvbox.vim +" Description: Retro groove color scheme for Vim +" Author: morhetz +" Source: https://github.com/morhetz/gruvbox +" Last Modified: 12 Aug 2017 +" ----------------------------------------------------------------------------- + +" Supporting code ------------------------------------------------------------- +" Initialisation: {{{ + +if version > 580 + hi clear + if exists("syntax_on") + syntax reset + endif +endif + +let g:colors_name='gruvbox' + +if !(has('termguicolors') && &termguicolors) && !has('gui_running') && &t_Co != 256 + finish +endif + +" }}} +" Global Settings: {{{ + +if !exists('g:gruvbox_bold') + let g:gruvbox_bold=1 +endif +if !exists('g:gruvbox_italic') + if has('gui_running') || $TERM_ITALICS == 'true' + let g:gruvbox_italic=1 + else + let g:gruvbox_italic=0 + endif +endif +if !exists('g:gruvbox_undercurl') + let g:gruvbox_undercurl=1 +endif +if !exists('g:gruvbox_underline') + let g:gruvbox_underline=1 +endif +if !exists('g:gruvbox_inverse') + let g:gruvbox_inverse=1 +endif + +if !exists('g:gruvbox_guisp_fallback') || index(['fg', 'bg'], g:gruvbox_guisp_fallback) == -1 + let g:gruvbox_guisp_fallback='NONE' +endif + +if !exists('g:gruvbox_improved_strings') + let g:gruvbox_improved_strings=0 +endif + +if !exists('g:gruvbox_improved_warnings') + let g:gruvbox_improved_warnings=0 +endif + +if !exists('g:gruvbox_termcolors') + let g:gruvbox_termcolors=256 +endif + +if !exists('g:gruvbox_invert_indent_guides') + let g:gruvbox_invert_indent_guides=0 +endif + +if exists('g:gruvbox_contrast') + echo 'g:gruvbox_contrast is deprecated; use g:gruvbox_contrast_light and g:gruvbox_contrast_dark instead' +endif + +if !exists('g:gruvbox_contrast_dark') + let g:gruvbox_contrast_dark='medium' +endif + +if !exists('g:gruvbox_contrast_light') + let g:gruvbox_contrast_light='medium' +endif + +let s:is_dark=(&background == 'dark') + +" }}} +" Palette: {{{ + +" setup palette dictionary +let s:gb = {} + +" fill it with absolute colors +let s:gb.dark0_hard = ['#1d2021', 234] " 29-32-33 +let s:gb.dark0 = ['#282828', 235] " 40-40-40 +let s:gb.dark0_soft = ['#32302f', 236] " 50-48-47 +let s:gb.dark1 = ['#3c3836', 237] " 60-56-54 +let s:gb.dark2 = ['#504945', 239] " 80-73-69 +let s:gb.dark3 = ['#665c54', 241] " 102-92-84 +let s:gb.dark4 = ['#7c6f64', 243] " 124-111-100 +let s:gb.dark4_256 = ['#7c6f64', 243] " 124-111-100 + +let s:gb.gray_245 = ['#928374', 245] " 146-131-116 +let s:gb.gray_244 = ['#928374', 244] " 146-131-116 + +let s:gb.light0_hard = ['#f9f5d7', 230] " 249-245-215 +let s:gb.light0 = ['#fbf1c7', 229] " 253-244-193 +let s:gb.light0_soft = ['#f2e5bc', 228] " 242-229-188 +let s:gb.light1 = ['#ebdbb2', 223] " 235-219-178 +let s:gb.light2 = ['#d5c4a1', 250] " 213-196-161 +let s:gb.light3 = ['#bdae93', 248] " 189-174-147 +let s:gb.light4 = ['#a89984', 246] " 168-153-132 +let s:gb.light4_256 = ['#a89984', 246] " 168-153-132 + +let s:gb.bright_red = ['#fb4934', 167] " 251-73-52 +let s:gb.bright_green = ['#b8bb26', 142] " 184-187-38 +let s:gb.bright_yellow = ['#fabd2f', 214] " 250-189-47 +let s:gb.bright_blue = ['#83a598', 109] " 131-165-152 +let s:gb.bright_purple = ['#d3869b', 175] " 211-134-155 +let s:gb.bright_aqua = ['#8ec07c', 108] " 142-192-124 +let s:gb.bright_orange = ['#fe8019', 208] " 254-128-25 + +let s:gb.neutral_red = ['#cc241d', 124] " 204-36-29 +let s:gb.neutral_green = ['#98971a', 106] " 152-151-26 +let s:gb.neutral_yellow = ['#d79921', 172] " 215-153-33 +let s:gb.neutral_blue = ['#458588', 66] " 69-133-136 +let s:gb.neutral_purple = ['#b16286', 132] " 177-98-134 +let s:gb.neutral_aqua = ['#689d6a', 72] " 104-157-106 +let s:gb.neutral_orange = ['#d65d0e', 166] " 214-93-14 + +let s:gb.faded_red = ['#9d0006', 88] " 157-0-6 +let s:gb.faded_green = ['#79740e', 100] " 121-116-14 +let s:gb.faded_yellow = ['#b57614', 136] " 181-118-20 +let s:gb.faded_blue = ['#076678', 24] " 7-102-120 +let s:gb.faded_purple = ['#8f3f71', 96] " 143-63-113 +let s:gb.faded_aqua = ['#427b58', 66] " 66-123-88 +let s:gb.faded_orange = ['#af3a03', 130] " 175-58-3 + +" }}} +" Setup Emphasis: {{{ + +let s:bold = 'bold,' +if g:gruvbox_bold == 0 + let s:bold = '' +endif + +let s:italic = 'italic,' +if g:gruvbox_italic == 0 + let s:italic = '' +endif + +let s:underline = 'underline,' +if g:gruvbox_underline == 0 + let s:underline = '' +endif + +let s:undercurl = 'undercurl,' +if g:gruvbox_undercurl == 0 + let s:undercurl = '' +endif + +let s:inverse = 'inverse,' +if g:gruvbox_inverse == 0 + let s:inverse = '' +endif + +" }}} +" Setup Colors: {{{ + +let s:vim_bg = ['bg', 'bg'] +let s:vim_fg = ['fg', 'fg'] +let s:none = ['NONE', 'NONE'] + +" determine relative colors +if s:is_dark + let s:bg0 = s:gb.dark0 + if g:gruvbox_contrast_dark == 'soft' + let s:bg0 = s:gb.dark0_soft + elseif g:gruvbox_contrast_dark == 'hard' + let s:bg0 = s:gb.dark0_hard + endif + + let s:bg1 = s:gb.dark1 + let s:bg2 = s:gb.dark2 + let s:bg3 = s:gb.dark3 + let s:bg4 = s:gb.dark4 + + let s:gray = s:gb.gray_245 + + let s:fg0 = s:gb.light0 + let s:fg1 = s:gb.light1 + let s:fg2 = s:gb.light2 + let s:fg3 = s:gb.light3 + let s:fg4 = s:gb.light4 + + let s:fg4_256 = s:gb.light4_256 + + let s:red = s:gb.bright_red + let s:green = s:gb.bright_green + let s:yellow = s:gb.bright_yellow + let s:blue = s:gb.bright_blue + let s:purple = s:gb.bright_purple + let s:aqua = s:gb.bright_aqua + let s:orange = s:gb.bright_orange +else + let s:bg0 = s:gb.light0 + if g:gruvbox_contrast_light == 'soft' + let s:bg0 = s:gb.light0_soft + elseif g:gruvbox_contrast_light == 'hard' + let s:bg0 = s:gb.light0_hard + endif + + let s:bg1 = s:gb.light1 + let s:bg2 = s:gb.light2 + let s:bg3 = s:gb.light3 + let s:bg4 = s:gb.light4 + + let s:gray = s:gb.gray_244 + + let s:fg0 = s:gb.dark0 + let s:fg1 = s:gb.dark1 + let s:fg2 = s:gb.dark2 + let s:fg3 = s:gb.dark3 + let s:fg4 = s:gb.dark4 + + let s:fg4_256 = s:gb.dark4_256 + + let s:red = s:gb.faded_red + let s:green = s:gb.faded_green + let s:yellow = s:gb.faded_yellow + let s:blue = s:gb.faded_blue + let s:purple = s:gb.faded_purple + let s:aqua = s:gb.faded_aqua + let s:orange = s:gb.faded_orange +endif + +" reset to 16 colors fallback +if g:gruvbox_termcolors == 16 + let s:bg0[1] = 0 + let s:fg4[1] = 7 + let s:gray[1] = 8 + let s:red[1] = 9 + let s:green[1] = 10 + let s:yellow[1] = 11 + let s:blue[1] = 12 + let s:purple[1] = 13 + let s:aqua[1] = 14 + let s:fg1[1] = 15 +endif + +" save current relative colors back to palette dictionary +let s:gb.bg0 = s:bg0 +let s:gb.bg1 = s:bg1 +let s:gb.bg2 = s:bg2 +let s:gb.bg3 = s:bg3 +let s:gb.bg4 = s:bg4 + +let s:gb.gray = s:gray + +let s:gb.fg0 = s:fg0 +let s:gb.fg1 = s:fg1 +let s:gb.fg2 = s:fg2 +let s:gb.fg3 = s:fg3 +let s:gb.fg4 = s:fg4 + +let s:gb.fg4_256 = s:fg4_256 + +let s:gb.red = s:red +let s:gb.green = s:green +let s:gb.yellow = s:yellow +let s:gb.blue = s:blue +let s:gb.purple = s:purple +let s:gb.aqua = s:aqua +let s:gb.orange = s:orange + +" }}} +" Setup Terminal Colors For Neovim: {{{ + +if has('nvim') + let g:terminal_color_0 = s:bg0[0] + let g:terminal_color_8 = s:gray[0] + + let g:terminal_color_1 = s:gb.neutral_red[0] + let g:terminal_color_9 = s:red[0] + + let g:terminal_color_2 = s:gb.neutral_green[0] + let g:terminal_color_10 = s:green[0] + + let g:terminal_color_3 = s:gb.neutral_yellow[0] + let g:terminal_color_11 = s:yellow[0] + + let g:terminal_color_4 = s:gb.neutral_blue[0] + let g:terminal_color_12 = s:blue[0] + + let g:terminal_color_5 = s:gb.neutral_purple[0] + let g:terminal_color_13 = s:purple[0] + + let g:terminal_color_6 = s:gb.neutral_aqua[0] + let g:terminal_color_14 = s:aqua[0] + + let g:terminal_color_7 = s:fg4[0] + let g:terminal_color_15 = s:fg1[0] +endif + +" }}} +" Overload Setting: {{{ + +let s:hls_cursor = s:orange +if exists('g:gruvbox_hls_cursor') + let s:hls_cursor = get(s:gb, g:gruvbox_hls_cursor) +endif + +let s:number_column = s:none +if exists('g:gruvbox_number_column') + let s:number_column = get(s:gb, g:gruvbox_number_column) +endif + +let s:sign_column = s:bg1 + +if exists('g:gitgutter_override_sign_column_highlight') && + \ g:gitgutter_override_sign_column_highlight == 1 + let s:sign_column = s:number_column +else + let g:gitgutter_override_sign_column_highlight = 0 + + if exists('g:gruvbox_sign_column') + let s:sign_column = get(s:gb, g:gruvbox_sign_column) + endif +endif + +let s:color_column = s:bg1 +if exists('g:gruvbox_color_column') + let s:color_column = get(s:gb, g:gruvbox_color_column) +endif + +let s:vert_split = s:bg0 +if exists('g:gruvbox_vert_split') + let s:vert_split = get(s:gb, g:gruvbox_vert_split) +endif + +let s:invert_signs = '' +if exists('g:gruvbox_invert_signs') + if g:gruvbox_invert_signs == 1 + let s:invert_signs = s:inverse + endif +endif + +let s:invert_selection = s:inverse +if exists('g:gruvbox_invert_selection') + if g:gruvbox_invert_selection == 0 + let s:invert_selection = '' + endif +endif + +let s:invert_tabline = '' +if exists('g:gruvbox_invert_tabline') + if g:gruvbox_invert_tabline == 1 + let s:invert_tabline = s:inverse + endif +endif + +let s:italicize_comments = s:italic +if exists('g:gruvbox_italicize_comments') + if g:gruvbox_italicize_comments == 0 + let s:italicize_comments = '' + endif +endif + +let s:italicize_strings = '' +if exists('g:gruvbox_italicize_strings') + if g:gruvbox_italicize_strings == 1 + let s:italicize_strings = s:italic + endif +endif + +" }}} +" Highlighting Function: {{{ + +function! s:HL(group, fg, ...) + " Arguments: group, guifg, guibg, gui, guisp + + " foreground + let fg = a:fg + + " background + if a:0 >= 1 + let bg = a:1 + else + let bg = s:none + endif + + " emphasis + if a:0 >= 2 && strlen(a:2) + let emstr = a:2 + else + let emstr = 'NONE,' + endif + + " special fallback + if a:0 >= 3 + if g:gruvbox_guisp_fallback != 'NONE' + let fg = a:3 + endif + + " bg fallback mode should invert higlighting + if g:gruvbox_guisp_fallback == 'bg' + let emstr .= 'inverse,' + endif + endif + + let histring = [ 'hi', a:group, + \ 'guifg=' . fg[0], 'ctermfg=' . fg[1], + \ 'guibg=' . bg[0], 'ctermbg=' . bg[1], + \ 'gui=' . emstr[:-2], 'cterm=' . emstr[:-2] + \ ] + + " special + if a:0 >= 3 + call add(histring, 'guisp=' . a:3[0]) + endif + + execute join(histring, ' ') +endfunction + +" }}} +" Gruvbox Hi Groups: {{{ + +" memoize common hi groups +call s:HL('GruvboxFg0', s:fg0) +call s:HL('GruvboxFg1', s:fg1) +call s:HL('GruvboxFg2', s:fg2) +call s:HL('GruvboxFg3', s:fg3) +call s:HL('GruvboxFg4', s:fg4) +call s:HL('GruvboxGray', s:gray) +call s:HL('GruvboxBg0', s:bg0) +call s:HL('GruvboxBg1', s:bg1) +call s:HL('GruvboxBg2', s:bg2) +call s:HL('GruvboxBg3', s:bg3) +call s:HL('GruvboxBg4', s:bg4) + +call s:HL('GruvboxRed', s:red) +call s:HL('GruvboxRedBold', s:red, s:none, s:bold) +call s:HL('GruvboxGreen', s:green) +call s:HL('GruvboxGreenBold', s:green, s:none, s:bold) +call s:HL('GruvboxYellow', s:yellow) +call s:HL('GruvboxYellowBold', s:yellow, s:none, s:bold) +call s:HL('GruvboxBlue', s:blue) +call s:HL('GruvboxBlueBold', s:blue, s:none, s:bold) +call s:HL('GruvboxPurple', s:purple) +call s:HL('GruvboxPurpleBold', s:purple, s:none, s:bold) +call s:HL('GruvboxAqua', s:aqua) +call s:HL('GruvboxAquaBold', s:aqua, s:none, s:bold) +call s:HL('GruvboxOrange', s:orange) +call s:HL('GruvboxOrangeBold', s:orange, s:none, s:bold) + +call s:HL('GruvboxRedSign', s:red, s:sign_column, s:invert_signs) +call s:HL('GruvboxGreenSign', s:green, s:sign_column, s:invert_signs) +call s:HL('GruvboxYellowSign', s:yellow, s:sign_column, s:invert_signs) +call s:HL('GruvboxBlueSign', s:blue, s:sign_column, s:invert_signs) +call s:HL('GruvboxPurpleSign', s:purple, s:sign_column, s:invert_signs) +call s:HL('GruvboxAquaSign', s:aqua, s:sign_column, s:invert_signs) +call s:HL('GruvboxOrangeSign', s:orange, s:sign_column, s:invert_signs) + +" }}} + +" Vanilla colorscheme --------------------------------------------------------- +" General UI: {{{ + +" Normal text +call s:HL('Normal', s:fg1, s:bg0) + +" Correct background (see issue #7): +" --- Problem with changing between dark and light on 256 color terminal +" --- https://github.com/morhetz/gruvbox/issues/7 +if s:is_dark + set background=dark +else + set background=light +endif + +if version >= 700 + " Screen line that the cursor is + call s:HL('CursorLine', s:none, s:bg1) + " Screen column that the cursor is + hi! link CursorColumn CursorLine + + " Tab pages line filler + call s:HL('TabLineFill', s:bg4, s:bg1, s:invert_tabline) + " Active tab page label + call s:HL('TabLineSel', s:green, s:bg1, s:invert_tabline) + " Not active tab page label + hi! link TabLine TabLineFill + + " Match paired bracket under the cursor + call s:HL('MatchParen', s:none, s:bg3, s:bold) +endif + +if version >= 703 + " Highlighted screen columns + call s:HL('ColorColumn', s:none, s:color_column) + + " Concealed element: \lambda → λ + call s:HL('Conceal', s:blue, s:none) + + " Line number of CursorLine + call s:HL('CursorLineNr', s:yellow, s:bg1) +endif + +hi! link NonText GruvboxBg2 +hi! link SpecialKey GruvboxBg2 + +call s:HL('Visual', s:none, s:bg3, s:invert_selection) +hi! link VisualNOS Visual + +call s:HL('Search', s:yellow, s:bg0, s:inverse) +call s:HL('IncSearch', s:hls_cursor, s:bg0, s:inverse) + +call s:HL('Underlined', s:blue, s:none, s:underline) + +call s:HL('StatusLine', s:bg2, s:fg1, s:inverse) +call s:HL('StatusLineNC', s:bg1, s:fg4, s:inverse) + +" The column separating vertically split windows +call s:HL('VertSplit', s:bg3, s:vert_split) + +" Current match in wildmenu completion +call s:HL('WildMenu', s:blue, s:bg2, s:bold) + +" Directory names, special names in listing +hi! link Directory GruvboxGreenBold + +" Titles for output from :set all, :autocmd, etc. +hi! link Title GruvboxGreenBold + +" Error messages on the command line +call s:HL('ErrorMsg', s:bg0, s:red, s:bold) +" More prompt: -- More -- +hi! link MoreMsg GruvboxYellowBold +" Current mode message: -- INSERT -- +hi! link ModeMsg GruvboxYellowBold +" 'Press enter' prompt and yes/no questions +hi! link Question GruvboxOrangeBold +" Warning messages +hi! link WarningMsg GruvboxRedBold + +" }}} +" Gutter: {{{ + +" Line number for :number and :# commands +call s:HL('LineNr', s:bg4, s:number_column) + +" Column where signs are displayed +call s:HL('SignColumn', s:none, s:sign_column) + +" Line used for closed folds +call s:HL('Folded', s:gray, s:bg1, s:italic) +" Column where folds are displayed +call s:HL('FoldColumn', s:gray, s:bg1) + +" }}} +" Cursor: {{{ + +" Character under cursor +call s:HL('Cursor', s:none, s:none, s:inverse) +" Visual mode cursor, selection +hi! link vCursor Cursor +" Input moder cursor +hi! link iCursor Cursor +" Language mapping cursor +hi! link lCursor Cursor + +" }}} +" Syntax Highlighting: {{{ + +if g:gruvbox_improved_strings == 0 + hi! link Special GruvboxOrange +else + call s:HL('Special', s:orange, s:bg1, s:italicize_strings) +endif + +call s:HL('Comment', s:gray, s:none, s:italicize_comments) +call s:HL('Todo', s:vim_fg, s:vim_bg, s:bold . s:italic) +call s:HL('Error', s:red, s:vim_bg, s:bold . s:inverse) + +" Generic statement +hi! link Statement GruvboxRed +" if, then, else, endif, swicth, etc. +hi! link Conditional GruvboxRed +" for, do, while, etc. +hi! link Repeat GruvboxRed +" case, default, etc. +hi! link Label GruvboxRed +" try, catch, throw +hi! link Exception GruvboxRed +" sizeof, "+", "*", etc. +hi! link Operator Normal +" Any other keyword +hi! link Keyword GruvboxRed + +" Variable name +hi! link Identifier GruvboxBlue +" Function name +hi! link Function GruvboxGreenBold + +" Generic preprocessor +hi! link PreProc GruvboxAqua +" Preprocessor #include +hi! link Include GruvboxAqua +" Preprocessor #define +hi! link Define GruvboxAqua +" Same as Define +hi! link Macro GruvboxAqua +" Preprocessor #if, #else, #endif, etc. +hi! link PreCondit GruvboxAqua + +" Generic constant +hi! link Constant GruvboxPurple +" Character constant: 'c', '/n' +hi! link Character GruvboxPurple +" String constant: "this is a string" +if g:gruvbox_improved_strings == 0 + call s:HL('String', s:green, s:none, s:italicize_strings) +else + call s:HL('String', s:fg1, s:bg1, s:italicize_strings) +endif +" Boolean constant: TRUE, false +hi! link Boolean GruvboxPurple +" Number constant: 234, 0xff +hi! link Number GruvboxPurple +" Floating point constant: 2.3e10 +hi! link Float GruvboxPurple + +" Generic type +hi! link Type GruvboxYellow +" static, register, volatile, etc +hi! link StorageClass GruvboxOrange +" struct, union, enum, etc. +hi! link Structure GruvboxAqua +" typedef +hi! link Typedef GruvboxYellow + +" }}} +" Completion Menu: {{{ + +if version >= 700 + " Popup menu: normal item + call s:HL('Pmenu', s:fg1, s:bg2) + " Popup menu: selected item + call s:HL('PmenuSel', s:bg2, s:blue, s:bold) + " Popup menu: scrollbar + call s:HL('PmenuSbar', s:none, s:bg2) + " Popup menu: scrollbar thumb + call s:HL('PmenuThumb', s:none, s:bg4) +endif + +" }}} +" Diffs: {{{ + +call s:HL('DiffDelete', s:red, s:bg0, s:inverse) +call s:HL('DiffAdd', s:green, s:bg0, s:inverse) +"call s:HL('DiffChange', s:bg0, s:blue) +"call s:HL('DiffText', s:bg0, s:yellow) + +" Alternative setting +call s:HL('DiffChange', s:aqua, s:bg0, s:inverse) +call s:HL('DiffText', s:yellow, s:bg0, s:inverse) + +" }}} +" Spelling: {{{ + +if has("spell") + " Not capitalised word, or compile warnings + if g:gruvbox_improved_warnings == 0 + call s:HL('SpellCap', s:none, s:none, s:undercurl, s:red) + else + call s:HL('SpellCap', s:green, s:none, s:bold . s:italic) + endif + " Not recognized word + call s:HL('SpellBad', s:none, s:none, s:undercurl, s:blue) + " Wrong spelling for selected region + call s:HL('SpellLocal', s:none, s:none, s:undercurl, s:aqua) + " Rare word + call s:HL('SpellRare', s:none, s:none, s:undercurl, s:purple) +endif + +" }}} + +" Plugin specific ------------------------------------------------------------- +" EasyMotion: {{{ + +hi! link EasyMotionTarget Search +hi! link EasyMotionShade Comment + +" }}} +" Sneak: {{{ + +hi! link Sneak Search +hi! link SneakLabel Search + +" }}} +" Indent Guides: {{{ + +if !exists('g:indent_guides_auto_colors') + let g:indent_guides_auto_colors = 0 +endif + +if g:indent_guides_auto_colors == 0 + if g:gruvbox_invert_indent_guides == 0 + call s:HL('IndentGuidesOdd', s:vim_bg, s:bg2) + call s:HL('IndentGuidesEven', s:vim_bg, s:bg1) + else + call s:HL('IndentGuidesOdd', s:vim_bg, s:bg2, s:inverse) + call s:HL('IndentGuidesEven', s:vim_bg, s:bg3, s:inverse) + endif +endif + +" }}} +" IndentLine: {{{ + +if !exists('g:indentLine_color_term') + let g:indentLine_color_term = s:bg2[1] +endif +if !exists('g:indentLine_color_gui') + let g:indentLine_color_gui = s:bg2[0] +endif + +" }}} +" Rainbow Parentheses: {{{ + +if !exists('g:rbpt_colorpairs') + let g:rbpt_colorpairs = + \ [ + \ ['blue', '#458588'], ['magenta', '#b16286'], + \ ['red', '#cc241d'], ['166', '#d65d0e'] + \ ] +endif + +let g:rainbow_guifgs = [ '#d65d0e', '#cc241d', '#b16286', '#458588' ] +let g:rainbow_ctermfgs = [ '166', 'red', 'magenta', 'blue' ] + +if !exists('g:rainbow_conf') + let g:rainbow_conf = {} +endif +if !has_key(g:rainbow_conf, 'guifgs') + let g:rainbow_conf['guifgs'] = g:rainbow_guifgs +endif +if !has_key(g:rainbow_conf, 'ctermfgs') + let g:rainbow_conf['ctermfgs'] = g:rainbow_ctermfgs +endif + +let g:niji_dark_colours = g:rbpt_colorpairs +let g:niji_light_colours = g:rbpt_colorpairs + +"}}} +" GitGutter: {{{ + +hi! link GitGutterAdd GruvboxGreenSign +hi! link GitGutterChange GruvboxAquaSign +hi! link GitGutterDelete GruvboxRedSign +hi! link GitGutterChangeDelete GruvboxAquaSign + +" }}} +" GitCommit: "{{{ + +hi! link gitcommitSelectedFile GruvboxGreen +hi! link gitcommitDiscardedFile GruvboxRed + +" }}} +" Signify: {{{ + +hi! link SignifySignAdd GruvboxGreenSign +hi! link SignifySignChange GruvboxAquaSign +hi! link SignifySignDelete GruvboxRedSign + +" }}} +" Syntastic: {{{ + +call s:HL('SyntasticError', s:none, s:none, s:undercurl, s:red) +call s:HL('SyntasticWarning', s:none, s:none, s:undercurl, s:yellow) + +hi! link SyntasticErrorSign GruvboxRedSign +hi! link SyntasticWarningSign GruvboxYellowSign + +" }}} +" Signature: {{{ +hi! link SignatureMarkText GruvboxBlueSign +hi! link SignatureMarkerText GruvboxPurpleSign + +" }}} +" ShowMarks: {{{ + +hi! link ShowMarksHLl GruvboxBlueSign +hi! link ShowMarksHLu GruvboxBlueSign +hi! link ShowMarksHLo GruvboxBlueSign +hi! link ShowMarksHLm GruvboxBlueSign + +" }}} +" CtrlP: {{{ + +hi! link CtrlPMatch GruvboxYellow +hi! link CtrlPNoEntries GruvboxRed +hi! link CtrlPPrtBase GruvboxBg2 +hi! link CtrlPPrtCursor GruvboxBlue +hi! link CtrlPLinePre GruvboxBg2 + +call s:HL('CtrlPMode1', s:blue, s:bg2, s:bold) +call s:HL('CtrlPMode2', s:bg0, s:blue, s:bold) +call s:HL('CtrlPStats', s:fg4, s:bg2, s:bold) + +" }}} +" Startify: {{{ + +hi! link StartifyBracket GruvboxFg3 +hi! link StartifyFile GruvboxFg1 +hi! link StartifyNumber GruvboxBlue +hi! link StartifyPath GruvboxGray +hi! link StartifySlash GruvboxGray +hi! link StartifySection GruvboxYellow +hi! link StartifySpecial GruvboxBg2 +hi! link StartifyHeader GruvboxOrange +hi! link StartifyFooter GruvboxBg2 + +" }}} +" Vimshell: {{{ + +let g:vimshell_escape_colors = [ + \ s:bg4[0], s:red[0], s:green[0], s:yellow[0], + \ s:blue[0], s:purple[0], s:aqua[0], s:fg4[0], + \ s:bg0[0], s:red[0], s:green[0], s:orange[0], + \ s:blue[0], s:purple[0], s:aqua[0], s:fg0[0] + \ ] + +" }}} +" BufTabLine: {{{ + +call s:HL('BufTabLineCurrent', s:bg0, s:fg4) +call s:HL('BufTabLineActive', s:fg4, s:bg2) +call s:HL('BufTabLineHidden', s:bg4, s:bg1) +call s:HL('BufTabLineFill', s:bg0, s:bg0) + +" }}} +" Asynchronous Lint Engine: {{{ + +call s:HL('ALEError', s:none, s:none, s:undercurl, s:red) +call s:HL('ALEWarning', s:none, s:none, s:undercurl, s:yellow) +call s:HL('ALEInfo', s:none, s:none, s:undercurl, s:blue) + +hi! link ALEErrorSign GruvboxRedSign +hi! link ALEWarningSign GruvboxYellowSign +hi! link ALEInfoSign GruvboxBlueSign + +" }}} +" Dirvish: {{{ + +hi! link DirvishPathTail GruvboxAqua +hi! link DirvishArg GruvboxYellow + +" }}} +" Netrw: {{{ + +hi! link netrwDir GruvboxAqua +hi! link netrwClassify GruvboxAqua +hi! link netrwLink GruvboxGray +hi! link netrwSymLink GruvboxFg1 +hi! link netrwExe GruvboxYellow +hi! link netrwComment GruvboxGray +hi! link netrwList GruvboxBlue +hi! link netrwHelpCmd GruvboxAqua +hi! link netrwCmdSep GruvboxFg3 +hi! link netrwVersion GruvboxGreen + +" }}} +" NERDTree: {{{ + +hi! link NERDTreeDir GruvboxAqua +hi! link NERDTreeDirSlash GruvboxAqua + +hi! link NERDTreeOpenable GruvboxOrange +hi! link NERDTreeClosable GruvboxOrange + +hi! link NERDTreeFile GruvboxFg1 +hi! link NERDTreeExecFile GruvboxYellow + +hi! link NERDTreeUp GruvboxGray +hi! link NERDTreeCWD GruvboxGreen +hi! link NERDTreeHelp GruvboxFg1 + +hi! link NERDTreeToggleOn GruvboxGreen +hi! link NERDTreeToggleOff GruvboxRed + +" }}} +" Vim Multiple Cursors: {{{ + +call s:HL('multiple_cursors_cursor', s:none, s:none, s:inverse) +call s:HL('multiple_cursors_visual', s:none, s:bg2) + +" }}} +" coc.nvim: {{{ + +hi! link CocErrorSign GruvboxRedSign +hi! link CocWarningSign GruvboxOrangeSign +hi! link CocInfoSign GruvboxYellowSign +hi! link CocHintSign GruvboxBlueSign +hi! link CocErrorFloat GruvboxRed +hi! link CocWarningFloat GruvboxOrange +hi! link CocInfoFloat GruvboxYellow +hi! link CocHintFloat GruvboxBlue +hi! link CocDiagnosticsError GruvboxRed +hi! link CocDiagnosticsWarning GruvboxOrange +hi! link CocDiagnosticsInfo GruvboxYellow +hi! link CocDiagnosticsHint GruvboxBlue + +hi! link CocSelectedText GruvboxRed +hi! link CocCodeLens GruvboxGray + +call s:HL('CocErrorHighlight', s:none, s:none, s:undercurl, s:red) +call s:HL('CocWarningHighlight', s:none, s:none, s:undercurl, s:orange) +call s:HL('CocInfoHighlight', s:none, s:none, s:undercurl, s:yellow) +call s:HL('CocHintHighlight', s:none, s:none, s:undercurl, s:blue) + +" }}} + +" Filetype specific ----------------------------------------------------------- +" Diff: {{{ + +hi! link diffAdded GruvboxGreen +hi! link diffRemoved GruvboxRed +hi! link diffChanged GruvboxAqua + +hi! link diffFile GruvboxOrange +hi! link diffNewFile GruvboxYellow + +hi! link diffLine GruvboxBlue + +" }}} +" Html: {{{ + +hi! link htmlTag GruvboxBlue +hi! link htmlEndTag GruvboxBlue + +hi! link htmlTagName GruvboxAquaBold +hi! link htmlArg GruvboxAqua + +hi! link htmlScriptTag GruvboxPurple +hi! link htmlTagN GruvboxFg1 +hi! link htmlSpecialTagName GruvboxAquaBold + +call s:HL('htmlLink', s:fg4, s:none, s:underline) + +hi! link htmlSpecialChar GruvboxOrange + +call s:HL('htmlBold', s:vim_fg, s:vim_bg, s:bold) +call s:HL('htmlBoldUnderline', s:vim_fg, s:vim_bg, s:bold . s:underline) +call s:HL('htmlBoldItalic', s:vim_fg, s:vim_bg, s:bold . s:italic) +call s:HL('htmlBoldUnderlineItalic', s:vim_fg, s:vim_bg, s:bold . s:underline . s:italic) + +call s:HL('htmlUnderline', s:vim_fg, s:vim_bg, s:underline) +call s:HL('htmlUnderlineItalic', s:vim_fg, s:vim_bg, s:underline . s:italic) +call s:HL('htmlItalic', s:vim_fg, s:vim_bg, s:italic) + +" }}} +" Xml: {{{ + +hi! link xmlTag GruvboxBlue +hi! link xmlEndTag GruvboxBlue +hi! link xmlTagName GruvboxBlue +hi! link xmlEqual GruvboxBlue +hi! link docbkKeyword GruvboxAquaBold + +hi! link xmlDocTypeDecl GruvboxGray +hi! link xmlDocTypeKeyword GruvboxPurple +hi! link xmlCdataStart GruvboxGray +hi! link xmlCdataCdata GruvboxPurple +hi! link dtdFunction GruvboxGray +hi! link dtdTagName GruvboxPurple + +hi! link xmlAttrib GruvboxAqua +hi! link xmlProcessingDelim GruvboxGray +hi! link dtdParamEntityPunct GruvboxGray +hi! link dtdParamEntityDPunct GruvboxGray +hi! link xmlAttribPunct GruvboxGray + +hi! link xmlEntity GruvboxOrange +hi! link xmlEntityPunct GruvboxOrange +" }}} +" Vim: {{{ + +call s:HL('vimCommentTitle', s:fg4_256, s:none, s:bold . s:italicize_comments) + +hi! link vimNotation GruvboxOrange +hi! link vimBracket GruvboxOrange +hi! link vimMapModKey GruvboxOrange +hi! link vimFuncSID GruvboxFg3 +hi! link vimSetSep GruvboxFg3 +hi! link vimSep GruvboxFg3 +hi! link vimContinue GruvboxFg3 + +" }}} +" Clojure: {{{ + +hi! link clojureKeyword GruvboxBlue +hi! link clojureCond GruvboxOrange +hi! link clojureSpecial GruvboxOrange +hi! link clojureDefine GruvboxOrange + +hi! link clojureFunc GruvboxYellow +hi! link clojureRepeat GruvboxYellow +hi! link clojureCharacter GruvboxAqua +hi! link clojureStringEscape GruvboxAqua +hi! link clojureException GruvboxRed + +hi! link clojureRegexp GruvboxAqua +hi! link clojureRegexpEscape GruvboxAqua +call s:HL('clojureRegexpCharClass', s:fg3, s:none, s:bold) +hi! link clojureRegexpMod clojureRegexpCharClass +hi! link clojureRegexpQuantifier clojureRegexpCharClass + +hi! link clojureParen GruvboxFg3 +hi! link clojureAnonArg GruvboxYellow +hi! link clojureVariable GruvboxBlue +hi! link clojureMacro GruvboxOrange + +hi! link clojureMeta GruvboxYellow +hi! link clojureDeref GruvboxYellow +hi! link clojureQuote GruvboxYellow +hi! link clojureUnquote GruvboxYellow + +" }}} +" C: {{{ + +hi! link cOperator GruvboxPurple +hi! link cStructure GruvboxOrange + +" }}} +" Python: {{{ + +hi! link pythonBuiltin GruvboxOrange +hi! link pythonBuiltinObj GruvboxOrange +hi! link pythonBuiltinFunc GruvboxOrange +hi! link pythonFunction GruvboxAqua +hi! link pythonDecorator GruvboxRed +hi! link pythonInclude GruvboxBlue +hi! link pythonImport GruvboxBlue +hi! link pythonRun GruvboxBlue +hi! link pythonCoding GruvboxBlue +hi! link pythonOperator GruvboxRed +hi! link pythonException GruvboxRed +hi! link pythonExceptions GruvboxPurple +hi! link pythonBoolean GruvboxPurple +hi! link pythonDot GruvboxFg3 +hi! link pythonConditional GruvboxRed +hi! link pythonRepeat GruvboxRed +hi! link pythonDottedName GruvboxGreenBold + +" }}} +" CSS: {{{ + +hi! link cssBraces GruvboxBlue +hi! link cssFunctionName GruvboxYellow +hi! link cssIdentifier GruvboxOrange +hi! link cssClassName GruvboxGreen +hi! link cssColor GruvboxBlue +hi! link cssSelectorOp GruvboxBlue +hi! link cssSelectorOp2 GruvboxBlue +hi! link cssImportant GruvboxGreen +hi! link cssVendor GruvboxFg1 + +hi! link cssTextProp GruvboxAqua +hi! link cssAnimationProp GruvboxAqua +hi! link cssUIProp GruvboxYellow +hi! link cssTransformProp GruvboxAqua +hi! link cssTransitionProp GruvboxAqua +hi! link cssPrintProp GruvboxAqua +hi! link cssPositioningProp GruvboxYellow +hi! link cssBoxProp GruvboxAqua +hi! link cssFontDescriptorProp GruvboxAqua +hi! link cssFlexibleBoxProp GruvboxAqua +hi! link cssBorderOutlineProp GruvboxAqua +hi! link cssBackgroundProp GruvboxAqua +hi! link cssMarginProp GruvboxAqua +hi! link cssListProp GruvboxAqua +hi! link cssTableProp GruvboxAqua +hi! link cssFontProp GruvboxAqua +hi! link cssPaddingProp GruvboxAqua +hi! link cssDimensionProp GruvboxAqua +hi! link cssRenderProp GruvboxAqua +hi! link cssColorProp GruvboxAqua +hi! link cssGeneratedContentProp GruvboxAqua + +" }}} +" JavaScript: {{{ + +hi! link javaScriptBraces GruvboxFg1 +hi! link javaScriptFunction GruvboxAqua +hi! link javaScriptIdentifier GruvboxRed +hi! link javaScriptMember GruvboxBlue +hi! link javaScriptNumber GruvboxPurple +hi! link javaScriptNull GruvboxPurple +hi! link javaScriptParens GruvboxFg3 + +" }}} +" YAJS: {{{ + +hi! link javascriptImport GruvboxAqua +hi! link javascriptExport GruvboxAqua +hi! link javascriptClassKeyword GruvboxAqua +hi! link javascriptClassExtends GruvboxAqua +hi! link javascriptDefault GruvboxAqua + +hi! link javascriptClassName GruvboxYellow +hi! link javascriptClassSuperName GruvboxYellow +hi! link javascriptGlobal GruvboxYellow + +hi! link javascriptEndColons GruvboxFg1 +hi! link javascriptFuncArg GruvboxFg1 +hi! link javascriptGlobalMethod GruvboxFg1 +hi! link javascriptNodeGlobal GruvboxFg1 +hi! link javascriptBOMWindowProp GruvboxFg1 +hi! link javascriptArrayMethod GruvboxFg1 +hi! link javascriptArrayStaticMethod GruvboxFg1 +hi! link javascriptCacheMethod GruvboxFg1 +hi! link javascriptDateMethod GruvboxFg1 +hi! link javascriptMathStaticMethod GruvboxFg1 + +" hi! link javascriptProp GruvboxFg1 +hi! link javascriptURLUtilsProp GruvboxFg1 +hi! link javascriptBOMNavigatorProp GruvboxFg1 +hi! link javascriptDOMDocMethod GruvboxFg1 +hi! link javascriptDOMDocProp GruvboxFg1 +hi! link javascriptBOMLocationMethod GruvboxFg1 +hi! link javascriptBOMWindowMethod GruvboxFg1 +hi! link javascriptStringMethod GruvboxFg1 + +hi! link javascriptVariable GruvboxOrange +" hi! link javascriptVariable GruvboxRed +" hi! link javascriptIdentifier GruvboxOrange +" hi! link javascriptClassSuper GruvboxOrange +hi! link javascriptIdentifier GruvboxOrange +hi! link javascriptClassSuper GruvboxOrange + +" hi! link javascriptFuncKeyword GruvboxOrange +" hi! link javascriptAsyncFunc GruvboxOrange +hi! link javascriptFuncKeyword GruvboxAqua +hi! link javascriptAsyncFunc GruvboxAqua +hi! link javascriptClassStatic GruvboxOrange + +hi! link javascriptOperator GruvboxRed +hi! link javascriptForOperator GruvboxRed +hi! link javascriptYield GruvboxRed +hi! link javascriptExceptions GruvboxRed +hi! link javascriptMessage GruvboxRed + +hi! link javascriptTemplateSB GruvboxAqua +hi! link javascriptTemplateSubstitution GruvboxFg1 + +" hi! link javascriptLabel GruvboxBlue +" hi! link javascriptObjectLabel GruvboxBlue +" hi! link javascriptPropertyName GruvboxBlue +hi! link javascriptLabel GruvboxFg1 +hi! link javascriptObjectLabel GruvboxFg1 +hi! link javascriptPropertyName GruvboxFg1 + +hi! link javascriptLogicSymbols GruvboxFg1 +hi! link javascriptArrowFunc GruvboxYellow + +hi! link javascriptDocParamName GruvboxFg4 +hi! link javascriptDocTags GruvboxFg4 +hi! link javascriptDocNotation GruvboxFg4 +hi! link javascriptDocParamType GruvboxFg4 +hi! link javascriptDocNamedParamType GruvboxFg4 + +hi! link javascriptBrackets GruvboxFg1 +hi! link javascriptDOMElemAttrs GruvboxFg1 +hi! link javascriptDOMEventMethod GruvboxFg1 +hi! link javascriptDOMNodeMethod GruvboxFg1 +hi! link javascriptDOMStorageMethod GruvboxFg1 +hi! link javascriptHeadersMethod GruvboxFg1 + +hi! link javascriptAsyncFuncKeyword GruvboxRed +hi! link javascriptAwaitFuncKeyword GruvboxRed + +" }}} +" PanglossJS: {{{ + +hi! link jsClassKeyword GruvboxAqua +hi! link jsExtendsKeyword GruvboxAqua +hi! link jsExportDefault GruvboxAqua +hi! link jsTemplateBraces GruvboxAqua +hi! link jsGlobalNodeObjects GruvboxFg1 +hi! link jsGlobalObjects GruvboxFg1 +hi! link jsFunction GruvboxAqua +hi! link jsFuncParens GruvboxFg3 +hi! link jsParens GruvboxFg3 +hi! link jsNull GruvboxPurple +hi! link jsUndefined GruvboxPurple +hi! link jsClassDefinition GruvboxYellow + +" }}} +" TypeScript: {{{ + +hi! link typeScriptReserved GruvboxAqua +hi! link typeScriptLabel GruvboxAqua +hi! link typeScriptFuncKeyword GruvboxAqua +hi! link typeScriptIdentifier GruvboxOrange +hi! link typeScriptBraces GruvboxFg1 +hi! link typeScriptEndColons GruvboxFg1 +hi! link typeScriptDOMObjects GruvboxFg1 +hi! link typeScriptAjaxMethods GruvboxFg1 +hi! link typeScriptLogicSymbols GruvboxFg1 +hi! link typeScriptDocSeeTag Comment +hi! link typeScriptDocParam Comment +hi! link typeScriptDocTags vimCommentTitle +hi! link typeScriptGlobalObjects GruvboxFg1 +hi! link typeScriptParens GruvboxFg3 +hi! link typeScriptOpSymbols GruvboxFg3 +hi! link typeScriptHtmlElemProperties GruvboxFg1 +hi! link typeScriptNull GruvboxPurple +hi! link typeScriptInterpolationDelimiter GruvboxAqua + +" }}} +" PureScript: {{{ + +hi! link purescriptModuleKeyword GruvboxAqua +hi! link purescriptModuleName GruvboxFg1 +hi! link purescriptWhere GruvboxAqua +hi! link purescriptDelimiter GruvboxFg4 +hi! link purescriptType GruvboxFg1 +hi! link purescriptImportKeyword GruvboxAqua +hi! link purescriptHidingKeyword GruvboxAqua +hi! link purescriptAsKeyword GruvboxAqua +hi! link purescriptStructure GruvboxAqua +hi! link purescriptOperator GruvboxBlue + +hi! link purescriptTypeVar GruvboxFg1 +hi! link purescriptConstructor GruvboxFg1 +hi! link purescriptFunction GruvboxFg1 +hi! link purescriptConditional GruvboxOrange +hi! link purescriptBacktick GruvboxOrange + +" }}} +" CoffeeScript: {{{ + +hi! link coffeeExtendedOp GruvboxFg3 +hi! link coffeeSpecialOp GruvboxFg3 +hi! link coffeeCurly GruvboxOrange +hi! link coffeeParen GruvboxFg3 +hi! link coffeeBracket GruvboxOrange + +" }}} +" Ruby: {{{ + +hi! link rubyStringDelimiter GruvboxGreen +hi! link rubyInterpolationDelimiter GruvboxAqua + +" }}} +" ObjectiveC: {{{ + +hi! link objcTypeModifier GruvboxRed +hi! link objcDirective GruvboxBlue + +" }}} +" Go: {{{ + +hi! link goDirective GruvboxAqua +hi! link goConstants GruvboxPurple +hi! link goDeclaration GruvboxRed +hi! link goDeclType GruvboxBlue +hi! link goBuiltins GruvboxOrange + +" }}} +" Lua: {{{ + +hi! link luaIn GruvboxRed +hi! link luaFunction GruvboxAqua +hi! link luaTable GruvboxOrange + +" }}} +" MoonScript: {{{ + +hi! link moonSpecialOp GruvboxFg3 +hi! link moonExtendedOp GruvboxFg3 +hi! link moonFunction GruvboxFg3 +hi! link moonObject GruvboxYellow + +" }}} +" Java: {{{ + +hi! link javaAnnotation GruvboxBlue +hi! link javaDocTags GruvboxAqua +hi! link javaCommentTitle vimCommentTitle +hi! link javaParen GruvboxFg3 +hi! link javaParen1 GruvboxFg3 +hi! link javaParen2 GruvboxFg3 +hi! link javaParen3 GruvboxFg3 +hi! link javaParen4 GruvboxFg3 +hi! link javaParen5 GruvboxFg3 +hi! link javaOperator GruvboxOrange + +hi! link javaVarArg GruvboxGreen + +" }}} +" Elixir: {{{ + +hi! link elixirDocString Comment + +hi! link elixirStringDelimiter GruvboxGreen +hi! link elixirInterpolationDelimiter GruvboxAqua + +hi! link elixirModuleDeclaration GruvboxYellow + +" }}} +" Scala: {{{ + +" NB: scala vim syntax file is kinda horrible +hi! link scalaNameDefinition GruvboxFg1 +hi! link scalaCaseFollowing GruvboxFg1 +hi! link scalaCapitalWord GruvboxFg1 +hi! link scalaTypeExtension GruvboxFg1 + +hi! link scalaKeyword GruvboxRed +hi! link scalaKeywordModifier GruvboxRed + +hi! link scalaSpecial GruvboxAqua +hi! link scalaOperator GruvboxFg1 + +hi! link scalaTypeDeclaration GruvboxYellow +hi! link scalaTypeTypePostDeclaration GruvboxYellow + +hi! link scalaInstanceDeclaration GruvboxFg1 +hi! link scalaInterpolation GruvboxAqua + +" }}} +" Markdown: {{{ + +call s:HL('markdownItalic', s:fg3, s:none, s:italic) + +hi! link markdownH1 GruvboxGreenBold +hi! link markdownH2 GruvboxGreenBold +hi! link markdownH3 GruvboxYellowBold +hi! link markdownH4 GruvboxYellowBold +hi! link markdownH5 GruvboxYellow +hi! link markdownH6 GruvboxYellow + +hi! link markdownCode GruvboxAqua +hi! link markdownCodeBlock GruvboxAqua +hi! link markdownCodeDelimiter GruvboxAqua + +hi! link markdownBlockquote GruvboxGray +hi! link markdownListMarker GruvboxGray +hi! link markdownOrderedListMarker GruvboxGray +hi! link markdownRule GruvboxGray +hi! link markdownHeadingRule GruvboxGray + +hi! link markdownUrlDelimiter GruvboxFg3 +hi! link markdownLinkDelimiter GruvboxFg3 +hi! link markdownLinkTextDelimiter GruvboxFg3 + +hi! link markdownHeadingDelimiter GruvboxOrange +hi! link markdownUrl GruvboxPurple +hi! link markdownUrlTitleDelimiter GruvboxGreen + +call s:HL('markdownLinkText', s:gray, s:none, s:underline) +hi! link markdownIdDeclaration markdownLinkText + +" }}} +" Haskell: {{{ + +" hi! link haskellType GruvboxYellow +" hi! link haskellOperators GruvboxOrange +" hi! link haskellConditional GruvboxAqua +" hi! link haskellLet GruvboxOrange +" +hi! link haskellType GruvboxFg1 +hi! link haskellIdentifier GruvboxFg1 +hi! link haskellSeparator GruvboxFg1 +hi! link haskellDelimiter GruvboxFg4 +hi! link haskellOperators GruvboxBlue +" +hi! link haskellBacktick GruvboxOrange +hi! link haskellStatement GruvboxOrange +hi! link haskellConditional GruvboxOrange + +hi! link haskellLet GruvboxAqua +hi! link haskellDefault GruvboxAqua +hi! link haskellWhere GruvboxAqua +hi! link haskellBottom GruvboxAqua +hi! link haskellBlockKeywords GruvboxAqua +hi! link haskellImportKeywords GruvboxAqua +hi! link haskellDeclKeyword GruvboxAqua +hi! link haskellDeriving GruvboxAqua +hi! link haskellAssocType GruvboxAqua + +hi! link haskellNumber GruvboxPurple +hi! link haskellPragma GruvboxPurple + +hi! link haskellString GruvboxGreen +hi! link haskellChar GruvboxGreen + +" }}} +" Json: {{{ + +hi! link jsonKeyword GruvboxGreen +hi! link jsonQuote GruvboxGreen +hi! link jsonBraces GruvboxFg1 +hi! link jsonString GruvboxFg1 + +" }}} + + +" Functions ------------------------------------------------------------------- +" Search Highlighting Cursor {{{ + +function! GruvboxHlsShowCursor() + call s:HL('Cursor', s:bg0, s:hls_cursor) +endfunction + +function! GruvboxHlsHideCursor() + call s:HL('Cursor', s:none, s:none, s:inverse) +endfunction + +" }}} + +" vim: set sw=2 ts=2 sts=2 et tw=80 ft=vim fdm=marker: diff --git a/bundle/gruvbox/gruvbox_256palette.sh b/bundle/gruvbox/gruvbox_256palette.sh new file mode 100644 index 000000000..c7fd190ed --- /dev/null +++ b/bundle/gruvbox/gruvbox_256palette.sh @@ -0,0 +1,118 @@ +#!/bin/sh + +if [ "${TERM%%-*}" = "screen" ]; then + if [ -n "$TMUX" ]; then + printf "\033Ptmux;\033\033]4;236;rgb:32/30/2f\007\033\\" + printf "\033Ptmux;\033\033]4;234;rgb:1d/20/21\007\033\\" + + printf "\033Ptmux;\033\033]4;235;rgb:28/28/28\007\033\\" + printf "\033Ptmux;\033\033]4;237;rgb:3c/38/36\007\033\\" + printf "\033Ptmux;\033\033]4;239;rgb:50/49/45\007\033\\" + printf "\033Ptmux;\033\033]4;241;rgb:66/5c/54\007\033\\" + printf "\033Ptmux;\033\033]4;243;rgb:7c/6f/64\007\033\\" + + printf "\033Ptmux;\033\033]4;244;rgb:92/83/74\007\033\\" + printf "\033Ptmux;\033\033]4;245;rgb:92/83/74\007\033\\" + + printf "\033Ptmux;\033\033]4;228;rgb:f2/e5/bc\007\033\\" + printf "\033Ptmux;\033\033]4;230;rgb:f9/f5/d7\007\033\\" + + printf "\033Ptmux;\033\033]4;229;rgb:fb/f1/c7\007\033\\" + printf "\033Ptmux;\033\033]4;223;rgb:eb/db/b2\007\033\\" + printf "\033Ptmux;\033\033]4;250;rgb:d5/c4/a1\007\033\\" + printf "\033Ptmux;\033\033]4;248;rgb:bd/ae/93\007\033\\" + printf "\033Ptmux;\033\033]4;246;rgb:a8/99/84\007\033\\" + + printf "\033Ptmux;\033\033]4;167;rgb:fb/49/34\007\033\\" + printf "\033Ptmux;\033\033]4;142;rgb:b8/bb/26\007\033\\" + printf "\033Ptmux;\033\033]4;214;rgb:fa/bd/2f\007\033\\" + printf "\033Ptmux;\033\033]4;109;rgb:83/a5/98\007\033\\" + printf "\033Ptmux;\033\033]4;175;rgb:d3/86/9b\007\033\\" + printf "\033Ptmux;\033\033]4;108;rgb:8e/c0/7c\007\033\\" + printf "\033Ptmux;\033\033]4;208;rgb:fe/80/19\007\033\\" + + printf "\033Ptmux;\033\033]4;88;rgb:9d/00/06\007\033\\" + printf "\033Ptmux;\033\033]4;100;rgb:79/74/0e\007\033\\" + printf "\033Ptmux;\033\033]4;136;rgb:b5/76/14\007\033\\" + printf "\033Ptmux;\033\033]4;24;rgb:07/66/78\007\033\\" + printf "\033Ptmux;\033\033]4;96;rgb:8f/3f/71\007\033\\" + printf "\033Ptmux;\033\033]4;66;rgb:42/7b/58\007\033\\" + printf "\033Ptmux;\033\033]4;130;rgb:af/3a/03\007\033\\" + else + printf "\033P\033]4;236;rgb:32/30/2f\007\033\\" + printf "\033P\033]4;234;rgb:1d/20/21\007\033\\" + + printf "\033P\033]4;235;rgb:28/28/28\007\033\\" + printf "\033P\033]4;237;rgb:3c/38/36\007\033\\" + printf "\033P\033]4;239;rgb:50/49/45\007\033\\" + printf "\033P\033]4;241;rgb:66/5c/54\007\033\\" + printf "\033P\033]4;243;rgb:7c/6f/64\007\033\\" + + printf "\033P\033]4;244;rgb:92/83/74\007\033\\" + printf "\033P\033]4;245;rgb:92/83/74\007\033\\" + + printf "\033P\033]4;228;rgb:f2/e5/bc\007\033\\" + printf "\033P\033]4;230;rgb:f9/f5/d7\007\033\\" + + printf "\033P\033]4;229;rgb:fb/f1/c7\007\033\\" + printf "\033P\033]4;223;rgb:eb/db/b2\007\033\\" + printf "\033P\033]4;250;rgb:d5/c4/a1\007\033\\" + printf "\033P\033]4;248;rgb:bd/ae/93\007\033\\" + printf "\033P\033]4;246;rgb:a8/99/84\007\033\\" + + printf "\033P\033]4;167;rgb:fb/49/34\007\033\\" + printf "\033P\033]4;142;rgb:b8/bb/26\007\033\\" + printf "\033P\033]4;214;rgb:fa/bd/2f\007\033\\" + printf "\033P\033]4;109;rgb:83/a5/98\007\033\\" + printf "\033P\033]4;175;rgb:d3/86/9b\007\033\\" + printf "\033P\033]4;108;rgb:8e/c0/7c\007\033\\" + printf "\033P\033]4;208;rgb:fe/80/19\007\033\\" + + printf "\033P\033]4;88;rgb:9d/00/06\007\033\\" + printf "\033P\033]4;100;rgb:79/74/0e\007\033\\" + printf "\033P\033]4;136;rgb:b5/76/14\007\033\\" + printf "\033P\033]4;24;rgb:07/66/78\007\033\\" + printf "\033P\033]4;96;rgb:8f/3f/71\007\033\\" + printf "\033P\033]4;66;rgb:42/7b/58\007\033\\" + printf "\033P\033]4;130;rgb:af/3a/03\007\033\\" + fi + +elif [ "$TERM" != "linux" ] && [ "$TERM" != "vt100" ] && [ "$TERM" != "vt220" ]; then + + printf "\033]4;236;rgb:32/30/2f\033\\" + printf "\033]4;234;rgb:1d/20/21\033\\" + + printf "\033]4;235;rgb:28/28/28\033\\" + printf "\033]4;237;rgb:3c/38/36\033\\" + printf "\033]4;239;rgb:50/49/45\033\\" + printf "\033]4;241;rgb:66/5c/54\033\\" + printf "\033]4;243;rgb:7c/6f/64\033\\" + + printf "\033]4;244;rgb:92/83/74\033\\" + printf "\033]4;245;rgb:92/83/74\033\\" + + printf "\033]4;228;rgb:f2/e5/bc\033\\" + printf "\033]4;230;rgb:f9/f5/d7\033\\" + + printf "\033]4;229;rgb:fb/f1/c7\033\\" + printf "\033]4;223;rgb:eb/db/b2\033\\" + printf "\033]4;250;rgb:d5/c4/a1\033\\" + printf "\033]4;248;rgb:bd/ae/93\033\\" + printf "\033]4;246;rgb:a8/99/84\033\\" + + printf "\033]4;167;rgb:fb/49/34\033\\" + printf "\033]4;142;rgb:b8/bb/26\033\\" + printf "\033]4;214;rgb:fa/bd/2f\033\\" + printf "\033]4;109;rgb:83/a5/98\033\\" + printf "\033]4;175;rgb:d3/86/9b\033\\" + printf "\033]4;108;rgb:8e/c0/7c\033\\" + printf "\033]4;208;rgb:fe/80/19\033\\" + + printf "\033]4;88;rgb:9d/00/06\033\\" + printf "\033]4;100;rgb:79/74/0e\033\\" + printf "\033]4;136;rgb:b5/76/14\033\\" + printf "\033]4;24;rgb:07/66/78\033\\" + printf "\033]4;96;rgb:8f/3f/71\033\\" + printf "\033]4;66;rgb:42/7b/58\033\\" + printf "\033]4;130;rgb:af/3a/03\033\\" +fi diff --git a/bundle/gruvbox/gruvbox_256palette_osx.sh b/bundle/gruvbox/gruvbox_256palette_osx.sh new file mode 100644 index 000000000..ad5111a19 --- /dev/null +++ b/bundle/gruvbox/gruvbox_256palette_osx.sh @@ -0,0 +1,116 @@ +#!/bin/sh + +if [ "${TERM%%-*}" = "screen" ]; then + if [ -n "$TMUX" ]; then + printf "\033Ptmux;\033\033]4;236;rgb:26/24/23\007\033\\" + printf "\033Ptmux;\033\033]4;234;rgb:16/18/19\007\033\\" + + printf "\033Ptmux;\033\033]4;235;rgb:1e/1e/1e\007\033\\" + printf "\033Ptmux;\033\033]4;237;rgb:2e/2a/29\007\033\\" + printf "\033Ptmux;\033\033]4;239;rgb:3f/39/35\007\033\\" + printf "\033Ptmux;\033\033]4;241;rgb:53/4a/42\007\033\\" + printf "\033Ptmux;\033\033]4;243;rgb:68/5c/51\007\033\\" + + printf "\033Ptmux;\033\033]4;244;rgb:7f/70/61\007\033\\" + printf "\033Ptmux;\033\033]4;245;rgb:7f/70/61\007\033\\" + + printf "\033Ptmux;\033\033]4;228;rgb:ef/df/ae\007\033\\" + printf "\033Ptmux;\033\033]4;230;rgb:f8/f4/cd\007\033\\" + + printf "\033Ptmux;\033\033]4;229;rgb:fa/ee/bb\007\033\\" + printf "\033Ptmux;\033\033]4;223;rgb:e6/d4/a3\007\033\\" + printf "\033Ptmux;\033\033]4;250;rgb:cb/b8/90\007\033\\" + printf "\033Ptmux;\033\033]4;248;rgb:af/9f/81\007\033\\" + printf "\033Ptmux;\033\033]4;246;rgb:97/87/71\007\033\\" + + printf "\033Ptmux;\033\033]4;167;rgb:f7/30/28\007\033\\" + printf "\033Ptmux;\033\033]4;142;rgb:aa/b0/1e\007\033\\" + printf "\033Ptmux;\033\033]4;214;rgb:f7/b1/25\007\033\\" + printf "\033Ptmux;\033\033]4;109;rgb:71/95/86\007\033\\" + printf "\033Ptmux;\033\033]4;175;rgb:c7/70/89\007\033\\" + printf "\033Ptmux;\033\033]4;108;rgb:7d/b6/69\007\033\\" + printf "\033Ptmux;\033\033]4;208;rgb:fb/6a/16\007\033\\" + + printf "\033Ptmux;\033\033]4;88;rgb:89/00/09\007\033\\" + printf "\033Ptmux;\033\033]4;100;rgb:66/62/0d\007\033\\" + printf "\033Ptmux;\033\033]4;136;rgb:a5/63/11\007\033\\" + printf "\033Ptmux;\033\033]4;24;rgb:0e/53/65\007\033\\" + printf "\033Ptmux;\033\033]4;96;rgb:7b/2b/5e\007\033\\" + printf "\033Ptmux;\033\033]4;66;rgb:35/6a/46\007\033\\" + printf "\033Ptmux;\033\033]4;130;rgb:9d/28/07\007\033\\" + else + printf "\033P\033]4;236;rgb:26/24/23\007\033\\" + printf "\033P\033]4;234;rgb:16/18/19\007\033\\" + + printf "\033P\033]4;235;rgb:1e/1e/1e\007\033\\" + printf "\033P\033]4;237;rgb:2e/2a/29\007\033\\" + printf "\033P\033]4;239;rgb:3f/39/35\007\033\\" + printf "\033P\033]4;241;rgb:53/4a/42\007\033\\" + printf "\033P\033]4;243;rgb:68/5c/51\007\033\\" + + printf "\033P\033]4;244;rgb:7f/70/61\007\033\\" + printf "\033P\033]4;245;rgb:7f/70/61\007\033\\" + + printf "\033P\033]4;228;rgb:ef/df/ae\007\033\\" + printf "\033P\033]4;230;rgb:f8/f4/cd\007\033\\" + + printf "\033P\033]4;229;rgb:fa/ee/bb\007\033\\" + printf "\033P\033]4;223;rgb:e6/d4/a3\007\033\\" + printf "\033P\033]4;250;rgb:cb/b8/90\007\033\\" + printf "\033P\033]4;248;rgb:af/9f/81\007\033\\" + printf "\033P\033]4;246;rgb:97/87/71\007\033\\" + + printf "\033P\033]4;167;rgb:f7/30/28\007\033\\" + printf "\033P\033]4;142;rgb:aa/b0/1e\007\033\\" + printf "\033P\033]4;214;rgb:f7/b1/25\007\033\\" + printf "\033P\033]4;109;rgb:71/95/86\007\033\\" + printf "\033P\033]4;175;rgb:c7/70/89\007\033\\" + printf "\033P\033]4;108;rgb:7d/b6/69\007\033\\" + printf "\033P\033]4;208;rgb:fb/6a/16\007\033\\" + + printf "\033P\033]4;88;rgb:89/00/09\007\033\\" + printf "\033P\033]4;100;rgb:66/62/0d\007\033\\" + printf "\033P\033]4;136;rgb:a5/63/11\007\033\\" + printf "\033P\033]4;24;rgb:0e/53/65\007\033\\" + printf "\033P\033]4;96;rgb:7b/2b/5e\007\033\\" + printf "\033P\033]4;66;rgb:35/6a/46\007\033\\" + printf "\033P\033]4;130;rgb:9d/28/07\007\033\\" + fi +else + printf "\033]4;236;rgb:26/24/23\033\\" + printf "\033]4;234;rgb:16/18/19\033\\" + + printf "\033]4;235;rgb:1e/1e/1e\033\\" + printf "\033]4;237;rgb:2e/2a/29\033\\" + printf "\033]4;239;rgb:3f/39/35\033\\" + printf "\033]4;241;rgb:53/4a/42\033\\" + printf "\033]4;243;rgb:68/5c/51\033\\" + + printf "\033]4;244;rgb:7f/70/61\033\\" + printf "\033]4;245;rgb:7f/70/61\033\\" + + printf "\033]4;228;rgb:ef/df/ae\033\\" + printf "\033]4;230;rgb:f8/f4/cd\033\\" + + printf "\033]4;229;rgb:fa/ee/bb\033\\" + printf "\033]4;223;rgb:e6/d4/a3\033\\" + printf "\033]4;250;rgb:cb/b8/90\033\\" + printf "\033]4;248;rgb:af/9f/81\033\\" + printf "\033]4;246;rgb:97/87/71\033\\" + + printf "\033]4;167;rgb:f7/30/28\033\\" + printf "\033]4;142;rgb:aa/b0/1e\033\\" + printf "\033]4;214;rgb:f7/b1/25\033\\" + printf "\033]4;109;rgb:71/95/86\033\\" + printf "\033]4;175;rgb:c7/70/89\033\\" + printf "\033]4;108;rgb:7d/b6/69\033\\" + printf "\033]4;208;rgb:fb/6a/16\033\\" + + printf "\033]4;88;rgb:89/00/09\033\\" + printf "\033]4;100;rgb:66/62/0d\033\\" + printf "\033]4;136;rgb:a5/63/11\033\\" + printf "\033]4;24;rgb:0e/53/65\033\\" + printf "\033]4;96;rgb:7b/2b/5e\033\\" + printf "\033]4;66;rgb:35/6a/46\033\\" + printf "\033]4;130;rgb:9d/28/07\033\\" +fi diff --git a/bundle/gruvbox/package.json b/bundle/gruvbox/package.json new file mode 100644 index 000000000..355c1808a --- /dev/null +++ b/bundle/gruvbox/package.json @@ -0,0 +1,10 @@ +{ + "name": "gruvbox", + "version": "2.0.0", + "repository": "git@github.com:morhetz/gruvbox.git", + "author": "Pavel Pertsev ", + "license": "MIT", + "vim": { + "opt": true + } +} diff --git a/bundle/indentLine/.gitignore b/bundle/indentLine/.gitignore new file mode 100644 index 000000000..e9b9a75fd --- /dev/null +++ b/bundle/indentLine/.gitignore @@ -0,0 +1,171 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store + + +############# +## Vim +############# + +# Exclude auto generated vim doc tags. +doc/tags diff --git a/bundle/indentLine/LICENSE b/bundle/indentLine/LICENSE new file mode 100644 index 000000000..438d512d4 --- /dev/null +++ b/bundle/indentLine/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Yggdroot + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/bundle/indentLine/README.md b/bundle/indentLine/README.md new file mode 100644 index 000000000..91bca2837 --- /dev/null +++ b/bundle/indentLine/README.md @@ -0,0 +1,132 @@ +indentLine +========== + +This plugin is used for displaying thin vertical lines at each indentation level for code indented with spaces. For code indented with tabs I think there is no need to support it, because you can use `:set list lcs=tab:\|\ (here is a space)`. + +## Requirements +This plugin takes advantage of the newly provided `conceal` feature in Vim 7.3, so this plugin will not work with lower versions of Vim. + +## Installation +If you are using VIM version 8 or higher you can use its built-in package management; see `:help packages` for more information. Just run these commands in your terminal: +```bash +git clone https://github.com/Yggdroot/indentLine.git ~/.vim/pack/vendor/start/indentLint +vim -u NONE -c "helptags ~/.vim/pack/vendor/start/indentLint/doc" -c "q" +``` + +Otherwise, these are some of the other options: + +* To install the plugin just put the plugin files in your `~/.vim` (Linux) or `~/vimfiles` (Windows). + +* If you use a plugin manager you can put the whole directory into your `~/.vim/bundle/` directory ([Pathogen][pathogen]) or add the line `Plugin 'Yggdroot/indentLine'` to your `.vimrc` ([Vundle][vundle]). + +## Customization +To apply customization, apply the variable definitions to your `.vimrc` file. + +**Change Character Color** + +indentLine will overwrite 'conceal' color with grey by default. If you want to highlight conceal color with your colorscheme, disable by: +```vim +let g:indentLine_setColors = 0 +``` + +Or you can customize conceal color by: +```vim +" Vim +let g:indentLine_color_term = 239 + +" GVim +let g:indentLine_color_gui = '#A4E57E' + +" none X terminal +let g:indentLine_color_tty_light = 7 " (default: 4) +let g:indentLine_color_dark = 1 " (default: 2) + +" Background (Vim, GVim) +let g:indentLine_bgcolor_term = 202 +let g:indentLine_bgcolor_gui = '#FF5F00' +``` + +**Change Indent Char** + +Vim and GVim +```vim +let g:indentLine_char = 'c' +``` +where `'c'` can be any ASCII character. You can also use one of `¦`, `┆`, `│`, `⎸`, or `▏` to display more beautiful lines. However, these characters will only work with files whose encoding is UTF-8. + +or +```vim +let g:indentLine_char_list = ['|', '¦', '┆', '┊'] +``` +each indent level has a distinct character. + +**Change Conceal Behaviour** + +This plugin enables the Vim `conceal` feature which automatically hides stretches of text based on syntax highlighting. This setting will apply to all syntax items. + +For example, users utilizing the built in json.vim syntax file will no longer see quotation marks in their JSON files. + +indentLine will overwrite your "concealcursor" and "conceallevel" with default value: + +```vim +let g:indentLine_concealcursor = 'inc' +let g:indentLine_conceallevel = 2 +``` + +You can customize these settings, but the plugin will not function if `conceallevel` is not set to 1 or 2. + +If you want to keep your conceal setting, put this line to your vim dotfile: +```vim +let g:indentLine_setConceal = 0 +``` + +See the [VIM Reference Manual](http://vimdoc.sourceforge.net/htmldoc/version7.html#new-conceal) for more information on the `conceal` feature. + + +**Disable by default** +```vim +let g:indentLine_enabled = 0 +``` + +### Commands +`:IndentLinesToggle` toggles lines on and off. + +### Font patching +If you find all the standard unicode and ASCII characters too obtrusive, you might consider patching your font with the [indentLine-dotted-guide.eps][glyph] glyph provided. [FontForge][fontforge] makes the process amazingly simple: + + 1. Download and install FontForge. + 2. Locate and open your terminal/gVim font. + 3. Open the font in FontForge, choose __Goto__ from the __View__ menu and select _Private Use Area_ from the drop down box. + 4. In the private use area, locate a blank spot for the glyph. Make a note of the code, e.g. `U+E0A3`. + 5. Double-click the selected code point to open the font drawing tool. + 6. From the __File__ menu, select __Import...__ and locate the _indentLine-dotted-guide.eps_ file. + 7. Once imported, choose __File__ -> __Generate Fonts__ and choose a location and file type for the new font. + +Once completed, your new font will contain the more subtle dotted guide and all you have to do is set that glyph to `g:indentLine_char` in your `.vimrc` file. + +[glyph]: glyph/indentLine-dotted-guide.eps +[fontforge]: http://fontforge.github.io/ + +## Self promotion +If you think this script is helpful, follow the [GitHub repository][repository], and don't forget to vote for it on Vim.org! ([vimscript #4354][script]). + +[pathogen]: https://github.com/tpope/vim-pathogen +[vundle]: https://github.com/gmarik/vundle +[repository]: https://github.com/Yggdroot/indentLine +[script]: http://www.vim.org/scripts/script.php?script_id=4354 + +## Screenshots + +### Vertical bars +![Screenshot](http://i.imgur.com/KVi0T.jpg) + +### Patched font +![Screenshot](http://i.imgur.com/2ZA7oaZ.png) + +### Leading Spaces +![Screenshot](http://i.imgur.com/tLYkb79.png) + +![Screenshot](http://i.imgur.com/07Atrrs.png) + +## License +- MIT diff --git a/bundle/indentLine/after/plugin/indentLine.vim b/bundle/indentLine/after/plugin/indentLine.vim new file mode 100644 index 000000000..6c81f8da9 --- /dev/null +++ b/bundle/indentLine/after/plugin/indentLine.vim @@ -0,0 +1,459 @@ +" Script Name: indentLine.vim +" Author: Yggdroot +" +" Description: To show the indention levels with thin vertical lines + +scriptencoding utf-8 + +if !has("conceal") || exists("g:indentLine_loaded") + finish +endif +let g:indentLine_loaded = 1 + +let g:indentLine_newVersion = get(g:,'indentLine_newVersion',v:version > 704 || v:version == 704 && has("patch792")) + +let g:indentLine_char = get(g:, 'indentLine_char', (&encoding ==# "utf-8" && &term isnot# "linux" ? '¦' : '|')) +let g:indentLine_char_list = get(g:, 'indentLine_char_list', []) +let g:indentLine_first_char = get(g:, 'indentLine_first_char', (&encoding ==# "utf-8" && &term isnot# "linux" ? '¦' : '|')) +let g:indentLine_indentLevel = get(g:, 'indentLine_indentLevel', 20) +let g:indentLine_enabled = get(g:, 'indentLine_enabled', 1) +let g:indentLine_fileType = get(g:, 'indentLine_fileType', []) +let g:indentLine_fileTypeExclude = get(g:, 'indentLine_fileTypeExclude', []) +let g:indentLine_bufNameExclude = get(g:, 'indentLine_bufNameExclude', []) +let g:indentLine_bufTypeExclude = get(g:, 'indentLine_bufTypeExclude', []) +let g:indentLine_showFirstIndentLevel = get(g:, 'indentLine_showFirstIndentLevel', 0) +let g:indentLine_maxLines = get(g:, 'indentLine_maxLines', 3000) +let g:indentLine_setColors = get(g:, 'indentLine_setColors', 1) +let g:indentLine_setConceal = get(g:, 'indentLine_setConceal', 1) +let g:indentLine_defaultGroup = get(g:, 'indentLine_defaultGroup', "") +let g:indentLine_faster = get(g:, 'indentLine_faster', 0) +let g:indentLine_leadingSpaceChar = get(g:, 'indentLine_leadingSpaceChar', (&encoding ==# "utf-8" && &term isnot# "linux" ? '˰' : '.')) +let g:indentLine_leadingSpaceEnabled = get(g:, 'indentLine_leadingSpaceEnabled', 0) +let g:indentLine_mysyntaxfile = fnamemodify(expand(""), ":p:h:h")."/syntax/indentLine.vim" + +"{{{1 function! s:InitColor() +function! s:InitColor() + if !g:indentLine_setColors + return + endif + + let default_term_bg = "NONE" + let default_gui_bg = "NONE" + if &background ==# "light" + let default_term_fg = 249 + let default_gui_fg = "Grey70" + else + let default_term_fg = 239 + let default_gui_fg = "Grey30" + endif + + if g:indentLine_defaultGroup != "" + let default_id = synIDtrans(hlID(g:indentLine_defaultGroup)) + let default_term_fg = synIDattr(default_id, "fg", "cterm") == "" ? default_term_fg : synIDattr(default_id, "fg", "cterm") + let default_term_bg = synIDattr(default_id, "bg", "cterm") == "" ? default_term_bg : synIDattr(default_id, "bg", "cterm") + let default_gui_fg = synIDattr(default_id, "fg", "gui") == "" ? default_gui_fg : synIDattr(default_id, "fg", "gui") + let default_gui_bg = synIDattr(default_id, "bg", "gui") == "" ? default_gui_bg : synIDattr(default_id, "bg", "gui") + endif + + if !exists("g:indentLine_color_term") + let term_color = default_term_fg + else + let term_color = g:indentLine_color_term + endif + + if !exists("g:indentLine_bgcolor_term") + let term_bgcolor = default_term_bg + else + let term_bgcolor = g:indentLine_bgcolor_term + endif + + if !exists("g:indentLine_color_gui") + let gui_color = default_gui_fg + else + let gui_color = g:indentLine_color_gui + endif + + if !exists("g:indentLine_bgcolor_gui") + let gui_bgcolor = default_gui_bg + else + let gui_bgcolor = g:indentLine_bgcolor_gui + endif + + execute "highlight Conceal cterm=NONE ctermfg=" . term_color . " ctermbg=" . term_bgcolor + execute "highlight Conceal gui=NONE guifg=" . gui_color . " guibg=" . gui_bgcolor + + if &term ==# "linux" + if &background ==# "light" + let tty_color = exists("g:indentLine_color_tty_light") ? g:indentLine_color_tty_light : 4 + else + let tty_color = exists("g:indentLine_color_tty_dark") ? g:indentLine_color_tty_dark : 2 + endif + execute "highlight Conceal cterm=bold ctermfg=" . tty_color . " ctermbg=NONE" + endif +endfunction + +"{{{1 function! s:SetConcealOption() +function! s:SetConcealOption() + if !g:indentLine_setConceal + return + endif + if !(exists("b:indentLine_ConcealOptionSet") && b:indentLine_ConcealOptionSet) + let b:indentLine_ConcealOptionSet = 1 + let b:indentLine_original_concealcursor = &l:concealcursor + let b:indentLine_original_conceallevel = &l:conceallevel + let &l:concealcursor = exists("g:indentLine_concealcursor") ? g:indentLine_concealcursor : "inc" + let &l:conceallevel = exists("g:indentLine_conceallevel") ? g:indentLine_conceallevel : "2" + endif +endfunction + +"{{{1 function! s:ResetConcealOption() +function! s:ResetConcealOption() + if exists("b:indentLine_ConcealOptionSet") && b:indentLine_ConcealOptionSet + if exists("b:indentLine_original_concealcursor") + let &l:concealcursor = b:indentLine_original_concealcursor + endif + if exists("b:indentLine_original_conceallevel") + let &l:conceallevel = b:indentLine_original_conceallevel + endif + let b:indentLine_ConcealOptionSet = 0 + endif +endfunction + +"{{{1 function! s:DisableOnDiff() +function! s:DisableOnDiff() + if &diff + call s:IndentLinesDisable() + call s:LeadingSpaceDisable() + endif +endfunction + +"{{{1 function! s:VimEnter() +function! s:VimEnter() + let init_winnr = winnr() + noautocmd windo call s:DisableOnDiff() + noautocmd exec init_winnr . "wincmd w" +endfunction + +"{{{1 function! s:ToggleOnDiff() +function! s:ToggleOnDiff() + if &diff + call s:IndentLinesDisable() + call s:LeadingSpaceDisable() + else + call s:Setup() + endif +endfunction + +"{{{1 function! s:IndentLinesEnable() +function! s:IndentLinesEnable() + if g:indentLine_newVersion + if exists("b:indentLine_enabled") && b:indentLine_enabled == 0 + return + endif + + if !exists("w:indentLine_indentLineId") + let w:indentLine_indentLineId = [] + endif + + call s:SetConcealOption() + + if g:indentLine_showFirstIndentLevel + call add(w:indentLine_indentLineId, matchadd('Conceal', '^ ', 0, -1, {'conceal': g:indentLine_first_char})) + endif + + let space = &l:shiftwidth == 0 ? &l:tabstop : &l:shiftwidth + let n = len(g:indentLine_char_list) + let level = 0 + for i in range(space+1, space * g:indentLine_indentLevel + 1, space) + if n > 0 + let char = g:indentLine_char_list[level % n] + let level += 1 + else + let char = g:indentLine_char + endif + call add(w:indentLine_indentLineId, matchadd('Conceal', '^\s\+\zs\%'.i.'v ', 0, -1, {'conceal': char})) + endfor + + return + endif + + if exists("b:indentLine_enabled") && b:indentLine_enabled + return + else + let b:indentLine_enabled = 1 + endif + + call s:SetConcealOption() + + let g:mysyntaxfile = g:indentLine_mysyntaxfile + + let space = &l:shiftwidth == 0 ? &l:tabstop : &l:shiftwidth + + if g:indentLine_showFirstIndentLevel + execute 'syntax match IndentLine /^ / containedin=ALL conceal cchar=' . g:indentLine_first_char + endif + + if g:indentLine_faster + execute 'syntax match IndentLineSpace /^\s\+/ containedin=ALL contains=IndentLine' + execute 'syntax match IndentLine / \{'.(space-1).'}\zs / contained conceal cchar=' . g:indentLine_char + execute 'syntax match IndentLine /\t\zs / contained conceal cchar=' . g:indentLine_char + else + let pattern = line('$') < g:indentLine_maxLines ? 'v' : 'c' + for i in range(space+1, space * g:indentLine_indentLevel + 1, space) + execute 'syntax match IndentLine /\%(^\s\+\)\@<=\%'.i.pattern.' / containedin=ALL conceal cchar=' . g:indentLine_char + endfor + endif +endfunction + +"{{{1 function! s:IndentLinesDisable() +function! s:IndentLinesDisable() + if g:indentLine_newVersion + if exists("w:indentLine_indentLineId") && ! empty(w:indentLine_indentLineId) + for id in w:indentLine_indentLineId + try + call matchdelete(id) + catch /^Vim\%((\a\+)\)\=:E80[23]/ + endtry + endfor + let w:indentLine_indentLineId = [] + endif + + call s:ResetConcealOption() + return + endif + + let b:indentLine_enabled = 0 + try + syntax clear IndentLine + syntax clear IndentLineSpace + catch /^Vim\%((\a\+)\)\=:E28/ " catch error E28 + endtry +endfunction + +"{{{1 function! s:IndentLinesToggle() +function! s:IndentLinesToggle() + if g:indentLine_newVersion + if exists("w:indentLine_indentLineId") && ! empty(w:indentLine_indentLineId) + let b:indentLine_enabled = 0 + call s:IndentLinesDisable() + else + let b:indentLine_enabled = 1 + call s:IndentLinesEnable() + endif + + return + endif + + if exists("b:indentLine_enabled") && b:indentLine_enabled + call s:IndentLinesDisable() + else + call s:IndentLinesEnable() + endif +endfunction + +"{{{1 function! s:ResetWidth(...) +function! s:ResetWidth(...) + if 0 < a:0 + noautocmd let &l:shiftwidth = a:1 + endif + + let b:indentLine_enabled = 1 + call s:IndentLinesDisable() + call s:IndentLinesEnable() +endfunction + +"{{{1 function! s:AutoResetWidth() +function! s:AutoResetWidth() + + let l:enable = get( + \ b:, + \ 'indentLine_enabled', + \ g:indentLine_enabled ? s:Filter() : 0 + \) + + let g:indentLine_autoResetWidth = get(g:, 'indentLine_autoResetWidth', 1) + + if l:enable != 1 || g:indentLine_autoResetWidth != 1 + return + endif + + let b:indentLine_enabled = l:enable + call s:IndentLinesDisable() + call s:IndentLinesEnable() +endfunction + +"{{{1 function! s:Filter() +function! s:Filter() + if index(g:indentLine_fileTypeExclude, &filetype) != -1 + return 0 + endif + + if index(g:indentLine_bufTypeExclude, &buftype) != -1 + return 0 + endif + + if len(g:indentLine_fileType) != 0 && index(g:indentLine_fileType, &filetype) == -1 + return 0 + endif + + for name in g:indentLine_bufNameExclude + if matchstr(bufname(''), name) == bufname('') + return 0 + endif + endfor + + return 1 +endfunction + +"{{{1 function! s:Disable() +function! s:Disable() + if exists("b:indentLine_enabled") && b:indentLine_enabled + return + elseif exists("b:indentLine_leadingSpaceEnabled") && b:indentLine_leadingSpaceEnabled + return + elseif s:Filter() == 0 + call s:IndentLinesDisable() + call s:LeadingSpaceDisable() + endif +endfunction + +"{{{1 function! s:Setup() +function! s:Setup() + if &filetype ==# "" + call s:InitColor() + endif + + if s:Filter() && g:indentLine_enabled || exists("b:indentLine_enabled") && b:indentLine_enabled + call s:IndentLinesEnable() + endif + + if s:Filter() && g:indentLine_leadingSpaceEnabled || exists("b:indentLine_leadingSpaceEnabled") && b:indentLine_leadingSpaceEnabled + call s:LeadingSpaceEnable() + endif +endfunction + +"{{{1 function! s:LeadingSpaceEnable() +function! s:LeadingSpaceEnable() + if g:indentLine_newVersion + if exists("b:indentLine_leadingSpaceEnabled") && b:indentLine_leadingSpaceEnabled == 0 + return + endif + + if !exists("w:indentLine_leadingSpaceId") + let w:indentLine_leadingSpaceId = [] + endif + + call s:SetConcealOption() + + call add(w:indentLine_leadingSpaceId, matchadd('Conceal', '\%(^\s*\)\@<= ', 0, -1, {'conceal': g:indentLine_leadingSpaceChar})) + + if exists("w:indentLine_indentLineId") && ! empty(w:indentLine_indentLineId) + call s:ResetWidth() + endif + + return + endif + + if g:indentLine_faster + echoerr 'LeadingSpace can not be shown when g:indentLine_faster == 1' + return + endif + let g:mysyntaxfile = g:indentLine_mysyntaxfile + let b:indentLine_leadingSpaceEnabled = 1 + call s:SetConcealOption() + execute 'syntax match IndentLineLeadingSpace /\%(^\s*\)\@<= / containedin=ALLBUT,IndentLine conceal cchar=' . g:indentLine_leadingSpaceChar +endfunction + +"{{{1 function! s:LeadingSpaceDisable() +function! s:LeadingSpaceDisable() + if g:indentLine_newVersion + if exists("w:indentLine_leadingSpaceId") && ! empty(w:indentLine_leadingSpaceId) + for id in w:indentLine_leadingSpaceId + try + call matchdelete(id) + catch /^Vim\%((\a\+)\)\=:E80[23]/ + endtry + endfor + let w:indentLine_leadingSpaceId = [] + endif + + return + endif + + let b:indentLine_leadingSpaceEnabled = 0 + try + syntax clear IndentLineLeadingSpace + catch /^Vim\%((\a\+)\)\=:E28/ " catch error E28 + endtry +endfunction + +"{{{1 function! s:LeadingSpaceToggle() +function! s:LeadingSpaceToggle() + if g:indentLine_newVersion + if exists("w:indentLine_leadingSpaceId") && ! empty(w:indentLine_leadingSpaceId) + let b:indentLine_leadingSpaceEnabled = 0 + call s:LeadingSpaceDisable() + else + let b:indentLine_leadingSpaceEnabled = 1 + call s:LeadingSpaceEnable() + endif + + return + endif + + if exists("b:indentLine_leadingSpaceEnabled") && b:indentLine_leadingSpaceEnabled + call s:LeadingSpaceDisable() + else + call s:LeadingSpaceEnable() + endif +endfunction + +"{{{1 augroup indentLine +augroup indentLine + autocmd! + if g:indentLine_newVersion + autocmd BufRead,BufNewFile,ColorScheme,Syntax * call s:InitColor() + if exists("##WinNew") + autocmd WinNew * call s:Setup() + endif + autocmd BufWinEnter * call s:IndentLinesDisable() | call s:LeadingSpaceDisable() | call s:Setup() + autocmd FileType * call s:Disable() + if exists("##OptionSet") + autocmd OptionSet diff call s:ToggleOnDiff() + autocmd OptionSet shiftwidth,tabstop noautocmd call s:AutoResetWidth() + endif + autocmd VimEnter * call s:VimEnter() + else + autocmd BufWinEnter * call s:Setup() + autocmd User * if exists("b:indentLine_enabled") || exists("b:indentLine_leadingSpaceEnabled") | + \ call s:Setup() | endif + autocmd BufRead,BufNewFile,ColorScheme,Syntax * call s:InitColor() + autocmd BufUnload * let b:indentLine_enabled = 0 | let b:indentLine_leadingSpaceEnabled = 0 + autocmd SourcePre $VIMRUNTIME/syntax/nosyntax.vim doautocmd indentLine BufUnload + autocmd FileChangedShellPost * doautocmd indentLine BufUnload | call s:Setup() + if exists("##OptionSet") + autocmd OptionSet diff call s:ToggleOnDiff() + autocmd OptionSet shiftwidth,tabstop noautocmd call s:AutoResetWidth() + endif + autocmd VimEnter * call s:VimEnter() + endif +augroup END + +"{{{1 commands +command! -nargs=? IndentLinesReset call s:ResetWidth() +command! IndentLinesToggle call s:IndentLinesToggle() +if g:indentLine_newVersion + command! IndentLinesEnable let b:indentLine_enabled = 1 | call s:IndentLinesEnable() + command! IndentLinesDisable let b:indentLine_enabled = 0 | call s:IndentLinesDisable() + command! LeadingSpaceEnable let b:indentLine_leadingSpaceEnabled = 1 | call s:LeadingSpaceEnable() + command! LeadingSpaceDisable let b:indentLine_leadingSpaceEnabled = 0 | call s:LeadingSpaceDisable() +else + command! IndentLinesEnable call s:IndentLinesEnable() + command! IndentLinesDisable call s:IndentLinesDisable() + command! LeadingSpaceEnable call s:LeadingSpaceEnable() + command! LeadingSpaceDisable call s:LeadingSpaceDisable() +endif +command! LeadingSpaceToggle call s:LeadingSpaceToggle() + +" vim:et:ts=4:sw=4:fdm=marker:fmr={{{,}}} + diff --git a/bundle/indentLine/after/syntax/indentLine.vim b/bundle/indentLine/after/syntax/indentLine.vim new file mode 100644 index 000000000..b1f20a0de --- /dev/null +++ b/bundle/indentLine/after/syntax/indentLine.vim @@ -0,0 +1,2 @@ +"this is the `mysyntaxfile`, will be sourced after sourcing synload.vim +autocmd Syntax * doautocmd indentLine User diff --git a/bundle/indentLine/doc/indentLine.txt b/bundle/indentLine/doc/indentLine.txt new file mode 100644 index 000000000..ed581191e --- /dev/null +++ b/bundle/indentLine/doc/indentLine.txt @@ -0,0 +1,218 @@ +*indentLine.txt* Show vertical lines for indent with conceal feature + +CONTENTS *indentLine-contents* +Introduction |indentLine-introduction| +Config |indentLine-config| +Variables |indentLine-variables| +Commands |indentLine-commands| +FAQ |indentLine-faq| +Changelog |indentLine-changelog| +Credits |indentLine-credits| +============================================================================== +INTRODUCTION *indentLine-introduction* +This plugin is used for displaying thin vertical lines at each indentation +level for code indented with spaces. For code indented with tabs, I think +there is no need to support it, using :set list lcs=tab:\|\ (here is a space) +can achieve it. +============================================================================== +CONFIG *indentLine-config* + +============================================================================== +VARIABLES *indentLine-variables* + +g:indentLine_char *g:indentLine_char* + Specify a character to be used as indent line if + |g:indentLine_char_list| is not []. + You also can use other characters: + | ¦ ┆ │ + Default value is "|". + +g:indentLine_char_list *g:indentLine_char_list* + Specify a list of characters to be used as indent line for + each indent level. If the value is an empty list [], use + |g:indentLine_char| instead. + e.g., let g:indentLine_char_list = ['|', '¦', '┆', '┊'] + Default value is []. + +g:indentLine_setColors *g:indentLine_setColors* + By default, indentLine will overwrite 'conceal' color. + If you want to highlight conceal with your + colorscheme, set this value to 0. + Default value is 1. + +g:indentLine_first_char *g:indentLine_first_char* + Specify a character to be used as indent line + on the first level. + You also can use other characters: + | ¦ ┆ │ + Default value is "|". + +g:indentLine_color_term *g:indentLine_color_term* + Specify terminal vim indent line color. + e.g. let g:indentLine_color_term = 239 + +g:indentLine_bgcolor_term *g:indentLine_bgcolor_term* + Specify terminal vim indent line background color. + e.g. let g:indentLine_bgcolor_term = 202 + + +g:indentLine_color_gui *g:indentLine_color_gui* + Specify GUI vim indent line color. + e.g. let g:indentLine_color_gui = '#A4E57E' + +g:indentLine_bgcolor_gui *g:indentLine_bgcolor_gui* + Specify GUI vim indent line background color. + e.g. let g:indentLine_color_gui = '#FF5F00' + +g:indentLine_color_tty_light *g:indentLine_color_tty_light* + Specify none X terminal vim indent line color in bg light. + default: 4 + e.g. let g:indentLine_color_tty_light = 7 + +g:indentLine_color_tty_dark *g:indentLine_color_tty_dark* + Specify none X terminal vim indent line color in bg dark. + default: 2 + e.g. let g:indentLine_color_tty_dark = 1 + +g:indentLine_indentLevel *g:indentLine_indentLevel* + Specify how much indent level do you want to use for + indentLine. Most program will not has bigger indent level than + 10. + Default value is 10. + +g:indentLine_showFirstIndentLevel *g:indentLine_showFirstIndentLevel* + Specify whether the first indent level should be shown. + This is useful if you use indentLine in combination with + |listchars| in order to show tabs. + Default value is 0. + +g:indentLine_enabled *g:indentLine_enabled* + Specify whether to enable indentLine plugin by default. + If value is not 0, the plugin is on by default, otherwise off. + Default value is 1. + +g:indentLine_fileType *g:indentLine_fileType* + This variable specify a list of file types. + When opening these types of files, the plugin is enabled by + default. + e.g. let g:indentLine_fileType = ['c', 'cpp'] + Default value is [] which means all file types is supported. + +g:indentLine_fileTypeExclude *g:indentLine_fileTypeExclude* + This variable specify a list of file types. + When opening these types of files, the plugin is disabled by + default. + e.g. let g:indentLine_fileTypeExclude = ['text', 'sh'] + Default value is [] which means no file types are excluded. + +g:indentLine_bufTypeExclude *g:indentLine_bufTypeExclude* + This variable specify a list of buffer types. + When opening these types of buffers, the plugin is disabled + by default. + e.g. let g:indentLine_bufTypeExclude = ['help', 'terminal'] + Default value is [] which means no buffer type is excluded. + +g:indentLine_bufNameExclude *g:indentLine_bufNameExclude* + This variable specify a list of buffer names, which can be + regular expression. If the buffer's name fall into this list, + the indentLine won't display. + e.g. let g:indentLine_bufNameExclude = ['_.*', 'NERD_tree.*'] + Default value is []. + +g:indentLine_maxLines *g:indentLine_maxLines* + This variable specify a number, when the number of buffer's + lines exceed it, the plugin try to use another pattern to make + the performance better. + Default value is 3000. + +g:indentLine_faster *g:indentLine_faster* + If you want the performance better, you can set the value as + 1, default value is 0. But better performance may bring little + issue with it. + +g:indentLine_setConceal + The plugin will overwrite your "concealcursor" and + "conceallevel" by default. If you want to keep your setting, + set this value to 0. + Default value is 1. + +g:indentLine_concealcursor *g:indentLine_concealcursor* + This variable toggles cursor lines behavior. If variable + exists and is empty, that is, set to '', then the indentlines + will not show up in the cursorline. + See *concealcursor*. + Default value is 'inc'. + +g:indentLine_conceallevel *g:indentLine_conceallevel* + This variable toggles the concealing behavior. + See *conceallevel*. + Default value is '2'. + +g:indentLine_leadingSpaceChar *g:indentLine_leadingSpaceChar* + Specify a character to show for leading spaces. + You also can use other characters:˽˰·· + e.g. let g:indentLine_leadingSpaceChar = '·' + +g:indentLine_leadingSpaceEnabled *g:indentLine_leadingSpaceEnabled* + Specify whether to show leading spaces by default. + Default value is 0. + +g:indentLine_defaultGroup *g:indentLine_defaultGroup* + Specify a highlight group to use for default values + of g:indentLine_[bg]color_(term|gui) + +g:indentLine_autoResetWidth *g:indentLine_autoResetWidth* + Specify whether to auto redraw the indentLines after + 'shiftwidth' or 'tabstop' change. + Default value is 1. + +============================================================================== +COMMANDS *indentLine-commands* + +*IndentLinesReset* [number] + if 'shiftwidth' changes, using this command can redraw the + indentLines. number is optional, it means the width between + two indent level, if ommited, value of 'shiftwidth' is used. + +*IndentLinesToggle* + toggle the indent lines of the current buffer. + +*IndentLinesEnable* + enable the indent lines of the current buffer. + +*IndentLinesDisable* + disable the indent lines of the current buffer. + +*LeadingSpaceEnable* + enable the leading spaces of the current buffer. + +*LeadingSpaceDisable* + disable the leading spaces of the current buffer. + +*LeadingSpaceToggle* + toggle the leading spaces of the current buffer. +============================================================================== +FAQ *indentLine-faq* + +Q. How can I make the indent line visual similar to the line used in Sublime + Text 2? + +A. Use let g:indentLine_char = '┊' + +Q. I don't see quotes in JSON. + +A. Use let g:vim_json_syntax_conceal = 0 or run :IndentLinesDisable + +============================================================================== +CHANGELOG *indentLine-changelog* + +============================================================================== +CREDITS *indentLine-credits* + +Thanks to the following people for suggestions and patches: + +NagatoPain +Salman Halim +Christophe +============================================================================== +vim:tw=78:ts=8:ft=help:norl diff --git a/bundle/indentLine/glyph/indentLine-dotted-guide.eps b/bundle/indentLine/glyph/indentLine-dotted-guide.eps new file mode 100644 index 000000000..146309f69 --- /dev/null +++ b/bundle/indentLine/glyph/indentLine-dotted-guide.eps @@ -0,0 +1,169 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 2.96296 -488.5 170.5 1988.5 +%%Pages: 0 +%%Title: uniE0A3 from DejaVuSansMonoForPowerline +%%Creator: FontForge +%%Author: Andy Earnshaw +%%CreationDate: 22:53 1-8-2014 +%%EndComments +%%BeginPreview: 5 74 4 74 +%013100 +%3EFE40 +%BFFFD0 +%DFFFE0 +%7FFF80 +%059600 +%000000 +%000000 +%000000 +%000000 +%048500 +%6FFF80 +%CFFFE0 +%CFFFD0 +%4EFE50 +%014100 +%000000 +%000000 +%000000 +%000000 +%19DA10 +%9FFFB0 +%DFFFE0 +%AFFFB0 +%1AEB20 +%000000 +%000000 +%000000 +%000000 +%013100 +%3EFE40 +%BFFFD0 +%DFFFE0 +%7FFF80 +%059600 +%000000 +%000000 +%000000 +%000000 +%048500 +%6FFF80 +%CFFFE0 +%CFFFD0 +%4EFF50 +%014100 +%000000 +%000000 +%000000 +%000000 +%19DA10 +%9FFFB0 +%DFFFE0 +%AFFFB0 +%1AEB20 +%000000 +%000000 +%000000 +%000000 +%013100 +%3EFE40 +%BFFFD0 +%DFFFE0 +%7FFF80 +%059600 +%000000 +%000000 +%000000 +%000000 +%048500 +%6FFF80 +%CFFFE0 +%CFFFD0 +%4EFF50 +%014100 +%%EndPreview +%%EndProlog +%%Page "uniE0A3" 1 +gsave newpath + 3 -405 moveto + 3.66667 -381.667 12 -362 28 -346 curveto + 44 -330 63.6667 -321.833 87 -321.5 curveto + 110.333 -321.833 130 -330 146 -346 curveto + 162 -362 170.167 -381.667 170.5 -405 curveto + 170.167 -428.333 162 -448 146 -464 curveto + 130 -480 110.333 -488.167 87 -488.5 curveto + 63.6667 -488.167 44 -480 28 -464 curveto + 10.6667 -446.667 2.33333 -427 3 -405 curveto + closepath + 3 255 moveto + 3.66667 278.333 12 298 28 314 curveto + 44 330 63.6667 338.167 87 338.5 curveto + 110.333 338.167 130 330 146 314 curveto + 162 298 170.167 278.333 170.5 255 curveto + 170.167 231.667 162 212 146 196 curveto + 130 180 110.333 171.833 87 171.5 curveto + 63.6667 171.833 44 180 28 196 curveto + 10.6667 213.333 2.33333 233 3 255 curveto + closepath + 3 -75 moveto + 3.66667 -51.6667 12 -32 28 -16 curveto + 44 0 63.6667 8.16667 87 8.5 curveto + 110.333 8.16667 130 0 146 -16 curveto + 162 -32 170.167 -51.6667 170.5 -75 curveto + 170.167 -98.3333 162 -118 146 -134 curveto + 130 -150 110.333 -158.167 87 -158.5 curveto + 63.6667 -158.167 44 -150 28 -134 curveto + 10.6667 -116.667 2.33333 -97 3 -75 curveto + closepath + 3 915 moveto + 3.66667 938.333 12 958 28 974 curveto + 44 990 63.6667 998.167 87 998.5 curveto + 110.333 998.167 130 990 146 974 curveto + 162 958 170.167 938.333 170.5 915 curveto + 170.167 891.667 162 872 146 856 curveto + 130 840 110.333 831.833 87 831.5 curveto + 63.6667 831.833 44 840 28 856 curveto + 10.6667 873.333 2.33333 893 3 915 curveto + closepath + 3 585 moveto + 3.66667 608.333 12 628 28 644 curveto + 44 660 63.6667 668.167 87 668.5 curveto + 110.333 668.167 130 660 146 644 curveto + 162 628 170.167 608.333 170.5 585 curveto + 170.167 561.667 162 542 146 526 curveto + 130 510 110.333 501.833 87 501.5 curveto + 63.6667 501.833 44 510 28 526 curveto + 10.6667 543.333 2.33333 563 3 585 curveto + closepath + 3 1575 moveto + 3.66667 1598.33 12 1618 28 1634 curveto + 44 1650 63.6667 1658.17 87 1658.5 curveto + 110.333 1658.17 130 1650 146 1634 curveto + 162 1618 170.167 1598.33 170.5 1575 curveto + 170.167 1551.67 162 1532 146 1516 curveto + 130 1500 110.333 1491.83 87 1491.5 curveto + 63.6667 1491.83 44 1500 28 1516 curveto + 10.6667 1533.33 2.33333 1553 3 1575 curveto + closepath + 3 1245 moveto + 3.66667 1268.33 12 1288 28 1304 curveto + 44 1320 63.6667 1328.17 87 1328.5 curveto + 110.333 1328.17 130 1320 146 1304 curveto + 162 1288 170.167 1268.33 170.5 1245 curveto + 170.167 1221.67 162 1202 146 1186 curveto + 130 1170 110.333 1161.83 87 1161.5 curveto + 63.6667 1161.83 44 1170 28 1186 curveto + 10.6667 1203.33 2.33333 1223 3 1245 curveto + closepath + 3 1905 moveto + 3.66667 1928.33 12 1948 28 1964 curveto + 44 1980 63.6667 1988.17 87 1988.5 curveto + 110.333 1988.17 130 1980 146 1964 curveto + 162 1948 170.167 1928.33 170.5 1905 curveto + 170.167 1881.67 162 1862 146 1846 curveto + 130 1830 110.333 1821.83 87 1821.5 curveto + 63.6667 1821.83 44 1830 28 1846 curveto + 10.6667 1863.33 2.33333 1883 3 1905 curveto + closepath +fill grestore +%%EOF diff --git a/bundle/neco-syntax/.gitignore b/bundle/neco-syntax/.gitignore new file mode 100644 index 000000000..63746c0b6 --- /dev/null +++ b/bundle/neco-syntax/.gitignore @@ -0,0 +1,2 @@ +*.py[cod] +doc/tags diff --git a/bundle/neco-syntax/LICENSE b/bundle/neco-syntax/LICENSE new file mode 100644 index 000000000..5c4ca4301 --- /dev/null +++ b/bundle/neco-syntax/LICENSE @@ -0,0 +1,22 @@ +License: MIT license +AUTHOR: Shougo Matsushita + Jia Sui + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bundle/neco-syntax/autoload/cm/sources/necosyntax.vim b/bundle/neco-syntax/autoload/cm/sources/necosyntax.vim new file mode 100644 index 000000000..a9067f2c3 --- /dev/null +++ b/bundle/neco-syntax/autoload/cm/sources/necosyntax.vim @@ -0,0 +1,25 @@ +"============================================================================= +" FILE: necosyntax.vim (NCM source) +" AUTHOR: Jia Sui +" License: MIT license +"============================================================================= + +let s:initialized = 0 + +function! cm#sources#necosyntax#refresh(opt, ctx) + if !s:initialized + call necosyntax#initialize() + let s:initialized = 1 + endif + + let col = a:ctx['col'] + let typed = a:ctx['typed'] + + let kw = matchstr(typed, '\w\+$') + let kwlen = len(kw) + + let matches = necosyntax#gather_candidates() + let startcol = col - kwlen + + call cm#complete(a:opt.name, a:ctx, startcol, matches) +endfunction diff --git a/bundle/neco-syntax/autoload/necosyntax.vim b/bundle/neco-syntax/autoload/necosyntax.vim new file mode 100644 index 000000000..460bd8c68 --- /dev/null +++ b/bundle/neco-syntax/autoload/necosyntax.vim @@ -0,0 +1,265 @@ +"============================================================================= +" FILE: necosyntax.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +let g:necosyntax#min_keyword_length = + \ get(g:, 'necosyntax#min_keyword_length', 4) +let g:necosyntax#max_syntax_lines = + \ get(g:, 'necosyntax#max_syntax_lines', 300) + +function! necosyntax#initialize() abort + let s:syntax_list = {} + + augroup necosyntax + autocmd! + autocmd Syntax * call s:make_cache() + augroup END + + " Initialize check. + call s:make_cache() +endfunction + +function! necosyntax#gather_candidates() abort + let filetype = &filetype + if filetype == '' + return [] + endif + + if !has_key(s:syntax_list, filetype) + call s:make_cache() + endif + + let list = [] + for ft in s:get_context_filetypes(filetype) + let list += get(s:syntax_list, ft, []) + endfor + return list +endfunction + +function! s:make_cache() abort + let ft = &filetype + if ft == '' || ft ==# 'vim' || has_key(s:syntax_list, ft) + return + endif + + " Make cache from syntax list. + let s:syntax_list[ft] = s:make_cache_from_syntax(ft) +endfunction + +function! s:make_cache_from_syntax(filetype) abort + " Get current syntax list. + let syntax_list = s:redir('syntax list') + if syntax_list =~ '^E\d\+' || syntax_list =~ '^No Syntax items' + return [] + endif + + let lines = split(syntax_list, '\n') + if len(lines) > g:necosyntax#max_syntax_lines + " Too long. + return [] + endif + + let group_name = '' + let keyword_pattern = '\h\w*' + + let keyword_list = [] + for line in lines + if line =~ '^\h\w\+' + " Change syntax group name. + let group_name = matchstr(line, '^\S\+') + let line = substitute(line, '^\S\+\s*xxx', '', '') + endif + + if line =~ 'Syntax items' || line =~ '^\s*links to' || + \ line =~ '^\s*nextgroup=' + " Next line. + continue + endif + + let line = substitute(line, + \ 'contained\|skipwhite\|skipnl\|oneline', '', 'g') + let line = substitute(line, + \ '^\s*nextgroup=.*\ze\s', '', '') + + if line =~ '^\s*match' + let line = s:substitute_candidate( + \ matchstr(line, '/\zs[^/]\+\ze/')) + elseif line =~ '^\s*start=' + let line = + \s:substitute_candidate( + \ matchstr(line, 'start=/\zs[^/]\+\ze/')) . ' ' . + \s:substitute_candidate( + \ matchstr(line, 'end=/zs[^/]\+\ze/')) + endif + + " Add keywords. + let match_num = 0 + let match_str = matchstr(line, keyword_pattern, match_num) + + while match_str != '' + " Ignore too short keyword. + if len(match_str) >= g:necosyntax#min_keyword_length + \&& match_str =~ '^[[:print:]]\+$' + call add(keyword_list, match_str) + endif + + let match_num += len(match_str) + + let match_str = matchstr(line, keyword_pattern, match_num) + endwhile + endfor + + let keyword_list = s:uniq(keyword_list) + + return keyword_list +endfunction + +function! s:substitute_candidate(candidate) abort + let candidate = a:candidate + + " Collection. + let candidate = substitute(candidate, + \'\\\@{}]\|[$^]\|\\z\?\a\)', ' ', 'g') + + if candidate =~ '\\%\?(' + let candidate = join(necosyntax#_split_pattern( + \ candidate, '')) + endif + + " \ + let candidate = substitute(candidate, '\\\\', '\\', 'g') + " * + let candidate = substitute(candidate, '\\\*', '*', 'g') + return candidate +endfunction + +function! necosyntax#_split_pattern(keyword_pattern, prefix) abort + let original_pattern = a:keyword_pattern + let result_patterns = [] + let analyzing_patterns = [ '' ] + + let i = 0 + let max = len(original_pattern) + while i < max + if match(original_pattern, '^\\%\?(', i) >= 0 + " Grouping. + let end = s:match_pair(original_pattern, '\\%\?(', '\\)', i) + if end < 0 + break + endif + + let save_patterns = analyzing_patterns + let analyzing_patterns = [] + for pattern in filter(save_patterns, "v:val !~ '.*\\s\\+.*\\s'") + let analyzing_patterns += necosyntax#_split_pattern( + \ original_pattern[matchend(original_pattern, + \ '^\\%\?(', i) : end-1], + \ pattern) + endfor + + let i = end + 2 + elseif match(original_pattern, '^\\|', i) >= 0 + " Select. + let result_patterns += analyzing_patterns + let analyzing_patterns = [ '' ] + let original_pattern = original_pattern[i+2 :] + let max = len(original_pattern) + + let i = 0 + elseif original_pattern[i] == '\' && i+1 < max + call map(analyzing_patterns, 'v:val . original_pattern[i+1]') + + " Escape. + let i += 2 + else + call map(analyzing_patterns, 'v:val . original_pattern[i]') + + let i += 1 + endif + endwhile + + let result_patterns += analyzing_patterns + return map(result_patterns, 'a:prefix . v:val') +endfunction + +function! s:match_pair(string, start_pattern, end_pattern, start_cnt) abort + let end = -1 + let start_pattern = '\%(' . a:start_pattern . '\)' + let end_pattern = '\%(' . a:end_pattern . '\)' + + let i = a:start_cnt + let max = len(a:string) + let nest_level = 0 + while i < max + let start = match(a:string, start_pattern, i) + let end = match(a:string, end_pattern, i) + + if start >= 0 && (end < 0 || start < end) + let i = matchend(a:string, start_pattern, i) + let nest_level += 1 + elseif end >= 0 && (start < 0 || end < start) + let nest_level -= 1 + + if nest_level == 0 + return end + endif + + let i = matchend(a:string, end_pattern, i) + else + break + endif + endwhile + + if nest_level != 0 + return -1 + else + return end + endif +endfunction + +function! s:uniq(list) abort + let dict = {} + for item in a:list + if !has_key(dict, item) + let dict[item] = item + endif + endfor + + return values(dict) +endfunction + +function! s:get_context_filetypes(filetype) abort + if !exists('s:exists_context_filetype') + try + call context_filetype#version() + let s:exists_context_filetype = 1 + catch + let s:exists_context_filetype = 0 + endtry + endif + + return s:exists_context_filetype + \ && exists('*context_filetype#get_filetypes') ? + \ context_filetype#get_filetypes(a:filetype) : [a:filetype] +endfunction + +function! s:redir(command) abort + if exists('*execute') + return execute(a:command) + endif + + redir => r + execute 'silent!' a:command + redir END + + return r +endfunction diff --git a/bundle/neco-syntax/autoload/neocomplete/sources/syntax.vim b/bundle/neco-syntax/autoload/neocomplete/sources/syntax.vim new file mode 100644 index 000000000..68b5f62a6 --- /dev/null +++ b/bundle/neco-syntax/autoload/neocomplete/sources/syntax.vim @@ -0,0 +1,30 @@ +"============================================================================= +" FILE: syntax.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +" Important variables. +if !exists('s:syntax_list') + let s:syntax_list = {} +endif + +let s:source = { + \ 'name' : 'syntax', + \ 'kind' : 'keyword', + \ 'mark' : '[S]', + \ 'rank' : 4, + \ 'hooks' : {}, + \} + +function! s:source.hooks.on_init(context) abort + call necosyntax#initialize() +endfunction + +function! s:source.gather_candidates(context) abort + return necosyntax#gather_candidates() +endfunction + +function! neocomplete#sources#syntax#define() abort + return s:source +endfunction diff --git a/bundle/neco-syntax/doc/necosyntax.txt b/bundle/neco-syntax/doc/necosyntax.txt new file mode 100644 index 000000000..1a8405c80 --- /dev/null +++ b/bundle/neco-syntax/doc/necosyntax.txt @@ -0,0 +1,59 @@ +*necosyntax.txt* Syntax source for neocomplete/deoplete/ncm. + +Version: 0.1 +Author: Shougo +License: MIT license + +CONTENTS *necosyntax-contents* + +Introduction |necosyntax-introduction| +Install |necosyntax-install| +Interface |necosyntax-interface| + Commands |necosyntax-commands| + Variables |necosyntax-variables| +FAQ |necosyntax-faq| + +============================================================================== +INTRODUCTION *necosyntax-introduction* + +*neco-syntax* is the syntax source for neocomplete/deoplete/ncm. + +This source analyzes a syntax file like autoload/syntaxcomplete.vim offered by +default, and to add to candidate completion. The plugin can recognize +candidates a lot more than autoload/syntaxcomplete.vim. + +Note: neco-syntax does not support Vim syntax. Because, neco-vim is better. + +https://github.com/Shougo/neco-vim + +============================================================================== +INSTALL *necosyntax-install* + + +============================================================================== +INTERFACE *necosyntax-interface* + +------------------------------------------------------------------------------ +COMMANDS *necosyntax-commands* + +------------------------------------------------------------------------------ +VARIABLES *necosyntax-variables* + + *g:necosyntax#min_keyword_length* +g:necosyntax#min_keyword_length + In syntax files, this variable controls length of keyword + becoming the object of the completion at the minimum. + + Default value is 4. + + *g:necosyntax#max_syntax_lines* +g:necosyntax#max_syntax_lines + Disable neco-syntax if |:syn-list| lines are than it. + + Default value is 300. + +============================================================================== +FAQ *necosyntax-faq* + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: diff --git a/bundle/neco-syntax/plugin/necosyntax.vim b/bundle/neco-syntax/plugin/necosyntax.vim new file mode 100644 index 000000000..58836c27d --- /dev/null +++ b/bundle/neco-syntax/plugin/necosyntax.vim @@ -0,0 +1,14 @@ +"============================================================================= +" FILE: necosyntax.vim +" AUTHOR: Jia Sui +" License: MIT license +"============================================================================= + +" Register source for NCM +autocmd User CmSetup call cm#register_source({ + \ 'name': 'neco-syntax', + \ 'abbreviation': 'syntax', + \ 'priority': 8, + \ 'cm_refresh': 'cm#sources#necosyntax#refresh', + \ 'cm_refresh_patterns': ['\w\+$'], + \ }) diff --git a/bundle/neco-syntax/rplugin/python3/deoplete/sources/syntax.py b/bundle/neco-syntax/rplugin/python3/deoplete/sources/syntax.py new file mode 100644 index 000000000..da5a754a4 --- /dev/null +++ b/bundle/neco-syntax/rplugin/python3/deoplete/sources/syntax.py @@ -0,0 +1,26 @@ +#============================================================================= +# FILE: syntax.py +# AUTHOR: Shougo Matsushita +# License: MIT license +#============================================================================= + +from deoplete.base.source import Base + +import deoplete.util + +class Source(Base): + def __init__(self, vim): + Base.__init__(self, vim) + + self.name = 'syntax' + self.mark = '[S]' + self.__include_files = {} + self.vim.call('necosyntax#initialize') + + def on_event(self, context): + self.__include_files[context['filetype']] = [ + { 'word': x } for x in + self.vim.call('necosyntax#gather_candidates')] + + def gather_candidates(self, context): + return self.__include_files.get(context['filetype'], []) diff --git a/bundle/neco-syntax/test/necosyntax.vim b/bundle/neco-syntax/test/necosyntax.vim new file mode 100644 index 000000000..0cdeacf01 --- /dev/null +++ b/bundle/neco-syntax/test/necosyntax.vim @@ -0,0 +1,20 @@ +let s:suite = themis#suite('parser') +let s:assert = themis#helper('assert') + +function! s:suite.syntax() abort + call s:assert.equals(sort(necosyntax#_split_pattern( + \ '\(d\|e\|f\)', '')), + \ ['d', 'e', 'f']) + call s:assert.equals(sort(necosyntax#_split_pattern( + \ '\(a\|b\)-c', '')), + \ ['a-c', 'b-c']) + call s:assert.equals(sort(necosyntax#_split_pattern( + \ 'c\(d\|e\|f\)', '')), + \ ['cd', 'ce', 'cf']) + call s:assert.equals(sort(necosyntax#_split_pattern( + \ '\(a\|b\)c\(d\|e\|f\)', '')), + \ ['acd', 'ace', 'acf', 'bcd', 'bce', 'bcf']) + call s:assert.equals(sort(necosyntax#_split_pattern( + \ '\\\%(dump\|end\|jobname\)', '')), + \ ['\dump', '\end', '\jobname']) +endfunction diff --git a/bundle/neoformat/.editorconfig b/bundle/neoformat/.editorconfig new file mode 100644 index 000000000..e95a293ad --- /dev/null +++ b/bundle/neoformat/.editorconfig @@ -0,0 +1,13 @@ +[*] +indent_style = space +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.vim] +indent_size = 4 +tab_width = 4 + +[*.vader] +indent_size = 2 diff --git a/bundle/neoformat/.gitignore b/bundle/neoformat/.gitignore new file mode 100644 index 000000000..523e87e2a --- /dev/null +++ b/bundle/neoformat/.gitignore @@ -0,0 +1,4 @@ +test/$VADER_OUTPUT_FILE +node_modules/ +.cache +doc/tags diff --git a/bundle/neoformat/.nvmrc b/bundle/neoformat/.nvmrc new file mode 100644 index 000000000..32447ce31 --- /dev/null +++ b/bundle/neoformat/.nvmrc @@ -0,0 +1 @@ +5.11.1 diff --git a/bundle/neoformat/.travis.yml b/bundle/neoformat/.travis.yml new file mode 100644 index 000000000..00718fd8c --- /dev/null +++ b/bundle/neoformat/.travis.yml @@ -0,0 +1,23 @@ +language: python + +sudo: required + +cache: + - pip + - npm + +env: + - PATH="$PATH:/home/travis/build/sbdchd/neoformat/test/bin" + +python: + - "3.6" + +before_install: + - nvm install $NODE_VERSION + +install: + - ./test/install.sh + - pip install -r test/requirements.txt + +script: + - cd test && pytest -v test.py diff --git a/bundle/neoformat/.vintrc.yaml b/bundle/neoformat/.vintrc.yaml new file mode 100644 index 000000000..05b6299e2 --- /dev/null +++ b/bundle/neoformat/.vintrc.yaml @@ -0,0 +1,13 @@ +cmdargs: + severity: error + +env: + neovim: true + +policies: + ProhibitSetNoCompatible: + enabled: false + ProhibitImplicitScopeVariable: + enabled: false + ProhibitEqualTildeOperator: + enabled: false diff --git a/bundle/neoformat/CONTRIBUTING.md b/bundle/neoformat/CONTRIBUTING.md new file mode 100644 index 000000000..517213a02 --- /dev/null +++ b/bundle/neoformat/CONTRIBUTING.md @@ -0,0 +1,4 @@ +# contributing + +If you are looking to add or update a formatter, please be sure to update both +[`doc/neoformat.txt`](./doc/neoformat.txt) as well as [`README.md`](./README.md). Thanks! diff --git a/bundle/neoformat/LICENSE b/bundle/neoformat/LICENSE new file mode 100644 index 000000000..6c9cb596b --- /dev/null +++ b/bundle/neoformat/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2016, Steve Dignam +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/bundle/neoformat/Makefile b/bundle/neoformat/Makefile new file mode 100644 index 000000000..1083cd71d --- /dev/null +++ b/bundle/neoformat/Makefile @@ -0,0 +1,5 @@ +all: + +.PHONY: test +test: + ./test/test.sh diff --git a/bundle/neoformat/README.md b/bundle/neoformat/README.md new file mode 100644 index 000000000..3320e9a72 --- /dev/null +++ b/bundle/neoformat/README.md @@ -0,0 +1,422 @@ +# Neoformat [![Build Status](https://travis-ci.org/sbdchd/neoformat.svg?branch=master)](https://travis-ci.org/sbdchd/neoformat) + +A (Neo)vim plugin for formatting code. + +Neoformat uses a variety of formatters for many filetypes. Currently, Neoformat +will run a formatter using the current buffer data, and on success it will +update the current buffer with the formatted text. On a formatter failure, +Neoformat will try the next formatter defined for the filetype. + +By using `getbufline()` to read from the current buffer instead of file, +Neoformat is able to format your buffer without you having to `:w` your file first. +Also, by using `setline()`, marks, jumps, etc. are all maintained after formatting. + +Neoformat supports both sending buffer data to formatters via stdin, and also +writing buffer data to `/tmp/` for formatters to read that do not support input +via stdin. + +## Basic Usage + +Format the entire buffer, or visual selection of the buffer + +```viml +:Neoformat +``` + +Or specify a certain formatter (must be defined for the current filetype) + +```viml +:Neoformat jsbeautify +``` + +Or format a visual selection of code in a different filetype + +**Note:** you must use a ! and pass the filetype of the selection + +```viml +:Neoformat! python +``` + +You can also pass a formatter to use + +```viml +:Neoformat! python yapf +``` + +Or perhaps run a formatter on save + +```viml +augroup fmt + autocmd! + autocmd BufWritePre * undojoin | Neoformat +augroup END +``` + +The `undojoin` command will put changes made by Neoformat into the same +`undo-block` with the latest preceding change. See +[Managing Undo History](#managing-undo-history). + +## Install + +[vim-plug](https://github.com/junegunn/vim-plug) + +```viml +Plug 'sbdchd/neoformat' +``` + +## Current Limitation(s) + +If a formatter is either not configured to use `stdin`, or is not able to read +from `stdin`, then buffer data will be written to a file in `/tmp/neoformat/`, +where the formatter will then read from + +## Config [Optional] + +Define custom formatters. + +Options: + +| name | description | default | optional / required | +| ------------------ | ----------------------------------------------------------------------------------------------------------------- | ------- | ------------------- | +| `exe` | the name the formatter executable in the path | n/a | **required** | +| `args` | list of arguments | \[] | optional | +| `replace` | overwrite the file, instead of updating the buffer | 0 | optional | +| `stdin` | send data to the stdin of the formatter | 0 | optional | +| `stderr` | capture stderr output from formatter | 0 | optional | +| `no_append` | do not append the `path` of the file to the formatter command, used when the `path` is in the middle of a command | 0 | optional | +| `env` | list of environment variable definitions to be prepended to the formatter command | \[] | optional | +| `valid_exit_codes` | list of valid exit codes for formatters who do not respect common unix practices | \[0] | optional | + +Example: + +```viml +let g:neoformat_python_autopep8 = { + \ 'exe': 'autopep8', + \ 'args': ['-s 4', '-E'], + \ 'replace': 1 " replace the file, instead of updating buffer (default: 0), + \ 'stdin': 1, " send data to stdin of formatter (default: 0) + \ 'env': ["DEBUG=1"], " prepend environment variables to formatter command + \ 'valid_exit_codes': [0, 23], + \ 'no_append': 1, + \ } + +let g:neoformat_enabled_python = ['autopep8'] +``` + +Configure enabled formatters. + +```viml + +let g:neoformat_enabled_python = ['autopep8', 'yapf', 'docformatter', 'autoflake'] + +``` + +Have Neoformat use &formatprg as a formatter + +```viml +let g:neoformat_try_formatprg = 1 +``` + +Enable basic formatting when a filetype is not found. Disabled by default. + +```viml +" Enable alignment +let g:neoformat_basic_format_align = 1 + +" Enable tab to spaces conversion +let g:neoformat_basic_format_retab = 1 + +" Enable trimmming of trailing whitespace +let g:neoformat_basic_format_trim = 1 +``` + +Run all enabled formatters (by default Neoformat stops after the first formatter +succeeds) + +```viml +let g:neoformat_run_all_formatters = 1 +``` + +Above options can be activated or deactivated per buffer. For example: + +```viml + " runs all formatters for current buffer without tab to spaces conversion + let b:neoformat_run_all_formatters = 1 + let b:neoformat_basic_format_retab = 0 +``` + +Have Neoformat only msg when there is an error + +```viml +let g:neoformat_only_msg_on_error = 1 +``` + +When debugging, you can enable either of following variables for extra logging. + +```viml +let g:neoformat_verbose = 1 " only affects the verbosity of Neoformat +" Or +let &verbose = 1 " also increases verbosity of the editor as a whole +``` + +## Adding a New Formatter + +Note: you should replace everything `{{ }}` accordingly + +1. Create a file in `autoload/neoformat/formatters/{{ filetype }}.vim` if it does not + already exist for your filetype. + +2. Follow the following format + +See Config above for options + +```viml +function! neoformat#formatters#{{ filetype }}#enabled() abort + return ['{{ formatter name }}', '{{ other formatter name for filetype }}'] +endfunction + +function! neoformat#formatters#{{ filetype }}#{{ formatter name }}() abort + return { + \ 'exe': '{{ formatter name }}', + \ 'args': ['-s 4', '-q'], + \ 'stdin': 1 + \ } +endfunction + +function! neoformat#formatters#{{ filetype }}#{{ other formatter name }}() abort + return {'exe': {{ other formatter name }} +endfunction +``` + +## Managing Undo History + +If you use an `autocmd` to run Neoformat on save, and you have your editor +configured to save automatically on `CursorHold` then you might run into +problems reverting changes. Pressing `u` will undo the last change made by +Neoformat instead of the change that you made yourself - and then Neoformat +will run again redoing the change that you just reverted. To avoid this +problem you can run Neoformat with the Vim `undojoin` command to put changes +made by Neoformat into the same `undo-block` with the preceding change. For +example: + +```viml +augroup fmt + autocmd! + autocmd BufWritePre * undojoin | Neoformat +augroup END +``` + +When `undojoin` is used this way pressing `u` will "skip over" the Neoformat +changes - it will revert both the changes made by Neoformat and the change +that caused Neoformat to be invoked. + +## Supported Filetypes + +- Arduino + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`astyle`](http://astyle.sourceforge.net) +- Assembly + - [`asmfmt`](https://github.com/klauspost/asmfmt) +- Bazel + - [`buildifier`](https://github.com/bazelbuild/buildtools/blob/master/buildifier/README.md) +- C + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`astyle`](http://astyle.sourceforge.net) +- C# + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`astyle`](http://astyle.sourceforge.net) +- C++ + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`astyle`](http://astyle.sourceforge.net) +- CMake + - [`cmake_format`](https://github.com/cheshirekow/cmake_format) +- Crystal + - `crystal tool format` (ships with [`crystal`](http://crystal-lang.org)) +- CSS + - `css-beautify` (ships with [`js-beautify`](https://github.com/beautify-web/js-beautify)), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`stylefmt`](https://github.com/morishitter/stylefmt), + [`stylelint`](https://stylelint.io/), + [`csscomb`](http://csscomb.com), + [`prettier`](https://github.com/prettier/prettier) +- CSV + - [`prettydiff`](https://github.com/prettydiff/prettydiff) +- D + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`dfmt`](https://github.com/Hackerpilot/dfmt) +- Dart + - [`dartfmt`](https://www.dartlang.org/tools/) +- Dhall + - [`dhall format`](https://dhall-lang.org) +- dune + - [`dune format`](https://github.com/ocaml/dune) +- Elixir + - [`mix format`](https://hexdocs.pm/mix/master/Mix.Tasks.Format.html) +- Elm + - [`elm-format`](https://github.com/avh4/elm-format) +- Fish + - [`fish_indent`](http://fishshell.com) +- Go + - [`gofmt`](https://golang.org/cmd/gofmt/), + [`goimports`](https://godoc.org/golang.org/x/tools/cmd/goimports) +- GLSL + - [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html) +- GraphQL + - [`prettier`](https://github.com/prettier/prettier) +- Haskell + - [`stylish-haskell`](https://github.com/jaspervdj/stylish-haskell), + [`hindent`](https://github.com/chrisdone/hindent), + [`hfmt`](https://github.com/danstiner/hfmt), + [`brittany`](https://github.com/lspitzner/brittany), + [`sort-imports`](https://github.com/evanrelf/sort-imports), + [`floskell`](https://github.com/ennocramer/floskell) + [`ormolu`](https://github.com/tweag/ormolu) + ```vim + let g:ormolu_ghc_opt=["TypeApplications", "RankNTypes"] + ``` +- PureScript + - [`purty`](https://gitlab.com/joneshf/purty) +- HTML + - `html-beautify` (ships with [`js-beautify`](https://github.com/beautify-web/js-beautify)), + [`prettier`](https://github.com/prettier/prettier), + [`prettydiff`](https://github.com/prettydiff/prettydiff) +- Jade + - [`pug-beautifier`](https://github.com/vingorius/pug-beautifier) +- Java + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`astyle`](http://astyle.sourceforge.net), + [`prettier`](https://github.com/prettier/prettier) +- JavaScript + - [`js-beautify`](https://github.com/beautify-web/js-beautify), + [`prettier`](https://github.com/prettier/prettier), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`esformatter`](https://github.com/millermedeiros/esformatter/), + [`prettier-eslint`](https://github.com/kentcdodds/prettier-eslint-cli), + [`eslint_d`](https://github.com/mantoni/eslint_d.js) + [`standard`](https://standardjs.com/) +- JSON + - [`js-beautify`](https://github.com/beautify-web/js-beautify), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`prettier`](https://github.com/prettier/prettier), + [`jq`](https://stedolan.github.io/jq/), + [`fixjson`](https://github.com/rhysd/fixjson) +- Kotlin + - [`ktlint`](https://github.com/shyiko/ktlint), + [`prettier`](https://github.com/prettier/prettier) +- LaTeX + - [`latexindent`](https://github.com/cmhughes/latexindent.pl) +- Less + - [`csscomb`](http://csscomb.com), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`prettier`](https://github.com/prettier/prettier), + [`stylelint`](https://stylelint.io/) +- Lua + - [`luaformatter`](https://github.com/LuaDevelopmentTools/luaformatter) + - [`lua-fmt`](https://github.com/trixnz/lua-fmt) +- Markdown + - [`remark`](https://github.com/wooorm/remark) + [`prettier`](https://github.com/prettier/prettier) +- Matlab + - [`matlab-formatter-vscode`](https://github.com/affenwiesel/matlab-formatter-vscode) +- Nim + - `nimpretty` (ships with [`nim`](https://nim-lang.org/)) +- Nix + - [`nixfmt`](https://github.com/serokell/nixfmt) +- Objective-C + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`astyle`](http://astyle.sourceforge.net) +- OCaml + - [`ocp-indent`](http://www.typerex.org/ocp-indent.html), + [`ocamlformat`](https://github.com/ocaml-ppx/ocamlformat) +- Pandoc Markdown + - [`pandoc`](https://pandoc.org/MANUAL.html) +- Pawn + - [`uncrustify`](http://uncrustify.sourceforge.net) +- Perl + - [`perltidy`](http://perltidy.sourceforge.net) +- PHP + - [`php_beautifier`](http://pear.php.net/package/PHP_Beautifier), + [`php-cs-fixer`](http://cs.sensiolabs.org/), + [`phpcbf`](https://github.com/squizlabs/PHP_CodeSniffer) +- Proto + - [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html) +- Pug (formally Jade) + - [`pug-beautifier`](https://github.com/vingorius/pug-beautifier) +- Python + - [`yapf`](https://github.com/google/yapf), + [`autopep8`](https://github.com/hhatto/autopep8), + [`black`](https://github.com/ambv/black) + [`pydevf`](https://github.com/fabioz/PyDev.Formatter) + - [`isort`](https://github.com/timothycrosley/isort) + - [`docformatter`](https://github.com/myint/docformatter) + - [`pyment`](https://github.com/dadadel/pyment) + - [`autoflake`](https://github.com/myint/autoflake) +- R + - [`styler`](https://github.com/r-lib/styler), + [`formatR`](https://github.com/yihui/formatR) +- Reason + - [`refmt`](https://github.com/facebook/reason) +- Ruby + - [`rufo`](https://github.com/ruby-formatter/rufo), + [`ruby-beautify`](https://github.com/erniebrodeur/ruby-beautify), + [`rubocop`](https://github.com/bbatsov/rubocop) +- Rust + - [`rustfmt`](https://github.com/rust-lang-nursery/rustfmt) +- Sass + - [`sass-convert`](http://sass-lang.com/documentation/#executables), + [`stylelint`](https://stylelint.io/), + [`csscomb`](http://csscomb.com) +- Sbt + - [`scalafmt`](http://scalameta.org/scalafmt/) +- Scala + - [`scalariform`](https://github.com/scala-ide/scalariform), + [`scalafmt`](http://scalameta.org/scalafmt/) +- SCSS + - [`sass-convert`](http://sass-lang.com/documentation/#executables), + [`stylelint`](https://stylelint.io/), + [`stylefmt`](https://github.com/morishitter/stylefmt), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`csscomb`](http://csscomb.com), + [`prettier`](https://github.com/prettier/prettier) +- Shell + - [`shfmt`](https://github.com/mvdan/sh) + ```vim + let g:shfmt_opt="-ci" + ``` +- SQL + - [`sqlfmt`](https://github.com/jackc/sqlfmt), + `sqlformat` (ships with [sqlparse](https://github.com/andialbrecht/sqlparse)), + `pg_format` (ships with [pgFormatter](https://github.com/darold/pgFormatter)) +- Starlark + - [`buildifier`](https://github.com/bazelbuild/buildtools/blob/master/buildifier/README.md) +- Svelte + - [`prettier-plugin-svelte`](https://github.com/UnwrittenFun/prettier-plugin-svelte) +- Swift + - [`Swiftformat`](https://github.com/nicklockwood/SwiftFormat) +- Terraform + - [`terraform`](https://www.terraform.io/docs/commands/fmt.html), +- TypeScript + - [`tsfmt`](https://github.com/vvakame/typescript-formatter), + [`prettier`](https://github.com/prettier/prettier), + [`tslint`](https://palantir.github.io/tslint) + [`eslint_d`](https://github.com/mantoni/eslint_d.js) + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), +- VALA + - [`uncrustify`](http://uncrustify.sourceforge.net) +- Vue + - [`prettier`](https://github.com/prettier/prettier) +- XHTML + - [`tidy`](http://www.html-tidy.org), + [`prettydiff`](https://github.com/prettydiff/prettydiff) +- XML + - [`tidy`](http://www.html-tidy.org), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`prettier`](https://github.com/prettier/prettier) +- YAML + - [`pyaml`](https://pypi.python.org/pypi/pyaml), + [`prettier`](https://github.com/prettier/prettier) diff --git a/bundle/neoformat/autoload/neoformat.vim b/bundle/neoformat/autoload/neoformat.vim new file mode 100644 index 000000000..1aa642c93 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat.vim @@ -0,0 +1,325 @@ +function! neoformat#Neoformat(bang, user_input, start_line, end_line) abort + let search = @/ + let view = winsaveview() + let original_filetype = &filetype + + call s:neoformat(a:bang, a:user_input, a:start_line, a:end_line) + + let @/ = search + call winrestview(view) + let &filetype = original_filetype +endfunction + +function! s:neoformat(bang, user_input, start_line, end_line) abort + + if !&modifiable + return neoformat#utils#warn('buffer not modifiable') + endif + + let using_visual_selection = a:start_line != 1 || a:end_line != line('$') + + let inputs = split(a:user_input) + if a:bang + let &filetype = len(inputs) > 1 ? inputs[0] : a:user_input + endif + + let filetype = s:split_filetypes(&filetype) + + let using_user_passed_formatter = (!empty(a:user_input) && !a:bang) + \ || (len(inputs) > 1 && a:bang) + + if using_user_passed_formatter + let formatters = len(inputs) > 1 ? [inputs[1]] : [a:user_input] + else + let formatters = s:get_enabled_formatters(filetype) + if formatters == [] + call neoformat#utils#msg('formatter not defined for ' . filetype . ' filetype') + return s:basic_format() + endif + endif + + let formatters_failed = [] + let formatters_changed = [] + for formatter in formatters + + if &formatprg != '' && split(&formatprg)[0] ==# formatter + \ && neoformat#utils#var('neoformat_try_formatprg') + call neoformat#utils#log('using formatprg') + let fmt_prg_def = split(&formatprg) + let definition = { + \ 'exe': fmt_prg_def[0], + \ 'args': fmt_prg_def[1:], + \ 'stdin': 1, + \ } + elseif exists('b:neoformat_' . filetype . '_' . formatter) + let definition = b:neoformat_{filetype}_{formatter} + elseif exists('g:neoformat_' . filetype . '_' . formatter) + let definition = g:neoformat_{filetype}_{formatter} + elseif s:autoload_func_exists('neoformat#formatters#' . filetype . '#' . formatter) + let definition = neoformat#formatters#{filetype}#{formatter}() + else + call neoformat#utils#log('definition not found for formatter: ' . formatter) + if using_user_passed_formatter + call neoformat#utils#msg('formatter definition for ' . a:user_input . ' not found') + + return s:basic_format() + endif + continue + endif + + let cmd = s:generate_cmd(definition, filetype) + if cmd == {} + if using_user_passed_formatter + return neoformat#utils#warn('formatter ' . a:user_input . ' failed') + endif + continue + endif + + let stdin = getbufline(bufnr('%'), a:start_line, a:end_line) + let original_buffer = getbufline(bufnr('%'), 1, '$') + + call neoformat#utils#log(stdin) + + call neoformat#utils#log(cmd.exe) + if cmd.stdin + call neoformat#utils#log('using stdin') + let stdin_str = join(stdin, "\n") + let stdout = split(system(cmd.exe, stdin_str), '\n') + else + call neoformat#utils#log('using tmp file') + call writefile(stdin, cmd.tmp_file_path) + let stdout = split(system(cmd.exe), '\n') + endif + + " read from /tmp file if formatter replaces file on format + if cmd.replace || len(stdout) == 0 + let stdout = readfile(cmd.tmp_file_path) + endif + + call neoformat#utils#log(stdout) + + call neoformat#utils#log(cmd.valid_exit_codes) + call neoformat#utils#log(v:shell_error) + + let process_ran_succesfully = index(cmd.valid_exit_codes, v:shell_error) != -1 + + if cmd.stderr_log != '' + call neoformat#utils#log('stderr output redirected to file' . cmd.stderr_log) + call neoformat#utils#log_file_content(cmd.stderr_log) + endif + if process_ran_succesfully + " 1. append the lines that are before and after the formatterd content + let lines_after = getbufline(bufnr('%'), a:end_line + 1, '$') + let lines_before = getbufline(bufnr('%'), 1, a:start_line - 1) + + let new_buffer = lines_before + stdout + lines_after + if new_buffer !=# original_buffer + + call s:deletelines(len(new_buffer), line('$')) + + call setline(1, new_buffer) + + call add(formatters_changed, cmd.name) + let endmsg = cmd.name . ' formatted buffer' + else + + let endmsg = 'no change necessary with ' . cmd.name + endif + if !neoformat#utils#var('neoformat_run_all_formatters') + return neoformat#utils#msg(endmsg) + endif + call neoformat#utils#log('running next formatter') + else + call add(formatters_failed, cmd.name) + call neoformat#utils#log(v:shell_error) + call neoformat#utils#log('trying next formatter') + endif + endfor + if len(formatters_failed) > 0 + call neoformat#utils#msg('formatters ' . join(formatters_failed, ", ") . ' failed to run') + endif + if len(formatters_changed) > 0 + call neoformat#utils#msg(join(formatters_changed, ", ") . ' formatted buffer') + elseif len(formatters_failed) == 0 + call neoformat#utils#msg('no change necessary') + endif +endfunction + +function! s:get_enabled_formatters(filetype) abort + if &formatprg != '' && neoformat#utils#var('neoformat_try_formatprg') + call neoformat#utils#log('adding formatprg to enabled formatters') + let format_prg_exe = [split(&formatprg)[0]] + else + let format_prg_exe = [] + endif + + " Note: we append format_prg_exe to ever return as it will either be + " [], or it will be a formatter that we want to try first + + if exists('b:neoformat_enabled_' . a:filetype) + return format_prg_exe + b:neoformat_enabled_{a:filetype} + elseif exists('g:neoformat_enabled_' . a:filetype) + return format_prg_exe + g:neoformat_enabled_{a:filetype} + elseif s:autoload_func_exists('neoformat#formatters#' . a:filetype . '#enabled') + return format_prg_exe + neoformat#formatters#{a:filetype}#enabled() + endif + return format_prg_exe +endfunction + +function! s:deletelines(start, end) abort + silent! execute a:start . ',' . a:end . 'delete _' +endfunction + +function! neoformat#CompleteFormatters(ArgLead, CmdLine, CursorPos) abort + if a:CmdLine =~ '!' + " 1. user inputting formatter :Neoformat! css + if a:CmdLine =~# 'Neoformat! \S*\s' + let filetype = split(a:CmdLine)[1] + return filter(s:get_enabled_formatters(filetype), + \ "v:val =~? '^" . a:ArgLead ."'") + endif + + " 2. user inputting filetype :Neoformat! + " https://github.com/junegunn/fzf.vim/pull/110 + " 1. globpath (find) all filetype files in neoformat + " 2. split at new lines + " 3. map ~/.config/nvim/plugged/neoformat/autoload/neoformat/formatters/xml.vim --> xml + " 4. sort & uniq to eliminate dupes + " 5. filter for input + return filter(uniq(sort(map(split(globpath(&runtimepath, + \ 'plugged/neoformat/autoload/neoformat/formatters/*.vim'), '\n'), + \ "fnamemodify(v:val, ':t:r')"))), + \ "v:val =~? '^" . a:ArgLead . "'") + endif + if a:ArgLead =~ '[^A-Za-z0-9]' + return [] + endif + let filetype = s:split_filetypes(&filetype) + return filter(s:get_enabled_formatters(filetype), + \ "v:val =~? '^" . a:ArgLead ."'") +endfunction + +function! s:autoload_func_exists(func_name) abort + try + call eval(a:func_name . '()') + catch /^Vim\%((\a\+)\)\=:E/ + return 0 + endtry + return 1 +endfunction + +function! s:split_filetypes(filetype) abort + if a:filetype == '' + return '' + endif + return split(a:filetype, '\.')[0] +endfunction + +function! s:generate_cmd(definition, filetype) abort + let executable = get(a:definition, 'exe', '') + if executable == '' + call neoformat#utils#log('no exe field in definition') + return {} + endif + if !executable(executable) + call neoformat#utils#log('executable: ' . executable . ' is not an executable') + return {} + endif + + let args = get(a:definition, 'args', []) + let args_expanded = [] + for a in args + let args_expanded = add(args_expanded, s:expand_fully(a)) + endfor + + let no_append = get(a:definition, 'no_append', 0) + let using_stdin = get(a:definition, 'stdin', 0) + let using_stderr = get(a:definition, 'stderr', 0) + let stderr_log = '' + + let filename = expand('%:t') + + let tmp_dir = has('win32') ? expand('$TEMP/neoformat') : + \ exists('$TMPDIR') ? expand('$TMPDIR/neoformat') : + \ '/tmp/neoformat' + + if !isdirectory(tmp_dir) + call mkdir(tmp_dir, 'p') + endif + + if get(a:definition, 'replace', 0) + let path = !using_stdin ? expand(tmp_dir . '/' . fnameescape(filename)) : '' + else + let path = !using_stdin ? tempname() : '' + endif + + let inline_environment = get(a:definition, 'env', []) + let _fullcmd = join(inline_environment, ' ') . ' ' . executable . ' ' . join(args_expanded) . ' ' . (no_append ? '' : path) + " make sure there aren't any double spaces in the cmd + let fullcmd = join(split(_fullcmd)) + if !using_stderr + if neoformat#utils#should_be_verbose() + let stderr_log = expand(tmp_dir . '/stderr.log') + let fullcmd = fullcmd . ' 2> ' . stderr_log + else + if (has('win32') || has('win64')) + let stderr_log = '' + let fullcmd = fullcmd . ' 2> ' . 'NUL' + else + let stderr_log = '' + let fullcmd = fullcmd . ' 2> ' . '/dev/null' + endif + endif + endif + + return { + \ 'exe': fullcmd, + \ 'stdin': using_stdin, + \ 'stderr_log': stderr_log, + \ 'name': a:definition.exe, + \ 'replace': get(a:definition, 'replace', 0), + \ 'tmp_file_path': path, + \ 'valid_exit_codes': get(a:definition, 'valid_exit_codes', [0]), + \ } +endfunction + +function! s:expand_fully(string) abort + return substitute(a:string, '%\(:[a-z]\)*', '\=expand(submatch(0))', 'g') +endfunction + +function! s:basic_format() abort + call neoformat#utils#log('running basic format') + if !exists('g:neoformat_basic_format_align') + let g:neoformat_basic_format_align = 0 + endif + + if !exists('g:neoformat_basic_format_retab') + let g:neoformat_basic_format_retab = 0 + endif + + if !exists('g:neoformat_basic_format_trim') + let g:neoformat_basic_format_trim = 0 + endif + + if neoformat#utils#var('neoformat_basic_format_align') + call neoformat#utils#log('aligning with basic formatter') + let v = winsaveview() + silent! execute 'normal gg=G' + call winrestview(v) + endif + if neoformat#utils#var('neoformat_basic_format_retab') + call neoformat#utils#log('converting tabs with basic formatter') + retab + endif + if neoformat#utils#var('neoformat_basic_format_trim') + call neoformat#utils#log('trimming whitespace with basic formatter') + " http://stackoverflow.com/q/356126 + let search = @/ + let view = winsaveview() + " vint: -ProhibitCommandRelyOnUser -ProhibitCommandWithUnintendedSideEffect + silent! %s/\s\+$//e + " vint: +ProhibitCommandRelyOnUser +ProhibitCommandWithUnintendedSideEffect + let @/=search + call winrestview(view) + endif +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/arduino.vim b/bundle/neoformat/autoload/neoformat/formatters/arduino.vim new file mode 100644 index 000000000..c3901b92b --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/arduino.vim @@ -0,0 +1,15 @@ +function! neoformat#formatters#arduino#enabled() abort + return ['uncrustify', 'clangformat', 'astyle'] +endfunction + +function! neoformat#formatters#arduino#uncrustify() abort + return neoformat#formatters#cpp#uncrustify() +endfunction + +function! neoformat#formatters#arduino#clangformat() abort + return neoformat#formatters#c#clangformat() +endfunction + +function! neoformat#formatters#arduino#astyle() abort + return neoformat#formatters#c#astyle() +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/asm.vim b/bundle/neoformat/autoload/neoformat/formatters/asm.vim new file mode 100644 index 000000000..f2d72c044 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/asm.vim @@ -0,0 +1,10 @@ +function! neoformat#formatters#asm#enabled() abort + return ['asmfmt', ] +endfunction + +function! neoformat#formatters#asm#asmfmt() abort + return { + \ 'exe': 'asmfmt', + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/bzl.vim b/bundle/neoformat/autoload/neoformat/formatters/bzl.vim new file mode 100644 index 000000000..6895686d0 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/bzl.vim @@ -0,0 +1,10 @@ +function! neoformat#formatters#bzl#enabled() abort + return ['buildifier'] +endfunction + +function! neoformat#formatters#bzl#buildifier() abort + return { + \ 'exe': 'buildifier', + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/c.vim b/bundle/neoformat/autoload/neoformat/formatters/c.vim new file mode 100644 index 000000000..304907d9b --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/c.vim @@ -0,0 +1,27 @@ +function! neoformat#formatters#c#enabled() abort + return ['uncrustify', 'clangformat', 'astyle'] +endfunction + +function! neoformat#formatters#c#uncrustify() abort + return { + \ 'exe': 'uncrustify', + \ 'args': ['-q', '-l C'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#c#clangformat() abort + return { + \ 'exe': 'clang-format', + \ 'args': ['-assume-filename=' . expand('%:t')], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#c#astyle() abort + return { + \ 'exe': 'astyle', + \ 'args': ['--mode=c'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/cmake.vim b/bundle/neoformat/autoload/neoformat/formatters/cmake.vim new file mode 100644 index 000000000..aec99b5b6 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/cmake.vim @@ -0,0 +1,9 @@ +function! neoformat#formatters#cmake#enabled() abort + return ['cmakeformat'] +endfunction + +function! neoformat#formatters#cmake#cmakeformat() abort + return { + \ 'exe': 'cmake-format' + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/cpp.vim b/bundle/neoformat/autoload/neoformat/formatters/cpp.vim new file mode 100644 index 000000000..c6263f76c --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/cpp.vim @@ -0,0 +1,20 @@ +function! neoformat#formatters#cpp#enabled() abort + return ['uncrustify', 'clangformat', 'astyle'] +endfunction + +function! neoformat#formatters#cpp#uncrustify() abort + return { + \ 'exe': 'uncrustify', + \ 'args': ['-q', '-l CPP'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#cpp#clangformat() abort + return neoformat#formatters#c#clangformat() +endfunction + +function! neoformat#formatters#cpp#astyle() abort + return neoformat#formatters#c#astyle() +endfunction + diff --git a/bundle/neoformat/autoload/neoformat/formatters/crystal.vim b/bundle/neoformat/autoload/neoformat/formatters/crystal.vim new file mode 100644 index 000000000..d8c909933 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/crystal.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#crystal#enabled() abort + return ['crystalformat'] +endfunction + +function! neoformat#formatters#crystal#crystalformat() abort + return { + \ 'exe': 'crystal', + \ 'args': ['tool', 'format'], + \ 'replace': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/cs.vim b/bundle/neoformat/autoload/neoformat/formatters/cs.vim new file mode 100644 index 000000000..7827a487a --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/cs.vim @@ -0,0 +1,19 @@ +function! neoformat#formatters#cs#enabled() abort + return ['uncrustify', 'astyle'] +endfunction + +function! neoformat#formatters#cs#uncrustify() abort + return { + \ 'exe': 'uncrustify', + \ 'args': ['-q', '-l CS'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#cs#astyle() abort + return { + \ 'exe': 'astyle', + \ 'args': ['--mode=cs'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/css.vim b/bundle/neoformat/autoload/neoformat/formatters/css.vim new file mode 100644 index 000000000..0eb740bf6 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/css.vim @@ -0,0 +1,54 @@ +function! neoformat#formatters#css#enabled() abort + return ['stylelint', 'stylefmt', 'prettier', 'cssbeautify', 'prettydiff', 'csscomb'] +endfunction + +function! neoformat#formatters#css#cssbeautify() abort + return { + \ 'exe': 'css-beautify', + \ 'args': ['--indent-size ' .shiftwidth()], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#css#csscomb() abort + return { + \ 'exe': 'csscomb', + \ 'replace': 1 + \ } +endfunction + +function! neoformat#formatters#css#prettydiff() abort + return { + \ 'exe': 'prettydiff', + \ 'args': ['mode:"beautify"', + \ 'lang:"css"', + \ 'insize:' .shiftwidth(), + \ 'readmethod:"filescreen"', + \ 'endquietly:"quiet"', + \ 'source:"%:p"'], + \ 'no_append': 1 + \ } +endfunction + +function! neoformat#formatters#css#stylefmt() abort + return { + \ 'exe': 'stylefmt', + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#css#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"', '--parser', 'css'], + \ 'stdin': 1 + \ } +endfunction + +function! neoformat#formatters#css#stylelint() abort + return { + \ 'exe': 'stylelint', + \ 'args': ['--fix', '--stdin-filename', '"%:t"'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/csv.vim b/bundle/neoformat/autoload/neoformat/formatters/csv.vim new file mode 100644 index 000000000..57a2f0b7d --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/csv.vim @@ -0,0 +1,15 @@ +function! neoformat#formatters#csv#enabled() abort + return ['prettydiff'] +endfunction + +function! neoformat#formatters#csv#prettydiff() abort + return { + \ 'exe': 'prettydiff', + \ 'args': ['mode:"beautify"', + \ 'lang:"csv"', + \ 'readmethod:"filescreen"', + \ 'endquietly:"quiet"', + \ 'source:"%:p"'], + \ 'no_append': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/d.vim b/bundle/neoformat/autoload/neoformat/formatters/d.vim new file mode 100644 index 000000000..e8413024a --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/d.vim @@ -0,0 +1,18 @@ +function! neoformat#formatters#d#enabled() abort + return ['uncrustify', 'dfmt'] +endfunction + +function! neoformat#formatters#d#dfmt() abort + return { + \ 'exe': 'dfmt', + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#d#uncrustify() abort + return { + \ 'exe': 'uncrustify', + \ 'args': ['-q', '-l D'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/dart.vim b/bundle/neoformat/autoload/neoformat/formatters/dart.vim new file mode 100644 index 000000000..0f32faf30 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/dart.vim @@ -0,0 +1,10 @@ +function! neoformat#formatters#dart#enabled() abort + return ['dartfmt'] +endfunction + +function! neoformat#formatters#dart#dartfmt() abort + return { + \ 'exe': 'dartfmt', + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/dhall.vim b/bundle/neoformat/autoload/neoformat/formatters/dhall.vim new file mode 100644 index 000000000..d2023b437 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/dhall.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#dhall#enabled() abort + return ['dhall'] +endfunction + +function! neoformat#formatters#dhall#dhall() abort + return { + \ 'exe': 'dhall', + \ 'args': ['format'], + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/dune.vim b/bundle/neoformat/autoload/neoformat/formatters/dune.vim new file mode 100644 index 000000000..e720a8b64 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/dune.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#dune#enabled() abort + return ['dune'] +endfunction + +function! neoformat#formatters#dune#dune() abort + return { + \ 'exe': 'dune', + \ 'args': ['format'], + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/elixir.vim b/bundle/neoformat/autoload/neoformat/formatters/elixir.vim new file mode 100644 index 000000000..575e2790b --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/elixir.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#elixir#enabled() abort + return ['mixformat'] +endfunction + +function! neoformat#formatters#elixir#mixformat() abort + return { + \ 'exe': 'mix', + \ 'args': ['format', "-"], + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/elm.vim b/bundle/neoformat/autoload/neoformat/formatters/elm.vim new file mode 100644 index 000000000..730e6e62b --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/elm.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#elm#enabled() abort + return ['elmformat'] +endfunction + +function! neoformat#formatters#elm#elmformat() abort + return { + \ 'exe': 'elm-format', + \ 'args': ['--stdin', '--elm-version=0.19'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/fish.vim b/bundle/neoformat/autoload/neoformat/formatters/fish.vim new file mode 100644 index 000000000..63989a151 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/fish.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#fish#enabled() abort + return ['fish_indent'] +endfunction + +function! neoformat#formatters#fish#fish_indent() abort + return { + \ 'exe': 'fish_indent', + \ 'stdin': 1, + \ } +endfunction + diff --git a/bundle/neoformat/autoload/neoformat/formatters/glsl.vim b/bundle/neoformat/autoload/neoformat/formatters/glsl.vim new file mode 100644 index 000000000..83b135524 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/glsl.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#glsl#enabled() abort + return ['clangformat'] +endfunction + +function! neoformat#formatters#glsl#clangformat() abort + return { + \ 'exe': 'clang-format', + \ 'args': ['-assume-filename=' . expand('%:t')], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/go.vim b/bundle/neoformat/autoload/neoformat/formatters/go.vim new file mode 100644 index 000000000..33387ff38 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/go.vim @@ -0,0 +1,18 @@ +function! neoformat#formatters#go#enabled() abort + return ['goimports', 'gofmt'] +endfunction + +function! neoformat#formatters#go#gofmt() abort + return { + \ 'exe': 'gofmt', + \ 'stdin': 1, + \ } + endfunction + +function! neoformat#formatters#go#goimports() abort + return { + \ 'exe': 'goimports', + \ 'stdin': 1, + \ } +endfunction + diff --git a/bundle/neoformat/autoload/neoformat/formatters/graphql.vim b/bundle/neoformat/autoload/neoformat/formatters/graphql.vim new file mode 100644 index 000000000..6f95d122b --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/graphql.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#graphql#enabled() abort + return ['prettier'] +endfunction + +function! neoformat#formatters#graphql#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"', '--parser', 'graphql'], + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/haskell.vim b/bundle/neoformat/autoload/neoformat/formatters/haskell.vim new file mode 100644 index 000000000..8c91a97f5 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/haskell.vim @@ -0,0 +1,61 @@ +function! neoformat#formatters#haskell#enabled() abort + return ['hindent', 'stylishhaskell', 'hfmt', 'brittany', 'sortimports', 'floskell', 'ormolu'] +endfunction + +function! neoformat#formatters#haskell#hindent() abort + return { + \ 'exe' : 'hindent', + \ 'args': ['--indent-size ' . shiftwidth()], + \ 'stdin' : 1, + \ } +endfunction + +function! neoformat#formatters#haskell#stylishhaskell() abort + return { + \ 'exe': 'stylish-haskell', + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#haskell#hfmt() abort + return { + \ 'exe': 'hfmt', + \ 'args': ['-'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#haskell#brittany() abort + return { + \ 'exe': 'brittany', + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#haskell#sortimports() abort + return { + \ 'exe': 'sort-imports', + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#haskell#floskell() abort + return { + \ 'exe': 'floskell', + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#haskell#ormolu() abort + let opts = get(g:, 'ormolu_ghc_opt', []) + if opts != [] + let opts = '-o' . join(opts, ' -o') + else + let opts = '' + endif + return { + \ 'exe' : 'ormolu', + \ 'args': ['-p', opts], + \ 'stdin' : 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/html.vim b/bundle/neoformat/autoload/neoformat/formatters/html.vim new file mode 100644 index 000000000..8f41ba17b --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/html.vim @@ -0,0 +1,44 @@ +function! neoformat#formatters#html#enabled() abort + return ['htmlbeautify', 'prettier', 'tidy', 'prettydiff'] +endfunction + +function! neoformat#formatters#html#tidy() abort + return { + \ 'exe': 'tidy', + \ 'args': ['-quiet', + \ '--indent auto', + \ '--indent-spaces ' . shiftwidth(), + \ '--vertical-space yes', + \ '--tidy-mark no', + \ '-wrap ' . &textwidth + \ ] + \ } +endfunction + +function! neoformat#formatters#html#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#html#htmlbeautify() abort + return { + \ 'exe': 'html-beautify', + \ 'args': ['--indent-size ' .shiftwidth()], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#html#prettydiff() abort + return { + \ 'exe': 'prettydiff', + \ 'args': ['mode:"beautify"', + \ 'lang:"html"', + \ 'readmethod:"filescreen"', + \ 'endquietly:"quiet"', + \ 'source:"%:p"'], + \ 'no_append': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/jade.vim b/bundle/neoformat/autoload/neoformat/formatters/jade.vim new file mode 100644 index 000000000..083b21cc2 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/jade.vim @@ -0,0 +1,7 @@ +function! neoformat#formatters#jade#enabled() abort + return ['pugbeautifier'] +endfunction + +function! neoformat#formatters#jade#pugbeautifier() abort + return neoformat#formatters#pug#pugbeautifier() +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/java.vim b/bundle/neoformat/autoload/neoformat/formatters/java.vim new file mode 100644 index 000000000..81aaa80ca --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/java.vim @@ -0,0 +1,39 @@ +function! neoformat#formatters#java#enabled() abort + return ['uncrustify', 'astyle', 'clangformat', 'prettier'] +endfunction + +function! neoformat#formatters#java#uncrustify() abort + return { + \ 'exe': 'uncrustify', + \ 'args': ['-q', '-l JAVA'], + \ 'stdin': 1, + \ } +endfunction + + +function! neoformat#formatters#java#astyle() abort + return { + \ 'exe': 'astyle', + \ 'args': ['--mode=java'], + \ 'stdin': 1, + \ } +endfunction + + +function! neoformat#formatters#java#clangformat() abort + return { + \ 'exe': 'clang-format', + \ 'args': ['-assume-filename=' . expand('%:t')], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#java#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"'], + \ 'stdin': 1, + \ } +endfunction + + diff --git a/bundle/neoformat/autoload/neoformat/formatters/javascript.vim b/bundle/neoformat/autoload/neoformat/formatters/javascript.vim new file mode 100644 index 000000000..f4a741cff --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/javascript.vim @@ -0,0 +1,70 @@ +function! neoformat#formatters#javascript#enabled() abort + return ['jsbeautify', 'standard', 'prettier', 'prettydiff', 'clangformat', 'esformatter', 'prettiereslint', 'eslint_d'] +endfunction + +function! neoformat#formatters#javascript#jsbeautify() abort + return { + \ 'exe': 'js-beautify', + \ 'args': ['--indent-size ' .shiftwidth()], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#javascript#clangformat() abort + return { + \ 'exe': 'clang-format', + \ 'args': ['-assume-filename=' . expand('%:t')], + \ 'stdin': 1 + \ } +endfunction + +function! neoformat#formatters#javascript#prettydiff() abort + return { + \ 'exe': 'prettydiff', + \ 'args': ['mode:"beautify"', + \ 'lang:"javascript"', + \ 'readmethod:"filescreen"', + \ 'endquietly:"quiet"', + \ 'source:"%:p"'], + \ 'no_append': 1 + \ } +endfunction + +function! neoformat#formatters#javascript#esformatter() abort + return { + \ 'exe': 'esformatter', + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#javascript#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#javascript#prettiereslint() abort + return { + \ 'exe': 'prettier-eslint', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#javascript#eslint_d() abort + return { + \ 'exe': 'eslint_d', + \ 'args': ['--stdin', '--stdin-filename', '"%:p"', '--fix-to-stdout'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#javascript#standard() abort + return { + \ 'exe': 'standard', + \ 'args': ['--stdin','--fix'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/jinja.vim b/bundle/neoformat/autoload/neoformat/formatters/jinja.vim new file mode 100644 index 000000000..caf0a16d7 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/jinja.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#jinja#enabled() abort + return ['prettydiff', 'htmlbeautify'] +endfunction + +function! neoformat#formatters#jinja#htmlbeautify() abort + return neoformat#formatters#html#htmlbeautify() +endfunction + +function! neoformat#formatters#jinja#prettydiff() abort + return neoformat#formatters#html#prettydiff() +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/json.vim b/bundle/neoformat/autoload/neoformat/formatters/json.vim new file mode 100644 index 000000000..f11dc7fec --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/json.vim @@ -0,0 +1,35 @@ +function! neoformat#formatters#json#enabled() abort + return ['jsbeautify', 'prettydiff', 'prettier', 'jq', 'fixjson'] +endfunction + +function! neoformat#formatters#json#jsbeautify() abort + return neoformat#formatters#javascript#jsbeautify() +endfunction + +function! neoformat#formatters#json#prettydiff() abort + return neoformat#formatters#javascript#prettydiff() +endfunction + +function! neoformat#formatters#json#jq() abort + return { + \ 'exe': 'jq', + \ 'args': ['.'], + \ } +endfunction + +function! neoformat#formatters#json#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"', '--parser', 'json'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#json#fixjson() abort + let l:filename = fnamemodify(bufname('%'), ':t') + return { + \ 'exe': 'fixjson', + \ 'args': ['--stdin-filename', l:filename], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/kotlin.vim b/bundle/neoformat/autoload/neoformat/formatters/kotlin.vim new file mode 100644 index 000000000..f19b62cd4 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/kotlin.vim @@ -0,0 +1,21 @@ +function! neoformat#formatters#kotlin#enabled() abort + return ['ktlint', 'prettier'] +endfunction + +function! neoformat#formatters#kotlin#ktlint() abort + return { + \ 'exe': 'ktlint', + \ 'args': ['-F'], + \ 'replace': 1, + \ } +endfunction + +function! neoformat#formatters#kotlin#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"'], + \ 'stdin': 1, + \ } +endfunction + + diff --git a/bundle/neoformat/autoload/neoformat/formatters/less.vim b/bundle/neoformat/autoload/neoformat/formatters/less.vim new file mode 100644 index 000000000..cb4d6d31f --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/less.vim @@ -0,0 +1,19 @@ +function! neoformat#formatters#less#enabled() abort + return ['stylelint', 'prettier', 'csscomb', 'prettydiff'] +endfunction + +function! neoformat#formatters#less#csscomb() abort + return neoformat#formatters#css#csscomb() +endfunction + +function! neoformat#formatters#less#prettydiff() abort + return neoformat#formatters#css#prettydiff() +endfunction + +function! neoformat#formatters#less#prettier() abort + return neoformat#formatters#css#prettier() +endfunction + +function! neoformat#formatters#less#stylelint() abort + return neoformat#formatters#css#stylelint() +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/lua.vim b/bundle/neoformat/autoload/neoformat/formatters/lua.vim new file mode 100644 index 000000000..83a5dc399 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/lua.vim @@ -0,0 +1,17 @@ +function! neoformat#formatters#lua#enabled() abort + return ['luaformatter', 'luafmt'] +endfunction + +function! neoformat#formatters#lua#luaformatter() abort + return { + \ 'exe': 'luaformatter' + \ } +endfunction + +function! neoformat#formatters#lua#luafmt() abort + return { + \ 'exe': 'luafmt', + \ 'args': ['--stdin'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/markdown.vim b/bundle/neoformat/autoload/neoformat/formatters/markdown.vim new file mode 100644 index 000000000..2003e0a4b --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/markdown.vim @@ -0,0 +1,19 @@ +function! neoformat#formatters#markdown#enabled() abort + return ['remark', 'prettier'] +endfunction + +function! neoformat#formatters#markdown#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#markdown#remark() abort + return { + \ 'exe': 'remark', + \ 'args': ['--no-color', '--silent'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/matlab.vim b/bundle/neoformat/autoload/neoformat/formatters/matlab.vim new file mode 100644 index 000000000..9bc268c91 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/matlab.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#matlab#enabled() abort + return ['matlabformatter'] +endfunction + +function! neoformat#formatters#matlab#matlabformatter() abort + return { + \ 'exe': 'matlab_formatter.py', + \ 'stdin': 0 + \ } +endfunction + diff --git a/bundle/neoformat/autoload/neoformat/formatters/nim.vim b/bundle/neoformat/autoload/neoformat/formatters/nim.vim new file mode 100644 index 000000000..edaa6fa0a --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/nim.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#nim#enabled() abort + return ['nimpretty'] +endfunction + +function! neoformat#formatters#nim#nimpretty() abort + return { + \ 'exe': 'nimpretty', + \ 'args': ['--backup:off'], + \ 'replace': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/nix.vim b/bundle/neoformat/autoload/neoformat/formatters/nix.vim new file mode 100644 index 000000000..86475edfa --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/nix.vim @@ -0,0 +1,10 @@ +function! neoformat#formatters#nix#enabled() abort + return ['nixfmt'] +endfunction + +function! neoformat#formatters#nix#nixfmt() abort + return { + \ 'exe': 'nixfmt', + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/objc.vim b/bundle/neoformat/autoload/neoformat/formatters/objc.vim new file mode 100644 index 000000000..2075abdce --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/objc.vim @@ -0,0 +1,20 @@ +function! neoformat#formatters#objc#enabled() abort + return ['uncrustify', 'clangformat', 'astyle'] +endfunction + +function! neoformat#formatters#objc#uncrustify() abort + return { + \ 'exe': 'uncrustify', + \ 'args': ['-q', '-l OC+'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#objc#clangformat() abort + return neoformat#formatters#c#clangformat() +endfunction + +function! neoformat#formatters#objc#astyle() abort + return neoformat#formatters#c#astyle() +endfunction + diff --git a/bundle/neoformat/autoload/neoformat/formatters/ocaml.vim b/bundle/neoformat/autoload/neoformat/formatters/ocaml.vim new file mode 100644 index 000000000..1a5281ad5 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/ocaml.vim @@ -0,0 +1,18 @@ +function! neoformat#formatters#ocaml#enabled() abort + return ['ocamlformat', 'ocpindent'] +endfunction + +function! neoformat#formatters#ocaml#ocpindent() abort + return { + \ 'exe': 'ocp-indent', + \ } +endfunction + +function! neoformat#formatters#ocaml#ocamlformat() abort + return { + \ 'exe': 'ocamlformat', + \ 'no_append': 1, + \ 'stdin': 1, + \ 'args': ['--name', '"%:p"', '-'] + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/pandoc.vim b/bundle/neoformat/autoload/neoformat/formatters/pandoc.vim new file mode 100644 index 000000000..deab6b763 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/pandoc.vim @@ -0,0 +1,40 @@ +function! neoformat#formatters#pandoc#enabled() abort + return ['pandoc'] +endfunction + +function! neoformat#formatters#pandoc#pandoc() abort + let l:input_flags = ['markdown', + \ '+abbreviations', + \ '+autolink_bare_uris', + \ '+markdown_attribute', + \ '+mmd_header_identifiers', + \ '+mmd_link_attributes', + \ '+tex_math_double_backslash', + \ '+emoji', + \ '+task_lists', + \ ] + + let l:target_flags = ['markdown', + \ '+raw_tex', + \ '-native_spans', + \ '-simple_tables', + \ '-multiline_tables', + \ '-fenced_code_attributes', + \ '+emoji', + \ '+task_lists', + \ ] + + return { + \ 'exe': 'pandoc', + \ 'args': [ + \ '-f' , + \ join(l:input_flags, ''), + \ '-t', + \ join(l:target_flags, ''), + \ '-s', + \ '--wrap=auto', + \ '--atx-headers', + \], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/pawn.vim b/bundle/neoformat/autoload/neoformat/formatters/pawn.vim new file mode 100644 index 000000000..051a8235a --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/pawn.vim @@ -0,0 +1,12 @@ +function! neoformat#formatters#pawn#enabled() abort + return ['uncrustify'] +endfunction + +function! neoformat#formatters#pawn#uncrustify() abort + return { + \ 'exe': 'uncrustify', + \ 'args': ['-q', '-l PAWN'], + \ 'stdin': 1, + \ } +endfunction + diff --git a/bundle/neoformat/autoload/neoformat/formatters/perl.vim b/bundle/neoformat/autoload/neoformat/formatters/perl.vim new file mode 100644 index 000000000..953bfebe3 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/perl.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#perl#enabled() abort + return ['perltidy'] +endfunction + +function! neoformat#formatters#perl#perltidy() abort + return { + \ 'exe': 'perltidy', + \ 'args': ['-q'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/php.vim b/bundle/neoformat/autoload/neoformat/formatters/php.vim new file mode 100644 index 000000000..ea9d4851c --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/php.vim @@ -0,0 +1,24 @@ +function! neoformat#formatters#php#enabled() abort + return ['phpbeautifier', 'phpcsfixer', 'phpcbf'] +endfunction + +function! neoformat#formatters#php#phpbeautifier() abort + return { + \ 'exe': 'php_beautifier', + \ } +endfunction + +function! neoformat#formatters#php#phpcsfixer() abort + return { + \ 'exe': 'php-cs-fixer', + \ 'args': ['fix', '-q'], + \ } +endfunction + +function! neoformat#formatters#php#phpcbf() abort + return { + \ 'exe': 'phpcbf', + \ 'stdin': 1, + \ 'valid_exit_codes': [0,1], + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/proto.vim b/bundle/neoformat/autoload/neoformat/formatters/proto.vim new file mode 100644 index 000000000..033906688 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/proto.vim @@ -0,0 +1,7 @@ +function! neoformat#formatters#proto#enabled() abort + return ['clangformat'] +endfunction + +function! neoformat#formatters#proto#clangformat() abort + return neoformat#formatters#c#clangformat() +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/pug.vim b/bundle/neoformat/autoload/neoformat/formatters/pug.vim new file mode 100644 index 000000000..1bfebd0b9 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/pug.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#pug#enabled() abort + return ['pugbeautifier'] +endfunction + +function! neoformat#formatters#pug#pugbeautifier() abort + return { + \ 'exe': 'pug-beautifier', + \ 'args': ['-s 2'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/purescript.vim b/bundle/neoformat/autoload/neoformat/formatters/purescript.vim new file mode 100644 index 000000000..1e02199e1 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/purescript.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#purescript#enabled() abort + return ['purty'] +endfunction + +function! neoformat#formatters#purescript#purty() abort + return { + \ 'exe': 'purty', + \ 'args': ['-'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/python.vim b/bundle/neoformat/autoload/neoformat/formatters/python.vim new file mode 100644 index 000000000..6934954f5 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/python.vim @@ -0,0 +1,69 @@ +function! neoformat#formatters#python#enabled() abort + return ['yapf', 'autopep8', 'black', 'isort', 'docformatter', 'pyment', 'pydevf', 'autoflake'] +endfunction + +function! neoformat#formatters#python#yapf() abort + return { + \ 'exe': 'yapf', + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#python#autopep8() abort + return { + \ 'exe': 'autopep8', + \ 'args': ['-'], + \ 'stdin': 1, + \ } +endfunction + + +function! neoformat#formatters#python#isort() abort + return { + \ 'exe': 'isort', + \ 'args': ['-', '--quiet',], + \ 'stdin': 1, + \ } +endfunction + + +function! neoformat#formatters#python#docformatter() abort + return { + \ 'exe': 'docformatter', + \ 'args': ['-',], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#python#autoflake() abort + return { + \ 'exe': 'autoflake', + \ 'args': ['--remove-all-unused-imports', '--in-place', '--remove-duplicate-keys', '--expand-star-imports'], + \ 'stdin': 0, + \ } +endfunction + +function! neoformat#formatters#python#black() abort + return { + \ 'exe': 'black', + \ 'stdin': 1, + \ 'args': ['-q', '-'], + \ } +endfunction + + +function! neoformat#formatters#python#pyment() abort + return { + \ 'exe': 'pyment', + \ 'stdin': 1, + \ 'args': ['-w', '-'], + \ } +endfunction + +function! neoformat#formatters#python#pydevf() abort + return { + \ 'exe': 'pydevf', + \ 'replace': 1, + \ 'args': ['-', '2>/dev/null'], + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/r.vim b/bundle/neoformat/autoload/neoformat/formatters/r.vim new file mode 100644 index 000000000..45d767e97 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/r.vim @@ -0,0 +1,19 @@ +function! neoformat#formatters#r#enabled() abort + return ['styler', 'formatR'] +endfunction + +function! neoformat#formatters#r#styler() abort + return { + \ 'exe': 'R', + \ 'args': ['--slave', '--no-restore', '--no-save', '-e "styler::style_text(readr::read_file((file(\"stdin\"))))"', '2>/dev/null'], + \ 'replace': 1, + \} +endfunction + +function! neoformat#formatters#r#formatR() abort + return { + \ 'exe': 'R', + \ 'args': ['--slave', '--no-restore', '--no-save', '-e "formatR::tidy_source(\"stdin\", arrow=FALSE)"', '2>/dev/null'], + \ 'stdin': 1, + \} +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/reason.vim b/bundle/neoformat/autoload/neoformat/formatters/reason.vim new file mode 100644 index 000000000..e6201adf6 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/reason.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#reason#enabled() abort + return ['refmt'] +endfunction + +function! neoformat#formatters#reason#refmt() abort + return { + \ 'exe': 'refmt', + \ 'stdin': 1, + \ 'args': ["--interface=" . (expand('%:e') == "rei" ? "true" : "false")], + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/ruby.vim b/bundle/neoformat/autoload/neoformat/formatters/ruby.vim new file mode 100644 index 000000000..f3cc808ea --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/ruby.vim @@ -0,0 +1,27 @@ +function! neoformat#formatters#ruby#enabled() abort + return ['rufo', 'rubybeautify', 'rubocop'] +endfunction + +function! neoformat#formatters#ruby#rufo() abort + return { + \ 'exe': 'rufo', + \ 'stdin': 1, + \ 'valid_exit_codes': [0, 3] + \ } +endfunction + +function! neoformat#formatters#ruby#rubybeautify() abort + return { + \ 'exe': 'ruby-beautify', + \ 'args': ['--spaces', '-c ' . shiftwidth()], + \ } +endfunction + +function! neoformat#formatters#ruby#rubocop() abort + return { + \ 'exe': 'rubocop', + \ 'args': ['--auto-correct', '--stdin', '"%:p"', '2>/dev/null', '|', 'sed "1,/^====================$/d"'], + \ 'stdin': 1, + \ 'stderr': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/rust.vim b/bundle/neoformat/autoload/neoformat/formatters/rust.vim new file mode 100644 index 000000000..762542319 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/rust.vim @@ -0,0 +1,10 @@ +function! neoformat#formatters#rust#enabled() abort + return ['rustfmt'] +endfunction + +function! neoformat#formatters#rust#rustfmt() abort + return { + \ 'exe': 'rustfmt', + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/sass.vim b/bundle/neoformat/autoload/neoformat/formatters/sass.vim new file mode 100644 index 000000000..339728239 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/sass.vim @@ -0,0 +1,19 @@ +function! neoformat#formatters#sass#enabled() abort + return ['sassconvert', 'stylelint', 'csscomb'] +endfunction + +function! neoformat#formatters#sass#sassconvert() abort + return { + \ 'exe': 'sass-convert', + \ 'args': ['-F sass', '-T sass', '-s'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#sass#csscomb() abort + return neoformat#formatters#css#csscomb() +endfunction + +function! neoformat#formatters#sass#stylelint() abort + return neoformat#formatters#css#stylelint() +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/sbt.vim b/bundle/neoformat/autoload/neoformat/formatters/sbt.vim new file mode 100644 index 000000000..d7c34bd43 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/sbt.vim @@ -0,0 +1,14 @@ +function! neoformat#formatters#sbt#enabled() abort + return ['scalafmt'] +endfunction + +" To understand sbt files on stdin, scalafmt needs to assume any old filename +" that ends in .sbt. Using a dummy filename instead of the actual one is +" required to support buffers of sbt filetype without the extension. +function! neoformat#formatters#sbt#scalafmt() abort + return { + \ 'exe': 'scalafmt', + \ 'args': ['--stdin', '--assume-filename', 'foo.sbt'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/scala.vim b/bundle/neoformat/autoload/neoformat/formatters/scala.vim new file mode 100644 index 000000000..d547d8227 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/scala.vim @@ -0,0 +1,19 @@ +function! neoformat#formatters#scala#enabled() abort + return ['scalariform', 'scalafmt'] +endfunction + +function! neoformat#formatters#scala#scalariform() abort + return { + \ 'exe': 'scalariform', + \ 'args': ['--stdin'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#scala#scalafmt() abort + return { + \ 'exe': 'scalafmt', + \ 'args': ['--stdin'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/scss.vim b/bundle/neoformat/autoload/neoformat/formatters/scss.vim new file mode 100644 index 000000000..201af293e --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/scss.vim @@ -0,0 +1,31 @@ +function! neoformat#formatters#scss#enabled() abort + return ['sassconvert', 'stylelint', 'stylefmt', 'prettier', 'prettydiff', 'csscomb'] +endfunction + +function! neoformat#formatters#scss#sassconvert() abort + return { + \ 'exe': 'sass-convert', + \ 'args': ['-F scss', '-T scss', '--indent ' . (&expandtab ? shiftwidth() : 't')], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#scss#csscomb() abort + return neoformat#formatters#css#csscomb() +endfunction + +function! neoformat#formatters#scss#prettydiff() abort + return neoformat#formatters#css#prettydiff() +endfunction + +function! neoformat#formatters#scss#stylefmt() abort + return neoformat#formatters#css#stylefmt() +endfunction + +function! neoformat#formatters#scss#prettier() abort + return neoformat#formatters#css#prettier() +endfunction + +function! neoformat#formatters#scss#stylelint() abort + return neoformat#formatters#css#stylelint() +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/sh.vim b/bundle/neoformat/autoload/neoformat/formatters/sh.vim new file mode 100644 index 000000000..08c9a21e2 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/sh.vim @@ -0,0 +1,13 @@ +function! neoformat#formatters#sh#enabled() abort + return ['shfmt'] +endfunction + +function! neoformat#formatters#sh#shfmt() abort + let opts = get(g:, 'shfmt_opt', '') + + return { + \ 'exe': 'shfmt', + \ 'args': ['-i ' . shiftwidth(), opts], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/sql.vim b/bundle/neoformat/autoload/neoformat/formatters/sql.vim new file mode 100644 index 000000000..2218f45d9 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/sql.vim @@ -0,0 +1,27 @@ +function! neoformat#formatters#sql#enabled() abort + return ['sqlformat', 'pg_format', 'sqlfmt'] +endfunction + +function! neoformat#formatters#sql#sqlformat() abort + return { + \ 'exe': 'sqlformat', + \ 'args': ['--reindent', '-'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#sql#pg_format() abort + return { + \ 'exe': 'pg_format', + \ 'args': ['-'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#sql#sqlfmt() abort + return { + \ 'exe': 'sqlfmt', + \ 'args': [], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/starlark.vim b/bundle/neoformat/autoload/neoformat/formatters/starlark.vim new file mode 100644 index 000000000..97b7e9cff --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/starlark.vim @@ -0,0 +1,10 @@ +function! neoformat#formatters#starlark#enabled() abort + return ['buildifier'] +endfunction + +function! neoformat#formatters#starlark#buildifier() abort + return { + \ 'exe': 'buildifier', + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/svelte.vim b/bundle/neoformat/autoload/neoformat/formatters/svelte.vim new file mode 100644 index 000000000..5803ad500 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/svelte.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#svelte#enabled() abort + return ['prettier'] +endfunction + +function! neoformat#formatters#svelte#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '--parser=svelte', '--plugin-search-dir=.', '"%:p"'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/swift.vim b/bundle/neoformat/autoload/neoformat/formatters/swift.vim new file mode 100644 index 000000000..e2a49f831 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/swift.vim @@ -0,0 +1,10 @@ +function! neoformat#formatters#swift#enabled() abort + return ['swiftformat'] +endfunction + +function! neoformat#formatters#swift#swiftformat() abort + return { + \ 'exe': 'swiftformat', + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/terraform.vim b/bundle/neoformat/autoload/neoformat/formatters/terraform.vim new file mode 100644 index 000000000..7ee6a7303 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/terraform.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#terraform#enabled() abort + return ['terraform'] +endfunction + +function! neoformat#formatters#terraform#terraform() abort + return { + \ 'exe': 'terraform', + \ 'args': ['fmt', '-write', '-'], + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/tex.vim b/bundle/neoformat/autoload/neoformat/formatters/tex.vim new file mode 100644 index 000000000..37e5a3687 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/tex.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#tex#enabled() abort + return ['latexindent'] +endfunction + +function! neoformat#formatters#tex#latexindent() abort + return { + \ 'exe': 'latexindent', + \ 'args': ['-sl', '-g /dev/stderr', '2>/dev/null'], + \ 'stdin': 1, + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/typescript.vim b/bundle/neoformat/autoload/neoformat/formatters/typescript.vim new file mode 100644 index 000000000..10556da57 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/typescript.vim @@ -0,0 +1,49 @@ +function! neoformat#formatters#typescript#enabled() abort + return ['tsfmt', 'prettier', 'tslint', 'eslint_d', 'clangformat'] +endfunction + +function! neoformat#formatters#typescript#tsfmt() abort + return { + \ 'exe': 'tsfmt', + \ 'args': ['--replace', '--baseDir=%:h'], + \ 'replace': 1 + \ } +endfunction + +function! neoformat#formatters#typescript#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"', '--parser', 'typescript'], + \ 'stdin': 1 + \ } +endfunction + +function! neoformat#formatters#typescript#tslint() abort + let args = ['--fix', '--force'] + + if filereadable('tslint.json') + let args = ['-c tslint.json'] + args + endif + + return { + \ 'exe': 'tslint', + \ 'args': args, + \ 'replace': 1 + \ } +endfunction + +function! neoformat#formatters#typescript#eslint_d() abort + return { + \ 'exe': 'eslint_d', + \ 'args': ['--stdin', '--stdin-filename', '"%:p"', '--fix-to-stdout'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#typescript#clangformat() abort + return { + \ 'exe': 'clang-format', + \ 'args': ['-assume-filename=' . expand('%:t')], + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/vala.vim b/bundle/neoformat/autoload/neoformat/formatters/vala.vim new file mode 100644 index 000000000..dfb7e8556 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/vala.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#vala#uncrustify() abort + return { + \ 'exe': 'uncrustify', + \ 'args': ['-q', '-l VALA'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#vala#enabled() abort + return ['uncrustify'] +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/vue.vim b/bundle/neoformat/autoload/neoformat/formatters/vue.vim new file mode 100644 index 000000000..4bec11247 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/vue.vim @@ -0,0 +1,11 @@ +function! neoformat#formatters#vue#enabled() abort + return ['prettier'] +endfunction + +function! neoformat#formatters#vue#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"', '--parser', 'vue'], + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/xhtml.vim b/bundle/neoformat/autoload/neoformat/formatters/xhtml.vim new file mode 100644 index 000000000..885e88425 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/xhtml.vim @@ -0,0 +1,21 @@ +function! neoformat#formatters#xhtml#enabled() abort + return ['tidy', 'prettydiff'] +endfunction + +function! neoformat#formatters#xhtml#tidy() abort + return { + \ 'exe': 'tidy', + \ 'args': ['-quiet', + \ '-asxhtml', + \ '--indent auto', + \ '--indent-spaces '. shiftwidth(), + \ '--vertical-space yes', + \ '--tidy-mark no' + \ ], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#xhtml#prettydiff() abort + return neoformat#formatters#html#prettydiff() +endfunction diff --git a/bundle/neoformat/autoload/neoformat/formatters/xml.vim b/bundle/neoformat/autoload/neoformat/formatters/xml.vim new file mode 100644 index 000000000..13061cb5d --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/xml.vim @@ -0,0 +1,31 @@ +function! neoformat#formatters#xml#enabled() abort + return ['tidy', 'prettydiff', 'prettier'] +endfunction + +function! neoformat#formatters#xml#tidy() abort + return { + \ 'exe': 'tidy', + \ 'args': ['-quiet', + \ '-xml', + \ '--indent auto', + \ '--indent-spaces ' . shiftwidth(), + \ '--vertical-space yes', + \ '--tidy-mark no' + \ ], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#xml#prettydiff() abort + return neoformat#formatters#html#prettydiff() +endfunction + +function! neoformat#formatters#xml#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"'], + \ 'stdin': 1, + \ } +endfunction + + diff --git a/bundle/neoformat/autoload/neoformat/formatters/yaml.vim b/bundle/neoformat/autoload/neoformat/formatters/yaml.vim new file mode 100644 index 000000000..54a407f11 --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/formatters/yaml.vim @@ -0,0 +1,19 @@ +function! neoformat#formatters#yaml#enabled() abort + return ['pyaml', 'prettier'] +endfunction + +function! neoformat#formatters#yaml#pyaml() abort + return { + \ 'exe': 'python3', + \ 'args': ['-m', 'pyaml'], + \ 'stdin': 1, + \ } +endfunction + +function! neoformat#formatters#yaml#prettier() abort + return { + \ 'exe': 'prettier', + \ 'args': ['--stdin', '--stdin-filepath', '"%:p"', '--parser', 'yaml'], + \ 'stdin': 1 + \ } +endfunction diff --git a/bundle/neoformat/autoload/neoformat/utils.vim b/bundle/neoformat/autoload/neoformat/utils.vim new file mode 100644 index 000000000..06fe933fe --- /dev/null +++ b/bundle/neoformat/autoload/neoformat/utils.vim @@ -0,0 +1,49 @@ +function! neoformat#utils#log(msg) abort + if neoformat#utils#should_be_verbose() + return s:better_echo(a:msg) + endif +endfunction + +function! neoformat#utils#log_file_content(path) abort + if neoformat#utils#should_be_verbose() + return s:better_echo(readfile(a:path)) + endif +endfunction + +function! neoformat#utils#warn(msg) abort + echohl WarningMsg | call s:better_echo(a:msg) | echohl NONE +endfunction + +function! neoformat#utils#msg(msg) abort + if exists('g:neoformat_only_msg_on_error') && g:neoformat_only_msg_on_error + return + endif + return s:better_echo(a:msg) +endfunction + +function! neoformat#utils#should_be_verbose() abort + if !exists('g:neoformat_verbose') + let g:neoformat_verbose = 0 + endif + return &verbose || g:neoformat_verbose +endfunction + +function! s:better_echo(msg) abort + if type(a:msg) != type('') + echom 'Neoformat: ' . string(a:msg) + else + echom 'Neoformat: ' . a:msg + endif +endfunction + +function! neoformat#utils#var(name) abort + return neoformat#utils#var_default(a:name, 0) +endfunction + +function! neoformat#utils#var_default(name, default) abort + if exists('b:' . a:name) + return get(b:, a:name) + endif + + return get(g:, a:name, a:default) +endfunction diff --git a/bundle/neoformat/doc/neoformat.txt b/bundle/neoformat/doc/neoformat.txt new file mode 100644 index 000000000..5cb67cc4b --- /dev/null +++ b/bundle/neoformat/doc/neoformat.txt @@ -0,0 +1,404 @@ +*neoformat.txt* A Neovim plugin for formatting. + +CONTENTS *neoformat-contents* + +Introduction |neoformat-introduction| +Install |neoformat-install| +Usage |neoformat-usage| +Managing Undo History |neoformat-managing-undo-history| +Supported Filetypes |neoformat-supported-filetypes| + +============================================================================== +INTRODUCTION *neoformat-introduction* + +A [Neovim](https://neovim.io) and Vim8 plugin for formatting code. + +*Neoformat* uses a variety of formatters for many filetypes. Currently, Neoformat +will run a formatter using the current buffer data, and on success it will +update the current buffer with the formatted text. On a formatter failure, +Neoformat will try the next formatter defined for the filetype. + +By using `getbufline()` to read from the current buffer instead of file, +Neoformat is able to format your buffer without you having to `:w` your file first. +Also, by using `setline()`, marks, jumps, etc. are all maintained after formatting. + +Neoformat supports both sending buffer data to formatters via stdin, and also +writing buffer data to `/tmp/` for formatters to read that do not support input +via stdin. + +============================================================================== +INSTALL *neoformat-install* + +Install with [vim-plug](https://github.com/junegunn/vim-plug) +> + Plug 'sbdchd/neoformat' +< +============================================================================== +USAGE *neoformat-usage* + +Format the entire buffer, or visual selection of the buffer +> + :Neoformat + + + :Neoformat jsbeautify + +Or format a visual selection of code in a different filetype + +*Note:* you must use a ! and pass the filetype of the selection + +> + :Neoformat! python +> +You can also pass a formatter to use + +> + :Neoformat! python yapf +< + +Or perhaps run a formatter on save + +> + augroup fmt + autocmd! + autocmd BufWritePre * undojoin | Neoformat + augroup END +< + +The |undojoin| command will put changes made by Neoformat into the same +|undo-block| with the latest preceding change. See +|neoformat-managing-undo-history|. + + +============================================================================== +CURRENT LIMITATION(S) *neoformat-limitations* + +If a formatter is either not configured to use `stdin`, or is not able to read +from `stdin`, then buffer data will be written to a file in `/tmp/neoformat/`, +where the formatter will then read from + +============================================================================== +CONFIG *neoformat-config* + +Define custom formatters. + +Options: + +| `exe` | the name the formatter executable in the path | required +| `args` | list of arguments | default: [] | optional +| `replace` | overwrite the file, instead of updating the buffer | default: 0 | optional +| `stdin` | send data to the stdin of the formatter | default 0 | optional +| `stderr` | used to specify whether stderr output should be read along with + the stdin, otherwise redirects stderr to `stderr.log` file in neoformat's + temporary directory | default 0 | optional +| `no_append` | do not append the `path` of the file to the formatter command, + used when the `path` is in the middle of a command | default: 0 | + optional +| `env` | list of environment variables to prepend to the command | default: [] | optional + +| `valid_exit_codes` | list of valid exit codes for formatters who do not respect common unix practices | \[0] | optional + +Example: + +Define custom formatters. +> + let g:neoformat_python_autopep8 = { + \ 'exe': 'autopep8', + \ 'args': ['-s 4', '-E'], + \ 'replace': 1 " replace the file, instead of updating buffer (default: 0), + \ 'stdin': 1, " send data to stdin of formatter (default: 0) + \ 'valid_exit_codes': [0, 23], + \ 'no_append': 1, + \ } + + let g:neoformat_enabled_python = ['autopep8'] +< +Have Neoformat use &formatprg as a formatter +> + let g:neoformat_try_formatprg = 1 +< +Enable basic formatting when a filetype is not found. Disabled by default. +> + " Enable alignment globally + let g:neoformat_basic_format_align = 1 + + " Enable tab to spaces conversion globally + let g:neoformat_basic_format_retab = 1 + + " Enable trimmming of trailing whitespace globally + let g:neoformat_basic_format_trim = 1 + +Run all enabled formatters (by default Neoformat stops after the first +formatter succeeds) + + let g:neoformat_run_all_formatters = 1 + +Above options can be activated or deactivated per buffer. For example: + + " runs all formatters for current buffer without tab to spaces conversion + let b:neoformat_run_all_formatters = 1 + let b:neoformat_basic_format_retab = 0 + +Have Neoformat only msg when there is an error +> + let g:neoformat_only_msg_on_error = 1 +< +When debugging, you can enable either of following variables for extra logging. +> + let g:neoformat_verbose = 1 " only affects the verbosity of Neoformat + " Or + let &verbose = 1 " also increases verbosity of the editor as a whole +< +============================================================================== +ADDING A NEW FORMATTER *neoformat-adding-new-formatter* + +Note: you should replace everything `{{ }}` accordingly + +1. Create a file in `autoload/neoformat/formatters/{{ filetype }}.vim` if it does not + already exist for your filetype. + +2. Follow the following format + +See Config above for options +> + function! neoformat#formatters#{{ filetype }}#enabled() abort + return ['{{ formatter name }}', '{{ other formatter name for filetype }}'] + endfunction + + function! neoformat#formatters#{{ filetype }}#{{ formatter name }}() abort + return { + \ 'exe': '{{ formatter name }}', + \ 'args': ['-s 4', '-q'], + \ 'stdin': 1 + \ } + endfunction + + function! neoformat#formatters#{{ filetype }}#{{ other formatter name }}() abort + return {'exe': {{ other formatter name }} + endfunction +< + +============================================================================== +MANAGING UNDO HISTORY *neoformat-managing-undo-history* + +If you use an |autocmd| to run Neoformat on save, and you have your editor +configured to save automatically on |CursorHold| then you might run into +problems reverting changes. Pressing |u| will undo the last change made by +Neoformat instead of the change that you made yourself - and then Neoformat +will run again redoing the change that you just reverted. To avoid this +problem you can run Neoformat with the Vim |undojoin| command to put changes +made by Neoformat into the same |undo-block| with the preceding change. For +example: + +> + augroup fmt + autocmd! + autocmd BufWritePre * undojoin | Neoformat + augroup END +< + +When |undojoin| is used this way pressing |u| will "skip over" the Neoformat +changes - it will revert both the changes made by Neoformat and the change +that caused Neoformat to be invoked. + +============================================================================== +SUPPORTED FILETYPES *neoformat-supported-filetypes* + +- Arduino + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`astyle`](http://astyle.sourceforge.net) +- Assembly + - [`asmfmt`](https://github.com/klauspost/asmfmt) +- Bazel + - [`buildifier`](https://github.com/bazelbuild/buildtools/blob/master/buildifier/README.md) +- C + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`astyle`](http://astyle.sourceforge.net) +- C# + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`astyle`](http://astyle.sourceforge.net) +- C++ + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`astyle`](http://astyle.sourceforge.net) +- CMake + - [`cmake_format`](https://github.com/cheshirekow/cmake_format) +- Crystal + - `crystal tool format` (ships with [`crystal`](http://crystal-lang.org)) +- CSS + - `css-beautify` (ships with [`js-beautify`](https://github.com/beautify-web/js-beautify)), + [`prettier`](https://github.com/prettier/prettier), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`stylefmt`](https://github.com/morishitter/stylefmt), + [`stylelint`](https://stylelint.io/), + [`csscomb`](http://csscomb.com) +- CSV + - [`prettydiff`](https://github.com/prettydiff/prettydiff) +- D + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`dfmt`](https://github.com/Hackerpilot/dfmt) +- Dart + - [`dartfmt`](https://www.dartlang.org/tools/) +- Dhall + - [`dhall format`](https://dhall-lang.org) +- dune + - [`dune format`](https://github.com/ocaml/dune) +- Elixir + - [mix format](https://hexdocs.pm/mix/master/Mix.Tasks.Format.html) +- Elm + - [`elm-format`](https://github.com/avh4/elm-format) +- Fish + - [`fish_indent`](http://fishshell.com) +- Go + - [`gofmt`](https://golang.org/cmd/gofmt/), + [`goimports`](https://godoc.org/golang.org/x/tools/cmd/goimports) +- GLSL + - [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html) +- GraphQL + - [`prettier`](https://github.com/prettier/prettier) +- Haskell + - [`stylish-haskell`](https://github.com/jaspervdj/stylish-haskell) + - [`hindent`](https://github.com/chrisdone/hindent) + - [`hfmt`](https://github.com/danstiner/hfmt) + - [`brittany`](https://github.com/lspitzner/brittany) + - [`sort-imports`](https://github.com/evanrelf/sort-imports) + - [`floskell`](https://github.com/ennocramer/floskell) + - [`ormolu`](https://github.com/tweag/ormolu) + `let g:ormolu_ghc_opt=["TypeApplications", "RankNTypes"]` +- PureScript + - [`purty`](https://gitlab.com/joneshf/purty) +- HTML + - `html-beautify` (ships with [`js-beautify`](https://github.com/beautify-web/js-beautify)), + [`prettier`](https://github.com/jlongster/prettier), + [`prettydiff`](https://github.com/prettydiff/prettydiff) +- Jade + - [`pug-beautifier`](https://github.com/vingorius/pug-beautifier) +- Java + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`astyle`](http://astyle.sourceforge.net) +- JavaScript + - [`js-beautify`](https://github.com/beautify-web/js-beautify), + [`prettier`](https://github.com/jlongster/prettier), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`esformatter`](https://github.com/millermedeiros/esformatter/), + [`prettier-eslint`](https://github.com/kentcdodds/prettier-eslint-cli), + [`standard`](https://standardjs.com/) +- JSON + - [`js-beautify`](https://github.com/beautify-web/js-beautify), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`prettier`](https://github.com/prettier/prettier), + [`jq`](https://stedolan.github.io/jq/), + [`fixjson`](https://github.com/rhysd/fixjson) +- Kotlin + - [`ktlint`](https://github.com/shyiko/ktlint) +- LaTeX + - [`latexindent`](https://github.com/cmhughes/latexindent.pl) +- Less + - [`csscomb`](http://csscomb.com), + [`prettier`](https://github.com/prettier/prettier), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`stylelint`](https://stylelint.io/) +- Lua + - [`luaformatter`](https://github.com/LuaDevelopmentTools/luaformatter) +- Markdown + - [`remark`](https://github.com/wooorm/remark) + [`prettier`](https://github.com/prettier/prettier), +- Matlab + - [`matlab-formatter-vscode`](https://github.com/affenwiesel/matlab-formatter-vscode) +- Nim + - nimpretty (ships with [nim](https://nim-lang.org/)), +- Nix + - [`nixfmt`](https://github.com/serokell/nixfmt) +- Objective-C + - [`uncrustify`](http://uncrustify.sourceforge.net), + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), + [`astyle`](http://astyle.sourceforge.net) +- OCaml + - [`ocp-indent`](http://www.typerex.org/ocp-indent.html) + - [`ocamlformat`](https://github.com/ocaml-ppx/ocamlformat) +- Pandoc Markdown + - [`pandoc`](https://pandoc.org/MANUAL.html) +- Pawn + - [`uncrustify`](http://uncrustify.sourceforge.net) +- Perl + - [`perltidy`](http://perltidy.sourceforge.net) +- PHP + - [`php_beautifier`](http://pear.php.net/package/PHP_Beautifier) + - [`php-cs-fixer`](http://cs.sensiolabs.org/) + - [`phpcbf`](https://github.com/squizlabs/PHP_CodeSniffer) +- Proto + - [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html) +- Pug (formally Jade) + - [`pug-beautifier`](https://github.com/vingorius/pug-beautifier) +- Python + - [`yapf`](https://github.com/google/yapf), + [`autopep8`](https://github.com/hhatto/autopep8), + [`pydevf`](https://github.com/fabioz/PyDev.Formatter), + [`pyment`](https://github.com/dadadel/pyment) + [autoflake](https://github.com/myint/autoflake) +- R + - [`styler`](https://github.com/r-lib/styler), + [`formatR`](https://github.com/yihui/formatR) + - [`refmt`](https://github.com/facebook/reason) +- Ruby + - [`rufo`](https://github.com/asterite/rufo) + - [`ruby-beautify`](https://github.com/erniebrodeur/ruby-beautify) + - [`rubocop`](https://github.com/bbatsov/rubocop) +- Rust + - [`rustfmt`](https://github.com/rust-lang-nursery/rustfmt) +- Sass + - [`sass-convert`](http://sass-lang.com/documentation/#executables), + [`stylelint`](https://stylelint.io/), + [`csscomb`](http://csscomb.com) +- Sbt + - [`scalafmt`](http://scalameta.org/scalafmt/) +- Scala + - [`scalariform`](https://github.com/scala-ide/scalariform), + [`scalafmt`](http://scalameta.org/scalafmt/) +- SCSS + - [`sass-convert`](http://sass-lang.com/documentation/#executables), + [`stylefmt`](https://github.com/morishitter/stylefmt), + [`stylelint`](https://stylelint.io/) + [`prettier`](https://github.com/prettier/prettier), + [`prettydiff`](https://github.com/prettydiff/prettydiff), + [`csscomb`](http://csscomb.com) +- Shell + - [`shfmt`](https://github.com/mvdan/sh) +- SQL + - [`sqlfmt`](https://github.com/jackc/sqlfmt) + - `sqlformat` (ships with [`sqlparse`](https://github.com/andialbrecht/sqlparse)) + - `pg_format` (ships with [`pgFormatter`](https://github.com/darold/pgFormatter)) +- Starlark + - [`buildifier`](https://github.com/bazelbuild/buildtools/blob/master/buildifier/README.md) +- Svelte + - [`prettier-plugin-svelte`](https://github.com/UnwrittenFun/prettier-plugin-svelte) +- Swift + - [`Swiftformat`](https://github.com/nicklockwood/SwiftFormat) +- Terraform + - [`terraform`](https://www.terraform.io/docs/commands/fmt.html) +- TypeScript + - [`tsfmt`](https://github.com/vvakame/typescript-formatter), + [`prettier`](https://github.com/prettier/prettier), + [`tslint`](https://palantir.github.io/tslint) + [`eslint_d`](https://github.com/mantoni/eslint_d.js) + [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html), +- VALA + - [`uncrustify`](http://uncrustify.sourceforge.net) +- Vue + - [`prettier`](https://github.com/prettier/prettier) +- XHTML + - [`tidy`](http://www.html-tidy.org), + [`prettydiff`](https://github.com/prettydiff/prettydiff) +- XML + - [`tidy`](http://www.html-tidy.org), + [`prettydiff`](https://github.com/prettydiff/prettydiff) +- YAML + - [`pyaml`](https://pypi.python.org/pypi/pyaml), + [`prettier`](https://github.com/prettier/prettier) + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: diff --git a/bundle/neoformat/plugin/neoformat.vim b/bundle/neoformat/plugin/neoformat.vim new file mode 100644 index 000000000..a2baae691 --- /dev/null +++ b/bundle/neoformat/plugin/neoformat.vim @@ -0,0 +1,2 @@ +command! -nargs=? -bar -range=% -bang -complete=customlist,neoformat#CompleteFormatters Neoformat + \ call neoformat#Neoformat(0, , , ) diff --git a/bundle/neoformat/test/.gitignore b/bundle/neoformat/test/.gitignore new file mode 100644 index 000000000..f7275bbbd --- /dev/null +++ b/bundle/neoformat/test/.gitignore @@ -0,0 +1 @@ +venv/ diff --git a/bundle/neoformat/test/README.md b/bundle/neoformat/test/README.md new file mode 100644 index 000000000..7d95db760 --- /dev/null +++ b/bundle/neoformat/test/README.md @@ -0,0 +1,14 @@ +# Neoformat Tests + +Running tests + +```bash +# inside test/ + +./install.sh + +python3 -m virtualenv venv +pip install -r requirements.txt + +pytest -v test.py +``` diff --git a/bundle/neoformat/test/after/cp.cp b/bundle/neoformat/test/after/cp.cp new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/neoformat/test/after/cssbeautify-indent-6.css b/bundle/neoformat/test/after/cssbeautify-indent-6.css new file mode 100644 index 000000000..42170fe06 --- /dev/null +++ b/bundle/neoformat/test/after/cssbeautify-indent-6.css @@ -0,0 +1,3 @@ +.body { + color: red; +} diff --git a/bundle/neoformat/test/after/cssbeautify.css b/bundle/neoformat/test/after/cssbeautify.css new file mode 100644 index 000000000..b4197b16a --- /dev/null +++ b/bundle/neoformat/test/after/cssbeautify.css @@ -0,0 +1,3 @@ +.body { + color: red; +} diff --git a/bundle/neoformat/test/after/csscomb.css b/bundle/neoformat/test/after/csscomb.css new file mode 100644 index 000000000..f1d0ccbda --- /dev/null +++ b/bundle/neoformat/test/after/csscomb.css @@ -0,0 +1,4 @@ +.body +{ + color: red; +} diff --git a/bundle/neoformat/test/after/prettydiff.css b/bundle/neoformat/test/after/prettydiff.css new file mode 100644 index 000000000..f44498d32 --- /dev/null +++ b/bundle/neoformat/test/after/prettydiff.css @@ -0,0 +1,4 @@ +.body { + color: red; +} + diff --git a/bundle/neoformat/test/after/tsfmt.ts b/bundle/neoformat/test/after/tsfmt.ts new file mode 100644 index 000000000..fe71c9b82 --- /dev/null +++ b/bundle/neoformat/test/after/tsfmt.ts @@ -0,0 +1,13 @@ +module Geometry { + export class Square { + constructor(public sideLength: number = 0) { + } + area() { + return Math.pow(this.sideLength, 2); + } + } +} + +class Tuple { + constructor(public item1: T1, public item2: T2) { } +} diff --git a/bundle/neoformat/test/after/yapf.py b/bundle/neoformat/test/after/yapf.py new file mode 100644 index 000000000..336e825c8 --- /dev/null +++ b/bundle/neoformat/test/after/yapf.py @@ -0,0 +1,2 @@ +def main(): + pass diff --git a/bundle/neoformat/test/autocomplete_test.vim b/bundle/neoformat/test/autocomplete_test.vim new file mode 100644 index 000000000..d4d1e3165 --- /dev/null +++ b/bundle/neoformat/test/autocomplete_test.vim @@ -0,0 +1,65 @@ +let s:tests = {} +" Utilities +function! s:Run(function) + let o = &filetype + " let output = call(a:function, ['']) + " call function(a:function) + let output = call(a:function, []) + let &filetype = o + " expecting output to either be a 1 or 0 + let s:tests[a:function[2:]] = output + return output +endfunction + +function! s:Cleanup() + let error = 0 + for test in keys(s:tests) + if !s:tests[test] + let error = 1 + endif + echom test . ' : ' . s:tests[test] + endfor + + if error + " make vim exit with a non-zero value + cquit! + else + qall! + endif +endfunction + +" Test Definitions +function! s:valid_option() + let &filetype = 'python' + + let g:neoformat_python_enabled = ['autopep8', 'yapf'] + let out = neoformat#CompleteFormatters('auto','', 0) + + return ['autopep8'] == out +endfunction + +function! s:invalid_option() + let &filetype = 'javascript' + + let g:neoformat_python_enabled = ['autopep8'] + let out = neoformat#CompleteFormatters('autopep8', '', 0) + + return [] == out +endfunction + +function! s:formtprg_option() + let &filetype = 'javascript' + let &formatprg = 'testing' + let out = neoformat#CompleteFormatters('test', '', 0) + + return [] == out +endfunction + +" Run Tests +call s:Run('s:valid_option') +call s:Run('s:invalid_option') +call s:Run('s:formtprg_option') + + +" Check the outputs +call s:Cleanup() diff --git a/bundle/neoformat/test/before/cp.cp b/bundle/neoformat/test/before/cp.cp new file mode 100644 index 000000000..9d40dd8b0 --- /dev/null +++ b/bundle/neoformat/test/before/cp.cp @@ -0,0 +1 @@ +'test' diff --git a/bundle/neoformat/test/before/cssbeautify.css b/bundle/neoformat/test/before/cssbeautify.css new file mode 100644 index 000000000..687483070 --- /dev/null +++ b/bundle/neoformat/test/before/cssbeautify.css @@ -0,0 +1,3 @@ +.body { +color: red; +} diff --git a/bundle/neoformat/test/before/csscomb.css b/bundle/neoformat/test/before/csscomb.css new file mode 100644 index 000000000..687483070 --- /dev/null +++ b/bundle/neoformat/test/before/csscomb.css @@ -0,0 +1,3 @@ +.body { +color: red; +} diff --git a/bundle/neoformat/test/before/prettydiff.css b/bundle/neoformat/test/before/prettydiff.css new file mode 100644 index 000000000..687483070 --- /dev/null +++ b/bundle/neoformat/test/before/prettydiff.css @@ -0,0 +1,3 @@ +.body { +color: red; +} diff --git a/bundle/neoformat/test/before/tsfmt.ts b/bundle/neoformat/test/before/tsfmt.ts new file mode 100644 index 000000000..0dd234aec --- /dev/null +++ b/bundle/neoformat/test/before/tsfmt.ts @@ -0,0 +1,13 @@ + module Geometry { +export class Square { +constructor(public sideLength: number = 0) { +} + area() { + return Math.pow(this.sideLength, 2); + } +} +} + +class Tuple { + constructor(public item1: T1, public item2: T2) { } +} diff --git a/bundle/neoformat/test/before/yapf.py b/bundle/neoformat/test/before/yapf.py new file mode 100644 index 000000000..66135be47 --- /dev/null +++ b/bundle/neoformat/test/before/yapf.py @@ -0,0 +1,2 @@ +def main(): + pass diff --git a/bundle/neoformat/test/bin/exit64 b/bundle/neoformat/test/bin/exit64 new file mode 100644 index 000000000..b1800a866 --- /dev/null +++ b/bundle/neoformat/test/bin/exit64 @@ -0,0 +1 @@ +exit 64 diff --git a/bundle/neoformat/test/install.sh b/bundle/neoformat/test/install.sh new file mode 100644 index 000000000..c9304fe64 --- /dev/null +++ b/bundle/neoformat/test/install.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +if [[ $OSTYPE == darwin* ]]; then + OS='mac' +elif [[ $OSTYPE == linux-gnu* ]]; then + OS='linux' +else + OS='unknown' +fi + +# Formatters +npm install -g csscomb@3.1.7 +npm install -g prettydiff@99.0.1 +npm install -g js-beautify@1.6.2 # for css-beautify +npm install -g typescript@2.0.6 +npm install -g typescript-formatter@4.0.1 +pip install yapf==0.14.0 + +# Linter(s) +if ! hash vint 2>/dev/null; then + pip3 install vim-vint +fi + +# Make sure neovim is installed +if ! hash nvim 2>/dev/null; then + echo "installing neovim" + if [[ $OS == 'linux' ]]; then + echo "installing nvim on linux" + sudo add-apt-repository -y ppa:neovim-ppa/unstable + sudo apt-get update + sudo apt-get install -y neovim + elif [[ $OS == 'mac' ]]; then + echo "install nvim on mac" + brew install neovim + fi +else + echo "neovim already installed" +fi + +# Vader +if [ ! -d "$HOME/.vim/plugged/vader.vim" ]; then + git clone https://github.com/junegunn/vader.vim.git ~/.vim/plugged/vader.vim +fi + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +export PATH=$PATH:"$DIR"/bin +echo $PATH diff --git a/bundle/neoformat/test/neoformat.vader b/bundle/neoformat/test/neoformat.vader new file mode 100644 index 000000000..6212a563a --- /dev/null +++ b/bundle/neoformat/test/neoformat.vader @@ -0,0 +1,43 @@ +Before: + function! g:CmdOutput(cmd) + redir => out + silent exe a:cmd + redir END + return out[1:] + endfunction + +Execute (empty filetype): + let &filetype = '' + let out = g:CmdOutput('Neoformat') + AssertEqual 'Neoformat: formatter not defined for filetype', out + +Execute (filetype without defined formatter): + let &filetype = 'not_real_filetype' + let out = g:CmdOutput('Neoformat') + + AssertEqual 'Neoformat: formatter not defined for ' . &filetype . ' filetype', out + +Execute (formatter defined for other filetype, but is called via user cmd): + let &filetype = 'javascript' + let out = g:CmdOutput('Neoformat autopep8') + + AssertEqual 'Neoformat: formatter definition for autopep8 not found', out + +Execute (user disabled all formatters for current (python) filetype): + let g:neoformat_enabled_python= [] + let &filetype = 'python' + let out = g:CmdOutput('Neoformat') + + AssertEqual 'Neoformat: formatter not defined for ' . &filetype . ' filetype', out + +Execute (user disabled all formatters for current (python) filetype): + let g:neoformat_enabled_python= ['not_real_formatter'] + let &filetype = 'python' + let out = g:CmdOutput('Neoformat') + + AssertEqual 'Neoformat: no change necessary', out + +Execute (invalid user cmd: formatter not defined): + let out = g:CmdOutput('Neoformat not_a_real_formatter') + + AssertEqual 'Neoformat: formatter definition for not_a_real_formatter not found', out diff --git a/bundle/neoformat/test/requirements.txt b/bundle/neoformat/test/requirements.txt new file mode 100644 index 000000000..ae190bf60 --- /dev/null +++ b/bundle/neoformat/test/requirements.txt @@ -0,0 +1,2 @@ +py==1.4.32 +pytest==3.0.5 diff --git a/bundle/neoformat/test/test.py b/bundle/neoformat/test/test.py new file mode 100644 index 000000000..f5c42eebf --- /dev/null +++ b/bundle/neoformat/test/test.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3.6 + +import subprocess + +from os import listdir +from shutil import copyfile + +def run_vim_cmd(cmd, filename=''): + cmd = f'nvim -u vimrc -c "set verbose=1 | {cmd} | wq " --headless {filename}' + return run_cmd(cmd) + + +def run_cmd(cmd): + return subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).wait() + + +def readlines(filename): + with open(filename) as f: + return f.readlines() + + +def test_formatters(): + ''' + run formatters on entire buffer + ''' + for filename in listdir('before'): + output_file = '/tmp/neoformat_' + filename + formatter = filename.split('.')[0] + cmd = f'nvim -u vimrc -c "set verbose=1 | Neoformat {formatter} | w! {output_file} | q! " --headless ./before/{filename}' + run_cmd(cmd) + before = readlines(output_file) + after = readlines('./after/' + filename) + assert before == after + + +def test_visual_selection_multi_filetype(): + ''' + Format different filetypes in one file + ''' + filename_before = 'visual_selection_before.txt' + output_file = '/tmp/neoformat_' + filename_before + copyfile(filename_before, output_file) + + for test in [('python', 4, 7), ('css', 9, 9), ('css', 14, 15)]: + (filetype, start_line, end_line) = test + print(start_line) + vim_cmd = f'{start_line},{end_line}Neoformat! {filetype}' + cmd = f'nvim -u vimrc -c "set verbose=1 | {vim_cmd} | wq " --headless {output_file}' + run_cmd(cmd) + + before = readlines(output_file) + after = readlines('visual_selection_after.txt') + assert before == after + + +def test_visual_selection_with_filetype_and_formatter(): + ''' + Test that passing filetype and formatter to Neoformat! works + ''' + dir_before = 'visual_before/' + dir_after = 'visual_after/' + for filename in listdir(dir_before): + (filetype, formatter, start_line, end_line) = filename.split('_') + output_file = '/tmp/neoformat_' + filename + cmd = f'nvim -u vimrc -c "set verbose=1 | {start_line},{end_line}Neoformat! {filetype} {formatter} | w! {output_file} | q! " --headless {dir_before + filename}' + run_cmd(cmd) + before = readlines(output_file) + after = readlines(dir_after + filename) + assert before == after + + +def test_formatprg_with_neoformat(): + ''' + Test that formatprg is processed by neoformat + ''' + + dir_before = 'before/' + filename = 'cssbeautify.css' + output_file = '/tmp/neoformat_fmt_prg_' + filename + viml = ''' + let &formatprg = 'css-beautify -s 6 -n' + let g:neoformat_try_formatprg = 1 + ''' + cmd = f'nvim -u vimrc -c "set verbose=1 | {viml} | Neoformat | w! {output_file} | q! " --headless {dir_before + filename}' + run_cmd(cmd) + before = readlines(output_file) + after = readlines('./after/cssbeautify-indent-6.css') + assert before == after + + +def test_formatprg_without_enable(): + ''' + Test that formatprg isn't use when not enabled + ''' + + dir_before = 'before/' + filename = 'cssbeautify.css' + output_file = '/tmp/neoformat_fmtprg_not_enabled' + filename + viml = ''' + let &formatprg = 'css-beautify -s 6 -n' + ''' + cmd = f'nvim -u vimrc -c "set verbose=1 | {viml} | Neoformat | w! {output_file} | q! " --headless {dir_before + filename}' + run_cmd(cmd) + before = readlines(output_file) + after = readlines('./after/cssbeautify.css') + assert before == after + + +def test_vader(): + ''' + run *.vader tests + ''' + cmd = f'nvim -u vimrc -c "Vader! *.vader" --headless' + exit_code = run_cmd(cmd) + assert exit_code == 0 + + +def test_autocompletion(): + ''' + run the vim autocompletion tests + ''' + cmd = f'nvim -u vimrc -c "source autocomplete_test.vim" --headless' + exit_code = run_cmd(cmd) + assert exit_code == 0 + + +def test_viml_syntax(): + ''' + run vint to check vim syntax + ''' + exit_code = run_cmd('vint ../') + assert exit_code == 0 + + +if __name__ == '__main__': + # run all functions with names in the form of 'test_...' + [func() for func in (val for key, val in vars().items() + if key.startswith('test_'))] diff --git a/bundle/neoformat/test/utils.vader b/bundle/neoformat/test/utils.vader new file mode 100644 index 000000000..ccf4ce30c --- /dev/null +++ b/bundle/neoformat/test/utils.vader @@ -0,0 +1,56 @@ +Before: + function! g:CmdOutput(cmd) + redir => out + silent exe 'call ' . a:cmd + redir END + return out[1:] + endfunction + +Execute (test log util): + let g:neoformat_verbose = 1 + let out = g:CmdOutput('neoformat#utils#log("test")') + + let g:neoformat_verbose = 0 + AssertEqual 'Neoformat: test', out + +Execute (test msg util): + let g:neoformat_verbose = 0 + " vader persists g: variables between tests so we need to make sure it is zero + let g:neoformat_only_msg_on_error = 0 + let out = g:CmdOutput('neoformat#utils#msg("test")') + + AssertEqual 'Neoformat: test', out + +Execute (test warn util): + let g:neoformat_verbose = 0 + let out = g:CmdOutput('neoformat#utils#warn("test")') + + AssertEqual 'Neoformat: test', out + +Execute (msg when g:neoformat_only_msg_on_error is false): + let g:neoformat_only_msg_on_error = 0 + + let out = g:CmdOutput('neoformat#utils#msg("test")') + + AssertEqual 'Neoformat: test', out + +Execute (msg when g:neoformat_only_msg_on_error is true): + let g:neoformat_only_msg_on_error = 1 + + let out = g:CmdOutput('neoformat#utils#msg("test")') + + AssertEqual '', out + +Execute (msg when g:neoformat_only_msg_on_error is false): + let g:neoformat_only_msg_on_error = 0 + + let out = g:CmdOutput('neoformat#utils#warn("test")') + + AssertEqual 'Neoformat: test', out + +Execute (warn when g:neoformat_only_msg_on_error is true): + let g:neoformat_only_msg_on_error = 1 + + let out = g:CmdOutput('neoformat#utils#warn("test")') + + AssertEqual 'Neoformat: test', out diff --git a/bundle/neoformat/test/vimrc b/bundle/neoformat/test/vimrc new file mode 100644 index 000000000..21b8c7e31 --- /dev/null +++ b/bundle/neoformat/test/vimrc @@ -0,0 +1,18 @@ +filetype off +set runtimepath+=$HOME/.vim/plugged/vader.vim +set runtimepath+=../ +filetype plugin indent on +syntax enable +autocmd! filetype css set shiftwidth=2 +autocmd! filetype python set shiftwidth=4 +autocmd! filetype javascript set shiftwidth=4 +autocmd! BufRead *.ts set filetype=typescript +autocmd! BufRead *.cp set filetype=copy +set nocompatible +set noswapfile + +" seems like cp doesn't have standard exit codes +let g:neoformat_copy_cp = { + \ 'exe': 'exit64', + \ 'valid_exit_codes': [1, 64], + \ } diff --git a/bundle/neoformat/test/visual_after/css_cssbeautify_3_4 b/bundle/neoformat/test/visual_after/css_cssbeautify_3_4 new file mode 100644 index 000000000..619d18127 --- /dev/null +++ b/bundle/neoformat/test/visual_after/css_cssbeautify_3_4 @@ -0,0 +1,8 @@ + + +.test { + color: blue; + border: none; +} + + diff --git a/bundle/neoformat/test/visual_after/javascript_jsbeautify_3_4 b/bundle/neoformat/test/visual_after/javascript_jsbeautify_3_4 new file mode 100644 index 000000000..468df3c06 --- /dev/null +++ b/bundle/neoformat/test/visual_after/javascript_jsbeautify_3_4 @@ -0,0 +1,5 @@ + + +function main() { + console.log('test') +} diff --git a/bundle/neoformat/test/visual_before/css_cssbeautify_3_4 b/bundle/neoformat/test/visual_before/css_cssbeautify_3_4 new file mode 100644 index 000000000..28ec6cbfa --- /dev/null +++ b/bundle/neoformat/test/visual_before/css_cssbeautify_3_4 @@ -0,0 +1,6 @@ + + +.test{color:blue; +border:none;} + + diff --git a/bundle/neoformat/test/visual_before/javascript_jsbeautify_3_4 b/bundle/neoformat/test/visual_before/javascript_jsbeautify_3_4 new file mode 100644 index 000000000..ed9f89752 --- /dev/null +++ b/bundle/neoformat/test/visual_before/javascript_jsbeautify_3_4 @@ -0,0 +1,4 @@ + + +function main(){ +console.log('test')} diff --git a/bundle/neoformat/test/visual_selection_after.txt b/bundle/neoformat/test/visual_selection_after.txt new file mode 100644 index 000000000..095304e1f --- /dev/null +++ b/bundle/neoformat/test/visual_selection_after.txt @@ -0,0 +1,16 @@ + + + +def main(): + + pass + + +.body { + color: red; +} + + +.textleft { + text-align: left; +} diff --git a/bundle/neoformat/test/visual_selection_before.txt b/bundle/neoformat/test/visual_selection_before.txt new file mode 100644 index 000000000..b8d715b01 --- /dev/null +++ b/bundle/neoformat/test/visual_selection_before.txt @@ -0,0 +1,14 @@ + + + +def main(): + + + pass + + +.body{color:red;} + + +.textleft{ +text-align:left;} diff --git a/bundle/neoinclude.vim/.gitignore b/bundle/neoinclude.vim/.gitignore new file mode 100644 index 000000000..63746c0b6 --- /dev/null +++ b/bundle/neoinclude.vim/.gitignore @@ -0,0 +1,2 @@ +*.py[cod] +doc/tags diff --git a/bundle/neoinclude.vim/LICENSE b/bundle/neoinclude.vim/LICENSE new file mode 100644 index 000000000..3a4b98ed8 --- /dev/null +++ b/bundle/neoinclude.vim/LICENSE @@ -0,0 +1,21 @@ +License: MIT license +AUTHOR: Shougo Matsushita + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bundle/neoinclude.vim/autoload/cm/sources/neoinclude.vim b/bundle/neoinclude.vim/autoload/cm/sources/neoinclude.vim new file mode 100644 index 000000000..770da9a2a --- /dev/null +++ b/bundle/neoinclude.vim/autoload/cm/sources/neoinclude.vim @@ -0,0 +1,21 @@ +"============================================================================= +" FILE: neoinclude.vim (NCM source) +" AUTHOR: Jia Sui +" License: MIT license +" ============================================================================ + +function! cm#sources#neoinclude#refresh(opt, ctx) abort + let typed = a:ctx['typed'] + + let startcol = neoinclude#file_include#get_complete_position(typed) + + if startcol == -1 + return + endif + + let inc = neoinclude#file_include#get_include_files(typed) + + let matches = map(inc, "{'word': v:val['word'], 'dup': 1, 'icase': 1, 'menu': 'FI: ' . v:val['kind']}") + + call cm#complete(a:opt.name, a:ctx, startcol + 1, matches) +endfunction diff --git a/bundle/neoinclude.vim/autoload/neocomplete/sources/file_include.vim b/bundle/neoinclude.vim/autoload/neocomplete/sources/file_include.vim new file mode 100644 index 000000000..23980cd94 --- /dev/null +++ b/bundle/neoinclude.vim/autoload/neocomplete/sources/file_include.vim @@ -0,0 +1,27 @@ +"============================================================================= +" FILE: file_include.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +let s:source = { + \ 'name' : 'file/include', + \ 'kind' : 'manual', + \ 'mark' : '[FI]', + \ 'rank' : 150, + \ 'sorters' : 'sorter_filename', + \ 'converters' : ['converter_remove_overlap', 'converter_abbr'], + \ 'min_pattern_length' : 0, + \} + +function! neocomplete#sources#file_include#define() abort + return s:source +endfunction + +function! s:source.get_complete_position(context) abort + return neoinclude#file_include#get_complete_position(a:context.input) +endfunction + +function! s:source.gather_candidates(context) abort + return neoinclude#file_include#get_include_files(a:context.input) +endfunction diff --git a/bundle/neoinclude.vim/autoload/neoinclude.vim b/bundle/neoinclude.vim/autoload/neoinclude.vim new file mode 100644 index 000000000..bc7ba32eb --- /dev/null +++ b/bundle/neoinclude.vim/autoload/neoinclude.vim @@ -0,0 +1,313 @@ +"============================================================================= +" FILE: neoinclude.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +let s:initialized = 0 + +function! neoinclude#initialize() abort + if s:initialized + return + endif + + let g:neoinclude#ctags_commands = + \ get(g:, 'neoinclude#ctags_commands', {}) + let g:neoinclude#_ctags_commands = {} + let g:neoinclude#ctags_arguments = + \ get(g:, 'neoinclude#ctags_arguments', {}) + let g:neoinclude#_ctags_arguments = {} + let g:neoinclude#max_processes = + \ get(g:, 'neoinclude#max_processes', 20) + let g:neoinclude#paths = + \ get(g:, 'neoinclude#paths', {}) + let g:neoinclude#_paths = {} + let g:neoinclude#patterns = + \ get(g:, 'neoinclude#patterns', {}) + let g:neoinclude#_patterns = {} + let g:neoinclude#exprs = + \ get(g:, 'neoinclude#exprs', {}) + let g:neoinclude#_exprs = {} + let g:neoinclude#exts = + \ get(g:, 'neoinclude#exts', {}) + let g:neoinclude#_exts = {} + let g:neoinclude#reverse_exprs = + \ get(g:, 'neoinclude#reverse_exprs', {}) + let g:neoinclude#_reverse_exprs = {} + let g:neoinclude#functions = + \ get(g:, 'neoinclude#functions', {}) + let g:neoinclude#_functions = {} + let g:neoinclude#delimiters = + \ get(g:, 'neoinclude#delimiters', {}) + let g:neoinclude#_delimiters = {} + let g:neoinclude#suffixes = + \ get(g:, 'neoinclude#suffixes', {}) + let g:neoinclude#_suffixes = {} + + " Initialize include pattern. + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_patterns', + \ 'java,haskell', '^\s*\') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_patterns', + \ 'r', '^\s*source(') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_patterns', + \ 'html,xhtml,xml,markdown,mkd', '\%(src\|href\)="\ze[^"]*$') + + " Initialize include suffixes. + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_suffixes', + \ 'haskell', '.hs') + + " Initialize include functions. + " call neoinclude#util#set_default_dictionary( + " \ 'g:neoinclude#_functions', 'vim', + " \ 'neoinclude#analyze_vim_include_files') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_functions', 'ruby', + \ 'neoinclude#analyze_ruby_include_files') + + " Initialize filename include expr. + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_reverse_exprs', + \ 'perl', + \ 'substitute(v:fname, "/", "::", "g")') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_reverse_exprs', + \ 'java,d', + \ 'substitute(v:fname, "/", ".", "g")') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_reverse_exprs', + \ 'ruby', + \ 'substitute(v:fname, "\.rb$", "", "")') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_reverse_exprs', + \ 'python', + \ "substitute(substitute(v:fname, + \ '\\v.*egg%(-info|-link)?$', '', ''), '/', '.', 'g')") + + " Initialize filename include extensions. + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_exts', + \ 'c', ['h']) + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_exts', + \ 'cpp', ['', 'h', 'hpp', 'hxx']) + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_exts', + \ 'perl', ['pm']) + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_exts', + \ 'java', ['java']) + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_exts', + \ 'ruby', ['rb']) + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_exts', + \ 'python', ['py', 'py3']) + + " Initialize filename include delimiter. + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_delimiters', + \ 'c,cpp,ruby', '/') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_delimiters', + \ 'html,xhtml,xml,markdown,mkd', '') + + " Initialize ctags command. + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_ctags_commands', + \ '_', 'ctags') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_ctags_commands', + \ 'go', 'gotags') + + " Initialize ctags arguments. + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_ctags_arguments', + \ '_', '') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_ctags_arguments', 'vim', + \ '--language-force=vim --extra=fq --fields=+ailmnSz --vim-kinds=-f '. + \ '--regex-vim=''/function!?[ \t]+'. + \ '(([bwtglsa]:)?\w+(\.\w+)+|(g:)?([A-Z]\w*|\w+(#\w+)+)|s:\w+)'. + \ '[ \t]*\(/\1/function/''') + if neoinclude#util#is_mac() + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_ctags_arguments', 'c', + \ '--c-kinds=+p --fields=+iaS --extra=+q + \ -I__DARWIN_ALIAS,__DARWIN_ALIAS_C,__DARWIN_ALIAS_I,__DARWIN_INODE64 + \ -I__DARWIN_1050,__DARWIN_1050ALIAS,__DARWIN_1050ALIAS_C,__DARWIN_1050ALIAS_I,__DARWIN_1050INODE64 + \ -I__DARWIN_EXTSN,__DARWIN_EXTSN_C + \ -I__DARWIN_LDBL_COMPAT,__DARWIN_LDBL_COMPAT2') + else + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_ctags_arguments', 'c', + \ '-R --sort=1 --c-kinds=+p --fields=+iaS --extra=+q ' . + \ '-I __wur,__THROW,__attribute_malloc__,__nonnull+,'. + \ '__attribute_pure__,__attribute_warn_unused_result__,__attribute__+') + endif + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#_ctags_arguments', 'cpp', + \ '--language-force=C++ -R --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q '. + \ '-I __wur,__THROW,__attribute_malloc__,__nonnull+,'. + \ '__attribute_pure__,__attribute_warn_unused_result__,__attribute__+') + + augroup neoinclude + autocmd! + augroup END + + call neoinclude#include#initialize() + + let s:initialized = 1 +endfunction + +function! neoinclude#set_filetype_paths(bufnr, filetype) abort + if a:filetype ==# 'python' && !has_key(g:neoinclude#paths, 'python') + " Initialize python path pattern. + if executable('python3') + call s:set_python_paths('python3') + elseif executable('python') + call s:set_python_paths('python') + endif + elseif a:filetype ==# 'cpp' + \ && !has_key(g:neoinclude#paths, 'cpp') + \ && isdirectory('/usr/include/c++') + call s:set_cpp_paths(a:bufnr) + endif +endfunction + +function! neoinclude#get_path(bufnr, filetype) abort + " Don't use global path if it is not C or C++ + let default = (a:filetype ==# 'c' || a:filetype ==# 'cpp' + \ || getbufvar(a:bufnr, '&path') !=# &g:path) ? + \ getbufvar(a:bufnr, '&path') : '.' + return neoinclude#util#substitute_path_separator( + \ neoinclude#util#get_buffer_config( + \ a:filetype, 'b:neoinclude_paths', + \ g:neoinclude#paths, g:neoinclude#_paths, + \ default)) +endfunction +function! neoinclude#get_pattern(bufnr, filetype) abort + return neoinclude#util#get_buffer_config( + \ a:filetype, 'b:neoinclude_patterns', + \ g:neoinclude#patterns, g:neoinclude#_patterns, + \ getbufvar(a:bufnr, '&include')) +endfunction +function! neoinclude#get_expr(bufnr, filetype) abort + return neoinclude#util#get_buffer_config( + \ a:filetype, 'b:neoinclude_exprs', + \ g:neoinclude#exprs, g:neoinclude#_exprs, + \ getbufvar(a:bufnr, '&includeexpr')) +endfunction +function! neoinclude#get_reverse_expr(filetype) abort + return neoinclude#util#get_buffer_config( + \ a:filetype, 'b:neoinclude_reverse_exprs', + \ g:neoinclude#reverse_exprs, g:neoinclude#_reverse_exprs, + \ '') +endfunction +function! neoinclude#get_exts(filetype) abort + return neoinclude#util#get_buffer_config( + \ a:filetype, 'b:neoinclude_exts', + \ g:neoinclude#exts, g:neoinclude#_exts, + \ []) +endfunction +function! neoinclude#get_function(filetype) abort + return neoinclude#util#get_buffer_config( + \ a:filetype, 'b:neoinclude_functions', + \ g:neoinclude#functions, g:neoinclude#_functions, + \ '') +endfunction +function! neoinclude#get_delimiters(filetype) abort + return neoinclude#util#get_buffer_config( + \ a:filetype, 'b:neoinclude_delimiters', + \ g:neoinclude#delimiters, g:neoinclude#_delimiters, + \ '.') +endfunction +function! neoinclude#get_suffixes(bufnr, filetype) abort + return neoinclude#util#get_buffer_config( + \ a:filetype, 'b:neoinclude_suffixes', + \ g:neoinclude#suffixes, g:neoinclude#_suffixes, + \ getbufvar(a:bufnr, '&suffixesadd')) +endfunction + +" Analyze include files functions. +function! neoinclude#analyze_vim_include_files(lines, path) abort + let include_files = [] + let dup_check = {} + for line in a:lines + if line =~ '\<\h\w*#' && line !~ '\' + let filename = 'autoload/' . substitute(matchstr(line, '\<\%(\h\w*#\)*\h\w*\ze#'), + \ '#', '/', 'g') . '.vim' + if filename == '' || has_key(dup_check, filename) + continue + endif + let dup_check[filename] = 1 + + let filename = fnamemodify(findfile(filename, &runtimepath), ':p') + if filereadable(filename) + call add(include_files, filename) + endif + endif + endfor + + return include_files +endfunction +function! neoinclude#analyze_ruby_include_files(lines, path) abort + let include_files = [] + let dup_check = {} + for line in a:lines + if line =~ '\' + let args = split(line, ',') + if len(args) < 2 + continue + endif + let filename = substitute(matchstr(args[1], '["'']\zs\f\+\ze["'']'), + \ '\.', '/', 'g') . '.rb' + if filename == '' || has_key(dup_check, filename) + continue + endif + let dup_check[filename] = 1 + + let filename = fnamemodify(findfile(filename, a:path), ':p') + if filereadable(filename) + call add(include_files, filename) + endif + endif + endfor + + return include_files +endfunction + +function! s:set_python_paths(python_bin) abort + let python_sys_path_cmd = a:python_bin . + \ ' -c "import sys;sys.stdout.write(\",\".join(sys.path))"' + let path = neoinclude#util#system(python_sys_path_cmd) + let path = join(neoinclude#util#uniq(filter( + \ split(path, ',', 1), "v:val != ''")), ',') + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#paths', 'python', path) +endfunction + +function! s:set_cpp_paths(bufnr) abort + let files = split(glob('/usr/include/*'), '\n') + \ + split(glob('/usr/include/c++/*'), '\n') + \ + split(glob('/usr/include/*/c++/*'), '\n') + call filter(files, 'isdirectory(v:val)') + + " Add cpp path. + call neoinclude#util#set_default_dictionary( + \ 'g:neoinclude#paths', 'cpp', + \ getbufvar(a:bufnr, '&path') . + \ ','.join(files, ',')) +endfunction diff --git a/bundle/neoinclude.vim/autoload/neoinclude/file_include.vim b/bundle/neoinclude.vim/autoload/neoinclude/file_include.vim new file mode 100644 index 000000000..b24534e28 --- /dev/null +++ b/bundle/neoinclude.vim/autoload/neoinclude/file_include.vim @@ -0,0 +1,141 @@ +"============================================================================= +" FILE: file_include.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! neoinclude#file_include#get_complete_position(input) abort + call neoinclude#initialize() + + let filetype = neoinclude#util#get_context_filetype() + if filetype ==# 'java' || filetype ==# 'haskell' + " Cannot complete include path. + " You should use omnifunc plugins.. + return -1 + endif + + " Not Filename pattern. + let pattern = neoinclude#get_pattern('%', filetype) + if (pattern == '' || a:input !~ pattern) + \ && a:input =~ '\*$\|\.\.\+$\|/c\%[ygdrive/]$' + " Skip filename completion. + return -1 + endif + + " Check include pattern. + let pattern = neoinclude#get_pattern('%', filetype) + if pattern =~ '\w$' + let pattern .= '\m\s\+' + endif + if pattern == '' || a:input !~ pattern + return -1 + endif + + let match_end = matchend(a:input, pattern) + let complete_str = matchstr(a:input[match_end :], '\f\+') + + let complete_pos = len(a:input) - len(complete_str) + + let delimiter = neoinclude#get_delimiters(filetype) + if delimiter != '' && strridx(complete_str, delimiter) >= 0 + let complete_pos += strridx(complete_str, delimiter) + 1 + endif + + return complete_pos +endfunction + +function! neoinclude#file_include#get_include_files(input) abort + call neoinclude#initialize() + + let filetype = neoinclude#util#get_context_filetype() + + call neoinclude#set_filetype_paths('%', filetype) + + let path = neoinclude#get_path('%', filetype) + let pattern = neoinclude#get_pattern('%', filetype) + let expr = neoinclude#get_expr('%', filetype) + let reverse_expr = neoinclude#get_reverse_expr(filetype) + let exts = neoinclude#get_exts(filetype) + + let line = a:input + + let match_end = matchend(line, pattern) + let complete_str = matchstr(line[match_end :], '\f\+') + if expr != '' + let complete_str = + \ substitute(eval(substitute(expr, + \ 'v:fname', string(complete_str), 'g')), '\.\w*$', '', '') + endif + let delimiter = neoinclude#get_delimiters(filetype) + + if (line =~ '^\s*\' && filetype =~# 'ruby') + \ || stridx(complete_str, '.') == 0 + " For include relative. + let path = '.' + endif + + " Path search. + let glob = (complete_str !~ '\*$')? + \ complete_str . '*' : complete_str + let bufdirectory = neoinclude#util#substitute_path_separator( + \ fnamemodify(expand('%'), ':p:h')) + let candidates = s:get_default_include_files(filetype) + let path = join(map(split(path, ',\+'), + \ "v:val == '.' ? bufdirectory : v:val"), ',') + for word in filter(split( + \ neoinclude#util#substitute_path_separator( + \ globpath(path, glob, 1)), '\n')," + \ isdirectory(v:val) || empty(exts) || + \ index(exts, fnamemodify(v:val, ':e')) >= 0") + + let dict = { + \ 'word' : word, + \ 'action__is_directory' : isdirectory(word), + \ 'kind' : (isdirectory(word) ? 'dir' : 'file'), + \ } + + if reverse_expr != '' + " Convert filename. + let dict.word = eval(substitute(reverse_expr, + \ 'v:fname', string(dict.word), 'g')) + endif + + if !dict.action__is_directory && delimiter != '/' + " Remove extension. + let dict.word = fnamemodify(dict.word, ':r') + endif + + " Remove before delimiter. + if delimiter != '' && strridx(dict.word, delimiter) >= 0 + let dict.word = dict.word[strridx(dict.word, delimiter)+strlen(delimiter): ] + endif + + " Remove bufdirectory. + if stridx(dict.word, bufdirectory . '/') == 0 + let dict.word = dict.word[len(bufdirectory)+1 : ] + endif + + let dict.abbr = dict.word + if dict.action__is_directory + let dict.abbr .= delimiter + endif + + call add(candidates, dict) + endfor + + return candidates +endfunction + +function! s:get_default_include_files(filetype) abort + let files = [] + + if a:filetype ==# 'python' || a:filetype ==# 'python3' + let files = ['sys'] + endif + + return map(files, "{ + \ 'word' : v:val, + \ 'action__is_directory' : isdirectory(v:val), + \ 'kind' : (isdirectory(v:val) ? 'dir' : 'file'), + \}") +endfunction diff --git a/bundle/neoinclude.vim/autoload/neoinclude/include.vim b/bundle/neoinclude.vim/autoload/neoinclude/include.vim new file mode 100644 index 000000000..73cfa7ead --- /dev/null +++ b/bundle/neoinclude.vim/autoload/neoinclude/include.vim @@ -0,0 +1,231 @@ +"============================================================================= +" FILE: include.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +function! neoinclude#include#initialize() abort + let s:include_info = {} + let s:include_cache = {} + let s:async_include_cache = {} + let s:cached_pattern = {} + + augroup neoinclude + autocmd BufWritePost * call s:check_buffer('', 0) + augroup END +endfunction + +function! neoinclude#include#get_include_files(...) abort + call neoinclude#initialize() + + call s:check_buffer('', 0) + + let bufnr = get(a:000, 0, bufnr('%')) + if has_key(s:include_info, bufnr) + return copy(s:include_info[bufnr].include_files) + else + return s:get_buffer_include_files(bufnr) + endif +endfunction + +function! neoinclude#include#get_tag_files(...) abort + call neoinclude#initialize() + + call s:check_buffer('', 0) + + let bufnr = get(a:000, 0, bufnr('%')) + let include_files = neoinclude#include#get_include_files(bufnr) + return filter(map(filter(map(include_files, + \ 'get(s:async_include_cache, v:val, {})'), + \ '!empty(v:val)'), 'v:val.cachename'), 'filereadable(v:val)') +endfunction + +" For Debug. +function! neoinclude#include#get_current_include_files() abort + call neoinclude#initialize() + + return s:get_buffer_include_files(bufnr('%')) +endfunction + +function! s:check_buffer(bufnr, is_force) abort + let bufnr = (a:bufnr == '') ? bufnr('%') : a:bufnr + let filename = fnamemodify(bufname(bufnr), ':p') + + if !has_key(s:include_info, bufnr) + " Initialize. + let s:include_info[bufnr] = { + \ 'include_files' : [], 'lines' : [], + \ 'async_files' : {}, + \ } + endif + + let include_info = s:include_info[bufnr] + + if a:is_force || include_info.lines !=# getbufline(bufnr, 1, 100) + let include_info.lines = getbufline(bufnr, 1, 100) + + " Check include files contained bufname. + let include_files = s:get_buffer_include_files(bufnr) + + " Check include files from function. + let filetype = getbufvar(a:bufnr, '&filetype') + let function = neoinclude#get_function(filetype) + if function != '' && getbufvar(bufnr, '&buftype') !~ 'nofile' + let path = neoinclude#get_path(a:bufnr, filetype) + let include_files += call(function, + \ [getbufline(bufnr, 1, (a:is_force ? '$' : 1000)), path]) + endif + + if getbufvar(bufnr, '&buftype') !~ 'nofile' + \ && filereadable(filename) + call add(include_files, filename) + endif + let include_info.include_files = neoinclude#util#uniq(include_files) + endif + + let filetype = getbufvar(bufnr, '&filetype') + if filetype == '' + let filetype = 'nothing' + endif + + let ctags = neoinclude#util#get_buffer_config(filetype, + \ 'b:neoinclude_ctags_commands', + \ g:neoinclude#ctags_commands, + \ g:neoinclude#_ctags_commands, '') + + if g:neoinclude#max_processes <= 0 || !executable(ctags) + return + endif + + for filename in include_info.include_files + if (a:is_force || !has_key(include_info.async_files, filename)) + \ && !has_key(s:include_cache, filename) + if !a:is_force && has_key(s:async_include_cache, filename) + \ && len(s:async_include_cache[filename]) + \ >= g:neoinclude#max_processes + break + endif + + let s:async_include_cache[filename] + \ = s:initialize_include(filename, filetype, ctags, a:is_force) + let include_info.async_files[filename] = 1 + endif + endfor +endfunction + +function! s:get_buffer_include_files(bufnr) abort + let filetype = getbufvar(a:bufnr, '&filetype') + if filetype == '' + return [] + endif + + call neoinclude#set_filetype_paths(a:bufnr, filetype) + + let pattern = neoinclude#get_pattern(a:bufnr, filetype) + if pattern == '' + return [] + endif + let path = neoinclude#get_path(a:bufnr, filetype) + let expr = neoinclude#get_expr(a:bufnr, filetype) + let suffixes = &l:suffixesadd + + " Change current directory. + let buffer_dir = fnamemodify(bufname(a:bufnr), ':p:h') + let cwd_save = neoinclude#util#cd(buffer_dir) + + try + let include_files = s:get_include_files(0, + \ getbufline(a:bufnr, 1, 100), filetype, pattern, path, expr) + finally + if !empty(cwd_save) + execute cwd_save[0] fnameescape(cwd_save[1]) + endif + + " Restore option. + let &l:suffixesadd = suffixes + endtry + + return neoinclude#util#uniq(include_files) +endfunction +function! s:get_include_files(nestlevel, lines, filetype, pattern, path, expr) abort + let include_files = [] + for line in a:lines + if line =~ a:pattern + let match_end = matchend(line, a:pattern) + if a:expr != '' + let eval = substitute(a:expr, 'v:fname', + \ string(matchstr(line[match_end :], '\f\+')), 'g') + try + let filename = fnamemodify(findfile(eval(eval), a:path), ':p') + catch + " Error + let filename = '' + endtry + else + let filename = fnamemodify(findfile( + \ matchstr(line[match_end :], '\f\+'), a:path), ':p') + endif + + if filereadable(filename) + call add(include_files, filename) + + if a:nestlevel < 1 + " Nested include files. + let include_files += s:get_include_files( + \ a:nestlevel + 1, readfile(filename, '', 100), + \ a:filetype, a:pattern, a:path, a:expr) + endif + elseif isdirectory(filename) && a:filetype ==# 'java' + " For Java import with *. + " Ex: import lejos.nxt.* + let include_files += neoinclude#util#glob(filename . '/*.java') + endif + endif + endfor + + return include_files +endfunction + +function! s:initialize_include(filename, filetype, ctags, is_force) abort + " Initialize include list from tags. + let tags_file_name = tempname() + let args = neoinclude#util#get_buffer_config(a:filetype, + \ 'b:neoinclude_ctags_arguments', + \ g:neoinclude#ctags_arguments, + \ g:neoinclude#_ctags_arguments, '') + if a:ctags == 'jsctags' + let command = printf('%s ''%s'' %s >''%s''', + \ a:ctags, a:filename, args, tags_file_name) + elseif has('win32') || has('win64') + let filename = + \ neoinclude#util#substitute_path_separator(a:filename) + let command = printf('%s -f "%s" %s "%s" ', + \ a:ctags, tags_file_name, args, filename) + else + let command = printf('%s -f ''%s'' 2>/dev/null %s ''%s''', + \ a:ctags, tags_file_name, args, a:filename) + endif + + if a:is_force + call neoinclude#util#system(command) + else + call neoinclude#util#async_system(command) + endif + + return { + \ 'filename' : a:filename, + \ 'cachename' : tags_file_name, + \ } +endfunction +function! neoinclude#include#make_cache(bufname) abort + call neoinclude#initialize() + + let bufnr = (a:bufname == '') ? bufnr('%') : bufnr(a:bufname) + + " Initialize. + if has_key(s:include_info, bufnr) + call remove(s:include_info, bufnr) + endif + + call s:check_buffer(bufnr, 1) +endfunction diff --git a/bundle/neoinclude.vim/autoload/neoinclude/util.vim b/bundle/neoinclude.vim/autoload/neoinclude/util.vim new file mode 100644 index 000000000..4a719cba7 --- /dev/null +++ b/bundle/neoinclude.vim/autoload/neoinclude/util.vim @@ -0,0 +1,137 @@ +"============================================================================= +" FILE: util.vim +" AUTHOR: Shougo Matsushita +" License: MIT license +"============================================================================= + +let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95') +let s:is_cygwin = has('win32unix') +let s:is_mac = !s:is_windows && !s:is_cygwin + \ && (has('mac') || has('macunix') || has('gui_macvim') || + \ (!isdirectory('/proc') && executable('sw_vers'))) +let s:is_unix = has('unix') + +function! neoinclude#util#is_windows() abort + return s:is_windows +endfunction + +function! neoinclude#util#is_cygwin() abort + return s:is_cygwin +endfunction + +function! neoinclude#util#is_mac() abort + return s:is_mac +endfunction + +function! neoinclude#util#uniq(list) abort + let dict = {} + for item in a:list + if !has_key(dict, item) + let dict[item] = item + endif + endfor + + return values(dict) +endfunction + +function! neoinclude#util#glob(pattern) abort + " Escape [. + if neoinclude#util#is_windows() + let glob = substitute(a:pattern, '\[', '\\[[]', 'g') + else + let glob = escape(a:pattern, '[') + endif + + return split(neoinclude#util#substitute_path_separator(glob(glob)), '\n') +endfunction + +function! neoinclude#util#substitute_path_separator(path) abort + return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path +endfunction + +function! neoinclude#util#set_default_dictionary(variable, keys, value) abort + call neoinclude#util#set_dictionary_helper({a:variable}, a:keys, a:value) +endfunction +function! neoinclude#util#set_dictionary_helper(variable, keys, pattern) abort + for key in split(a:keys, '\s*,\s*') + if !has_key(a:variable, key) + let a:variable[key] = a:pattern + endif + endfor +endfunction + +function! neoinclude#util#system(command) abort + let command = s:iconv(a:command, &encoding, 'char') + let output = s:iconv(system(command), 'char', &encoding) + + return substitute(output, '\n$', '', '') +endfunction +function! neoinclude#util#async_system(command) abort + let command = s:iconv(a:command, &encoding, 'char') + + if has('job') + return job_start(command) + elseif has('nvim') + return jobstart(command) + else + return neoinclude#util#system(a:command) + endif +endfunction + +function! s:iconv(expr, from, to) abort + if a:from == '' || a:to == '' || a:from ==? a:to + return a:expr + endif + let result = iconv(a:expr, a:from, a:to) + return result != '' ? result : a:expr +endfunction + +function! neoinclude#util#get_context_filetype() abort + " context_filetype.vim installation check. + if !exists('s:exists_context_filetype') + try + call context_filetype#version() + let s:exists_context_filetype = 1 + catch + let s:exists_context_filetype = 0 + endtry + endif + + return s:exists_context_filetype ? + \ context_filetype#get_filetype() : &filetype +endfunction + +function! neoinclude#util#get_buffer_config( + \ filetype, buffer_var, user_var, default_var, ...) + let default_val = get(a:000, 0, '') + + if exists(a:buffer_var) + return {a:buffer_var} + endif + + let filetype = !has_key(a:user_var, a:filetype) + \ && !has_key(a:default_var, a:filetype) ? '_' : a:filetype + + return get(a:user_var, filetype, + \ get(a:default_var, filetype, default_val)) +endfunction + +function! neoinclude#util#head_match(checkstr, headstr) abort + let checkstr = &ignorecase ? + \ tolower(a:checkstr) : a:checkstr + let headstr = &ignorecase ? + \ tolower(a:headstr) : a:headstr + return stridx(checkstr, headstr) == 0 +endfunction + +function! neoinclude#util#cd(dir) abort + let cwd = getcwd() + if !isdirectory(a:dir) || a:dir ==# cwd + return [] + endif + + let cd_command = haslocaldir() ? 'lcd' : + \ (exists(':tcd') == 2 && haslocaldir(-1, 0)) ? 'tcd' : 'cd' + silent! execute cd_command fnameescape(a:dir) + return [cd_command, cwd] +endfunction diff --git a/bundle/neoinclude.vim/autoload/unite/sources/file_include.vim b/bundle/neoinclude.vim/autoload/unite/sources/file_include.vim new file mode 100644 index 000000000..7aba788ad --- /dev/null +++ b/bundle/neoinclude.vim/autoload/unite/sources/file_include.vim @@ -0,0 +1,44 @@ +"============================================================================= +" FILE: file_include.vim +" AUTHOR: Shougo Matsushita +" manga_osyo (Original) +" License: MIT license +"============================================================================= + +function! unite#sources#file_include#define() abort + return s:source +endfunction + +let s:source = { + \ 'name' : 'file_include', + \ 'description' : 'candidates from include files', + \ 'hooks' : {}, + \} +function! s:source.hooks.on_init(args, context) abort + let a:context.source__include_files = + \ neoinclude#include#get_include_files(bufnr('%')) + let a:context.source__path = &path +endfunction + +function! s:source.gather_candidates(args, context) abort + let files = map(copy(a:context.source__include_files), '{ + \ "word" : neoinclude#util#substitute_path_separator(v:val), + \ "abbr" : neoinclude#util#substitute_path_separator(v:val), + \ "source" : "file_include", + \ "kind" : "file", + \ "action__path" : v:val + \ }') + + for word in files + " Path search. + for path in map(split(a:context.source__path, ','), + \ 'neoinclude#util#substitute_path_separator(v:val)') + if path != '' && neoinclude#util#head_match(word.word, path . '/') + let word.abbr = word.abbr[len(path)+1 : ] + break + endif + endfor + endfor + + return files +endfunction diff --git a/bundle/neoinclude.vim/doc/neoinclude.txt b/bundle/neoinclude.vim/doc/neoinclude.txt new file mode 100644 index 000000000..aecee17f8 --- /dev/null +++ b/bundle/neoinclude.vim/doc/neoinclude.txt @@ -0,0 +1,207 @@ +*neoinclude.txt* Include completion framework for neocomplete/deoplete/ncm. + +Version: 0.1 +Author: Shougo +License: MIT license + +CONTENTS *neoinclude-contents* + +Introduction |neoinclude-introduction| +Install |neoinclude-install| +Interface |neoinclude-interface| + Commands |neoinclude-commands| + Variables |neoinclude-variables| + Functions |neoinclude-functions| +Examples |neoinclude-examples| +FAQ |neoinclude-faq| + +============================================================================== +INTRODUCTION *neoinclude-introduction* + +*neoinclude* is the framework for |neocomplete|/|deoplete|/|ncm|. + +It has "file/include" source and extends tag sources in neocomplete/deoplete/ncm. + +============================================================================== +INSTALL *neoinclude-install* + +Requirements: neocomplete.vim, deoplete.nvim or ncm + +https://github.com/Shougo/neocomplete.vim + +https://github.com/Shougo/deoplete.nvim + +https://github.com/roxma/nvim-completion-manager + +============================================================================== +INTERFACE *neoinclude-interface* + +------------------------------------------------------------------------------ +COMMANDS *neoinclude-commands* + +:NeoIncludeMakeCache [bufname] *:NeoIncludeMakeCache* + Make a cache based on the buffer with the name [bufname]. + The command selects the current buffer when you omit + [bufname]. + +------------------------------------------------------------------------------ +VARIABLES *neoinclude-variables* + +g:neoinclude#max_processes *g:neoinclude#max_processes* + This variable appoints the max number of include processes. + When this variable is 0, include process will be disabled. + + Default value is 20. + +g:neoinclude#ctags_commands *g:neoinclude#ctags_commands* + It is the dictionary of the path to the ctags command. The + dictionary's key is filetype. If the key is "_", it will be + used for default. + Note: If this command is not installed, "include" source is + disabled. + + Default value is in "g:neoinclude#_ctags_commands". + + *b:neoinclude_ctags_commands* +b:neoinclude_ctags_commands + Buffer local variable of |g:neoinclude#_ctags_commands|. + +g:neoinclude#ctags_arguments *g:neoinclude#ctags_arguments* + It is the dictionary of the character string to set a value + to give as an argument of the commands when buffer + and include use a ctags command. The dictionary's + key is filetype. If the key is "_", it will be used for + default. + + Default value is in "g:neoinclude#_ctags_arguments". + + *b:neoinclude_ctags_arguments* +b:neoinclude_ctags_arguments + Buffer local variable of |g:neoinclude#_ctags_arguments|. + +g:neoinclude#paths *g:neoinclude#paths* + It is the variable to enumerate path of the include file + every file type. When there is not it, 'path' is used. + Refer to 'path' for the description form. It is the + dictionary of the character string that assumed file type a + key. + + Default value is in "g:neoinclude#_paths". + + *b:neoinclude_paths* +b:neoinclude_paths + Buffer local variable of |g:neoinclude#_paths|. + +g:neoinclude#patterns *g:neoinclude#patterns* + This variable appoints the pattern of the include command. + When there is not it, 'include' is used. Refer to 'include' + for the description form. It is the dictionary of the + character string that assumed file type a key. + + Default value is in "g:neoinclude#_patterns". + + *b:neoinclude_patterns* +b:neoinclude_patterns + Buffer local variable of |g:neoinclude#_patterns|. + +g:neoinclude#exprs *g:neoinclude#exprs* + It is the expression string of the line analysis to perform + to acquire an include file name. When there is not it, + 'includeexpr' is used. Refer to 'includeexpr' for the + description form. It is the dictionary of the character + string that assumed file type a key. + + Default value is in "g:neoinclude#_exprs". + + *b:neoinclude_exprs* +b:neoinclude_exprs + Buffer local variable of |g:neoinclude#_exprs|. + +g:neoinclude#reverse_exprs *g:neoinclude#reverse_exprs* + It is the expression string of the line analysis to perform + to substitute an include file name. When there is not it, + ignored. Refer to 'includeexpr' for the + description form. It is the dictionary of the character + string that assumed file type a key. + + Example: Perl +> + if !exists('g:neoinclude#reverse_exprs') + let g:neoinclude#reverse_exprs = {} + endif + let g:neoinclude#reverse_exprs.perl = + \ 'fnamemodify(substitute(v:fname, "/", "::", "g"), ":r")' +< + Default value is in "g:neoinclude#_reverse_exprs". + + *b:neoinclude_reverse_exprs* +b:neoinclude_reverse_exprs + Buffer local variable of |g:neoinclude#_reverse_exprs|. + +g:neoinclude#exts *g:neoinclude#exts* + It is the list of include file name extensions. When there + is not it, all file name is used. It is the dictionary of + the list that assumed file type a key. In order to use this + feature you have to initialize 'g:neoinclude#exts' as shown in + the following example. + + Example: C++ +> + if !exists('g:neoinclude#exts') + let g:neoinclude#exts = {} + endif + let g:neoinclude#exts.cpp = ['', 'h', 'hpp', 'hxx'] +< + Default value is in "g:neoinclude#_exts". + + *b:neoinclude_exts* +b:neoinclude_exts + Buffer local variable of |g:neoinclude#_exts|. + +g:neoinclude#delimiters *g:neoinclude#delimiters* + It is the delimiter character of include path. When there is + not it, "." is used. It is the dictionary of the string that + assumed file type a key. + + Default value is in "g:neoinclude#_delimiters". + + *b:neoinclude_delimiters* +b:neoinclude_delimiters + Buffer local variable of |g:neoinclude#_delimiters|. + +g:neoinclude#functions *g:neoinclude#functions* + This variable appoints the function name of the include + command. When there is not it, ignored. It is the dictionary + of the function name string that assumed file type a key. + + The function args are {lines} and {path}. + {lines} is the list of buffer lines. + {path} is the include path. + The return value is the list of include files. + + Default value is in "g:neoinclude#_functions". + + *b:neoinclude_functions* +b:neoinclude_functions + Buffer local variable of |g:neoinclude#_functions|. + +------------------------------------------------------------------------------ +FUNCTIONS *neoinclude-functions* + +============================================================================== +EXAMPLES *neoinclude-examples* +> + +< +============================================================================== +FAQ *neoinclude-faq* + +Q: The ctags cache takes too much time. +https://github.com/Shougo/neoinclude.vim/issues/9 + +A: You can disable it by |g:neoinclude#ctags_command| to empty string. +But you cannot use "include" source. You can use "file/include" source +though. + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: diff --git a/bundle/neoinclude.vim/plugin/neoinclude.vim b/bundle/neoinclude.vim/plugin/neoinclude.vim new file mode 100644 index 000000000..21569761e --- /dev/null +++ b/bundle/neoinclude.vim/plugin/neoinclude.vim @@ -0,0 +1,23 @@ +"============================================================================= +" FILE: neoinclude.vim +" AUTHOR: Shougo Matsushita +"============================================================================= + +if exists('g:loaded_neoinclude') + finish +endif + +" Add commands. +command! -complete=buffer -nargs=? NeoIncludeMakeCache + \ call neoinclude#include#make_cache() + +let g:loaded_neoinclude = 1 + +" Register source for NCM +autocmd User CmSetup call cm#register_source({ + \ 'name': 'neoinclude', + \ 'abbreviation': 'FI', + \ 'priority': 8, + \ 'cm_refresh': 'cm#sources#neoinclude#refresh', + \ 'cm_refresh_min_word_len': 0, + \ }) diff --git a/bundle/neoinclude.vim/rplugin/python3/deoplete/sources/file_include.py b/bundle/neoinclude.vim/rplugin/python3/deoplete/sources/file_include.py new file mode 100644 index 000000000..6899a6015 --- /dev/null +++ b/bundle/neoinclude.vim/rplugin/python3/deoplete/sources/file_include.py @@ -0,0 +1,26 @@ +#============================================================================= +# FILE: file_include.py +# AUTHOR: Shougo Matsushita +# License: MIT license +#============================================================================= + +from .base import Base + +import deoplete.util + +class Source(Base): + def __init__(self, vim): + Base.__init__(self, vim) + + self.name = 'file/include' + self.mark = '[FI]' + self.is_bytepos = True + self.min_pattern_length = 0 + + def get_complete_position(self, context): + return self.vim.call( + 'neoinclude#file_include#get_complete_position', context['input']) + + def gather_candidates(self, context): + return self.vim.call( + 'neoinclude#file_include#get_include_files', context['input']) diff --git a/bundle/neomake/.circleci/config.yml b/bundle/neomake/.circleci/config.yml new file mode 100644 index 000000000..c4c952d24 --- /dev/null +++ b/bundle/neomake/.circleci/config.yml @@ -0,0 +1,125 @@ +version: 2 + +common: &common + docker: + - image: neomake/vims-for-tests:50@sha256:7a9de350cebf98b1d67edc0fc74cc3e925a45b5a956ffbbf26a93d0262ada45d + working_directory: ~/repo + steps: + - checkout + - run: + name: Run tests + command: | + cc-test-reporter before-build + make --keep-going testcoverage TEST_VIM=$TEST_VIM + - run: + name: Handle coverage + command: | + set -x + mkdir test-results + cp -a .coverage_covimerage test-results/.coverage_covimerage.$CIRCLE_BUILD_NUM + + # Upload to codecov, which handles this per job itself. + coverage xml + # -Z: exit with 1 in case of failures. + codecov -Z -X search -X gcov -X pycov -f coverage.xml \ + -n "$CIRCLE_JOB" -F "${CIRCLE_JOB%%-*}" -e CIRCLE_JOB + set +x + - persist_to_workspace: + root: . + paths: + - test-results/ + +jobs: + nvim-038: + <<: *common + environment: + TEST_VIM=/vim-build/bin/neovim-v0.3.8 + nvim-017: + <<: *common + environment: + TEST_VIM=/vim-build/bin/neovim-v0.1.7 + nvim-master: + <<: *common + environment: + TEST_VIM=/vim-build/bin/neovim-master + vim-master: + <<: *common + environment: + TEST_VIM=/vim-build/bin/vim-master + vim-81: + <<: *common + environment: + TEST_VIM=/vim-build/bin/vim81 + vim-80: + <<: *common + environment: + TEST_VIM=/vim-build/bin/vim80 + vim-74-xenial: + <<: *common + environment: + TEST_VIM=/vim-build/bin/vim74-xenial + vim-74-trusty: + <<: *common + environment: + TEST_VIM=/vim-build/bin/vim74-trusty + vim-73: + <<: *common + environment: + TEST_VIM=/vim-build/bin/vim73 + + checkqa: + <<: *common + steps: + - checkout + - run: make checkqa + + coverage: + <<: *common + steps: + # TODO: checkout only necessary for covimerage plugin?! + # Writing/using .coveragerc only might be enough. + - checkout + - attach_workspace: + at: /tmp/workspace + - run: + name: Upload global coverage results + command: | + set -x + cp -a /tmp/workspace/test-results/.coverage_covimerage.* . + + coverage combine + coverage xml + + # Coveralls. + # Only TRAVIS_JOB_ID is used by python-coveralls. + env -u COVERALLS_PARALLEL TRAVIS_JOB_ID=$CIRCLE_WORKFLOW_ID coveralls + + # Codeclimate. + cc-test-reporter after-build + set +x + +workflows: + version: 2 + test: + jobs: + - nvim-038 + - nvim-017 + - vim-81 + - vim-80 + - vim-74-xenial + - vim-74-trusty + - vim-73 + - nvim-master + - vim-master + - checkqa + - coverage: + requires: + - nvim-master + - nvim-038 + - nvim-017 + - vim-master + - vim-81 + - vim-80 + - vim-74-xenial + - vim-74-trusty + - vim-73 diff --git a/bundle/neomake/.coveragerc b/bundle/neomake/.coveragerc new file mode 100644 index 000000000..67e7b5e19 --- /dev/null +++ b/bundle/neomake/.coveragerc @@ -0,0 +1,7 @@ +[run] +plugins = covimerage +data_file = .coverage_covimerage + +[report] +include = autoload/*,plugin/*,syntax/*,tests/* +omit = tests/fixtures/vim/* diff --git a/bundle/neomake/.dockerignore b/bundle/neomake/.dockerignore new file mode 100644 index 000000000..72e8ffc0d --- /dev/null +++ b/bundle/neomake/.dockerignore @@ -0,0 +1 @@ +* diff --git a/bundle/neomake/.github/ISSUE_TEMPLATE.md b/bundle/neomake/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..4d97a3777 --- /dev/null +++ b/bundle/neomake/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,42 @@ +### Expected behavior + + + +### Steps to reproduce + + + +### Output from :NeomakeInfo + + diff --git a/bundle/neomake/.gitignore b/bundle/neomake/.gitignore new file mode 100644 index 000000000..b0ef45745 --- /dev/null +++ b/bundle/neomake/.gitignore @@ -0,0 +1,11 @@ +.project.vim +neomake.log +scratch/ +tags +*.class +testmaker/ + +tests/shada.nvim +tests/vader +tests/viminfo +build/ diff --git a/bundle/neomake/.vintrc.yaml b/bundle/neomake/.vintrc.yaml new file mode 100644 index 000000000..a958f2bf9 --- /dev/null +++ b/bundle/neomake/.vintrc.yaml @@ -0,0 +1,6 @@ +policies: + ProhibitImplicitScopeVariable: + enabled: false + + ProhibitUnnecessaryDoubleQuote: + enabled: True diff --git a/bundle/neomake/Dockerfile.tests b/bundle/neomake/Dockerfile.tests new file mode 100644 index 000000000..f6fcbc7d8 --- /dev/null +++ b/bundle/neomake/Dockerfile.tests @@ -0,0 +1,63 @@ +# From https://github.com/tweekmonster/vim-testbed. +FROM testbed/vim:18@sha256:2b1872c68b6e9dfbfd8f804ad9727516ee971150142a80df354c244dcafa59c4 + +# Currently tested versions: +# - v7.3.429 (Ubuntu Precise, 12.04LTS) +# - v7.4.052 (Ubuntu Trusty, 14.04LTS) +# - v7.4.1689 (Ubuntu Xenial, 16.04LTS) +# - v8.0.586 (Updated Vim 8, https://vim.sourceforge.io/download.php) +# TODO: clean up names to make them usable as-is in CircleCI config. +# Uses fixed-profiling patch with vim81 (https://github.com/vim/vim/pull/2499). +RUN install_vim -tag v7.3.429 -name vim73 --with-features=huge -build \ + -tag v7.4.052 -name vim74-trusty --with-features=huge -build \ + -tag v7.4.1689 -name vim74-xenial --with-features=huge -build \ + -tag v8.0.0586 -name vim80 -py2 -build \ + -tag neovim:v0.1.7 -build \ + && rm -rf /vim-build/**/runtime/tutor +RUN install_vim -tag v8.1.0622 -name vim81 -build \ + -tag neovim:v0.3.8 -py3 -build \ + && rm -rf /vim-build/**/runtime/tutor + +ENV NEOMAKE_DOCKERFILE_UPDATE=2020-01-27 + +# Git master in a separate layer, since the above is meant to be stable. +RUN install_vim -tag master -build \ + -tag neovim:master -build \ + && rm -rf /vim-build/**/runtime/tutor + +# Install tools for running tests (busybox's grep does not have --line-number). +# openssh for CircleCI to improve Git checkout. +RUN apk --no-cache add bash curl grep make openssh-client + +# Codeclimate reporter. +RUN curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > /usr/local/bin/cc-test-reporter \ + && chmod +x /usr/local/bin/cc-test-reporter + +# Install dep plugins (test runner and those used during tests). +# Keeps git and installs ssh for CircleCI's checkout (and diffing for changed +# files). grep for checks. +ENV NEOMAKE_TESTS_DEP_PLUGINS_DIR=/neomake-deps +ENV VIMHELPLINT_DIR=$NEOMAKE_TESTS_DEP_PLUGINS_DIR/vim-vimhelplint +RUN mkdir $NEOMAKE_TESTS_DEP_PLUGINS_DIR +RUN apk --no-cache add git \ + && git clone -q --depth=1 -b display-source-with-exceptions https://github.com/blueyed/vader.vim $NEOMAKE_TESTS_DEP_PLUGINS_DIR/vader \ + && git clone -q --depth=1 https://github.com/tpope/vim-fugitive $NEOMAKE_TESTS_DEP_PLUGINS_DIR/vim-fugitive \ + && git clone -q --depth=1 https://github.com/machakann/vim-vimhelplint $NEOMAKE_TESTS_DEP_PLUGINS_DIR/vim-vimhelplint \ + && git clone -q --depth=1 https://github.com/syngan/vim-vimlint /tools/vim-vimlint \ + && git clone -q --depth=1 https://github.com/ynkdir/vim-vimlparser /tools/vim-vimlparser +RUN test -f /vim-build/bin/vim81 && ln -s /vim-build/bin/vim81 /usr/local/bin/vim +RUN printf '#!/bin/sh -x\n/tools/vim-vimlint/bin/vimlint.sh -l /tools/vim-vimlint -p /tools/vim-vimlparser "$@"\n' > /usr/local/bin/vimlint +RUN chmod +x /usr/local/bin/vimlint + +# Install covimerage and vint. +RUN apk --no-cache add python3 \ + && pip3 install -U pip \ + && pip3 install --no-cache-dir 'coverage<5' python-coveralls covimerage==0.2.1 vim-vint==0.3.21 \ + && rm -rf /usr/include /usr/lib/python*/turtle* /usr/lib/python*/tkinter \ + && pip3 uninstall --yes pip \ + && curl https://codecov.io/bash -o /usr/bin/codecov \ + && chmod +x /usr/bin/codecov \ + && cd /usr/bin && ln -s python3 python + +RUN adduser -D -s /bin/bash neomake +USER neomake diff --git a/bundle/neomake/LICENSE b/bundle/neomake/LICENSE new file mode 100644 index 000000000..828009683 --- /dev/null +++ b/bundle/neomake/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 benekastah + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/bundle/neomake/Makefile b/bundle/neomake/Makefile new file mode 100644 index 000000000..b7f48e455 --- /dev/null +++ b/bundle/neomake/Makefile @@ -0,0 +1,413 @@ +# Do not let mess "cd" with user-defined paths. +CDPATH:= + +TEST_SHELL:=$(shell command -v bash 2>/dev/null) +ifeq ($(TEST_SHELL),) + $(error Could not determine TEST_SHELL (defaults to bash)) +endif +# This is expected in tests. +TEST_VIM_PREFIX:=SHELL=$(TEST_SHELL) +SHELL:=$(TEST_SHELL) -o pipefail + +# Use nvim if it is installed, otherwise vim. +ifeq ($(TEST_VIM),) +ifeq ($(shell command -v nvim 2>/dev/null),) + TEST_VIM:=vim +else + TEST_VIM:=nvim +endif +endif + +IS_NEOVIM=$(findstring nvim,$(TEST_VIM))$(findstring neovim,$(TEST_VIM)) +test: $(if $(IS_NEOVIM),testnvim,testvim) +test_interactive: $(if $(TEST_VIM),$(if $(IS_NEOVIM),testnvim_interactive,testvim_interactive),testnvim_interactive testvim_interactive) + +VADER:=Vader! +VADER_OPTIONS:=-q +VADER_ARGS=tests/all.vader +VIM_ARGS='+$(VADER) $(VADER_OPTIONS) $(VADER_ARGS)' + +NEOMAKE_TESTS_DEP_PLUGINS_DIR?=build/vim/plugins +TESTS_VADER_DIR:=$(NEOMAKE_TESTS_DEP_PLUGINS_DIR)/vader +$(TESTS_VADER_DIR): + mkdir -p $(dir $@) + git clone -q --depth=1 -b display-source-with-exceptions https://github.com/blueyed/vader.vim $@ +TESTS_FUGITIVE_DIR:=$(NEOMAKE_TESTS_DEP_PLUGINS_DIR)/vim-fugitive +$(TESTS_FUGITIVE_DIR): + mkdir -p $(dir $@) + git clone -q --depth=1 https://github.com/tpope/vim-fugitive $@ + +DEP_PLUGINS=$(TESTS_VADER_DIR) $(TESTS_FUGITIVE_DIR) + +TEST_VIMRC:=tests/vim/vimrc + +testwatch: override export VADER_OPTIONS+=-q +testwatch: + contrib/run-tests-watch + +testwatchx: override export VADER_OPTIONS+=-x +testwatchx: testwatch + +testx: override VADER_OPTIONS+=-x +testx: test +testnvimx: override VADER_OPTIONS+=-x +testnvimx: testnvim +testvimx: override VADER_OPTIONS+=-x +testvimx: testvim + +# Set Neovim logfile destination to prevent `.nvimlog` being created. +testnvim: export NVIM_LOG_FILE:=/dev/stderr +testnvim: TEST_VIM:=nvim +testnvim: TEST_VIM_PREFIX+=VADER_OUTPUT_FILE=/dev/stderr +testnvim: | build/vim-test-home $(DEP_PLUGINS) + $(call func-run-vim) + +testvim: TEST_VIM:=vim +testvim: | build/vim-test-home $(DEP_PLUGINS) + $(call func-run-vim) + +# Add coloring to Vader's output: +# 1. failures (includes pending) in red "(X)" +# 2. test case header in bold "(2/2)" +# 3. Neomake's debug log messages in less intense grey +# 4. non-Neomake log lines (e.g. from :Log) in bold/bright yellow. +_SED_HIGHLIGHT_ERRORS:=| contrib/highlight-log --compact vader +# Need to close stdin to fix spurious 'sed: couldn't write X items to stdout: Resource temporarily unavailable'. +# NOTE: uses &1 >/dev/null Vim: Error reading input, exiting... +# > Vim: Finished. +# For Vim `-s /dev/null` is used to skip the 2s delay with warning +# "Vim: Warning: Output is not to a terminal". +COVERAGE_FILE:=.coverage_covimerage +_COVIMERAGE=$(if $(filter-out 0,$(NEOMAKE_DO_COVERAGE)),covimerage run --data-file $(COVERAGE_FILE) --append --no-report ,) +define func-run-vim + $(info Using: $(shell $(TEST_VIM_PREFIX) "$(TEST_VIM)" --version | head -n2)) + ($(_COVIMERAGE)$(if $(TEST_VIM_PREFIX),env $(TEST_VIM_PREFIX) ,)"$(TEST_VIM)" \ + $(if $(IS_NEOVIM),$(if $(_REDIR_STDOUT),--headless,),-X $(if $(_REDIR_STDOUT),-s /dev/null,)) \ + --noplugin -Nu $(TEST_VIMRC) -i NONE $(VIM_ARGS) $(_REDIR_STDOUT)) $(_SED_HIGHLIGHT_ERRORS) +endef + +# Interactive tests, keep Vader open. +_run_interactive: VADER:=Vader +_run_interactive: _REDIR_STDOUT:= +_run_interactive: + $(call func-run-vim) + +testvim_interactive: TEST_VIM:=vim -X +testvim_interactive: _run_interactive + +testnvim_interactive: TEST_VIM:=nvim +testnvim_interactive: _run_interactive + + +# Manually invoke Vim, using the test setup. This helps with building tests. +runvim: VIM_ARGS:= +runvim: testvim_interactive + +runnvim: VIM_ARGS:= +runnvim: testnvim_interactive + +# Add targets for .vader files, absolute and relative. +# This can be used with `b:dispatch = ':Make %'` in Vim. +TESTS:=$(wildcard tests/*.vader tests/*/*.vader) +uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) +_TESTS_REL_AND_ABS:=$(call uniq,$(abspath $(TESTS)) $(TESTS)) +FILE_TEST_TARGET=$(if $(IS_NEOVIM),testnvim,testvim) +$(_TESTS_REL_AND_ABS): + $(MAKE) --no-print-directory $(FILE_TEST_TARGET) VADER_ARGS='$@' +.PHONY: $(_TESTS_REL_AND_ABS) + +testcoverage: COVERAGE_VADER_ARGS:=tests/main.vader $(wildcard tests/isolated/*.vader) +testcoverage: + $(RM) $(COVERAGE_FILE) + @ret=0; \ + for testfile in $(COVERAGE_VADER_ARGS); do \ + $(MAKE) --no-print-directory test VADER_ARGS=$$testfile NEOMAKE_DO_COVERAGE=1 || (( ++ret )); \ + done; \ + exit $$ret + +tags: + ctags -R --langmap=vim:+.vader +.PHONY: tags + +# Linters, called from .travis.yml. +LINT_ARGS:=./plugin ./autoload + +# Vint. +VINT_BIN=$(shell command -v vint 2>/dev/null || echo build/vint/bin/vint) +build/vint: | build + $(shell command -v virtualenv 2>/dev/null || echo python3 -m venv) $@ +build/vint/bin/vint: | build/vint + build/vint/bin/pip install --quiet vim-vint +vint: | $(VINT_BIN) + $| --color $(LINT_ARGS) +vint-errors: | $(VINT_BIN) + $| --color --error $(LINT_ARGS) + +# vimlint +VIMLINT_BIN=$(shell command -v vimlint 2>/dev/null || echo build/vimlint/bin/vimlint.sh -l build/vimlint -p build/vimlparser) +build/vimlint/bin/vimlint.sh: build/vimlint build/vimlparser +build/vimlint: | build + git clone -q --depth=1 https://github.com/syngan/vim-vimlint $@ +build/vimlparser: | build + git clone -q --depth=1 https://github.com/ynkdir/vim-vimlparser $@ +VIMLINT_OPTIONS=-u -e EVL102.l:_=1 -e 'EVL103.a:_.*=1' +vimlint: | $(firstword $(VIMLINT_BIN)) + $(VIMLINT_BIN) $(VIMLINT_OPTIONS) $(LINT_ARGS) +vimlint-errors: | $(firstword VIMLINT_BIN) + $(VIMLINT_BIN) $(VIMLINT_OPTIONS) -E $(LINT_ARGS) + +build build/vim-test-home: + mkdir $@ +build/vim-test-home: | build +build/vimhelplint: | build + cd build \ + && wget -O- https://github.com/machakann/vim-vimhelplint/archive/master.tar.gz \ + | tar xz \ + && mv vim-vimhelplint-master vimhelplint +vimhelplint: | $(if $(VIMHELPLINT_DIR),,build/vimhelplint) + contrib/vimhelplint doc/neomake.txt + +# Run tests in dockerized Vims. +DOCKER_REPO:=neomake/vims-for-tests +DOCKER_TAG:=50 +NEOMAKE_DOCKER_IMAGE?= +DOCKER_IMAGE:=$(if $(NEOMAKE_DOCKER_IMAGE),$(NEOMAKE_DOCKER_IMAGE),$(DOCKER_REPO):$(DOCKER_TAG)) +DOCKER_STREAMS:=-ti +DOCKER_ARGS:= +DOCKER=docker run $(DOCKER_STREAMS) --rm \ + -v $(PWD):/testplugin \ + -w /testplugin \ + -e NEOMAKE_TEST_NO_COLORSCHEME \ + $(DOCKER_ARGS) $(DOCKER_IMAGE) +docker_image: + docker build -f Dockerfile.tests -t $(DOCKER_REPO):$(DOCKER_TAG) . +docker_push: + docker push $(DOCKER_REPO):$(DOCKER_TAG) +docker_update_latest: + docker tag $(DOCKER_REPO):$(DOCKER_TAG) $(DOCKER_REPO):latest + docker push $(DOCKER_REPO):latest +docker_update_image: + @git diff --cached --exit-code >/dev/null || { echo "WARN: git index is not clean."; } + @if git diff --exit-code -- Makefile >/dev/null; then \ + sed -i '/^DOCKER_TAG:=/s/:=.*/:=$(shell echo $$(($(DOCKER_TAG)+1)))/' Makefile; \ + else \ + echo "WARN: Makefile is not clean. Not updating."; \ + fi + @if git diff --exit-code -- Dockerfile.tests >/dev/null; then \ + sed -i '/^ENV NEOMAKE_DOCKERFILE_UPDATE=/s/=.*/=$(shell date +%Y-%m-%d)/' Dockerfile.tests; \ + else \ + echo "WARN: Dockerfile.tests is not clean. Not updating."; \ + fi + make docker_image + make docker_test DOCKER_VIM=vim81 + @echo "Done. Use 'make docker_push' to push it, and then update .circleci/config.yml." + +DOCKER_VIMS:=vim73 vim74-trusty vim74-xenial vim80 vim81 \ + neovim-v0.1.7 neovim-v0.3.8 neovim-master vim-master +_DOCKER_VIM_TARGETS:=$(addprefix docker_test-,$(DOCKER_VIMS)) + +docker_test_all: $(_DOCKER_VIM_TARGETS) + +$(_DOCKER_VIM_TARGETS): + $(MAKE) docker_test DOCKER_VIM=$(patsubst docker_test-%,%,$@) + +_docker_test: DOCKER_VIM:=vim81 +_docker_test: DOCKER_MAKE_TARGET=$(DOCKER_MAKE_TEST_TARGET) \ + TEST_VIM='/vim-build/bin/$(DOCKER_VIM)' \ + VADER_OPTIONS="$(VADER_OPTIONS)" VADER_ARGS="$(VADER_ARGS)" \ + _REDIR_STDOUT="$(_REDIR_STDOUT)" \ + $(DOCKER_MAKE_TEST_ARGS) +_docker_test: docker_make +docker_test: DOCKER_MAKE_TEST_TARGET:=test +docker_test: DOCKER_STREAMS:=-t +docker_test: _docker_test + +docker_test_interactive: DOCKER_MAKE_TEST_TARGET:=test_interactive +docker_test_interactive: DOCKER_STREAMS:=-ti +docker_test_interactive: _docker_test + +docker_testcoverage: DOCKER_MAKE_TEST_TARGET:=testcoverage +# Pick up VADER_ARGS from command line for COVERAGE_VADER_ARGS. +docker_testcoverage: DOCKER_MAKE_TEST_ARGS:=$(if $(filter command line,$(origin COVERAGE_VADER_ARGS)),COVERAGE_VADER_ARGS="$(COVERAGE_VADER_ARGS)",$(if $(filter command line,$(origin VADER_ARGS)),COVERAGE_VADER_ARGS="$(VADER_ARGS)",)) +docker_testcoverage: DOCKER_STREAMS:=-t +docker_testcoverage: _docker_test + sed -i 's~/testplugin/~$(CURDIR)/~g' $(COVERAGE_FILE) + coverage report -m + +docker_run: DOCKER_ARGS:=-e PATH=/vim-build/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +docker_run: $(DEP_PLUGINS) +docker_run: + $(DOCKER) $(if $(DOCKER_RUN),$(DOCKER_RUN),bash) + +# Pass down/through MAKEFLAGS explicitly (not available in Docker env). +docker_make: DOCKER_RUN=$(MAKE) -$(MAKEFLAGS) $(DOCKER_MAKE_TARGET) +docker_make: docker_run + +docker_check: DOCKER_MAKE_TARGET=check_docker +docker_check: docker_make + +docker_vimhelplint: + $(MAKE) docker_make DOCKER_MAKE_TARGET=vimhelplint + +_ECHO_DOCKER_VIMS:=ls /vim-build/bin | grep vim | sort +docker_list_vims: + docker run --rm $(DOCKER_IMAGE) $(_ECHO_DOCKER_VIMS) + +check_lint_diff: + @# NOTE: does not see changed files for builds on master. + @set -e; \ + echo "Looking for changed files (to origin/master)."; \ + CHANGED_VIM_FILES=($$(git diff-tree --no-commit-id --name-only --diff-filter=AM -r origin/master.. \ + | grep '\.vim$$' | grep -v '^tests/fixtures')) || true; \ + ret=0; \ + if [ "$${#CHANGED_VIM_FILES[@]}" -eq 0 ]; then \ + echo 'No .vim files changed.'; \ + else \ + MAKE_ARGS="LINT_ARGS=$${CHANGED_VIM_FILES[*]}"; \ + echo "== Running \"make vimlint $$MAKE_ARGS\" =="; \ + $(MAKE) --no-print-directory vimlint "$$MAKE_ARGS" || (( ret+=1 )); \ + echo "== Running \"make vint $$MAKE_ARGS\" =="; \ + $(MAKE) --no-print-directory vint "$$MAKE_ARGS" || (( ret+=2 )); \ + fi; \ + if ! git diff-tree --quiet --exit-code --diff-filter=AM -r origin/master.. -- doc/neomake.txt; then \ + echo "== Running \"make vimhelplint\" for changed doc/neomake.txt =="; \ + $(MAKE) --no-print-directory vimhelplint || (( ret+=4 )); \ + fi; \ + exit $$ret + +check_lint: vimlint vint vimhelplint + +# Checks to be run within the Docker image. +check_docker: + @:; set -e; ret=0; \ + echo '== Checking for DOCKER_VIMS to be in sync'; \ + vims=$$($(_ECHO_DOCKER_VIMS)); \ + docker_vims="$$(printf '%s\n' $(DOCKER_VIMS) | sort)"; \ + if ! [ "$$vims" = "$$docker_vims" ]; then \ + echo "DOCKER_VIMS is out of sync with Vims in image."; \ + diff <(echo "$$vims") <(echo "$$docker_vims"); \ + (( ret+=8 )); \ + fi; \ + exit $$ret + +# Like CircleCI runs them. +check_in_docker: DOCKER_MAKE_TARGET=checkqa +check_in_docker: docker_make + +# Run in CircleCI. +checkqa: + $(MAKE) -k check check_docker check_lint_diff + +check: + @:; set -e; ret=0; \ + [ $$TERM = dumb ] && export TERM=xterm; \ + echo_bold() { tput bold; echo "$$@"; tput sgr0; }; \ + echo '== Checking that all tests are included'; \ + for f in $(filter-out all.vader main.vader isolated.vader,$(notdir $(shell git ls-files tests/*.vader))); do \ + if ! grep -q "^Include.*: $$f" tests/main.vader; then \ + echo_bold "Test not included in main.vader: $$f" >&2; ret=1; \ + fi; \ + done; \ + for f in $(notdir $(shell git ls-files tests/isolated/*.vader)); do \ + if ! grep -q "^Include.*: isolated/$$f" tests/isolated.vader; then \ + echo_bold "Test not included in isolated.vader: $$f" >&2; ret=1; \ + fi; \ + done; \ + echo '== Checking for absent Before sections in tests'; \ + if grep '^Before:' tests/*.vader; then \ + echo_bold "Before: should not be used in tests itself, because it overrides the global one."; \ + (( ret+=2 )); \ + fi; \ + echo '== Checking for absent :Log calls'; \ + if git --no-pager grep --line-number --color --perl-regexp '^(\s*au.*\b)?\s*Log\b' \ + -- :^tests/include/init.vim :^tests/include/setup.vader; then \ + echo_bold "Found Log commands."; \ + (( ret+=4 )); \ + fi; \ + echo '== Checking tests'; \ + output="$$(grep --line-number --color AssertThrows -A1 tests/*.vader)"; \ + output="$(echo "$$output" \ + | grep -E '^[^[:space:]]+- ' \ + | grep -v g:vader_exception | sed -e s/-/:/ -e s/-// || true)"; \ + if [[ -n "$$output" ]]; then \ + echo_bold 'AssertThrows used without checking g:vader_exception:' >&2; \ + echo "$$output" >&2; \ + (( ret+=16 )); \ + fi; \ + echo '== Running custom checks'; \ + tput bold; \ + contrib/vim-checks $(LINT_ARGS) || (( ret+= 16 )); \ + tput sgr0; \ + exit $$ret + +NEOMAKE_LOG:=/tmp/neomake.log +tail_log: + fifo=$(shell mktemp -u); \ + mkfifo $$fifo; \ + tail -f $(NEOMAKE_LOG) \ + | $(CURDIR)/contrib/highlight-log >> $$fifo & \ + less --force --chop-long-lines +F $$fifo + +clean: + $(RM) -r build +.PHONY: clean + +# Fixtures {{{ + +# A function to define targets/rules for fixture generation. +# Args: +# 1: the tool (bin) and input/output dir. +# 2: arguments for the tool +# NOTE: uses "sed -i.bak" for MacOS's default sed. +define func-generate-fixture +tests/fixtures/output/$1: + mkdir -p $$@ +tests/fixtures/output/$1/%.stderr tests/fixtures/output/$1/%.stdout tests/fixtures/output/$1/%.exitcode: tests/fixtures/input/$1/% | tests/fixtures/output/$1 + @baseout=tests/fixtures/output/$1/$$*; \ + echo "Generating $$$$baseout"; \ + $1 $2 $$< >$$$$baseout.stdout 2>$$$$baseout.stderr; \ + ret=$$$$?; \ + printf $$$$ret > $$$$baseout.exitcode; \ + if ! [ -f $$$$baseout.stdout ]; then \ + echo "Missing output: $$$$baseout.stdout." >&2; exit 1; \ + fi; \ + sed -i.bak -e "s~$(CURDIR)/~/tmp/neomake-tests/~g" \ + $$$$baseout.stdout $$$$baseout.stderr; \ + $(RM) $$$$baseout.stdout.bak $$$$baseout.stderr.bak +endef + +# Call and eval the above function to generate rules for different tools. +$(eval $(call func-generate-fixture,puppet,parser validate --color=false)) +$(eval $(call func-generate-fixture,puppet-lint,--log-format "%{path}:%{line}:%{column}:%{kind}:[%{check}] %{message}")) +$(eval $(call func-generate-fixture,xmllint,--xinclude --postvalid --noout)) +$(eval $(call func-generate-fixture,zsh,-n)) + +_FIXTURES_INPUT:=$(wildcard tests/fixtures/input/*/*) +_FIXTURES_OUTPUT:=$(patsubst tests/fixtures/input/%,tests/fixtures/output/%,$(addsuffix .stdout,$(_FIXTURES_INPUT)) $(addsuffix .stderr,$(_FIXTURES_INPUT))) + +fixtures: $(_FIXTURES_OUTPUT) +.PHONY: fixtures + +fixtures-rebuild: + $(RM) tests/fixtures/output/*/*.stdout tests/fixtures/output/*/*.stderr + $(MAKE) --keep-going fixtures +.PHONY: fixtures-rebuild +# }}} + +.PHONY: vint vint-errors vimlint vimlint-errors +.PHONY: test testnvim testvim testnvim_interactive testvim_interactive +.PHONY: runvim runnvim tags _run_tests diff --git a/bundle/neomake/README.md b/bundle/neomake/README.md new file mode 100644 index 000000000..f15bba437 --- /dev/null +++ b/bundle/neomake/README.md @@ -0,0 +1,188 @@ +# [![Neomake](https://cloud.githubusercontent.com/assets/111942/22717189/9e3e1760-ed67-11e6-94c5-e8955869d6d0.png)](#neomake) + +[![Build Status](https://circleci.com/gh/neomake/neomake.png?style=shield)](https://circleci.com/gh/neomake/neomake) +[![codecov](https://codecov.io/gh/neomake/neomake/branch/master/graph/badge.svg)](https://codecov.io/gh/neomake/neomake) +[![Coveralls](https://coveralls.io/repos/github/neomake/neomake/badge.svg)](https://coveralls.io/github/neomake/neomake) + +Neomake is a plugin for [Vim]/[Neovim] to asynchronously run programs. + +You can use it instead of the built-in `:make` command (since it can pick +up your `'makeprg'` setting), but its focus is on providing an extra layer +of makers based on the current file (type) or project. +Its origin is a proof-of-concept for [Syntastic] to be asynchronous. + +## Requirements + +### Neovim + +With Neovim any release will do (after 0.0.0-alpha+201503292107). + +### Vim + +The minimal Vim version supported by Neomake is 7.4.503 (although if you don't +use `g:neomake_logfile` older versions will probably work fine as well). + +You need Vim 8.0.0027 or later for asynchronous features. + +## Installation + +Use your preferred installation method for Vim plugins. + +With [vim-plug](https://github.com/junegunn/vim-plug) that would mean to add +the following to your vimrc: + +```vim +Plug 'neomake/neomake' +``` + +## Setup + +If you want to run Neomake automatically (in file mode), you can configure it +in your `vimrc` by using `neomake#configure#automake`, e.g. by picking one of: + +```vim +" When writing a buffer (no delay). +call neomake#configure#automake('w') +" When writing a buffer (no delay), and on normal mode changes (after 750ms). +call neomake#configure#automake('nw', 750) +" When reading a buffer (after 1s), and when writing (no delay). +call neomake#configure#automake('rw', 1000) +" Full config: when writing or reading a buffer, and on changes in insert and +" normal mode (after 500ms; no delay when writing). +call neomake#configure#automake('nrwi', 500) +``` + +(Any function calls like these need to come after indicating the end of plugins +to your plugin manager, e.g. after `call plug#end()` with vim-plug.) + +### Advanced setup + +The author liked to use the following, which uses different modes based on if +your laptop runs on battery (for MacOS or Linux): + +```vim +function! MyOnBattery() + if has('macunix') + return match(system('pmset -g batt'), "Now drawing from 'Battery Power'") != -1 + elseif has('unix') + return readfile('/sys/class/power_supply/AC/online') == ['0'] + endif + return 0 +endfunction + +if MyOnBattery() + call neomake#configure#automake('w') +else + call neomake#configure#automake('nw', 1000) +endif +``` + +See `:help neomake-automake` (in [doc/neomake.txt](doc/neomake.txt)) for more +information, e.g. how to configure it based on certain autocommands explicitly, +and for details about which events get used for the different string-based +modes. + +## Usage + +When calling `:Neomake` manually (or automatically through +`neomake#configure#automake` (see above)) it will populate the window's +location list with any issues that get reported by the maker(s). + +You can then navigate them using the built-in methods like `:lwindow` / +`:lopen` (to view the list) and `:lprev` / `:lnext` to go back and forth. + +You can configure Neomake to open the list automatically: + +```vim +let g:neomake_open_list = 2 +``` + +Please refer to [`:help neomake.txt`] for more details on configuration. + +### Maker types + +There are two types of makers: file makers (acting on the current buffer) and +project makers (acting globally). + +You invoke file makers using `:Neomake`, and project makers using `:Neomake!`. + +See [`:help neomake.txt`] for more details. + +### Manually run a maker + +You can run a specific maker on the current file by specifying the maker's +name, e.g. `:Neomake jshint` (you can use Vim's completion here to complete +maker names). + +## Default makers + +For a list of default makers please see the +[Makers page in the wiki](https://github.com/neomake/neomake/wiki/Makers). + +# Contributing + +If you find this plugin useful, please contribute your maker recipes to the +repository! Check out `autoload/neomake/makers/**/*.vim` for existing makers. + +This is a community driven project, and maintainers are wanted. +Please contact [@blueyed](https://github.com/blueyed) if you are interested. +You should have a good profile of issue triaging and PRs on this repo already. + +## Hacking / Testing + +We are using [Vader](https://github.com/junegunn/vader.vim) for our tests. + +### Logging + +Set `let g:neomake_logfile = '/tmp/neomake.log'` (dynamically or in your vimrc) +to enable debug logging to the given file. +From Neomake's source tree you can then run `make tail_log`, which will color +the output and pipe it into `less`, which folds long lines by default and will +follow the output (like `tail -f`). +You can use Ctrl-C to interrupt for scrolling etc, and then F to follow again. + +### Running tests + +#### Run all tests against your local Neovim and Vim + + make test + +#### Run a specific test file + + make tests/integration.vader + +#### Run some specific tests for Vim + + make testvim VADER_ARGS=tests/integration.vader + +### Dockerized tests + +The `docker_test` target runs tests for a specific Vim version. +See `Dockerfile.tests` for the Vim versions provided in the Docker image. + +The image for this gets pulled from Docker Hub via +[neomake/vims-for-tests](https://hub.docker.com/r/neomake/vims-for-tests/). + +NOTE: the Docker image used for tests does not include (different versions) +of Neovim at the moment. + +#### Run all tests for Vim 8.0.586 + + make docker_test DOCKER_VIM=vim-8.0.586 + +#### Run all tests against all Vims in the Docker image + + make docker_test_all + +## Donate + + * Bitcoin: 1JscK5VaHyBhdE2ayVr63hDc6Mx94m9Y7R + * Flattr: [![Flattr](http://api.flattr.com/button/flattr-badge-large.png)]( +https://flattr.com/submit/auto?user_id=blueyed&url=https://github.com/neomake/neomake&title=Neomake&language=en_GB&tags=github&category=software) + +[Neovim]: http://neovim.org/ +[Vim]: http://vim.org/ +[Syntastic]: https://github.com/scrooloose/syntastic +[cargo]: https://github.com/neomake/neomake/blob/master/autoload/neomake/makers/cargo.vim +[mvn]: https://github.com/neomake/neomake/blob/master/autoload/neomake/makers/mvn.vim +[`:help neomake.txt`]: doc/neomake.txt diff --git a/bundle/neomake/autoload/neomake.vim b/bundle/neomake/autoload/neomake.vim new file mode 100644 index 000000000..940f53709 --- /dev/null +++ b/bundle/neomake/autoload/neomake.vim @@ -0,0 +1,2608 @@ +" vim: ts=4 sw=4 et +scriptencoding utf-8 + +if !exists('s:make_id') + let s:make_id = 0 +endif +" A map of make_id to options, e.g. cwd when jobs where started. +if !exists('s:make_info') + let s:make_info = {} +endif +if !exists('s:job_id') + let s:job_id = 1 +endif +if !exists('s:jobs') + let s:jobs = {} +endif +if !exists('s:map_job_ids') + let s:map_job_ids = {} +endif + +" Errors by [maker_type][bufnr][lnum] +let s:current_errors = {'project': {}, 'file': {}} + +if !has('nvim') + let s:kill_vim_timers = {} +endif + +" A list of references to keep when profiling. +" Workaround for https://github.com/vim/vim/issues/2350, where +" https://github.com/blueyed/vader.vim/commit/e66d91dea is not enough. +if v:profiling + let s:hack_keep_refs_for_profiling = [] +endif + +" Can Neovim buffer output? +let s:nvim_can_buffer_output = has('nvim-0.3.0') ? 1 : 0 + +" Private function to access script-local variables during tests. +function! neomake#_get_s() abort + return s: +endfunction + +" Sentinels. +let s:unset_list = [] +let s:unset_dict = {} +let s:unset = {} + +let s:can_use_env_in_job_opts = has('patch-8.0.0902') && has('patch-8.0.1832') + +let s:is_testing = exists('g:neomake_test_messages') + +let s:async = has('nvim') + \ || has('channel') && has('job') && has('patch-8.0.0027') +function! neomake#has_async_support() abort + return s:async +endfunction + +if v:version >= 704 || (v:version == 703 && has('patch1058')) + function! s:function(name) abort + return function(a:name) + endfunction +else + " Older Vim does not handle s: function references across files. + function! s:function(name) abort + return function(substitute(a:name,'^s:',matchstr(expand(''), '.*\zs\d\+_'),'')) + endfunction +endif + +function! s:sort_jobs(a, b) abort + return a:a.id - a:b.id +endfunction + +function! neomake#GetJobs(...) abort + if empty(s:jobs) + return [] + endif + let jobs = copy(values(s:jobs)) + if a:0 + call filter(jobs, 'index(a:1, v:val.id) != -1') + endif + return sort(jobs, function('s:sort_jobs')) +endfunction + +function! neomake#GetJob(job_id) abort + return s:jobs[a:job_id] +endfunction + +" Not documented, only used in tests for now. +function! neomake#GetStatus() abort + return { + \ 'last_make_id': s:make_id, + \ 'make_info': s:make_info, + \ 'action_queue': g:neomake#action_queue#_s.action_queue, + \ } +endfunction + +" neomake#GetMakeOptions: not documented, only used internally for now. +" More lax when not being used in tests to avoid errors, but fail during tests. +if s:is_testing + function! neomake#GetMakeOptions(...) abort + let make_id = a:0 ? a:1 : s:make_id + try + let r = s:make_info[make_id] + catch + let msg = printf('GetMakeOptions failed: %s (in %s)', v:exception, v:throwpoint) + call vader#log(msg) + let g:neomake_test_errors += [msg] + return {'verbosity': 3} + endtry + return r + endfunction +else + function! neomake#GetMakeOptions(...) abort + let make_id = a:0 ? a:1 : s:make_id + if !has_key(s:make_info, make_id) + call neomake#log#warning('warning: missing make_info key: '.make_id.'.') + return {'verbosity': get(g:, 'neomake_verbose', 1)} + endif + return s:make_info[make_id] + endfunction +endif + +function! neomake#ListJobs() abort + if !s:async + echom 'This Vim version has no support for jobs.' + return + endif + let jobs = neomake#GetJobs() + if empty(jobs) + return + endif + echom 'make_id | job_id | name/maker' + for jobinfo in jobs + let desc = !empty(jobinfo.maker.name) && jobinfo.name != jobinfo.maker.name + \ ? jobinfo.name. ' ('.jobinfo.maker.name.')' + \ : jobinfo.name + echom printf('%7d | %6d | %s', jobinfo.make_id, jobinfo.id, desc) + endfor +endfunction + +function! neomake#CancelMake(...) abort + let make_id = a:0 ? a:1 : s:make_id + if !has_key(s:make_info, make_id) + call neomake#log#error('CancelMake: make not found: '.make_id.'.') + return 0 + endif + let bang = a:0 > 1 ? a:1 : 0 + let make_info = s:make_info[make_id] + call neomake#log#debug('Canceling make.', make_info) + let make_info.canceled = 1 + let jobs = filter(copy(values(s:jobs)), 'v:val.make_id == make_id') + call s:abort_next_makers(make_id) + for job in jobs + call neomake#CancelJob(job.id, bang) + endfor + call neomake#action_queue#clean(make_info) + " Ensure that make info gets cleaned really, e.g. if there were no jobs yet. + if has_key(s:make_info, make_id) + call s:clean_make_info(make_info, bang) + endif + return 1 +endfunction + +function! neomake#CancelAllMakes(...) abort + let bang = a:0 ? a:1 : 0 + for make_id in keys(s:make_info) + call neomake#CancelMake(make_id, bang) + endfor +endfunction + +" Returns 1 if a job was canceled, 0 otherwise. +function! neomake#CancelJob(job_id, ...) abort + let job_id = type(a:job_id) == type({}) ? a:job_id.id : +a:job_id + let remove_always = a:0 ? a:1 : 0 + let jobinfo = get(s:jobs, job_id, {}) + call neomake#log#debug('Canceling job.', jobinfo) + + call neomake#action_queue#clean(empty(jobinfo) ? {'id': job_id} : jobinfo) + + if empty(jobinfo) + call neomake#log#error('CancelJob: job not found: '.job_id.'.') + return 0 + endif + + if get(jobinfo, 'canceled', 0) + call neomake#log#info('Job was canceled already.', jobinfo) + if remove_always + call s:CleanJobinfo(jobinfo) + endif + return 0 + endif + let jobinfo.canceled = 1 + + let ret = 0 + if get(jobinfo, 'finished') + call neomake#log#debug('Removing already finished job.', jobinfo) + elseif has_key(jobinfo, 'exit_code') + call neomake#log#debug('Job exited already.', jobinfo) + elseif has_key(jobinfo.maker, 'get_list_entries') + call neomake#log#debug('Removing job for get_list_entries.', jobinfo) + elseif s:async + if has('nvim') + let job = jobinfo.nvim_job + call neomake#log#debug(printf('Stopping Neovim job: %s.', job), jobinfo) + else + let job = jobinfo.vim_job + call neomake#log#debug(printf('Stopping Vim job: %s.', job), jobinfo) + endif + if has('nvim') + try + let ret = jobstop(job) + catch /^Vim\%((\a\+)\)\=:\(E474\|E900\):/ + call neomake#log#info(printf( + \ 'jobstop failed: %s.', v:exception), jobinfo) + endtry + else + " Use ch_status here, since job_status might be 'dead' already, + " without the exit handler being called yet. + if job_status(job) !=# 'run' + call neomake#log#info( + \ 'job_stop: job was not running anymore.', jobinfo) + else + " NOTE: might be "dead" already, but that is fine. + call job_stop(job) + let ret = 1 + if job_status(job) ==# 'run' + let timer = timer_start(1000, function('s:kill_vimjob_cb')) + let s:kill_vim_timers[timer] = jobinfo + endif + endif + endif + endif + + if ret == 0 || remove_always + call s:CleanJobinfo(jobinfo) + endif + return ret +endfunction + +function! s:kill_vimjob_cb(timer) abort + let jobinfo = s:kill_vim_timers[a:timer] + let vim_job = jobinfo.vim_job + if job_status(vim_job) ==# 'run' + call neomake#log#debug('Forcefully killing still running Vim job.', jobinfo) + call job_stop(vim_job, 'kill') + endif + unlet s:kill_vim_timers[a:timer] +endfunction + +function! neomake#CancelJobs(bang) abort + call neomake#log#debug(printf('Canceling %d jobs.', len(s:jobs))) + for job in neomake#GetJobs() + call neomake#CancelJob(job.id, a:bang) + endfor +endfunction + +function! s:handle_get_list_entries(jobinfo, ...) abort + if !a:0 + return s:pcall('s:handle_get_list_entries', [a:jobinfo]) + endif + let jobinfo = a:jobinfo + let jobinfo.serialize = 0 + let maker = jobinfo.maker + try + let entries = maker.get_list_entries(jobinfo) + catch /^\%(Vim\%((\a\+)\)\=:\%(E48\|E523\)\)\@!/ " everything, but E48/E523 (sandbox / not allowed here) + if v:exception ==# 'NeomakeTestsException' + throw v:exception + endif + call neomake#log#exception(printf( + \ 'Error during get_list_entries for %s: %s.', + \ jobinfo.maker.name, v:exception), jobinfo) + call s:CleanJobinfo(jobinfo) + return g:neomake#action_queue#processed + endtry + + if type(entries) != type([]) + call neomake#log#error(printf('The get_list_entries method for maker %s did not return a list, but: %s.', jobinfo.maker.name, string(entries)[:100]), jobinfo) + elseif !empty(entries) && type(entries[0]) != type({}) + call neomake#log#error(printf('The get_list_entries method for maker %s did not return a list of dicts, but: %s.', jobinfo.maker.name, string(entries)[:100]), jobinfo) + else + call s:ProcessEntries(jobinfo, entries) + endif + call s:CleanJobinfo(jobinfo) + return g:neomake#action_queue#processed +endfunction + +function! s:MakeJob(make_id, options) abort + let job_id = s:job_id + let s:job_id += 1 + + " Optional: + " - serialize (default: 0 for async (and get_list_entries), + " 1 for non-async) + " - serialize_abort_on_error (default: 0) + " - exit_callback (string/function, default: 0) + let jobinfo = extend(neomake#jobinfo#new(), extend({ + \ 'id': job_id, + \ 'make_id': a:make_id, + \ 'name': empty(get(a:options.maker, 'name', '')) ? 'neomake_'.job_id : a:options.maker.name, + \ 'maker': a:options.maker, + \ 'bufnr': a:options.bufnr, + \ 'file_mode': a:options.file_mode, + \ 'ft': a:options.ft, + \ 'cwd': s:make_info[a:make_id].cwd, + \ }, a:options)) + + let maker = jobinfo.maker + + if has_key(maker, 'get_list_entries') + call neomake#log#info(printf( + \ '%s: getting entries via get_list_entries.', + \ maker.name), jobinfo) + let s:jobs[jobinfo.id] = jobinfo + let s:make_info[a:make_id].active_jobs += [jobinfo] + call s:handle_get_list_entries(jobinfo) + return jobinfo + endif + + call extend(jobinfo, { + \ 'output_stream': a:options.maker.output_stream, + \ 'buffer_output': a:options.maker.buffer_output, + \ }, 'keep') + + let error = '' + try + " Change to job's cwd (before args, for relative filename). + let cd_error = jobinfo.cd() + if !empty(cd_error) + throw printf("Neomake: %s: could not change to maker's cwd (%s): %s.", + \ maker.name, jobinfo.cd_from_setting, cd_error) + endif + let jobinfo.argv = maker._get_argv(jobinfo) + + call neomake#utils#hook('NeomakeJobInit', {'jobinfo': jobinfo}) + + let start_msg = s:async ? 'Starting async job' : 'Starting' + if type(jobinfo.argv) == type('') + let start_msg .= ' [string]: '.jobinfo.argv + else + let start_msg .= ': '.join(map(copy(jobinfo.argv), 'neomake#utils#shellescape(v:val)')) + endif + call neomake#log#info(start_msg.'.', jobinfo) + + let cwd = jobinfo.cwd + let changed = !empty(jobinfo.cd_back_cmd) + if changed + call neomake#log#debug('cwd: '.cwd.' (changed).', jobinfo) + else + call neomake#log#debug('cwd: '.cwd.'.', jobinfo) + endif + + let base_job_opts = {} + if has_key(jobinfo, 'filename') + if s:can_use_env_in_job_opts + let base_job_opts = { + \ 'env': { + \ 'NEOMAKE_FILE': jobinfo.filename + \ }} + else + let save_env_file = exists('$NEOMAKE_FILE') ? $NEOMAKE_FILE : s:unset + let $NEOMAKE_FILE = jobinfo.filename + endif + endif + + " Lock maker to make sure it does not get changed accidentally, but + " only with depth=1, so that a postprocess object can change itself. + lockvar 1 maker + if s:async + if has('nvim') + if jobinfo.buffer_output + let opts = extend(base_job_opts, { + \ 'stdout_buffered': 1, + \ 'stderr_buffered': 1, + \ }) + if s:nvim_can_buffer_output == 1 + let opts.on_exit = function('s:nvim_exit_handler_buffered') + else + call extend(opts, { + \ 'on_stdout': function('s:nvim_output_handler'), + \ 'on_stderr': function('s:nvim_output_handler'), + \ }) + let opts.on_exit = function('s:nvim_exit_handler') + endif + let jobinfo.jobstart_opts = opts + else + let opts = { + \ 'on_stdout': function('s:nvim_output_handler'), + \ 'on_stderr': function('s:nvim_output_handler'), + \ 'on_exit': function('s:nvim_exit_handler'), + \ } + endif + if has_key(maker, 'nvim_job_opts') + call extend(opts, maker.nvim_job_opts) + endif + if !has('nvim-0.3.0') + \ && !neomake#utils#IsRunningWindows() + \ && !has_key(opts, 'detach') + \ && !has_key(opts, 'pty') + " Always use detach to trigger setsid() with older Neovim. + let opts.detach = 1 + endif + try + let job = jobstart(jobinfo.argv, opts) + catch + let error = printf('Failed to start Neovim job: %s: %s.', + \ string(jobinfo.argv), v:exception) + endtry + if empty(error) + if job == 0 + let error = printf('Failed to start Neovim job: %s: %s.', + \ 'Job table is full or invalid arguments given', string(jobinfo.argv)) + elseif job == -1 + let error = printf('Failed to start Neovim job: %s: %s.', + \ 'Executable not found', string(jobinfo.argv)) + else + let s:map_job_ids[job] = jobinfo.id + let jobinfo.nvim_job = job + let s:jobs[jobinfo.id] = jobinfo + + if get(jobinfo, 'uses_stdin', 0) + call jobsend(job, s:make_info[a:make_id].buffer_lines) + call jobclose(job, 'stdin') + endif + endif + endif + else + " vim-async. + let opts = extend(base_job_opts, { + \ 'out_cb': function('s:vim_output_handler_stdout'), + \ 'err_cb': function('s:vim_output_handler_stderr'), + \ 'close_cb': function('s:vim_exit_handler'), + \ 'mode': 'raw', + \ }) + if has_key(maker, 'vim_job_opts') + call extend(opts, maker.vim_job_opts) + endif + try + let job = job_start(jobinfo.argv, opts) + " Get this as early as possible! + let channel_id = ch_info(job)['id'] + catch + " NOTE: not covered in tests. Vim seems to always return + " a job. Might be able to trigger this using custom opts?! + let error = printf('Failed to start Vim job: %s: %s.', + \ jobinfo.argv, v:exception) + endtry + if empty(error) + let jobinfo.vim_job = job + let s:map_job_ids[channel_id] = jobinfo.id + let s:jobs[jobinfo.id] = jobinfo + call neomake#log#debug(printf('Vim job: %s.', + \ string(job_info(job))), jobinfo) + call neomake#log#debug(printf('Vim channel: %s.', + \ string(ch_info(job))), jobinfo) + + if get(jobinfo, 'uses_stdin', 0) + call ch_sendraw(job, join(s:make_info[a:make_id].buffer_lines, "\n")) + call ch_close_in(job) + endif + endif + endif + + " Bail out on errors. + if !empty(error) + throw 'Neomake: '.error + endif + + call neomake#utils#hook('NeomakeJobStarted', {'jobinfo': jobinfo}) + else + " vim-sync. + " Use a temporary file to capture stderr. + let stderr_file = tempname() + let argv = jobinfo.argv . ' 2>'.stderr_file + + try + if get(jobinfo, 'uses_stdin', 0) + " Pass stdin to system(), but only if non-empty. + " Otherwise it might cause E677 (vim74-trusty at least). + let stdin = join(s:make_info[a:make_id].buffer_lines, "\n") + if !empty(stdin) + let output = system(argv, stdin) + else + let output = system(argv) + endif + else + let output = system(argv) + endif + catch /^Vim(let):E484:/ + throw printf('Neomake: Could not run %s: %s.', argv, v:exception) + endtry + + let jobinfo.id = job_id + let s:jobs[job_id] = jobinfo + let s:make_info[a:make_id].active_jobs += [jobinfo] + + call s:output_handler(jobinfo, split(output, '\r\?\n', 1), 'stdout', 0) + let stderr_output = readfile(stderr_file) + if !empty(stderr_output) + call s:output_handler(jobinfo, stderr_output, 'stderr', 1) + endif + call delete(stderr_file) + + call s:exit_handler(jobinfo, v:shell_error) + return jobinfo + endif + finally + call jobinfo.cd_back() + if exists('save_env_file') + call s:restore_env('NEOMAKE_FILE', save_env_file) + endif + endtry + let s:make_info[a:make_id].active_jobs += [jobinfo] + return jobinfo +endfunction + +if !s:can_use_env_in_job_opts + function! s:restore_env(var, value) abort + " Cannot unlet environment vars without patch 8.0.1832. + exe printf('let $%s = %s', a:var, string(a:value is s:unset ? '' : a:value)) + endfunction +endif + +let s:command_maker_base = copy(g:neomake#core#command_maker_base) +" Check if a temporary file is used, and set it in s:make_info in case it is. +function! s:command_maker_base._get_tempfilename(jobinfo) abort dict + let l:Supports_stdin = neomake#utils#GetSetting('supports_stdin', self, s:unset_dict, a:jobinfo.ft, a:jobinfo.bufnr) + if Supports_stdin isnot s:unset_dict + if type(Supports_stdin) == type(function('tr')) + let supports_stdin = call(Supports_stdin, [a:jobinfo], self) + else + let supports_stdin = Supports_stdin + endif + if supports_stdin + let a:jobinfo.uses_stdin = 1 + return get(self, 'tempfile_name', '-') + endif + endif + + if has_key(self, 'tempfile_name') + return self.tempfile_name + endif + return self._get_default_tempfilename(a:jobinfo) +endfunction + +function! s:command_maker_base._get_default_tempfilename(jobinfo) abort dict + let tempfile_enabled = neomake#utils#GetSetting('tempfile_enabled', self, 1, a:jobinfo.ft, a:jobinfo.bufnr) + if !tempfile_enabled + return '' + endif + + let make_id = a:jobinfo.make_id + if !has_key(s:make_info[make_id], 'tempfile_name') + if !exists('s:pid') + let s:pid = getpid() + endif + let slash = neomake#utils#Slash() + + let dir = neomake#utils#GetSetting('tempfile_dir', self, '', a:jobinfo.ft, a:jobinfo.bufnr) + + " Use absolute path internally, which is important for removal. + let orig_fname = neomake#utils#fnamemodify(a:jobinfo.bufnr, ':p') + if empty(dir) + if empty(orig_fname) + let dir = tempname() + else + let dir = fnamemodify(orig_fname, ':h') + if filewritable(dir) != 2 + let dir = tempname() + let s:make_info[make_id].tempfile_dir = dir + call neomake#log#debug('Using temporary directory for non-writable parent directory.') + endif + endif + + if empty(orig_fname) + let filename = 'neomaketmp.'.a:jobinfo.ft + else + let filename = fnamemodify(orig_fname, ':t') + \ .'@neomake_'.s:pid.'_'.make_id + let ext = fnamemodify(orig_fname, ':e') + if !empty(ext) + let filename .= '.'.ext + endif + " Use hidden files to make e.g. pytest not trying to import it. + if filename[0] !=# '.' + let filename = '.' . filename + endif + endif + else + let dir = neomake#utils#ExpandArgs([dir], a:jobinfo)[0] + if empty(orig_fname) + let filename = 'neomaketmp.'.a:jobinfo.ft + else + let filename = fnamemodify(orig_fname, ':t') + endif + endif + + let temp_file = dir . slash . filename + let s:make_info[make_id].tempfile_name = temp_file + endif + return s:make_info[make_id].tempfile_name +endfunction + +" Get the filename to use for a:jobinfo's make/buffer. +function! s:command_maker_base._get_fname_for_buffer(jobinfo) abort + let bufnr = a:jobinfo.bufnr + let bufname = bufname(bufnr) + let temp_file = '' + if has_key(a:jobinfo, 'uses_stdin') + let uses_stdin = a:jobinfo.uses_stdin + if uses_stdin + let temp_file = neomake#utils#GetSetting('tempfile_name', a:jobinfo.maker, '-', a:jobinfo.ft, bufnr) + endif + else + if empty(bufname) + let temp_file = self._get_tempfilename(a:jobinfo) + if !get(a:jobinfo, 'uses_stdin', 0) && empty(temp_file) + throw 'Neomake: no file name.' + endif + let used_for = 'unnamed' + elseif getbufvar(bufnr, '&modified') + let temp_file = self._get_tempfilename(a:jobinfo) + if !get(a:jobinfo, 'uses_stdin', 0) && empty(temp_file) + throw 'Neomake: skip_job: buffer is modified, but temporary files are disabled.' + endif + let used_for = 'modified' + elseif !filereadable(bufname) + let temp_file = self._get_tempfilename(a:jobinfo) + if !get(a:jobinfo, 'uses_stdin', 0) && empty(temp_file) + " Using ':p' as modifier is unpredictable as per doc, but OK. + throw printf('Neomake: file is not readable (%s)', fnamemodify(bufname, ':p')) + endif + let used_for = 'unreadable' + else + let bufname = fnamemodify(bufname, ':.') + let used_for = '' + endif + + let uses_stdin = get(a:jobinfo, 'uses_stdin', 0) + + if !empty(used_for) + if uses_stdin + call neomake#log#debug(printf( + \ 'Using stdin for %s buffer (%s).', used_for, temp_file), + \ a:jobinfo) + elseif !empty(temp_file) + call neomake#log#debug(printf( + \ 'Using tempfile for %s buffer: "%s".', used_for, temp_file), + \ a:jobinfo) + endif + endif + endif + + let make_info = s:make_info[a:jobinfo.make_id] + " Handle stdin when supports_stdin sets self.tempfile_name = ''. + if uses_stdin + if !has_key(make_info, 'buffer_lines') + let make_info.buffer_lines = neomake#utils#get_buffer_lines(bufnr) + endif + let bufname = temp_file + elseif !empty(temp_file) + " Use relative path for args. + let bufname = fnamemodify(temp_file, ':.') + let temp_file = fnamemodify(temp_file, ':p') + if !has_key(make_info, 'tempfiles') + let make_info.tempfiles = [temp_file] + let make_info.created_dirs = s:create_dirs_for_file(temp_file) + call neomake#utils#write_tempfile(bufnr, temp_file) + elseif temp_file !=# make_info.tempfiles[0] + call extend(make_info.created_dirs, s:create_dirs_for_file(temp_file)) + call writefile(readfile(make_info.tempfiles[0], 'b'), temp_file, 'b') + call add(make_info.tempfiles, temp_file) + endif + let a:jobinfo.tempfile = temp_file + endif + + let a:jobinfo.filename = bufname + return bufname +endfunction + +function! s:create_dirs_for_file(fpath) abort + let created_dirs = [] + let last_dir = a:fpath + while 1 + let temp_dir = fnamemodify(last_dir, ':h') + if isdirectory(temp_dir) || last_dir ==# temp_dir + break + endif + call insert(created_dirs, temp_dir) + let last_dir = temp_dir + endwhile + for dir in created_dirs + call mkdir(dir, '', 0700) + endfor + return created_dirs +endfunction + +function! s:command_maker_base._bind_args() abort dict + " Resolve args, which might be a function or dictionary. + if type(self.args) == type(function('tr')) + " Deprecated: use InitForJob + call neomake#log#warn_once(printf("Please use 'InitForJob' instead of 'args' for maker %s.", self.name), + \ printf('deprecated-args-%s', self.name)) + let args = call(self.args, []) + elseif type(self.args) == type({}) + " Deprecated: use InitForJob + call neomake#log#warn_once(printf("Please use 'InitForJob' instead of 'args.fn' for maker %s.", self.name), + \ printf('deprecated-args-fn-%s', self.name)) + let args = call(self.args.fn, [], self.args) + else + let args = copy(self.args) + endif + let self.args = args + return self +endfunction + +function! s:command_maker_base._get_argv(jobinfo) abort dict + let filename = self._get_fname_for_args(a:jobinfo) + let args_is_list = type(self.args) == type([]) + if args_is_list + let args = neomake#utils#ExpandArgs(self.args, a:jobinfo) + if !empty(filename) + call add(args, filename) + endif + elseif !empty(filename) + let args = copy(self.args) + let args .= (empty(args) ? '' : ' ').neomake#utils#shellescape(filename) + else + let args = self.args + endif + return neomake#compat#get_argv(self.exe, args, args_is_list) +endfunction + +function! s:GetMakerForFiletype(ft, maker_name) abort + for config_ft in neomake#utils#get_config_fts(a:ft) + call neomake#utils#load_ft_makers(config_ft) + let f = 'neomake#makers#ft#'.config_ft.'#'.a:maker_name + if exists('*'.f) + let maker = call(f, []) + return maker + endif + endfor + return s:unset_dict +endfunction + +function! neomake#get_maker_by_name(maker_name, ...) abort + let for_ft = a:0 ? a:1 : 0 + let ft_config = for_ft is# 0 ? &filetype : for_ft + let bufnr = bufnr('%') + if a:maker_name !~# '\v^\w+$' + throw printf('Neomake: Invalid maker name: "%s"', a:maker_name) + endif + + let maker = neomake#utils#GetSetting('maker', {'name': a:maker_name}, s:unset_dict, ft_config, bufnr) + if maker is# s:unset_dict + if a:maker_name ==# 'makeprg' + let maker = s:get_makeprg_maker() + elseif for_ft isnot# 0 + let maker = s:GetMakerForFiletype(for_ft, a:maker_name) + else + call neomake#utils#load_global_makers() + let f = 'neomake#makers#'.a:maker_name.'#'.a:maker_name + if exists('*'.f) + let maker = call(f, []) + endif + endif + endif + if type(maker) != type({}) + throw printf('Neomake: Got non-dict for maker %s: %s', + \ a:maker_name, maker) + endif + if maker isnot# s:unset_dict && !has_key(maker, 'name') + let maker.name = a:maker_name + endif + return maker +endfunction + +function! neomake#GetMaker(name_or_maker, ...) abort + let for_ft = a:0 ? a:1 : 0 + if type(a:name_or_maker) == type({}) + let maker = a:name_or_maker + if !has_key(maker, 'name') + let maker.name = 'unnamed_maker' + endif + else + let maker = neomake#get_maker_by_name(a:name_or_maker, for_ft) + if maker is# s:unset_dict + if !a:0 + " Check &filetype if no args where provided. + let maker = neomake#get_maker_by_name(a:name_or_maker, &filetype) + endif + endif + if maker is# s:unset_dict + if for_ft isnot# 0 + throw printf('Neomake: Maker not found (for %s): %s', + \ !empty(for_ft) ? 'filetype '.for_ft : 'empty filetype', + \ a:name_or_maker) + else + throw printf('Neomake: Maker not found (without filetype): %s', + \ a:name_or_maker) + endif + endif + endif + return neomake#create_maker_object(maker, a:0 ? a:1 : &filetype) +endfunction + +" NOTE: uses ft and bufnr for config only. +function! neomake#create_maker_object(maker, ft) abort + let [maker, ft, bufnr] = [a:maker, a:ft, bufnr('%')] + + " Create the maker object. + let l:GetEntries = neomake#utils#GetSetting('get_list_entries', maker, -1, ft, bufnr) + if GetEntries isnot# -1 + let maker = copy(maker) + let maker.get_list_entries = GetEntries + else + let maker = extend(copy(s:command_maker_base), copy(maker)) + endif + if !has_key(maker, 'get_list_entries') + " Set defaults for command/job based makers. + let defaults = extend( + \ copy(g:neomake#config#_defaults['maker_defaults']), + \ neomake#config#get('maker_defaults')) + call extend(defaults, { + \ 'exe': maker.name, + \ 'args': [], + \ }) + if !has_key(maker, 'process_output') && !has_key(maker, 'process_json') + call extend(defaults, { + \ 'errorformat': &errorformat, + \ }) + endif + for [key, default] in items(defaults) + let maker[key] = neomake#utils#GetSetting(key, {'name': maker.name}, get(maker, key, default), ft, bufnr, 1) + unlet default " for Vim without patch-7.4.1546 + endfor + + " Check settings, without setting a default. + for key in ['cwd'] + let setting = neomake#utils#GetSetting(key, {'name': maker.name}, get(maker, key, s:unset), ft, bufnr, 1) + if setting isnot s:unset + let maker[key] = setting + endif + endfor + endif + if v:profiling + call add(s:hack_keep_refs_for_profiling, maker) + endif + return maker +endfunction + +if exists('*getcompletion') + function! s:get_makers_for_pattern(pattern) abort + " Get function prefix based on pattern, until the first backslash. + let prefix = substitute(a:pattern, '\v\\.*', '', '') + + " NOTE: the pattern uses &ignorecase. + let funcs = getcompletion(prefix.'[a-z]', 'function') + call filter(funcs, 'v:val =~# a:pattern') + " Remove prefix. + call map(funcs, 'v:val['.len(prefix).':]') + " Only keep lowercase function names. + call filter(funcs, "v:val =~# '\\m^[a-z].*('") + " Remove parenthesis and #.* (for project makers). + return sort(map(funcs, "substitute(v:val, '\\v[(#].*', '', '')")) + endfunction +else + function! s:get_makers_for_pattern(pattern) abort + let funcs_output = neomake#utils#redir('fun /'.a:pattern) + return sort(map(split(funcs_output, '\n'), + \ "substitute(v:val, '\\v^.*#(.*)\\(.*$', '\\1', '')")) + endfunction +endif + +function! neomake#GetMakers(ft) abort + " Get all makers for a given filetype. This is used from completion. + " XXX: this should probably use a callback or some other more stable + " approach to get the list of makers (than looking at the lowercase + " functions)?! + + let makers = [] + " Do not use 'b:neomake_jsx_javascript_foo_maker' twice for + " ft=jsx.javascript. + let used_vars = [] + for ft in neomake#utils#get_config_fts(a:ft) + call neomake#utils#load_ft_makers(ft) + + " Add sorted list per filetype. + let add = [] + + let maker_names = s:get_makers_for_pattern('neomake#makers#ft#'.ft.'#\l') + for maker_name in maker_names + if index(makers, maker_name) == -1 && index(add, maker_name) == -1 + let add += [maker_name] + endif + endfor + + " Get makers from g:/b: variables. + for v in sort(extend(keys(g:), keys(b:))) + if index(used_vars, v) != -1 + continue + endif + let maker_name = matchstr(v, '\v^neomake_'.ft.'_\zs[0-9a-z_]+\ze_maker$') + if !empty(maker_name) + \ && index(makers, maker_name) == -1 + \ && index(add, maker_name) == -1 + let used_vars += [v] + let add += [maker_name] + endif + endfor + + " Get makers from new-style config. + for [maker_name, val] in items(neomake#config#get('ft.'.ft)) + if has_key(val, 'maker') + \ && index(makers, maker_name) == -1 + \ && index(add, maker_name) == -1 + let add += [maker_name] + endif + endfor + + call sort(add) + call extend(makers, add) + endfor + return makers +endfunction + +function! neomake#GetProjectMakers() abort + call neomake#utils#load_global_makers() + return s:get_makers_for_pattern('neomake#makers#\(ft#\)\@!\l') +endfunction + +function! neomake#GetEnabledMakers(...) abort + let file_mode = a:0 + if !file_mode + " If we have no filetype, use the global default makers. + " This variable is also used for project jobs, so it has no + " buffer local ('b:') counterpart for now. + let enabled_makers = copy(get(g:, 'neomake_enabled_makers', [])) + if empty(enabled_makers) + let makeprg_maker = s:get_makeprg_maker() + if !empty(makeprg_maker) + let makeprg_maker = neomake#GetMaker(makeprg_maker) + let makeprg_maker.auto_enabled = 1 + let enabled_makers = [makeprg_maker] + endif + else + call map(enabled_makers, "extend(neomake#GetMaker(v:val), + \ {'auto_enabled': 0}, 'error')") + endif + else + let enabled_makers = [] + let bufnr = bufnr('%') + let makers = neomake#utils#GetSetting('enabled_makers', {}, s:unset_list, a:1, bufnr) + if makers is# s:unset_list + let auto_enabled = 1 + for config_ft in neomake#utils#get_config_fts(a:1) + call neomake#utils#load_ft_makers(config_ft) + let fnname = 'neomake#makers#ft#'.config_ft.'#EnabledMakers' + if exists('*'.fnname) + try + let makers = call(fnname, []) + catch /^Vim(let):E119:/ " Not enough arguments for function + let makers = call(fnname, [{'file_mode': file_mode, 'bufnr': bufnr}]) + endtry + break + endif + endfor + else + let auto_enabled = 0 + endif + let enabled_makers = neomake#map_makers(makers, a:1, auto_enabled) + endif + return enabled_makers +endfunction + +" a:1: override "open_list" setting. +function! s:HandleLoclistQflistDisplay(jobinfo, loc_or_qflist, ...) abort + let open_list_default = a:0 ? a:1 : 0 + let open_val = neomake#utils#GetSetting('open_list', a:jobinfo.maker, open_list_default, a:jobinfo.ft, a:jobinfo.bufnr) + if !open_val + return + endif + let height = neomake#utils#GetSetting('list_height', a:jobinfo.maker, 10, a:jobinfo.ft, a:jobinfo.bufnr) + if !height + return + endif + let height = min([len(a:loc_or_qflist), height]) + if a:jobinfo.file_mode + call neomake#log#debug('Handling location list: executing lwindow.', a:jobinfo) + let cmd = 'lwindow' + else + call neomake#log#debug('Handling quickfix list: executing cwindow.', a:jobinfo) + let cmd = 'botright cwindow' + endif + if open_val == 2 + let make_id = a:jobinfo.make_id + let make_info = s:make_info[make_id] + let g:neomake#core#_ignore_autocommands += 1 + try + call neomake#compat#save_prev_windows() + + let win_count = winnr('$') + exe cmd height + let new_win_count = winnr('$') + if win_count == new_win_count + " No new window, adjust height eventually. + let found = 0 + + if get(make_info, '_did_lwindow', 0) + for w in range(1, winnr('$')) + if getwinvar(w, 'neomake_window_for_make_id') == make_id + let found = w + break + endif + endfor + if found + let cmd = printf('%dresize %d', found, height) + if winheight(found) != height + call neomake#log#debug(printf( + \ 'Resizing existing quickfix window: %s.', + \ cmd), a:jobinfo) + exe cmd + endif + else + call neomake#log#debug( + \ 'Could not find corresponding quickfix window.', + \ a:jobinfo) + endif + endif + elseif new_win_count > win_count + if &filetype !=# 'qf' + call neomake#log#debug(printf( + \ 'WARN: unexpected filetype for new window: %s', + \ &filetype), a:jobinfo) + else + call neomake#log#debug(printf( + \ 'list window has been opened (old count: %d, new count: %d, height: %d).', + \ win_count, new_win_count, winheight(0)), a:jobinfo) + let w:neomake_window_for_make_id = a:jobinfo.make_id + endif + else + call neomake#log#debug(printf( + \ 'list window has been closed (old count: %d, new count: %d).', + \ win_count, new_win_count), a:jobinfo) + endif + call neomake#compat#restore_prev_windows() + let make_info._did_lwindow = 1 + finally + let g:neomake#core#_ignore_autocommands -= 1 + endtry + else + exe cmd height + endif +endfunction + +" Experimental/private wrapper. +function! neomake#_handle_list_display(jobinfo, ...) abort + if a:0 + let list = a:1 + else + let list = a:jobinfo.file_mode ? getloclist(0) : getqflist() + endif + call s:HandleLoclistQflistDisplay(a:jobinfo, list, 2) +endfunction + +" Get a maker for &makeprg. +" This could be cached, but needs to take into account / set &errorformat, +" and other settings that are handled by neomake#GetMaker. +function! s:get_makeprg_maker() abort + if empty(&makeprg) + return {} + elseif &makeprg =~# '\s' + let maker = neomake#utils#MakerFromCommand(&makeprg) + else + let maker = neomake#utils#MakerFromCommand([&makeprg]) + endif + let maker.name = 'makeprg' + " Do not append file. &makeprg should contain %/# for this instead. + let maker.append_file = 0 + return neomake#GetMaker(maker) +endfunction + +function! s:Make(options) abort + let is_automake = get(a:options, 'automake', !empty(expand(''))) + if is_automake + if g:neomake#core#_ignore_autocommands + call neomake#log#debug(printf( + \ 'Ignoring Make through autocommand due to ignore_autocommands=%d.', g:neomake#core#_ignore_autocommands), {'winnr': winnr()}) + return [] + endif + let disabled = neomake#config#get_with_source('disabled', 0) + if disabled[0] + call neomake#log#debug(printf( + \ 'Make through autocommand disabled via %s.', disabled[1])) + return [] + endif + endif + + let s:make_id += 1 + let make_id = s:make_id + let options = extend(copy(a:options), { + \ 'file_mode': 1, + \ 'ft': &filetype, + \ }, 'keep') + let options.make_id = make_id " Deprecated. + let file_mode = options.file_mode + + " Require winid/winnr with non-current buffer in file_mode. + if has_key(options, 'bufnr') + if options.bufnr != bufnr('%') + if !has_key(options, 'winid') && !has_key(options, 'winnr') + throw 'Neomake: winid or winnr are required for non-current buffer.' + endif + endif + if !bufexists(options.bufnr) + throw printf('Neomake: buffer %d does not exist.', options.bufnr) + endif + else + let options.bufnr = bufnr('%') + endif + + " Validate winid/winnr (required for location list windows). + let file_mode_win = 0 + if file_mode + if has_key(options, 'winid') + if win_id2tabwin(options.winid) == [0, 0] + throw printf('Neomake: window id %d does not exist.', options.winid) + endif + let file_mode_win = options.winid + elseif has_key(options, 'winnr') + if winbufnr(options.winnr) == -1 + throw printf('Neomake: window %d does not exist.', options.winnr) + endif + let file_mode_win = options.winnr + elseif exists('*win_getid') + let options.winid = win_getid() + endif + elseif has_key(options, 'winid') + throw 'Neomake: do not use winid with file_mode=0.' + elseif has_key(options, 'winnr') + throw 'Neomake: do not use winnr with file_mode=0.' + endif + + lockvar 1 options + let s:make_info[make_id] = { + \ 'make_id': make_id, + \ 'cwd': getcwd(), + \ 'verbosity': get(g:, 'neomake_verbose', 1), + \ 'active_jobs': [], + \ 'finished_jobs': [], + \ 'options': options, + \ } + let make_info = s:make_info[make_id] + let bufnr = options.bufnr + if &verbose + let make_info.verbosity += &verbose + call neomake#log#debug(printf( + \ 'Adding &verbose (%d) to verbosity level: %d.', + \ &verbose, make_info.verbosity), make_info) + endif + if make_info.verbosity >= 3 + call neomake#log#debug(printf( + \ 'Calling Make with options %s.', + \ string(filter(copy(options), "index(['bufnr', 'make_id'], v:key) == -1"))), {'make_id': make_id, 'bufnr': bufnr}) + endif + + " Use pre-compiled jobs (used with automake). + if has_key(options, 'jobs') + let jobs = map(copy(options.jobs), "extend(v:val, {'make_id': make_id})") + else + if has_key(options, 'enabled_makers') + if file_mode + let makers = neomake#map_makers(options.enabled_makers, options.ft, 0) + else + let makers = neomake#map_makers(options.enabled_makers, -1, 0) + endif + else + let makers = call('neomake#GetEnabledMakers', file_mode ? [options.ft] : []) + if empty(makers) + if file_mode + let msg = printf('Nothing to make: no enabled file mode makers (filetype=%s).', options.ft) + if is_automake + call neomake#log#debug(msg, make_info) + else + call neomake#log#warning(msg, make_info) + endif + unlet s:make_info[make_id] + return [] + endif + endif + endif + let job_options = copy(options) + let job_options.make_id = make_id " Used for logging. + let jobs = neomake#core#create_jobs(job_options, makers) + endif + + if empty(jobs) + call neomake#log#debug('Nothing to make: no valid makers.', make_info) + call s:clean_make_info(make_info) + return [] + endif + let make_info.jobs = copy(jobs) + + let maker_info = join(map(copy(jobs), + \ "v:val.maker.name . (get(v:val.maker, 'auto_enabled', 0) ? ' (auto)' : '')"), ', ') + call neomake#log#debug(printf('Running makers: %s.', maker_info), make_info) + + let make_info.jobs_queue = jobs + + if file_mode + " XXX: this clears counts for job's buffer only, but we add counts for + " the entry's buffers, which might be different! + call neomake#statusline#ResetCountsForBuf(bufnr) + if g:neomake_place_signs + call neomake#signs#Reset(bufnr, 'file') + endif + else + call neomake#statusline#ResetCountsForProject() + if g:neomake_place_signs + call neomake#signs#ResetProject() + endif + endif + + " Store make_id on window (used to find window for location lists (without + " winid, but also used to check the current window via w: directly)). + if file_mode + call setwinvar(file_mode_win, 'neomake_make_ids', + \ neomake#compat#getwinvar(file_mode_win, 'neomake_make_ids', []) + [make_id]) + endif + + let use_list = get(options, 'use_list', 1) + if use_list + let any_job_uses_list = 0 + for job in jobs + if get(job.maker, 'use_list', 1) + let any_job_uses_list = 1 + break + endif + endfor + if !any_job_uses_list + let use_list = 0 + endif + endif + + if use_list + let make_info.entries_list = neomake#list#ListForMake(make_info) + + " Reuse existing location list window with automake. + if is_automake && has('patch-7.4.2200') + if file_mode + let title = get(getloclist(0, {'title': 1}), 'title') + else + let title = get(getqflist({'title': 1}), 'title') + endif + if title =~# '\V\^Neomake[auto]' + let make_info.entries_list.reset_existing_qflist = 1 + endif + endif + endif + + " Cancel any already running jobs for the makers from these jobs. + if !empty(s:jobs) + " @vimlint(EVL102, 1, l:job) + for job in jobs + let running_already = values(filter(copy(s:jobs), + \ '(v:val.maker.name == job.maker.name' + \ .' || (!is_automake && get(v:val, "automake", 0)))' + \ .' && v:val.bufnr == job.bufnr' + \ .' && v:val.file_mode == job.file_mode' + \ ." && !get(v:val, 'canceled')")) + if !empty(running_already) + for running_job in running_already + call neomake#log#info(printf( + \ 'Canceling already running job (%d.%d) for the same maker.', + \ running_job.make_id, running_job.id), {'make_id': make_id}) + call neomake#CancelJob(running_job.id, 1) + endfor + endif + endfor + endif + + " Update automake tick (used to skip unchanged buffers). + if is_automake + call neomake#configure#_update_automake_tick(bufnr, options.ft) + endif + + " Start all jobs in the queue (until serialized). + let jobinfos = [] + while 1 + if empty(make_info.jobs_queue) + break + endif + let jobinfo = s:handle_next_job({}) + if empty(jobinfo) + break + endif + call add(jobinfos, jobinfo) + if jobinfo.serialize + let make_info.serializing_for_job = jobinfo.id + " Break and continue through exit handler. + break + endif + endwhile + return jobinfos +endfunction + +function! s:AddExprCallback(jobinfo, lines) abort + if s:need_to_postpone_loclist(a:jobinfo) + return neomake#action_queue#add(['BufEnter', 'WinEnter'], [s:function('s:AddExprCallback'), + \ [a:jobinfo, a:lines] + a:000]) + endif + + " Create location/quickfix list and add lines to it. + let cd_error = a:jobinfo.cd() + if !empty(cd_error) + call neomake#log#debug(printf( + \ "Could not change to job's cwd (%s): %s.", + \ a:jobinfo.cd_from_setting, cd_error), a:jobinfo) + endif + + let make_list = s:make_info[a:jobinfo.make_id].entries_list + let prev_list = copy(make_list.entries) + + let added_entries = make_list.add_lines_with_efm(a:lines, a:jobinfo) + return s:ProcessEntries(a:jobinfo, added_entries, prev_list) +endfunction + +function! s:CleanJobinfo(jobinfo, ...) abort + if get(a:jobinfo, '_in_exit_handler', 0) + " Do not clean job yet. + return + endif + if !empty(a:jobinfo.pending_output) && !get(a:jobinfo, 'canceled', 0) + call neomake#log#debug( + \ 'Output left to be processed, not cleaning job yet.', a:jobinfo) + return g:neomake#action_queue#not_processed + endif + + let queued_actions = neomake#action_queue#get_queued_actions(a:jobinfo) + if !empty(queued_actions) + call neomake#log#debug(printf( + \ 'Skipping cleaning of job info because of queued actions: %s.', + \ join(queued_actions, ', ')), a:jobinfo) + return neomake#action_queue#add(['WinEnter'], [s:function('s:CleanJobinfo'), [a:jobinfo]]) + endif + + call neomake#log#debug('Cleaning jobinfo.', a:jobinfo) + let a:jobinfo.finished = 1 + + if !has_key(s:make_info, a:jobinfo.make_id) + return g:neomake#action_queue#processed + endif + let make_info = s:make_info[a:jobinfo.make_id] + + if has_key(s:jobs, get(a:jobinfo, 'id', -1)) + call remove(s:jobs, a:jobinfo.id) + call filter(s:map_job_ids, 'v:val != a:jobinfo.id') + endif + + if exists('s:kill_vim_timers') + for [timer, job] in items(s:kill_vim_timers) + if job == a:jobinfo + call timer_stop(+timer) + unlet s:kill_vim_timers[timer] + break + endif + endfor + endif + + if !get(a:jobinfo, 'canceled', 0) + \ && !get(a:jobinfo, 'failed_to_start', 0) + let make_info.finished_jobs += [a:jobinfo] + call neomake#utils#hook('NeomakeJobFinished', {'jobinfo': a:jobinfo}) + endif + + call filter(make_info.active_jobs, 'v:val != a:jobinfo') + + " Trigger cleanup (and autocommands) if all jobs have finished. + if empty(make_info.active_jobs) && empty(make_info.jobs_queue) + call s:clean_make_info(make_info) + endif + return g:neomake#action_queue#processed +endfunction + +function! s:clean_make_info(make_info, ...) abort + let make_id = a:make_info.make_id + let bang = a:0 ? a:1 : 0 + if !bang && !empty(a:make_info.active_jobs) + call neomake#log#debug(printf( + \ 'Skipping cleaning of make info: %d active jobs: %s.', + \ len(a:make_info.active_jobs), + \ string(map(copy(a:make_info.active_jobs), 'v:val.as_string()'))), + \ a:make_info) + return + endif + + " Queue cleanup in case of queued actions, e.g. NeomakeJobFinished hook. + let queued = [] + for [_, v] in g:neomake#action_queue#_s.action_queue + if has_key(v[1][0], 'id') + let jobinfo = v[1][0] + if jobinfo.make_id == make_id + let queued += ['job '.jobinfo.id] + endif + else + if v[1][0] == a:make_info + let queued += ['make '.make_id] + endif + endif + endfor + if !empty(queued) + call neomake#log#debug(printf('Queuing clean_make_info for already queued actions: %s', string(queued))) + return neomake#action_queue#add( + \ g:neomake#action_queue#any_event, + \ [s:function('s:clean_make_info'), [a:make_info]]) + endif + + if exists('*neomake#statusline#make_finished') + call neomake#statusline#make_finished(a:make_info) + endif + + if !empty(a:make_info.finished_jobs) + " Clean old signs after all jobs have finished, so that they can be + " reused, avoiding flicker and keeping them for longer in general. + if g:neomake_place_signs + if a:make_info.options.file_mode + call neomake#signs#CleanOldSigns(a:make_info.options.bufnr, 'file') + else + call neomake#signs#CleanAllOldSigns('project') + endif + endif + call s:clean_for_new_make(a:make_info) + + if exists('#neomake') + call neomake#EchoCurrentError(1) + call neomake#virtualtext#handle_current_error() + endif + + if get(a:make_info, 'canceled', 0) + call neomake#log#debug('Skipping final processing for canceled make.', a:make_info) + call s:do_clean_make_info(a:make_info) + elseif has_key(a:make_info, 'entries_list') " use_list option + return s:handle_locqf_list_for_finished_jobs(a:make_info) + else + call s:handle_finished_make(a:make_info) + endif + else + call s:do_clean_make_info(a:make_info) + endif + return g:neomake#action_queue#processed +endfunction + +function! s:do_clean_make_info(make_info) abort + call neomake#log#debug('Cleaning make info.', a:make_info) + let make_id = a:make_info.make_id + + " Remove make_id from its window. + let [t, w] = neomake#core#get_tabwin_for_makeid(make_id) + if [t, w] != [-1, -1] + let make_ids = neomake#compat#gettabwinvar(t, w, 'neomake_make_ids', []) + let idx = index(make_ids, make_id) + if idx != -1 + call remove(make_ids, idx) + call settabwinvar(t, w, 'neomake_make_ids', make_ids) + endif + endif + + " Clean up temporary files and buffers. + let wipe_unlisted_buffers = get(a:make_info, '_wipe_unlisted_buffers', []) + let tempfiles = get(a:make_info, 'tempfiles') + if !empty(tempfiles) + for tempfile in tempfiles + let delete_ret = delete(tempfile) + if delete_ret == 0 + call neomake#log#debug(printf('Removing temporary file: "%s".', + \ tempfile)) + else + call neomake#log#warning(printf('Failed to remove temporary file: "%s" (%d).', + \ tempfile, delete_ret)) + endif + let bufnr_tempfile = bufnr(tempfile) + if bufnr_tempfile != -1 && !buflisted(bufnr_tempfile) + let wipe_unlisted_buffers += [bufnr_tempfile] + endif + endfor + + " Only delete the dir, if Vim supports it. + if v:version >= 705 || (v:version == 704 && has('patch1107')) + for dir in reverse(copy(get(a:make_info, 'created_dirs'))) + call delete(dir, 'd') + endfor + endif + endif + if !empty(wipe_unlisted_buffers) + if !empty(wipe_unlisted_buffers) + call neomake#compat#uniq(sort(wipe_unlisted_buffers)) + endif + call neomake#log#debug(printf('Wiping out %d unlisted/remapped buffers: %s.', + \ len(wipe_unlisted_buffers), + \ string(wipe_unlisted_buffers))) + " NOTE: needs to be silent with more than a single buffer. + exe 'silent bwipeout '.join(wipe_unlisted_buffers) + endif + + let buf_prev_makes = getbufvar(a:make_info.options.bufnr, '_neomake_automake_make_ids') + if !empty(buf_prev_makes) + call filter(buf_prev_makes, 'v:val != make_id') + call setbufvar(a:make_info.options.bufnr, '_neomake_automake_make_ids', buf_prev_makes) + endif + + unlet s:make_info[make_id] +endfunction + +function! s:handle_locqf_list_for_finished_jobs(make_info) abort + let file_mode = a:make_info.options.file_mode + let create_list = a:make_info.entries_list.need_init + + let open_val = get(g:, 'neomake_open_list', 0) + let height = open_val ? get(g:, 'neomake_list_height', 10) : 0 + if height + let close_list = create_list || empty(file_mode ? getloclist(0) : getqflist()) + else + let close_list = 0 + endif + + if file_mode + if create_list && !bufexists(a:make_info.options.bufnr) + call neomake#log#info('No buffer found for location list!', a:make_info) + let create_list = 0 + let close_list = 0 + elseif (create_list || close_list) + if index(get(w:, 'neomake_make_ids', []), a:make_info.make_id) == -1 + call neomake#log#debug( + \ 'Postponing final location list handling (in another window).', + \ a:make_info) + return neomake#action_queue#add(['WinEnter'], [s:function('s:handle_locqf_list_for_finished_jobs'), + \ [a:make_info] + a:000]) + endif + + " TODO: merge with s:need_to_postpone_output_processing. + if neomake#compat#in_completion() + call neomake#log#debug( + \ 'Postponing final location list handling during completion.', + \ a:make_info) + return neomake#action_queue#add(['CompleteDone'], [s:function('s:handle_locqf_list_for_finished_jobs'), + \ [a:make_info] + a:000]) + endif + let mode = neomake#compat#get_mode() + if index(['n', 'i'], mode) == -1 + call neomake#log#debug(printf( + \ 'Postponing final location list handling for mode "%s".', mode), + \ a:make_info) + return neomake#action_queue#add(['CursorHold', 'WinEnter'], [s:function('s:handle_locqf_list_for_finished_jobs'), + \ [a:make_info] + a:000]) + endif + endif + endif + + " Update list title. + " This has to be done currently by itself to reflect running/finished + " state properly. + if create_list || !a:make_info.entries_list.need_init + if has_key(a:make_info, 'entries_list') + call a:make_info.entries_list.finish_for_make() + endif + endif + + " Close empty list. + if close_list + if file_mode + call neomake#log#debug('Handling location list: executing lclose.', {'winnr': winnr()}) + lclose + else + call neomake#log#debug('Handling quickfix list: executing cclose.') + cclose + endif + endif + + call s:handle_finished_make(a:make_info) + + return g:neomake#action_queue#processed +endfunction + +function! s:handle_finished_make(make_info) abort + let hook_context = { + \ 'make_info': a:make_info, + \ 'make_id': a:make_info.make_id, + \ 'options': a:make_info.options, + \ 'finished_jobs': a:make_info.finished_jobs, + \ } + call neomake#utils#hook('NeomakeFinished', hook_context) + + call neomake#configure#_reset_automake_cancelations(a:make_info.options.bufnr) + + call s:do_clean_make_info(a:make_info) +endfunction + +function! neomake#VimLeave() abort + call neomake#log#debug('Calling VimLeave.') + for make_id in keys(s:make_info) + call neomake#CancelMake(make_id) + endfor +endfunction + +function! s:clean_for_new_make(make_info) abort + if get(a:make_info, 'cleaned_for_make', 0) + return + endif + " XXX: needs to handle buffers for list entries?! + " See "get_list_entries: minimal example (from doc)" in + " tests/makers.vader. + call neomake#_clean_errors(extend(copy(a:make_info.options), {'make_id': a:make_info.make_id})) + let a:make_info.cleaned_for_make = 1 +endfunction + +" a:context: dictionary with keys: +" - file_mode +" - bufnr (required for file_mode) +" - make_id (used for logging) +function! neomake#_clean_errors(context) abort + if a:context.file_mode + let bufnr = a:context.bufnr + if has_key(s:current_errors['file'], bufnr) + unlet s:current_errors['file'][bufnr] + endif + call neomake#highlights#ResetFile(bufnr) + call neomake#log#debug('File-level errors cleaned.', a:context) + else + let s:current_errors['project'] = {} + call neomake#highlights#ResetProject() + call neomake#log#debug('Project-level errors cleaned.', a:context) + endif +endfunction + +" Change to a job's cwd, if any. +" Returns: a list: +" - error (empty for success) +" - directory changed into (empty if skipped) +" - command to change back to the current workding dir (might be empty) + +" Call a:fn with a:args and queue it, in case if fails with E48/E523. +function! s:pcall(fn, args) abort + let jobinfo = a:args[0] + try + return call(a:fn, a:args + [1]) + catch /^\%(Vim\%((\a\+)\)\=:\%(E48\|E523\)\)/ " only E48/E523 (sandbox / not allowed here) + call neomake#log#debug('Error during pcall: '.v:exception.'.', jobinfo) + call neomake#log#debug(printf('(in %s)', v:throwpoint), jobinfo) + " Might throw in case of X failed attempts. + call neomake#action_queue#add(['Timer', 'WinEnter'], [s:function(a:fn), a:args]) + endtry + return g:neomake#action_queue#not_processed +endfunction + +function! s:ProcessEntries(jobinfo, entries, ...) abort + if empty(a:entries) + return + endif + if get(a:jobinfo, 'canceled') + return + endif + if s:need_to_postpone_loclist(a:jobinfo) + return neomake#action_queue#add(['BufEnter', 'WinEnter'], [s:function('s:ProcessEntries'), + \ [a:jobinfo, a:entries] + a:000]) + endif + if !a:0 || type(a:[len(a:000)]) != 0 + return s:pcall('s:ProcessEntries', [a:jobinfo, a:entries] + a:000) + endif + let file_mode = a:jobinfo.file_mode + + call neomake#log#debug(printf( + \ 'Processing %d entries.', len(a:entries)), a:jobinfo) + + let make_info = s:make_info[a:jobinfo.make_id] + let make_list = make_info.entries_list + let maker_name = a:jobinfo.maker.name + if a:0 > 1 + " Via errorformat processing, where the list has been set already. + let prev_list = a:1 + let parsed_entries = a:entries + else + " Fix entries with get_list_entries/process_output/process_json. + " @vimlint(EVL102, 1, l:default_type) + let default_type = neomake#utils#GetSetting('default_entry_type', a:jobinfo.maker, 'W', a:jobinfo.ft, a:jobinfo.bufnr) + call map(a:entries, 'extend(v:val, {' + \ . "'bufnr': str2nr(get(v:val, 'bufnr', 0))," + \ . "'lnum': str2nr(get(v:val, 'lnum', 0))," + \ . "'col': str2nr(get(v:val, 'col', 0))," + \ . "'vcol': str2nr(get(v:val, 'vcol', 0))," + \ . "'type': get(v:val, 'type', default_type)," + \ . "'nr': get(v:val, 'nr', has_key(v:val, 'text') ? -1 : 0)," + \ . "'text': get(v:val, 'text', '')," + \ . '})') + + let cd_error = a:jobinfo.cd() + if !empty(cd_error) + call neomake#log#debug(printf( + \ "Could not change to job's cwd (%s): %s.", + \ a:jobinfo.cd_from_setting, cd_error), a:jobinfo) + endif + + let prev_list = file_mode ? getloclist(0) : getqflist() + try + let parsed_entries = make_list.add_entries_for_job(a:entries, a:jobinfo) + if exists(':Assert') && !empty(a:entries) + Assert get(a:entries[0], 'text', '') !~# 'nmcfg:' + endif + finally + call a:jobinfo.cd_back() + endtry + endif + call s:clean_for_new_make(make_info) + + let counts_changed = 0 + let maker_type = file_mode ? 'file' : 'project' + let do_highlight = get(g:, 'neomake_highlight_columns', 1) + \ || get(g:, 'neomake_highlight_lines', 0) + let signs_by_bufnr = {} + let debug = neomake#utils#get_verbosity(a:jobinfo) >= 3 || !empty(get(g:, 'neomake_logfile')) || s:is_testing + let entries_with_lnum_by_bufnr = {} + let skipped_without_bufnr = [] + let skipped_without_lnum = [] + + let idx = -1 + for entry in parsed_entries + let idx += 1 + if !file_mode + if neomake#statusline#AddQflistCount(entry) + let counts_changed = 1 + endif + endif + + if !entry.bufnr + if debug + let skipped_without_bufnr += [idx] + endif + continue + endif + + if file_mode + if neomake#statusline#AddLoclistCount(entry.bufnr, entry) + let counts_changed = 1 + endif + endif + + if !entry.lnum + if debug + let skipped_without_lnum += [idx] + endif + continue + endif + + if !has_key(entries_with_lnum_by_bufnr, entry.bufnr) + let entries_with_lnum_by_bufnr[entry.bufnr] = [] + let signs_by_bufnr[entry.bufnr] = [] + endif + + if do_highlight || g:neomake_place_signs + " NOTE: only lnum/type required for signs. Similar for do_highlight?! + call add(entries_with_lnum_by_bufnr[entry.bufnr], entry) + endif + + " Track all errors by buffer and line + let entry.maker_name = maker_name + call neomake#_add_error(maker_type, entry) + endfor + + " Handle placing signs and highlights. + for [b, entries] in items(entries_with_lnum_by_bufnr) + if g:neomake_place_signs + call neomake#signs#PlaceSigns(b, entries, maker_type) + endif + if do_highlight + for entry in entries + call neomake#highlights#AddHighlight(entry, maker_type) + endfor + endif + endfor + + if !empty(skipped_without_bufnr) + call neomake#log#debug(printf('Skipped %d entries without bufnr: %s.', + \ len(skipped_without_bufnr), + \ string(map(skipped_without_bufnr, 'a:entries[v:val]'))), a:jobinfo) + endif + + if !empty(skipped_without_lnum) + call neomake#log#debug(printf( + \ 'Could not place signs for %d entries without line number: %s.', + \ len(skipped_without_lnum), + \ string(map(skipped_without_lnum, 'a:entries[v:val]'))), a:jobinfo) + endif + + let new_list = make_list.entries + if !counts_changed + let counts_changed = new_list != prev_list + endif + if counts_changed + call neomake#utils#hook('NeomakeCountsChanged', {'reset': 0, 'jobinfo': a:jobinfo}) + endif + + if has_key(a:jobinfo, '_delayed_qf_autocmd') && exists('#QuickfixCmdPost') + " NOTE: need to use :silent, since we can only check the event, but + " not the pattern - `exists()` for 'laddexpr' will not match '*'. + silent call neomake#compat#doautocmd(a:jobinfo._delayed_qf_autocmd) + unlet a:jobinfo._delayed_qf_autocmd + endif + + if !empty(new_list) + call s:HandleLoclistQflistDisplay(a:jobinfo, new_list) + endif + call neomake#highlights#ShowHighlights() + return g:neomake#action_queue#processed +endfunction + +function! s:ProcessJobOutput(jobinfo, lines, source, ...) abort + if s:need_to_postpone_loclist(a:jobinfo) + return neomake#action_queue#add(['BufEnter', 'WinEnter'], [s:function('s:ProcessJobOutput'), + \ [a:jobinfo, a:lines, a:source]]) + endif + if !a:0 + return s:pcall('s:ProcessJobOutput', [a:jobinfo, a:lines, a:source]) + endif + + let maker = a:jobinfo.maker + call neomake#log#debug(printf('Processing %d lines of output.', + \ len(a:lines)), a:jobinfo) + let cd_error = a:jobinfo.cd() + if !empty(cd_error) + call neomake#log#debug(printf( + \ "Could not change to job's cwd (%s): %s.", + \ a:jobinfo.cd_from_setting, cd_error), a:jobinfo) + endif + try + if has_key(maker, 'process_json') || has_key(maker, 'process_output') + if has_key(maker, 'process_json') + let method = 'process_json' + let output = join(a:lines, "\n") + try + let json = neomake#compat#json_decode(output) + catch + let error = printf( + \ 'Failed to decode JSON: %s (output: %s).', + \ substitute(v:exception, '^Neomake: ', '', ''), string(output)) + call neomake#log#exception(error, a:jobinfo) + return g:neomake#action_queue#not_processed + endtry + call neomake#log#debug(printf( + \ "Calling maker's process_json method with %d JSON entries.", + \ len(json)), a:jobinfo) + let entries = call(maker.process_json, [{ + \ 'json': json, + \ 'source': a:source, + \ 'jobinfo': a:jobinfo}], maker) + else + call neomake#log#debug(printf( + \ "Calling maker's process_output method with %d lines of output on %s.", + \ len(a:lines), a:source), a:jobinfo) + let method = 'process_output' + let entries = call(maker.process_output, [{ + \ 'output': a:lines, + \ 'source': a:source, + \ 'jobinfo': a:jobinfo}], maker) + endif + if type(entries) != type([]) + call neomake#log#error(printf('The %s method for maker %s did not return a list, but: %s.', + \ method, maker.name, string(entries)[:100]), a:jobinfo) + return g:neomake#action_queue#not_processed + elseif !empty(entries) && type(entries[0]) != type({}) + call neomake#log#error(printf('The %s method for maker %s did not return a list of dicts, but: %s.', + \ method, maker.name, string(entries)[:100]), a:jobinfo) + return g:neomake#action_queue#not_processed + endif + return s:ProcessEntries(a:jobinfo, entries) + endif + + " Old-school handling through errorformat. + if has_key(maker, 'mapexpr') + let neomake_bufname = fnamemodify(bufname(a:jobinfo.bufnr), ':p') + " @vimlint(EVL102, 1, l:neomake_bufdir) + let neomake_bufdir = fnamemodify(neomake_bufname, ':h') + " @vimlint(EVL102, 1, l:neomake_output_source) + let neomake_output_source = a:source + call map(a:lines, maker.mapexpr) + endif + + if !empty(a:lines) + call s:AddExprCallback(a:jobinfo, a:lines) + endif + catch /^\%(Vim\%((\a\+)\)\=:\%(E48\|E523\)\)\@!/ " everything, but E48/E523 (sandbox / not allowed here) + if v:exception ==# 'NeomakeTestsException' + throw v:exception + endif + call neomake#log#exception(printf( + \ 'Error during output processing for %s: %s.', + \ a:jobinfo.maker.name, v:exception), a:jobinfo) + return + finally + call a:jobinfo.cd_back() + endtry + return g:neomake#action_queue#processed +endfunction + +function! s:process_pending_output(jobinfo, lines, source, ...) abort + let retry_events = s:need_to_postpone_output_processing(a:jobinfo) + if empty(retry_events) + let retry_events = s:ProcessPendingOutput(a:jobinfo, a:lines, a:source) + if empty(retry_events) + return g:neomake#action_queue#processed + endif + endif + + if !a:0 + " Remember pending output, but only when not called via action queue. + call add(a:jobinfo.pending_output, [a:lines, a:source]) + endif + + if index(neomake#action_queue#get_queued_actions(a:jobinfo), + \ ['process_pending_output', retry_events]) == -1 + return neomake#action_queue#add(retry_events, [s:function('s:process_pending_output'), [a:jobinfo, [], a:source, retry_events]]) + endif + return g:neomake#action_queue#not_processed +endfunction + +function! s:ProcessPendingOutput(jobinfo, lines, source) abort + if a:jobinfo.file_mode + let window_make_ids = get(w:, 'neomake_make_ids', []) + if index(window_make_ids, a:jobinfo.make_id) == -1 + if !bufexists(a:jobinfo.bufnr) + call neomake#log#info('No buffer found for output!', a:jobinfo) + return [] + endif + + if a:jobinfo.bufnr != bufnr('%') + call neomake#log#debug(printf('Skipped pending job output for another buffer (current=%d).', bufnr('%')), a:jobinfo) + return ['BufEnter', 'WinEnter'] + elseif neomake#core#get_tabwin_for_makeid(a:jobinfo.make_id) != [-1, -1] + call neomake#log#debug('Skipped pending job output (not in origin window).', a:jobinfo) + return ['WinEnter'] + else + call neomake#log#debug("Processing pending output for job's buffer in new window.", a:jobinfo) + let w:neomake_make_ids = add(get(w:, 'neomake_make_ids', []), a:jobinfo.make_id) + endif + endif + endif + + " Process any pending output first. + if !empty(a:jobinfo.pending_output) + let outputs = {'stdout': [], 'stderr': []} + for [lines, source] in a:jobinfo.pending_output + call extend(outputs[source], lines) + endfor + for [source, lines] in items(outputs) + if !empty(lines) + call s:ProcessJobOutput(a:jobinfo, lines, source) + endif + endfor + call neomake#log#debug(printf( + \ 'Processed %d pending outputs.', len(a:jobinfo.pending_output)), + \ a:jobinfo) + call neomake#action_queue#remove(a:jobinfo, s:function('s:process_pending_output')) + endif + + if !empty(a:lines) + call s:ProcessJobOutput(a:jobinfo, a:lines, a:source) + endif + + " Clean job if it had exited already. + if !empty(a:jobinfo.pending_output) + let a:jobinfo.pending_output = [] + if has_key(a:jobinfo, 'exit_code') + " XXX: add test (tested manually) + call s:CleanJobinfo(a:jobinfo) + endif + endif + return [] +endfunction + +" Do we need to postpone location list processing (creation and :laddexpr)? +function! s:need_to_postpone_loclist(jobinfo) abort + if !a:jobinfo.file_mode + return 0 + endif + if index(get(w:, 'neomake_make_ids', []), a:jobinfo.make_id) != -1 + return 0 + endif + call neomake#log#debug('Postponing location list processing.', a:jobinfo) + return 1 +endfunction + +" TODO: merge with s:handle_locqf_list_for_finished_jobs. +let s:has_getcmdwintype = exists('*getcmdwintype') +function! s:need_to_postpone_output_processing(jobinfo) abort + " We can only process output (change the location/quickfix list) in + " certain modes, otherwise e.g. the visual selection gets lost. + if neomake#compat#in_completion() + call neomake#log#debug('Not processing output during completion.', a:jobinfo) + return ['CompleteDone'] + endif + let mode = neomake#compat#get_mode() + if index(['n', 'i'], mode) == -1 + call neomake#log#debug('Not processing output for mode "'.mode.'".', a:jobinfo) + return ['BufEnter', 'WinEnter', 'InsertLeave', 'CursorHold', 'CursorHoldI'] + endif + if s:has_getcmdwintype && !empty(getcmdwintype()) + call neomake#log#debug('Not processing output from command-line window "'.getcmdwintype().'".', a:jobinfo) + return ['InsertLeave', 'CursorHold', 'CursorHoldI'] + endif + return [] +endfunction + +function! s:RegisterJobOutput(jobinfo, lines, source) abort + " Allow to filter output (storing the setting on the jobinfo lazily). + if !has_key(a:jobinfo, 'filter_output') + let a:jobinfo.filter_output = neomake#utils#GetSetting('filter_output', a:jobinfo.maker, '', a:jobinfo.ft, a:jobinfo.bufnr) + endif + if !empty(a:jobinfo.filter_output) + call call(a:jobinfo.filter_output, [ + \ a:lines, {'source': a:source, 'jobinfo': a:jobinfo}], + \ a:jobinfo.maker) + endif + + if empty(a:lines) + return + endif + + " Register unexpected output. + if a:jobinfo.output_stream !=# 'both' && a:jobinfo.output_stream !=# a:source + if !has_key(a:jobinfo, 'unexpected_output') + let a:jobinfo.unexpected_output = {} + endif + if !has_key(a:jobinfo.unexpected_output, a:source) + let a:jobinfo.unexpected_output[a:source] = [] + endif + let a:jobinfo.unexpected_output[a:source] += a:lines + return + endif + + let make_info = s:make_info[a:jobinfo.make_id] + if has_key(make_info, 'entries_list') " use_list option + " Process output for list processing. + call s:process_pending_output(a:jobinfo, a:lines, a:source) + endif +endfunction + +function! s:vim_output_handler(channel, output, event_type) abort + let channel_id = ch_info(a:channel)['id'] + let jobinfo = get(s:jobs, get(s:map_job_ids, channel_id, -1), {}) + if empty(jobinfo) + call neomake#log#debug(printf("warn: job '%s' not found for output on %s.", + \ a:channel, a:event_type)) + return + endif + let data = split(a:output, '\r\?\n', 1) + call s:output_handler_queued(jobinfo, data, a:event_type, 0) +endfunction + +function! s:vim_output_handler_stdout(channel, output) abort + call s:vim_output_handler(a:channel, a:output, 'stdout') +endfunction + +function! s:vim_output_handler_stderr(channel, output) abort + call s:vim_output_handler(a:channel, a:output, 'stderr') +endfunction + +function! s:vim_exit_handler(channel) abort + let channel_id = ch_info(a:channel)['id'] + let jobinfo = get(s:jobs, get(s:map_job_ids, channel_id, -1), {}) + if empty(jobinfo) + try + let job_info = job_info(ch_getjob(a:channel)) + catch /^Vim(let):E916:/ + " Might happen with older Vim (8.0.69, but not 8.0.586). + call neomake#log#debug(printf('exit: job not found: %s.', a:channel)) + return + endtry + call neomake#log#debug(printf('exit: job not found: %s (%s).', a:channel, job_info)) + return + endif + let job_info = job_info(ch_getjob(a:channel)) + + " Handle failing starts from Vim here. + let status = job_info['exitval'] + if status == 122 " Vim uses EXEC_FAILED, but only on Unix?! + let jobinfo.failed_to_start = 1 + " The error is on stderr. + let error = 'Vim job failed to run: '.substitute(join(jobinfo.stderr), '\v\s+$', '', '').'.' + let jobinfo.stderr = [] + call neomake#log#error(error) + call s:CleanJobinfo(jobinfo) + else + call s:exit_handler(jobinfo, status) + endif +endfunction + +" @vimlint(EVL108, 1) +if has('nvim-0.2.0') +" @vimlint(EVL108, 0) + function! s:nvim_output_handler(job_id, data, event_type) abort + let jobinfo = get(s:jobs, get(s:map_job_ids, a:job_id, -1), {}) + if empty(jobinfo) + call neomake#log#debug(printf('output [%s]: job %d not found.', a:event_type, a:job_id)) + return + endif + if a:data == [''] && !exists('jobinfo[a:event_type]') + " EOF in Neovim (see :h on_data). + return + endif + call s:output_handler_queued(jobinfo, copy(a:data), a:event_type, 1) + endfunction +else + " Neovim: register output from jobs as quick as possible, and trigger + " processing through a timer. + " This works around https://github.com/neovim/neovim/issues/5889). + " NOTE: a:data is never [''] here (like with other/newer Neovim + " handlers) + let s:nvim_output_handler_queue = [] + function! s:nvim_output_handler(job_id, data, event_type) abort + let jobinfo = get(s:jobs, get(s:map_job_ids, a:job_id, -1), {}) + if empty(jobinfo) + call neomake#log#debug(printf('output [%s]: job %d not found.', a:event_type, a:job_id)) + return + endif + let args = [jobinfo, copy(a:data), a:event_type, 1] + call add(s:nvim_output_handler_queue, args) + if !exists('jobinfo._nvim_in_handler') + let jobinfo._nvim_in_handler = 1 + else + let jobinfo._nvim_in_handler += 1 + endif + if !exists('s:nvim_output_handler_timer') + let s:nvim_output_handler_timer = timer_start(0, function('s:nvim_output_handler_cb')) + endif + endfunction + + function! s:nvim_output_handler_cb(_timer) abort + while !empty(s:nvim_output_handler_queue) + let args = remove(s:nvim_output_handler_queue, 0) + let jobinfo = args[0] + call call('s:output_handler', args) + let jobinfo._nvim_in_handler -= 1 + + if !jobinfo._nvim_in_handler + " Trigger previously delayed exit handler. + unlet jobinfo._nvim_in_handler + if exists('jobinfo._exited_while_in_handler') + call neomake#log#debug('Trigger delayed exit.', jobinfo) + call s:exit_handler(jobinfo, jobinfo._exited_while_in_handler) + endif + endif + endwhile + unlet! s:nvim_output_handler_timer + endfunction +endif + +" Exit handler for buffered output with Neovim. +" In this case the output gets stored on the jobstart-options dict. +function! s:nvim_exit_handler_buffered(job_id, data, _event_type) abort + let jobinfo = get(s:jobs, get(s:map_job_ids, a:job_id, -1), {}) + if empty(jobinfo) + call neomake#log#debug(printf('exit: job not found: %d.', a:job_id)) + return + endif + + for stream in ['stdout', 'stderr'] + if has_key(jobinfo.jobstart_opts, stream) + let data = copy(jobinfo.jobstart_opts[stream]) + if data == [''] + " EOF in Neovim (see :h on_data). + continue + endif + call s:output_handler(jobinfo, data, stream, 1) + endif + endfor + + call s:exit_handler(jobinfo, a:data) +endfunction + +function! s:nvim_exit_handler(job_id, data, _event_type) abort + let jobinfo = get(s:jobs, get(s:map_job_ids, a:job_id, -1), {}) + if empty(jobinfo) + call neomake#log#debug(printf('exit: job not found: %d.', a:job_id)) + return + endif + call s:exit_handler(jobinfo, a:data) +endfunction + +function! s:exit_handler(jobinfo, data) abort + let jobinfo = a:jobinfo + let jobinfo.exit_code = a:data + let maker = jobinfo.maker + if get(jobinfo, 'canceled') + call neomake#log#debug(printf('exit: %s: %s (job was canceled).', + \ maker.name, string(a:data)), jobinfo) + call s:CleanJobinfo(jobinfo) + return + endif + + if exists('jobinfo._output_while_in_handler') || exists('jobinfo._nvim_in_handler') + let jobinfo._exited_while_in_handler = a:data + call neomake#log#debug(printf('exit (delayed): %s: %s.', + \ maker.name, string(a:data)), jobinfo) + return + endif + call neomake#log#debug(printf('exit: %s: %s.', + \ maker.name, string(a:data)), jobinfo) + + let jobinfo._in_exit_handler = 1 + try + " Handle any unfinished lines from stdout/stderr callbacks. + for event_type in ['stdout', 'stderr'] + if has_key(jobinfo, event_type) + let lines = jobinfo[event_type] + if !empty(lines) + if lines[-1] ==# '' + call remove(lines, -1) + endif + if !empty(lines) + call s:RegisterJobOutput(jobinfo, lines, event_type) + endif + unlet jobinfo[event_type] + endif + endif + endfor + + if !get(jobinfo, 'failed_to_start') + let l:ExitCallback = neomake#utils#GetSetting('exit_callback', + \ extend(copy(jobinfo), maker), 0, jobinfo.ft, jobinfo.bufnr) + if ExitCallback isnot# 0 + let callback_dict = { 'status': jobinfo.exit_code, + \ 'name': maker.name, + \ 'has_next': !empty(s:make_info[jobinfo.make_id].jobs_queue) } + try + if type(ExitCallback) == type('') + let l:ExitCallback = function(ExitCallback) + endif + call call(ExitCallback, [callback_dict], jobinfo) + catch + call neomake#log#error(printf( + \ 'Error during exit_callback: %s.', v:exception), + \ jobinfo) + endtry + endif + endif + + if s:async + if has('nvim') || jobinfo.exit_code != 122 + call neomake#log#debug(printf( + \ '%s: completed with exit code %d.', + \ maker.name, jobinfo.exit_code), jobinfo) + endif + let jobinfo.finished = 1 + endif + + if has_key(jobinfo, 'unexpected_output') + for [source, output] in items(jobinfo.unexpected_output) + let msg = printf('%s: unexpected output on %s: ', maker.name, source) + call neomake#log#debug(msg . join(output, '\n') . '.', jobinfo) + + echohl WarningMsg + echom printf('Neomake: %s%s', msg, output[0]) + for line in output[1:-1] + echom line + endfor + echohl None + endfor + " NOTE: messages do not cause a wait-enter prompt during job + " callback processing. Therefore we're giving a final + " message referring to ":messages". + " (related: https://github.com/vim/vim/issues/836) + if s:async + call neomake#log#error(printf( + \ '%s: unexpected output. See :messages for more information.', maker.name), jobinfo) + else + " For non-async the above messages are visible, but we want an + " error for the log also. + call neomake#log#error(printf('%s: unexpected output.', maker.name), jobinfo) + endif + endif + finally + unlet jobinfo._in_exit_handler + endtry + call s:handle_next_job(jobinfo) +endfunction + +function! s:output_handler_queued(jobinfo, data, event_type, trim_CR) abort + let jobinfo = a:jobinfo + if exists('jobinfo._output_while_in_handler') + call neomake#log#debug(printf('Queuing: %s: %s: %s.', + \ a:event_type, jobinfo.maker.name, string(a:data)), jobinfo) + let jobinfo._output_while_in_handler += [[jobinfo, a:data, a:event_type, a:trim_CR]] + return + else + let jobinfo._output_while_in_handler = [] + endif + + call s:output_handler(jobinfo, a:data, a:event_type, a:trim_CR) + + " Process queued events that might have arrived by now. + " The attribute might be unset here, since output_handler might have + " been interrupted. + if exists('jobinfo._output_while_in_handler') + while has_key(jobinfo, '_output_while_in_handler') && !empty(jobinfo._output_while_in_handler) + let args = remove(jobinfo._output_while_in_handler, 0) + call call('s:output_handler', args) + endwhile + unlet! jobinfo._output_while_in_handler + endif + " Trigger previously delayed exit handler. + if exists('jobinfo._exited_while_in_handler') + call neomake#log#debug('Trigger delayed exit.', jobinfo) + call s:exit_handler(jobinfo, jobinfo._exited_while_in_handler) + endif +endfunction + +function! s:output_handler(jobinfo, data, event_type, trim_CR) abort + let jobinfo = a:jobinfo + call neomake#log#debug(printf('output on %s: %s.', + \ a:event_type, string(a:data)), jobinfo) + if get(jobinfo, 'canceled') + call neomake#log#debug('Ignoring output (job was canceled).', jobinfo) + return + endif + let data = copy(a:data) + if a:trim_CR && !empty(a:data) + call map(data, "substitute(v:val, '\\r$', '', '')") + endif + let last_event_type = get(jobinfo, 'event_type', a:event_type) + + " data is a list of 'lines' read. Each element *after* the first + " element represents a newline. + if has_key(jobinfo, a:event_type) + let jobinfo[a:event_type][-1] .= data[0] + call extend(jobinfo[a:event_type], data[1:]) + else + let jobinfo[a:event_type] = data + endif + + if !jobinfo.buffer_output || last_event_type !=# a:event_type + let lines = jobinfo[a:event_type][:-2] + let jobinfo[a:event_type] = jobinfo[a:event_type][-1:] + + if !empty(lines) + call s:RegisterJobOutput(jobinfo, lines, a:event_type) + endif + endif +endfunction + +function! s:abort_next_makers(make_id) abort + let jobs_queue = s:make_info[a:make_id].jobs_queue + if !empty(jobs_queue) + let next_makers = join(map(copy(jobs_queue), 'v:val.maker.name'), ', ') + call neomake#log#info('Aborting next makers: '.next_makers.'.', {'make_id': a:make_id}) + let s:make_info[a:make_id].aborted_jobs = copy(s:make_info[a:make_id].jobs_queue) + let s:make_info[a:make_id].jobs_queue = [] + endif +endfunction + +function! s:handle_next_job(prev_jobinfo) abort + let make_id = get(a:prev_jobinfo, 'make_id', s:make_id) + if !has_key(s:make_info, make_id) + return {} + endif + let make_info = s:make_info[make_id] + + if !empty(a:prev_jobinfo) + let status = get(a:prev_jobinfo, 'exit_code', 0) + if status != 0 && index([122, 127], status) == -1 + " TODO: mark maker.exe as non-executable with status 127, and + " maybe re-introduce a wrapper for `executable()` to handle it. + " Ref: https://github.com/neomake/neomake/issues/1699 + if neomake#utils#GetSetting('serialize_abort_on_error', a:prev_jobinfo.maker, 0, a:prev_jobinfo.ft, a:prev_jobinfo.bufnr) + let a:prev_jobinfo.aborted = 1 + call s:abort_next_makers(make_id) + call s:CleanJobinfo(a:prev_jobinfo) + return {} + endif + endif + call s:CleanJobinfo(a:prev_jobinfo) + if !has_key(s:make_info, make_id) + " Last job was cleaned. + return {} + endif + + let serializing_for_job = get(make_info, 'serializing_for_job') + if serializing_for_job + if serializing_for_job != a:prev_jobinfo.id + call neomake#log#debug(printf('waiting for job %d to finish.', serializing_for_job)) + return {} + endif + unlet make_info.serializing_for_job + endif + endif + + " Create job from the start of the queue, returning it. + while !empty(make_info.jobs_queue) + let options = remove(make_info.jobs_queue, 0) + let maker = options.maker + if empty(maker) + continue + endif + + " Serialization of jobs, always for non-async Vim. + if !has_key(options, 'serialize') + if !s:async || neomake#utils#GetSetting('serialize', maker, 0, options.ft, options.bufnr) + let options.serialize = 1 + else + let options.serialize = 0 + endif + endif + try + let jobinfo = s:MakeJob(make_id, options) + catch /^Neomake: / + let log_context = extend(options, {'make_id': make_id}) + if v:exception =~# '\v^Neomake: skip_job: ' + let msg = substitute(v:exception, '^Neomake: skip_job: ', '', '') + call neomake#log#debug(printf('Skipping job: %s', msg), log_context) + else + let error = substitute(v:exception, '^Neomake: ', '', '') + call neomake#log#exception(error, log_context) + + if options.serialize + if neomake#utils#GetSetting('serialize_abort_on_error', maker, 0, options.ft, options.bufnr) + call s:abort_next_makers(make_id) + break + endif + endif + endif + continue + endtry + if !empty(jobinfo) + return jobinfo + endif + endwhile + + " Cleanup make info, but only if there are no queued actions. + for [_, v] in g:neomake#action_queue#_s.action_queue + if v[1][0] == make_info + call neomake#log#debug('Skipping cleaning of make info for queued actions.', make_info) + return {} + endif + endfor + call s:clean_make_info(make_info) + return {} +endfunction + +function! neomake#_add_error(maker_type, entry) abort + if !has_key(s:current_errors[a:maker_type], a:entry.bufnr) + let s:current_errors[a:maker_type][a:entry.bufnr] = {} + endif + if !has_key(s:current_errors[a:maker_type][a:entry.bufnr], a:entry.lnum) + let s:current_errors[a:maker_type][a:entry.bufnr][a:entry.lnum] = [a:entry] + else + call add(s:current_errors[a:maker_type][a:entry.bufnr][a:entry.lnum], a:entry) + endif +endfunction + +function! neomake#get_nearest_error() abort + let buf = bufnr('%') + let ln = line('.') + let ln_errors = [] + + for maker_type in ['file', 'project'] + let buf_errors = get(s:current_errors[maker_type], buf, {}) + let ln_errors += get(buf_errors, ln, []) + endfor + + if empty(ln_errors) + return {} + endif + + if len(ln_errors) > 1 + call sort(ln_errors, function('neomake#utils#sort_by_col')) + endif + return ln_errors[0] +endfunction + +function! neomake#GetCurrentErrorMsg() abort + let entry = neomake#get_nearest_error() + if empty(entry) + return '' + endif + let r = entry.maker_name . ': ' . entry.text + let suffix = entry.type . (entry.nr != -1 ? entry.nr : '') + if !empty(suffix) + let r .= ' ('.suffix.')' + endif + return r +endfunction + +function! neomake#EchoCurrentError(...) abort + if !get(g:, 'neomake_echo_current_error', 1) + return + endif + " a:1 might be a timer from the VimResized event. + let force = a:0 ? a:1 : 0 + + let message = neomake#GetCurrentErrorMsg() + if empty(message) + if exists('s:neomake_last_echoed_error') + echon '' + unlet s:neomake_last_echoed_error + endif + return + endif + if !force && exists('s:neomake_last_echoed_error') + \ && s:neomake_last_echoed_error == message + return + endif + let s:neomake_last_echoed_error = message + call neomake#utils#WideMessage(message) +endfunction + +function! neomake#CursorMoved() abort + call neomake#EchoCurrentError() + call neomake#virtualtext#handle_current_error() +endfunction + +function! s:cursormoved_delayed_cb(...) abort + if getpos('.') == s:cursormoved_last_pos + call neomake#CursorMoved() + endif +endfunction +function! neomake#CursorMovedDelayed() abort + if exists('s:cursormoved_timer') + call timer_stop(s:cursormoved_timer) + endif + let delay = get(g:, 'neomake_cursormoved_delay', 100) + let s:cursormoved_timer = timer_start(delay, function('s:cursormoved_delayed_cb')) + let s:cursormoved_last_pos = getpos('.') +endfunction + +function! neomake#Make(file_mode_or_options, ...) abort + if type(a:file_mode_or_options) == type({}) + return s:Make(a:file_mode_or_options) + endif + + let file_mode = a:file_mode_or_options + let options = {'file_mode': file_mode} + if file_mode + let options.ft = &filetype + endif + if a:0 + if !empty(a:1) + let maker_names = a:1 + " Split names on non-breaking space (annotation from completion). + call map(maker_names, "type(v:val) == 1 ? split(v:val, ' (')[0] : v:val") + let options.enabled_makers = a:1 + endif + if a:0 > 1 + let options.exit_callback = a:2 + endif + endif + return map(copy(s:Make(options)), 'v:val.id') +endfunction + +function! neomake#ShCommand(bang, sh_command, ...) abort + let maker = neomake#utils#MakerFromCommand(a:sh_command) + let maker.name = 'sh: '.a:sh_command + let maker.errorformat = '%m' + let maker.default_entry_type = '' + let options = { + \ 'enabled_makers': [maker], + \ 'file_mode': 0, + \ 'output_stream': 'both', + \ 'buffer_output': !a:bang, + \ } + if a:0 + call extend(options, a:1) + endif + let jobinfos = s:Make(options) + return empty(jobinfos) ? -1 : jobinfos[0].id +endfunction + +function! neomake#Sh(sh_command, ...) abort + " Deprecated, but documented. + let options = a:0 ? { 'exit_callback': a:1 } : {} + return neomake#ShCommand(0, a:sh_command, options) +endfunction + +function! neomake#map_makers(makers, ft, auto_enabled) abort + let makers = [] + let errors = [] + let get_args = a:ft is# -1 ? [] : [a:ft] + for maker in a:makers + try + let m = call('neomake#GetMaker', [maker] + get_args) + catch /^Neomake: / + call add(errors, substitute(v:exception, '^Neomake: ', '', '').'.') + unlet maker " vim73/vim-trusty + continue + endtry + call add(makers, m) + unlet maker " vim73/vim-trusty + endfor + if !empty(errors) + let log_context = get(s:make_info, s:make_id, {}) + for error in errors + if a:auto_enabled + call neomake#log#debug(error, log_context) + else + call neomake#log#error(error, log_context) + endif + endfor + endif + " Set auto_enabled, but keep explicitly set value. + call map(makers, 'extend(v:val, {''auto_enabled'': a:auto_enabled}, ''keep'')') + return makers +endfunction diff --git a/bundle/neomake/autoload/neomake/action_queue.vim b/bundle/neomake/autoload/neomake/action_queue.vim new file mode 100644 index 000000000..33b9652a6 --- /dev/null +++ b/bundle/neomake/autoload/neomake/action_queue.vim @@ -0,0 +1,309 @@ +if !exists('s:action_queue') + let s:action_queue = [] +endif +if !exists('s:action_queue_registered_events') + let s:action_queue_registered_events = [] +endif +let s:action_queue_timer_timeouts = get(g:, 'neomake_action_queue_timeouts', {1: 100, 2: 200, 3: 500}) + +let g:neomake#action_queue#processed = {} +let g:neomake#action_queue#not_processed = {} +let g:neomake#action_queue#any_event = [] + +let g:neomake#action_queue#_s = s: + +function! s:actionname(funcref) abort + let s = string(a:funcref) + let r = matchstr(s, '\v^^function\(''\zs.*\ze''\)$') + if empty(r) + return s + endif + return substitute(r, '\v^(\\d+_|s:)', '', '') +endfunction + +" Queue an action to be processed later for autocmd a:event or through a timer +" for a:event=Timer. +" It will call a:data[0], with a:data[1] as args (where the first should be +" a jobinfo object). The callback should return 1 if it was successful, +" with 0 it will be re-queued. +" When called recursively (queuing the same event/data again, it will be +" re-queued also). +function! neomake#action_queue#add(events, data) abort + let job_or_make_info = a:data[1][0] + if a:events is# g:neomake#action_queue#any_event + call neomake#log#debug(printf('Queuing action %s for any event.', + \ s:actionname(a:data[0])), job_or_make_info) + else + call neomake#log#debug(printf('Queuing action %s for %s.', + \ s:actionname(a:data[0]), join(a:events, ', ')), job_or_make_info) + endif + + for event in a:events + if event ==# 'Timer' + if !has_key(job_or_make_info, 'action_queue_timer_tries') + let job_or_make_info.action_queue_timer_tries = {'count': 1, 'data': a:data[0]} + else + let job_or_make_info.action_queue_timer_tries.count += 1 + endif + if has_key(s:action_queue_timer_timeouts, job_or_make_info.action_queue_timer_tries.count) + let timeout = s:action_queue_timer_timeouts[job_or_make_info.action_queue_timer_tries.count] + else + throw printf('Neomake: Giving up handling Timer callbacks after %d attempts. Please report this. See :messages for more information.', len(s:action_queue_timer_timeouts)) + endif + if has('timers') + if exists('s:action_queue_timer') + call timer_stop(s:action_queue_timer) + endif + let s:action_queue_timer = timer_start(timeout, function('s:process_action_queue_timer_cb')) + call neomake#log#debug(printf( + \ 'Retrying Timer event in %dms (timer %d).', + \ timeout, s:action_queue_timer), job_or_make_info) + else + call neomake#log#debug('Retrying Timer event on CursorHold(I).', job_or_make_info) + if !exists('#neomake_event_queue#CursorHold') + let s:action_queue_registered_events += ['CursorHold', 'CursorHoldI'] + augroup neomake_event_queue + exe 'autocmd CursorHold,CursorHoldI * call s:process_action_queue('''.event.''')' + augroup END + endif + endif + else + if !exists('#neomake_event_queue#'.event) + let s:action_queue_registered_events += [event] + augroup neomake_event_queue + exe 'autocmd '.event.' * call s:process_action_queue('''.event.''')' + augroup END + endif + endif + endfor + call add(s:action_queue, [a:events, a:data]) + return g:neomake#action_queue#not_processed +endfunction + +" Remove any queued actions for a jobinfo or make_info object. +function! neomake#action_queue#clean(job_or_make_info) abort + let len_before = len(s:action_queue) + call filter(s:action_queue, 'v:val[1][1][0] != a:job_or_make_info') + let removed = len_before - len(s:action_queue) + if removed + call s:clean_action_queue_events() + call neomake#log#debug(printf( + \ 'Removed %d action queue entries.', + \ removed), a:job_or_make_info) + endif +endfunction + +" Remove given action for a jobinfo or make_info object. +function! neomake#action_queue#remove(job_or_make_info, action) abort + let len_before = len(s:action_queue) + call filter(s:action_queue, 'v:val[1][1][0] != a:job_or_make_info || v:val[1][0] != a:action') + let removed = len_before - len(s:action_queue) + if removed + call s:clean_action_queue_events() + call neomake#log#debug(printf( + \ 'Removed %d action queue entries for %s.', + \ removed, s:actionname(a:action)), a:job_or_make_info) + endif +endfunction + +function! s:process_action_queue_timer_cb(...) abort + call neomake#log#debug(printf( + \ 'action queue: callback for Timer queue (%d).', s:action_queue_timer)) + unlet s:action_queue_timer + call s:process_action_queue('Timer') +endfunction + +function! s:process_action_queue(event) abort + let queue = s:action_queue + let q_for_this_event = [] + let i = 0 + if g:neomake#core#_ignore_autocommands + call neomake#log#debug(printf('action queue: skip processing for %s (ignore_autocommands=%d).', + \ a:event, g:neomake#core#_ignore_autocommands), + \ {'bufnr': bufnr('%'), 'winnr': winnr()}) + return + endif + for [events, v] in queue + if index(events, a:event) != -1 || events is# g:neomake#action_queue#any_event + call add(q_for_this_event, [i, v]) + endif + let i += 1 + endfor + call neomake#log#debug(printf('action queue: processing for %s (%d items).', + \ a:event, len(q_for_this_event)), {'bufnr': bufnr('%'), 'winnr': winnr()}) + call neomake#log#indent(1) + + let processed = [] + let removed = 0 + let stop_processing = {'make_id': [], 'job_id': []} + for [idx_q_for_this_event, data] in q_for_this_event + let job_or_make_info = data[1][0] + let current_event = remove(queue, idx_q_for_this_event - removed) + let removed += 1 + + let make_id_job_id = {} " make_id/job_id relevant to re-queue following. + if has_key(job_or_make_info, 'make_id') + if has_key(job_or_make_info, 'options') + let make_id_job_id = { + \ 'make_id': job_or_make_info.make_id, + \ } + else + let make_id_job_id = { + \ 'make_id': job_or_make_info.make_id, + \ 'job_id': job_or_make_info.id, + \ } + endif + endif + + " Skip/re-queue entries for same make/job. + let skip = 0 + for [prop_name, prop_value] in items(make_id_job_id) + if index(stop_processing[prop_name], prop_value) != -1 + call neomake#log#debug(printf('action queue: skipping %s for not processed %s.', + \ s:actionname(data[0]), prop_name), job_or_make_info) + call add(queue, current_event) + let skip = 1 + break + endif + endfor + if skip + continue + endif + + call neomake#log#debug(printf('action queue: calling %s.', + \ s:actionname(data[0])), job_or_make_info) + let queue_before_call = copy(queue) + try + " Call the queued action. On failure they should have requeued + " themselves already. + let rv = call(data[0], data[1]) + catch + if v:exception =~# '^Neomake: ' + let error = substitute(v:exception, '^Neomake: ', '', '') + else + let error = printf('Error during action queue processing: %s.', + \ v:exception) + endif + call neomake#log#exception(error, job_or_make_info) + + " Cancel job in case its action failed to get re-queued after X + " attempts. + if has_key(job_or_make_info, 'id') + call neomake#CancelJob(job_or_make_info.id) + endif + continue + endtry + if rv is# g:neomake#action_queue#processed + let processed += [data] + continue + endif + + if rv is# g:neomake#action_queue#not_processed + if a:event !=# 'Timer' && has_key(job_or_make_info, 'action_queue_timer_tries') + call neomake#log#debug('s:process_action_queue: decrementing timer tries for non-Timer event.', job_or_make_info) + let job_or_make_info.action_queue_timer_tries.count -= 1 + endif + + " Requeue any entries for the same job. + let i = 0 + for q in queue_before_call + for [prop_name, prop_value] in items(make_id_job_id) + " Assert current_event != q + if get(q[1][1][0], prop_name) == prop_value + call neomake#log#debug(printf('action queue: re-queuing %s for not processed %s.', + \ s:actionname(q[1][0]), prop_name), job_or_make_info) + call add(queue, remove(queue, i)) + let i -= 1 + break + endif + endfor + let i += 1 + endfor + for [prop_name, prop_value] in items(make_id_job_id) + call add(stop_processing[prop_name], prop_value) + endfor + else + let args_str = neomake#utils#Stringify(data[1]) + throw printf('Internal Neomake error: hook function %s(%s) returned unexpected value (%s)', data[0], args_str, rv) + endif + endfor + call neomake#log#debug(printf('action queue: processed %d items.', + \ len(processed)), {'bufnr': bufnr('%')}) + call neomake#log#indent(-1) + + call s:clean_action_queue_events() +endfunction + +if has('timers') + function! s:get_left_events() abort + let r = {} + for [events, _] in s:action_queue + for event in events + let r[event] = 1 + endfor + endfor + return keys(r) + endfunction +else + function! s:get_left_events() abort + let r = {} + for [events, _] in s:action_queue + for event in events + if event ==# 'Timer' + let r['CursorHold'] = 1 + let r['CursorHoldI'] = 1 + else + let r[event] = 1 + endif + endfor + endfor + return keys(r) + endfunction +endif + +function! neomake#action_queue#get_queued_actions(jobinfo) abort + " Check if there are any queued actions for this job. + let queued_actions = [] + for [events, v] in s:action_queue + if v[1][0] == a:jobinfo + let queued_actions += [[s:actionname(v[0]), events]] + endif + endfor + return queued_actions +endfunction + +function! s:clean_action_queue_events() abort + let left_events = s:get_left_events() + + if empty(left_events) + if exists('#neomake_event_queue') + autocmd! neomake_event_queue + augroup! neomake_event_queue + endif + else + let clean_events = [] + for event in s:action_queue_registered_events + if index(left_events, event) == -1 + let clean_events += [event] + endif + endfor + if !empty(clean_events) + augroup neomake_event_queue + for event in clean_events + if exists('#neomake_event_queue#'.event) + exe 'au! '.event + endif + endfor + augroup END + endif + endif + let s:action_queue_registered_events = left_events + + if index(left_events, 'Timer') == -1 + if exists('s:action_queue_timer') + call timer_stop(s:action_queue_timer) + unlet s:action_queue_timer + endif + endif +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/cmd.vim b/bundle/neomake/autoload/neomake/cmd.vim new file mode 100644 index 000000000..84f606dc9 --- /dev/null +++ b/bundle/neomake/autoload/neomake/cmd.vim @@ -0,0 +1,194 @@ +scriptencoding utf8 + +let s:last_completion = [] +function! neomake#cmd#complete_makers(ArgLead, CmdLine, ...) abort + if a:CmdLine !~# '\s' + " Just 'Neomake!' without following space. + return [' '] + endif + + " Filter only by name before non-breaking space. + let filter_name = split(a:ArgLead, ' ', 1)[0] + + let file_mode = a:CmdLine =~# '\v^(Neomake|NeomakeFile)\s' + + let compl_info = [bufnr('%'), &filetype, a:CmdLine] + if empty(&filetype) + let maker_names = neomake#GetProjectMakers() + else + let maker_names = neomake#GetMakers(&filetype) + + " Prefer (only) makers for the current filetype. + if file_mode + if !empty(filter_name) + call filter(maker_names, 'v:val[:len(filter_name)-1] ==# filter_name') + endif + if empty(maker_names) || s:last_completion == compl_info + call extend(maker_names, neomake#GetProjectMakers()) + endif + else + call extend(maker_names, neomake#GetProjectMakers()) + endif + endif + + " Only display executable makers. + let makers = [] + for maker_name in maker_names + try + let maker = neomake#GetMaker(maker_name) + catch /^Neomake: / + let error = substitute(v:exception, '^Neomake: ', '', '').'.' + call neomake#log#debug(printf('Could not get maker %s: %s', + \ maker_name, error)) + continue + endtry + if type(get(maker, 'exe', 0)) != type('') || executable(maker.exe) + let makers += [[maker_name, maker]] + endif + endfor + + " Append maker.name if it differs, uses non-breaking-space. + let r = [] + for [maker_name, maker] in makers + if maker.name !=# maker_name + \ && (empty(a:ArgLead) || stridx(maker_name, a:ArgLead) != 0) + let r += [printf('%s (%s)', maker_name, maker.name)] + else + let r += [maker_name] + endif + endfor + + let s:last_completion = compl_info + if !empty(filter_name) + call filter(r, 'v:val[:len(filter_name)-1] ==# filter_name') + endif + return r +endfunction + +function! neomake#cmd#complete_jobs(...) abort + return join(map(neomake#GetJobs(), "v:val.id.': '.v:val.maker.name"), "\n") +endfunction + +function! s:is_neomake_list(list) abort + if empty(a:list) + return 0 + endif + return a:list[0].text =~# ' nmcfg:{.\{-}}$' +endfunction + +function! neomake#cmd#clean(file_mode) abort + let buf = bufnr('%') + call neomake#_clean_errors({ + \ 'file_mode': a:file_mode, + \ 'bufnr': buf, + \ }) + if a:file_mode + if s:is_neomake_list(getloclist(0)) + call setloclist(0, [], 'r') + lclose + endif + call neomake#signs#ResetFile(buf) + call neomake#statusline#ResetCountsForBuf(buf) + else + if s:is_neomake_list(getqflist()) + call setqflist([], 'r') + cclose + endif + call neomake#signs#ResetProject() + call neomake#statusline#ResetCountsForProject() + endif + call neomake#EchoCurrentError(1) + call neomake#virtualtext#handle_current_error() +endfunction + +" Enable/disable/toggle commands. {{{ +function! s:handle_disabled_status(scope, disabled) abort + if a:scope is# g: + if a:disabled + if exists('#neomake') + autocmd! neomake + augroup! neomake + endif + call neomake#configure#disable_automake() + call neomake#virtualtext#handle_current_error() + else + call neomake#setup#setup_autocmds() + endif + elseif a:scope is# t: + let buffers = neomake#compat#uniq(sort(tabpagebuflist())) + if a:disabled + for b in buffers + call neomake#configure#disable_automake_for_buffer(b) + endfor + else + for b in buffers + call neomake#configure#enable_automake_for_buffer(b) + endfor + endif + elseif a:scope is# b: + let bufnr = bufnr('%') + if a:disabled + call neomake#configure#disable_automake_for_buffer(bufnr) + else + call neomake#configure#enable_automake_for_buffer(bufnr) + endif + endif + call neomake#cmd#display_status() + call neomake#configure#automake() + call neomake#statusline#clear_cache() +endfunction + +function! neomake#cmd#disable(scope) abort + let old = get(get(a:scope, 'neomake', {}), 'disabled', -1) + if old ==# 1 + return + endif + call neomake#config#set_dict(a:scope, 'neomake.disabled', 1) + call s:handle_disabled_status(a:scope, 1) +endfunction + +function! neomake#cmd#enable(scope) abort + let old = get(get(a:scope, 'neomake', {}), 'disabled', -1) + if old ==# 0 + return + endif + call neomake#config#set_dict(a:scope, 'neomake.disabled', 0) + call s:handle_disabled_status(a:scope, 0) +endfunction + +function! neomake#cmd#toggle(scope) abort + let new = !get(get(a:scope, 'neomake', {}), 'disabled', 0) + if new + call neomake#config#set_dict(a:scope, 'neomake.disabled', 1) + call s:handle_disabled_status(a:scope, 1) + else + call neomake#config#unset_dict(a:scope, 'neomake.disabled') + call s:handle_disabled_status(a:scope, 0) + endif +endfunction + +function! neomake#cmd#display_status() abort + let [disabled, source] = neomake#config#get_with_source('disabled', 0) + let msg = 'Neomake is ' . (disabled ? 'disabled' : 'enabled') + if source !=# 'default' + let msg .= ' ('.source.')' + endif + + " Add information from different scopes (if explicitly configured there). + for [scope_name, scope] in [['buffer', b:], ['tab', t:], ['global', g:]] + if scope_name ==# source + continue + endif + let disabled = get(get(scope, 'neomake', {}), 'disabled', -1) + if disabled != -1 + let msg .= printf(' [%s: %s]', scope_name, disabled ? 'disabled' : 'enabled') + endif + endfor + let msg .= '.' + + echom msg + call neomake#log#debug(msg) +endfunction +" }}} + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/compat.vim b/bundle/neomake/autoload/neomake/compat.vim new file mode 100644 index 000000000..d90b822a7 --- /dev/null +++ b/bundle/neomake/autoload/neomake/compat.vim @@ -0,0 +1,327 @@ +" Compatibility wrappers for different (Neo)Vim versions and platforms. + +if neomake#utils#IsRunningWindows() + let g:neomake#compat#dev_null = 'NUL' +else + let g:neomake#compat#dev_null = '/dev/null' +endif + +if v:version >= 704 + function! neomake#compat#getbufvar(buf, key, def) abort + return getbufvar(a:buf, a:key, a:def) + endfunction + function! neomake#compat#getwinvar(win, key, def) abort + return getwinvar(a:win, a:key, a:def) + endfunction +else + function! neomake#compat#getbufvar(buf, key, def) abort + return get(getbufvar(a:buf, ''), a:key, a:def) + endfunction + function! neomake#compat#getwinvar(win, key, def) abort + return get(getwinvar(a:win, ''), a:key, a:def) + endfunction +endif + +unlockvar neomake#compat#json_true +unlockvar neomake#compat#json_false +unlockvar neomake#compat#json_null +unlockvar neomake#compat#json_none + +if exists('v:none') + let neomake#compat#json_none = v:none +else + let neomake#compat#json_none = [] +endif + +if exists('*json_decode') + let neomake#compat#json_true = v:true + let neomake#compat#json_false = v:false + let neomake#compat#json_null = v:null + + if has('nvim') + function! neomake#compat#json_decode(json) abort + if a:json is# '' + " Prevent Neovim from throwing E474: Attempt to decode a blank string. + return g:neomake#compat#json_none + endif + return json_decode(a:json) + endfunction + else + function! neomake#compat#json_decode(json) abort + return json_decode(a:json) + endfunction + endif +else + let neomake#compat#json_true = 1 + let neomake#compat#json_false = 0 + function! s:json_null() abort + endfunction + let neomake#compat#json_null = [function('s:json_null')] + + " Via Syntastic (https://github.com/vim-syntastic/syntastic/blob/6fb14d624b6081459360fdbba743f82cf84c8f92/autoload/syntastic/preprocess.vim#L576-L607), + " based on https://github.com/MarcWeber/vim-addon-json-encoding/blob/master/autoload/json_encoding.vim. + " @vimlint(EVL102, 1, l:true) + " @vimlint(EVL102, 1, l:false) + " @vimlint(EVL102, 1, l:null) + function! neomake#compat#json_decode(json) abort " {{{2 + if a:json ==# '' + return g:neomake#compat#json_none + endif + + " The following is inspired by https://github.com/MarcWeber/vim-addon-manager and + " http://stackoverflow.com/questions/17751186/iterating-over-a-string-in-vimscript-or-parse-a-json-file/19105763#19105763 + " A hat tip to Marc Weber for this trick + " Replace newlines, which eval() does not like. + let json = substitute(a:json, "\n", '', 'g') + if substitute(json, '\v\"%(\\.|[^"\\])*\"|true|false|null|[+-]?\d+%(\.\d+%([Ee][+-]?\d+)?)?', '', 'g') !~# "[^,:{}[\\] \t]" + " JSON artifacts + let true = g:neomake#compat#json_true + let false = g:neomake#compat#json_false + let null = g:neomake#compat#json_null + + try + let object = eval(json) + catch + throw 'Neomake: Failed to parse JSON input: '.v:exception + endtry + else + throw 'Neomake: Failed to parse JSON input: invalid input' + endif + + return object + endfunction " }}}2 + " @vimlint(EVL102, 0, l:true) + " @vimlint(EVL102, 0, l:false) + " @vimlint(EVL102, 0, l:null) +endif + +lockvar neomake#compat#json_true +lockvar neomake#compat#json_false +lockvar neomake#compat#json_null + +if exists('*uniq') + function! neomake#compat#uniq(l) abort + return uniq(a:l) + endfunction +else + function! neomake#compat#uniq(l) abort + let n = len(a:l) + if n < 2 + return a:l + endif + let prev = a:l[0] + let idx = 1 + while idx < n + if a:l[idx] ==# prev && type(a:l[idx]) == type(prev) + call remove(a:l, idx) + let n -= 1 + else + let prev = a:l[idx] + let idx += 1 + endif + endwhile + return a:l + endfunction +endif + +if exists('*reltimefloat') + function! neomake#compat#reltimefloat() abort + return reltimefloat(reltime()) + endfunction +else + function! neomake#compat#reltimefloat() abort + let t = split(reltimestr(reltime()), '\V.') + return str2float(t[0] . '.' . t[1]) + endfunction +endif + +" Wrapper around systemlist() that supports a list for a:cmd. +" It returns an empty string on error. +" NOTE: Neovim before 0.2.0 would throw an error (which is caught), but it +" does not set v:shell_error! +function! neomake#compat#systemlist(cmd) abort + if empty(a:cmd) + return [] + endif + if has('nvim') && exists('*systemlist') + " @vimlint(EVL108, 1) + if !has('nvim-0.2.0') + try + return systemlist(a:cmd) + catch /^Vim\%((\a\+)\)\=:E902/ + return '' + endtry + endif + " @vimlint(EVL108, 0) + try + return systemlist(a:cmd) + catch /^Vim\%((return)\)\=:E475/ + call neomake#log#exception(printf('systemlist error: %s.', v:exception)) + return '' + endtry + endif + + if type(a:cmd) == type([]) + let cmd = join(map(a:cmd, 'neomake#utils#shellescape(v:val)')) + else + let cmd = a:cmd + endif + if exists('*systemlist') + return systemlist(cmd) + endif + return split(system(cmd), '\n') +endfunction + +function! neomake#compat#globpath_list(path, pattern, suf) abort + if v:version >= 705 || (v:version == 704 && has('patch279')) + return globpath(a:path, a:pattern, a:suf, 1) + endif + return split(globpath(a:path, a:pattern, a:suf), '\n') +endfunction + +function! neomake#compat#glob_list(pattern) abort + if v:version <= 703 + return split(glob(a:pattern, 1), '\n') + endif + return glob(a:pattern, 1, 1) +endfunction + +if neomake#utils#IsRunningWindows() + " Windows needs a shell to handle PATH/%PATHEXT% etc. + function! neomake#compat#get_argv(exe, args, args_is_list) abort + let prefix = &shell.' '.&shellcmdflag.' ' + if a:args_is_list + if a:exe ==# &shell && get(a:args, 0) ==# &shellcmdflag + " Remove already existing &shell/&shellcmdflag from e.g. NeomakeSh. + let argv = join(a:args[1:]) + else + let argv = join(map(copy([a:exe] + a:args), 'neomake#utils#shellescape(v:val)')) + endif + else + let argv = a:exe . (empty(a:args) ? '' : ' '.a:args) + if argv[0:len(prefix)-1] ==# prefix + return argv + endif + endif + return prefix.argv + endfunction +elseif has('nvim') + function! neomake#compat#get_argv(exe, args, args_is_list) abort + if a:args_is_list + return [a:exe] + a:args + endif + return a:exe . (empty(a:args) ? '' : ' '.a:args) + endfunction +elseif neomake#has_async_support() " Vim-async. + function! neomake#compat#get_argv(exe, args, args_is_list) abort + if a:args_is_list + return [a:exe] + a:args + endif + " Use a shell to handle argv properly (Vim splits at spaces). + let argv = a:exe . (empty(a:args) ? '' : ' '.a:args) + return [&shell, &shellcmdflag, argv] + endfunction +else + " Vim (synchronously), via system(). + function! neomake#compat#get_argv(exe, args, args_is_list) abort + if a:args_is_list + return join(map(copy([a:exe] + a:args), 'neomake#utils#shellescape(v:val)')) + endif + return a:exe . (empty(a:args) ? '' : ' '.a:args) + endfunction +endif + +if v:version >= 704 || (v:version == 703 && has('patch831')) + function! neomake#compat#gettabwinvar(t, w, v, d) abort + return gettabwinvar(a:t, a:w, a:v, a:d) + endfunction +else + " Wrapper around gettabwinvar that has no default (older Vims). + function! neomake#compat#gettabwinvar(t, w, v, d) abort + let r = gettabwinvar(a:t, a:w, a:v) + if r is# '' + unlet r + let r = a:d + endif + return r + endfunction +endif + +" Not really necessary for now, but allows to overwriting and extending. +if exists('*nvim_get_mode') + function! neomake#compat#get_mode() abort + let mode = nvim_get_mode() + return mode.mode + endfunction +else + function! neomake#compat#get_mode() abort + return mode(1) + endfunction +endif + +function! neomake#compat#in_completion() abort + if pumvisible() + return 1 + endif + if has('patch-8.0.0283') + let mode = mode(1) + if mode[1] ==# 'c' || mode[1] ==# 'x' + return 1 + endif + endif + return 0 +endfunction + +let s:prev_windows = [] +if exists('*win_getid') + function! neomake#compat#save_prev_windows() abort + call add(s:prev_windows, [win_getid(winnr('#')), win_getid(winnr())]) + endfunction + + function! neomake#compat#restore_prev_windows() abort + " Go back, maintaining the '#' window (CTRL-W_p). + let [aw_id, pw_id] = remove(s:prev_windows, 0) + let pw = win_id2win(pw_id) + if !pw + call neomake#log#debug(printf( + \ 'Cannot restore previous windows (previous window with ID %d not found).', + \ pw_id)) + elseif winnr() != pw + let aw = win_id2win(aw_id) + if aw + exec aw . 'wincmd w' + endif + exec pw . 'wincmd w' + endif + endfunction +else + function! neomake#compat#save_prev_windows() abort + call add(s:prev_windows, [winnr('#'), winnr()]) + endfunction + + function! neomake#compat#restore_prev_windows() abort + " Go back, maintaining the '#' window (CTRL-W_p). + let [aw, pw] = remove(s:prev_windows, 0) + if pw > winnr('$') + call neomake#log#debug(printf( + \ 'Cannot restore previous windows (%d > %d).', + \ pw, winnr('$'))) + elseif winnr() != pw + if aw + exec aw . 'wincmd w' + endif + exec pw . 'wincmd w' + endif + endfunction +endif + +if v:version >= 704 || (v:version == 703 && has('patch442')) + function! neomake#compat#doautocmd(event) abort + exec 'doautocmd ' . a:event + endfunction +else + function! neomake#compat#doautocmd(event) abort + exec 'doautocmd ' . a:event + endfunction +endif +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/config.vim b/bundle/neomake/autoload/neomake/config.vim new file mode 100644 index 000000000..54860fcdc --- /dev/null +++ b/bundle/neomake/autoload/neomake/config.vim @@ -0,0 +1,204 @@ +" New-style config API. + +let g:neomake#config#_defaults = { + \ 'maker_defaults': { + \ 'buffer_output': 1, + \ 'output_stream': 'both', + \ 'remove_invalid_entries': 0, + \ }} +lockvar g:neomake#config#_defaults + +let g:neomake#config#undefined = {} +lockvar! g:neomake#config#undefined + +" Resolve a:name (list of keys or string (split on dots)) and (optionally) +" init a:dict accordingly. +function! s:resolve_name(dict, name, init, validate) abort + let parts = type(a:name) == type([]) ? a:name : split(a:name, '\.') + if a:validate && parts[0] ==# 'neomake' + throw printf( + \ 'Neomake: config: "neomake" is not necessary with new-style config settings (%s).', + \ string(a:name)) + endif + let c = a:dict + for p in parts[0:-2] + if !has_key(c, p) + if !a:init + return [g:neomake#config#undefined, ''] + endif + let c[p] = {} + endif + if type(c[p]) != type({}) + return [g:neomake#config#undefined, ''] + endif + let c = c[p] + endfor + return [c, parts[-1]] +endfunction + +" Get a:name (list of keys or string (split on dots)) from a:dict, +" using a:prefixes. +function! s:get(dict, parts, prefixes) abort + for prefix in a:prefixes + let [c, k] = s:resolve_name(a:dict, prefix + a:parts[0:-1], 0, 1) + if has_key(c, k) + return [prefix, get(c, k)] + endif + endfor + return [[], g:neomake#config#undefined] +endfunction + +" Get a:name (string (split on dots), or list of keys) from config. +" See neomake#config#get_with_source for args. +function! neomake#config#get(name, ...) abort + return call('neomake#config#get_with_source', [a:name] + a:000)[0] +endfunction + +" Get a:name (string (split on dots), or list of keys) from config, with +" information about the setting's source ('buffer', 'tab', 'global', 'maker', +" 'default'). +" Optional args: +" - a:1: default value +" - a:2: context: defaults to {'ft': &filetype} +" - maker: a maker dict (where maker.name is used from for prefixes, and +" as a lookup itself) +" - ft: filetype string (use an empty string to ignore it) +" - bufnr: buffer number (use an empty string to ignore it) +" - maker_only: should settings get looked up only in the maker context? +" (i.e. with maker.name prefix in general and in context.maker) +" - log_source: additional information to log. +function! neomake#config#get_with_source(name, ...) abort + let context = a:0 > 1 ? a:2 : {'ft': &filetype, 'bufnr': bufnr('%')} + let parts = type(a:name) == type([]) ? a:name : split(a:name, '\.') + + let prefixes = [[]] + if has_key(context, 'ft') && !empty(context.ft) + for ft in neomake#utils#get_config_fts(context.ft, '.') + call insert(prefixes, ['ft', ft], 0) + endfor + endif + + let maker_name = get(get(context, 'maker', {}), 'name', '') + let maker_only = get(context, 'maker_only', 0) + if parts[0][0:1] ==# 'b:' + if !has_key(context, 'bufnr') + let context.bufnr = bufnr('%') + endif + let parts[0] = parts[0][2:-1] + if context.bufnr is# '' + let lookups = [] + else + let lookups = [['buffer', getbufvar(context.bufnr, 'neomake')]] + endif + call add(lookups, ['maker', get(context, 'maker', {})]) + elseif empty(maker_name) && maker_only + let lookups = [['maker', get(context, 'maker', {})]] + else + let lookups = (has_key(context, 'bufnr') && context.bufnr isnot# '' + \ ? [['buffer', getbufvar(context.bufnr, 'neomake')]] + \ : []) + [ + \ ['tab', get(t:, 'neomake', {})], + \ ['global', get(g:, 'neomake', {})], + \ ['maker', get(context, 'maker', {})]] + if !empty(maker_name) + if maker_only + if parts[0] !=# maker_name + call map(prefixes, 'add(v:val, maker_name)') + endif + else + for prefix in reverse(copy(prefixes)) + call insert(prefixes, prefix + [maker_name], 0) + endfor + endif + endif + endif + + for [source, lookup] in lookups + if !empty(lookup) + if source ==# 'maker' + let maker_prefixes = map(copy(prefixes), '!empty(v:val) && v:val[-1] ==# maker_name ? v:val[:-2] : v:val') + let maker_setting_parts = parts[0] == maker_name ? parts[1:] : parts + let [prefix, l:R] = s:get(lookup, maker_setting_parts, maker_prefixes) + else + let [prefix, l:R] = s:get(lookup, parts, prefixes) + endif + if R isnot# g:neomake#config#undefined + let log_name = join(map(copy(parts), "substitute(v:val, '\\.', '|', '')"), '.') + let log_source = get(context, 'log_source', '') + call neomake#log#debug(printf( + \ "Using setting %s=%s from '%s'%s%s.", + \ log_name, string(R), source, + \ empty(prefix) ? '' : ' (prefix: '.string(prefix).')', + \ empty(log_source) ? '' : ' ('.log_source.')'), + \ context) + return [R, source] + endif + unlet R " for Vim without patch-7.4.1546 + endif + unlet lookup " for Vim without patch-7.4.1546 + endfor + + " Return default. + if a:0 + return [a:1, 'default'] + elseif has_key(g:neomake#config#_defaults, a:name) + return [copy(g:neomake#config#_defaults[a:name]), 'default'] + endif + return [g:neomake#config#undefined, 'default'] +endfunction + + +" Set a:name (list or string (split on dots)) in a:dict to a:value. +function! s:set(dict, name, value, validate) abort + let [c, k] = s:resolve_name(a:dict, a:name, 1, a:validate) + let c[k] = a:value + return c +endfunction + +" Set a:name to a:value in the config. +" a:name: +" - a list (e.g. `['ft', 'javascript.jsx', 'eslint', 'exe']`, or +" - a string (split on dots, e.g. `'ft.python.enabled_makers'`), where +" `b:` sets a buffer-local setting (via `neomake#config#set_buffer`). +" a:value: the value to set +function! neomake#config#set(name, value) abort + let parts = type(a:name) == type([]) ? a:name : split(a:name, '\.') + if parts[0] =~# '^b:' + let parts[0] = parts[0][2:-1] + return neomake#config#set_buffer(bufnr('%'), parts, a:value) + endif + if !has_key(g:, 'neomake') + let g:neomake = {} + endif + return s:set(g:neomake, parts, a:value, 1) +endfunction + +" Set a:name (list or string (split on dots)) to a:value for buffer a:bufnr. +function! neomake#config#set_buffer(bufnr, name, value) abort + let bufnr = +a:bufnr + let bneomake = getbufvar(bufnr, 'neomake') + if bneomake is# '' + unlet bneomake " for Vim without patch-7.4.1546 + let bneomake = {} + call setbufvar(bufnr, 'neomake', bneomake) + endif + return s:set(bneomake, a:name, a:value, 1) +endfunction + +" Set a:name (list or string (split on dots)) to a:value in a:scope. +" This is meant for advanced usage, e.g.: +" set_scope(t:, 'neomake.disabled', 1) +function! neomake#config#set_dict(dict, name, value) abort + return s:set(a:dict, a:name, a:value, 0) +endfunction + +" Unset a:name (list or string (split on dots)). +" This is meant for advanced usage, e.g.: +" unset_dict(t:, 'neomake.disabled', 1) +function! neomake#config#unset_dict(dict, name) abort + let [c, k] = s:resolve_name(a:dict, a:name, 0, 0) + if has_key(c, k) + unlet c[k] + endif +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/configure.vim b/bundle/neomake/autoload/neomake/configure.vim new file mode 100644 index 000000000..9f9d5add7 --- /dev/null +++ b/bundle/neomake/autoload/neomake/configure.vim @@ -0,0 +1,802 @@ +" Default settings, setup in global config dict. +let s:default_settings = { + \ 'ignore_filetypes': ['startify'], + \ } +let g:neomake = get(g:, 'neomake', {}) +let g:neomake.automake = get(g:neomake, 'automake', {}) +call extend(g:neomake.automake, s:default_settings, 'keep') + +if !exists('s:timer_info') + let s:timer_info = {} + let s:timer_by_bufnr = {} +endif + +let s:default_delay = has('timers') ? 500 : 0 + +" A mapping of configured buffers with cached settings (maker_jobs). +let s:configured_buffers = {} +" A list of configured/used autocommands. +let s:registered_events = [] + +" TextChanged gets triggered in this case when loading a buffer (Vim +" issue #2742). +let s:need_to_skip_first_textchanged = !has('nvim-0.3.2') && has('patch-8.0.1494') && !has('patch-8.0.1633') + + +" TODO: allow for namespaces, and prefer 'automake' here. +" TODO: handle bufnr! (getbufvar) +function! s:get_setting(name, default) abort + return get(get(b:, 'neomake', {}), a:name, + \ get(get(t:, 'neomake', {}), a:name, + \ get(get(g:, 'neomake', {}), a:name, a:default))) +endfunction + + +function! s:debug_log(msg, ...) abort + let context = {'bufnr': bufnr('%')} + if a:0 + call extend(context, a:1) + endif + call neomake#log#debug(printf('automake: %s.', a:msg), context) +endfunction + +" Check if buffer's tick (or ft) changed. +function! s:tick_changed(context) abort + let bufnr = +a:context.bufnr + let ft = get(a:context, 'ft', getbufvar(bufnr, '&filetype')) + let prev_tick = getbufvar(bufnr, '_neomake_automake_tick') + let r = 1 + if empty(prev_tick) + call s:debug_log('tick changed (new)') + else + let cur_tick = [getbufvar(bufnr, 'changedtick'), ft] + if cur_tick == prev_tick + call s:debug_log('tick is unchanged') + return 0 + endif + endif + return r +endfunction + +function! neomake#configure#_update_automake_tick(bufnr, ft) abort + if has_key(s:configured_buffers, a:bufnr) + let tick = getbufvar(a:bufnr, 'changedtick') + call s:debug_log('updating tick: '.tick) + call setbufvar(a:bufnr, '_neomake_automake_tick', [tick, a:ft]) + endif +endfunction + +function! neomake#configure#_reset_automake_cancelations(bufnr) abort + if has_key(s:configured_buffers, a:bufnr) + call setbufvar(a:bufnr, '_neomake_cancelations', [0, 0]) + endif +endfunction + +function! s:update_cancel_rate(bufnr, via_timer) abort + let canceled = getbufvar(a:bufnr, '_neomake_cancelations', [0, 0]) + if a:via_timer + let canceled[0] += 1 + else + let canceled[1] += 1 + endif + call setbufvar(a:bufnr, '_neomake_cancelations', canceled) + return canceled +endfunction + +function! s:handle_changed_buffer(make_id, event) abort + " Cleanup always. + if exists('b:_neomake_automake_changed_context') + let [make_id, prev_tick, changedtick, context] = b:_neomake_automake_changed_context + + if s:need_to_skip_first_textchanged && a:event ==# 'TextChanged' + if !get(b:, '_neomake_seen_TextChanged', 0) + call s:debug_log('ignoring first TextChanged') + let b:_neomake_seen_TextChanged = 1 + return + endif + endif + + if changedtick == b:changedtick + call s:debug_log(printf('handle_changed_buffer: %s: tick was not changed', a:event)) + return + endif + + unlet b:_neomake_automake_changed_context + augroup neomake_automake_abort + au! * + augroup END + else + return + endif + + if make_id != a:make_id + call neomake#log#warning(printf('automake: handle_changed_buffer: mismatched make_id: %d != %d.', make_id, a:make_id)) + return + endif + + let window_make_ids = get(w:, 'neomake_make_ids', []) + if index(window_make_ids, a:make_id) == -1 + return + endif + + call setbufvar(context.bufnr, '_neomake_automake_tick', prev_tick) + call filter(b:_neomake_automake_make_ids, 'v:val != '.a:make_id) + call s:update_cancel_rate(context.bufnr, 0) + + call s:debug_log(printf('buffer was changed (%s), canceling make', a:event), {'make_id': a:make_id}) + call neomake#CancelMake(a:make_id) + + if a:event ==# 'TextChangedI' + call s:debug_log('queueing make restart for InsertLeave', {'make_id': a:make_id}) + let b:_neomake_postponed_automake_context = [1, context] + augroup neomake_automake_retry + au! * + autocmd InsertLeave call s:do_postponed_automake(2) + augroup END + elseif context.delay + call s:debug_log(printf('restarting timer for original event %s', context.event), {'make_id': a:make_id}) + if has_key(context, '_via_timer_cb') + unlet context._via_timer_cb + endif + if has_key(context, 'pos') + unlet context.pos + endif + call s:neomake_do_automake(context) + else + call s:debug_log(printf('restarting for original event (%s) without delay', context.event)) + call s:neomake_do_automake(context) + endif +endfunction + +function! s:neomake_do_automake(context) abort + let bufnr = +a:context.bufnr + if s:skip_for_running_jobs(bufnr) + return + endif + + if !get(a:context, '_via_timer_cb') && a:context.delay + if exists('s:timer_by_bufnr[bufnr]') + let timer = s:timer_by_bufnr[bufnr] + call s:stop_timer(timer) + call s:debug_log(printf('stopped existing timer: %d', timer), {'bufnr': bufnr}) + call s:update_cancel_rate(bufnr, 1) + endif + if !s:tick_changed(a:context) + call s:debug_log('buffer was not changed', {'bufnr': bufnr}) + return + endif + + " Cancel any already running automake runs. + let prev_make_ids = getbufvar(bufnr, '_neomake_automake_make_ids') + if !empty(prev_make_ids) + call s:debug_log(printf('stopping previous make runs: %s', join(prev_make_ids, ', '))) + for prev_make_id in prev_make_ids + call neomake#CancelMake(prev_make_id) + endfor + let canceled = s:update_cancel_rate(bufnr, 0) + else + let canceled = getbufvar(bufnr, '_neomake_cancelations', [0, 0]) + endif + + let delay = a:context.delay + + " Increase delay for canceled/restarted timers, and canceled makes. + " IDEA: take into account the mean duration of this make run. + if canceled[0] || canceled[1] + let [mult_timers, mult_makes, max_delay] = neomake#config#get('automake.cancelation_delay', [0.2, 0.5, 3000], {'bufnr': bufnr}) + let cancel_rate = 1 + (canceled[0]*mult_timers + canceled[1]*mult_makes) + let delay = min([max_delay, float2nr(ceil(delay * cancel_rate))]) + call s:debug_log(printf('increasing delay (%d/%d canceled timers/makes, rate=%.2f): %d => %d/%d', canceled[0], canceled[1], cancel_rate, a:context.delay, delay, max_delay)) + endif + + let timer = timer_start(delay, function('s:automake_delayed_cb')) + let s:timer_info[timer] = a:context + if !has_key(a:context, 'pos') + let s:timer_info[timer].pos = s:get_position_context() + endif + let s:timer_by_bufnr[bufnr] = timer + call s:debug_log(printf('started timer (%dms): %d', delay, timer), + \ {'bufnr': a:context.bufnr}) + return + endif + + let ft = getbufvar(bufnr, '&filetype') + let event = a:context.event + + call s:debug_log('neomake_do_automake: '.event, {'bufnr': bufnr}) + if !s:tick_changed({'event': event, 'bufnr': bufnr, 'ft': ft}) + call s:debug_log('buffer was not changed', {'bufnr': bufnr}) + return + endif + let prev_tick = getbufvar(bufnr, '_neomake_automake_tick') + + call s:debug_log(printf('enabled makers: %s', join(map(copy(a:context.maker_jobs), 'v:val.maker.name'), ', '))) + let make_options = { + \ 'file_mode': 1, + \ 'jobs': deepcopy(a:context.maker_jobs), + \ 'ft': ft, + \ 'automake': 1} + let jobinfos = neomake#Make(make_options) + + let started_jobs = filter(copy(jobinfos), "!get(v:val, 'finished', 0)") + call s:debug_log(printf('started jobs: %s', string(map(copy(started_jobs), 'v:val.id')))) + if !empty(started_jobs) + let make_id = jobinfos[0].make_id + call setbufvar(bufnr, '_neomake_automake_make_ids', + \ neomake#compat#getbufvar(bufnr, '_neomake_automake_make_ids', []) + [make_id]) + + " Setup buffer autocmd to cancel/restart make for changed buffer. + let events = [] + for event in ['TextChangedI', 'TextChanged'] + if a:context.event !=# event + call add(events, event) + endif + endfor + call setbufvar(bufnr, '_neomake_automake_changed_context', [make_id, prev_tick, getbufvar(bufnr, 'changedtick'), a:context]) + augroup neomake_automake_abort + exe printf('au! * ', bufnr) + for event in events + exe printf('autocmd %s call s:handle_changed_buffer(%s, %s)', + \ event, bufnr, string(make_id), string(event)) + endfor + augroup END + endif +endfunction + +function! s:get_position_context() abort + let w = exists('*win_getid') ? win_getid() : winnr() + return [w, getpos('.'), neomake#compat#get_mode()] +endfunction + +function! s:automake_delayed_cb(timer) abort + let timer_info = s:timer_info[a:timer] + unlet s:timer_info[a:timer] + unlet s:timer_by_bufnr[timer_info.bufnr] + + if !bufexists(timer_info.bufnr) + call s:debug_log(printf('buffer does not exist anymore for timer %d', a:timer), + \ {'bufnr': timer_info.bufnr}) + return + endif + + call s:debug_log(printf('callback for timer %d (via %s)', string(a:timer), timer_info.event), + \ {'bufnr': timer_info.bufnr}) + + let bufnr = bufnr('%') + if timer_info.bufnr != bufnr + call s:debug_log(printf('buffer changed: %d => %d, queueing make restart for BufEnter,WinEnter', + \ timer_info.bufnr, bufnr)) + let restart_context = copy(timer_info) + call setbufvar(restart_context.bufnr, '_neomake_postponed_automake_context', [1, restart_context]) + let b:_neomake_postponed_automake_context = [1, restart_context] + augroup neomake_automake_retry + exe 'au! * ' + exe 'autocmd BufEnter,WinEnter call s:do_postponed_automake(2)' + augroup END + return + endif + + if neomake#compat#in_completion() + call s:debug_log('postponing automake during completion') + if has_key(timer_info, 'pos') + unlet timer_info.pos + endif + let b:_neomake_postponed_automake_context = [0, timer_info] + + augroup neomake_automake_retry + au! * + autocmd CompleteDone call s:do_postponed_automake(1) + autocmd InsertLeave call s:do_postponed_automake(2) + augroup END + return + endif + + " Verify context/position is the same. + " This is meant to give an additional delay after e.g. TextChanged. + " Only events with delay are coming here, so this does not affect + " BufWritePost etc typically. + if !empty(timer_info.pos) + let current_context = s:get_position_context() + if current_context != timer_info.pos + if current_context[2] != timer_info.pos[2] + " Mode was changed. + if current_context[2][0] ==# 'i' && timer_info.event !=# 'TextChangedI' + " Changed to insert mode, trigger on InsertLeave. + call s:debug_log(printf('context/position changed: %s => %s, restarting on InsertLeave', + \ string(timer_info.pos), string(current_context))) + let context = copy(timer_info) + let context.delay = 0 + unlet context.pos + call s:update_cancel_rate(bufnr, 1) + let b:_neomake_postponed_automake_context = [1, context] + augroup neomake_automake_retry + au! * + autocmd InsertLeave call s:do_postponed_automake(2) + augroup END + return + endif + endif + call s:debug_log(printf('context/position changed: %s => %s, restarting', + \ string(timer_info.pos), string(current_context))) + unlet timer_info.pos + call s:update_cancel_rate(bufnr, 1) + call s:neomake_do_automake(timer_info) + return + endif + endif + " endif + + let context = copy(timer_info) + let context._via_timer_cb = 1 + call s:neomake_do_automake(context) +endfunction + +function! s:do_postponed_automake(step) abort + if exists('b:_neomake_postponed_automake_context') + let context = b:_neomake_postponed_automake_context + + if context[0] == a:step - 1 + if a:step == 2 + call s:debug_log('re-starting postponed automake') + let context[1].pos = s:get_position_context() + call s:neomake_do_automake(context[1]) + else + let context[0] = a:step + return + endif + else + call s:debug_log('postponed automake: unexpected step '.a:step.', cleaning up') + endif + unlet b:_neomake_postponed_automake_context + else + call s:debug_log('missing context information for postponed automake') + endif + " Cleanup. + augroup neomake_automake_retry + autocmd! * + augroup END +endfunction + +" Parse/get events dict from args. +" a:config: config dict to write into. +" a:string_or_dict_config: a string or dict describing the config. +" a:1: default delay. +function! s:parse_events_from_args(config, string_or_dict_config, ...) abort + " Get default delay from a:1. + if a:0 + if has('timers') + let delay = a:1 + else + if a:1 != 0 + call neomake#log#warning('automake: timer support is required for delayed events.') + endif + let delay = 0 + endif + else + let delay = s:default_delay + endif + + if type(a:string_or_dict_config) == type({}) + let events = copy(a:string_or_dict_config) + + " Validate events. + for [event, config] in items(events) + if !exists('##'.event) + call neomake#log#error(printf( + \ 'automake: event %s does not exist.', event)) + unlet events[event] + continue + endif + + if get(config, 'delay', 0) && !has('timers') + call neomake#log#error(printf( + \ 'automake: timer support is required for automaking, removing event %s.', + \ event)) + unlet events[event] + endif + endfor + call neomake#config#set_dict(a:config, 'automake.events', events) + if a:0 + let a:config.automake_delay = a:1 + endif + else + " Map string config to events dict. + let modes = split(a:string_or_dict_config, '\zs') + let events = {} + let default_with_delay = {} + + let unknown = [] + for mode in modes + " Insert mode. + if mode ==# 'i' + if exists('##TextChangedI') && has('timers') + let events['TextChangedI'] = default_with_delay + else + call s:debug_log('using CursorHoldI instead of TextChangedI') + let events['CursorHoldI'] = (delay != 0 ? {'delay': 0} : {}) + endif + " Normal mode. + elseif mode ==# 'n' + if exists('##TextChanged') && has('timers') + let events['TextChanged'] = default_with_delay + if !has_key(events, 'TextChangedI') + " Run when leaving insert mode, since only TextChangedI would be triggered + " for `ciw` etc. + let events['InsertLeave'] = default_with_delay + endif + else + call s:debug_log('using CursorHold instead of TextChanged') + let events['CursorHold'] = (delay != 0 ? {'delay': 0} : {}) + let events['InsertLeave'] = (delay != 0 ? {'delay': 0} : {}) + endif + " On writes. + elseif mode ==# 'w' + let events['BufWritePost'] = (delay != 0 ? {'delay': 0} : {}) + " On reads. + elseif mode ==# 'r' + let events['BufWinEnter'] = {} + let events['FileType'] = {} + + " When a file was changed outside of Vim. + " TODO: test + let events['FileChangedShellPost'] = {} + " XXX: FileType might work better, at least when wanting to skip filetypes. + " let events['FileType'] = {'delay': a:0 > 1 ? delay : 0} + else + let unknown += [mode] + endif + endfor + if !empty(unknown) + call neomake#log#error(printf('unknown modes in string automake config (%s): %s.', + \ a:string_or_dict_config, join(unknown, ', '))) + endif + endif + + call neomake#config#set_dict(a:config, 'automake.events', events) + if a:0 + let a:config.automake_delay = delay + endif +endfunction + +" Setup automake for buffer (current, or options.bufnr). +" a:1: delay +" a:2: options ('bufnr', 'makers') / or list of makers TODO +function! neomake#configure#automake_for_buffer(string_or_dict_config, ...) abort + let options = {} + if a:0 + let options.delay = a:1 + endif + let bufnr = bufnr('%') + if a:0 > 1 + if type(a:2) == type([]) + let options.makers = a:2 + else + call extend(options, a:2) + if has_key(options, 'bufnr') + let bufnr = options.bufnr + unlet options.bufnr + endif + endif + endif + return call('s:configure_buffer', [bufnr, a:string_or_dict_config, options]) +endfunction + +" Workaround for getbufvar not having support for defaults. +function! s:getbufvar(bufnr, name, default) abort + let b_dict = getbufvar(+a:bufnr, '') + if empty(b_dict) + " NOTE: it is an empty string for non-existing buffers. + return a:default + endif + return get(b_dict, a:name, a:default) +endfunction + +function! s:is_buffer_ignored(bufnr) abort + " TODO: blacklist/whitelist. + let bufnr = +a:bufnr + let buftype = getbufvar(bufnr, '&buftype') + if !empty(buftype) + call s:debug_log(printf('ignoring buffer with buftype=%s', buftype), {'bufnr': bufnr}) + return 1 + endif + + let ft = getbufvar(bufnr, '&filetype') + if index(neomake#config#get('automake.ignore_filetypes', []), ft) != -1 + call s:debug_log(printf('ignoring buffer with filetype=%s', ft), {'bufnr': bufnr}) + return 1 + endif +endfunction + +if exists('##OptionSet') + function! s:update_buffer_options() abort + let bufnr = bufnr('%') + call s:maybe_reconfigure_buffer(bufnr) + endfunction + augroup neomake_automake_update + au! + au OptionSet buftype call s:update_buffer_options() + augroup END +endif + +" a:1: string or dict describing the events +" a:2: options ('delay', 'makers') +function! s:configure_buffer(bufnr, ...) abort + let bufnr = +a:bufnr + let ft = getbufvar(bufnr, '&filetype') + let config = s:getbufvar(bufnr, 'neomake', {}) + let old_config = deepcopy(config) + if a:0 + let args = [config, a:1] + if a:0 > 1 && has_key(a:2, 'delay') + let args += [a:2.delay] + endif + call call('s:parse_events_from_args', args) + call setbufvar(bufnr, 'neomake', config) + + let implicit_config = {'custom': 1, 'ignore': 0} + else + let implicit_config = {'custom': 0, 'ignore': s:is_buffer_ignored(bufnr)} + endif + + " Register the buffer, and remember if it is custom. + if has_key(s:configured_buffers, bufnr) + let old_registration = copy(get(s:configured_buffers, bufnr, {})) + call extend(s:configured_buffers[bufnr], implicit_config, 'force') + else + let s:configured_buffers[bufnr] = implicit_config + + augroup neomake_automake_clean + autocmd BufWipeout call s:neomake_automake_clean(expand('')) + augroup END + endif + + if implicit_config.ignore + return s:configured_buffers[bufnr] + endif + + let s:configured_buffers[bufnr].events_config = neomake#config#get('automake.events', {}) + + " Create jobs. + let options = a:0 > 1 ? a:2 : {} + if has_key(options, 'makers') + let makers = neomake#map_makers(options.makers, ft, 0) + let source = 'options' + else + let [makers, source] = neomake#config#get_with_source('automake.enabled_makers') + if makers is g:neomake#config#undefined + unlet makers + let makers = neomake#GetEnabledMakers(ft) + else + let makers = neomake#map_makers(makers, ft, 0) + endif + endif + let options = {'file_mode': 1, 'ft': ft, 'bufnr': bufnr, 'automake': 1} + let jobs = neomake#core#create_jobs(options, makers) + let s:configured_buffers[bufnr].maker_jobs = jobs + call s:debug_log(printf('configured buffer for ft=%s (%s)', + \ ft, empty(jobs) ? 'no enabled makers' : join(map(copy(jobs), 'v:val.maker.name'), ', ').' ('.source.')'), {'bufnr': bufnr}) + if old_config != config + call s:debug_log('resetting tick because of config changes') + call setbufvar(bufnr, '_neomake_automake_tick', []) + elseif exists('old_registration') + if old_registration != s:configured_buffers[bufnr] + call s:debug_log('resetting tick because of registration changes') + call setbufvar(bufnr, '_neomake_automake_tick', []) + endif + else + call s:debug_log('setting tick for new buffer') + call setbufvar(bufnr, '_neomake_automake_tick', []) + endif + + if a:0 + " Setup autocommands etc (when called manually)?! + call neomake#configure#automake() + endif + return config +endfunction + +function! s:maybe_reconfigure_buffer(bufnr) abort + if has_key(s:configured_buffers, a:bufnr) && !s:configured_buffers[a:bufnr].custom + call s:configure_buffer(a:bufnr) + endif +endfunction + +function! s:skip_for_running_jobs(bufnr) abort + let running_jobs = values(filter(copy(neomake#_get_s().jobs), + \ 'v:val.bufnr == a:bufnr' + \ .' && v:val.file_mode == 1' + \ .' && !get(v:val, "automake", 0)' + \ ." && !get(v:val, 'canceled')")) + if !empty(running_jobs) + call s:debug_log(printf('skipping for already running jobs: %s', + \ string(map(running_jobs, 'v:val.as_string()'))), + \ {'bufnr': a:bufnr}) + return 1 + endif +endfunction + +" Called from autocommands. +function! s:neomake_automake(event, bufnr) abort + let disabled = neomake#config#get_with_source('disabled', 0) + if disabled[0] + call s:debug_log(printf('disabled (%s)', disabled[1])) + return + endif + let bufnr = +a:bufnr + + if has_key(s:configured_buffers, bufnr) + let buffer_config = s:configured_buffers[bufnr] + else + " Register the buffer, and remember that it's automatic. + let buffer_config = s:configure_buffer(bufnr) + endif + if get(buffer_config, 'ignore', 0) + " NOTE: might be too verbose. + call s:debug_log('buffer is ignored') + return + endif + + if s:need_to_skip_first_textchanged && a:event ==# 'TextChanged' + if !getbufvar(bufnr, '_neomake_seen_TextChanged', 0) + call s:debug_log('ignoring first TextChanged') + call setbufvar(bufnr, '_neomake_seen_TextChanged', 1) + return + endif + endif + + call s:debug_log(printf('handling event %s', a:event), {'bufnr': bufnr}) + + if empty(s:configured_buffers[bufnr].maker_jobs) + call s:debug_log('no enabled makers', {'bufnr': bufnr}) + return + endif + + if s:skip_for_running_jobs(bufnr) + return + endif + + call s:debug_log(printf('automake for event %s', a:event), {'bufnr': bufnr}) + let config = s:configured_buffers[bufnr].events_config + if !has_key(config, a:event) + call s:debug_log('event is not registered', {'bufnr': bufnr}) + return + endif + let config = config[a:event] + + let event = a:event + let bufnr = +a:bufnr + " TODO: rename to neomake.automake.delay + let delay = get(config, 'delay', s:get_setting('automake_delay', s:default_delay)) + let context = { + \ 'delay': delay, + \ 'bufnr': bufnr, + \ 'event': a:event, + \ 'maker_jobs': s:configured_buffers[bufnr].maker_jobs, + \ } + if event ==# 'BufWinEnter' + " Ignore context, so that e.g. with vim-stay restoring the view + " (cursor position), it will still be triggered. + let context.pos = [] + endif + call s:neomake_do_automake(context) +endfunction + +function! s:stop_timer(timer) abort + let timer_info = s:timer_info[a:timer] + unlet s:timer_info[a:timer] + unlet s:timer_by_bufnr[timer_info.bufnr] + call timer_stop(+a:timer) +endfunction + +function! s:stop_timers() abort + let timers = keys(s:timer_info) + if !empty(timers) + call s:debug_log(printf('stopping timers: %s', join(timers, ', '))) + for timer in timers + call s:stop_timer(timer) + endfor + endif +endfunction + +function! neomake#configure#reset_automake() abort + for bufnr in keys(s:configured_buffers) + call s:neomake_automake_clean(bufnr) + endfor + let s:registered_events = [] + call s:stop_timers() + call neomake#configure#automake() +endfunction + +function! s:neomake_automake_clean(bufnr) abort + if has_key(s:timer_by_bufnr, a:bufnr) + let timer = s:timer_by_bufnr[a:bufnr] + call s:stop_timer(timer) + call s:debug_log('stopped timer for cleaned buffer: '.timer) + endif + if has_key(s:configured_buffers, a:bufnr) + unlet s:configured_buffers[a:bufnr] + augroup neomake_automake_clean + exe printf('au! * ', a:bufnr) + augroup END + endif +endfunction + +function! neomake#configure#disable_automake() abort + call s:debug_log('disabling globally') + call s:stop_timers() +endfunction + +function! neomake#configure#disable_automake_for_buffer(bufnr) abort + call s:debug_log(printf('disabling buffer %d', a:bufnr)) + if has_key(s:timer_by_bufnr, a:bufnr) + let timer = s:timer_by_bufnr[a:bufnr] + call s:stop_timer(timer) + call s:debug_log('stopped timer for buffer: '.timer) + endif + if has_key(s:configured_buffers, a:bufnr) + let s:configured_buffers[a:bufnr].disabled = 1 + endif +endfunction + +function! neomake#configure#enable_automake_for_buffer(bufnr) abort + if exists('s:configured_buffers[a:bufnr].disabled') + call s:debug_log(printf('Re-enabled buffer %d', a:bufnr)) + unlet s:configured_buffers[a:bufnr].disabled + endif +endfunction + +function! neomake#configure#reset_automake_for_buffer(...) abort + let bufnr = a:0 ? +a:1 : bufnr('%') + call s:neomake_automake_clean(bufnr) +endfunction + +function! neomake#configure#automake(...) abort + call s:debug_log(printf('configuring automake: %s', string(a:000))) + if !exists('g:neomake') + let g:neomake = {} + endif + if a:0 + call call('s:parse_events_from_args', [g:neomake] + a:000) + endif + + let disabled_globally = get(get(g:, 'neomake', {}), 'disabled', 0) + if disabled_globally + let s:registered_events = [] + else + let s:registered_events = keys(get(get(g:neomake, 'automake', {}), 'events', {})) + endif + " Keep custom configured buffers. + call filter(s:configured_buffers, 'v:val.custom') + for b in keys(s:configured_buffers) + if empty(s:configured_buffers[b].maker_jobs) + continue + endif + if get(s:configured_buffers[b], 'disabled', 0) + continue + endif + let b_cfg = neomake#config#get('b:automake.events', {}) + for event_config in items(b_cfg) + let event = event_config[0] + if index(s:registered_events, event) == -1 + call add(s:registered_events, event) + endif + endfor + endfor + call s:debug_log('registered events: '.join(s:registered_events, ', ')) + + augroup neomake_automake + au! + for event in s:registered_events + exe 'autocmd '.event." * call s:neomake_automake('".event."', expand(''))" + endfor + augroup END + if empty(s:registered_events) + augroup! neomake_automake + endif +endfunction + +augroup neomake_automake_base + au! + autocmd FileType * call s:maybe_reconfigure_buffer(expand('')) +augroup END +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/core.vim b/bundle/neomake/autoload/neomake/core.vim new file mode 100644 index 000000000..41ce51645 --- /dev/null +++ b/bundle/neomake/autoload/neomake/core.vim @@ -0,0 +1,127 @@ +let g:neomake#core#valid_maker_name_pattern = '\v^\w+$' + +let g:neomake#core#_ignore_autocommands = 0 + +function! neomake#core#create_jobs(options, makers) abort + let args = [a:options, a:makers] + let jobs = call('s:bind_makers_for_job', args) + return jobs +endfunction + +" Map/bind a:makers to a list of job options, using a:options. +function! s:bind_makers_for_job(options, makers) abort + let r = [] + for maker in a:makers + let options = copy(a:options) + try + let maker = neomake#core#instantiate_maker(maker, options, 1) + catch /^Neomake: skip_job: / + let msg = substitute(v:exception, '^Neomake: skip_job: ', '', '') + call neomake#log#debug(printf('%s: skipping job: %s.', + \ maker.name, msg), options) + continue + catch /^Neomake: / + let error = substitute(v:exception, '^Neomake: ', '', '').'.' + call neomake#log#error(error, options) + continue + endtry + if !empty(maker) + let options.maker = maker + let r += [options] + endif + endfor + return r +endfunction + +function! neomake#core#instantiate_maker(maker, options, check_exe) abort + let maker = a:maker + let options = a:options + let ft = get(options, 'ft', '') + let bufnr = get(options, 'bufnr', '') + + " Call InitForJob function in maker object, if any. + let l:Init = neomake#utils#GetSetting('InitForJob', maker, g:neomake#config#undefined, ft, bufnr) + if empty(Init) + " Deprecated: should use InitForJob instead. + if has_key(maker, 'fn') + unlet Init " vim73 + let l:Init = maker.fn + call neomake#log#warn_once(printf("Please use 'InitForJob' instead of 'fn' for maker %s.", maker.name), + \ printf('deprecated-fn-%s', maker.name)) + endif + endif + if !empty(Init) + let returned_maker = call(Init, [options], maker) + if returned_maker isnot# 0 + " This conditional assignment allows to both return a copy + " (factory), while also can be used as a init method. + let maker = returned_maker + endif + endif + + if has_key(maker, '_bind_args') + call maker._bind_args() + if type(maker.exe) != type('') + let error = printf('Non-string given for executable of maker %s: type %s', + \ maker.name, type(maker.exe)) + if !get(maker, 'auto_enabled', 0) + throw 'Neomake: '.error + endif + call neomake#log#debug(error.'.', options) + return {} + endif + if a:check_exe && !executable(maker.exe) + if get(maker, 'auto_enabled', 0) + call neomake#log#debug(printf( + \ 'Exe (%s) of auto-configured maker %s is not executable, skipping.', maker.exe, maker.name), options) + else + let error = printf('Exe (%s) of maker %s is not executable', maker.exe, maker.name) + throw 'Neomake: '.error + endif + return {} + endif + endif + return maker +endfunction + +" Base class for command makers. +let g:neomake#core#command_maker_base = {} + +function! g:neomake#core#command_maker_base._get_fname_for_args(jobinfo) abort dict + " Append file? (defaults to jobinfo.file_mode, project/global makers should set it to 0) + let append_file = neomake#utils#GetSetting('append_file', self, a:jobinfo.file_mode, a:jobinfo.ft, a:jobinfo.bufnr) + " Use stdin? (checked here always to work without setting "uses_filename"). + let uses_stdin = neomake#utils#GetSetting('uses_stdin', self, g:neomake#config#undefined, a:jobinfo.ft, a:jobinfo.bufnr) + if uses_stdin isnot g:neomake#config#undefined + let a:jobinfo.uses_stdin = uses_stdin + call neomake#log#debug(printf('Using uses_stdin (%s) from setting.', + \ a:jobinfo.uses_stdin), a:jobinfo) + endif + " Use/generate a filename? (defaults to 1 if tempfile_name is set) + let uses_filename = append_file || neomake#utils#GetSetting('uses_filename', self, has_key(self, 'tempfile_name'), a:jobinfo.ft, a:jobinfo.bufnr) + if append_file || uses_filename || !empty(uses_stdin) + let filename = self._get_fname_for_buffer(a:jobinfo) + if append_file + return filename + endif + endif + return '' +endfunction + +function! g:neomake#core#command_maker_base._get_argv(_jobinfo) abort dict + return neomake#compat#get_argv(self.exe, self.args, type(self.args) == type([])) +endfunction + +" Get tabnr and winnr for a given make ID. +function! neomake#core#get_tabwin_for_makeid(make_id) abort + let curtab = tabpagenr() + for t in [curtab] + range(1, curtab-1) + range(curtab+1, tabpagenr('$')) + for w in range(1, tabpagewinnr(t, '$')) + if index(neomake#compat#gettabwinvar(t, w, 'neomake_make_ids', []), a:make_id) != -1 + return [t, w] + endif + endfor + endfor + return [-1, -1] +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/debug.vim b/bundle/neomake/autoload/neomake/debug.vim new file mode 100644 index 000000000..e6f246f72 --- /dev/null +++ b/bundle/neomake/autoload/neomake/debug.vim @@ -0,0 +1,274 @@ +" Debug/feedback helpers. + +function! neomake#debug#pprint(d, ...) abort + return call('s:pprint', [a:d] + a:000) +endfunction + +function! s:pprint(v, ...) abort + let indent = a:0 ? a:1 : '' + if type(a:v) ==# type({}) + if empty(a:v) + return '{}' + endif + let r = "{\n" + for [k, l:V] in items(a:v) + let r .= printf("%s %s: %s,\n", + \ indent, + \ string(k), + \ s:pprint(neomake#utils#fix_self_ref(V), indent . ' ')) + unlet V " old-vim + endfor + let r .= indent.'}' + return r + elseif type(a:v) ==# type([]) + if empty(a:v) + return '[]' + endif + let r = '['."\n".join(map(copy(a:v), 'indent." ".s:pprint(v:val, indent." ")'), ",\n").",\n".indent.']' + return r + endif + return string(a:v) +endfunction + +function! neomake#debug#validate_maker(maker) abort + let issues = {'errors': [], 'warnings': []} + + if has_key(a:maker, 'process_json') && has_key(a:maker, 'process_output') + let issues.warnings += ['maker has process_json and process_output, but only process_json will be used.'] + let check_process = ['process_json'] + else + let check_process = ['process_json', 'process_output'] + endif + + for f in check_process + if has_key(a:maker, f) + if has_key(a:maker, 'mapexpr') + let issues.warnings += [printf( + \ 'maker has mapexpr, but only %s will be used.', + \ f)] + endif + if has_key(a:maker, 'postprocess') + let issues.warnings += [printf( + \ 'maker has postprocess, but only %s will be used.', + \ f)] + endif + if has_key(a:maker, 'errorformat') + let issues.warnings += [printf( + \ 'maker has errorformat, but only %s will be used.', + \ f)] + endif + endif + endfor + + let jobinfo = neomake#jobinfo#new() + try + let maker = neomake#core#instantiate_maker(a:maker, jobinfo, 0) + if !executable(maker.exe) + let t = get(maker, 'auto_enabled', 0) ? 'warnings' : 'errors' + let issues[t] += [printf("maker's exe (%s) is not executable.", maker.exe)] + endif + catch /^Neomake: / + let issues.errors += [substitute(v:exception, '^Neomake: ', '', '').'.'] + endtry + + if has_key(a:maker, 'name') + if a:maker.name !~# g:neomake#core#valid_maker_name_pattern + call add(issues['errors'], printf( + \ 'Invalid maker name: %s (should match %s)', + \ string(a:maker.name), + \ string(g:neomake#core#valid_maker_name_pattern))) + endif + endif + + return issues +endfunction + +" Optional arg: ft +function! s:get_makers_info(...) abort + let maker_names = call('neomake#GetEnabledMakers', a:000) + if empty(maker_names) + return ['None.'] + endif + let maker_defaults = g:neomake#config#_defaults['maker_defaults'] + let r = [] + for maker_name in maker_names + let maker = call('neomake#GetMaker', [maker_name] + a:000) + let r += [' - '.maker.name] + let r += map(s:get_maker_info(maker, maker_defaults), "' '.v:val") + endfor + return r +endfunction + +function! s:get_maker_info(maker, ...) abort + let maker_defaults = a:0 ? a:1 : {} + let maker = a:maker + let r = [] + for [k, l:V] in sort(copy(items(maker))) + if k !=# 'name' && k !=# 'ft' && k !~# '^_' + if !has_key(maker_defaults, k) + \ || type(V) != type(maker_defaults[k]) + \ || V !=# maker_defaults[k] + let r += [' - '.k.': '.string(V)] + endif + endif + unlet V " vim73 + endfor + + let issues = neomake#debug#validate_maker(maker) + if !empty(issues) + for type in sort(copy(keys(issues))) + let items = issues[type] + if !empty(items) + let r += [' - '.toupper(type) . ':'] + for issue in items + let r += [' - ' . issue] + endfor + endif + endfor + endif + + if type(maker.exe) == type('') && executable(maker.exe) + let version_arg = get(maker, 'version_arg', '--version') + let exe = exists('*exepath') ? exepath(maker.exe) : maker.exe + let version_output = neomake#compat#systemlist([exe, version_arg]) + if empty(version_output) + let version_output = [printf( + \ 'failed to get version information (%s)', + \ v:shell_error)] + endif + let r += [printf(' - version information (%s %s): %s', + \ exe, + \ version_arg, + \ join(version_output, "\n "))] + endif + return r +endfunction + +function! s:get_fts_with_makers() abort + return neomake#compat#uniq(sort(map(split(globpath(escape(&runtimepath, ' '), + \ 'autoload/neomake/makers/ft/*.vim'), "\n"), + \ 'fnamemodify(v:val, ":t:r")'))) +endfunction + +function! neomake#debug#get_maker_info(maker_name) abort + let source = '' + let maker = neomake#get_maker_by_name(a:maker_name, &filetype) + if empty(maker) + let maker = neomake#get_maker_by_name(a:maker_name) + if empty(maker) + let fts = filter(s:get_fts_with_makers(), 'v:val != &filetype') + for ft in fts + let maker = neomake#get_maker_by_name(a:maker_name, ft) + if !empty(maker) + let source = 'filetype '.ft + break + endif + endfor + else + let source = 'project maker' + endif + endif + if empty(maker) + call neomake#log#error(printf('Maker not found: %s.', a:maker_name)) + return [] + endif + let maker = neomake#create_maker_object(maker, &filetype) + return [maker.name . (empty(source) ? '' : ' ('.source.')')] + \ + s:get_maker_info(maker) +endfunction + +function! neomake#debug#display_info(...) abort + let bang = a:0 ? a:1 : 0 + if a:0 > 1 + let maker_name = a:2 + let lines = neomake#debug#get_maker_info(maker_name) + else + let lines = neomake#debug#_get_info_lines() + endif + if bang + try + call setreg('+', join(lines, "\n"), 'l') + catch + call neomake#log#error(printf( + \ 'Could not set clipboard: %s.', v:exception)) + return + endtry + echom 'Copied Neomake info to clipboard ("+).' + else + echon join(lines, "\n") + endif +endfunction + +function! s:trim(s) abort + return substitute(a:s, '\v^[ \t\r\n]+|[ \t\r\n]+$', '', 'g') +endfunction + +function! neomake#debug#_get_info_lines() abort + let r = [] + let ft = &filetype + + let r += ['#### Neomake debug information'] + let r += [''] + let r += ['Async support: '.neomake#has_async_support()] + let r += ['Current filetype: '.ft] + let r += ['Windows: '.neomake#utils#IsRunningWindows()] + let r += ['[shell, shellcmdflag, shellslash]: '.string([&shell, &shellcmdflag, &shellslash])] + let r += [join(map(split(neomake#utils#redir('verb set makeprg?'), '\n'), 's:trim(v:val)'), ', ')] + + let r += [''] + let r += ['##### Enabled makers'] + let r += [''] + let r += ['For the current filetype ("'.ft.'", used with :Neomake):'] + let r += s:get_makers_info(ft) + if empty(ft) + let r += ['NOTE: the current buffer does not have a filetype.'] + else + let conf_ft = neomake#utils#get_ft_confname(ft) + let r += ['NOTE: you can define g:neomake_'.conf_ft.'_enabled_makers' + \ .' to configure it (or b:neomake_'.conf_ft.'_enabled_makers).'] + endif + let r += [''] + let r += ['For the project (used with :Neomake!):'] + let r += s:get_makers_info() + let r += ['NOTE: you can define g:neomake_enabled_makers to configure it.'] + let r += [''] + let r += ['Default maker settings:'] + for [k, v] in items(neomake#config#get('maker_defaults')) + let r += [' - '.k.': '.string(v)] + unlet! v " Fix variable type mismatch with Vim 7.3. + endfor + let r += [''] + let r += ['##### Settings'] + let r += [''] + let r += ['###### New-style (dict, overrides old-style)'] + let r += [''] + let r += ['```'] + + let r += ['g:neomake: '.(exists('g:neomake') ? s:pprint(g:neomake) : 'unset')] + let r += ['b:neomake: '.(exists('b:neomake') ? s:pprint(b:neomake) : 'unset')] + let r += ['```'] + let r += [''] + let r += ['###### Old-style'] + let r += [''] + let r += ['```'] + for [k, V] in sort(items(filter(copy(g:), "v:key =~# '^neomake_'"))) + let r += ['g:'.k.' = '.string(V)] + unlet! V " Fix variable type mismatch with Vim 7.3. + endfor + let r += [''] + let r += ['```'] + let r += ["\n"] + let r += ['#### :version'] + let r += [''] + let r += ['```'] + let r += split(neomake#utils#redir('version'), '\n') + let r += ['```'] + let r += [''] + let r += ['#### :messages'] + let r += [''] + let r += ['```'] + let r += split(neomake#utils#redir('messages'), '\n') + let r += ['```'] + return r +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/highlights.vim b/bundle/neomake/autoload/neomake/highlights.vim new file mode 100644 index 000000000..cdc416a5e --- /dev/null +++ b/bundle/neomake/autoload/neomake/highlights.vim @@ -0,0 +1,155 @@ +" vim: ts=4 sw=4 et + +let s:highlights = {'file': {}, 'project': {}} +let s:highlight_types = { + \ 'E': 'NeomakeError', + \ 'W': 'NeomakeWarning', + \ 'I': 'NeomakeInfo', + \ 'M': 'NeomakeMessage' + \ } + +let s:nvim_api = exists('*nvim_buf_add_highlight') + +" Used in tests. +function! neomake#highlights#_get() abort + return s:highlights +endfunction + +if s:nvim_api + function! s:InitBufHighlights(type, buf) abort + if !bufexists(a:buf) + " The buffer might be wiped by now: prevent 'Invalid buffer id'. + return + endif + if has_key(s:highlights[a:type], a:buf) + call nvim_buf_clear_highlight(a:buf, s:highlights[a:type][a:buf], 0, -1) + else + let s:highlights[a:type][a:buf] = nvim_buf_add_highlight(a:buf, 0, '', 0, 0, -1) + endif + endfunction + + function! s:reset(type, buf) abort + if has_key(s:highlights[a:type], a:buf) + call nvim_buf_clear_highlight(a:buf, s:highlights[a:type][a:buf], 0, -1) + unlet s:highlights[a:type][a:buf] + endif + endfunction +else + function! s:InitBufHighlights(type, buf) abort + let s:highlights[a:type][a:buf] = { + \ 'NeomakeError': [], + \ 'NeomakeWarning': [], + \ 'NeomakeInfo': [], + \ 'NeomakeMessage': [] + \ } + endfunction + + function! s:reset(type, buf) abort + if has_key(s:highlights[a:type], a:buf) + unlet s:highlights[a:type][a:buf] + call neomake#highlights#ShowHighlights() + endif + endfunction +endif + +function! neomake#highlights#ResetFile(buf) abort + call s:reset('file', a:buf) +endfunction +function! neomake#highlights#ResetProject(...) abort + if a:0 " deprecated a:buf + call neomake#log#warn_once('neomake#highlights#ResetProject does not use a:buf anymore.', + \ 'deprecated-highlight-resetproject') + endif + for buf in keys(s:highlights['project']) + call s:reset('project', +buf) + endfor +endfunction + +function! neomake#highlights#AddHighlight(entry, type) abort + " Some makers use line 0 for file warnings (which cannot be highlighted, + " e.g. cpplint with "no copyright" warnings). + if a:entry.lnum == 0 + return + endif + + if !has_key(s:highlights[a:type], a:entry.bufnr) + call s:InitBufHighlights(a:type, a:entry.bufnr) + endif + let hi = get(s:highlight_types, toupper(a:entry.type), 'NeomakeError') + + if a:entry.col > 0 && get(g:, 'neomake_highlight_columns', 1) + let length = get(a:entry, 'length', 1) + if s:nvim_api + call nvim_buf_add_highlight(a:entry.bufnr, s:highlights[a:type][a:entry.bufnr], hi, a:entry.lnum - 1, a:entry.col - 1, a:entry.col + length - 1) + else + call add(s:highlights[a:type][a:entry.bufnr][hi], [a:entry.lnum, a:entry.col, length]) + endif + elseif get(g:, 'neomake_highlight_lines', 0) + if s:nvim_api + call nvim_buf_add_highlight(a:entry.bufnr, s:highlights[a:type][a:entry.bufnr], hi, a:entry.lnum - 1, 0, -1) + else + call add(s:highlights[a:type][a:entry.bufnr][hi], a:entry.lnum) + endif + endif +endfunction + +if s:nvim_api + function! neomake#highlights#ShowHighlights() abort + endfunction +else + function! neomake#highlights#ShowHighlights() abort + if exists('w:neomake_highlights') + for highlight in w:neomake_highlights + try + call matchdelete(highlight) + catch /^Vim\%((\a\+)\)\=:E803/ + endtry + endfor + endif + let w:neomake_highlights = [] + + let buf = bufnr('%') + for type in ['file', 'project'] + for [hi, locs] in items(filter(copy(get(s:highlights[type], buf, {})), '!empty(v:val)')) + if exists('*matchaddpos') + call add(w:neomake_highlights, matchaddpos(hi, locs)) + else + for loc in locs + if len(loc) == 1 + call add(w:neomake_highlights, matchadd(hi, '\%' . loc[0] . 'l')) + else + call add(w:neomake_highlights, matchadd(hi, '\%' . loc[0] . 'l\%' . loc[1] . 'c.\{' . loc[2] . '}')) + endif + endfor + endif + endfor + endfor + endfunction +endif + +function! neomake#highlights#DefineHighlights() abort + for [group, link] in items({ + \ 'NeomakeError': 'SpellBad', + \ 'NeomakeWarning': 'SpellCap', + \ 'NeomakeInfo': 'NeomakeWarning', + \ 'NeomakeMessage': 'NeomakeWarning' + \ }) + if !neomake#utils#highlight_is_defined(group) + exe 'highlight link '.group.' '.link + endif + endfor +endfunction + +function! s:wipe_highlights(bufnr) abort + for type in ['file', 'project'] + if has_key(s:highlights[type], a:bufnr) + unlet s:highlights[type][a:bufnr] + endif + endfor +endfunction +augroup neomake_highlights + au! + autocmd BufWipeout * call s:wipe_highlights(expand('')) +augroup END + +call neomake#highlights#DefineHighlights() diff --git a/bundle/neomake/autoload/neomake/jobinfo.vim b/bundle/neomake/autoload/neomake/jobinfo.vim new file mode 100644 index 000000000..c150784e7 --- /dev/null +++ b/bundle/neomake/autoload/neomake/jobinfo.vim @@ -0,0 +1,93 @@ +let s:jobinfo_base = { + \ 'cd_back_cmd': '', + \ 'pending_output': [], + \ 'file_mode': 1, + \ } +function! s:jobinfo_base.get_pid() abort + if has_key(self, 'vim_job') + let info = job_info(self.vim_job) + if info.status ==# 'run' + return info.process + endif + return -1 + endif + try + return jobpid(self.nvim_job) + catch /^Vim(return):E900:/ + return -1 + endtry +endfunction + +function! s:jobinfo_base.as_string() abort + let extra = [] + for k in ['canceled', 'finished'] + if get(self, k, 0) + let extra += [k] + endif + endfor + return printf('Job %d: %s%s', self.id, self.name, + \ empty(extra) ? '' : ' ['.join(extra, ', ').']') +endfunction + +function! s:jobinfo_base.cd_back() abort + if !empty(self.cd_back_cmd) + exe self.cd_back_cmd + let self.cd_back_cmd = '' + endif +endfunction + +function! s:jobinfo_base.cd(...) abort + if a:0 + if has_key(self, 'cd_from_setting') + call neomake#log#debug(printf( + \ 'jobinfo.cd(): keeping cwd from setting: %s.', + \ string(self.cd_from_setting)), self) + return '' + endif + let dir = a:1 + else + let maker = self.maker + let dir = neomake#utils#GetSetting('cwd', maker, '', self.ft, self.bufnr, 1) + if !empty(dir) + let self.cd_from_setting = dir + endif + endif + + if dir !=# '' + if dir[0:1] ==# '%:' + let dir = neomake#utils#fnamemodify(self.bufnr, dir[1:]) + else + let dir = expand(dir, 1) + endif + let dir = fnamemodify(dir, ':p') + " NOTE: need to keep trailing backslash with "/" and "X:\" on Windows. + if dir !=# '/' && dir[-1:] ==# neomake#utils#Slash() && dir[-2] !=# ':' + let dir = dir[:-2] + endif + else + let dir = get(self, 'cwd', $HOME) + endif + + let cur_wd = getcwd() + if dir !=# cur_wd + let [cd_error, cd_back_cmd] = neomake#utils#temp_cd(dir, cur_wd) + if !empty(cd_error) + call neomake#log#debug(printf('jobinfo.cd(): error when trying to change cwd to %s: %s.', + \ dir, cd_error)) + return cd_error + endif + let self.cwd = dir + let self.cd_back_cmd = cd_back_cmd + else + let self.cwd = cur_wd + endif + return '' +endfunction + +function! neomake#jobinfo#new() abort + let jobinfo = deepcopy(s:jobinfo_base) + let jobinfo.bufnr = bufnr('%') + return jobinfo +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/list.vim b/bundle/neomake/autoload/neomake/list.vim new file mode 100644 index 000000000..8c9ccdecc --- /dev/null +++ b/bundle/neomake/autoload/neomake/list.vim @@ -0,0 +1,1047 @@ +scriptencoding utf-8 +" Create a List object from a quickfix/location list. +" TODO: (optionally?) add entries sorted? (errors first, grouped by makers (?) etc) + +let s:can_set_qf_title = has('patch-7.4.2200') +let s:can_set_qf_context = has('patch-8.0.0590') +let s:can_set_qf_items = has('patch-8.0.0657') +let s:has_support_for_qfid = has('patch-8.0.1023') +let s:use_efm_parsing = has('patch-8.0.1040') " 'efm' in setqflist/getqflist + +" Do we need to replace (instead of append) the location/quickfix list, for +" :lwindow to not open it with only invalid entries?! +" Without patch-7.4.379 this does not work though, and a new list needs to +" be created (which is not done). +" @vimlint(EVL108, 1) +let s:needs_to_replace_qf_for_lwindow = has('patch-7.4.379') + \ && (!has('patch-7.4.1752') || (has('nvim') && !has('nvim-0.2.0'))) +" @vimlint(EVL108, 0) +let s:needs_to_init_qf_for_lwindow = !has('patch-8.1.0622') + +function! s:save_list_ref(list) abort + if a:list.type ==# 'loclist' + for d in [w:, b:] + let info = get(d, '_neomake_info', {}) + let info['loclist'] = a:list + let d['_neomake_info'] = info + endfor + else + let info = get(g:, '_neomake_info', {}) + let info['qflist'] = a:list + let g:_neomake_info = info + endif +endfunction + +function! neomake#list#ListForMake(make_info) abort + let file_mode = a:make_info.options.file_mode + let type = file_mode ? 'loclist' : 'quickfix' + let list = neomake#list#List(type) + let list.make_info = a:make_info + call s:save_list_ref(list) + return list +endfunction + +" a:type: "loclist" or "quickfix" +function! neomake#list#List(type) abort + let list = deepcopy(s:base_list) + let list.type = a:type + " Display debug messages about changed entries. + let list.debug = get(g:, 'neomake_debug_list', + \ exists('g:neomake_test_messages') + \ || !empty(get(g:, 'neomake_logfile')) + \ || neomake#utils#get_verbosity() >= 3) + return list +endfunction + +" Internal base list implementation. +let s:base_list = { + \ 'need_init': 1, + \ 'entries': [], + \ } +" Info about contained jobs. +let s:base_list.job_entries = {} +let s:base_list.maker_info_by_jobid = {} + +function! s:base_list.sort_by_location() dict abort + let entries = get(self, '_sorted_entries_by_location', copy(self.entries)) + let self._sorted_entries_by_location = sort(entries, 's:cmp_listitem_loc') + return self._sorted_entries_by_location +endfunction + +" a:1: optional jobinfo +function! s:base_list.add_entries(entries, ...) dict abort + let idx = len(self.entries) + if a:0 && !has_key(self.job_entries, a:1.id) + let self.job_entries[a:1.id] = [] + let self.maker_info_by_jobid[a:1.id] = a:1.maker + endif + for entry in a:entries + let idx += 1 + let e = extend(copy(entry), {'nmqfidx': idx}) + if a:0 + call add(self.job_entries[a:1.id], e) + let e.job_id = a:1.id + endif + call add(self.entries, e) + endfor + if self.debug + let indexes = map(copy(self.entries), 'v:val.nmqfidx') + if len(neomake#compat#uniq(sort(copy(indexes)))) != len(indexes) + call neomake#log#error(printf('Duplicate qf indexes in list entries: %s.', + \ string(indexes))) + endif + endif + " Sort if it was sorted before. + if has_key(self, '_sorted_entries_by_location') + call extend(self._sorted_entries_by_location, a:entries) + call self.sort_by_location() + endif +endfunction + +" Add entries for a job (non-efm method). +function! s:base_list.add_entries_for_job(entries, jobinfo) dict abort + let tempfiles = get(self.make_info, 'tempfiles', []) + if !empty(tempfiles) + let mapped = 0 + for e in a:entries + if has_key(e, 'filename') && get(e, 'bufnr', 0) == 0 + if index(tempfiles, e.filename) != -1 + unlet e.filename + let e.bufnr = a:jobinfo.bufnr + let mapped += 1 + endif + endif + endfor + if mapped + call neomake#log#debug(printf('Mapped %d bufnrs from temporary files.', mapped), a:jobinfo) + endif + endif + return self._appendlist(a:entries, a:jobinfo) +endfunction + +function! neomake#list#get_title(prefix, bufnr, maker_info) abort + let prefix = 'Neomake' + if !empty(a:prefix) + let prefix .= '['.a:prefix.']' + endif + if a:bufnr + let bufname = bufname(a:bufnr) + if empty(bufname) + let bufname = 'buf:'.a:bufnr + else + let bufname = pathshorten(bufname) + endif + let maker_info = bufname + if empty(a:maker_info) + let maker_info = bufname + else + let maker_info = bufname.' ('.a:maker_info.')' + endif + else + let maker_info = a:maker_info + endif + let title = prefix + if !empty(maker_info) + let title = prefix.': '.maker_info + endif + return title +endfunction + +function! s:base_list._get_title() abort + let maker_info = [] + for job in self.make_info.finished_jobs + let info = job.maker.name + let ok = 1 + if get(job, 'aborted', 0) + let info .= '!' + let ok = 0 + endif + if has_key(self.job_entries, job.id) + let c = len(self.job_entries[job.id]) + let info .= '('.c.')' + let ok = 0 + endif + if ok + let info .= '✓' + endif + call add(maker_info, info) + endfor + for job in self.make_info.active_jobs + let info = job.maker.name + let info .= '...' + if has_key(self.job_entries, job.id) + let c = len(self.job_entries[job.id]) + let info .= '('.c.')' + endif + call add(maker_info, info) + endfor + for job in self.make_info.jobs_queue + let info = job.maker.name + let info .= '?' + call add(maker_info, info) + endfor + for job in get(self.make_info, 'aborted_jobs', []) + let info = job.maker.name + let info .= '-' + call add(maker_info, info) + endfor + let maker_info_str = join(maker_info, ', ') + if self.type ==# 'loclist' + let bufnr = self.make_info.options.bufnr + else + let bufnr = 0 + endif + if get(self.make_info.options, 'automake') + let prefix = 'auto' + elseif self.make_info.options.file_mode + let prefix = 'file' + else + let prefix = 'project' + endif + return neomake#list#get_title(prefix, bufnr, maker_info_str) +endfunction + +function! s:base_list.finish_for_make() abort + if self.need_init + if self.type ==# 'loclist' + call neomake#log#debug('Cleaning location list.', self.make_info) + else + call neomake#log#debug('Cleaning quickfix list.', self.make_info) + endif + call self._call_qf_fn('set', [], ' ') + else + " Set title, but only if list window is still valid. + if s:has_support_for_qfid + let valid = self._has_valid_qf() + elseif self.type ==# 'loclist' + let valid = self._get_loclist_win(1) != -1 + else + let valid = 1 + endif + if !valid + call neomake#log#debug('list: finish: list is not valid anymore.', self.make_info) + return + endif + call self.set_title() + endif +endfunction + +function! s:base_list._call_qf_fn(action, ...) abort + let fns_args = call(self._get_fn_args, [a:action] + a:000, self) + + if a:action ==# 'get' + let [fn, args] = fns_args[0] + if s:has_support_for_qfid + let args[-1].items = 1 + if self.debug + call neomake#log#debug(printf('list: call: "get", returning items: %s.', string(fns_args))) + endif + return call(fn, args).items + endif + if self.debug + call neomake#log#debug(printf('list: call: "get": %s.', string(fns_args))) + endif + return call(fn, args) + endif + + for fns in fns_args + let [fn, args] = fns + + if self.debug + if a:action ==# 'set' + let log_args = deepcopy(args) + " Only display 5 items. + if self.type ==# 'loclist' + let log_args[1] = neomake#utils#shorten_list_for_log(log_args[1], 5) + else + let log_args[0] = neomake#utils#shorten_list_for_log(log_args[0], 5) + endif + " Massage options dict. + if type(log_args[-1]) == type({}) + let neomake_context = get(get(log_args[-1], 'context', {}), 'neomake', {}) + if !empty(neomake_context) + for [k, v] in items(neomake_context) + if k ==# 'make_info' + " Fixes self-ref, and makes it much shorter. + let neomake_context[k] = 'make_id='.v.make_id + endif + endfor + endif + " Only display 5 items. + if has_key(log_args[-1], 'items') + let log_args[-1].items = neomake#utils#shorten_list_for_log(log_args[-1].items, 5) + endif + endif + call neomake#log#debug(printf('list: call: set: %s.', string(log_args))) + else + call neomake#log#debug(printf('list: call: "%s": %s.', a:action, string(args))) + endif + endif + + call call(fn, args, self) + endfor + + " Get qfid. + if self.need_init + if a:action ==# 'set' && s:has_support_for_qfid + if self.type ==# 'loclist' + let loclist_win = self._get_loclist_win() + let self.qfid = getloclist(loclist_win, {'id': 0}).id + else + let self.qfid = getqflist({'id': 0}).id + endif + if self.debug + call neomake#log#debug(printf('list: got qfid (action=%s): %s.', a:action, self.qfid)) + endif + endif + let self.need_init = 0 + endif +endfunction + +function! s:base_list.set_title() abort + if s:can_set_qf_title + call self._call_qf_fn('title', self._get_title()) + endif +endfunction + +" Check if quickfix list is still valid, which might not be the case anymore +" if more than 10 new lists have been opened etc. +" Returns -1 without suffort for quickfix ids. +function! s:base_list._has_valid_qf() abort + if !s:has_support_for_qfid + return -1 + endif + + if self.type ==# 'loclist' + let loclist_win = self._get_loclist_win(1) + if loclist_win is -1 + return 0 + endif + if !get(getloclist(loclist_win, {'id': self.qfid}), 'id') + return 0 + endif + else + if !get(getqflist({'id': self.qfid}), 'id') + return 0 + endif + endif + return 1 +endfunction + +" Get winnr/winid to be used with loclist functions. +" a:1: return -1 instead of throwing when no window could be found? +function! s:base_list._get_loclist_win(...) abort + if !has_key(self, 'make_info') + throw 'cannot handle type=loclist without make_info' + endif + let loclist_win = 0 + let make_id = self.make_info.make_id + " NOTE: prefers using 0 for when winid is not supported with + " setloclist() yet (vim74-xenial, patch-7.4.1895). + if index(get(w:, 'neomake_make_ids', []), make_id) == -1 + if has_key(self.make_info.options, 'winid') && has('patch-7.4.1895') + " Can only use it with getloclist after patch-7.4.1895. + let loclist_win = self.make_info.options.winid + else + let [t, w] = neomake#core#get_tabwin_for_makeid(make_id) + if [t, w] == [-1, -1] + for w in range(1, winnr('$')) + if get(get(get(neomake#compat#getwinvar(w, '_neomake_info', {}), 'loclist', {}), 'make_info', {}), 'make_id') == make_id + let loclist_win = w + break + endif + endfor + if loclist_win == 0 + if a:0 && a:1 + return -1 + endif + throw printf('Neomake: could not find location list for make_id %d.', make_id) + endif + return loclist_win + endif + if t != tabpagenr() + if a:0 && a:1 + return -1 + endif + throw printf('Neomake: trying to use location list from another tab (current=%d != target=%d).', tabpagenr(), t) + endif + let loclist_win = w + endif + endif + return loclist_win +endfunction + +" Return a list of commands to be called. +" action: "get", "set", "init", "title" +" a:000: optional args (for set/init/title) +function! s:base_list._get_fn_args(action, ...) abort + if self.type ==# 'loclist' + if a:action ==# 'get' + let fn = 'getloclist' + else + let fn = 'setloclist' + endif + else + if a:action ==# 'get' + let fn = 'getqflist' + else + let fn = 'setqflist' + endif + endif + + if self.type ==# 'loclist' + let args = [self._get_loclist_win()] + else + let args = [] + endif + + let options = {} + if !self.need_init + let valid = self._has_valid_qf() + if valid == 1 + let options.id = self.qfid + elseif valid == 0 + if self.type ==# 'loclist' + let loclist_win = args[0] + throw printf('Neomake: qfid %d for location list (%d) has become invalid.', self.qfid, loclist_win) + else + throw printf('Neomake: qfid %d for quickfix list has become invalid.', self.qfid) + endif + endif + endif + + if a:action ==# 'title' + call extend(args, [[], 'a']) + if exists('*vader#assert#true') + call vader#assert#true(s:can_set_qf_title) + endif + let options.title = a:1 + else + call extend(args, a:000) + if a:action ==# 'set' + if exists('*vader#assert#equal') + call vader#assert#equal(len(a:000), 2) + endif + if s:can_set_qf_items + let options.items = a:1 + let args[-2] = [] + endif + endif + endif + if !empty(options) + call add(args, options) + endif + + let r = [] + if a:action ==# 'set' + if self.need_init && get(self, 'reset_existing_qflist') + if self.type ==# 'loclist' + let args[2] = 'r' " action + else + let args[1] = 'r' " action + endif + if self.type ==# 'loclist' + let msg = 'Reusing location list for entries.' + else + let msg = 'Reusing quickfix list for entries.' + endif + call neomake#log#debug(msg, self.make_info) + endif + + " Experimental: set make_info into context. + " This is used to access make info from the qf window itself. + if self.need_init && s:can_set_qf_context + let options.context = {'neomake': {'make_info': self.make_info}} + endif + + " Handle setting title, which gets done initially and when maker + " names are updated. This has to be done in a separate call + " without patch-8.0.0657. + if s:can_set_qf_title + let title = self._get_title() + if s:can_set_qf_items + if type(args[-1]) != type({}) + call add(args, {'title': title, 'items': args[1]}) + else + let args[-1].title = title + endif + else + " Update title after actual call. + call add(r, [fn, args]) + + if self.type ==# 'loclist' + let args = [args[0], [], 'a', {'title': title}] + else + let args = [[], 'a', {'title': title}] + endif + endif + endif + endif + call add(r, [fn, args]) + return r +endfunction + +function! s:mark_entry_with_nmcfg(entry, maker_info) abort + let maker_name = a:maker_info.name + let config = { + \ 'name': maker_name, + \ 'short': get(a:maker_info, 'short_name', maker_name[:3]), + \ } + let marker_entry = copy(a:entry) + let marker_entry.text .= printf(' nmcfg:%s', string(config)) + return marker_entry +endfunction + +function! s:base_list._replace_qflist_entries(entries) abort + let set_entries = a:entries + + " Handle nmcfg markers when setting all entries without jobinfo. + if neomake#quickfix#is_enabled() + let set_entries = copy(set_entries) + let prev_job_id = 0 + + " Handle re-setting all entries. This is meant to be used later + " for replacing the whole list. + let i = 0 + for e in set_entries + if e.job_id != prev_job_id + let maker_info = self.maker_info_by_jobid[e.job_id] + let set_entries[i] = s:mark_entry_with_nmcfg(e, maker_info) + let prev_job_id = e.job_id + endif + let i += 1 + endfor + endif + + call self._set_qflist_entries(set_entries, 'r') +endfunction + +function! s:base_list._set_qflist_entries(entries, action) abort + let action = a:action + if self.need_init && !get(self, 'reset_existing_qflist') + if self.type ==# 'loclist' + let msg = 'Creating location list for entries.' + else + let msg = 'Creating quickfix list for entries.' + endif + call neomake#log#debug(msg, self.make_info) + + if s:needs_to_init_qf_for_lwindow + " Clean list without autocommands (customqf etc) to avoid + " flicker. This is only to work around a Vim bug anyway. + noautocmd call self._call_qf_fn('set', [], ' ') + else + let action = ' ' + endif + endif + call self._call_qf_fn('set', a:entries, action) +endfunction + +function! s:base_list._get_qflist_entries() abort + return self._call_qf_fn('get') +endfunction + +" Append entries to location/quickfix list. +function! s:base_list._appendlist(entries, jobinfo) abort + call neomake#log#debug(printf('Adding %d list entries.', len(a:entries)), self.make_info) + + let set_entries = a:entries + let action = 'a' + if !self.need_init + let action = 'a' + if s:needs_to_replace_qf_for_lwindow || neomake#quickfix#is_enabled() + " Need to replace whole list with customqf to trigger FileType + " autocmd (which is not done for action='a'). + " This should be enhanced to only format new entries instead + " later, but needs support for changing non-current buffer lines. + let action = 'r' + if self.type ==# 'loclist' + let set_entries = self._get_qflist_entries() + set_entries + else + let set_entries = getqflist() + set_entries + endif + endif + endif + + " Add marker for custom quickfix to the first (new) entry. + let needs_custom_qf_marker = neomake#quickfix#is_enabled() + if needs_custom_qf_marker + if action ==# 'a' + let prev_idx = 0 + else + let prev_idx = len(self.entries) + endif + let set_entries = copy(set_entries) + let set_entries[prev_idx] = s:mark_entry_with_nmcfg(set_entries[prev_idx], a:jobinfo.maker) + endif + + " NOTE: need to fetch (or pre-parse with new patch) to get updated bufnr etc. + call self._set_qflist_entries(set_entries, action) + let added = self._get_qflist_entries()[len(self.entries) :] + + if needs_custom_qf_marker + " Remove marker that should only be in the quickfix list. + let added[0].text = substitute(added[0].text, ' nmcfg:{.\{-}}$', '', '') + endif + + if self.debug && added != a:entries + let diff = neomake#list#_diff_new_entries(a:entries, added) + if !empty(diff) + for [k, v] in items(diff) + " TODO: handle valid=1 being added? + call neomake#log#debug(printf( + \ 'Entry %d differs after adding: %s.', + \ k+1, + \ string(v)), + \ a:jobinfo) + endfor + endif + endif + + let parsed_entries = copy(a:entries) + let idx = 0 + for e in added + if parsed_entries[idx].bufnr != e.bufnr + call neomake#log#debug(printf( + \ 'Updating entry bufnr: %s => %s.', + \ a:entries[idx].bufnr, e.bufnr)) + let parsed_entries[idx].bufnr = e.bufnr + endif + let idx += 1 + endfor + + call self.add_entries(parsed_entries, a:jobinfo) + return parsed_entries +endfunction + +function! neomake#list#_diff_new_entries(orig, new) abort + if a:orig == a:new + return {} + endif + let i = 0 + let r = {} + for new in a:new + let orig = copy(get(a:orig, i, {})) + for [k, v] in items({'pattern': '', 'module': '', 'valid': 1}) + if has_key(new, k) + let orig[k] = v + endif + endfor + if new != orig + " 'removed': {'length': 4, 'filename': 'from.rs', + " 'maker_name': 'cargo'}} + let new = copy(new) + for k in ['length', 'maker_name'] + if has_key(orig, k) + let new[k] = orig[k] + endif + endfor + let diff = neomake#utils#diff_dict(orig, new) + if !empty(diff) + let r[i] = diff + endif + endif + let i += 1 + endfor + return r +endfunction + +" Add raw lines using errorformat. +" This either pre-parses them with newer versions, or uses +" :laddexpr/:caddexpr. +function! s:base_list.add_lines_with_efm(lines, jobinfo) dict abort + let maker = a:jobinfo.maker + let file_mode = self.type ==# 'loclist' + + if s:use_efm_parsing + let efm = a:jobinfo.maker.errorformat + let parsed_entries = get(getqflist({'lines': a:lines, 'efm': efm}), 'items', -1) + if parsed_entries is -1 + call neomake#log#error(printf('Failed to get items via efm-parsing. Invalid errorformat? (%s)', efm), a:jobinfo) + let parsed_entries = getqflist({'lines': a:lines, 'efm': &errorformat}).items + endif + if empty(parsed_entries) + return [] + endif + else + if self.need_init + if self.type ==# 'loclist' + let msg = 'Creating location list.' + else + let msg = 'Creating quickfix list.' + endif + call neomake#log#debug(msg, self.make_info) + call self._call_qf_fn('set', [], ' ') + endif + let olderrformat = &errorformat + try + let &errorformat = maker.errorformat + catch + call neomake#log#error(printf('Failed to set errorformat (%s): %s.', string(maker.errorformat), v:exception), a:jobinfo) + endtry + try + if file_mode + let cmd = 'laddexpr' + else + let cmd = 'caddexpr' + endif + let a:jobinfo._delayed_qf_autocmd = 'QuickfixCmdPost '.cmd + let cmd = 'noautocmd '.cmd.' a:lines' + if self.debug + call neomake#log#debug(printf('list: exe: %s (with %d lines).', cmd, len(a:lines)), a:jobinfo) + endif + exe cmd + finally + let &errorformat = olderrformat + call a:jobinfo.cd_back() + endtry + + let new_list = self._get_qflist_entries() + let parsed_entries = new_list[len(self.entries) :] + if empty(parsed_entries) + return [] + endif + endif + + let l:Postprocess = neomake#utils#GetSetting('postprocess', maker, [], a:jobinfo.ft, a:jobinfo.bufnr) + if type(Postprocess) != type([]) + let postprocessors = [Postprocess] + else + let postprocessors = Postprocess + endif + + let default_type = 'unset' + + let entries = [] + let changed_entries = {} + let removed_entries = [] + let different_bufnrs = {} + let bufnr_from_temp = {} + let bufnr_from_stdin = {} + let tempfile_bufnrs = has_key(self.make_info, 'tempfiles') ? map(copy(self.make_info.tempfiles), 'bufnr(v:val)') : [] + let uses_stdin = get(a:jobinfo, 'uses_stdin', 0) + + let entry_idx = -1 + for entry in parsed_entries + let entry_idx += 1 + let before = copy(entry) + " Handle unlisted buffers via tempfiles and uses_stdin. + if entry.bufnr && entry.bufnr != a:jobinfo.bufnr + \ && (!empty(tempfile_bufnrs) || uses_stdin) + let map_bufnr = index(tempfile_bufnrs, entry.bufnr) + if map_bufnr != -1 + let entry.bufnr = a:jobinfo.bufnr + let map_bufnr = tempfile_bufnrs[map_bufnr] + if !has_key(bufnr_from_temp, map_bufnr) + let bufnr_from_temp[map_bufnr] = [] + endif + let bufnr_from_temp[map_bufnr] += [entry_idx+1] + elseif uses_stdin + if !buflisted(entry.bufnr) && bufexists(entry.bufnr) + if !has_key(bufnr_from_stdin, entry.bufnr) + let bufnr_from_stdin[entry.bufnr] = [] + endif + let bufnr_from_stdin[entry.bufnr] += [entry_idx+1] + let entry.bufnr = a:jobinfo.bufnr + endif + endif + endif + if self.debug && entry.bufnr && entry.bufnr != a:jobinfo.bufnr + if !has_key(different_bufnrs, entry.bufnr) + let different_bufnrs[entry.bufnr] = 1 + else + let different_bufnrs[entry.bufnr] += 1 + endif + endif + if !empty(postprocessors) + let g:neomake_postprocess_context = {'jobinfo': a:jobinfo} + try + for l:F in postprocessors + if type(F) == type({}) + call call(F.fn, [entry], F) + else + call call(F, [entry], maker) + endif + unlet! F " vim73 + endfor + finally + unlet! g:neomake_postprocess_context " Might be unset already with sleep in postprocess. + endtry + endif + if entry != before + let changed_entries[entry_idx] = entry + if self.debug + " Ignore bufnr changes for tempfiles/stdin (logged together + " later). + let diff = neomake#utils#diff_dict(before, entry) + let changed_bufnr = get(get(diff, 'changed', {}), 'bufnr', []) + if !empty(changed_bufnr) && ( + \ has_key(bufnr_from_temp, changed_bufnr[0]) + \ || has_key(bufnr_from_stdin, changed_bufnr[0])) + unlet diff.changed.bufnr + if empty(diff.changed) + unlet diff.changed + endif + endif + if !empty(diff) + call neomake#log#debug(printf( + \ 'Modified list entry %d (postprocess): %s.', + \ entry_idx + 1, + \ substitute(string(diff), '\n', '\\n', 'g')), + \ a:jobinfo) + endif + endif + endif + + if entry.valid <= 0 + if entry.valid < 0 || maker.remove_invalid_entries + call insert(removed_entries, entry_idx) + let entry_copy = copy(entry) + call neomake#log#debug(printf( + \ 'Removing invalid entry: %s (%s).', + \ remove(entry_copy, 'text'), + \ string(entry_copy)), a:jobinfo) + continue + endif + endif + + if empty(entry.type) && entry.valid + if default_type ==# 'unset' + let default_type = neomake#utils#GetSetting('default_entry_type', maker, 'W', a:jobinfo.ft, a:jobinfo.bufnr) + endif + if !empty(default_type) + let entry.type = default_type + let changed_entries[entry_idx] = entry + endif + endif + call add(entries, entry) + endfor + + if !s:use_efm_parsing + let new_index = len(self.entries) + " Add marker for custom quickfix to the first (new) entry. + if neomake#quickfix#is_enabled() + let changed_entries[0] = s:mark_entry_with_nmcfg(entries[0], maker) + endif + + if !empty(changed_entries) || !empty(removed_entries) + " Need to update/replace current list. + let list = self._get_qflist_entries() + if !empty(changed_entries) + for k in keys(changed_entries) + let list[new_index + k] = changed_entries[k] + endfor + endif + if !empty(removed_entries) + for k in removed_entries + call remove(list, new_index + k) + endfor + endif + call self._set_qflist_entries(list, 'r') + endif + endif + + if !empty(bufnr_from_temp) || !empty(bufnr_from_stdin) + if !has_key(self.make_info, '_wipe_unlisted_buffers') + let self.make_info._wipe_unlisted_buffers = [] + endif + let self.make_info._wipe_unlisted_buffers += keys(bufnr_from_stdin) + keys(bufnr_from_stdin) + if !empty(bufnr_from_temp) + for [tempbuf, entries_idx] in items(bufnr_from_temp) + let log_entries_idx = join(neomake#utils#shorten_list_for_log(entries_idx, 50), ', ') + call neomake#log#debug(printf( + \ 'Used bufnr from temporary buffer %d (%s) for %d entries: %s.', + \ tempbuf, + \ bufname(+tempbuf), + \ len(entries_idx), + \ log_entries_idx), a:jobinfo) + endfor + endif + if !empty(bufnr_from_stdin) + for [tempbuf, entries_idx] in items(bufnr_from_stdin) + let log_entries_idx = join(neomake#utils#shorten_list_for_log(entries_idx, 50), ', ') + call neomake#log#debug(printf( + \ 'Used bufnr from stdin buffer %d (%s) for %d entries: %s.', + \ tempbuf, + \ bufname(+tempbuf), + \ len(entries_idx), + \ log_entries_idx), a:jobinfo) + endfor + endif + endif + if !empty(different_bufnrs) + call neomake#log#debug(printf('WARN: seen entries with bufnr different from jobinfo.bufnr (%d): %s, current bufnr: %d.', a:jobinfo.bufnr, string(different_bufnrs), bufnr('%'))) + endif + + if empty(entries) + return [] + endif + + if s:use_efm_parsing + call self._appendlist(entries, a:jobinfo) + else + call self.add_entries(entries, a:jobinfo) + endif + return entries +endfunction + +" Get location list from current window, or via buffer. +function! s:get_loclist() abort + let win_info = neomake#compat#getwinvar(winnr(), '_neomake_info', {}) + if has_key(win_info, 'loclist') + return win_info['loclist'] + endif + let buf_info = neomake#compat#getbufvar(bufnr('%'), '_neomake_info', {}) + if has_key(buf_info, 'loclist') + return buf_info['loclist'] + endif + return {} +endfunction + +" Get the current location or quickfix list. +function! neomake#list#get() abort + let loclist = s:get_loclist() + if !empty(loclist) + return loclist + endif + let info = get(g:, '_neomake_info', {}) + if has_key(info, 'qflist') + return info['qflist'] + endif + return {} +endfunction + +function! neomake#list#get_loclist() abort + let loclist = s:get_loclist() + if empty(loclist) + " Create a new list, not bound to a job. + call neomake#log#debug('Creating new List object.') + let loclist = neomake#list#List('loclist') + call loclist.add_entries(getloclist(0)) + call s:save_list_ref(loclist) + endif + return loclist +endfunction + +" TODO: save project-maker quickfix list. +function! neomake#list#get_qflist() abort + let info = get(g:, '_neomake_info', {}) + if !has_key(info, 'qflist') + " Create a new list, not bound to a job. + call neomake#log#debug('Creating new List object.') + let list = neomake#list#List('quickfix') + call list.add_entries(getqflist()) + let info['qflist'] = list + let g:_neomake_info = info + endif + return info['qflist'] +endfunction + +function! s:get_list(file_mode) abort + if a:file_mode + let list = neomake#list#get_loclist() + let g:unimpaired_prevnext = ['NeomakePrevLoclist', 'NeomakeNextLoclist'] + else + let list = neomake#list#get_qflist() + let g:unimpaired_prevnext = ['NeomakePrevQuickfix', 'NeomakeNextQuickfix'] + endif + return list +endfunction + +function! neomake#list#next(c, ...) abort + let file_mode = a:0 ? a:1 : 1 + let list = s:get_list(file_mode) + call s:goto_nearest(list, a:c == 0 ? 1 : a:c) +endfunction + +function! neomake#list#prev(c, ...) abort + let file_mode = a:0 ? a:1 : 1 + let list = s:get_list(file_mode) + call s:goto_nearest(list, a:c == 0 ? -1 : -a:c) +endfunction + +" TODO: global / already used somewhere else? / config +let g:neomake#list#type_prio = { + \ 'E': 0, + \ 'W': 1, + \ 'I': 2, + \ } + +" TODO: allow to customize via own callback(s)? +function! s:cmp_listitem_loc(a, b) abort + let buf_diff = a:a.bufnr - a:b.bufnr + if buf_diff + return buf_diff + endif + + if exists('*vader#assert#not_equal') + call vader#assert#not_equal(a:a.bufnr, -1) + call vader#assert#not_equal(a:b.bufnr, -1) + endif + + let lnum_diff = a:a.lnum - a:b.lnum + if lnum_diff + return lnum_diff + endif + + let col_diff = a:a.col - a:b.col + if col_diff + return col_diff + endif + + let prio = g:neomake#list#type_prio + return get(prio, a:a.type, 99) - get(prio, a:b.type, 99) +endfunction + +function! s:goto_nearest(list, offset) abort + let [lnum, col] = getpos('.')[1:2] + if a:offset == 0 + throw 'a:offset must not be 0' + endif + + if !has_key(a:list, '_sorted_entries_by_location') + call a:list.sort_by_location() + endif + let entries = a:list._sorted_entries_by_location + if a:offset < 0 + call reverse(entries) + endif + + let c = a:offset + let step = a:offset > 0 ? 1 : -1 + let found = 0 + for item in entries + if (a:offset > 0 && (item.lnum > lnum || (item.lnum == lnum && item.col > col))) + \ || (a:offset < 0 && (item.lnum < lnum || (item.lnum == lnum && item.col < col))) + let c -= step + let found = item.nmqfidx + if c == 0 + break + endif + endif + endfor + + if found + if a:list.type ==# 'loclist' + if exists('*vader#assert#equal') + " @vimlint(EVL102, 1, l:ll_item) + let ll_item = getloclist(0)[found-1] + call vader#assert#equal([ll_item.bufnr, ll_item.lnum], [item.bufnr, item.lnum]) + endif + execute 'll '.found + else + if exists('*vader#assert#equal') + " @vimlint(EVL102, 1, l:cc_item) + let cc_item = getqflist()[found-1] + call vader#assert#equal([cc_item.bufnr, cc_item.lnum], [item.bufnr, item.lnum]) + endif + execute 'cc '.found + endif + elseif c > 0 + call neomake#log#error('No more next items.') + elseif c < 0 + call neomake#log#error('No more previous items.') + endif +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/log.vim b/bundle/neomake/autoload/neomake/log.vim new file mode 100644 index 000000000..2a3c25343 --- /dev/null +++ b/bundle/neomake/autoload/neomake/log.vim @@ -0,0 +1,179 @@ +let s:level_to_name = {0: 'error ', 1: 'warning', 2: 'verbose', 3: 'debug '} +let s:name_to_level = {'error': 0, 'warning': 1, 'verbose': 2, 'debug': 3} +let s:short_level_to_name = {0: 'E', 1: 'W', 2: 'V', 3: 'D'} +let s:is_testing = exists('g:neomake_test_messages') +let s:pid = getpid() +let s:indent = 0 +let s:indent_str = '' + +if !exists('s:last_msg_ts') + let s:last_msg_ts = neomake#compat#reltimefloat() +endif + +function! s:reltime_lastmsg() abort + let cur = neomake#compat#reltimefloat() + let diff = (cur - s:last_msg_ts) + let s:last_msg_ts = cur + + if diff < 0.01 + return ' ' + elseif diff < 10 + let format = '+%.2f' + elseif diff < 100 + let format = '+%.1f' + elseif diff < 100 + let format = ' +%.0f' + elseif diff < 1000 + let format = ' +%.0f' + else + let format = '+%.0f' + endif + return printf(format, diff) +endfunction + +function! s:log(level, msg, ...) abort + let context = a:0 ? a:1 : {} + let verbosity = neomake#utils#get_verbosity(context) + let logfile = get(g:, 'neomake_logfile', '') + + if !s:is_testing && verbosity < a:level && empty(logfile) + return + endif + + let msg = s:indent_str . a:msg + if a:0 + if has_key(a:1, 'options') + let context = copy(a:1.options) + let context.make_id = a:1.make_id + else + let context = copy(a:1) + endif + let msg = printf('[%s.%s:%s:%d] %s', + \ get(context, 'make_id', '-'), + \ get(context, 'id', '-'), + \ get(context, 'bufnr', get(context, 'file_mode', 0) ? '?' : '-'), + \ get(context, 'winnr', winnr()), + \ msg) + endif + + " Use Vader's log for messages during tests. + " @vimlint(EVL104, 1, l:timediff) + if s:is_testing && (verbosity >= a:level || get(g:, 'neomake_test_log_all_messages', 0)) + let timediff = s:reltime_lastmsg() + if timediff !=# ' ' + let test_msg = '['.s:short_level_to_name[a:level].' '.timediff.']: '.msg + else + let test_msg = '['.s:level_to_name[a:level].']: '.msg + endif + + if exists('*vader#log') + " Might not exist with rpcrequest-based nvim test, or throw errors + " if called too early. + call vader#log(test_msg) + endif + " Only keep context entries that are relevant for / used in the message. + let context = a:0 + \ ? extend(filter(copy(context), "index(['id', 'make_id', 'bufnr', 'winnr'], v:key) != -1"), {'winnr': winnr()}, 'keep') + \ : {} + call add(g:neomake_test_messages, [a:level, a:msg, context]) + if index(['.', '!', ')', ']'], a:msg[-1:-1]) == -1 + let g:neomake_test_errors += ['Log msg does not end with punctuation: "'.a:msg.'".'] + endif + elseif verbosity >= a:level + if verbosity > 2 + echom 'Neomake: '.msg + else + if a:level ==# 0 + echohl ErrorMsg + else + echohl WarningMsg + endif + " Use message without context for non-debug msgs. + echom 'Neomake: '.a:msg + echohl None + endif + endif + if !empty(logfile) + if !exists('s:logfile_writefile_opts') + " Use 'append' with writefile, but only if it is available. Otherwise, just + " overwrite the file. 'S' is used to disable fsync in Neovim + " (https://github.com/neovim/neovim/pull/6427). + if has('patch-7.4.503') + let s:logfile_writefile_opts = 'aS' + else + let s:logfile_writefile_opts = '' + echohl WarningMsg + echom 'Neomake: appending to the logfile is not supported in your Vim version.' + echohl NONE + endif + endif + + let time = strftime('%H:%M:%S') + if !exists('timediff') + let timediff = s:reltime_lastmsg() + endif + try + call writefile([printf('%s %s [%s %s] %s', + \ time, s:pid, s:short_level_to_name[a:level], timediff, msg)], + \ logfile, s:logfile_writefile_opts) + catch + unlet g:neomake_logfile + call neomake#log#error(printf('Error when trying to write to logfile %s: %s. Unsetting g:neomake_logfile.', logfile, v:exception)) + endtry + endif + " @vimlint(EVL104, 0, l:timediff) +endfunction + +function! neomake#log#indent(offset) abort + if a:offset < 0 && s:indent <= 0 + throw 'invalid offset (already 0)' + endif + let s:indent += a:offset + let s:indent_str = repeat(' ', s:indent*2) +endfunction + +function! neomake#log#error(...) abort + call call('s:log', [0] + a:000) +endfunction + +function! neomake#log#warning(...) abort + call call('s:log', [1] + a:000) +endfunction + +function! neomake#log#info(...) abort + call call('s:log', [2] + a:000) +endfunction + +function! neomake#log#debug(...) abort + call call('s:log', [3] + a:000) +endfunction + +function! neomake#log#debug_obj(msg, obj) abort + if s:is_testing || neomake#utils#get_verbosity() >= 3 || !empty(get(g:, 'neomake_logfile', '')) + call neomake#log#debug(a:msg.': '.neomake#utils#Stringify(a:obj).'.') + endif +endfunction + +function! neomake#log#exception(error, ...) abort + let log_context = a:0 ? a:1 : {'bufnr': bufnr('%')} + echom printf('Neomake error in: %s', v:throwpoint) + call neomake#log#error(a:error, log_context) + call neomake#log#debug(printf('(in %s)', v:throwpoint), log_context) +endfunction + +let s:warned = {} +function! neomake#log#warn_once(msg, key) abort + if !has_key(s:warned, a:key) + let s:warned[a:key] = 1 + echohl WarningMsg + echom 'Neomake: ' . a:msg + echohl None + let v:warningmsg = 'Neomake: '.a:msg + call neomake#log#debug('Neomake warning: '.a:msg) + endif +endfunction + +function! neomake#log#reset_warnings() abort + let s:warned = {} +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/cabal.vim b/bundle/neomake/autoload/neomake/makers/cabal.vim new file mode 100644 index 000000000..070b2a58b --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/cabal.vim @@ -0,0 +1,15 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#cabal#cabal() abort + let errorformat = join([ + \ '%A%f:%l:%c:', + \ '%A%f:%l:%c: %m', + \ '%+C %m', + \ '%-Z%[%^ ]', + \ ], ',') + return { + \ 'exe': 'cabal', + \ 'args': ['build'], + \ 'errorformat': errorformat + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/clippy.vim b/bundle/neomake/autoload/neomake/makers/clippy.vim new file mode 100644 index 000000000..6f2a8a3dd --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/clippy.vim @@ -0,0 +1,39 @@ +" vim: ts=4 sw=4 et + +" Yet to be determined +let s:rustup_has_nightly = get(g:, 'neomake_clippy_rustup_has_nightly', -1) + +function! neomake#makers#clippy#clippy() abort + " When rustup and a nightly toolchain is installed, that is used. + " Otherwise, the default cargo exectuable is used. If this is not part + " of a nightly rust, this will fail. + if s:rustup_has_nightly == -1 + if !executable('rustup') + let s:rustup_has_nightly = 0 + call system('rustc --version | grep -q "\-nightly"') + if v:shell_error + call neomake#log#warning('Clippy requires a nightly rust installation.') + endif + else + call system('rustup show | grep -q "^nightly-"') + let s:rustup_has_nightly = !v:shell_error + endif + endif + + let cargo_maker = neomake#makers#ft#rust#cargo() + let json_args = ['--message-format=json', '--quiet'] + + if s:rustup_has_nightly + return { + \ 'exe': 'rustup', + \ 'args': ['run', 'nightly', 'cargo', 'clippy'] + json_args, + \ 'process_output': cargo_maker.process_output, + \ } + else + return { + \ 'exe': 'cargo', + \ 'args': ['clippy'] + json_args, + \ 'process_output': cargo_maker.process_output, + \ } + endif +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/ada.vim b/bundle/neomake/autoload/neomake/makers/ft/ada.vim new file mode 100644 index 000000000..822da3c50 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/ada.vim @@ -0,0 +1,14 @@ +function! neomake#makers#ft#ada#EnabledMakers() abort + return ['gcc'] +endfunction + +function! neomake#makers#ft#ada#gcc() abort + return { + \ 'args': ['-c', '-x', 'ada', '-gnatc'], + \ 'errorformat': + \ '%-G%f:%s:,' . + \ '%f:%l:%c: %m,' . + \ '%f:%l: %m' + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/angular.vim b/bundle/neomake/autoload/neomake/makers/ft/angular.vim new file mode 100644 index 000000000..8c2f2d9f5 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/angular.vim @@ -0,0 +1,9 @@ +function! neomake#makers#ft#angular#SupersetOf() abort + return 'javascript' +endfunction + +function! neomake#makers#ft#angular#EnabledMakers() abort + return ['jshint', 'eslint', 'jscs'] +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/ansible.vim b/bundle/neomake/autoload/neomake/makers/ft/ansible.vim new file mode 100644 index 000000000..a1a001f8c --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/ansible.vim @@ -0,0 +1,17 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#ansible#EnabledMakers() abort + return ['ansiblelint', 'yamllint'] +endfunction + +function! neomake#makers#ft#ansible#yamllint() abort + return neomake#makers#ft#yaml#yamllint() +endfunction + +function! neomake#makers#ft#ansible#ansiblelint() abort + return { + \ 'exe': 'ansible-lint', + \ 'args': ['-p', '--nocolor'], + \ 'errorformat': '%f:%l: [%tANSIBLE%n] %m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/apiblueprint.vim b/bundle/neomake/autoload/neomake/makers/ft/apiblueprint.vim new file mode 100644 index 000000000..2e91b42ef --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/apiblueprint.vim @@ -0,0 +1,16 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#apiblueprint#EnabledMakers() abort + return executable('drafter') ? ['drafter'] : [] +endfunction + +function! neomake#makers#ft#apiblueprint#drafter() abort + " Drafter only operates on a single file at a time, and therefore doesn't + " bother to print out a file name with each error. We need to attach this + " so that the quickfix list can function properly. + return { + \ 'args': ['-l', '-u'], + \ 'errorformat': '%f: %t%[%^:]\\+: (%n) %m; line %l\, column %c%.%#', + \ 'mapexpr': 'neomake_bufname . ": " . v:val' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/applescript.vim b/bundle/neomake/autoload/neomake/makers/ft/applescript.vim new file mode 100644 index 000000000..71a00f173 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/applescript.vim @@ -0,0 +1,11 @@ +function! neomake#makers#ft#applescript#EnabledMakers() abort + return ['osacompile'] +endfunction + +function! neomake#makers#ft#applescript#osacompile() abort + return { + \ 'args': ['-o', g:neomake#compat#dev_null], + \ 'errorformat': '%f:%l: %trror: %m', + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/asciidoc.vim b/bundle/neomake/autoload/neomake/makers/ft/asciidoc.vim new file mode 100644 index 000000000..4d5375134 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/asciidoc.vim @@ -0,0 +1,28 @@ +function! neomake#makers#ft#asciidoc#SupersetOf() abort + return 'text' +endfunction + +function! neomake#makers#ft#asciidoc#EnabledMakers() abort + let makers = executable('asciidoctor') ? ['asciidoctor'] : ['asciidoc'] + return makers + neomake#makers#ft#text#EnabledMakers() +endfunction + +function! neomake#makers#ft#asciidoc#asciidoc() abort + return { + \ 'errorformat': + \ '%E%\w%\+: %tRROR: %f: line %l: %m,' . + \ '%E%\w%\+: %tRROR: %f: %m,' . + \ '%E%\w%\+: FAILED: %f: line %l: %m,' . + \ '%E%\w%\+: FAILED: %f: %m,' . + \ '%W%\w%\+: %tARNING: %f: line %l: %m,' . + \ '%W%\w%\+: %tARNING: %f: %m,' . + \ '%W%\w%\+: DEPRECATED: %f: line %l: %m,' . + \ '%W%\w%\+: DEPRECATED: %f: %m', + \ 'args': ['-o', g:neomake#compat#dev_null], + \ } +endfunction + +function! neomake#makers#ft#asciidoc#asciidoctor() abort + return neomake#makers#ft#asciidoc#asciidoc() +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/beancount.vim b/bundle/neomake/autoload/neomake/makers/ft/beancount.vim new file mode 100644 index 000000000..95eb31a81 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/beancount.vim @@ -0,0 +1,12 @@ +function! neomake#makers#ft#beancount#EnabledMakers() abort + return ['bean_check'] +endfunction + +function! neomake#makers#ft#beancount#bean_check() abort + return { + \ 'exe': 'bean-check', + \ 'errorformat': '%E%f:%l:%m', + \ 'postprocess': function('neomake#postprocess#compress_whitespace'), + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/bib.vim b/bundle/neomake/autoload/neomake/makers/ft/bib.vim new file mode 100644 index 000000000..e3a9602cf --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/bib.vim @@ -0,0 +1,16 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#bib#EnabledMakers() abort + return [] +endfunction + +function! neomake#makers#ft#bib#bibtex() abort + return { + \ 'exe': 'bibtex', + \ 'args': ['-terse', '%:r'], + \ 'append_file': 0, + \ 'uses_filename': 0, + \ 'errorformat': '%E%m---line %l of file %f', + \ 'cwd': '%:p:h' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/c.vim b/bundle/neomake/autoload/neomake/makers/ft/c.vim new file mode 100644 index 000000000..5eead6ba5 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/c.vim @@ -0,0 +1,108 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#c#EnabledMakers() abort + let makers = executable('clang') ? ['clang', 'clangtidy', 'clangcheck'] : ['gcc'] + call add(makers, 'checkpatch') + call add(makers, 'cppcheck') + return makers +endfunction + +let g:neomake#makers#ft#c#project_root_files = ['configure', 'CMakeLists.txt'] + +function! neomake#makers#ft#c#clang() abort + " as a single-file maker, include the current directory in the default + " search path + return { + \ 'args': ['-fsyntax-only', '-Wall', '-Wextra', '-I./'], + \ 'errorformat': + \ '%-G%f:%s:,' . + \ '%f:%l:%c: %trror: %m,' . + \ '%f:%l:%c: %tarning: %m,' . + \ '%I%f:%l:%c: note: %m,' . + \ '%f:%l:%c: %m,'. + \ '%f:%l: %trror: %m,'. + \ '%f:%l: %tarning: %m,'. + \ '%I%f:%l: note: %m,'. + \ '%f:%l: %m' + \ } +endfunction + +function! neomake#makers#ft#c#clangcheck() abort + return { + \ 'exe': 'clang-check', + \ 'errorformat': + \ '%-G%f:%s:,' . + \ '%f:%l:%c: %trror: %m,' . + \ '%f:%l:%c: %tarning: %m,' . + \ '%I%f:%l:%c: note: %m,' . + \ '%f:%l:%c: %m,'. + \ '%f:%l: %trror: %m,'. + \ '%f:%l: %tarning: %m,'. + \ '%I%f:%l: note: %m,'. + \ '%f:%l: %m', + \ } +endfunction + +function! neomake#makers#ft#c#gcc() abort + " as a single-file maker, include the current directory in the default + " search path + return { + \ 'args': ['-fsyntax-only', '-Wall', '-Wextra', '-I./'], + \ 'errorformat': + \ '%-G%f:%s:,' . + \ '%-G%f:%l: %#error: %#(Each undeclared identifier is reported only%.%#,' . + \ '%-G%f:%l: %#error: %#for each function it appears%.%#,' . + \ '%-GIn file included%.%#,' . + \ '%-G %#from %f:%l\,,' . + \ '%f:%l:%c: %trror: %m,' . + \ '%f:%l:%c: %tarning: %m,' . + \ '%I%f:%l:%c: note: %m,' . + \ '%f:%l:%c: %m,' . + \ '%f:%l: %trror: %m,' . + \ '%f:%l: %tarning: %m,'. + \ '%I%f:%l: note: %m,'. + \ '%f:%l: %m', + \ } +endfunction + +" The -p option followed by the path to the build directory should be set in +" the maker's arguments. That directory should contain the compile command +" database (compile_commands.json). +function! neomake#makers#ft#c#clangtidy() abort + return { + \ 'exe': 'clang-tidy', + \ 'errorformat': + \ '%E%f:%l:%c: fatal error: %m,' . + \ '%E%f:%l:%c: error: %m,' . + \ '%W%f:%l:%c: warning: %m,' . + \ '%-G%\m%\%%(LLVM ERROR:%\|No compilation database found%\)%\@!%.%#,' . + \ '%E%m', + \ 'short_name': 'ctdy', + \ } +endfunction + +function! neomake#makers#ft#c#checkpatch() abort + return { + \ 'exe': 'checkpatch.pl', + \ 'args': ['--no-summary', '--no-tree', '--terse', '--file'], + \ 'errorformat': + \ '%f:%l: %tARNING: %m,' . + \ '%f:%l: %tRROR: %m', + \ } +endfunction + +function! neomake#makers#ft#c#cppcheck() abort + " NOTE: '--language=c' should be the first args, it gets replaced in + " neomake#makers#ft#cpp#cppcheck. + return { + \ 'args': ['--language=c', '--quiet', '--enable=warning', + \ '--template={file}:{line}:{column}:{severity}:{message}'], + \ 'errorformat': + \ 'nofile:0:0:%trror:%m,' . + \ '%f:%l:%c:%trror:%m,' . + \ 'nofile:0:0:%tarning:%m,'. + \ '%f:%l:%c:%tarning:%m,'. + \ 'nofile:0:0:%tnformation:%m,'. + \ '%f:%l:%c:%tnformation:%m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/cf3.vim b/bundle/neomake/autoload/neomake/makers/ft/cf3.vim new file mode 100644 index 000000000..7826fc6f1 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/cf3.vim @@ -0,0 +1,14 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#cf3#EnabledMakers() abort + return ['cfpromises'] +endfunction + +function! neomake#makers#ft#cf3#cfpromises() abort + return { + \ 'exe': 'cf-promises', + \ 'args': ['-cf'], + \ 'errorformat': + \ '%E%f:%l:%c: error: %m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/chef.vim b/bundle/neomake/autoload/neomake/makers/ft/chef.vim new file mode 100644 index 000000000..805a0702e --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/chef.vim @@ -0,0 +1,23 @@ +function! neomake#makers#ft#chef#SupersetOf() abort + return 'ruby' +endfunction + +function! neomake#makers#ft#chef#EnabledMakers() abort + let ruby_makers = neomake#makers#ft#ruby#EnabledMakers() + return ruby_makers + ['foodcritic', 'cookstyle'] +endfunction + +function! neomake#makers#ft#chef#foodcritic() abort + return { + \ 'errorformat': '%WFC%n: %m: %f:%l', + \ } +endfunction + +function! neomake#makers#ft#chef#cookstyle() abort + return { + \ 'args': ['-f', 'emacs'], + \ 'errorformat': '%f:%l:%c: %t: %m', + \ 'postprocess': function('neomake#makers#ft#ruby#RubocopEntryProcess'), + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/coffee.vim b/bundle/neomake/autoload/neomake/makers/ft/coffee.vim new file mode 100644 index 000000000..67c6cc37f --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/coffee.vim @@ -0,0 +1,15 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#coffee#EnabledMakers() abort + return ['coffeelint'] +endfunction + +function! neomake#makers#ft#coffee#coffeelint() abort + return { + \ 'args': ['--reporter=csv'], + \ 'errorformat': '%f\,%l\,%\d%#\,%trror\,%m,' . + \ '%f\,%l\,%trror\,%m,' . + \ '%f\,%l\,%\d%#\,%tarn\,%m,' . + \ '%f\,%l\,%tarn\,%m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/cpp.vim b/bundle/neomake/autoload/neomake/makers/ft/cpp.vim new file mode 100644 index 000000000..0cfa8774a --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/cpp.vim @@ -0,0 +1,50 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#cpp#EnabledMakers() abort + let makers = executable('clang++') ? ['clang', 'clangtidy', 'clangcheck'] : ['gcc'] + call add(makers, 'cppcheck') + return makers +endfunction + +function! neomake#makers#ft#cpp#clang() abort + let maker = neomake#makers#ft#c#clang() + let maker.exe = 'clang++' + let maker.args += ['-std=c++1z'] + return maker +endfunction + +function! neomake#makers#ft#cpp#gcc() abort + let maker = neomake#makers#ft#c#gcc() + let maker.exe = 'g++' + let maker.args += ['-std=c++1z'] + return maker +endfunction + +function! neomake#makers#ft#cpp#clangtidy() abort + return neomake#makers#ft#c#clangtidy() +endfunction + +function! neomake#makers#ft#cpp#clangcheck() abort + return neomake#makers#ft#c#clangcheck() +endfunction + +function! neomake#makers#ft#cpp#cppcheck() abort + let maker = neomake#makers#ft#c#cppcheck() + let maker.args[0] = '--language=c++' + return maker +endfunction + +function! neomake#makers#ft#cpp#cpplint() abort + return { + \ 'exe': executable('cpplint') ? 'cpplint' : 'cpplint.py', + \ 'args': ['--verbose=3'], + \ 'errorformat': + \ '%A%f:%l: %m [%t],' . + \ '%-G%.%#', + \ 'postprocess': function('neomake#makers#ft#cpp#CpplintEntryProcess') + \ } +endfunction + +function! neomake#makers#ft#cpp#CpplintEntryProcess(entry) abort + let a:entry.type = str2nr(a:entry.type) < 5 ? 'W' : 'E' +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/crystal.vim b/bundle/neomake/autoload/neomake/makers/ft/crystal.vim new file mode 100644 index 000000000..b570c7463 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/crystal.vim @@ -0,0 +1,25 @@ +function! neomake#makers#ft#crystal#EnabledMakers() abort + return ['crystal', 'ameba'] +endfunction + +function! neomake#makers#ft#crystal#crystal() abort + " from vim-crystal + return { + \ 'args': ['run', '--no-color', '--no-codegen'], + \ 'errorformat': + \ '%ESyntax error in line %l: %m,'. + \ '%ESyntax error in %f:%l: %m,'. + \ '%EError in %f:%l: %m,'. + \ '%C%p^,'. + \ '%-C%.%#' + \ } +endfunction + +function! neomake#makers#ft#crystal#ameba() abort + " from vim-crystal + return { + \ 'args': ['--format', 'flycheck'], + \ 'errorformat': '%f:%l:%c: %t: %m' + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/cs.vim b/bundle/neomake/autoload/neomake/makers/ft/cs.vim new file mode 100644 index 000000000..6457cff9c --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/cs.vim @@ -0,0 +1,22 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#cs#EnabledMakers() abort + return ['mcs'] +endfunction + +function! neomake#makers#ft#cs#mcs() abort + return { + \ 'args': ['--parse', '--unsafe'], + \ 'errorformat': '%f(%l\,%c): %trror %m', + \ } +endfunction + +function! neomake#makers#ft#cs#msbuild() abort + return { + \ 'exe': 'msbuild', + \ 'args': ['-nologo', '-v:q', '-property:GenerateFullPaths=true', neomake#utils#FindGlobFile('*.sln')], + \ 'errorformat': '%E%f(%l\,%c): error CS%n: %m [%.%#],'. + \ '%W%f(%l\,%c): warning CS%n: %m [%.%#]', + \ 'append_file' : 0, + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/css.vim b/bundle/neomake/autoload/neomake/makers/ft/css.vim new file mode 100644 index 000000000..3afbccd85 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/css.vim @@ -0,0 +1,35 @@ +scriptencoding utf8 + +function! neomake#makers#ft#css#EnabledMakers() abort + return ['csslint', 'stylelint'] +endfunction + +function! neomake#makers#ft#css#csslint() abort + return { + \ 'args': ['--format=compact'], + \ 'errorformat': + \ '%-G,'. + \ '%-G%f: lint free!,'. + \ '%f: line %l\, col %c\, %trror - %m,'. + \ '%f: line %l\, col %c\, %tarning - %m,'. + \ '%f: line %l\, col %c\, %m,'. + \ '%f: %tarning - %m' + \ } +endfunction + +function! neomake#makers#ft#css#stylelint() abort + let maker = { + \ 'errorformat': + \ '%-P%f,'. + \ '%W%*\s%l:%c%*\s✖ %m,'. + \ '%-Q,'. + \ '%+EError: No configuration provided for %f,%-C %.%#' + \ } + + function! maker.postprocess(entry) abort + let a:entry.text = substitute(a:entry.text, '\v\s\s+(.{-})\s*$', ' [\1]', 'g') + endfunction + + return maker +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/cuda.vim b/bundle/neomake/autoload/neomake/makers/ft/cuda.vim new file mode 100644 index 000000000..0fbf6c981 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/cuda.vim @@ -0,0 +1,15 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#cuda#EnabledMakers() abort + return ['nvcc'] +endfunction + +function! neomake#makers#ft#cuda#nvcc() abort + return { + \ 'exe': 'nvcc', + \ 'errorformat': + \ '%f\(%l\): %trror: %m,'. + \ '%f\(%l\): %tarning: %m,'. + \ '%f\(%l\): %m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/d.vim b/bundle/neomake/autoload/neomake/makers/ft/d.vim new file mode 100644 index 000000000..5206a8d0e --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/d.vim @@ -0,0 +1,92 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#d#EnabledMakers() abort + " dmd, ldmd, and gdmd all share a common CLI. + " Ordered in efficiency of compiler + for m in ['dmd', 'ldmd', 'gdmd'] + if executable(m) + return [m] + endif + endfor + return [] +endfunction + +function! s:findDubRoot() abort + "Look upwards for a dub.json or dub.sdl to find the root + "I did it like this because it's the only cross platform way I know of + let tmp_file = findfile('dub.json', '.;') + if empty(tmp_file) + let tmp_file = findfile('dub.sdl', '.;') + endif + return tmp_file +endfunction + +function! s:UpdateDub() abort + "Add dub directories + let s:dubImports = [] + let tmp_file = s:findDubRoot() + if executable('dub') && !empty(tmp_file) + let tmp_dir = fnamemodify(tmp_file,':p:h') + let dubCmd = 'dub describe --data=import-paths --annotate ' + \ .'--skip-registry=all --vquiet --data-list --root=' + let output = system(dubCmd . tmp_dir) + if(v:shell_error == 0 && !empty(output)) + " Is \n portable? + let s:dubImports = split(output, '\n') + call map(s:dubImports, "'-I' . v:val") + endif + endif +endfunction + +"GDMD does not adhere to dmd's flags or output, but to GCC's. +"This is for LDMD and dmd only. +function! s:DmdStyleMaker(args) abort + "Updating dub paths each make might be slow? + call s:UpdateDub() + let args = ['-w', '-wi', '-c', '-o-', '-vcolumns'] + a:args + s:dubImports + return { + \ 'args': args, + \ 'errorformat': + \ '%f(%l\,%c): %trror: %m,' . + \ '%f(%l): %trror: %m,' . + \ '%f(%l\,%c): %tarning: %m,' . + \ '%f(%l): %tarning: %m,' . + \ '%f(%l\,%c): Deprecation: %m,' . + \ '%f(%l): Deprecation: %m,', + \ } +endfunction + +function! neomake#makers#ft#d#dmd() abort + let args = [] + if exists('g:neomake_d_dmd_args_conf') + call add(args, '-conf=' . expand(g:neomake_d_dmd_args_conf)) + endif + return s:DmdStyleMaker(args) +endfunction + +function! neomake#makers#ft#d#ldmd() abort + let args = [] + if exists('g:neomake_d_ldmd_args_conf') + call add(args, '-conf=' . expand(g:neomake_d_ldmd_args_conf)) + endif + return s:DmdStyleMaker(args) +endfunction + +function! neomake#makers#ft#d#gdmd() abort + let args = ['-c', '-o-', '-fsyntax-only', s:UpdateDub()] + return { + \ 'args': args, + \ 'errorformat': + \ '%-G%f:%s:,' . + \ '%-G%f:%l: %#error: %#(Each undeclared identifier is reported only%.%#,' . + \ '%-G%f:%l: %#error: %#for each function it appears%.%#,' . + \ '%-GIn file included%.%#,' . + \ '%-G %#from %f:%l\,,' . + \ '%f:%l:%c: %trror: %m,' . + \ '%f:%l:%c: %tarning: %m,' . + \ '%f:%l:%c: %m,' . + \ '%f:%l: %trror: %m,' . + \ '%f:%l: %tarning: %m,'. + \ '%f:%l: %m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/docbk.vim b/bundle/neomake/autoload/neomake/makers/ft/docbk.vim new file mode 100644 index 000000000..dceffac66 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/docbk.vim @@ -0,0 +1,8 @@ +function! neomake#makers#ft#docbk#EnabledMakers() abort + return ['xmllint'] +endfunction + +function! neomake#makers#ft#docbk#xmllint() abort + return neomake#makers#ft#xml#xmllint() +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/dockerfile.vim b/bundle/neomake/autoload/neomake/makers/ft/dockerfile.vim new file mode 100644 index 000000000..a6d767f80 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/dockerfile.vim @@ -0,0 +1,13 @@ +function! neomake#makers#ft#dockerfile#EnabledMakers() abort + return ['hadolint'] +endfunction + +function! neomake#makers#ft#dockerfile#hadolint() abort + return { + \ 'output_stream': 'stdout', + \ 'uses_stdin': 1, + \ 'args': ['--format', 'tty'], + \ 'errorformat': '%f:%l %m', + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/elixir.vim b/bundle/neomake/autoload/neomake/makers/ft/elixir.vim new file mode 100644 index 000000000..4de652ec2 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/elixir.vim @@ -0,0 +1,72 @@ +" vim: ts=4 sw=4 et + +" Credo error types. +" F -> Refactoring opportunities +" W -> Warnings +" C -> Convention violation +" D -> Software design suggestions +" R -> Readability suggestions +" Map structure {CredoError: NeomakeType, ...} +let s:neomake_elixir_credo_config_typemap = { + \ 'F': 'W', + \ 'C': 'W', + \ 'D': 'I', + \ 'R': 'I'} + +function! neomake#makers#ft#elixir#PostprocessEnforceMaxBufferLine(entry) abort + let buffer_lines = str2nr(line('$')) + if (buffer_lines < a:entry.lnum) + let a:entry.lnum = buffer_lines + endif +endfunction + +function! neomake#makers#ft#elixir#PostprocessCredo(entry) abort + let type = toupper(a:entry.type) + let type_map = extend(s:neomake_elixir_credo_config_typemap, + \ get(g:, 'neomake_elixir_credo_config_typemap', {})) + if has_key(type_map, type) + let a:entry.type = type_map[type] + endif +endfunction + +function! neomake#makers#ft#elixir#EnabledMakers() abort + return ['mix'] +endfunction + +function! neomake#makers#ft#elixir#elixir() abort + return { + \ 'errorformat': + \ '%E** %s %f:%l: %m,'. + \ '%W%f:%l: warning: %m' + \ } +endfunction + +function! neomake#makers#ft#elixir#credo() abort + return { + \ 'exe': 'mix', + \ 'args': ['credo', 'list', '--format=oneline'], + \ 'postprocess': function('neomake#makers#ft#elixir#PostprocessCredo'), + \ 'errorformat': + \'[%t] %. %f:%l:%c %m,' . + \'[%t] %. %f:%l %m' + \ } +endfunction + +function! neomake#makers#ft#elixir#mix() abort + return { + \ 'exe' : 'mix', + \ 'args': ['compile', '--warnings-as-errors'], + \ 'postprocess': function('neomake#makers#ft#elixir#PostprocessEnforceMaxBufferLine'), + \ 'errorformat': + \ '** %s %f:%l: %m,'. + \ '%Ewarning: %m,%C %f:%l,%Z' + \ } +endfunction + +function! neomake#makers#ft#elixir#dogma() abort + return { + \ 'exe': 'mix', + \ 'args': ['dogma', '--format=flycheck'], + \ 'errorformat': '%E%f:%l:%c: %.: %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/elm.vim b/bundle/neomake/autoload/neomake/makers/ft/elm.vim new file mode 100644 index 000000000..fe1d2f68f --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/elm.vim @@ -0,0 +1,53 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#elm#EnabledMakers() abort + return ['elmMake'] +endfunction + +function! neomake#makers#ft#elm#elmMake() abort + return { + \ 'exe': 'elm-make', + \ 'args': ['--report=json', '--output=' . g:neomake#compat#dev_null], + \ 'process_output': function('neomake#makers#ft#elm#ElmMakeProcessOutput') + \ } +endfunction + +function! neomake#makers#ft#elm#ElmMakeProcessOutput(context) abort + let errors = [] + " output will be a List, containing either: + " 1) A success message + " 2) A string holding a JSON array for both warnings and errors + + for line in a:context.output + if line[0] ==# '[' + let decoded = neomake#compat#json_decode(line) + for item in decoded + if get(item, 'type', '') ==# 'warning' + let code = 'W' + else + let code = 'E' + endif + + let compiler_error = item['tag'] + let message = item['overview'] + let filename = item['file'] + let region_start = item['region']['start'] + let region_end = item['region']['end'] + let row = region_start['line'] + let col = region_start['column'] + let length = region_end['column'] - region_start['column'] + + let error = { + \ 'text': compiler_error . ' : ' . message, + \ 'type': code, + \ 'lnum': row, + \ 'col': col, + \ 'length': length, + \ 'filename': filename, + \ } + call add(errors, error) + endfor + endif + endfor + return errors +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/erlang.vim b/bundle/neomake/autoload/neomake/makers/ft/erlang.vim new file mode 100644 index 000000000..a55409827 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/erlang.vim @@ -0,0 +1,72 @@ + +function! neomake#makers#ft#erlang#EnabledMakers() abort + return ['erlc'] +endfunction + +function! neomake#makers#ft#erlang#erlc() abort + let maker = { + \ 'errorformat': + \ '%W%f:%l: Warning: %m,' . + \ '%E%f:%l: %m' + \ } + function! maker.InitForJob(_jobinfo) abort + let self.args = neomake#makers#ft#erlang#GlobPaths() + endfunction + return maker +endfunction + +if !exists('g:neomake_erlang_erlc_target_dir') + let g:neomake_erlang_erlc_target_dir = tempname() +endif + +function! neomake#makers#ft#erlang#GlobPaths() abort + " Find project root directory. + let rebar_config = neomake#utils#FindGlobFile('rebar.config') + if !empty(rebar_config) + let root = fnamemodify(rebar_config, ':h') + else + " At least try with CWD + let root = getcwd() + endif + let root = fnamemodify(root, ':p') + let build_dir = root . '_build' + let ebins = [] + if isdirectory(build_dir) + " Pick the rebar3 profile to use + let default_profile = expand('%') =~# '_SUITE.erl$' ? 'test' : 'default' + let profile = get(b:, 'neomake_erlang_erlc_rebar3_profile', default_profile) + let ebins += neomake#compat#glob_list(build_dir . '/' . profile . '/lib/*/ebin') + let target_dir = build_dir . '/neomake' + else + let target_dir = get(b:, 'neomake_erlang_erlc_target_dir', + \ get(g:, 'neomake_erlang_erlc_target_dir')) + endif + " If /_build doesn't exist it might be a rebar2/erlang.mk project + if isdirectory(root . 'deps') + let ebins += neomake#compat#glob_list(root . 'deps/*/ebin') + endif + " Set g:neomake_erlang_erlc_extra_deps in a project-local .vimrc, e.g.: + " let g:neomake_erlang_erlc_extra_deps = ['deps.local'] + " Or just b:neomake_erlang_erlc_extra_deps in a specific buffer. + let extra_deps_dirs = get(b:, 'neomake_erlang_erlc_extra_deps', + \ get(g:, 'neomake_erlang_erlc_extra_deps')) + if !empty(extra_deps_dirs) + for extra_deps in extra_deps_dirs + if extra_deps[-1] !=# '/' + let extra_deps .= '/' + endif + let ebins += neomake#compat#glob_list(extra_deps . '*/ebin') + endfor + endif + let args = ['-pa', 'ebin', '-I', 'include', '-I', 'src'] + for ebin in ebins + let args += [ '-pa', ebin, + \ '-I', substitute(ebin, 'ebin$', 'include', '') ] + endfor + if !isdirectory(target_dir) + call mkdir(target_dir, 'p') + endif + let args += ['-o', target_dir] + return args +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/fish.vim b/bundle/neomake/autoload/neomake/makers/ft/fish.vim new file mode 100644 index 000000000..429afcc50 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/fish.vim @@ -0,0 +1,16 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#fish#EnabledMakers() abort + return ['fish'] +endfunction + +function! neomake#makers#ft#fish#fish() abort + return { + \ 'args': ['-n'], + \ 'errorformat': + \ '%C%f (line %l): %s,'. + \ '%-Gfish: %.%#,'. + \ '%Z%p^,'. + \ '%E%m' + \} +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/fortran.vim b/bundle/neomake/autoload/neomake/makers/ft/fortran.vim new file mode 100644 index 000000000..828bba9e3 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/fortran.vim @@ -0,0 +1,32 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#fortran#EnabledMakers() abort + return ['gfortran'] +endfunction + +" Using the errorformat from syntastic +function! neomake#makers#ft#fortran#ifort() abort + return { + \ 'args': ['-syntax-only', '-warn'], + \ 'errorformat': + \ '%E%f(%l): error #%n: %m,'. + \ '%W%f(%l): warning #%n: %m,'. + \ '%W%f(%l): remark #%n: %m,'. + \ '%-Z%p^,'. + \ '%-G%.%#', + \ } +endfunction + +" Using the errorformat from syntastic +function! neomake#makers#ft#fortran#gfortran() abort + return { + \ 'args': ['-fsyntax-only', '-Wall', '-Wextra'], + \ 'errorformat': + \ '%-C %#,'. + \ '%-C %#%.%#,'. + \ '%A%f:%l%[.:]%c:,'. + \ '%Z%\m%\%%(Fatal %\)%\?%trror: %m,'. + \ '%Z%tarning: %m,'. + \ '%-G%.%#', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/go.vim b/bundle/neomake/autoload/neomake/makers/ft/go.vim new file mode 100644 index 000000000..10c0b9b33 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/go.vim @@ -0,0 +1,85 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#go#EnabledMakers() abort + let makers = ['go'] + if executable('golangci-lint') + call add(makers, 'golangci_lint') + elseif executable('gometalinter') + call add(makers, 'gometalinter') + else + call extend(makers, ['golint', 'govet']) + endif + return makers +endfunction + +function! neomake#makers#ft#go#go() abort + return { + \ 'args': [ + \ 'test', '-c', + \ '-o', g:neomake#compat#dev_null, + \ ], + \ 'append_file': 0, + \ 'cwd': '%:h', + \ 'serialize': 1, + \ 'serialize_abort_on_error': 1, + \ 'errorformat': + \ '%W%f:%l: warning: %m,' . + \ '%E%f:%l:%c:%m,' . + \ '%E%f:%l:%m,' . + \ '%C%\s%\+%m,' . + \ '%-G%.%#\\\[no test files],' . + \ '%-G#%.%#', + \ 'postprocess': function('neomake#postprocess#compress_whitespace'), + \ 'version_arg': 'version', + \ } +endfunction + +function! neomake#makers#ft#go#golint() abort + " golint's issues are informational, as they're stylistic (not bugs) + return { + \ 'errorformat': + \ '%I%f:%l:%c: %m,' . + \ '%-G%.%#' + \ } +endfunction + +function! neomake#makers#ft#go#govet() abort + return { + \ 'exe': 'go', + \ 'args': ['vet'], + \ 'append_file': 0, + \ 'cwd': '%:h', + \ 'errorformat': + \ '%Evet: %.%\+: %f:%l:%c: %m,' . + \ '%W%f:%l: %m,' . + \ '%-G%.%#' + \ } +endfunction + +function! neomake#makers#ft#go#gometalinter() abort + " Only run a subset of gometalinter for speed, users can override with: + " let g:neomake_go_gometalinter_args = ['--disable-all', '--enable=X', ...] + " + " All linters are only warnings, the go compiler will report errors + return { + \ 'args': ['--disable-all', '--enable=errcheck', '--enable=megacheck', '--vendor'], + \ 'append_file': 0, + \ 'cwd': '%:h', + \ 'errorformat': + \ '%f:%l:%c:%t%*[^:]: %m,' . + \ '%f:%l::%t%*[^:]: %m' + \ } +endfunction + +function! neomake#makers#ft#go#golangci_lint() abort + return { + \ 'exe': 'golangci-lint', + \ 'args': ['run', '--out-format=line-number', '--print-issued-lines=false'], + \ 'output_stream': 'stdout', + \ 'append_file': 0, + \ 'cwd': '%:h', + \ 'errorformat': + \ '%f:%l:%c: %m,' . + \ '%f:%l: %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/haml.vim b/bundle/neomake/autoload/neomake/makers/ft/haml.vim new file mode 100644 index 000000000..df79b38b0 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/haml.vim @@ -0,0 +1,13 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#haml#EnabledMakers() abort + return ['hamllint'] +endfunction + +function! neomake#makers#ft#haml#hamllint() abort + return { + \ 'exe': 'haml-lint', + \ 'args': ['--no-color'], + \ 'errorformat': '%f:%l [%t] %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/haskell.vim b/bundle/neomake/autoload/neomake/makers/ft/haskell.vim new file mode 100644 index 000000000..64a522730 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/haskell.vim @@ -0,0 +1,169 @@ +unlet! s:makers +unlet! s:uses_cabal + +function! neomake#makers#ft#haskell#EnabledMakers() abort + if !exists('s:makers') + " cache whether each maker is available, to avoid lots of (UI blocking) + " system calls + " TODO: figure out how to do all this configuration async instead of + " caching it--that would allow the user to change directories from + " within vim and recalculate maker availability without restarting vim + let commands = ['ghc-mod', 'hdevtools', 'hlint', 'liquid'] + let s:makers = [] + let s:jobs = [] + for command in commands + " stack may be able to find a maker binary that's not on the normal + " path so check for that first + if executable('stack') + " run the maker command using stack to see whether stack can + " find it use the help flag to run the maker command without + " doing anything + let stack_command = [ + \ 'stack' + \ , 'exec' + \ , '--' + \ , command + \ , '--help' + \ ] + if has('nvim') + let job_id = jobstart( + \ stack_command, + \ { 'command': command + \ , 'on_exit': function('s:CheckStackMakerAsync') + \ }) + if job_id > 0 + call add(s:jobs, job_id) + endif + else + call extend(stack_command, ['> /dev/null 2>&1;', 'echo $?']) + if system(join(stack_command, ' ')) == 0 + call add(s:makers, substitute(command, '-', '', 'g')) + endif + endif + elseif executable(command) " no stack bin so check for maker bin + call add(s:makers, substitute(command, '-', '', 'g')) + endif + endfor + if has('nvim') + call jobwait(s:jobs) + endif + endif + return s:makers +endfunction + +function! neomake#makers#ft#haskell#hdevtools() abort + let params = { + \ 'exe': 'hdevtools', + \ 'args': ['check', '-g-Wall'], + \ 'mapexpr': s:CleanUpSpaceAndBackticks(), + \ 'errorformat': + \ '%-Z %#,'. + \ '%W%f:%l:%v: Warning: %m,'. + \ '%W%f:%l:%v: Warning:,'. + \ '%E%f:%l:%v: %m,'. + \ '%E%>%f:%l:%v:,'. + \ '%+C %#%m,'. + \ '%W%>%f:%l:%v:,'. + \ '%+C %#%tarning: %m,' + \ } + " hdevtools needs the GHC-PACKAGE-PATH environment variable to exist + " when running on a project WITHOUT a cabal file, but it needs the + " GHC-PACKAGE-PATH to NOT exist when running on a with a project WITH + " a cabal file + if !exists('s:uses_cabal') + let s:uses_cabal = 0 + if executable('stack') + let output = neomake#compat#systemlist(['stack', '--verbosity', 'silent', 'path', '--project-root']) + if !empty(output) + let rootdir = output[0] + if !empty(glob(rootdir . '/*.cabal')) + let s:uses_cabal = 1 + endif + endif + endif + endif + if s:uses_cabal + let params['stackexecargs'] = ['--no-ghc-package-path'] + endif + return s:TryStack(params) +endfunction + +function! neomake#makers#ft#haskell#ghcmod() abort + " This filters out newlines, which is what neovim gives us instead of the + " null bytes that ghc-mod sometimes spits out. + let mapexpr = 'substitute(v:val, "\n", "", "g")' + return s:TryStack({ + \ 'exe': 'ghc-mod', + \ 'args': ['check'], + \ 'mapexpr': mapexpr, + \ 'errorformat': + \ '%-G%\s%#,' . + \ '%f:%l:%c:%trror: %m,' . + \ '%f:%l:%c:%tarning: %m,'. + \ '%f:%l:%c: %trror: %m,' . + \ '%f:%l:%c: %tarning: %m,' . + \ '%E%f:%l:%c:%m,' . + \ '%E%f:%l:%c:,' . + \ '%Z%m' + \ }) +endfunction + +function! neomake#makers#ft#haskell#HlintEntryProcess(entry) abort + " Postprocess hlint output to make it more readable as a single line + let a:entry.text = substitute(a:entry.text, '\v(Found:)\s*\n', ' | \1', 'g') + let a:entry.text = substitute(a:entry.text, '\v(Why not:)\s*\n', ' | \1', 'g') + let a:entry.text = substitute(a:entry.text, '^No hints$', '', 'g') + call neomake#postprocess#compress_whitespace(a:entry) +endfunction + +function! neomake#makers#ft#haskell#hlint() abort + return s:TryStack({ + \ 'exe': 'hlint', + \ 'postprocess': function('neomake#makers#ft#haskell#HlintEntryProcess'), + \ 'args': [], + \ 'errorformat': + \ '%E%f:%l:%v: Error: %m,' . + \ '%W%f:%l:%v: Warning: %m,' . + \ '%I%f:%l:%v: Suggestion: %m,' . + \ '%C%m' + \ }) +endfunction + +function! neomake#makers#ft#haskell#liquid() abort + return s:TryStack({ + \ 'exe': 'liquid', + \ 'args': [], + \ 'mapexpr': s:CleanUpSpaceAndBackticks(), + \ 'errorformat': + \ '%E %f:%l:%c-%.%#Error: %m,' . + \ '%C%.%#|%.%#,' . + \ '%C %#^%#,' . + \ '%C%m,' + \ }) +endfunction + +function! s:CheckStackMakerAsync(_job_id, data, _event) dict abort + if a:data == 0 + call add(s:makers, substitute(self.command, '-', '', 'g')) + endif +endfunction + +function! s:TryStack(maker) abort + if executable('stack') + if !has_key(a:maker, 'stackexecargs') + let a:maker['stackexecargs'] = [] + endif + let a:maker['args'] = + \ ['--verbosity', 'silent', 'exec'] + \ + a:maker['stackexecargs'] + \ + ['--', a:maker['exe']] + \ + a:maker['args'] + let a:maker['exe'] = 'stack' + endif + return a:maker +endfunction + +function! s:CleanUpSpaceAndBackticks() abort + return 'substitute(substitute(v:val, " \\{2,\\}", " ", "g"), "`", "''", "g")' +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/haxe.vim b/bundle/neomake/autoload/neomake/makers/ft/haxe.vim new file mode 100644 index 000000000..9fd07ec4b --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/haxe.vim @@ -0,0 +1,11 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#haxe#EnabledMakers() abort + return ['haxe'] +endfunction + +function! neomake#makers#ft#haxe#haxe() abort + return { + \ 'errorformat': '%E%f:%l: characters %c-%n : %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/help.vim b/bundle/neomake/autoload/neomake/makers/ft/help.vim new file mode 100644 index 000000000..c573cef34 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/help.vim @@ -0,0 +1,40 @@ +let s:makers = ['writegood'] + +let s:slash = neomake#utils#Slash() +let s:vimhelplint_exe = '' +if executable('vimhelplint') + let s:vimhelplint_exe = 'vimhelplint' +else + let s:neomake_root = expand(':p:h:h:h:h:h', 1) + if !empty(glob(join([s:neomake_root, 'build', 'vimhelplint'], s:slash))) + let s:vimhelplint_exe = join([s:neomake_root, 'contrib', 'vimhelplint'], s:slash) + endif +endif +if !empty(s:vimhelplint_exe) + let s:makers += ['vimhelplint'] +endif + +function! neomake#makers#ft#help#EnabledMakers() abort + return s:makers +endfunction + +function! neomake#makers#ft#help#vimhelplint() abort + " NOTE: does not support/uses arg from wrapper script (i.e. no support for + " tempfiles). It will use the arg only to expand/glob `*.txt` + " (which does not include the hidden tempfile). + return { + \ 'exe': s:vimhelplint_exe, + \ 'errorformat': '%f:%l:%c:%trror:%n:%m,%f:%l:%c:%tarning:%n:%m', + \ 'postprocess': function('neomake#postprocess#generic_length'), + \ 'output_stream': 'stdout', + \ } +endfunction + +function! neomake#makers#ft#help#proselint() abort + return neomake#makers#ft#text#proselint() +endfunction + +function! neomake#makers#ft#help#writegood() abort + return neomake#makers#ft#text#writegood() +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/html.vim b/bundle/neomake/autoload/neomake/makers/ft/html.vim new file mode 100644 index 000000000..610017514 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/html.vim @@ -0,0 +1,20 @@ +function! neomake#makers#ft#html#tidy() abort + " NOTE: could also have info items, but those are skipped with -e/-q, e.g. + " 'line 7 column 1 - Info: value for attribute "id" missing quote marks'. + return { + \ 'args': ['-e', '-q', '--gnu-emacs', 'true'], + \ 'errorformat': '%W%f:%l:%c: Warning: %m', + \ } +endfunction + +function! neomake#makers#ft#html#htmlhint() abort + return { + \ 'args': ['--format', 'unix', '--nocolor'], + \ 'errorformat': '%f:%l:%c: %m,%-G,%-G%*\d problems', + \ } +endfunction + +function! neomake#makers#ft#html#EnabledMakers() abort + return ['tidy', 'htmlhint'] +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/idris.vim b/bundle/neomake/autoload/neomake/makers/ft/idris.vim new file mode 100644 index 000000000..5d95edbbb --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/idris.vim @@ -0,0 +1,25 @@ +function! neomake#makers#ft#idris#EnabledMakers() abort + return ['idris'] +endfunction + +function! neomake#makers#ft#idris#Postprocess(entry) abort + call neomake#postprocess#compress_whitespace(a:entry) + " Extract length from the beginning of the entry ('-4:When checking left hand side of xor:'). + if a:entry.text =~# '\v^\d+:' + let end = 0 + a:entry.text " cast to int + let a:entry.length = end - a:entry.col + let a:entry.text = substitute(a:entry.text, '\v^([^:]+:){2} ', '', '') + endif +endfunction + +function! neomake#makers#ft#idris#idris() abort + return { + \ 'exe': 'idris', + \ 'args': ['--check', '--warn', '--total', '--warnpartial', '--warnreach'], + \ 'errorformat': + \ '%E%f:%l:%c:%.%#,%-C %#%m,%-C%.%#,'. + \ '%E%f:%l:%c-%m,%-C %#%m,%-C%.%#', + \ 'postprocess': function('neomake#makers#ft#idris#Postprocess'), + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/jade.vim b/bundle/neomake/autoload/neomake/makers/ft/jade.vim new file mode 100644 index 000000000..c74795071 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/jade.vim @@ -0,0 +1,13 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#jade#EnabledMakers() abort + return ['jadelint'] +endfunction + +function! neomake#makers#ft#jade#jadelint() abort + return { + \ 'exe': 'jade-lint', + \ 'args': ['--reporter', 'inline'], + \ 'errorformat': '%f:%l:%c %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/jasmine.vim b/bundle/neomake/autoload/neomake/makers/ft/jasmine.vim new file mode 100644 index 000000000..56e0a4f6f --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/jasmine.vim @@ -0,0 +1,9 @@ +function! neomake#makers#ft#jasmine#SupersetOf() abort + return 'javascript' +endfunction + +function! neomake#makers#ft#jasmine#EnabledMakers() abort + return ['jshint', 'eslint', 'jscs'] +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/java.vim b/bundle/neomake/autoload/neomake/makers/ft/java.vim new file mode 100644 index 000000000..1c09bda89 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/java.vim @@ -0,0 +1,396 @@ +"============================================================================ +"File: java.vim +"Description: Syntax checking plugin for neomake +"Maintainer: Wang Shidong +"License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +"============================================================================ + +let s:save_cpo = &cpoptions +set cpoptions&vim + +if exists('g:loaded_neomake_java_javac_maker') + finish +endif +let g:loaded_neomake_java_javac_maker = 1 + +let g:neomake_java_javac_maven_pom_tags = ['build', 'properties'] +let g:neomake_java_javac_maven_pom_properties = {} +let s:is_windows = has('win32') || has('win64') || has('win16') || has('dos32') || has('dos16') +if s:is_windows + let s:fsep = ';' + let s:psep = '\' +else + let s:fsep = ':' + let s:psep = '/' +endif +let g:neomake_java_checker_home = fnamemodify(expand(''), ':p:h:gs?\\?/?') + +" custom options +let g:neomake_java_javac_executable = + \ get(g:, 'neomake_java_javac_executable', 'javac') + +let g:neomake_java_maven_executable = + \ get(g:, 'neomake_java_maven_executable', 'mvn') + +let g:neomake_java_gradle_executable = + \ get(g:, 'neomake_java_gradle_executable', s:is_windows? '.\gradlew.bat' : './gradlew') + +let g:neomake_java_ant_executable = + \ get(g:, 'neomake_java_ant_executable', 'ant') + +let g:neomake_java_checkstyle_executable = + \ get(g:, 'neomake_java_checkstyle_executable', 'checkstyle') + +let g:neomake_java_javac_options = + \ get(g:, 'neomake_java_javac_options', ['-Xlint']) + +let g:neomake_java_maven_options = + \ get(g:, 'neomake_java_maven_options', '') + +let g:neomake_java_javac_classpath = + \ get(g:, 'neomake_java_javac_classpath', '') + +let g:neomake_java_javac_outputdir = + \ get(g:, 'neomake_java_javac_outputdir', '') + +let g:neomake_java_checkstyle_xml = + \ get(g:, 'neomake_java_checkstyle_xml', '/usr/share/checkstyle/google_checks.xml') + +let g:neomake_java_javac_delete_output = + \ get(g:, 'neomake_java_javac_delete_output', 1) + +let g:neomake_java_javac_autoload_maven_classpath = + \ get(g:, 'neomake_java_javac_autoload_maven_classpath', 1) + +let g:neomake_java_javac_autoload_gradle_classpath = + \ get(g:, 'neomake_java_javac_autoload_gradle_classpath', 1) + +let g:neomake_java_javac_autoload_ant_classpath = + \ get(g:, 'neomake_java_javac_autoload_ant_classpath', 1) + +let g:neomake_java_javac_autoload_eclipse_classpath = + \ get(g:, 'neomake_java_javac_autoload_eclipse_classpath', 1) + +let g:neomake_java_javac_maven_pom_ftime = + \ get(g:, 'neomake_java_javac_maven_pom_ftime', {}) + +let g:neomake_java_javac_maven_pom_classpath = + \ get(g:, 'neomake_java_javac_maven_pom_classpath', {}) + +let g:neomake_java_javac_gradle_ftime = + \ get(g:, 'neomake_java_javac_gradle_ftime', {}) + +let g:neomake_java_javac_gradle_classpath = + \ get(g:, 'neomake_java_javac_gradle_classpath', {}) + +let g:neomake_java_javac_ant_ftime = + \ get(g:, 'neomake_java_javac_ant_ftime', {}) + +let g:neomake_java_javac_ant_classpath = + \ get(g:, 'neomake_java_javac_ant_classpath', {}) + + +let s:has_maven = executable(expand(g:neomake_java_maven_executable, 1)) +let s:has_gradle = executable(expand(g:neomake_java_gradle_executable, 1)) +let s:has_ant = executable(expand(g:neomake_java_ant_executable, 1)) + +function! s:tmpdir() abort + let tempdir = tempname() + call mkdir(tempdir, 'p', 0700) + return tempdir +endfunction + +function! s:ClassSep() abort + return (s:is_windows || has('win32unix')) ? ';' : ':' +endfunction + +function! s:shescape(string) abort + return neomake#utils#shellescape(a:string) +endfunction + +function! s:AddToClasspath(classpath, path) abort + if a:path ==# '' + return a:classpath + endif + return (a:classpath !=# '') ? a:classpath . s:ClassSep() . a:path : a:path +endfunction + +" @vimlint(EVL103, 1, a:classpathFile) +function! s:ReadClassPathFile(classpathFile) abort + let cp = '' + let file = g:neomake_java_checker_home. s:psep. 'java'. s:psep. 'classpath.py' + if has('python3') + execute 'py3file' file + py3 import vim + py3 vim.command("let cp = '%s'" % os.pathsep.join(ReadClasspathFile(vim.eval('a:classpathFile'))).replace('\\', '/')) + elseif has('python') + execute 'pyfile' file + py import vim + py vim.command("let cp = '%s'" % os.pathsep.join(ReadClasspathFile(vim.eval('a:classpathFile'))).replace('\\', '/')) + endif + return cp +endfunction +" @vimlint(EVL103, 0, a:classpathFile) + +function! neomake#makers#ft#java#EnabledMakers() abort + let makers = [] + if executable(expand(g:neomake_java_javac_executable, 1)) + call add(makers, g:neomake_java_javac_executable) + endif + if executable(expand(g:neomake_java_checkstyle_executable, 1)) + call add(makers, g:neomake_java_checkstyle_executable) + endif + return makers +endfunction + +function! neomake#makers#ft#java#javac() abort + let javac_opts = extend([], g:neomake_java_javac_options) + + let output_dir = '' + if g:neomake_java_javac_delete_output + let output_dir = s:tmpdir() + let javac_opts = extend(javac_opts, ['-d', s:shescape(output_dir)]) + endif + + let javac_classpath = get(g:, 'neomake_java_javac_classpath', '') + + if s:has_maven && g:neomake_java_javac_autoload_maven_classpath && empty(javac_classpath) + if !g:neomake_java_javac_delete_output + let javac_opts = extend(javac_opts, ['-d', s:shescape(s:MavenOutputDirectory())]) + endif + let javac_classpath = s:AddToClasspath(javac_classpath, s:GetMavenClasspath()) + endif + + if s:has_gradle && g:neomake_java_javac_autoload_gradle_classpath && empty(javac_classpath) + if !g:neomake_java_javac_delete_output + let javac_opts = extend(javac_opts, ['-d', s:shescape(s:GradleOutputDirectory())]) + endif + let javac_classpath = s:AddToClasspath(javac_classpath, s:GetGradleClasspath()) + endif + + if s:has_ant && g:neomake_java_javac_autoload_ant_classpath && empty(javac_classpath) + let javac_classpath = s:AddToClasspath(javac_classpath, s:GetAntClasspath()) + endif + + if (has('python') || has('python3')) && empty(javac_classpath) + let classpathFile = fnamemodify(findfile('.classpath', escape(expand('.'), '*[]?{}, ') . ';'), ':p') + if !empty(classpathFile) && filereadable(classpathFile) + let javac_classpath = s:ReadClassPathFile(classpathFile) + endif + endif + + if javac_classpath !=# '' + let javac_opts = extend(javac_opts, ['-cp', javac_classpath]) + endif + + return { + \ 'args': javac_opts, + \ 'exe': g:neomake_java_javac_executable, + \ 'errorformat': + \ '%E%f:%l: error: %m,'. + \ '%W%f:%l: warning: %m,'. + \ '%E%f:%l: %m,'. + \ '%Z%p^,'. + \ '%-G%.%#', + \ 'version_arg': '-version' + \ } +endfunction + +function! neomake#makers#ft#java#checkstyle() abort + return { + \ 'args': ['-c', g:neomake_java_checkstyle_xml], + \ 'exe': g:neomake_java_checkstyle_executable, + \ 'errorformat': + \ '%-GStarting audit...,'. + \ '%-GAudit done.,'. + \ '%-GPicked up _JAVA_OPTIONS:%.%#,'. + \ '[%t%*[^]]] %f:%l:%c: %m [%s],'. + \ '[%t%*[^]]] %f:%l: %m [%s]', + \ 'version_arg': '-v' + \ } +endfunction + +function! s:findFileInParent(what, where) abort " {{{2 + let old_suffixesadd = &suffixesadd + let &suffixesadd = '' + let file = findfile(a:what, escape(a:where, ' ') . ';') + let &suffixesadd = old_suffixesadd + return file +endfunction " }}}2 + +function! s:GetMavenProperties() abort " {{{2 + let mvn_properties = {} + let pom = s:findFileInParent('pom.xml', expand('%:p:h', 1)) + if s:has_maven && filereadable(pom) + if !has_key(g:neomake_java_javac_maven_pom_properties, pom) + let mvn_cmd = s:shescape(expand(g:neomake_java_maven_executable, 1)) . + \ ' -f ' . s:shescape(pom) . + \ ' ' . g:neomake_java_maven_options + let mvn_is_managed_tag = 1 + let mvn_settings_output = split(system(mvn_cmd . ' help:effective-pom'), "\n") + let current_path = 'project' + for line in mvn_settings_output + let matches = matchlist(line, '\m^\s*<\([a-zA-Z0-9\-\.]\+\)>\s*$') + if mvn_is_managed_tag && !empty(matches) + let mvn_is_managed_tag = index(g:neomake_java_javac_maven_pom_tags, matches[1]) >= 0 + let current_path .= '.' . matches[1] + else + let matches = matchlist(line, '\m^\s*\s*$') + if !empty(matches) + let mvn_is_managed_tag = index(g:neomake_java_javac_maven_pom_tags, matches[1]) < 0 + let current_path = substitute(current_path, '\m\.' . matches[1] . '$', '', '') + else + let matches = matchlist(line, '\m^\s*<\([a-zA-Z0-9\-\.]\+\)>\(.\+\)\s*$') + if mvn_is_managed_tag && !empty(matches) + let mvn_properties[current_path . '.' . matches[1]] = matches[2] + endif + endif + endif + endfor + let g:neomake_java_javac_maven_pom_properties[pom] = mvn_properties + endif + return g:neomake_java_javac_maven_pom_properties[pom] + endif + return mvn_properties +endfunction " }}}2 + +function! s:GetMavenClasspath() abort " {{{2 + let pom = s:findFileInParent('pom.xml', expand('%:p:h', 1)) + if s:has_maven && filereadable(pom) + if !has_key(g:neomake_java_javac_maven_pom_ftime, pom) || g:neomake_java_javac_maven_pom_ftime[pom] != getftime(pom) + let mvn_cmd = s:shescape(expand(g:neomake_java_maven_executable, 1)) . + \ ' -f ' . s:shescape(pom) . + \ ' ' . g:neomake_java_maven_options + let mvn_classpath_output = split(system(mvn_cmd . ' dependency:build-classpath -DincludeScope=test'), "\n") + let mvn_classpath = '' + let class_path_next = 0 + + for line in mvn_classpath_output + if class_path_next == 1 + let mvn_classpath = substitute(line, "\r", '', 'g') + break + endif + if stridx(line, 'Dependencies classpath:') >= 0 + let class_path_next = 1 + endif + endfor + + let mvn_properties = s:GetMavenProperties() + + let output_dir = get(mvn_properties, 'project.build.outputDirectory', join(['target', 'classes'], s:psep)) + let mvn_classpath = s:AddToClasspath(mvn_classpath, output_dir) + + let test_output_dir = get(mvn_properties, 'project.build.testOutputDirectory', join(['target', 'test-classes'], s:psep)) + let mvn_classpath = s:AddToClasspath(mvn_classpath, test_output_dir) + + let g:neomake_java_javac_maven_pom_ftime[pom] = getftime(pom) + let g:neomake_java_javac_maven_pom_classpath[pom] = mvn_classpath + endif + return g:neomake_java_javac_maven_pom_classpath[pom] + endif + return '' +endfunction " }}}2 + +function! s:MavenOutputDirectory() abort " {{{2 + let pom = s:findFileInParent('pom.xml', expand('%:p:h', 1)) + if s:has_maven && filereadable(pom) + let mvn_properties = s:GetMavenProperties() + let output_dir = get(mvn_properties, 'project.properties.build.dir', getcwd()) + + let src_main_dir = get(mvn_properties, 'project.build.sourceDirectory', join(['src', 'main', 'java'], s:psep)) + let src_test_dir = get(mvn_properties, 'project.build.testsourceDirectory', join(['src', 'test', 'java'], s:psep)) + if stridx(expand('%:p:h', 1), src_main_dir) >= 0 + let output_dir = get(mvn_properties, 'project.build.outputDirectory', join ([output_dir, 'target', 'classes'], s:psep)) + endif + if stridx(expand('%:p:h', 1), src_test_dir) >= 0 + let output_dir = get(mvn_properties, 'project.build.testOutputDirectory', join([output_dir, 'target', 'test-classes'], s:psep)) + endif + + if has('win32unix') + let output_dir = substitute(system('cygpath -m ' . s:shescape(output_dir)), "\n", '', 'g') + endif + return output_dir + endif + return '.' +endfunction " }}}2 + +function! s:GradleOutputDirectory() abort + let gradle_build = s:findFileInParent('build.gradle', expand('%:p:h', 1)) + let items = split(gradle_build, s:psep) + if len(items)==1 + return join(['build', 'intermediates', 'classes', 'debug'], s:psep) + endif + let outputdir = '' + for i in items + if i !=# 'build.gradle' + let outputdir .= i . s:psep + endif + endfor + return outputdir . join(['build', 'intermediates', 'classes', 'debug'], s:psep) +endf + +function! s:GetGradleClasspath() abort + let gradle = s:findFileInParent('build.gradle', expand('%:p:h', 1)) + if s:has_gradle && filereadable(gradle) + if !has_key(g:neomake_java_javac_gradle_ftime, gradle) || g:neomake_java_javac_gradle_ftime[gradle] != getftime(gradle) + try + let f = tempname() + if s:is_windows + let gradle_cmd = '.\gradlew.bat' + else + let gradle_cmd = './gradlew' + endif + call writefile(["allprojects{apply from: '" . g:neomake_java_checker_home . s:psep. 'java'. s:psep. "classpath.gradle'}"], f) + let ret = system(gradle_cmd . ' -q -I ' . shellescape(f) . ' classpath' ) + if v:shell_error == 0 + let cp = filter(split(ret, "\n"), "v:val =~# '^CLASSPATH:'")[0][10:] + if filereadable(getcwd() . s:psep . 'build.gradle') + let out_putdir = neomake#compat#globpath_list(getcwd(), join( + \ ['**', 'build', 'intermediates', 'classes', 'debug'], + \ s:psep), 0) + for classes in out_putdir + let cp .= s:ClassSep() . classes + endfor + endif + else + let cp = '' + endif + catch + finally + call delete(f) + endtry + let g:neomake_java_javac_gradle_ftime[gradle] = getftime(gradle) + let g:neomake_java_javac_gradle_classpath[gradle] = cp + endif + return g:neomake_java_javac_gradle_classpath[gradle] + endif + return '' +endf + +function! s:GetAntClasspath() abort + let ant = s:findFileInParent('build.xml', expand('%:p:h', 1)) + if s:has_ant && filereadable(ant) + if !has_key(g:neomake_java_javac_ant_ftime, ant) || g:neomake_java_javac_ant_ftime[ant] != getftime(ant) + try + let ant_cmd = 'ant classpath -f build.xml -S -q' + let cp = system(ant_cmd) + if v:shell_error != 0 + let cp = '' + endif + catch + endtry + let g:neomake_java_javac_ant_ftime[ant] = getftime(ant) + let g:neomake_java_javac_ant_classpath[ant] = cp + endif + return g:neomake_java_javac_ant_classpath[ant] + endif + return '' +endf + +let &cpoptions = s:save_cpo +unlet s:save_cpo +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/java/classpath.gradle b/bundle/neomake/autoload/neomake/makers/ft/java/classpath.gradle new file mode 100644 index 000000000..f548c0d0e --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/java/classpath.gradle @@ -0,0 +1,46 @@ +task classpath << { + + String finalFileContents = "" + HashSet classpathFiles = new HashSet() + for (proj in allprojects) { + + def exploded = proj.getBuildDir().absolutePath + File.separator + "intermediates" + File.separator + "exploded-aar" + def listFiles = new File(exploded) + if (listFiles.exists()) { + listFiles.eachFileRecurse(){ file -> + if (file.name.endsWith(".jar")){ + classpathFiles += file + } + } + } + + def rjava = proj.getBuildDir().absolutePath + File.separator + "intermediates" + File.separator + "classes" + File.separator + "debug" + def rFiles = new File(rjava) + if (rFiles.exists()) { + classpathFiles += rFiles + } + + for (conf in proj.configurations) { + for (dependency in conf) { + if (dependency.name.endsWith("aar")){ + } else { + classpathFiles += dependency + } + } + } + if (proj.hasProperty("android")){ + classpathFiles += proj.android.bootClasspath + } + + if (proj.hasProperty("sourceSets")) { + + for (srcSet in proj.sourceSets) { + for (dir in srcSet.java.srcDirs) { + classpathFiles += dir.absolutePath + } + } + } + } + def paths = classpathFiles.join(File.pathSeparator) + println "CLASSPATH:" + paths +} diff --git a/bundle/neomake/autoload/neomake/makers/ft/java/classpath.py b/bundle/neomake/autoload/neomake/makers/ft/java/classpath.py new file mode 100644 index 000000000..5a7ea8d93 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/java/classpath.py @@ -0,0 +1,15 @@ +import os +from xml.etree.ElementTree import * + + +def ReadClasspathFile(fn): + cp = [] + for a in parse(fn).findall('classpathentry'): + kind = a.get('kind') + if kind == 'src' and 'output' in a.keys(): + cp.append(os.path.abspath(a.get('output'))) + elif kind == 'lib' and 'path' in a.keys(): + cp.append(os.path.abspath(a.get('path'))) + elif kind == 'output' and 'path' in a.keys(): + cp.append(os.path.abspath(a.get('path'))) + return cp diff --git a/bundle/neomake/autoload/neomake/makers/ft/javascript.vim b/bundle/neomake/autoload/neomake/makers/ft/javascript.vim new file mode 100644 index 000000000..7bb379f2c --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/javascript.vim @@ -0,0 +1,119 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#javascript#EnabledMakers() abort + return ['jshint', 'jscs', + \ executable('eslint_d') ? 'eslint_d' : 'eslint', + \] +endfunction + +function! neomake#makers#ft#javascript#tsc() abort + return neomake#makers#ft#typescript#tsc() +endfunction + +function! neomake#makers#ft#javascript#gjslint() abort + return { + \ 'args': ['--nodebug_indentation', '--nosummary', '--unix_mode', '--nobeep'], + \ 'errorformat': '%f:%l:(New Error -%\\?\%n) %m,' . + \ '%f:%l:(-%\\?%n) %m,' . + \ '%-G1 files checked,' . + \ ' no errors found.,' . + \ '%-G%.%#' + \ } +endfunction + +function! neomake#makers#ft#javascript#jshint() abort + return { + \ 'args': ['--verbose'], + \ 'errorformat': '%A%f: line %l\, col %v\, %m \(%t%*\d\),%-G,%-G%\\d%\\+ errors', + \ 'postprocess': function('neomake#postprocess#generic_length'), + \ } +endfunction + +function! neomake#makers#ft#javascript#jscs() abort + return { + \ 'args': ['--no-colors', '--reporter', 'inline'], + \ 'errorformat': '%E%f: line %l\, col %c\, %m', + \ } +endfunction + +function! neomake#makers#ft#javascript#eslint() abort + let maker = { + \ 'args': ['--format=compact'], + \ 'errorformat': '%E%f: line %l\, col %c\, Error - %m,' . + \ '%W%f: line %l\, col %c\, Warning - %m,%-G,%-G%*\d problems%#', + \ 'cwd': '%:p:h', + \ 'output_stream': 'stdout', + \ } + + function! maker.supports_stdin(_jobinfo) abort + let self.args += ['--stdin', '--stdin-filename=%:p'] + let self.tempfile_name = '' + return 1 + endfunction + + return maker +endfunction + +function! neomake#makers#ft#javascript#eslint_d() abort + return neomake#makers#ft#javascript#eslint() +endfunction + +function! neomake#makers#ft#javascript#standard() abort + return { + \ 'args': ['-v'], + \ 'errorformat': '%W %f:%l:%c: %m,%-Gstandard: %.%#' + \ } +endfunction + +function! neomake#makers#ft#javascript#semistandard() abort + return { + \ 'errorformat': '%W %f:%l:%c: %m' + \ } +endfunction + +function! neomake#makers#ft#javascript#rjsx() abort + return { + \ 'exe': 'emacs', + \ 'args': ['%t','--quick','--batch','--eval=' + \ .'(progn(setq package-load-list ''((js2-mode t)(rjsx-mode t)))(package-initialize)(require ''rjsx-mode)' + \ .' (setq js2-include-node-externs t js2-include-rhino-externs t js2-include-browser-externs t js2-strict-missing-semi-warning nil)' + \ .' (rjsx-mode)(js2-reparse)(js2-display-error-list)' + \ .' (princ(replace-regexp-in-string "^" (concat buffer-file-name " ")' + \ .' (with-current-buffer "*js-lint*" (buffer-substring-no-properties(point-min)(point-max)))))(terpri))'], + \ 'errorformat': '%f line %l: %m,%-G%.%#', + \ 'append_file': 0, + \ } +endfunction + +function! neomake#makers#ft#javascript#flow() abort + return { + \ 'args': ['--from=vim', '--show-all-errors'], + \ 'errorformat': + \ '%-GNo errors!,' + \ .'%EFile "%f"\, line %l\, characters %c-%m,' + \ .'%trror: File "%f"\, line %l\, characters %c-%m,' + \ .'%C%m,%Z', + \ 'postprocess': function('neomake#makers#ft#javascript#FlowProcess') + \ } +endfunction + +function! neomake#makers#ft#javascript#FlowProcess(entry) abort + let lines = split(a:entry.text, '\n') + if !empty(lines) + let a:entry.text = join(lines[1:]) + let a:entry.length = lines[0] - a:entry.col + 1 + endif +endfunction + +function! neomake#makers#ft#javascript#xo() abort + return { + \ 'args': ['--compact'], + \ 'errorformat': '%E%f: line %l\, col %c\, Error - %m,' . + \ '%W%f: line %l\, col %c\, Warning - %m', + \ } +endfunction + +function! neomake#makers#ft#javascript#stylelint() abort + return neomake#makers#ft#css#stylelint() +endfunction + diff --git a/bundle/neomake/autoload/neomake/makers/ft/javascriptreact.vim b/bundle/neomake/autoload/neomake/makers/ft/javascriptreact.vim new file mode 100644 index 000000000..d8b20c932 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/javascriptreact.vim @@ -0,0 +1,17 @@ +function! neomake#makers#ft#javascriptreact#SupersetOf() abort + return 'javascript' +endfunction + +function! neomake#makers#ft#javascriptreact#EnabledMakers() abort + return ['jshint', executable('eslint_d') ? 'eslint_d' : 'eslint'] +endfunction + +function! neomake#makers#ft#javascriptreact#javascriptreacthint() abort + return neomake#makers#ft#javascript#jshint() +endfunction + +function! neomake#makers#ft#javascriptreact#stylelint() abort + return neomake#makers#ft#css#stylelint() +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/json.vim b/bundle/neomake/autoload/neomake/makers/ft/json.vim new file mode 100644 index 000000000..89a38e047 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/json.vim @@ -0,0 +1,38 @@ +function! neomake#makers#ft#json#EnabledMakers() abort + return ['jsonlint'] +endfunction + +function! neomake#makers#ft#json#jsonlintpy() abort + return { + \ 'exe': 'jsonlint-py', + \ 'args': ['--strict'], + \ 'errorformat': + \ '%f:%l:%c: %trror: %m,' . + \ '%f:%l:%c: %tarning: %m,', + \ } +endfunction + +function! neomake#makers#ft#json#jsonlint() abort + return { + \ 'args': ['--compact'], + \ 'errorformat': + \ '%ELine %l:%c,'. + \ '%Z\\s%#Reason: %m,'. + \ '%C%.%#,'. + \ '%f: line %l\, col %c\, %m,'. + \ '%-G%.%#' + \ } +endfunction + +function! neomake#makers#ft#json#eslint() abort + let maker = neomake#makers#ft#javascript#eslint() + let maker.args += ['--plugin', 'json'] + return maker +endfunction + +function! neomake#makers#ft#json#eslint_d() abort + let maker = neomake#makers#ft#javascript#eslint_d() + let maker.args += ['--plugin', 'json'] + return maker +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/jsx.vim b/bundle/neomake/autoload/neomake/makers/ft/jsx.vim new file mode 100644 index 000000000..38d3cc359 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/jsx.vim @@ -0,0 +1,17 @@ +function! neomake#makers#ft#jsx#SupersetOf() abort + return 'javascript' +endfunction + +function! neomake#makers#ft#jsx#EnabledMakers() abort + return ['jshint', executable('eslint_d') ? 'eslint_d' : 'eslint'] +endfunction + +function! neomake#makers#ft#jsx#jsxhint() abort + return neomake#makers#ft#javascript#jshint() +endfunction + +function! neomake#makers#ft#jsx#stylelint() abort + return neomake#makers#ft#css#stylelint() +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/julia.vim b/bundle/neomake/autoload/neomake/makers/ft/julia.vim new file mode 100644 index 000000000..a6fed9fa4 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/julia.vim @@ -0,0 +1,24 @@ +function! neomake#makers#ft#julia#EnabledMakers() abort + return ['lint'] +endfunction + +function! neomake#makers#ft#julia#lint() abort + return { +\ 'errorformat': '%f:%l %t%*[^ ] %m', +\ 'exe': 'julia', +\ 'args': ['-e', ' +\ try +\ using Lint +\ catch +\ println("$(basename(ARGS[1])):1 E999 Install Lint.jl: Pkg.add(""Lint"")"); +\ exit(1) +\ end; +\ r = lintfile(ARGS[1]); +\ if !isempty(r) +\ display(r); +\ exit(1) +\ end +\ '] +\ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/kotlin.vim b/bundle/neomake/autoload/neomake/makers/ft/kotlin.vim new file mode 100644 index 000000000..d7273e3ac --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/kotlin.vim @@ -0,0 +1,12 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#kotlin#EnabledMakers() abort + return ['ktlint'] +endfunction + +function! neomake#makers#ft#kotlin#ktlint() abort + return { + \ 'errorformat': '%E%f:%l:%c: %m', + \ } +endfunction + diff --git a/bundle/neomake/autoload/neomake/makers/ft/less.vim b/bundle/neomake/autoload/neomake/makers/ft/less.vim new file mode 100644 index 000000000..51ba941b7 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/less.vim @@ -0,0 +1,19 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#less#EnabledMakers() abort + return executable('stylelint') ? ['stylelint'] : ['lessc'] +endfunction + +function! neomake#makers#ft#less#lessc() abort + return { + \ 'args': ['--lint', '--no-color'], + \ 'errorformat': + \ '%m in %f on line %l\, column %c:,' . + \ '%m in %f:%l:%c,' . + \ '%-G%.%#' + \ } +endfunction + +function! neomake#makers#ft#less#stylelint() abort + return neomake#makers#ft#css#stylelint() +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/lex.vim b/bundle/neomake/autoload/neomake/makers/ft/lex.vim new file mode 100644 index 000000000..7dafebf9b --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/lex.vim @@ -0,0 +1,11 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#lex#EnabledMakers() abort + return ['flex'] +endfunction + +function! neomake#makers#ft#lex#flex() abort + return { + \ 'errorformat': '%f:%l: %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/lua.vim b/bundle/neomake/autoload/neomake/makers/ft/lua.vim new file mode 100644 index 000000000..ab93f337a --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/lua.vim @@ -0,0 +1,34 @@ +function! neomake#makers#ft#lua#EnabledMakers() abort + return executable('luacheck') ? ['luacheck'] : ['luac'] +endfunction + +" luacheck: postprocess: use pattern (%s) for end column. +function! neomake#makers#ft#lua#PostprocessLuacheck(entry) abort + if !(a:entry.type ==# 'W' && a:entry.nr ==# 631) + " Add length, but not with W631 (line too long). + let end_col = matchstr(a:entry.pattern, '\v\d+') + if !empty(end_col) + let a:entry.length = end_col - a:entry.col + 1 + endif + endif + let a:entry.pattern = '' +endfunction + +function! neomake#makers#ft#lua#luacheck() abort + " cwd: luacheck looks for .luacheckrc upwards from there. + return { + \ 'args': ['--no-color', '--formatter=plain', '--ranges', '--codes', '--filename', '%:p'], + \ 'cwd': '%:p:h', + \ 'errorformat': '%E%f:%l:%c-%s: \(%t%n\) %m', + \ 'postprocess': function('neomake#makers#ft#lua#PostprocessLuacheck'), + \ 'supports_stdin': 1, + \ } +endfunction + +function! neomake#makers#ft#lua#luac() abort + return { + \ 'args': ['-p'], + \ 'errorformat': '%*\f: %#%f:%l: %m', + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/mail.vim b/bundle/neomake/autoload/neomake/makers/ft/mail.vim new file mode 100644 index 000000000..54cd09e41 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/mail.vim @@ -0,0 +1,8 @@ +function! neomake#makers#ft#mail#EnabledMakers() abort + return ['proselint'] +endfunction + +function! neomake#makers#ft#mail#proselint() abort + return neomake#makers#ft#text#proselint() +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/markdown.vim b/bundle/neomake/autoload/neomake/makers/ft/markdown.vim new file mode 100644 index 000000000..7983816fe --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/markdown.vim @@ -0,0 +1,97 @@ +function! neomake#makers#ft#markdown#SupersetOf() abort + return 'text' +endfunction + +function! neomake#makers#ft#markdown#EnabledMakers() abort + let makers = executable('mdl') ? ['mdl'] : ['markdownlint'] + if executable('vale') | let makers += ['vale'] | endif + return makers + neomake#makers#ft#text#EnabledMakers() +endfunction + +function! neomake#makers#ft#markdown#mdl() abort + let maker = { + \ + \ 'errorformat': + \ '%W%f:%l: %m,%-G%.%#', + \ 'output_stream': 'stdout', + \ } + function! maker.postprocess(entry) abort + if a:entry.text[0:1] ==# 'MD' + let [code, text] = split(a:entry.text, '\v^MD\d+\zs ') + let a:entry.nr = str2nr(code[2:]) + let a:entry.text = printf('%s (%s)', text, code) + endif + return a:entry + endfunction + return maker +endfunction + +function! neomake#makers#ft#markdown#markdownlint() abort + return { + \ 'errorformat': '%f:%l %m,%f: %l: %m' + \ } +endfunction + +let s:alex_supports_stdin = {} +function! neomake#makers#ft#markdown#alex() abort + let maker = { + \ 'errorformat': + \ '%P%f,' + \ .'%-Q,' + \ .'%*[ ]%l:%c-%*\d:%n%*[ ]%tarning%*[ ]%m,' + \ .'%-G%.%#' + \ } + + function! maker.supports_stdin(_jobinfo) abort + let exe = exists('*exepath') ? exepath(self.exe) : self.exe + let support = get(s:alex_supports_stdin, exe, -1) + if support == -1 + let ver = neomake#compat#systemlist(['alex', '--version']) + let ver_split = split(ver[0], '\.') + if len(ver_split) > 1 && (ver_split[0] > 0 || +ver_split[1] >= 6) + let support = 1 + else + let support = 0 + endif + let s:alex_supports_stdin[exe] = support + call neomake#log#debug('alex: stdin support: '.support.'.') + endif + if support + let self.args += ['--stdin'] + let self.tempfile_name = '' + endif + return support + endfunction + + return maker +endfunction + +function! neomake#makers#ft#markdown#ProcessVale(context) abort + let entries = [] + for [filename, items] in items(a:context['json']) + for data in items + let entry = { + \ 'maker_name': 'vale', + \ 'filename': filename, + \ 'text': data.Message, + \ 'lnum': data.Line, + \ 'col': data.Span[0], + \ 'length': data.Span[1] - data.Span[0] + 1, + \ 'type': toupper(data.Severity[0]) + \ } + call add(entries, entry) + endfor + endfor + return entries +endfunction + +function! neomake#makers#ft#markdown#vale() abort + return { + \ 'args': [ + \ '--no-wrap', + \ '--output', 'JSON' + \ ], + \ 'process_json': function('neomake#makers#ft#markdown#ProcessVale') + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/matlab.vim b/bundle/neomake/autoload/neomake/makers/ft/matlab.vim new file mode 100644 index 000000000..f208be64f --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/matlab.vim @@ -0,0 +1,15 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#matlab#EnabledMakers() abort + return ['mlint'] +endfunction + +function! neomake#makers#ft#matlab#mlint() abort + return { + \ 'args': ['-id'], + \ 'mapexpr': "neomake_bufname.':'.v:val", + \ 'errorformat': + \ '%f:L %l (C %c): %m,'. + \ '%f:L %l (C %c-%*[0-9]): %m,', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/moon.vim b/bundle/neomake/autoload/neomake/makers/ft/moon.vim new file mode 100644 index 000000000..486bea7d9 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/moon.vim @@ -0,0 +1,15 @@ +function! neomake#makers#ft#moon#EnabledMakers() abort + return ['moonc'] +endfunction + +function! neomake#makers#ft#moon#moonc() abort + return { + \ 'args': ['-l'], + \ 'errorformat': + \ '%-G,' . + \ '%-G>%#,' . + \ '%+P%f,'. + \ 'line\ %l:\ %m' + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/neomake_tests.vim b/bundle/neomake/autoload/neomake/makers/ft/neomake_tests.vim new file mode 100644 index 000000000..e0e2b80e7 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/neomake_tests.vim @@ -0,0 +1,66 @@ +if !exists('g:neomake_test_messages') + " Only use it during tests. + finish +endif + +function! neomake#makers#ft#neomake_tests#EnabledMakers() abort + return get(b:, 'neomake_test_enabledmakers', + \ get(g:, 'neomake_test_enabledmakers', + \ ['maker_without_exe', 'nonexisting'])) +endfunction + +function! neomake#makers#ft#neomake_tests#maker_without_exe() abort + return {} +endfunction + +function! neomake#makers#ft#neomake_tests#maker_with_nonstring_exe() abort + return {'exe': function('tr')} +endfunction + +function! neomake#makers#ft#neomake_tests#echo_maker() abort + return { + \ 'exe': 'printf', + \ 'args': 'neomake_tests_echo_maker', + \ 'errorformat': '%m', + \ 'append_file': 0, + \ } +endfunction + +function! neomake#makers#ft#neomake_tests#echo_args() abort + return { + \ 'exe': 'echo', + \ 'errorformat': '%m', + \ } +endfunction + +function! neomake#makers#ft#neomake_tests#true() abort + return {} +endfunction + +function! neomake#makers#ft#neomake_tests#error_maker() abort + return { + \ 'exe': 'printf', + \ 'args': ['%s:1:error_msg_1'], + \ 'errorformat': '%E%f:%l:%m', + \ 'append_file': 1, + \ 'short_name': 'errmkr', + \ } +endfunction + +function! neomake#makers#ft#neomake_tests#process_output_error() abort + let maker = {'exe': 'echo', 'args': 'output', 'append_file': 0} + + function! maker.process_output(...) abort + return [{'valid': 1, 'text': 'error', 'lnum': 1, 'bufnr': bufnr('%')}] + endfunction + return maker +endfunction + +function! neomake#makers#ft#neomake_tests#success_entry_maker() abort + let maker = {} + function! maker.get_list_entries(...) abort + return [] + endfunction + return maker +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/nim.vim b/bundle/neomake/autoload/neomake/makers/ft/nim.vim new file mode 100644 index 000000000..68b72a365 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/nim.vim @@ -0,0 +1,16 @@ +function! neomake#makers#ft#nim#EnabledMakers() abort + return ['nim'] +endfunction + +function! neomake#makers#ft#nim#nim() abort + return { + \ 'exe': 'nim', + \ 'args': ['--listFullPaths', '--verbosity:0', '--colors:off', + \ '-c', 'check'], + \ 'errorformat': + \ '%I%f(%l\, %c) Hint: %m,' . + \ '%W%f(%l\, %c) Warning: %m,' . + \ '%E%f(%l\, %c) Error: %m' + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/nix.vim b/bundle/neomake/autoload/neomake/makers/ft/nix.vim new file mode 100644 index 000000000..f23978964 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/nix.vim @@ -0,0 +1,14 @@ +" vim: ts=4 sw=4 et +" +function! neomake#makers#ft#nix#EnabledMakers() abort + return ['nix_instantiate'] +endfunction + +function! neomake#makers#ft#nix#nix_instantiate() abort + return { + \ 'exe': 'nix-instantiate', + \ 'args': ['--parse-only'], + \ 'errorformat': 'error: %m at %f:%l:%c' + \ } +endfunction + diff --git a/bundle/neomake/autoload/neomake/makers/ft/node.vim b/bundle/neomake/autoload/neomake/makers/ft/node.vim new file mode 100644 index 000000000..a6cd321db --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/node.vim @@ -0,0 +1,9 @@ +function! neomake#makers#ft#node#SupersetOf() abort + return 'javascript' +endfunction + +function! neomake#makers#ft#node#EnabledMakers() abort + return ['jshint', 'eslint', 'jscs'] +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/objc.vim b/bundle/neomake/autoload/neomake/makers/ft/objc.vim new file mode 100644 index 000000000..5b093f436 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/objc.vim @@ -0,0 +1,55 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#objc#EnabledMakers() abort + let makers = ['clang', 'clangtidy', 'clangcheck'] + return makers +endfunction + +function! neomake#makers#ft#objc#clang() abort + " We will enable ARC and disable warnings about unused parameters because + " it is quite common in Cocoa not to use every method parameter. + return { + \ 'args': ['-fsyntax-only', '-fobjc-arc', '-Wall', '-Wextra', '-Wno-unused-parameter'], + \ 'errorformat': + \ '%-G%f:%s:,' . + \ '%f:%l:%c: %trror: %m,' . + \ '%f:%l:%c: %tarning: %m,' . + \ '%I%f:%l:%c: note: %m,' . + \ '%f:%l:%c: %m,'. + \ '%f:%l: %trror: %m,'. + \ '%f:%l: %tarning: %m,'. + \ '%I%f:%l: note: %m,'. + \ '%f:%l: %m' + \ } +endfunction + +" The -p option followed by the path to the build directory should be set in +" the maker's arguments. That directory should contain the compile command +" database (compile_commands.json). +function! neomake#makers#ft#objc#clangtidy() abort + return { + \ 'exe': 'clang-tidy', + \ 'errorformat': + \ '%E%f:%l:%c: fatal error: %m,' . + \ '%E%f:%l:%c: error: %m,' . + \ '%W%f:%l:%c: warning: %m,' . + \ '%-G%\m%\%%(LLVM ERROR:%\|No compilation database found%\)%\@!%.%#,' . + \ '%E%m', + \ } +endfunction + +function! neomake#makers#ft#objc#clangcheck() abort + return { + \ 'exe': 'clang-check', + \ 'errorformat': + \ '%-G%f:%s:,' . + \ '%f:%l:%c: %trror: %m,' . + \ '%f:%l:%c: %tarning: %m,' . + \ '%I%f:%l:%c: note: %m,' . + \ '%f:%l:%c: %m,'. + \ '%f:%l: %trror: %m,'. + \ '%f:%l: %tarning: %m,'. + \ '%I%f:%l: note: %m,'. + \ '%f:%l: %m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/pandoc.vim b/bundle/neomake/autoload/neomake/makers/ft/pandoc.vim new file mode 100644 index 000000000..ae56b0494 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/pandoc.vim @@ -0,0 +1,8 @@ +function! neomake#makers#ft#pandoc#SupersetOf() abort + return 'markdown' +endfunction + +function! neomake#makers#ft#pandoc#EnabledMakers() abort + return neomake#makers#ft#markdown#EnabledMakers() +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/perl.vim b/bundle/neomake/autoload/neomake/makers/ft/perl.vim new file mode 100644 index 000000000..da07694a6 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/perl.vim @@ -0,0 +1,34 @@ +" vim: ts=4 sw=4 et +function! neomake#makers#ft#perl#EnabledMakers() abort + return ['perl', 'perlcritic'] +endfunction + +function! neomake#makers#ft#perl#perlcritic() abort + return { + \ 'args' : ['--quiet', '--nocolor', '--verbose', + \ '\\%f:\\%l:\\%c:(\\%s) \\%m (\\%e)\\n'], + \ 'errorformat': '%f:%l:%c:%m,' + \} +endfunction + +function! neomake#makers#ft#perl#perl() abort + return { + \ 'args' : ['-c', '-X', '-Mwarnings'], + \ 'errorformat': '%-G%.%#had too many errors.,' + \ . '%-G%.%#had compilation errors.,' + \ . '%-G%.%#syntax OK,' + \ . '%m at %f line %l.,' + \ . '%+E%.%# at %f line %l\,%.%#,' + \ . '%+C%.%#', + \ 'postprocess': function('neomake#makers#ft#perl#PerlEntryProcess'), + \} +endfunction + +function! neomake#makers#ft#perl#PerlEntryProcess(entry) abort + let extramsg = substitute(a:entry.pattern, '\^\\V', '', '') + let extramsg = substitute(extramsg, '\\\$', '', '') + + if !empty(extramsg) + let a:entry.text .= ' ' . extramsg + endif +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/php.vim b/bundle/neomake/autoload/neomake/makers/ft/php.vim new file mode 100644 index 000000000..7edefa344 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/php.vim @@ -0,0 +1,72 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#php#EnabledMakers() abort + return ['php', 'phpmd', 'phpcs', 'phpstan'] +endfunction + +function! neomake#makers#ft#php#php() abort + return { + \ 'args': ['-l', '-d', 'display_errors=1', '-d', 'log_errors=0', + \ '-d', 'xdebug.cli_color=0'], + \ 'errorformat': + \ '%-GNo syntax errors detected in%.%#,'. + \ '%EParse error: %#syntax error\, %m in %f on line %l,'. + \ '%EParse error: %m in %f on line %l,'. + \ '%EFatal error: %m in %f on line %l,'. + \ '%-G\s%#,'. + \ '%-GErrors parsing %.%#', + \ 'output_stream': 'stdout', + \ } +endfunction + +function! neomake#makers#ft#php#phpcs() abort + let args = ['--report=csv', '-q'] + + "Add standard argument if one is set. + if exists('g:neomake_php_phpcs_args_standard') + call add(args, '--standard=' . expand(g:neomake_php_phpcs_args_standard)) + endif + + return { + \ 'args': args, + \ 'errorformat': + \ '%-GFile\,Line\,Column\,Type\,Message\,Source\,Severity%.%#,'. + \ '"%f"\,%l\,%c\,%t%*[a-zA-Z]\,"%m"\,%*[a-zA-Z0-9_.-]\,%*[0-9]%.%#', + \ } +endfunction + +function! neomake#makers#ft#php#phpmd() abort + return { + \ 'args': ['%t', 'text', 'codesize,design,unusedcode,naming'], + \ 'append_file': 0, + \ 'errorformat': '%W%f:%l%\s%\s%#%m' + \ } +endfunction + +function! neomake#makers#ft#php#phpstan() abort + " PHPStan normally considers 0 to be the default level, so that is used here as the default: + let maker = { + \ 'args': ['analyse', '--error-format', 'raw', '--no-progress', '--level', get(g:, 'neomake_phpstan_level', 0)], + \ 'errorformat': '%E%f:%l:%m', + \ } + " Check for the existence of a default PHPStan project configuration file. + " Technically PHPStan does not have a concept of a default filename for a + " project configuration file, but phpstan.neon is the filename shown in the + " example in the PHPStan documentation, so this is the default name expected + " by Neomake. + let phpStanConfigFilePath = neomake#utils#FindGlobFile('phpstan.neon') + if !empty(phpStanConfigFilePath) + call extend(maker.args, ['-c', phpStanConfigFilePath]) + endif + return maker +endfunction + +function! neomake#makers#ft#php#psalm() abort + let maker = { + \ 'args': [ + \ '--output-format=pylint' + \ ], + \ 'errorformat': '%A%f:%l:%\s[%t%n]%\s%m', + \ } + return maker +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/proto.vim b/bundle/neomake/autoload/neomake/makers/ft/proto.vim new file mode 100644 index 000000000..fcff57741 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/proto.vim @@ -0,0 +1,12 @@ +function! neomake#makers#ft#proto#EnabledMakers() abort + return ['prototool'] +endfunction + +function! neomake#makers#ft#proto#prototool() abort + return { + \ 'exe': 'prototool', + \ 'args': ['lint'], + \ 'errorformat': '%f:%l:%c:%m', + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/pug.vim b/bundle/neomake/autoload/neomake/makers/ft/pug.vim new file mode 100644 index 000000000..53f221451 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/pug.vim @@ -0,0 +1,13 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#pug#EnabledMakers() abort + return ['puglint'] +endfunction + +function! neomake#makers#ft#pug#puglint() abort + return { + \ 'exe': 'pug-lint', + \ 'args': ['--reporter', 'inline'], + \ 'errorformat': '%f:%l:%c %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/puppet.vim b/bundle/neomake/autoload/neomake/makers/ft/puppet.vim new file mode 100644 index 000000000..c7a467d69 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/puppet.vim @@ -0,0 +1,29 @@ +function! neomake#makers#ft#puppet#EnabledMakers() abort + return ['puppet', 'puppetlint'] +endfunction + +function! neomake#makers#ft#puppet#puppetlint() abort + return { + \ 'exe': 'puppet-lint', + \ 'args': ['--log-format', '%%{path}:%%{line}:%%{column}:%%{kind}:[%%{check}] %%{message}'], + \ 'errorformat': '%f:%l:%c:%t%*[a-zA-Z]:%m', + \ 'short_name': 'pupl', + \ 'output_stream': 'stdout', + \ } +endfunction + +function! neomake#makers#ft#puppet#puppet() abort + return { + \ 'args': ['parser', 'validate', '--color=false'], + \ 'errorformat': + \ '%-Gerr: Try ''puppet help parser validate'' for usage,' . + \ '%-GError: Try ''puppet help parser validate'' for usage,' . + \ '%t%*[a-zA-Z]: %m at %f:%l:%c,' . + \ '%t%*[a-zA-Z]: %m at %f:%l,'. + \ '%t%*[a-zA-Z]: Could not parse for environment production: %m (file: %f\, line: %l\, column: %c),' . + \ '%t%*[a-zA-Z]: Could not parse for environment production: %m (file: %f)', + \ 'short_name': 'pupp', + \ 'output_stream': 'stderr', + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/purescript.vim b/bundle/neomake/autoload/neomake/makers/ft/purescript.vim new file mode 100644 index 000000000..a26a40f06 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/purescript.vim @@ -0,0 +1,63 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#purescript#EnabledMakers() abort + return ['pulp'] +endfunction + +function! neomake#makers#ft#purescript#pulp() abort + " command is `pulp build --no-psa -- --json-errors` + " as indicated in https://github.com/nwolverson/atom-ide-purescript/issues/136 + let maker = { + \ 'args': ['build', '--no-psa', '--', '--json-errors'], + \ 'append_file': 0, + \ 'process_output': function('neomake#makers#ft#purescript#PSProcessOutput'), + \ } + + " Find project root, since files are reported relative to it. + let bower_file = neomake#utils#FindGlobFile('bower.json') + if !empty(bower_file) + let maker.cwd = fnamemodify(bower_file, ':h') + endif + + return maker +endfunction + +function! neomake#makers#ft#purescript#PSProcessOutput(context) abort + let errors = [] + for line in a:context.output + if line[0] !=# '{' + continue + endif + let decoded = neomake#compat#json_decode(line) + for [key, values] in items(decoded) + let code = key ==# 'warnings' ? 'W' : 'E' + for item in values + let compiler_error = item['errorCode'] + let message = item['message'] + let position = item['position'] + let filename = item['filename'] + if position is g:neomake#compat#json_null + let row = 1 + let col = 1 + let end_col = 1 + let length = 1 + else + let row = position['startLine'] + let col = position['startColumn'] + let end_col = position['endColumn'] + let length = end_col - col + endif + + call add(errors, { + \ 'text': compiler_error . ' : ' . message, + \ 'type': code, + \ 'lnum': row, + \ 'col': col, + \ 'length': length, + \ 'filename': filename, + \ }) + endfor + endfor + endfor + return errors +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/python.vim b/bundle/neomake/autoload/neomake/makers/ft/python.vim new file mode 100644 index 000000000..04c5d4ba5 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/python.vim @@ -0,0 +1,461 @@ +" vim: ts=4 sw=4 et + +if !exists('s:compile_script') + let s:slash = neomake#utils#Slash() + let s:compile_script = expand(':p:h', 1).s:slash.'python'.s:slash.'compile.py' +endif + +function! neomake#makers#ft#python#EnabledMakers() abort + let makers = ['python', 'frosted'] + if executable('pylama') + call add(makers, 'pylama') + else + if executable('flake8') + call add(makers, 'flake8') + else + call extend(makers, ['pyflakes', 'pycodestyle', 'pydocstyle']) + endif + call add(makers, 'pylint') " Last because it is the slowest + endif + return makers +endfunction + +let neomake#makers#ft#python#project_root_files = ['setup.cfg', 'tox.ini'] + +function! neomake#makers#ft#python#DetectPythonVersion() abort + let output = neomake#compat#systemlist('python -V 2>&1') + if v:shell_error + call neomake#log#error(printf( + \ 'Failed to detect Python version: %s.', + \ join(output))) + let s:python_version = [-1, -1, -1] + else + let s:python_version = split(split(output[0])[1], '\.') + endif +endfunction + +let s:ignore_python_warnings = [ + \ '\v[\/]inspect.py:\d+: Warning:', + \ '\v^.{-}:\d+: FutureWarning:', + \ ] + +" Filter Python warnings (the warning and the following line). +" To be used as a funcref with filter(). +function! s:filter_py_warning(v) abort + if s:filter_next_py_warning + let s:filter_next_py_warning = 0 + " Only keep (expected) lines starting with two spaces. + return a:v[0:1] !=# ' ' + endif + for pattern in s:ignore_python_warnings + if a:v =~# pattern + let s:filter_next_py_warning = 1 + return 0 + endif + endfor + return 1 +endfunction + +function! neomake#makers#ft#python#FilterPythonWarnings(lines, context) abort + if a:context.source ==# 'stderr' + let s:filter_next_py_warning = 0 + call filter(a:lines, 's:filter_py_warning(v:val)') + endif +endfunction + +function! neomake#makers#ft#python#pylint() abort + let maker = { + \ 'args': [ + \ '--output-format=text', + \ '--msg-template="{path}:{line}:{column}:{C}: [{symbol}] {msg} [{msg_id}]"', + \ '--reports=no' + \ ], + \ 'errorformat': + \ '%A%f:%l:%c:%t: %m,' . + \ '%A%f:%l: %m,' . + \ '%A%f:(%l): %m,' . + \ '%-Z%p^%.%#,' . + \ '%-G%.%#', + \ 'output_stream': 'stdout', + \ 'postprocess': [ + \ function('neomake#postprocess#generic_length'), + \ function('neomake#makers#ft#python#PylintEntryProcess'), + \ ]} + function! maker.filter_output(lines, context) abort + if a:context.source ==# 'stderr' + call filter(a:lines, "v:val !=# 'No config file found, using default configuration' && v:val !~# '^Using config file '") + endif + call neomake#makers#ft#python#FilterPythonWarnings(a:lines, a:context) + endfunction + return maker +endfunction + +function! neomake#makers#ft#python#PylintEntryProcess(entry) abort + if a:entry.type ==# 'F' " Fatal error which prevented further processing + let type = 'E' + elseif a:entry.type ==# 'E' " Error for important programming issues + let type = 'E' + elseif a:entry.type ==# 'W' " Warning for stylistic or minor programming issues + let type = 'W' + elseif a:entry.type ==# 'R' " Refactor suggestion + let type = 'W' + elseif a:entry.type ==# 'C' " Convention violation + let type = 'W' + elseif a:entry.type ==# 'I' " Informations + let type = 'I' + else + let type = '' + endif + let a:entry.type = type + " Pylint uses 0-indexed columns, vim uses 1-indexed columns + let a:entry.col += 1 +endfunction + +function! neomake#makers#ft#python#flake8() abort + let maker = { + \ 'args': ['--format=default'], + \ 'errorformat': + \ '%E%f:%l: could not compile,%-Z%p^,' . + \ '%A%f:%l:%c: %t%n %m,' . + \ '%A%f:%l: %t%n %m,' . + \ '%-G%.%#', + \ 'postprocess': function('neomake#makers#ft#python#Flake8EntryProcess'), + \ 'short_name': 'fl8', + \ 'output_stream': 'stdout', + \ 'filter_output': function('neomake#makers#ft#python#FilterPythonWarnings'), + \ } + + function! maker.supports_stdin(jobinfo) abort + let self.args += ['--stdin-display-name', '%:p'] + + let bufpath = bufname(a:jobinfo.bufnr) + if !empty(bufpath) + let bufdir = fnamemodify(bufpath, ':p:h') + if stridx(bufdir, getcwd()) != 0 + " The buffer is not below the current dir, so let's cd for lookup + " of config files etc. + " This avoids running into issues with flake8's per-file-ignores, + " which is handled not relative to the config file currently + " (https://gitlab.com/pycqa/flake8/issues/517). + call a:jobinfo.cd(bufdir) + endif + endif + return 1 + endfunction + return maker +endfunction + +function! neomake#makers#ft#python#Flake8EntryProcess(entry) abort + if a:entry.type ==# 'F' " pyflakes + " Ref: http://flake8.pycqa.org/en/latest/user/error-codes.html + if a:entry.nr > 400 && a:entry.nr < 500 + if a:entry.nr == 407 + let type = 'E' " 'an undefined __future__ feature name was imported' + else + let type = 'W' + endif + elseif a:entry.nr == 841 + let type = 'W' + else + let type = 'E' + endif + elseif a:entry.type ==# 'E' && a:entry.nr >= 900 " PEP8 runtime errors (E901, E902) + let type = 'E' + elseif a:entry.type ==# 'E' || a:entry.type ==# 'W' " PEP8 errors & warnings + let type = 'W' + elseif a:entry.type ==# 'N' || a:entry.type ==# 'D' " Naming (PEP8) & docstring (PEP257) conventions + let type = 'W' + elseif a:entry.type ==# 'C' || a:entry.type ==# 'T' " McCabe complexity & todo notes + let type = 'I' + elseif a:entry.type ==# 'I' " keep at least 'I' from isort (I1), could get style subtype?! + let type = a:entry.type + else + let type = '' + endif + + let token_pattern = '\v''\zs[^'']+\ze' + if a:entry.type ==# 'F' && (a:entry.nr == 401 || a:entry.nr == 811) + " Special handling for F401 (``module`` imported but unused) and + " F811 (redefinition of unused ``name`` from line ``N``). + " The unused column is incorrect for import errors and redefinition + " errors. + let token = matchstr(a:entry.text, token_pattern) + if !empty(token) + let view = winsaveview() + call cursor(a:entry.lnum, a:entry.col) + " The number of lines to give up searching afterwards + let search_lines = 5 + + if searchpos('\', 'cnW', a:entry.lnum)[1] == a:entry.col + " for 'from xxx.yyy import zzz' the token looks like + " xxx.yyy.zzz, but only the zzz part should be highlighted. So + " this discards the module part + let token = split(token, '\.')[-1] + + " Also the search should be started at the import keyword. + " Otherwise for 'from os import os' the first os will be + " found. This moves the cursor there. + call search('\', 'cW', a:entry.lnum + search_lines) + endif + + " Search for the first occurrence of the token and highlight in + " the next couple of lines and change the lnum and col to that + " position. + " Don't match entries surrounded by dots, even though + " it ends a word, we want to find a full identifier. It also + " matches all seperators such as spaces and newlines with + " backslashes until it knows for sure the previous real character + " was not a dot. + let ident_pos = searchpos('\(\.\(\_s\|\\\)*\)\@\(\(\_s\|\\\)*\.\)\@!', + \ 'cnW', + \ a:entry.lnum + search_lines) + if ident_pos[1] > 0 + let a:entry.lnum = ident_pos[0] + let a:entry.col = ident_pos[1] + endif + + call winrestview(view) + + let a:entry.length = strlen(token) + endif + else + call neomake#postprocess#generic_length_with_pattern(a:entry, token_pattern) + + " Special processing for F821 (undefined name) in f-strings. + if !has_key(a:entry, 'length') && a:entry.type ==# 'F' && a:entry.nr == 821 + let token = matchstr(a:entry.text, token_pattern) + if !empty(token) + " Search for '{token}' in reported and following lines. + " It seems like for the first line it is correct already (i.e. + " flake8 reports the column therein), but we still test there + " to be sure. + " https://gitlab.com/pycqa/flake8/issues/407 + let line = get(getbufline(a:entry.bufnr, a:entry.lnum), 0, '') + " NOTE: uses byte offset, starting at col means to start after + " the opening quote. + let pattern = '\V\C{\.\{-}\zs'.escape(token, '\').'\>' + let pos = match(line, pattern, a:entry.col) + if pos == -1 + let line_offset = 0 + while line_offset < 10 + let line_offset += 1 + let line = get(getbufline(a:entry.bufnr, a:entry.lnum + line_offset), 0, '') + let pos = match(line, pattern) + if pos != -1 + let a:entry.lnum = a:entry.lnum + line_offset + break + endif + endwhile + endif + if pos > 0 + let a:entry.col = pos + 1 + let a:entry.length = strlen(token) + endif + endif + endif + endif + + let a:entry.text = a:entry.type . a:entry.nr . ' ' . a:entry.text + let a:entry.type = type + " Reset "nr" to Avoid redundancy with neomake#GetCurrentErrorMsg. + " TODO: This is rather bad, since "nr" itself can be useful. + " This should rather use the entry via Neomake's list, and then a + " new property like "current_error_text" could be used. + " Or with the maker being available a callback could be used. + let a:entry.nr = -1 +endfunction + +function! neomake#makers#ft#python#pyflakes() abort + return { + \ 'errorformat': + \ '%E%f:%l: could not compile,' . + \ '%-Z%p^,'. + \ '%E%f:%l:%c: %m,' . + \ '%E%f:%l: %m,' . + \ '%-G%.%#', + \ } +endfunction + +function! neomake#makers#ft#python#pycodestyle() abort + if !exists('s:_pycodestyle_exe') + " Use the preferred exe to avoid deprecation warnings. + let s:_pycodestyle_exe = executable('pycodestyle') ? 'pycodestyle' : 'pep8' + endif + return { + \ 'exe': s:_pycodestyle_exe, + \ 'errorformat': '%f:%l:%c: %m', + \ 'postprocess': function('neomake#makers#ft#python#Pep8EntryProcess') + \ } +endfunction + +" Note: pep8 has been renamed to pycodestyle, but is kept also as alias. +function! neomake#makers#ft#python#pep8() abort + return neomake#makers#ft#python#pycodestyle() +endfunction + +function! neomake#makers#ft#python#Pep8EntryProcess(entry) abort + if a:entry.text =~# '^E9' " PEP8 runtime errors (E901, E902) + let a:entry.type = 'E' + elseif a:entry.text =~# '^E113' " unexpected indentation (IndentationError) + let a:entry.type = 'E' + else " Everything else is a warning + let a:entry.type = 'W' + endif +endfunction + +function! neomake#makers#ft#python#pydocstyle() abort + if !exists('s:_pydocstyle_exe') + " Use the preferred exe to avoid deprecation warnings. + let s:_pydocstyle_exe = executable('pydocstyle') ? 'pydocstyle' : 'pep257' + endif + return { + \ 'exe': s:_pydocstyle_exe, + \ 'errorformat': + \ '%W%f:%l %.%#:,' . + \ '%+C %m', + \ 'postprocess': function('neomake#postprocess#compress_whitespace'), + \ } +endfunction + +" Note: pep257 has been renamed to pydocstyle, but is kept also as alias. +function! neomake#makers#ft#python#pep257() abort + return neomake#makers#ft#python#pydocstyle() +endfunction + +function! neomake#makers#ft#python#PylamaEntryProcess(entry) abort + if a:entry.nr == -1 + " Get number from the beginning of text. + let nr = matchstr(a:entry.text, '\v^\u\zs\d+') + if !empty(nr) + let a:entry.nr = nr + 0 + endif + endif + if a:entry.type ==# 'C' && a:entry.text =~# '\v\[%(pycodestyle|pep8)\]$' + call neomake#makers#ft#python#Pep8EntryProcess(a:entry) + elseif a:entry.type ==# 'D' " pydocstyle/pep257 + let a:entry.type = 'W' + elseif a:entry.type ==# 'C' && a:entry.nr == 901 " mccabe + let a:entry.type = 'I' + elseif a:entry.type ==# 'R' " Radon + let a:entry.type = 'W' + endif +endfunction + +function! neomake#makers#ft#python#pylama() abort + let maker = { + \ 'args': ['--format', 'parsable'], + \ 'errorformat': '%f:%l:%c: [%t] %m', + \ 'postprocess': function('neomake#makers#ft#python#PylamaEntryProcess'), + \ 'output_stream': 'stdout', + \ } + " Pylama looks for the config only in the current directory. + " Therefore we change to where the config likely is. + " --options could be used to pass a config file, but we cannot be sure + " which one really gets used. + let ini_file = neomake#utils#FindGlobFile('{pylama.ini,setup.cfg,tox.ini,pytest.ini}') + if !empty(ini_file) + let maker.cwd = fnamemodify(ini_file, ':h') + endif + return maker +endfunction + +function! neomake#makers#ft#python#python() abort + return { + \ 'args': [s:compile_script], + \ 'errorformat': '%E%f:%l:%c: E: %m,%W%f:%l: W: %m', + \ 'serialize': 1, + \ 'serialize_abort_on_error': 1, + \ 'output_stream': 'stdout', + \ 'short_name': 'py', + \ } +endfunction + +function! neomake#makers#ft#python#frosted() abort + return { + \ 'args': [ + \ '-vb' + \ ], + \ 'errorformat': + \ '%f:%l:%c:%m,' . + \ '%E%f:%l: %m,' . + \ '%-Z%p^,' . + \ '%-G%.%#' + \ } +endfunction + +function! neomake#makers#ft#python#vulture() abort + return { + \ 'errorformat': '%f:%l: %m', + \ } +endfunction + +function! neomake#makers#ft#python#mypy() abort + " NOTE: uses defaults suitable for using it without any config. + " ignore_missing_imports cannot be disabled in a config then though + let args = [ + \ '--show-column-numbers', + \ '--show-error-codes', + \ '--check-untyped-defs', + \ '--ignore-missing-imports', + \ ] + + " Append '--py2' to args with Python 2 for Python 2 mode. + if !exists('s:python_version') + call neomake#makers#ft#python#DetectPythonVersion() + endif + if s:python_version[0] ==# '2' + call add(args, '--py2') + endif + + let maker = { + \ 'args': args, + \ 'output_stream': 'stdout', + \ 'errorformat': + \ '%E%f:%l:%c: error: %m,' . + \ '%W%f:%l:%c: warning: %m,' . + \ '%I%f:%l:%c: note: %m,' . + \ '%E%f:%l: error: %m,' . + \ '%W%f:%l: warning: %m,' . + \ '%I%f:%l: note: %m,' . + \ '%-GSuccess%.%#,' . + \ '%-GFound%.%#,' + \ } + function! maker.InitForJob(jobinfo) abort + let maker = deepcopy(self) + let file_mode = a:jobinfo.file_mode + if file_mode + " Follow imports, but do not emit errors/issues for it, which + " would result in errors for other buffers etc. + " XXX: dmypy requires "skip" or "error" + call insert(maker.args, '--follow-imports=silent') + else + let project_root = neomake#utils#get_project_root(a:jobinfo.bufnr) + if empty(project_root) + call add(maker.args, '.') + else + call add(maker.args, project_root) + endif + endif + return maker + endfunction + function! maker.supports_stdin(jobinfo) abort + if !has_key(self, 'tempfile_name') + let self.tempfile_name = self._get_default_tempfilename(a:jobinfo) + endif + let self.args += ['--shadow-file', '%', self.tempfile_name] + return 0 + endfunction + function! maker.postprocess(entry) abort + if a:entry.text =~# '\v^Need type (annotation|comment) for' + let a:entry.type = 'I' + endif + endfunction + return maker +endfunction + +function! neomake#makers#ft#python#py3kwarn() abort + return { + \ 'errorformat': '%W%f:%l:%c: %m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/python/compile.py b/bundle/neomake/autoload/neomake/makers/ft/python/compile.py new file mode 100644 index 000000000..a8ff164ae --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/python/compile.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import warnings +import sys + + +def main(argv): + if len(argv) != 2: + exit(64) + + with open(argv[1]) as fp: + contents = fp.read() + + exitcode = 0 + syntax_err = None + with warnings.catch_warnings(record=True) as wc: + try: + compile(contents, argv[1], "exec", 0, 1) + except SyntaxError as exc: + syntax_err = exc + + # Output any warnings (caught during `compile`). + # This could/should maybe only handle SyntaxWarnings? + for wm in wc: + print( + "%s:%s: W: %s (%s)" + % (wm.filename, wm.lineno, wm.message, wm.category.__name__) + ) + exitcode |= 2 + + # Output any SyntaxError. + if syntax_err: + print( + "%s:%s:%s: E: %s" + % ( + syntax_err.filename, + syntax_err.lineno, + syntax_err.offset, + syntax_err.msg, + ) + ) + exitcode |= 1 + return exitcode + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/bundle/neomake/autoload/neomake/makers/ft/r.vim b/bundle/neomake/autoload/neomake/makers/ft/r.vim new file mode 100644 index 000000000..59f488aa8 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/r.vim @@ -0,0 +1,17 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#r#EnabledMakers() abort + return ['lintr'] +endfunction + +function! neomake#makers#ft#r#lintr() abort + return { + \ 'exe': 'R', + \ 'args': ['--slave', '--no-restore', '--no-save', '-e lintr::lint("%t")'], + \ 'append_file': 0, + \ 'errorformat': + \ '%W%f:%l:%c: style: %m,' . + \ '%W%f:%l:%c: warning: %m,' . + \ '%E%f:%l:%c: error: %m,' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/racket.vim b/bundle/neomake/autoload/neomake/makers/ft/racket.vim new file mode 100644 index 000000000..fc7145a6f --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/racket.vim @@ -0,0 +1,32 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#racket#EnabledMakers() abort + return ['raco'] +endfunction + +" This is the same form of syntax-checking used by DrRacket as well. The +" downside is that it will only catch the first error, but none of the +" subsequent ones. This is due to how evaluation in Racket works. +" +" About the error format: raco will print the first line as +" :: +" Every successive line will be indented by two spaces: +" in: +" context...: +" ::: +" The last pattern will be repeated as often as necessary. Example: +" foo.rkt:4:1: dfine: unbound identifier in modulemessage +" in: dfine +" context...: +" /usr/local/Cellar/racket/6.5/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt:34:15: loop +" /usr/local/Cellar/racket/6.5/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt:10:2: show-program +" /usr/local/Cellar/racket/6.5/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt: [running body] +" /usr/local/Cellar/minimal-racket/6.6/share/racket/collects/raco/raco.rkt: [running body] +" /usr/local/Cellar/minimal-racket/6.6/share/racket/collects/raco/main.rkt: [running body] +function! neomake#makers#ft#racket#raco() abort + return { + \ 'exe': 'raco', + \ 'args': ['expand'], + \ 'errorformat': '%-G %.%#,%E%f:%l:%c: %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/rst.vim b/bundle/neomake/autoload/neomake/makers/ft/rst.vim new file mode 100644 index 000000000..9d589fbcb --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/rst.vim @@ -0,0 +1,89 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#rst#SupersetOf() abort + return 'text' +endfunction + +" Get Sphinx source dir for the current buffer (determined by looking for +" conf.py, typically in docs/ or doc/). +" Caches the value in a buffer-local setting. +function! s:get_sphinx_srcdir() abort + let srcdir = neomake#config#get('sphinx.source_dir') + if srcdir isnot# g:neomake#config#undefined + return srcdir + endif + + let r = '' + let project_root = neomake#utils#get_project_root() + let bufname = bufname('%') + if empty(bufname) + call neomake#log#debug('sphinx: skipping setting of source_dir for empty bufname.', {'bufnr': bufnr('%')}) + return '' + endif + let f = findfile('conf.py', printf('%s;%s', fnamemodify(bufname, ':p:h'), project_root)) + if !empty(f) + let r = fnamemodify(f, ':p:h') + endif + call neomake#log#debug(printf('sphinx: setting b:neomake.sphinx.source_dir=%s.', string(r)), {'bufnr': bufnr('%')}) + call neomake#config#set('b:sphinx.source_dir', r) + return r +endfunction + +function! neomake#makers#ft#rst#EnabledMakers() abort + if executable('sphinx-build') && !empty(s:get_sphinx_srcdir()) + return ['sphinx'] + endif + return ['rstlint', 'rstcheck'] +endfunction + +function! neomake#makers#ft#rst#rstlint() abort + return { + \ 'exe': 'rst-lint', + \ 'errorformat': + \ '%ESEVERE %f:%l %m,'. + \ '%EERROR %f:%l %m,'. + \ '%WWARNING %f:%l %m,'. + \ '%IINFO %f:%l %m,'. + \ '%C%m', + \ 'postprocess': function('neomake#postprocess#compress_whitespace'), + \ 'output_stream': 'stdout', + \ } +endfunction + +function! neomake#makers#ft#rst#rstcheck() abort + return { + \ 'errorformat': + \ '%I%f:%l: (INFO/1) %m,'. + \ '%W%f:%l: (WARNING/2) %m,'. + \ '%E%f:%l: (ERROR/3) %m,'. + \ '%E%f:%l: (SEVERE/4) %m', + \ } +endfunction + +function! neomake#makers#ft#rst#sphinx() abort + " TODO: + " - project mode (after cleanup branch) + let srcdir = s:get_sphinx_srcdir() + if empty(srcdir) + throw 'Neomake: sphinx: could not find conf.py (you can configure sphinx.source_dir)' + endif + if !exists('s:sphinx_cache') + let s:sphinx_cache = tempname() + endif + " NOTE: uses '%Z%m,%-G%.%#' instead of '%C%m,%-G' to include next line in + " multiline errors (fixed in 7.4.203). + return { + \ 'exe': 'sphinx-build', + \ 'args': ['-n', '-E', '-q', '-N', '-b', 'dummy', srcdir, s:sphinx_cache], + \ 'append_file': 0, + \ 'errorformat': + \ '%A%f:%l: %tARNING: %m,' . + \ '%EWARNING: %f:%l: (SEVER%t/4) %m,' . + \ '%EWARNING: %f:%l: (%tRROR/3) %m,' . + \ '%EWARNING: %f:%l: (%tARNING/2) %m,' . + \ '%Z%m,' . + \ '%-G%.%#', + \ 'output_stream': 'stderr', + \ 'postprocess': function('neomake#postprocess#compress_whitespace'), + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/ruby.vim b/bundle/neomake/autoload/neomake/makers/ft/ruby.vim new file mode 100644 index 000000000..fb0736291 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/ruby.vim @@ -0,0 +1,98 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#ruby#EnabledMakers() abort + return ['flog', 'mri', 'rubocop', 'reek', 'rubylint'] +endfunction + +function! neomake#makers#ft#ruby#rubocop() abort + let maker = { + \ 'args': ['--format', 'emacs', '--force-exclusion', '--display-cop-names'], + \ 'errorformat': '%f:%l:%c: %t: %m,%E%f:%l: %m', + \ 'postprocess': function('neomake#makers#ft#ruby#RubocopEntryProcess'), + \ 'output_stream': 'stdout', + \ } + + function! maker.supports_stdin(_jobinfo) abort + let self.args += ['--stdin', '%'] + let self.tempfile_name = '' + return 1 + endfunction + + return maker +endfunction + +function! neomake#makers#ft#ruby#RubocopEntryProcess(entry) abort + if a:entry.type ==# 'F' " Fatal error which prevented further processing + let a:entry.type = 'E' + elseif a:entry.type ==# 'E' " Error for important programming issues + let a:entry.type = 'E' + elseif a:entry.type ==# 'W' " Warning for stylistic or minor programming issues + let a:entry.type = 'W' + elseif a:entry.type ==# 'R' " Refactor suggestion + let a:entry.type = 'W' + elseif a:entry.type ==# 'C' " Convention violation + let a:entry.type = 'I' + endif +endfunction + +function! neomake#makers#ft#ruby#rubylint() abort + return { + \ 'exe': 'ruby-lint', + \ 'args': ['--presenter', 'syntastic'], + \ 'errorformat': '%f:%t:%l:%c: %m', + \ } +endfunction + +function! neomake#makers#ft#ruby#mri() abort + let errorformat = '%-G%\m%.%#warning: %\%%(possibly %\)%\?useless use of == in void context,' + let errorformat .= '%-G%\%.%\%.%\%.%.%#,' + let errorformat .= + \ '%-GSyntax OK,'. + \ '%E%f:%l: syntax error\, %m,'. + \ '%Z%p^,'. + \ '%W%f:%l: warning: %m,'. + \ '%Z%p^,'. + \ '%W%f:%l: %m,'. + \ '%-C%.%#' + + return { + \ 'exe': 'ruby', + \ 'args': ['-c', '-T1', '-w'], + \ 'errorformat': errorformat, + \ 'output_stream': 'both', + \ } +endfunction + +function! neomake#makers#ft#ruby#jruby() abort + let errorformat = + \ '%-GSyntax OK for %f,'. + \ '%ESyntaxError in %f:%l: syntax error\, %m,'. + \ '%Z%p^,'. + \ '%W%f:%l: warning: %m,'. + \ '%Z%p^,'. + \ '%W%f:%l: %m,'. + \ '%-C%.%#' + + return { + \ 'exe': 'jruby', + \ 'args': ['-c', '-T1', '-w'], + \ 'errorformat': errorformat + \ } +endfunction + +function! neomake#makers#ft#ruby#reek() abort + return { + \ 'args': ['--format', 'text', '--single-line'], + \ 'errorformat': '%W%f:%l: %m', + \ } +endfunction + +function! neomake#makers#ft#ruby#flog() abort + return { + \ 'errorformat': + \ '%W%m %f:%l-%c,' . + \ '%-G\s%#,' . + \ '%-G%.%#: flog total,' . + \ '%-G%.%#: flog/method average,' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/rust.vim b/bundle/neomake/autoload/neomake/makers/ft/rust.vim new file mode 100644 index 000000000..df86a576d --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/rust.vim @@ -0,0 +1,238 @@ +function! neomake#makers#ft#rust#EnabledMakers() abort + return ['cargo'] +endfunction + +function! neomake#makers#ft#rust#rustc() abort + return { + \ 'errorformat': + \ '%-Gerror: aborting due to previous error,'. + \ '%-Gerror: aborting due to %\\d%\\+ previous errors,'. + \ '%-Gerror: Could not compile `%s`.,'. + \ '%Eerror[E%n]: %m,'. + \ '%Eerror: %m,'. + \ '%Wwarning: %m,'. + \ '%Inote: %m,'. + \ '%-Z\ %#-->\ %f:%l:%c,'. + \ '%G\ %#\= %*[^:]: %m,'. + \ '%G\ %#|\ %#%\\^%\\+ %m,'. + \ '%I%>help:\ %#%m,'. + \ '%Z\ %#%m,'. + \ '%-G%.%#', + \ } +endfunction + +function! s:get_cargo_workspace_root() abort + if !exists('b:_neomake_cargo_workspace') + let cmd = 'cargo metadata --no-deps --format-version 1' + let [cd_error, cd_back_cmd] = neomake#utils#temp_cd(expand('%:h')) + if !empty(cd_error) + call neomake#log#debug(printf( + \ 's:get_cargo_workspace_root: failed to cd to buffer directory: %s.', + \ cd_error)) + endif + let output = system(cmd) + if !empty(cd_back_cmd) + exe cd_back_cmd + endif + if v:shell_error + call neomake#log#debug(printf( + \ 'Failed to get cargo metadata for workspace using %s.', + \ string(cmd))) + let b:_neomake_cargo_workspace = '' + else + let json = neomake#compat#json_decode(output) + let b:_neomake_cargo_workspace = json['workspace_root'] + endif + endif + return b:_neomake_cargo_workspace +endfunction + +function! s:get_cargo_maker_cwd(default) abort + let cargo_workspace_root = s:get_cargo_workspace_root() + if !empty(cargo_workspace_root) + return cargo_workspace_root + endif + + let cargo_toml = neomake#utils#FindGlobFile('Cargo.toml') + if !empty(cargo_toml) + return fnamemodify(cargo_toml, ':h') + endif + + return a:default +endfunction + +function! neomake#makers#ft#rust#cargotest() abort + " NOTE: duplicates are removed due to https://github.com/rust-lang/cargo/issues/5128. + let maker = { + \ 'exe': 'cargo', + \ 'args': ['test', '%:t:r', '--quiet'], + \ 'append_file': 0, + \ 'uses_filename': 0, + \ 'postprocess': copy(g:neomake#postprocess#remove_duplicates), + \ 'errorformat': + \ '%-G,' . + \ '%-Gtest %s,' . + \ '%-Grunning %\\d%# test%s,' . + \ '%-Gfailures:%s,' . + \ '%-G----%s,' . + \ '%-G%.%#--verbose%s,' . + \ '%-G%.%#--explain%s,' . + \ '%-Gerror: aborting due to previous error,' . + \ '%-G%\ %#error: aborting due to %\\d%#%\ %#previous errors,' . + \ '%E%\ %#error[E%n]:\ %m,' . + \ '%E%\ %#error:\ %m,' . + \ '%I%\ %#note:\ %m,'. + \ '%W%\ %#warning:\ %m,' . + \ '%-Z%\ %#-->\ %f:%l:%c,' . + \ '%-G%\\d%# %#|\ %s,' . + \ '%-G%\\d%# %#|,' . + \ '%-G\ %#\= %*[^:]:\ %m,'. + \ '%E%\ %#%m,' . + \ '%G%\ %#%s%\\,,' . + \ '%Z%\ %#%s%\\,%\\s%f:%l:%c' + \ } + + function! maker.InitForJob(_jobinfo) abort + if !has_key(self, 'cwd') + let self.cwd = s:get_cargo_maker_cwd('%:p:h') + return self + endif + endfunction + return maker +endfunction + +function! neomake#makers#ft#rust#cargo() abort + let maker_command = get(b:, 'neomake_rust_cargo_command', + \ get(g:, 'neomake_rust_cargo_command', ['check'])) + let maker = { + \ 'args': maker_command + ['--message-format=json', '--quiet'], + \ 'append_file': 0, + \ 'tempfile_enabled': 0, + \ 'process_output': function('neomake#makers#ft#rust#CargoProcessOutput'), + \ } + + function! maker.InitForJob(_jobinfo) abort + if !has_key(self, 'cwd') + let self.cwd = s:get_cargo_maker_cwd('%:p:h') + return self + endif + endfunction + return maker +endfunction + +" NOTE: does not use process_json, since cargo outputs multiple JSON root +" elements per line. +function! neomake#makers#ft#rust#CargoProcessOutput(context) abort + let errors = [] + for line in a:context['output'] + if line[0] !=# '{' + continue + endif + + let decoded = neomake#compat#json_decode(line) + let data = get(decoded, 'message', -1) + if type(data) != type({}) || empty(get(data, 'spans', [])) + " call neomake#log#debug(printf('cargo: ignoring input: %s.', line)) + continue + endif + + let error = {'maker_name': 'cargo'} + + let code_dict = get(data, 'code', -1) + if code_dict is g:neomake#compat#json_null + \ || index(['E', 'W'], code_dict['code'][0]) == -1 + let level = get(data, 'level', -1) + if level != -1 + let error.type = toupper(level[0]) + else + let error.type = 'W' + endif + else + let error.type = code_dict['code'][0] + let error.nr = str2nr(code_dict['code'][1:]) + endif + + let span = data.spans[0] + for candidate_span in data.spans + if candidate_span.is_primary + let span = candidate_span + break + endif + endfor + + let expanded = 0 + let has_expansion = type(span.expansion) == type({}) + \ && type(span.expansion.span) == type({}) + \ && type(span.expansion.def_site_span) == type({}) + + if span.file_name =~# '^<.*>$' && has_expansion + let expanded = 1 + call neomake#makers#ft#rust#FillErrorFromSpan(error, + \ span.expansion.span) + else + call neomake#makers#ft#rust#FillErrorFromSpan(error, span) + endif + + let error.text = data.message + let detail = span.label + let children = data.children + if type(detail) == type('') && !empty(detail) + let error.text = error.text . ': ' . detail + elseif !empty(children) && has_key(children[0], 'message') + let error.text = error.text . '. ' . children[0].message + endif + + call add(errors, error) + + if has_expansion && !expanded + let error = copy(error) + call neomake#makers#ft#rust#FillErrorFromSpan(error, + \ span.expansion.span) + call add(errors, error) + endif + + for child in children[1:] + if !has_key(child, 'message') + continue + endif + + let info = deepcopy(error) + let info.type = 'I' + let info.text = child.message + call neomake#postprocess#compress_whitespace(info) + if has_key(child, 'rendered') + \ && !(child.rendered is g:neomake#compat#json_null) + let info.text = info.text . ': ' . child.rendered + endif + + if len(child.spans) + let span = child.spans[0] + if span.file_name =~# '^<.*>$' + \ && type(span.expansion) == type({}) + \ && type(span.expansion.span) == type({}) + \ && type(span.expansion.def_site_span) == type({}) + call neomake#makers#ft#rust#FillErrorFromSpan(info, + \ span.expansion.span) + else + call neomake#makers#ft#rust#FillErrorFromSpan(info, span) + endif + let detail = span.label + if type(detail) == type('') && len(detail) + let info.text = info.text . ': ' . detail + endif + endif + + call add(errors, info) + endfor + endfor + return errors +endfunction + +function! neomake#makers#ft#rust#FillErrorFromSpan(error, span) abort + let a:error.filename = a:span.file_name + let a:error.col = a:span.column_start + let a:error.lnum = a:span.line_start + let a:error.length = a:span.byte_end - a:span.byte_start +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/scala.vim b/bundle/neomake/autoload/neomake/makers/ft/scala.vim new file mode 100644 index 000000000..08998812a --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/scala.vim @@ -0,0 +1,40 @@ +" vim: ts=4 sw=4 et +function! neomake#makers#ft#scala#EnabledMakers() abort + " use let g:neomake_scala_enabled_makers = ['fsc','scalastyle'] for fsc + let makers = ['scalac', 'scalastyle'] + return makers +endfunction + +function! neomake#makers#ft#scala#fsc() abort + return { + \ 'args': [ + \ '-Ystop-after:parser' + \ ], + \ 'errorformat': + \ '%E%f:%l: %trror: %m,' . + \ '%Z%p^,' . + \ '%-G%.%#' + \ } +endfunction + +function! neomake#makers#ft#scala#scalac() abort + return { + \ 'args': [ + \ '-Ystop-after:parser' + \ ], + \ 'errorformat': + \ '%E%f:%l: %trror: %m,' . + \ '%Z%p^,' . + \ '%-G%.%#' + \ } +endfunction + +function! neomake#makers#ft#scala#scalastyle() abort + return { + \ 'errorformat': + \ '%trror file=%f message=%m line=%l column=%c,' . + \ '%trror file=%f message=%m line=%l,' . + \ '%tarning file=%f message=%m line=%l column=%c,' . + \ '%tarning file=%f message=%m line=%l' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/scss.vim b/bundle/neomake/autoload/neomake/makers/ft/scss.vim new file mode 100644 index 000000000..e33ea6fc2 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/scss.vim @@ -0,0 +1,25 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#scss#EnabledMakers() abort + return executable('stylelint') ? ['stylelint'] : executable('sass-lint') ? ['sasslint'] : ['scsslint'] +endfunction + +function! neomake#makers#ft#scss#sasslint() abort + return { + \ 'exe': 'sass-lint', + \ 'args': ['--no-exit', '--verbose', '--format', 'compact'], + \ 'errorformat': neomake#makers#ft#javascript#eslint()['errorformat'] + \ } +endfunction + +function! neomake#makers#ft#scss#scsslint() abort + return { + \ 'exe': 'scss-lint', + \ 'errorformat': '%A%f:%l:%v [%t] %m,' . + \ '%A%f:%l [%t] %m' + \ } +endfunction + +function! neomake#makers#ft#scss#stylelint() abort + return neomake#makers#ft#css#stylelint() +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/serpent.vim b/bundle/neomake/autoload/neomake/makers/ft/serpent.vim new file mode 100644 index 000000000..eff20ba81 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/serpent.vim @@ -0,0 +1,13 @@ +function! neomake#makers#ft#serpent#EnabledMakers() abort + return ['serplint'] +endfunction + +function! neomake#makers#ft#serpent#serplint() abort + return { + \ 'exe': 'serplint', + \ 'args': [], + \ 'errorformat': + \ '%f:%l:%c %t%n %m', + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/sh.vim b/bundle/neomake/autoload/neomake/makers/ft/sh.vim new file mode 100644 index 000000000..00889b91e --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/sh.vim @@ -0,0 +1,86 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#sh#EnabledMakers() abort + return ['sh', 'shellcheck'] +endfunction + +let s:shellcheck = { + \ 'args': ['-fgcc', '-x'], + \ 'errorformat': + \ '%f:%l:%c: %trror: %m [SC%n],' . + \ '%f:%l:%c: %tarning: %m [SC%n],' . + \ '%I%f:%l:%c: Note: %m [SC%n]', + \ 'output_stream': 'stdout', + \ 'short_name': 'SC', + \ 'cwd': '%:h', + \ } + +function! neomake#makers#ft#sh#shellcheck() abort + let maker = deepcopy(s:shellcheck) + + let line1 = getline(1) + if match(line1, '\v^#!.*<%(sh|dash|bash|ksh)') < 0 + \ && match(line1, '\v^#\s*shellcheck\s+shell\=') < 0 + " shellcheck does not read the shebang by itself. + let ext = expand('%:e') + if ext ==# 'ksh' + let maker.args += ['-s', 'ksh'] + elseif ext ==# 'sh' + if exists('g:is_sh') + let maker.args += ['-s', 'sh'] + elseif exists('g:is_posix') || exists('g:is_kornshell') + let maker.args += ['-s', 'ksh'] + else + let maker.args += ['-s', 'bash'] + endif + else + let maker.args += ['-s', 'bash'] + endif + endif + return maker +endfunction + +function! neomake#makers#ft#sh#checkbashisms() abort + return { + \ 'args': ['-fx'], + \ 'errorformat': + \ '%-Gscript %f is already a bash script; skipping,' . + \ '%Eerror: %f: %m\, opened in line %l,' . + \ '%Eerror: %f: %m,' . + \ '%Ecannot open script %f for reading: %m,' . + \ '%Wscript %f %m,%C%.# lines,' . + \ '%Wpossible bashism in %f line %l (%m):,%C%.%#,%Z.%#,' . + \ '%-G%.%#', + \ 'output_stream': 'stderr', + \ } +endfunction + +function! neomake#makers#ft#sh#sh() abort + let shebang = matchstr(getline(1), '^#!\s*\zs.*$') + if !empty(shebang) + let l = split(shebang) + let exe = l[0] + let args = l[1:] + ['-n'] + else + let exe = '/usr/bin/env' + let args = ['sh', '-n'] + endif + + " NOTE: the format without "line" is used by dash. + return { + \ 'exe': exe, + \ 'args': args, + \ 'errorformat': + \ '%E%f: line %l: %m,' . + \ '%E%f: %l: %m', + \ 'output_stream': 'stderr', + \} +endfunction + +function! neomake#makers#ft#sh#dash() abort + return { + \ 'args': ['-n'], + \ 'errorformat': '%E%f: %l: %m', + \ 'output_stream': 'stderr', + \} +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/slim.vim b/bundle/neomake/autoload/neomake/makers/ft/slim.vim new file mode 100644 index 000000000..931f57fd9 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/slim.vim @@ -0,0 +1,13 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#slim#EnabledMakers() abort + return ['slimlint'] +endfunction + +function! neomake#makers#ft#slim#slimlint() abort + return { + \ 'exe': 'slim-lint', + \ 'args': ['--no-color'], + \ 'errorformat': '%f:%l [%t] %m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/sml.vim b/bundle/neomake/autoload/neomake/makers/ft/sml.vim new file mode 100644 index 000000000..46e0bd0e2 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/sml.vim @@ -0,0 +1,19 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#sml#EnabledMakers() abort + return ['smlnj'] +endfunction + +" This comes straight out of syntastic. +function! neomake#makers#ft#sml#smlnj() abort + return { + \ 'exe': 'sml', + \ 'errorformat': + \ '%E%f:%l%\%.%c %trror: %m,' . + \ '%E%f:%l%\%.%c-%\d%\+%\%.%\d%\+ %trror: %m,' . + \ '%W%f:%l%\%.%c %tarning: %m,' . + \ '%W%f:%l%\%.%c-%\d%\+%\%.%\d%\+ %tarning: %m,' . + \ '%C%\s%\+%m,' . + \ '%-G%.%#' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/solidity.vim b/bundle/neomake/autoload/neomake/makers/ft/solidity.vim new file mode 100644 index 000000000..200e910ea --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/solidity.vim @@ -0,0 +1,16 @@ +function! neomake#makers#ft#solidity#EnabledMakers() abort + return ['solium', 'solhint'] +endfunction + +function! neomake#makers#ft#solidity#solium() abort + return { + \ 'args': ['--reporter', 'gcc', '--file'], + \ 'errorformat': + \ '%f:%l:%c: %t%s: %m', + \ } +endfunction + +function! neomake#makers#ft#solidity#solhint() abort + return neomake#makers#ft#javascript#eslint() +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/spar.vim b/bundle/neomake/autoload/neomake/makers/ft/spar.vim new file mode 100644 index 000000000..9efe7a1ec --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/spar.vim @@ -0,0 +1,13 @@ +function! neomake#makers#ft#spar#EnabledMakers() abort + return ['spar'] +endfunction + +function! neomake#makers#ft#spar#spar() abort + return { + \ 'args': ['-g', '-c'], + \ 'errorformat': + \ '%f:%l:%c: %m', + \ 'nvim_job_opts': {'pty': 1} + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/spec.vim b/bundle/neomake/autoload/neomake/makers/ft/spec.vim new file mode 100644 index 000000000..272334019 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/spec.vim @@ -0,0 +1,16 @@ +function! neomake#makers#ft#spec#EnabledMakers() abort + return ['rpmlint'] +endfunction + +function! neomake#makers#ft#spec#rpmlint() abort + return { + \ 'errorformat': + \ '%E%f:%l: E: %m,' . + \ '%E%f: E: %m,' . + \ '%W%f:%l: W: %m,' . + \ '%W%f: W: %m,' . + \ '%-G%.%#' + \ } +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/sql.vim b/bundle/neomake/autoload/neomake/makers/ft/sql.vim new file mode 100644 index 000000000..bdbfdfa8f --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/sql.vim @@ -0,0 +1,13 @@ +function! neomake#makers#ft#sql#EnabledMakers() abort + return ['sqlint'] +endfunction + +function! neomake#makers#ft#sql#sqlint() abort + return { + \ 'errorformat': + \ '%E%f:%l:%c:ERROR %m,' . + \ '%W%f:%l:%c:WARNING %m,' . + \ '%C %m' + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/stylus.vim b/bundle/neomake/autoload/neomake/makers/ft/stylus.vim new file mode 100644 index 000000000..113a19484 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/stylus.vim @@ -0,0 +1,16 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#stylus#EnabledMakers() abort + return ['stylint'] +endfunction + +function! neomake#makers#ft#stylus#stylint() abort + return { + \ 'errorformat': + \ '%WWarning: %m,' . + \ '%EError: %m,' . + \ '%-Csee file: %f for the original selector,' . + \ '%CFile: %f,' . + \ '%ZLine: %l:%.%#' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/swift.vim b/bundle/neomake/autoload/neomake/makers/ft/swift.vim new file mode 100644 index 000000000..76bb4401b --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/swift.vim @@ -0,0 +1,54 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#swift#EnabledMakers() abort + if !empty(s:get_swiftpm_config()) + return ['swiftpm'] + endif + return ['swiftc'] +endfunction + +function! s:get_swiftpm_config() abort + return neomake#utils#FindGlobFile('Package.swift') +endfunction + +function! s:get_swiftpm_base_maker() abort + let maker = { + \ 'exe': 'swift', + \ 'append_file': 0, + \ 'errorformat': + \ '%E%f:%l:%c: error: %m,' . + \ '%E%f:%l: error: %m,' . + \ '%W%f:%l:%c: warning: %m,' . + \ '%Z%\s%#^~%#,' . + \ '%-G%.%#', + \ } + let config = s:get_swiftpm_config() + if !empty(config) + let maker.cwd = fnamemodify(config, ':h') + endif + return maker +endfunction + +function! neomake#makers#ft#swift#swiftpm() abort + let maker = s:get_swiftpm_base_maker() + let maker.args = ['build', '--build-tests'] + return maker +endfunction + +function! neomake#makers#ft#swift#swiftpmtest() abort + let maker = s:get_swiftpm_base_maker() + let maker.args = ['test'] + return maker +endfunction + +function! neomake#makers#ft#swift#swiftc() abort + " `export SDKROOT="$(xcodebuild -version -sdk macosx Path)"` + return { + \ 'args': ['-parse'], + \ 'errorformat': + \ '%E%f:%l:%c: error: %m,' . + \ '%W%f:%l:%c: warning: %m,' . + \ '%Z%\s%#^~%#,' . + \ '%-G%.%#', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/tcl.vim b/bundle/neomake/autoload/neomake/makers/ft/tcl.vim new file mode 100644 index 000000000..76c5af458 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/tcl.vim @@ -0,0 +1,15 @@ +function! neomake#makers#ft#tcl#EnabledMakers() abort + return ['nagelfar'] +endfunction + +function! neomake#makers#ft#tcl#nagelfar() abort + return { + \ 'exe': 'nagelfar', + \ 'args': ['-H'], + \ 'errorformat': + \ '%I%f: %l: N %m,' . + \ '%f: %l: %t %m,' . + \ '%-GChecking file %f' + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/tex.vim b/bundle/neomake/autoload/neomake/makers/ft/tex.vim new file mode 100644 index 000000000..9fca53be7 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/tex.vim @@ -0,0 +1,69 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#tex#EnabledMakers() abort + return ['chktex', 'lacheck', 'rubberinfo', 'proselint'] +endfunction + +function! neomake#makers#ft#tex#chktex() abort + let maker = { + \ 'args': [], + \ 'errorformat': + \ '%EError %n in %f line %l: %m,' . + \ '%WWarning %n in %f line %l: %m,' . + \ '%WMessage %n in %f line %l: %m,' . + \ '%Z%p^,' . + \ '%-G%.%#' + \ } + let rcfile = neomake#utils#FindGlobFile('.chktexrc') + if !empty(rcfile) + let maker.args += ['-l', fnamemodify(rcfile, ':h')] + endif + return maker +endfunction + +function! neomake#makers#ft#tex#lacheck() abort + return { + \ 'errorformat': + \ '%-G** %f:,' . + \ '%E"%f"\, line %l: %m' + \ } +endfunction + +function! neomake#makers#ft#tex#rubber() abort + return { + \ 'args': ['--pdf', '-f', '--warn=all'], + \ 'errorformat': + \ '%f:%l: %m,' . + \ '%f: %m' + \ } +endfunction + +function! neomake#makers#ft#tex#rubberinfo() abort + return { + \ 'exe': 'rubber-info', + \ 'errorformat': + \ '%f:%l: %m,' . + \ '%f:%l-%\d%\+: %m,' . + \ '%f: %m' + \ } +endfunction + +function! neomake#makers#ft#tex#latexrun() abort + return { + \ 'args': ['--color', 'never'], + \ 'errorformat': + \ '%f:%l: %m' + \ } +endfunction + +function! neomake#makers#ft#tex#pdflatex() abort + return { + \ 'exe': 'pdflatex', + \ 'args': ['-shell-escape', '-file-line-error', '-interaction', 'nonstopmode'], + \ 'errorformat': '%E%f:%l: %m' + \ } +endfunction + +function! neomake#makers#ft#tex#proselint() abort + return neomake#makers#ft#text#proselint() +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/text.vim b/bundle/neomake/autoload/neomake/makers/ft/text.vim new file mode 100644 index 000000000..a1ebe0a34 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/text.vim @@ -0,0 +1,30 @@ +function! neomake#makers#ft#text#EnabledMakers() abort + " No makers enabled by default, since text is used as fallback often. + return [] +endfunction + +function! neomake#makers#ft#text#proselint() abort + return { + \ 'errorformat': '%W%f:%l:%c: %m', + \ 'postprocess': function('neomake#postprocess#generic_length'), + \ } +endfunction + +function! neomake#makers#ft#text#PostprocessWritegood(entry) abort + let a:entry.col += 1 + if a:entry.text[0] ==# '"' + let matchend = match(a:entry.text, '\v^[^"]+\zs"', 1) + if matchend != -1 + let a:entry.length = matchend - 1 + endif + endif +endfunction + +function! neomake#makers#ft#text#writegood() abort + return { + \ 'args': ['--parse'], + \ 'errorformat': '%W%f:%l:%c:%m,%C%m,%-G', + \ 'postprocess': function('neomake#makers#ft#text#PostprocessWritegood'), + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/toml.vim b/bundle/neomake/autoload/neomake/makers/ft/toml.vim new file mode 100644 index 000000000..d3149114a --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/toml.vim @@ -0,0 +1,15 @@ +function! neomake#makers#ft#toml#EnabledMakers() abort + return ['tomlcheck'] +endfunction + +function! neomake#makers#ft#toml#tomlcheck() abort + return { + \ 'args': ['-f'], + \ 'errorformat': + \ '%E%f:%l:%c:,' . + \ '%E%m' + \ } +endfunction + +" vim: et sw=4 ts=4 +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/tsx.vim b/bundle/neomake/autoload/neomake/makers/ft/tsx.vim new file mode 100644 index 000000000..2a31b4d2b --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/tsx.vim @@ -0,0 +1,15 @@ +function! neomake#makers#ft#tsx#SupersetOf() abort + return 'typescript' +endfunction + +function! neomake#makers#ft#tsx#EnabledMakers() abort + return ['tsc', 'tslint'] +endfunction + +function! neomake#makers#ft#tsx#tsc() abort + let config = neomake#makers#ft#typescript#tsc() + let config.args = config.args + ['--jsx', 'preserve'] + return config +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/typescript.vim b/bundle/neomake/autoload/neomake/makers/ft/typescript.vim new file mode 100644 index 000000000..4d011b7bb --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/typescript.vim @@ -0,0 +1,45 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#typescript#EnabledMakers() abort + return ['tsc', 'tslint'] +endfunction + +function! neomake#makers#ft#typescript#tsc() abort + " tsc should not be passed a single file. + let maker = { + \ 'args': ['--noEmit', '--watch', 'false', '--pretty', 'false'], + \ 'append_file': 0, + \ 'errorformat': + \ '%E%f %#(%l\,%c): error %m,' . + \ '%E%f %#(%l\,%c): %m,' . + \ '%Eerror %m,' . + \ '%C%\s%\+%m' + \ } + let config = neomake#utils#FindGlobFile('tsconfig.json') + if !empty(config) + let maker.args += ['--project', config] + endif + return maker +endfunction + +function! neomake#makers#ft#typescript#tslint() abort + " NOTE: output format changed in tslint 5.12.0. + let maker = { + \ 'args': ['-t', 'prose'], + \ 'errorformat': '%-G,' + \ .'%EERROR: %f:%l:%c - %m,' + \ .'%WWARNING: %f:%l:%c - %m,' + \ .'%EERROR: %f[%l\, %c]: %m,' + \ .'%WWARNING: %f[%l\, %c]: %m', + \ } + let config = neomake#utils#FindGlobFile('tsconfig.json') + if !empty(config) + let maker.args += ['--project', config] + let maker.cwd = fnamemodify(config, ':h') + endif + return maker +endfunction + +function! neomake#makers#ft#typescript#eslint() abort + return neomake#makers#ft#javascript#eslint() +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/typescriptreact.vim b/bundle/neomake/autoload/neomake/makers/ft/typescriptreact.vim new file mode 100644 index 000000000..d558b5956 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/typescriptreact.vim @@ -0,0 +1,15 @@ +function! neomake#makers#ft#typescriptreact#SupersetOf() abort + return 'typescript' +endfunction + +function! neomake#makers#ft#typescriptreact#EnabledMakers() abort + return ['tsc', 'tslint'] +endfunction + +function! neomake#makers#ft#typescriptreact#tsc() abort + let config = neomake#makers#ft#typescript#tsc() + let config.args = config.args + ['--jsx', 'preserve'] + return config +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/verilog.vim b/bundle/neomake/autoload/neomake/makers/ft/verilog.vim new file mode 100644 index 000000000..78d918959 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/verilog.vim @@ -0,0 +1,16 @@ +function! neomake#makers#ft#verilog#EnabledMakers() abort + return ['iverilog'] +endfunction + +function! neomake#makers#ft#verilog#iverilog() abort + return { + \ 'args' : ['-tnull', '-Wall', '-y./'], + \ 'cwd' : '%:h', + \ 'errorformat' : '%f:%l: %trror: %m,' . + \ '%f:%l: %tarning: %m,' . + \ '%E%f:%l: : %m,' . + \ '%W%f:%l: : %m,' . + \ '%f:%l: %m', + \ } +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/vhdl.vim b/bundle/neomake/autoload/neomake/makers/ft/vhdl.vim new file mode 100644 index 000000000..dffa81356 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/vhdl.vim @@ -0,0 +1,12 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#vhdl#EnabledMakers() abort + return ['ghdl'] +endfunction + +function! neomake#makers#ft#vhdl#ghdl() abort + return { + \ 'args' : ['-s'], + \ 'errorformat' : '%E%f:%l:%c: %m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/vim.vim b/bundle/neomake/autoload/neomake/makers/ft/vim.vim new file mode 100644 index 000000000..8cd1318be --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/vim.vim @@ -0,0 +1,87 @@ +function! neomake#makers#ft#vim#EnabledMakers() abort + return ['vint'] +endfunction + +let s:slash = neomake#utils#Slash() +let s:neomake_root = expand(':p:h:h:h:h:h', 1) + +let s:vint_supports_stdin = {} + +function! neomake#makers#ft#vim#neomake_checks() abort + let maker = { + \ 'exe': join([s:neomake_root, 'contrib', 'vim-checks'], s:slash), + \ 'errorformat': '%f:%l: %m', + \ } + + return maker +endfunction + +function! neomake#makers#ft#vim#vint() abort + let args = ['--style-problem', '--no-color', + \ '-f', '{file_path}:{line_number}:{column_number}:{severity}:{description} ({policy_name})'] + + if has('nvim') + call add(args, '--enable-neovim') + endif + + let maker = { + \ 'args': args, + \ 'errorformat': '%I%f:%l:%c:style_problem:%m,' + \ .'%f:%l:%c:%t%*[^:]:E%n: %m,' + \ .'%f:%l:%c:%t%*[^:]:%m', + \ 'output_stream': 'stdout', + \ 'postprocess': { + \ 'fn': function('neomake#postprocess#generic_length'), + \ 'pattern': '\v%(^:|%([^:]+: ))\zs(\S+)', + \ }} + + function! maker.supports_stdin(_jobinfo) abort + let exe = exists('*exepath') ? exepath(self.exe) : self.exe + let support = get(s:vint_supports_stdin, exe, -1) + if support == -1 + let ver = neomake#compat#systemlist(['vint', '--version']) + let ver_split = split(ver[0], '\.') + if len(ver_split) > 1 && (ver_split[0] > 0 || +ver_split[1] >= 4) + let support = 1 + else + let support = 0 + endif + let s:vint_supports_stdin[exe] = support + call neomake#log#debug('vint: stdin support: '.support.'.') + endif + if support + let self.args += ['--stdin-display-name', '%:.'] + endif + return support + endfunction + return maker +endfunction + +function! neomake#makers#ft#vim#vimlint() abort + return { + \ 'args': ['-u'], + \ 'errorformat': '%f:%l:%c:%trror: EVL%n: %m,' + \ . '%f:%l:%c:%tarning: EVL%n: %m,' + \ . '%f:%l:%c:%t%*[^:]: EVP_%#E%#%n: %m', + \ 'postprocess': function('neomake#makers#ft#vim#PostprocessVimlint'), + \ 'output_stream': 'stdout', + \ } +endfunction + +function! neomake#makers#ft#vim#PostprocessVimlint(entry) abort + let m = matchlist(a:entry.text, '\v`\zs[^`]{-}\ze`') + if empty(m) + return + endif + + " Ensure that the text is there. + let l = len(m[0]) + let line = getline(a:entry.lnum) + if line[a:entry.col-1 : a:entry.col-2+l] == m[0] + let a:entry.length = l + elseif m[0][0:1] ==# 'l:' && line[a:entry.col-1 : a:entry.col-4+l] == m[0][2:] + " Ignore implicit 'l:' prefix. + let a:entry.length = l - 2 + endif +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/vue.vim b/bundle/neomake/autoload/neomake/makers/ft/vue.vim new file mode 100644 index 000000000..d9f530312 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/vue.vim @@ -0,0 +1,28 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#vue#EnabledMakers() abort + return ['eslint', 'standard'] +endfunction + +function! neomake#makers#ft#vue#eslint() abort + let maker = neomake#makers#ft#javascript#eslint() + call extend(get(maker, 'args', []), ['--plugin', 'html']) + return maker +endfunction + +function! neomake#makers#ft#vue#eslint_d() abort + return neomake#makers#ft#vue#eslint() +endfunction + +function! neomake#makers#ft#vue#standard() abort + let maker = neomake#makers#ft#javascript#standard() + call extend(get(maker, 'args', []), ['--plugin', 'html']) + return maker +endfunction + +function! neomake#makers#ft#vue#semistandard() abort + let maker = neomake#makers#ft#javascript#semistandard() + call extend(get(maker, 'args', []), ['--plugin', 'html']) + return maker +endfunction + diff --git a/bundle/neomake/autoload/neomake/makers/ft/xml.vim b/bundle/neomake/autoload/neomake/makers/ft/xml.vim new file mode 100644 index 000000000..75b699650 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/xml.vim @@ -0,0 +1,25 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#xml#EnabledMakers() abort + return ['xmllint'] +endfunction + +function! neomake#makers#ft#xml#xmllint() abort + let args = ['--xinclude', '--postvalid', '--noout'] + + return { + \ 'args': args, + \ 'supports_stdin': 1, + \ 'errorformat': + \ '%E%f:%l: error : %m,' . + \ '%-G%f:%l: validity error : Validation failed: no DTD found %m,' . + \ '%W%f:%l: warning : %m,' . + \ '%W%f:%l: validity warning : %m,' . + \ '%E%f:%l: validity error : %m,' . + \ '%E%f:%l: parser error : %m,' . + \ '%E%f:%l: %m,' . + \ '%-Z%p^,' . + \ '%-C%.%#,' . + \ '%-G%.%#', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/xslt.vim b/bundle/neomake/autoload/neomake/makers/ft/xslt.vim new file mode 100644 index 000000000..61bcf02aa --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/xslt.vim @@ -0,0 +1,8 @@ +function! neomake#makers#ft#xslt#EnabledMakers() abort + return ['xmllint'] +endfunction + +function! neomake#makers#ft#xslt#xmllint() abort + return neomake#makers#ft#xml#xmllint() +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/makers/ft/yacc.vim b/bundle/neomake/autoload/neomake/makers/ft/yacc.vim new file mode 100644 index 000000000..8a2edd526 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/yacc.vim @@ -0,0 +1,17 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#yacc#EnabledMakers() abort + return ['bison'] +endfunction + +function! neomake#makers#ft#yacc#bison() abort + return { + \ 'errorformat': + \ '%E%f:%l%.%v-%.%\{-}: %trror: %m,' . + \ '%E%f:%l%.%v: %trror: %m,' . + \ '%W%f:%l%.%v-%.%\{-}: %tarning: %m,' . + \ '%W%f:%l%.%v: %tarning: %m,' . + \ '%I%f:%l%.%v-%.%\{-}: %\s%\+%m,' . + \ '%I%f:%l%.%v: %\s%\+%m' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/yaml.vim b/bundle/neomake/autoload/neomake/makers/ft/yaml.vim new file mode 100644 index 000000000..338ca8cf3 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/yaml.vim @@ -0,0 +1,12 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#yaml#EnabledMakers() abort + return ['yamllint'] +endfunction + +function! neomake#makers#ft#yaml#yamllint() abort + return { + \ 'args': ['-f', 'parsable'], + \ 'errorformat': '%E%f:%l:%c: [error] %m,%W%f:%l:%c: [warning] %m', + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/ft/zsh.vim b/bundle/neomake/autoload/neomake/makers/ft/zsh.vim new file mode 100644 index 000000000..a63e365f2 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/ft/zsh.vim @@ -0,0 +1,19 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#ft#zsh#EnabledMakers() abort + return ['zsh'] +endfunction + +" Note: newer versions of shellcheck do not support zsh. +function! neomake#makers#ft#zsh#shellcheck() abort + let maker = neomake#makers#ft#sh#shellcheck() + let maker.args += ['--shell', 'zsh'] + return maker +endfunction + +function! neomake#makers#ft#zsh#zsh() abort + return { + \ 'args': ['-n'], + \ 'errorformat': '%E%f:%l: %m' + \} +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/gradle.vim b/bundle/neomake/autoload/neomake/makers/gradle.vim new file mode 100644 index 000000000..de892a7ee --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/gradle.vim @@ -0,0 +1,28 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#gradle#gradle() abort + let g:gradleBin = filereadable('./gradlew') ? './gradlew' : 'gradle' + + return { + \ 'exe': g:gradleBin, + \ 'append_file': 0, + \ 'args': ['assemble', '--daemon'], + \ 'errorformat': '\%+ATask\ %.%#\ not\ found\ %.%#.,'. + \'%EExecution\ failed\ for\ task\ %m,'. + \'findbugs:\ %tarning\ %f:%l:%c\ %m,'. + \'pmd:\ %tarning\ %f:%l:%c\ %m,'. + \'checkstyle:\ %tarning\ %f:%l:%c\ %m,'. + \'lint:\ %tarning\ %f:%l:%c\ %m,'. + \'%A>\ %f:%l:%c:\ %trror:\ %m,'. + \'%A>\ %f:%l:%c:\ %tarning:\ %m,'. + \'%A%f:%l:\ %trror:\ %m,'. + \'%A%f:%l:\ %tarning:\ %m,'. + \'%A%f:%l:\ %trror\ -\ %m,'. + \'%A%f:%l:\ %tarning\ -\ %m,'. + \'%E%f:%l\ :\ %m,'. + \'%C>\ %m,'. + \'%-G%p^,'. + \'%+G\ \ %.%#,'. + \'%-G%.%#' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/mvn.vim b/bundle/neomake/autoload/neomake/makers/mvn.vim new file mode 100644 index 000000000..cac2a80f5 --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/mvn.vim @@ -0,0 +1,9 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#mvn#mvn() abort + return { + \ 'exe': 'mvn', + \ 'args': ['install'], + \ 'errorformat': '[%tRROR]\ %f:[%l]\ %m,%-G%.%#' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/makers/sbt.vim b/bundle/neomake/autoload/neomake/makers/sbt.vim new file mode 100644 index 000000000..93e233bbd --- /dev/null +++ b/bundle/neomake/autoload/neomake/makers/sbt.vim @@ -0,0 +1,13 @@ +" vim: ts=4 sw=4 et + +function! neomake#makers#sbt#sbt() abort + return { + \ 'exe': 'sbt', + \ 'args': ['-Dsbt.log.noformat=true', 'compile'], + \ 'errorformat': + \ '%E[%trror]\ %f:%l:%c:\ %m,' . + \ '%-Z[error]\ %p^,' . + \ '%-C%.%#,' . + \ '%-G%.%#' + \ } +endfunction diff --git a/bundle/neomake/autoload/neomake/postprocess.vim b/bundle/neomake/autoload/neomake/postprocess.vim new file mode 100644 index 000000000..d92a89792 --- /dev/null +++ b/bundle/neomake/autoload/neomake/postprocess.vim @@ -0,0 +1,77 @@ +" Generic postprocessor to add `length` to `a:entry`. +" The pattern can be overridden on `self` and should adhere to this: +" - the matched word should be returned as the whole match (you can use \zs +" and \ze). +" - enclosing patterns should be returned as \1 and \2, where \1 is used as +" offset when the first entry did not match. +" See tests/postprocess.vader for tests/examples. +" See neomake#postprocess#generic_length_with_pattern for a non-dict variant. +function! neomake#postprocess#generic_length(entry) abort dict + if a:entry.lnum > 0 && a:entry.col + let pattern = get(self, 'pattern', '\v(["''`])\zs[^\1]{-}\ze(\1)') + let start = 0 + let best = 0 + while 1 + let m = matchlist(a:entry.text, pattern, start) + if empty(m) + break + endif + let l = len(m[0]) + if l > best + " Ensure that the text is there. + let line = get(getbufline(a:entry.bufnr, a:entry.lnum), 0, '') + if line[a:entry.col-1 : a:entry.col-2+l] == m[0] + let best = l + endif + endif + if exists('*matchstrpos') " vim73 + let pos = matchstrpos(a:entry.text, pattern, start) + if pos[1] == -1 + break + endif + let start += pos[2] + len(m[2]) + else + break + endif + endwhile + if best + let a:entry.length = best + endif + endif +endfunction + +" Wrapper to call neomake#process#generic_length (a dict function). +function! neomake#postprocess#generic_length_with_pattern(entry, pattern) abort + let this = {'pattern': a:pattern} + return call('neomake#postprocess#generic_length', [a:entry], this) +endfunction + +" Deprecated: renamed to neomake#postprocess#generic_length. +function! neomake#postprocess#GenericLengthPostprocess(entry) abort dict + return neomake#postprocess#generic_length(a:entry) +endfunction + +function! neomake#postprocess#compress_whitespace(entry) abort + let text = a:entry.text + let text = substitute(text, "\001", '', 'g') + let text = substitute(text, '\r\?\n', ' ', 'g') + let text = substitute(text, '\m\s\{2,}', ' ', 'g') + let text = substitute(text, '\m^\s\+', '', '') + let text = substitute(text, '\m\s\+$', '', '') + let a:entry.text = text +endfunction + +let g:neomake#postprocess#remove_duplicates = {} +function! g:neomake#postprocess#remove_duplicates.fn(entry) abort + if exists('self._seen_entries') + if index(self._seen_entries, a:entry) != -1 + let a:entry.valid = -1 + else + call add(self._seen_entries, a:entry) + endif + else + let self._seen_entries = [a:entry] + endif +endfunction +lockvar g:neomake#postprocess#remove_duplicates " Needs to be copied. +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/quickfix.vim b/bundle/neomake/autoload/neomake/quickfix.vim new file mode 100644 index 000000000..58751450a --- /dev/null +++ b/bundle/neomake/autoload/neomake/quickfix.vim @@ -0,0 +1,377 @@ +" vim: ts=4 sw=4 et +scriptencoding utf-8 + +let s:is_enabled = 0 + +let s:match_base_priority = 10 + +" args: a:1: force enabling? (used in tests and for VimEnter callback) +function! neomake#quickfix#enable(...) abort + if has('vim_starting') && !(a:0 && a:1) + " Delay enabling for our FileType autocommand to happen as late as + " possible, since placing signs triggers a redraw, and together with + " vim-qf_resize this causes flicker. + " https://github.com/vim/vim/issues/2763 + augroup neomake_qf + autocmd! + autocmd VimEnter * call neomake#quickfix#enable(1) + augroup END + return + endif + call neomake#log#debug('enabling custom quickfix list handling.') + let s:is_enabled = 1 + augroup neomake_qf + autocmd! + autocmd FileType qf if get(b:, 'current_syntax', '') !=# 'neomake_qf' + \ | call neomake#quickfix#FormatQuickfix() + \ | endif + augroup END + if &filetype ==# 'qf' + call neomake#quickfix#FormatQuickfix() + endif +endfunction + +function! neomake#quickfix#disable() abort + call neomake#log#debug('disabling custom quickfix list handling.') + let s:is_enabled = 0 + if &filetype ==# 'qf' + call neomake#quickfix#FormatQuickfix() + endif + if exists('#neomake_qf') + autocmd! neomake_qf + augroup! neomake_qf + endif +endfunction + +function! neomake#quickfix#is_enabled() abort + return s:is_enabled +endfunction + +function! s:highlight_cursor_listnr() abort + if col('.') <= b:neomake_start_col + 1 + call cursor(line('.'), b:neomake_start_col + 2) + endif + + " Update neomakeCursorListNr, but not with :syntax-off. + if empty(get(b:, 'current_syntax', '')) + return + endif + if exists('w:_neomake_cursor_match_id') + silent! call matchdelete(w:_neomake_cursor_match_id) + endif + if exists('*matchaddpos') + let w:_neomake_cursor_match_id = matchaddpos('neomakeCursorListNr', + \ [[line('.'), (b:neomake_start_col - b:neomake_number_len) + 2, b:neomake_number_len]], + \ s:match_base_priority+3) + else + let w:_neomake_cursor_match_id = matchadd('neomakeCursorListNr', + \ '\%' . line('.') . 'c' + \. '\%' . ((b:neomake_start_col - b:neomake_number_len) + 2) . 'c' + \. '.\{' . b:neomake_number_len . '}', + \ s:match_base_priority+3) + endif +endfunction + +function! s:set_qf_lines(lines) abort + let ul = &l:undolevels + setlocal modifiable nonumber undolevels=-1 + + call setline(1, a:lines) + + let &l:undolevels = ul + setlocal nomodifiable nomodified +endfunction + +function! s:clean_qf_annotations() abort + call neomake#log#debug('cleaning qf annotations.', {'bufnr': bufnr('%')}) + if exists('b:_neomake_qf_orig_lines') + call s:set_qf_lines(b:_neomake_qf_orig_lines) + unlet b:_neomake_qf_orig_lines + endif + unlet b:neomake_qf + augroup neomake_qf + autocmd! * + augroup END + + call s:clean_matches() +endfunction + +function! s:clean_matches() abort + if exists('w:_neomake_maker_match_id') + silent! call matchdelete(w:_neomake_maker_match_id) + endif + if exists('w:_neomake_gutter_match_id') + silent! call matchdelete(w:_neomake_gutter_match_id) + endif + if exists('w:_neomake_bufname_match_id') + silent! call matchdelete(w:_neomake_bufname_match_id) + endif + if exists('w:_neomake_cursor_match_id') + silent! call matchdelete(w:_neomake_cursor_match_id) + endif + call neomake#signs#ResetFile(bufnr('%')) +endfunction + +function! neomake#quickfix#_get_list() abort + if has('patch-7.4.2215') + let is_loclist = getwininfo(win_getid())[0].loclist + if is_loclist + let qflist = getloclist(0) + else + let qflist = getqflist() + endif + else + let is_loclist = 1 + let qflist = getloclist(0) + if empty(qflist) + let is_loclist = 0 + let qflist = getqflist() + endif + endif + return [is_loclist, qflist] +endfunction + +function! neomake#quickfix#FormatQuickfix() abort + if !s:is_enabled || &filetype !=# 'qf' + if exists('b:neomake_qf') + call s:clean_qf_annotations() + endif + return + endif + + let [is_loclist, qflist] = neomake#quickfix#_get_list() + + if empty(qflist) || qflist[0].text !~# ' nmcfg:{.\{-}}$' + if exists('b:neomake_qf') + call neomake#log#debug('Resetting custom qf for non-Neomake change.') + call s:clean_qf_annotations() + endif + return + endif + + if is_loclist + let b:neomake_qf = 'file' + let src_buf = qflist[0].bufnr + else + let b:neomake_qf = 'project' + let src_buf = 0 + endif + + let lines = [] + let signs = [] + let i = 0 + let lnum_width = 0 + let col_width = 0 + let maker_width = 0 + let nmcfg = {} + let makers = {} + + for item in qflist + " Look for marker at end of entry. + if item.text[-1:] ==# '}' + let idx = strridx(item.text, ' nmcfg:{') + if idx != -1 + let config = item.text[idx+7:] + try + let nmcfg = eval(config) + if !has_key(makers, nmcfg.name) + let makers[nmcfg.name] = 0 + endif + let item.text = idx == 0 ? '' : item.text[:(idx-1)] + catch + call neomake#log#exception(printf( + \ 'Error when evaluating nmcfg (%s): %s.', + \ config, v:exception)) + endtry + endif + endif + + " Count entries. + if !empty(nmcfg) + let makers[nmcfg.name] += 1 + endif + + let item.maker_name = get(nmcfg, 'short', '????') + let maker_width = max([len(item.maker_name), maker_width]) + + if item.lnum + let lnum_width = max([len(item.lnum), lnum_width]) + let col_width = max([len(item.col), col_width]) + endif + + let i += 1 + endfor + + let syntax = keys(makers) + if src_buf + for ft in split(neomake#compat#getbufvar(src_buf, '&filetype', ''), '\.') + if !empty(ft) && index(syntax, ft) == -1 + call add(syntax, ft) + endif + endfor + endif + + let current_syntax = get(b:, 'current_syntax', '') + if !empty(current_syntax) " not with :syntax-off. + runtime! syntax/neomake/qf.vim + for name in syntax + execute 'runtime! syntax/neomake/'.name.'.vim ' + \ . 'syntax/neomake/'.name.'/*.vim' + endfor + endif + + if maker_width + lnum_width + col_width > 0 + let b:neomake_start_col = maker_width + lnum_width + col_width + 2 + let b:neomake_number_len = lnum_width + col_width + 2 + let blank_col = repeat(' ', lnum_width + col_width + 1) + else + let b:neomake_start_col = 0 + let b:neomake_number_len = 0 + let blank_col = '' + endif + + " Count number of different buffers and cache their names. + let buffers = neomake#compat#uniq(sort( + \ filter(map(copy(qflist), 'v:val.bufnr'), 'v:val != 0'))) + let buffer_names = {} + if len(buffers) > 1 + for b in buffers + let bufname = bufname(b) + if empty(bufname) + let bufname = 'buf:'.b + else + let bufname = fnamemodify(bufname, ':t') + if len(bufname) > 15 + let bufname = bufname[0:13].'…' + endif + endif + let buffer_names[b] = bufname + endfor + endif + + let i = 1 + let buf = bufnr('%') + let last_bufnr = -1 + for item in qflist + if item.lnum + call add(signs, {'lnum': i, 'bufnr': buf, 'type': item.type}) + endif + let i += 1 + + let text = item.text + if item.bufnr != 0 && !empty(buffer_names) + if last_bufnr != item.bufnr + let text = printf('[%s] %s', buffer_names[item.bufnr], text) + let last_bufnr = item.bufnr + endif + endif + + if !item.lnum + call add(lines, printf('%*s %s %s', + \ maker_width, item.maker_name, + \ blank_col, text)) + else + call add(lines, printf('%*s %*s:%*s %s', + \ maker_width, item.maker_name, + \ lnum_width, item.lnum, + \ col_width, item.col ? item.col : '-', + \ text)) + endif + endfor + + if !exists('b:_neomake_qf_orig_lines') + let b:_neomake_qf_orig_lines = getbufline('%', 1, '$') + endif + call s:set_qf_lines(lines) + + if exists('+breakindent') + " Keeps the text aligned with the fake gutter. + setlocal breakindent linebreak + let &breakindentopt = 'shift:'.(b:neomake_start_col + 1) + endif + + call neomake#signs#Reset(buf, 'file') + call neomake#signs#PlaceSigns(buf, signs, 'file') + + augroup neomake_qf + autocmd! * + autocmd CursorMoved call s:highlight_cursor_listnr() + + if !empty(current_syntax) " not with :syntax-off. + call s:add_window_matches(maker_width) + + " Annotate in new window, e.g. with "tab sp". + " It keeps the syntax there, so should also have the rest. + " This happens on Neovim already through CursorMoved being invoked + " always then. + if exists('##WinNew') + exe 'autocmd WinNew call s:add_window_matches('.maker_width.')' + endif + + " Clear matches when opening another buffer in the same window, with + " the original window/buffer still being visible (e.g. in another + " tab). + autocmd BufLeave call s:on_bufleave() + endif + augroup END + + " Set title. + " Fallback without patch-7.4.2200, fix for without 8.0.1831. + if !has('patch-7.4.2200') || !exists('w:quickfix_title') || w:quickfix_title[0] ==# ':' + let maker_info = [] + for [maker, c] in items(makers) + call add(maker_info, maker.'('.c.')') + endfor + let maker_info_str = join(maker_info, ', ') + if is_loclist + let prefix = 'file' + else + let prefix = 'project' + endif + let w:quickfix_title = neomake#list#get_title(prefix, src_buf, maker_info_str) + endif +endfunction + +function! s:on_bufleave() abort + let s:left_winnr = winnr() + augroup neomake_qf + autocmd BufEnter * call s:on_bufenter_after_bufleave() + augroup END +endfunction + +function! s:on_bufenter_after_bufleave() abort + if winnr() == s:left_winnr + call s:clean_matches() + endif + unlet s:left_winnr + augroup neomake_qf + autocmd! BufEnter + augroup END +endfunction + +function! s:add_window_matches(maker_width) abort + if !b:neomake_start_col + return + endif + if exists('w:_neomake_maker_match_id') + silent! call matchdelete(w:_neomake_maker_match_id) + endif + let w:_neomake_maker_match_id = matchadd('neomakeMakerName', + \ '.*\%<'.(a:maker_width + 1).'c', + \ s:match_base_priority+1) + if exists('w:_neomake_gutter_match_id') + silent! call matchdelete(w:_neomake_gutter_match_id) + endif + let w:_neomake_gutter_match_id = matchadd('neomakeListNr', + \ '\%>'.(a:maker_width).'c' + \ .'.*\%<'.(b:neomake_start_col + 2).'c', + \ s:match_base_priority+2) + if exists('w:_neomake_bufname_match_id') + silent! call matchdelete(w:_neomake_bufname_match_id) + endif + let w:_neomake_bufname_match_id = matchadd('neomakeBufferName', + \ '.*\%<'.(a:maker_width + 1).'c', + \ s:match_base_priority+3) + + call s:highlight_cursor_listnr() +endfunction diff --git a/bundle/neomake/autoload/neomake/setup.vim b/bundle/neomake/autoload/neomake/setup.vim new file mode 100644 index 000000000..e0c52980a --- /dev/null +++ b/bundle/neomake/autoload/neomake/setup.vim @@ -0,0 +1,37 @@ +if has('signs') + let g:neomake_place_signs = get(g:, 'neomake_place_signs', 1) +else + let g:neomake_place_signs = 0 + lockvar g:neomake_place_signs +endif + +function! neomake#setup#define_highlights() abort + if g:neomake_place_signs + call neomake#signs#DefineHighlights() + endif + if get(g:, 'neomake_highlight_columns', 1) + \ || get(g:, 'neomake_highlight_lines', 0) + call neomake#highlights#DefineHighlights() + endif +endfunction + +function! neomake#setup#setup_autocmds() abort + augroup neomake + au! + if !exists('*nvim_buf_add_highlight') + autocmd BufEnter * call neomake#highlights#ShowHighlights() + endif + if has('timers') + autocmd CursorMoved * call neomake#CursorMovedDelayed() + " Force-redraw display of current error after resizing Vim, which appears + " to clear the previously echoed error. + autocmd VimResized * call timer_start(100, function('neomake#EchoCurrentError')) + else + autocmd CursorHold,CursorHoldI * call neomake#CursorMoved() + endif + autocmd VimLeave * call neomake#VimLeave() + autocmd ColorScheme * call neomake#setup#define_highlights() + augroup END +endfunction + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/signs.vim b/bundle/neomake/autoload/neomake/signs.vim new file mode 100644 index 000000000..d313448ad --- /dev/null +++ b/bundle/neomake/autoload/neomake/signs.vim @@ -0,0 +1,299 @@ +" vim: ts=4 sw=4 et +scriptencoding utf-8 + +if !has('signs') + call neomake#log#error('Trying to load signs.vim, without +signs.') + finish +endif + +let s:base_sign_id = 5000 +let s:placed_signs = {'project': {}, 'file': {}} +let s:last_placed_signs = {'project': {}, 'file': {}} + +exe 'sign define neomake_invisible' + +" Reset signs placed by a :Neomake! call +function! neomake#signs#ResetProject() abort + for buf in keys(s:placed_signs.project) + call neomake#signs#Reset(buf, 'project') + call neomake#signs#CleanOldSigns(buf, 'project') + endfor +endfunction + +" Reset signs placed by a :Neomake call in a buffer +function! neomake#signs#ResetFile(bufnr) abort + call neomake#signs#Reset(a:bufnr, 'file') + call neomake#signs#CleanOldSigns(a:bufnr, 'file') +endfunction + +function! neomake#signs#Reset(bufnr, type) abort + if has_key(s:placed_signs[a:type], a:bufnr) + " Clean any lingering, already retired signs. + call neomake#signs#CleanOldSigns(a:bufnr, a:type) + let s:last_placed_signs[a:type][a:bufnr] = s:placed_signs[a:type][a:bufnr] + unlet s:placed_signs[a:type][a:bufnr] + endif +endfunction + +let s:sign_order = {'neomake_file_err': 0, 'neomake_file_warn': 1, + \ 'neomake_file_info': 2, 'neomake_file_msg': 3, + \ 'neomake_project_err': 4, 'neomake_project_warn': 5, + \ 'neomake_project_info': 6, 'neomake_project_msg': 7} + +" Get the defined signs for a:bufnr. +" It returns a dictionary with line numbers as keys. +function! neomake#signs#by_lnum(bufnr) abort + let bufnr = a:bufnr + 0 + if !bufexists(bufnr) + return {} + endif + + let r = {} + if exists('*sign_getplaced') " patch-8.1.0614 + for sign in sign_getplaced(bufnr)[0].signs + if has_key(r, sign.lnum) + call add(r[sign.lnum], [sign.id, sign.name]) + else + let r[sign.lnum] = [[sign.id, sign.name]] + endif + endfor + return r + endif + + let signs_output = split(neomake#utils#redir('sign place buffer='.a:bufnr), '\n') + + " Originally via ALE. + " Matches output like : + " line=4 id=1 name=neomake_err + " строка=1 id=1000001 имя=neomake_err + " 行=1 識別子=1000001 名前=neomake_err + " línea=12 id=1000001 nombre=neomake_err + " riga=1 id=1000001, nome=neomake_err + for line in reverse(signs_output[2:]) + " XXX: does not really match "name=" + " (broken by patch-8.1.0614, but handled above) + let sign_type = line[strridx(line, '=')+1:] + let lnum_idx = stridx(line, '=') + let lnum = line[lnum_idx+1:] + 0 + if lnum + let sign_id = line[stridx(line, '=', lnum_idx+1)+1:] + 0 + if has_key(r, lnum) + call insert(r[lnum], [sign_id, sign_type]) + else + let r[lnum] = [[sign_id, sign_type]] + endif + endif + endfor + return r +endfunction + +let s:entry_to_sign_type = {'W': 'warn', 'I': 'info', 'M': 'msg'} + +" Place signs for list a:entries in a:bufnr for a:type ('file' or 'project'). +" List items in a:entries need to have a "type" and "lnum" (non-zero) property. +function! neomake#signs#PlaceSigns(bufnr, entries, type) abort + " Query the list of currently placed signs. + " This allows to cope with movements, e.g. when lines were added. + let all_placed_signs = neomake#signs#by_lnum(a:bufnr) + let placed_signs = filter(map(copy(all_placed_signs), + \ 'filter(copy(v:val), "v:val[1] =~# ''^neomake_''")'), + \ '!empty(v:val)') + + " TEMP: use the first sign only for now. + call map(placed_signs, 'v:val[0]') + + let entries_by_linenr = {} + for entry in a:entries + let lnum = entry.lnum + let sign_type = printf('neomake_%s_%s', + \ a:type, + \ get(s:entry_to_sign_type, toupper(entry.type), 'err')) + if !exists('entries_by_linenr[lnum]') + \ || s:sign_order[entries_by_linenr[lnum]] + \ > s:sign_order[sign_type] + let entries_by_linenr[lnum] = sign_type + endif + endfor + + let place_new = [] + let log_context = {'bufnr': a:bufnr} + let count_reused = 0 + for [lnum, sign_type] in items(entries_by_linenr) + let existing_sign = get(placed_signs, lnum, []) + if empty(existing_sign) || existing_sign[1] !~# '^neomake_'.a:type.'_' + call add(place_new, [lnum, sign_type]) + continue + endif + + let sign_id = existing_sign[0] + if existing_sign[1] == sign_type + let count_reused += 1 + " call neomake#log#debug(printf( + " \ 'Reusing sign: id=%d, type=%s, lnum=%d.', + " \ sign_id, existing_sign[1], lnum), log_context) + else + let cmd = printf('sign place %s name=%s buffer=%d', + \ sign_id, sign_type, a:bufnr) + call neomake#log#debug('Upgrading sign for lnum='.lnum.': '.cmd.'.', log_context) + exe cmd + endif + + " Keep this sign from being cleaned. + if exists('s:last_placed_signs[a:type][a:bufnr][sign_id]') + unlet s:last_placed_signs[a:type][a:bufnr][sign_id] + endif + endfor + if count_reused + call neomake#log#debug(printf('Reused %d signs.', count_reused), log_context) + endif + + for [lnum, sign_type] in place_new + if !exists('next_sign_id') + if !empty(all_placed_signs) + let next_sign_id = max(map(map(values(all_placed_signs), 'map(copy(v:val), ''v:val[0]'')'), 'v:val[0]')) + 1 + if next_sign_id < s:base_sign_id + let next_sign_id = s:base_sign_id + endif + else + let next_sign_id = s:base_sign_id + endif + else + let next_sign_id += 1 + endif + let cmd = 'sign place '.next_sign_id.' line='.lnum. + \ ' name='.sign_type. + \ ' buffer='.a:bufnr + call neomake#log#debug('Placing sign: '.cmd.'.', log_context) + let placed_signs[lnum] = [next_sign_id, sign_type] + exe cmd + endfor + + let s:placed_signs[a:type][a:bufnr] = {} + for [lnum, sign_info] in items(placed_signs) + let s:placed_signs[a:type][a:bufnr][sign_info[0]] = sign_info[1] + endfor +endfunction + +function! neomake#signs#CleanAllOldSigns(type) abort + call neomake#log#debug_obj('Removing signs', s:last_placed_signs) + for buf in keys(s:last_placed_signs[a:type]) + call neomake#signs#CleanOldSigns(buf, a:type) + endfor +endfunction + +" type may be either 'file' or 'project' +function! neomake#signs#CleanOldSigns(bufnr, type) abort + if !has_key(s:last_placed_signs[a:type], a:bufnr) + return + endif + let placed_signs = s:last_placed_signs[a:type][a:bufnr] + unlet s:last_placed_signs[a:type][a:bufnr] + if bufexists(+a:bufnr) + call neomake#log#debug(printf('Cleaning %d old signs.', len(placed_signs)), {'bufnr': a:bufnr}) + for sign_id in keys(placed_signs) + exe 'sign unplace '.sign_id.' buffer='.a:bufnr + if has_key(s:placed_signs[a:type], a:bufnr) + if has_key(s:placed_signs[a:type][a:bufnr], sign_id) + unlet s:placed_signs[a:type][a:bufnr][sign_id] + endif + endif + endfor + else + call neomake#log#debug_obj('Skipped cleaning of old signs in non-existing buffer '.a:bufnr, placed_signs) + endif +endfunction + +function! neomake#signs#RedefineSign(name, opts) abort + let sign_define = 'sign define '.a:name + for attr in keys(a:opts) + let sign_define .= ' '.attr.'='.a:opts[attr] + endfor + call neomake#log#debug(printf('Defining sign: %s.', sign_define)) + exe sign_define +endfunction + +function! neomake#signs#RedefineErrorSign(...) abort + let default_opts = {'text': '✖', 'texthl': 'NeomakeErrorSign'} + let opts = {} + if a:0 + call extend(opts, a:1) + elseif exists('g:neomake_error_sign') + call extend(opts, g:neomake_error_sign) + endif + call extend(opts, default_opts, 'keep') + call neomake#signs#RedefineSign('neomake_file_err', opts) + call neomake#signs#RedefineSign('neomake_project_err', opts) +endfunction + +function! neomake#signs#RedefineWarningSign(...) abort + let default_opts = {'text': '‼', 'texthl': 'NeomakeWarningSign'} + let opts = {} + if a:0 + call extend(opts, a:1) + elseif exists('g:neomake_warning_sign') + call extend(opts, g:neomake_warning_sign) + endif + call extend(opts, default_opts, 'keep') + call neomake#signs#RedefineSign('neomake_file_warn', opts) + call neomake#signs#RedefineSign('neomake_project_warn', opts) +endfunction + +function! neomake#signs#RedefineMessageSign(...) abort + let default_opts = {'text': '➤', 'texthl': 'NeomakeMessageSign'} + let opts = {} + if a:0 + call extend(opts, a:1) + elseif exists('g:neomake_message_sign') + call extend(opts, g:neomake_message_sign) + endif + call extend(opts, default_opts, 'keep') + call neomake#signs#RedefineSign('neomake_file_msg', opts) + call neomake#signs#RedefineSign('neomake_project_msg', opts) +endfunction + +function! neomake#signs#RedefineInfoSign(...) abort + let default_opts = {'text': 'ℹ', 'texthl': 'NeomakeInfoSign'} + let opts = {} + if a:0 + call extend(opts, a:1) + elseif exists('g:neomake_info_sign') + call extend(opts, g:neomake_info_sign) + endif + call extend(opts, default_opts, 'keep') + call neomake#signs#RedefineSign('neomake_file_info', opts) + call neomake#signs#RedefineSign('neomake_project_info', opts) +endfunction + +function! neomake#signs#DefineHighlights() abort + " Use background from SignColumn. + let ctermbg = neomake#utils#GetHighlight('SignColumn', 'bg', 'Normal') + let guibg = neomake#utils#GetHighlight('SignColumn', 'bg#', 'Normal') + + " Define NeomakeErrorSign, NeomakeWarningSign etc. + call neomake#utils#define_derived_highlights('Neomake%sSign', [ctermbg, guibg]) +endfunction + +function! neomake#signs#DefineSigns() abort + call neomake#signs#RedefineErrorSign() + call neomake#signs#RedefineWarningSign() + call neomake#signs#RedefineInfoSign() + call neomake#signs#RedefineMessageSign() +endfunction + +function! s:wipe_signs(bufnr) abort + for type in ['file', 'project'] + if has_key(s:placed_signs[type], a:bufnr) + unlet s:placed_signs[type][a:bufnr] + endif + if has_key(s:last_placed_signs[type], a:bufnr) + unlet s:last_placed_signs[type][a:bufnr] + endif + endfor +endfunction +augroup neomake_signs + au! + autocmd BufWipeout * call s:wipe_signs(expand('')) +augroup END + +call neomake#signs#DefineSigns() +call neomake#signs#DefineHighlights() diff --git a/bundle/neomake/autoload/neomake/statusline.vim b/bundle/neomake/autoload/neomake/statusline.vim new file mode 100644 index 000000000..97f1c53de --- /dev/null +++ b/bundle/neomake/autoload/neomake/statusline.vim @@ -0,0 +1,432 @@ +scriptencoding utf-8 + +unlockvar s:unknown_counts +let s:unknown_counts = {} +lockvar s:unknown_counts + +let s:counts = {} + +" Key: bufnr, Value: dict with cache keys. +let s:cache = {} + +" For debugging. +let g:neomake#statusline#_s = s: + +function! s:clear_cache(bufnr) abort + if has_key(s:cache, a:bufnr) + unlet s:cache[a:bufnr] + endif +endfunction + +function! neomake#statusline#clear_cache() abort + let s:cache = {} +endfunction + +function! s:incCount(counts, item, buf) abort + if !empty(a:item.type) && (!a:buf || a:item.bufnr ==# a:buf) + let type = toupper(a:item.type) + let a:counts[type] = get(a:counts, type, 0) + 1 + if a:buf + call s:clear_cache(a:buf) + else + let s:cache = {} + endif + return 1 + endif + return 0 +endfunction + +" Refresh statusline when make run finished. +function! neomake#statusline#make_finished(make_info) abort + if a:make_info.options.file_mode + let bufnr = a:make_info.options.bufnr + if !empty(a:make_info.finished_jobs) && !has_key(s:counts, bufnr) + let s:counts[bufnr] = {} + endif + call s:clear_cache(bufnr) + else + let s:cache = {} + if !empty(a:make_info.finished_jobs) && !has_key(s:counts, 'project') + let s:counts['project'] = {} + endif + endif + + " Trigger refreshing of statuslines for all windows. + " Using ":redrawstatus" is problematic (https://github.com/vim/vim/issues/4850). + " Could do it only for affected windows (via bufnr of finished_jobs, but + " it might still affect other windows). + " This cannot be tested using Vader, but was done manually, using a maker + " that changes entries for a buffer in another window. + " This could also be done when starting, to (better) handle non-current + " windows. + for w in range(1, winnr('$')) + call setwinvar(w, '&stl', getwinvar(w, '&stl')) + endfor +endfunction + +function! neomake#statusline#ResetCountsForBuf(...) abort + let bufnr = a:0 ? +a:1 : bufnr('%') + call s:clear_cache(bufnr) + if has_key(s:counts, bufnr) + let r = s:counts[bufnr] != {} + unlet s:counts[bufnr] + if r + call neomake#utils#hook('NeomakeCountsChanged', { + \ 'reset': 1, 'file_mode': 1, 'bufnr': bufnr}) + endif + return r + endif + return 0 +endfunction + +function! neomake#statusline#ResetCountsForProject(...) abort + let s:cache = {} + if !has_key(s:counts, 'project') + return 0 + endif + let r = s:counts['project'] != {} + let bufnr = bufnr('%') + unlet s:counts['project'] + if r + call neomake#utils#hook('NeomakeCountsChanged', { + \ 'reset': 1, 'file_mode': 0, 'bufnr': bufnr}) + endif + return r +endfunction + +function! neomake#statusline#ResetCounts() abort + let r = neomake#statusline#ResetCountsForProject() + for bufnr in keys(s:counts) + let r = neomake#statusline#ResetCountsForBuf(bufnr) || r + endfor + let s:counts = {} + return r +endfunction + +function! neomake#statusline#AddLoclistCount(buf, item) abort + let s:counts[a:buf] = get(s:counts, a:buf, {}) + return s:incCount(s:counts[a:buf], a:item, a:buf) +endfunction + +function! neomake#statusline#AddQflistCount(item) abort + let s:counts['project'] = get(s:counts, 'project', {}) + return s:incCount(s:counts['project'], a:item, 0) +endfunction + +function! neomake#statusline#LoclistCounts(...) abort + let buf = a:0 ? a:1 : bufnr('%') + if buf is# 'all' + return s:counts + endif + return get(s:counts, buf, {}) +endfunction + +function! neomake#statusline#QflistCounts() abort + return get(s:counts, 'project', s:unknown_counts) +endfunction + +function! s:showErrWarning(counts, prefix) abort + let w = get(a:counts, 'W', 0) + let e = get(a:counts, 'E', 0) + if w || e + let result = a:prefix + if e + let result .= 'E:'.e + endif + if w + if e + let result .= ',' + endif + let result .= 'W:'.w + endif + return result + else + return '' + endif +endfunction + +function! neomake#statusline#LoclistStatus(...) abort + return s:showErrWarning(neomake#statusline#LoclistCounts(), a:0 ? a:1 : '') +endfunction + +function! neomake#statusline#QflistStatus(...) abort + return s:showErrWarning(neomake#statusline#QflistCounts(), a:0 ? a:1 : '') +endfunction + +" Get counts for a bufnr or 'project'. +" Returns all counts when used without arguments. +function! neomake#statusline#get_counts(...) abort + if a:0 + return get(s:counts, a:1, s:unknown_counts) + endif + return s:counts +endfunction + + +let s:formatter = { + \ 'args': {}, + \ } +function! s:formatter.running_job_names() abort + let jobs = get(self.args, 'running_jobs', s:running_jobs(self.args.bufnr)) + let sep = get(self.args, 'running_jobs_separator', ', ') + let format_running_job_file = get(self.args, 'format_running_job_file', '%s') + let format_running_job_project = get(self.args, 'format_running_job_project', '%s!') + let formatted = [] + for job in jobs + if job.file_mode + call add(formatted, printf(format_running_job_file, job.name)) + else + call add(formatted, printf(format_running_job_project, job.name)) + endif + endfor + return join(formatted, sep) +endfunction + +function! s:formatter._substitute(m) abort + if has_key(self.args, a:m) + return self.args[a:m] + endif + if !has_key(self, a:m) + let self.errors += [printf('Unknown statusline format: {{%s}}.', a:m)] + return '{{'.a:m.'}}' + endif + try + return call(self[a:m], [], self) + catch + call neomake#log#error(printf( + \ 'Error while formatting statusline: %s.', v:exception)) + endtry +endfunction + +function! s:formatter.format(f, args) abort + if empty(a:f) + return a:f + endif + let self.args = a:args + let self.errors = [] + let r = substitute(a:f, '{{\(.\{-}\)}}', '\=self._substitute(submatch(1))', 'g') + if !empty(self.errors) + call neomake#log#error(printf( + \ 'Error%s when formatting %s: %s', + \ len(self.errors) > 1 ? 's' : '', + \ string(a:f), join(self.errors, ', '))) + endif + return r +endfunction + + +function! s:running_jobs(bufnr) abort + return filter(copy(neomake#GetJobs()), + \ "v:val.bufnr == a:bufnr && !get(v:val, 'canceled', 0)") +endfunction + +function! s:format_running(format_running, options, bufnr, running_jobs) abort + let args = {'bufnr': a:bufnr, 'running_jobs': a:running_jobs} + for opt in ['running_jobs_separator', 'format_running_job_project', 'format_running_job_file'] + if has_key(a:options, opt) + let args[opt] = a:options[opt] + endif + endfor + return s:formatter.format(a:format_running, args) +endfunction + +function! neomake#statusline#get_status(bufnr, options) abort + let filemode_jobs = [] + let project_jobs = [] + let format_running = get(a:options, 'format_running', '… ({{running_job_names}})') + if format_running isnot 0 + let running_jobs = s:running_jobs(a:bufnr) + if !empty(running_jobs) + for j in running_jobs + if j.file_mode + let filemode_jobs += [j] + else + let project_jobs += [j] + endif + endfor + endif + endif + + let r_loclist = '' + let r_quickfix = '' + + let use_highlights_with_defaults = get(a:options, 'use_highlights_with_defaults', 1) + + " Location list counts. + let loclist_counts = get(s:counts, a:bufnr, s:unknown_counts) + if !empty(filemode_jobs) + let r_loclist = s:format_running(format_running, a:options, a:bufnr, filemode_jobs) + elseif empty(loclist_counts) + if loclist_counts is s:unknown_counts + let format_unknown = get(a:options, 'format_loclist_unknown', '?') + let r_loclist = s:formatter.format(format_unknown, {'bufnr': a:bufnr}) + else + let format_ok = get(a:options, 'format_loclist_ok', use_highlights_with_defaults ? '%#NeomakeStatusGood#✓%#NeomakeStatReset#' : '✓') + let r_loclist = s:formatter.format(format_ok, {'bufnr': a:bufnr}) + endif + else + let format_loclist = get(a:options, 'format_loclist_issues', + \ use_highlights_with_defaults ? '%s%%#NeomakeStatReset#' : '%s') + if !empty(format_loclist) + let loclist = '' + for [type, c] in items(loclist_counts) + if has_key(a:options, 'format_loclist_type_'.type) + let format = a:options['format_loclist_type_'.type] + elseif has_key(a:options, 'format_loclist_type_default') + let format = a:options['format_loclist_type_default'] + else + let hl = '' + if use_highlights_with_defaults + if hlexists('NeomakeStatColorType'.type) + let hl = '%#NeomakeStatColorType{{type}}#' + elseif hlexists('NeomakeStatColorDefault') + let hl = '%#NeomakeStatColorDefault#' + endif + endif + let format = hl.' {{type}}:{{count}} ' + endif + let loclist .= s:formatter.format(format, { + \ 'bufnr': a:bufnr, + \ 'count': c, + \ 'type': type}) + endfor + let r_loclist = printf(format_loclist, loclist) + endif + endif + + " Quickfix counts. + let qflist_counts = get(s:counts, 'project', s:unknown_counts) + if !empty(project_jobs) + let r_quickfix = s:format_running(format_running, a:options, a:bufnr, project_jobs) + elseif empty(qflist_counts) + let format_ok = get(a:options, 'format_quickfix_ok', '') + if !empty(format_ok) + let r_quickfix = s:formatter.format(format_ok, {'bufnr': a:bufnr}) + endif + else + let format_quickfix = get(a:options, 'format_quickfix_issues', + \ use_highlights_with_defaults ? '%s%%#NeomakeStatReset#' : '%s') + if !empty(format_quickfix) + let quickfix = '' + for [type, c] in items(qflist_counts) + if has_key(a:options, 'format_quickfix_type_'.type) + let format = a:options['format_quickfix_type_'.type] + elseif has_key(a:options, 'format_quickfix_type_default') + let format = a:options['format_quickfix_type_default'] + else + let hl = '' + if use_highlights_with_defaults + if hlexists('NeomakeStatColorQuickfixType'.type) + let hl = '%#NeomakeStatColorQuickfixType{{type}}#' + elseif hlexists('NeomakeStatColorQuickfixDefault') + let hl = '%#NeomakeStatColorQuickfixDefault#' + endif + endif + let format = hl.' Q{{type}}:{{count}} ' + endif + if !empty(format) + let quickfix .= s:formatter.format(format, { + \ 'bufnr': a:bufnr, + \ 'count': c, + \ 'type': type}) + endif + endfor + let r_quickfix = printf(format_quickfix, quickfix) + endif + endif + + let format_lists = get(a:options, 'format_lists', '{{loclist}}{{lists_sep}}{{quickfix}}') + if empty(r_loclist) || empty(r_quickfix) + let lists_sep = '' + else + let lists_sep = get(a:options, 'lists_sep', ' ') + endif + return s:formatter.format(format_lists, {'loclist': r_loclist, 'quickfix': r_quickfix, 'lists_sep': lists_sep}) +endfunction + +function! neomake#statusline#get(bufnr, ...) abort + let options = a:0 ? a:1 : {} + let cache_key = string(options) + if !exists('s:cache[a:bufnr][cache_key]') + if !has_key(s:cache, a:bufnr) + let s:cache[a:bufnr] = {} + endif + let bufnr = +a:bufnr + + " TODO: needs to go into cache key then! + if getbufvar(bufnr, '&filetype') ==# 'qf' + let s:cache[bufnr][cache_key] = '' + else + let [disabled, src] = neomake#config#get_with_source('disabled', -1, {'bufnr': bufnr, 'log_source': 'statusline#get'}) + if src ==# 'default' + let disabled_scope = '' + else + let disabled_scope = src[0] + endif + if disabled != -1 && disabled + " Automake Disabled + let format_disabled_info = get(options, 'format_disabled_info', '{{disabled_scope}}-') + let disabled_info = s:formatter.format(format_disabled_info, + \ {'disabled_scope': disabled_scope}) + " Defaults to showing the disabled information (i.e. scope) + let format_disabled = get(options, 'format_status_disabled', '{{disabled_info}} %s') + let outer_format = s:formatter.format(format_disabled, {'disabled_info': disabled_info}) + else + " Automake Enabled + " Defaults to showing only the status + let format_enabled = get(options, 'format_status_enabled', '%s') + let outer_format = s:formatter.format(format_enabled, {}) + endif + let format_status = get(options, 'format_status', '%s') + let status = neomake#statusline#get_status(bufnr, options) + + let r = printf(outer_format, printf(format_status, status)) + + let s:cache[bufnr][cache_key] = r + endif + endif + return s:cache[a:bufnr][cache_key] +endfunction + +" XXX: TODO: cleanup/doc?! +function! neomake#statusline#DefineHighlights() abort + for suffix in ['', 'NC'] + let hl = 'StatusLine'.suffix + + " Highlight used for resetting color (used after counts). + exe 'hi default link NeomakeStatReset'.suffix.' StatusLine'.suffix + + " Uses "green" for NeomakeStatusGood, but the default with + " NeomakeStatusGoodNC (since it might be underlined there, and should + " not stand out in general there). + exe 'hi default NeomakeStatusGood'.suffix + \ . ' ctermfg=' . (suffix ? neomake#utils#GetHighlight(hl, 'fg') : 'green') + \ . ' guifg=' . (suffix ? neomake#utils#GetHighlight(hl, 'fg#') : 'green') + \ . ' ctermbg='.neomake#utils#GetHighlight(hl, 'bg') + \ . ' guifg='.neomake#utils#GetHighlight(hl, 'bg#') + \ . (neomake#utils#GetHighlight(hl, 'underline') ? ' cterm=underline' : '') + \ . (neomake#utils#GetHighlight(hl, 'underline#') ? ' gui=underline' : '') + \ . (neomake#utils#GetHighlight(hl, 'reverse') ? ' cterm=reverse' : '') + \ . (neomake#utils#GetHighlight(hl, 'reverse#') ? ' gui=reverse' : '') + endfor + + " Default highlight for type counts. + exe 'hi default NeomakeStatColorDefault cterm=NONE ctermfg=white ctermbg=blue' + hi link NeomakeStatColorQuickfixDefault NeomakeStatColorDefault + + " Specific highlights for types. Only used if defined. + exe 'hi default NeomakeStatColorTypeE cterm=NONE ctermfg=white ctermbg=red' + hi link NeomakeStatColorQuickfixTypeE NeomakeStatColorTypeE + + exe 'hi default NeomakeStatColorTypeW cterm=NONE ctermfg=white ctermbg=yellow' + hi link NeomakeStatColorQuickfixTypeW NeomakeStatColorTypeW +endfunction + +" Global augroup, gets configured always currently when autoloaded. +augroup neomake_statusline + autocmd! + autocmd BufWipeout * call s:clear_cache(expand('')) + autocmd ColorScheme * call neomake#statusline#DefineHighlights() +augroup END +call neomake#statusline#DefineHighlights() +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/autoload/neomake/utils.vim b/bundle/neomake/autoload/neomake/utils.vim new file mode 100644 index 000000000..69e2ad473 --- /dev/null +++ b/bundle/neomake/autoload/neomake/utils.vim @@ -0,0 +1,862 @@ +" vim: ts=4 sw=4 et +scriptencoding utf-8 + +" Get verbosity, optionally based on jobinfo's make_id (a:1). +function! neomake#utils#get_verbosity(...) abort + if a:0 && has_key(a:1, 'make_id') + return neomake#GetMakeOptions(a:1.make_id).verbosity + endif + return get(g:, 'neomake_verbose', 1) + &verbose +endfunction + +function! neomake#utils#Stringify(obj) abort + if type(a:obj) == type([]) + let ls = map(copy(a:obj), 'neomake#utils#Stringify(v:val)') + return '['.join(ls, ', ').']' + elseif type(a:obj) == type({}) + let ls = [] + for [k, l:V] in items(neomake#utils#fix_self_ref(a:obj)) + if type(V) == type(function('tr')) + let fname = substitute(string(V), ', {\zs.*\ze})', '…', '') + call add(ls, k.': '.fname) + else + call add(ls, k.': '.neomake#utils#Stringify(V)) + endif + unlet V " vim73 + endfor + return '{'.join(ls, ', ').'}' + elseif type(a:obj) == type(function('tr')) + return string(a:obj) + else + return a:obj + endif +endfunction + +function! neomake#utils#truncate_width(string, width, ...) abort + if a:width <= 0 + return '' + endif + if strwidth(a:string) <= a:width + return a:string + endif + + let ellipsis = a:0 ? a:1 : '…' + let len_ellipsis = strwidth(ellipsis) + let pos = a:width + let w_without_ellipsis = a:width - len_ellipsis + while pos >= 0 + let s = matchstr(a:string, '.\{,'.pos.'}', 0, 1) + let w = strwidth(s) + if w <= w_without_ellipsis + return s . ellipsis + endif + let pos -= max([(w - a:width)/2, 1]) + endwhile + return '' +endfunction + +" This comes straight out of syntastic. +"print as much of a:msg as possible without "Press Enter" prompt appearing +function! neomake#utils#WideMessage(msg) abort " {{{2 + " Replace newlines (typically in the msg) with a single space. This + " might happen with writegood. + let msg = substitute(a:msg, '\r\?\n', ' ', 'g') + + "convert tabs to spaces so that the tabs count towards the window + "width as the proper amount of characters + let chunks = split(msg, "\t", 1) + let msg = join(map(chunks[:-2], "v:val . repeat(' ', &tabstop - strwidth(v:val) % &tabstop)"), '') . chunks[-1] + + if exists('v:echospace') + let msg = neomake#utils#truncate_width(msg, v:echospace) + call neomake#log#debug('WideMessage: echo '.msg.'.') + echo msg + return + endif + + let msg = neomake#utils#truncate_width(msg, &columns-1) + + let old_ruler = &ruler + let old_showcmd = &showcmd + set noruler noshowcmd + redraw + echo msg + let &ruler = old_ruler + let &showcmd = old_showcmd +endfunction " }}}2 + +" This comes straight out of syntastic. +function! neomake#utils#IsRunningWindows() abort + return has('win32') || has('win64') +endfunction + +" Get directory/path separator. +function! neomake#utils#Slash() abort + return (!exists('+shellslash') || &shellslash) ? '/' : '\' +endfunction + +function! neomake#utils#Exists(exe) abort + " DEPRECATED: just use executable() directly. + return executable(a:exe) +endfunction + +" Object used with neomake#utils#MakerFromCommand. +let s:maker_from_command = extend(copy(g:neomake#core#command_maker_base), { + \ 'remove_invalid_entries': 0, + \ }) +function! s:maker_from_command._get_argv(jobinfo) abort dict + let fname = self._get_fname_for_args(a:jobinfo) + let args = neomake#utils#ExpandArgs(self.args, a:jobinfo) + if !empty(fname) + if self.__command_is_string + let fname = neomake#utils#shellescape(fname) + let args[-1] .= ' '.fname + else + call add(args, fname) + endif + endif + return neomake#compat#get_argv(self.exe, args, 1) +endfunction + +" Create a maker object for a given command. +" Args: command (string or list). Gets wrapped in a shell in case it is a +" string. +function! neomake#utils#MakerFromCommand(command) abort + let maker = copy(s:maker_from_command) + if type(a:command) == type('') + let argv = split(&shell) + split(&shellcmdflag) + let maker.exe = argv[0] + let maker.args = argv[1:] + [a:command] + let maker.__command_is_string = 1 + else + let maker.exe = a:command[0] + let maker.args = a:command[1:] + let maker.__command_is_string = 0 + endif + return maker +endfunction + +let s:super_ft_cache = {} +function! neomake#utils#GetSupersetOf(ft) abort + if !has_key(s:super_ft_cache, a:ft) + call neomake#utils#load_ft_makers(a:ft) + let l:SupersetOf = 'neomake#makers#ft#'.a:ft.'#SupersetOf' + if exists('*'.SupersetOf) + let s:super_ft_cache[a:ft] = call(SupersetOf, []) + else + let s:super_ft_cache[a:ft] = '' + endif + endif + return s:super_ft_cache[a:ft] +endfunction + +let s:loaded_ft_maker_runtime = [] +function! neomake#utils#load_ft_makers(ft) abort + " Load ft maker, but only once (for performance reasons and to allow for + " monkeypatching it in tests). + if index(s:loaded_ft_maker_runtime, a:ft) == -1 + if !exists('*neomake#makers#ft#'.a:ft.'#EnabledMakers') + silent exe 'runtime! autoload/neomake/makers/ft/'.a:ft.'.vim' + endif + call add(s:loaded_ft_maker_runtime, a:ft) + endif +endfunction + +let s:loaded_global_maker_runtime = 0 +function! neomake#utils#load_global_makers() abort + " Load global makers, but only once (for performance reasons and to allow + " for monkeypatching it in tests). + if !s:loaded_global_maker_runtime + exe 'runtime! autoload/neomake/makers/*.vim' + let s:loaded_global_maker_runtime = 1 + endif +endfunction + +function! neomake#utils#get_ft_confname(ft, ...) abort + return substitute(a:ft, '\W', a:0 ? a:1 : '_', 'g') +endfunction + +" Resolve filetype a:ft into a list of filetypes suitable for config vars +" (i.e. 'foo.bar' => ['foo_bar', 'foo', 'bar']). +function! neomake#utils#get_config_fts(ft, ...) abort + let delim = a:0 ? a:1 : '_' + let cache_key = a:ft . delim + if !has_key(s:cache_config_fts, cache_key) + let r = [] + let fts = split(a:ft, '\.') + for ft in fts + call add(r, ft) + let super_ft = neomake#utils#GetSupersetOf(ft) + while !empty(super_ft) + if index(fts, super_ft) == -1 + call add(r, super_ft) + endif + let super_ft = neomake#utils#GetSupersetOf(super_ft) + endwhile + endfor + if len(fts) > 1 + call insert(r, a:ft, 0) + endif + let s:cache_config_fts[cache_key] = map(r, 'neomake#utils#get_ft_confname(v:val, delim)') + endif + return s:cache_config_fts[cache_key] +endfunction +let s:cache_config_fts = {} + +let s:unset = {} " Sentinel. + +" Get a setting by key, based on filetypes, from the buffer or global +" namespace, defaulting to default. +" Use an empty bufnr ('') to ignore buffer-local settings. +function! neomake#utils#GetSetting(key, maker, default, ft, bufnr, ...) abort + let maker_only = a:0 ? a:1 : 0 + + " Check new-style config. + if exists('g:neomake') || !empty(getbufvar(a:bufnr, 'neomake')) + let context = {'ft': a:ft, 'maker': a:maker, 'bufnr': a:bufnr, 'maker_only': maker_only} + let [l:Ret, source] = neomake#config#get_with_source(a:key, g:neomake#config#undefined, context) + " Check old-style setting when source is the maker. + if source ==# 'maker' && !maker_only + let tmpmaker = {} + if has_key(a:maker, 'name') + let tmpmaker.name = a:maker.name + endif + let l:RetOld = s:get_oldstyle_setting(a:key, tmpmaker, s:unset, a:ft, a:bufnr, 1) + if RetOld isnot# s:unset + return RetOld + endif + endif + if Ret isnot g:neomake#config#undefined + return Ret + endif + endif + + return s:get_oldstyle_setting(a:key, a:maker, a:default, a:ft, a:bufnr, maker_only) +endfunction + +function! s:get_oldstyle_setting(key, maker, default, ft, bufnr, maker_only) abort + let maker_name = get(a:maker, 'name', '') + if a:maker_only && empty(maker_name) + if has_key(a:maker, a:key) + return get(a:maker, a:key) + endif + return a:default + endif + + if !empty(a:ft) + let fts = neomake#utils#get_config_fts(a:ft) + [''] + else + let fts = [''] + endif + for ft in fts + let part = join(filter([ft, maker_name], '!empty(v:val)'), '_') + if empty(part) + break + endif + let config_var = 'neomake_'.part.'_'.a:key + if a:bufnr isnot# '' + let l:Bufcfgvar = neomake#compat#getbufvar(a:bufnr, config_var, s:unset) + if Bufcfgvar isnot s:unset + return copy(Bufcfgvar) + endif + endif + if has_key(g:, config_var) + return copy(get(g:, config_var)) + endif + unlet! Bufcfgvar " vim73 + endfor + + if has_key(a:maker, a:key) + return get(a:maker, a:key) + endif + + let key = a:key + if a:maker_only + let key = maker_name.'_'.key + endif + let key = a:maker_only ? maker_name.'_'.a:key : a:key + " Look for 'neomake_'.key in the buffer and global namespace. + let bufvar = neomake#compat#getbufvar(a:bufnr, 'neomake_'.key, s:unset) + if bufvar isnot s:unset + return bufvar + endif + if a:key !=# 'enabled_makers' && has_key(g:, 'neomake_'.key) + return get(g:, 'neomake_'.key) + endif + return a:default +endfunction + +" Helper function to define default highlight for a:group (e.g. +" "Neomake%sSign"), using fg from another highlight, abd given background. +function! neomake#utils#define_derived_highlights(group_format, bg) abort + for [type, fg_from] in items({ + \ 'Error': ['Error', 'bg'], + \ 'Warning': ['Todo', 'fg'], + \ 'Info': ['Question', 'fg'], + \ 'Message': ['ModeMsg', 'fg'] + \ }) + let group = printf(a:group_format, type) + call s:define_derived_highlight_group(group, fg_from, a:bg) + endfo +endfunction + +function! s:define_derived_highlight_group(group, fg_from, bg) abort + let [fg_group, fg_attr] = a:fg_from + let [ctermbg, guibg] = a:bg + let bg = 'ctermbg='.ctermbg.' guibg='.guibg + + " NOTE: fg falls back to "Normal" always, not bg (for e.g. "SignColumn") + " inbetween. + let ctermfg = neomake#utils#GetHighlight(fg_group, fg_attr, 'Normal') + let guifg = neomake#utils#GetHighlight(fg_group, fg_attr.'#', 'Normal') + + " Ensure that we're not using bg as fg (as with gotham + " colorscheme, issue https://github.com/neomake/neomake/pull/659). + if ctermfg !=# 'NONE' && ctermfg ==# ctermbg + let ctermfg = neomake#utils#GetHighlight(fg_group, neomake#utils#ReverseSynIDattr(fg_attr)) + endif + if guifg !=# 'NONE' && guifg ==# guibg + let guifg = neomake#utils#GetHighlight(fg_group, neomake#utils#ReverseSynIDattr(fg_attr).'#') + endif + exe 'hi '.a:group.'Default ctermfg='.ctermfg.' guifg='.guifg.' '.bg + if !neomake#utils#highlight_is_defined(a:group) + exe 'hi link '.a:group.' '.a:group.'Default' + endif +endfunction + +" Get property from highlighting group. +function! neomake#utils#GetHighlight(group, what, ...) abort + let fallback = a:0 ? a:1 : '' + let mode = a:what[-1:] ==# '#' ? 'gui' : 'cterm' + let reverse = synIDattr(synIDtrans(hlID(a:group)), 'reverse', mode) + let what = a:what + if reverse + let what = neomake#utils#ReverseSynIDattr(what) + endif + if what[-1:] ==# '#' + let val = synIDattr(synIDtrans(hlID(a:group)), what, mode) + else + let val = synIDattr(synIDtrans(hlID(a:group)), what, mode) + endif + if empty(val) || val == -1 + if !empty(fallback) + " NOTE: this might still be NONE also for "Normal", with + " e.g. `vim -u NONE`. + return neomake#utils#GetHighlight(fallback, a:what) + endif + return 'NONE' + endif + return val +endfunction + +function! neomake#utils#ReverseSynIDattr(attr) abort + if a:attr ==# 'fg' + return 'bg' + elseif a:attr ==# 'bg' + return 'fg' + elseif a:attr ==# 'fg#' + return 'bg#' + elseif a:attr ==# 'bg#' + return 'fg#' + endif + return a:attr +endfunction + +" Deprecated: moved to neomake#postprocess#compress_whitespace. +function! neomake#utils#CompressWhitespace(entry) abort + call neomake#postprocess#compress_whitespace(a:entry) +endfunction + +function! neomake#utils#redir(cmd) abort + " @vimlint(EVL108, 1) + if exists('*execute') && has('nvim-0.2.0') + " @vimlint(EVL108, 0) + " NOTE: require Neovim, since Vim has at least an issue when using + " this in a :command-completion function. + " Ref: https://github.com/neomake/neomake/issues/650. + " Neovim 0.1.7 also parses 'highlight' wrongly. + return execute(a:cmd) + endif + if type(a:cmd) == type([]) + let r = '' + for cmd in a:cmd + let r .= neomake#utils#redir(cmd) + endfor + return r + endif + try + redir => neomake_redir + silent exe a:cmd + catch /^Vim(redir):E121:/ + throw printf('Neomake: neomake#utils#redir: called with outer :redir (error: %s).', + \ v:exception) + finally + redir END + endtry + return neomake_redir +endfunction + +function! s:exparg_subst(bufnr, s, mods) abort + let s = a:s + let mods = a:mods + if s[1:1] ==# '<' + " Convert "%<" to "%:r". + let mods = ':r' . mods + let s = s[0] . s[2:] + endif + return expand(substitute(s, '^%'.a:mods, neomake#utils#fnamemodify(a:bufnr, mods), '')) +endfunction + +function! neomake#utils#ExpandArgs(args, jobinfo) abort + if has_key(a:jobinfo, 'tempfile') + let fname = a:jobinfo.tempfile + else + let fname = bufname(a:jobinfo.bufnr) + if !empty(fname) + let fname = fnamemodify(fname, ':p') + endif + endif + let ret = map(copy(a:args), "substitute(v:val, '%t', fname, 'g')") + + " Expand % in args similar to when using :! + " \% is ignored + " \\% is expanded to \\file.ext + " %% becomes % + " % must be followed with an expansion keyword + let ret = map(ret, + \ 'substitute(v:val, ' + \ . '''\(\%(\\\@'), '.*\zs\d\+_'),'')) + endfunction +endif + +function! s:handle_hook(jobinfo, event, context) abort + let context_str = string(map(copy(a:context), + \ "v:key ==# 'make_info' ? 'make_info #'.get(v:val, 'make_id')" + \ .": (v:key ==# 'options' && has_key(v:val, 'jobs') ? extend(copy(v:val), {'jobs': map(copy(v:val.jobs), 'v:val.maker.name')}, 'force')" + \ .": (v:key ==# 'jobinfo' ? v:val.as_string()" + \ .": (v:key ==# 'finished_jobs' ? map(copy(v:val), 'v:val.as_string()') : v:val)))")) + + if exists('g:neomake_hook_context') + call neomake#log#debug(printf('Queuing User autocmd %s for nested invocation (%s).', a:event, context_str), + \ a:jobinfo) + return neomake#action_queue#add( + \ ['Timer', 'BufEnter', 'WinEnter', 'InsertLeave', 'CursorHold', 'CursorHoldI'], + \ [s:function('s:handle_hook'), [a:jobinfo, a:event, a:context]]) + endif + + let log_args = [printf('Calling User autocmd %s with context: %s.', + \ a:event, context_str)] + if !empty(a:jobinfo) + let log_args += [a:jobinfo] + endif + call call('neomake#log#debug', log_args) + + unlockvar g:neomake_hook_context + let g:neomake_hook_context = a:context + lockvar 1 g:neomake_hook_context + try + call neomake#compat#doautocmd('User '.a:event) + catch + let error = v:exception + if error[-1:] !=# '.' + let error .= '.' + endif + call neomake#log#exception(printf( + \ 'Error during User autocmd for %s: %s', + \ a:event, error), a:jobinfo) + finally + unlet g:neomake_hook_context + endtry + return g:neomake#action_queue#processed +endfunction + +function! neomake#utils#hook(event, context, ...) abort + if exists('#User#'.a:event) + let jobinfo = a:0 ? a:1 : ( + \ has_key(a:context, 'jobinfo') ? a:context.jobinfo : {}) + return s:handle_hook(jobinfo, a:event, a:context) + endif +endfunction + +function! neomake#utils#diff_dict(old, new) abort + let diff = {'removed': {}, 'added': {}, 'changed': {}} + + for k in keys(a:old) + if !has_key(a:new, k) + let diff['removed'][k] = a:old[k] + elseif type(a:old[k]) !=# type(a:new[k]) || a:old[k] !=# a:new[k] + let diff['changed'][k] = [a:old[k], a:new[k]] + endif + endfor + + for k in keys(a:new) + if !has_key(a:old, k) + let diff['added'][k] = a:new[k] + endif + endfor + + call filter(diff, '!empty(v:val)') + + return diff +endfunction + +" Sort quickfix/location list entries by distance to current cursor position's +" column, but preferring entries starting at or behind the cursor position. +function! neomake#utils#sort_by_col(a, b) abort + let col = getpos('.')[2] + if a:a.col > col + if a:b.col < col + return 1 + endif + elseif a:b.col > col + return -1 + endif + return abs(col - a:a.col) - abs(col - a:b.col) +endfunction + +function! neomake#utils#path_sep() abort + return neomake#utils#IsRunningWindows() ? ';' : ':' +endfunction + +" Find a file matching `a:glob` (using `globpath()`) by going up the +" directories from the start directory (a:1, defaults to `expand('%:p:h')`, +" i.e. the directory of the current buffer's file).) +function! neomake#utils#FindGlobFile(glob, ...) abort + let curDir = a:0 ? a:1 : expand('%:p:h') + let fileFound = [] + while 1 + let fileFound = neomake#compat#globpath_list(curDir, a:glob, 1) + if !empty(fileFound) + return fileFound[0] + endif + let lastFolder = curDir + let curDir = fnamemodify(curDir, ':h') + if curDir ==# lastFolder + break + endif + endwhile + return '' +endfunction + +function! neomake#utils#JSONdecode(json) abort + return neomake#compat#json_decode(a:json) +endfunction + +" Smarter shellescape, via vim-fugitive. +function! s:gsub(str,pat,rep) abort + return substitute(a:str,'\v\C'.a:pat,a:rep,'g') +endfunction + +function! neomake#utils#shellescape(arg) abort + if a:arg =~# '^[A-Za-z0-9_/.=-]\+$' + return a:arg + elseif &shell =~? 'cmd' || exists('+shellslash') && !&shellslash + return '"'.s:gsub(s:gsub(a:arg, '"', '""'), '\%', '"%"').'"' + endif + return shellescape(a:arg) +endfunction + +function! neomake#utils#get_buffer_lines(bufnr) abort + let buflines = getbufline(a:bufnr, 1, '$') + " Special case: empty buffer; do not write an empty line in this case. + if len(buflines) > 1 || buflines != [''] + if getbufvar(a:bufnr, '&endofline') + \ || (!getbufvar(a:bufnr, '&binary') + \ && (!exists('+fixendofline') || getbufvar(a:bufnr, '&fixendofline'))) + call add(buflines, '') + endif + endif + return buflines +endfunction + +function! neomake#utils#write_tempfile(bufnr, temp_file) abort + call writefile(neomake#utils#get_buffer_lines(a:bufnr), a:temp_file, 'b') + if exists('*setfperm') + let perms = getfperm(bufname(+a:bufnr)) + if empty(perms) + let perms = 'rw-------' + endif + call setfperm(a:temp_file, perms) + endif +endfunction + +" Wrapper around fnamemodify that handles special buffers (e.g. fugitive). +function! neomake#utils#fnamemodify(bufnr, modifier) abort + let bufnr = +a:bufnr + if empty(getbufvar(bufnr, 'fugitive_type')) + let path = bufname(bufnr) + else + if exists('*FugitivePath') + let path = FugitivePath(bufname(bufnr)) + else + let fug_buffer = fugitive#buffer(bufnr) + let path = fug_buffer.repo().translate(fug_buffer.path()) + endif + if empty(a:modifier) + let path = fnamemodify(path, ':.') + endif + endif + return empty(path) ? '' : fnamemodify(path, a:modifier) +endfunction + +function! s:fix_nvim_partial(obj) abort + " Ensure that Funcrefs can be used as a string. + " Ref: https://github.com/neovim/neovim/issues/7432 + try + call string(a:obj) + catch /^Vim(call):E724:/ + return '' + endtry + return a:obj +endfunction + +function! neomake#utils#fix_self_ref(obj, ...) abort + let obj_type = type(a:obj) + if has('nvim') && obj_type == 2 + return s:fix_nvim_partial(a:obj) + endif + + if obj_type != type({}) + if obj_type == type([]) + return map(copy(a:obj), 'neomake#utils#fix_self_ref(v:val)') + endif + return a:obj + endif + let obj = a:obj + for k in keys(obj) + if a:0 + let self_ref = filter(copy(a:1), 'v:val[1][0] is obj[k]') + if !empty(self_ref) + if obj is a:obj + let obj = copy(a:obj) + endif + let obj[k] = printf('', self_ref[0][0], self_ref[0][1][1]) + continue + endif + endif + if type(obj[k]) == type({}) + let fixed = neomake#utils#fix_self_ref(get(obj, k), a:0 ? a:1 + [[len(a:1)+1, [a:obj, k]]] : [[1, [a:obj, k]]]) + if fixed != obj[k] + if obj is a:obj + let obj = copy(a:obj) + endif + let obj[k] = fixed + endif + elseif has('nvim') && type(obj[k]) == 2 + let l:Fixed_partial = s:fix_nvim_partial(get(obj, k)) + if l:Fixed_partial != get(obj, k) + if obj is a:obj + let obj = copy(a:obj) + endif + let obj[k] = l:Fixed_partial + endif + endif + endfor + return obj +endfunction + +function! neomake#utils#parse_highlight(group) abort + let output = neomake#utils#redir('highlight '.a:group) + return join(split(output)[2:]) +endfunction + +function! neomake#utils#highlight_is_defined(group) abort + if !hlexists(a:group) + return 0 + endif + return neomake#utils#parse_highlight(a:group) !=# 'cleared' +endfunction + +" Get the root directory of the current project. +" This is determined by looking for specific files (e.g. `.git` and +" `Makefile`), and `g:neomake#makers#ft#X#project_root_files` (if defined for +" filetype "X"). +" This can be overridden in b:neomake.project_root (where it gets cached +" also). +" a:1 buffer number (defaults to current) +function! neomake#utils#get_project_root(...) abort + let bufnr = a:0 ? a:1 : bufnr('%') + let bufcfg = getbufvar(bufnr, 'neomake') + if !empty(bufcfg) + let buf_project_root = get(bufcfg, 'project_root', -1) + if buf_project_root isnot -1 + return buf_project_root + endif + endif + let ft = getbufvar(bufnr, '&filetype') + call neomake#utils#load_ft_makers(ft) + + let project_root_files = ['.git', 'Makefile'] + + let ft_project_root_files = 'neomake#makers#ft#'.ft.'#project_root_files' + if has_key(g:, ft_project_root_files) + let project_root_files = get(g:, ft_project_root_files) + project_root_files + endif + + let r = '' + let buf_dir = expand('#'.bufnr.':p:h') + for fname in project_root_files + let project_root = neomake#utils#FindGlobFile(fname, buf_dir) + if !empty(project_root) + let r = fnamemodify(project_root, ':h') + break + endif + endfor + call neomake#config#set_buffer(bufnr, 'project_root', r) + return r +endfunction + +" Return the number of lines for a given buffer. +" This returns 0 for unloaded buffers. +if exists('*nvim_buf_line_count') + function! neomake#utils#get_buf_line_count(bufnr) abort + if !bufloaded(a:bufnr) + " https://github.com/neovim/neovim/issues/7688 + return 0 + endif + return nvim_buf_line_count(a:bufnr) + endfunction +else + function! neomake#utils#get_buf_line_count(bufnr) abort + if a:bufnr == bufnr('%') + return line('$') + endif + " TODO: this should get cached (based on b:changedtick), and cleaned + " in BufWipeOut. + return len(getbufline(a:bufnr, 1, '$')) + endfunction +endif + +" Returns: [error, cd_back_cmd] +function! neomake#utils#temp_cd(dir, ...) abort + if a:dir ==# '.' + return ['', ''] + endif + if a:0 + let cur_wd = a:1 + else + let cur_wd = getcwd() + if cur_wd ==# a:dir + " No need to change directory. + return ['', ''] + endif + endif + let cd = haslocaldir() ? 'lcd' : (exists(':tcd') == 2 && haslocaldir(-1, 0)) ? 'tcd' : 'cd' + try + exe cd.' '.fnameescape(a:dir) + catch + " Tests fail with E344, but in reality it is E472?! + " If uncaught, both are shown - let's just catch everything. + return [v:exception, ''] + endtry + return ['', cd.' '.fnameescape(cur_wd)] +endfunction + +if exists('*nvim_buf_get_lines') + function! neomake#utils#buf_get_lines(bufnr, start, end) abort + if a:start < 1 + throw 'neomake#utils#buf_get_lines: start is lower than 1' + endif + try + return nvim_buf_get_lines(a:bufnr, a:start-1, a:end-1, 1) + catch + throw 'neomake#utils#buf_get_lines: '.substitute(v:exception, '\v^[^:]+:', '', '') + endtry + endfunction +else + function! neomake#utils#buf_get_lines(bufnr, start, end) abort + if a:bufnr != bufnr('%') + throw 'Neomake: neomake#utils#buf_get_lines: used for non-current buffer' + endif + if a:start < 1 + throw 'neomake#utils#buf_get_lines: start is lower than 1' + endif + if a:end-1 > line('$') + throw 'neomake#utils#buf_get_lines: end is higher than number of lines' + endif + let r = [] + let i = a:start + while i < a:end + let r += [getline(i)] + let i += 1 + endwhile + return r + endfunction +endif + +if exists('*nvim_buf_set_lines') + function! neomake#utils#buf_set_lines(bufnr, start, end, replacement) abort + if a:start < 1 + return 'neomake#utils#buf_set_lines: start is lower than 1' + endif + try + call nvim_buf_set_lines(a:bufnr, a:start-1, a:end-1, 1, a:replacement) + catch + " call neomake#log#error('Fixing entry failed (out of bounds)') + return 'neomake#utils#buf_set_lines: '.substitute(v:exception, '\v^[^:]+:', '', '') + endtry + return '' + endfunction +else + function! neomake#utils#buf_set_lines(bufnr, start, end, replacement) abort + if a:bufnr != bufnr('%') + return 'neomake#utils#buf_set_lines: used for non-current buffer' + endif + + if a:start < 1 + return 'neomake#utils#buf_set_lines: start is lower than 1' + endif + if a:end > line('$')+1 + return 'neomake#utils#buf_set_lines: end is higher than number of lines' + endif + + if a:start == a:end + let lnum = a:start < 0 ? line('$') - a:start : a:start + if append(lnum-1, a:replacement) == 1 + call neomake#log#error(printf('Failed to append line(s): %d (%d).', a:start, lnum), {'bufnr': a:bufnr}) + endif + + else + let range = a:end - a:start + if range > len(a:replacement) + let end = min([a:end, line('$')]) + silent execute a:start.','.end.'d_' + call setline(a:start, a:replacement) + else + let i = 0 + let n = len(a:replacement) + while i < n + call setline(a:start + i, a:replacement[i]) + let i += 1 + endwhile + endif + endif + return '' + endfunction +endif + +function! neomake#utils#shorten_list_for_log(l, max) abort + if len(a:l) > a:max + return a:l[:a:max-1] + ['... ('.len(a:l).' total)'] + endif + return a:l +endfunction + +augroup neomake_utils + au! + autocmd FileType * if exists('b:neomake.project_root') | unlet b:neomake.project_root | endif +augroup END diff --git a/bundle/neomake/autoload/neomake/virtualtext.vim b/bundle/neomake/autoload/neomake/virtualtext.vim new file mode 100644 index 000000000..7523d5835 --- /dev/null +++ b/bundle/neomake/autoload/neomake/virtualtext.vim @@ -0,0 +1,113 @@ +scriptencoding utf8 + +let s:highlight_types = { + \ 'E': 'NeomakeVirtualtextError', + \ 'W': 'NeomakeVirtualtextWarning', + \ 'I': 'NeomakeVirtualtextInfo', + \ 'M': 'NeomakeVirtualtextMessage' + \ } + +function! neomake#virtualtext#show(...) abort + let list = neomake#list#get() + if empty(list) + echom 'Neomake: no annotations to show (no list)' + return + endif + + let filter = a:0 ? a:1 : '' + if empty(filter) + let entries = list.entries + else + let entries = map(copy(list.entries), filter) + endif + + if empty(entries) + echom 'Neomake: no annotations to show (no errors)' + return + endif + + for entry in entries + let buf_info = getbufvar(entry.bufnr, '_neomake_info', {}) + + call neomake#virtualtext#add_entry(entry, s:all_ns) + + " Keep track of added entries, because stacking is not supported. + let set_buf_info = 0 + if !has_key(buf_info, 'virtual_text_entries') + let buf_info.virtual_text_entries = [] + endif + if index(buf_info.virtual_text_entries, entry.lnum) == -1 + " Do not add it, but define it still - could return here also later. + call add(buf_info.virtual_text_entries, entry.lnum) + let set_buf_info = 1 + endif + + if set_buf_info + call setbufvar(entry.bufnr, '_neomake_info', buf_info) + endif + endfor +endfunction + +function! neomake#virtualtext#add_entry(entry, src_id) abort + let hi = get(s:highlight_types, toupper(a:entry.type), 'NeomakeVirtualtextMessage') + let prefix = get(g:, 'neomake_virtualtext_prefix', '❯ ') + let text = prefix . a:entry.text + let used_src_id = nvim_buf_set_virtual_text(a:entry.bufnr, a:src_id, a:entry.lnum-1, [[text, hi]], {}) + return used_src_id +endfunction + +function! neomake#virtualtext#show_errors() abort + call neomake#virtualtext#show('v:val ==? "e"') +endfunction + +function! neomake#virtualtext#hide() abort + let bufnr = bufnr('%') + let buf_info = getbufvar(bufnr, '_neomake_info', {}) + call nvim_buf_clear_highlight(bufnr, s:all_ns, 0, -1) + if !empty(get(buf_info, 'virtual_text_entries', [])) + let buf_info.virtual_text_entries = [] + call setbufvar(bufnr, '_neomake_info', buf_info) + endif +endfunction + +if exists('*nvim_create_namespace') " Includes nvim_buf_set_virtual_text. + let s:current_ns = nvim_create_namespace('neomake-virtualtext-current') + let s:all_ns = nvim_create_namespace('neomake-virtualtext-all') + let s:cur_virtualtext = [] + + function! neomake#virtualtext#handle_current_error() abort + " Clean always. + if !empty(s:cur_virtualtext) + if bufexists(s:cur_virtualtext[0]) + call nvim_buf_clear_highlight(s:cur_virtualtext[0], s:cur_virtualtext[1], 0, -1) + endif + endif + if !get(g:, 'neomake_virtualtext_current_error', 1) + return + endif + let entry = neomake#get_nearest_error() + if empty(entry) + let s:cur_virtualtext = [] + else + " Only add it when there is none already (stacking is not + " supported). https://github.com/neovim/neovim/issues/9285 + let buf_info = getbufvar(entry.bufnr, '_neomake_info', {}) + if index(get(buf_info, 'virtual_text_entries', []), entry.lnum) == -1 + let src_id = neomake#virtualtext#add_entry(entry, s:current_ns) + let s:cur_virtualtext = [bufnr('%'), src_id] + endif + endif + endfunction +else + function! neomake#virtualtext#handle_current_error() abort + endfunction +endif + +function! neomake#virtualtext#DefineHighlights() abort + " NOTE: linking to SpellBad etc is bad/distracting (with undercurl). + call neomake#utils#define_derived_highlights('NeomakeVirtualtext%s', ['NONE', 'NONE']) +endfunction + +call neomake#virtualtext#DefineHighlights() + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/contrib/highlight-log b/bundle/neomake/contrib/highlight-log new file mode 100644 index 000000000..59c950331 --- /dev/null +++ b/bundle/neomake/contrib/highlight-log @@ -0,0 +1,144 @@ +#!/usr/bin/env bash + +# This script adds color highlighting to the output from Neomake's Vader tests +# (when called with "vader"), or to the file that gets written into according +# to `neomake_logfile`. +# +# You can use the following to watch colored logs in a terminal window, after +# having used `let g:neomake_logfile = '/tmp/neomake.log'` in Neovim/Vim: +# +# tail -f /tmp/neomake.log | /path/to/neomake/contrib/highlight-log + +bold="" # $(tput bold) +bold_off="" +debug_color="" # $(tput dim), does not work in urxvt (although in infocmp/terminfo). +debug_color_off="" +color_off="" +log_color="" +log_color_off="$bold_off$color_off" +error_color="" +error_color_off="$bold_off$color_off" + +# compact: display test headers, but not inner output for successful ones. +compact=0 + +while [ $# -ne 0 ]; do + case $1 in + --compact) compact=1; shift ;; + --) shift; break ;; + -?*) echo "Unknown option: $1" 1>&2; exit 64 ;; + *) break ;; + esac +done + +if [ "$1" = vader ]; then + # Match non-log lines (i.e. keep output from :Log, which should cause + # all messages from a case to be visible). + # This should also ignore empty lines and lines starting with a character + # (e.g. via NVIM_LOG_FILE:=/dev/stderr, and from :echom). + re_log_line='^(.*( )? )(> .*)$' + re_ignore_log_line='^.*( )? > \[(debug |verbose|warning|error )|((D|V|W|E) +\+[.0-9]+)\]' + + colorize() { + # Only colorize if stdout is connected to a tty (not with :!make). + if ! [ -t 1 ]; then + cat - + return + fi + + # sed: add coloring to Vader's output: + # 1. failures (includes pending) in red "(X)" + # 2. test case header in bold "(2/2)" + # 3. Neomake's error log messages + # 4. Neomake's debug log messages + # 5. non-Neomake log lines (e.g. from :Log) + sed -E -e 's/^(([^ ].*)? +)\([ [:digit:]]+\/[[:digit:]]+\) \[[ [:alpha:]]+\] \(X\).*/'"$error_color"'\0'"$error_color_off"'/' \ + -e 's/^(([^ ].*)? +)(\([ [:digit:]]+\/[[:digit:]]+\))/\1'"$bold"'\3'"$bold_off"'/' \ + -e 's/^ +> \[(error |E \+[.[:digit:]]+)\]: .*/'"$bold"'\0'"$bold_off"'/' \ + -e 's/^ +> \[(debug |D \+[.[:digit:]]+)\]: .*/'"$debug_color"'\0'"$debug_color_off"'/' \ + -e '/'"$re_ignore_log_line"'/! s/'"$re_log_line"'/\1'"$log_color"'\3'"$log_color_off"'/' + } + + if ((compact)); then + # Do not display output for successful tests (i.e. the log statements). + last_start_match= + # Match Vader header ("( 1/33) [EXECUTE] …"), but also if there is output + # from Vim, e.g. with ":colder". + re_vader_header='^([^ ].*)?\ +(\(\ *[0-9]+/[0-9]+\))' + filtering=0 + finished_reading=0 + stopped_filtering=0 + while [ "$finished_reading" = 0 ]; do + if ! read -r; then + if [ -z "$REPLY" ]; then + break + finished_reading=1 + fi + fi + if [[ "$REPLY" == *'Vader error:'* ]] || [[ "$REPLY" == 'Error'* ]] || [[ "$REPLY" == 'Traceback'* ]]; then + printf "\r" >&2 + printf "%s\n" "$REPLY" + continue + fi + if (( stopped_filtering )); then + echo "$REPLY" + continue + fi + if [[ "$REPLY" == *'Starting Vader:'* ]]; then + echo "$REPLY" + elif [[ "$REPLY" == ' Duration: '* ]]; then + echo "$REPLY" + elif [[ "$REPLY" == *'(X)'* ]]; then + # Should also match "(1/1) [EXECUTE] (X) Error: Vim(function):E126: Missing :endfunction" already. + if [[ -n "$filtered" ]]; then + echo "$filtered" + fi + echo "$REPLY" + filtered= + filtering=0 + elif [[ "$REPLY" =~ $re_vader_header ]]; then + filtering=1 + if [[ ${BASH_REMATCH[2]} == "$last_start_match" ]]; then + filtered="$filtered"$'\n'"$REPLY" + else + echo "$REPLY" + filtered= + fi + last_start_match="${BASH_REMATCH[2]}" + elif [[ "$REPLY" == *'Success/Total: '* || "$REPLY" == ' Slowest tests:' ]]; then + echo "$REPLY" + filtering=0 + filtered= + stopped_filtering=1 + elif ! ((filtering)); then + echo "$REPLY" + elif [[ "$REPLY" =~ $re_log_line && ! "$REPLY" =~ $re_ignore_log_line ]]; then + if [[ "$REPLY" =~ '> SKIP:' ]]; then + echo "$REPLY" + continue + fi + if [[ -n "$filtered" ]]; then + echo "$filtered" + fi + echo "$REPLY" + filtered= + filtering=0 + elif [[ -n "$filtered" ]]; then + filtered="$filtered"$'\n'"$REPLY" + else + filtered="$REPLY" + fi + done + else + cat - + fi | colorize + +else + # Output from neomake_logfile. + error='^[:[:digit:]]\+ [[:digit:]]\+ \[E .*' + warn='^[:[:digit:]]\+ [[:digit:]]\+ \[W .*' + debug='^[:[:digit:]]\+ [[:digit:]]\+ \[D .*' + sed -e "s/$error/\0/" \ + -e "s/$warn/w:\0/" \ + -e "s/$debug/$debug_color\\0$debug_color_off/" +fi diff --git a/bundle/neomake/contrib/run-tests-watch b/bundle/neomake/contrib/run-tests-watch new file mode 100644 index 000000000..11edbdf04 --- /dev/null +++ b/bundle/neomake/contrib/run-tests-watch @@ -0,0 +1,127 @@ +#!/bin/sh -x +# +# Wrapper around inotifywait to run tests on file changes. +# If a test file changes, only this file is run (first), while the whole test +# suite is run afterwards (and initially). +# +# The recommended way to run it is via `make testwatch`, or `make testwatchx` +# (to exit on first failure). +# +# # Internal documentation: +# The default run command is "make %s" (where %s gets replaced with the test +# file(s)), and can be given as first argument. +# +# You can specify VADER_OPTIONS=-x to exit on the first test failure: +# VADER_OPTIONS=-x contrib/run-tests-watch +# or use the following: +# contrib/run-tests-watch 'make %s VADER_OPTIONS=-x' +# +# VADER_ARGS gets used to focus on a specific test file initially, until +# another test file gets changed. + +watch="autoload plugin tests" +echo "Watching: $watch" + +if [ -n "$1" ]; then + cmdpattern="$1" +else + cmdpattern="make %s VADER_OPTIONS='$VADER_OPTIONS'" +fi + +title() { + printf '\e]1;%s\a' "$*" + printf '\e]2;%s\a' "$*" +} + +status_file=$(mktemp) +handle_cmd_result() { + if [ "$1" = 0 ]; then + last_test_succeeded=1 + title "✔ $2" + if [ "${2#*${alltestsfile}*}" != "$2" ]; then + alltests_succeeded=1 + fi + else + last_test_succeeded=0 + title "✘ $2" + if [ "${2#*${alltestsfile}*}" != "$2" ]; then + alltests_succeeded=0 + fi + fi + echo "$last_test_succeeded $alltests_succeeded" > "$status_file" +} + +# Recursively kill childs - required to get out of a running pdb. +kill_with_childs() { + for p in $(pgrep -P "$1"); do + kill_with_childs "$p" + done + if kill -0 "$1" 2>/dev/null; then + kill "$1" || true + fi +} + +alltestsfile='tests/all.vader' +alltests_succeeded=0 +pid= +changed_files= +set -e +last_changed_testsfile="${VADER_ARGS:-$alltestsfile}" + +while true; do + testfiles="$last_changed_testsfile" + if [ -n "$changed_files" ]; then + # There was a previous run + echo "=================================================================" + echo "changed file: $changed_files" + + read -r last_test_succeeded alltests_succeeded < "$status_file" || alltests_succeeded=0 + + if [ "${changed_files#tests/}" != "$changed_files" ] \ + && [ "${changed_files#tests/include/}" = "$changed_files" ]; then + # A test file was changed (but not an include file). + last_changed_testsfile="$changed_files" + testfiles="$last_changed_testsfile" + + # Run full tests afterwards (if not successful before). + if [ "$testfiles" != "$alltestsfile" ] && [ "$alltests_succeeded" = 0 ]; then + testfiles="$testfiles $alltestsfile" + fi + + elif [ "$last_test_succeeded" = 1 ]; then + # Run all tests. + alltests_succeeded=0 + testfiles="$alltestsfile" + + if [ "${VADER_OPTIONS#*-x*}" != "$VADER_OPTIONS" ]; then + # Run tests matching the changed file first, e.g. tests/config.vader for + # autoload/neomake/config.vim. + test_file_for_changed_file="tests/${changed_files#autoload/neomake/}" + test_file_for_changed_file="${test_file_for_changed_file%.vim}.vader" + declare -p test_file_for_changed_file + if [ -f "$test_file_for_changed_file" ]; then + testfiles="$test_file_for_changed_file $testfiles" + fi + fi + fi + + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + echo 'Killing previous run…' + kill_with_childs "$pid" + fi + fi + + # shellcheck disable=SC2059 + cmd="$(printf "$cmdpattern" "$testfiles")" + echo "Running $cmd" + title "… $testfiles" + # shellcheck disable=SC2015 + (set +e; eval "$cmd"; handle_cmd_result "$?" "$testfiles") +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +RETURN_CODE=0 + +function print_help() { + echo "Usage: ./custom-checks FILE|DIRECTORY…" 1>&2 + echo 1>&2 + echo " -h, --help Print this help text" 1>&2 + exit 1 +} + +while [ $# -ne 0 ]; do + case $1 in + -h) ;& --help) + print_help + ;; + --) + shift + break + ;; + -?*) + echo "Invalid argument: $1" 1>&2 + exit 1 + ;; + *) + break + ;; + esac +done + +if [ $# -eq 0 ] || [ -z "$1" ]; then + print_help +fi + +shopt -s globstar + +args=("$@") + +expand_arg() { + if [[ -d $arg ]]; then + expanded_arg=("$arg"/**/*.vim) + else + expanded_arg=("$arg") + fi +} + +check_errors() { + regex="$1"; shift + message="$1"; shift + + for arg in "${args[@]}"; do + expand_arg "$arg" + # Ensure that errors from grep are not ignored, i.e. busybox's grep + # does not have "--with-filename". + set +e + output="$(grep "$@" --with-filename -n "$regex" "${expanded_arg[@]}" 2>&1)" + ret=$? + set -e + if (( ret > 1 )); then + echo "$output" + RETURN_CODE=2 + continue + fi + if [[ -z "$output" ]]; then + continue + fi + + while IFS= read -r match; do + RETURN_CODE=1 + echo "$match $message" + done < <(echo "$output" \ + | grep -o '^[^:]\+\(:[0-9]\+\)\?:' \ + | sed 's:^\./::') + done +} + +check_errors \ + '^\s*function.*) *$' \ + 'Function without abort keyword (See :help except-compat)' +check_errors ' \+$' 'Trailing whitespace' +check_errors '^ * end\?i\? *$' 'Write endif, not en, end, or endi' +check_errors '^(( )*([^ ]|$)|\s+\\)' 'Use four spaces for indentation' -v -E +check_errors $'\t' 'Do not use tabs for indentation' +check_errors '^\s*[^" ].*[^&]l:[a-z]' 'Do not use l: prefix for local variables' +for arg in "${args[@]}"; do + expand_arg "$arg" + grep --files-without-match '^"[ ]vim: ts=4 sw=4 et' "${expanded_arg[@]}" \ + | while read -r f; do + echo "$f:$(( $(wc -l "$f" | cut -f1 -d\ ) + 1)): Missing modeline" + done +done + +exit $RETURN_CODE diff --git a/bundle/neomake/contrib/vimhelplint b/bundle/neomake/contrib/vimhelplint new file mode 100644 index 000000000..3a87e2c4b --- /dev/null +++ b/bundle/neomake/contrib/vimhelplint @@ -0,0 +1,46 @@ +#!/bin/sh +# A wrapper around vim-vimhelp (https://github.com/machakann/vim-vimhelplint). +# +# This file is automatically used by autoload/neomake/makers/ft/help.vim, if +# vimhelplint is installed in Neomake's build dir (and `vimhelplint` is not +# found as an executable). +# +# You can run `make build/vimhelplint` (from Neomake's root) to +# download/install it into Neomake's build dir, and Neomake will use this for +# help files then. + +if [ -z "$VIMHELPLINT_DIR" ]; then + # Change to parent dir (not POSIXly, but resolving symlinks). + CDPATH='' cd -P -- "$(dirname -- "$(readlink -f -- "$0" 2>/dev/null || echo "$0")")/.." || exit + VIMHELPLINT_DIR=$PWD/build/vimhelplint + cd - >/dev/null || exit +fi +vimhelplint=${VIMHELPLINT_DIR}/ftplugin/help_lint.vim + +if ! [ -f "$vimhelplint" ]; then + echo "$vimhelplint not found." >&2 + echo "Run 'make build/vimhelplint' Neomake's root directory to install it." >&2 + exit 64 +fi + +file="$1" +if [ -z "$file" ]; then + echo 'No input file specified.' >&2 + exit 64 +fi +if ! [ -e "$file" ]; then + echo "File $file is not readable." >&2 + exit 1 +fi + +out=$(${VIMHELPLINT_VIM:-vim} -esN -u NONE -i NONE \ + -c "silent edit $1" \ + -c 'set ft=help' \ + -c "source $vimhelplint" \ + -c 'verb VimhelpLintEcho' \ + -c 'qall!' 2>&1) +if [ -z "$out" ]; then + exit 0 +fi +echo "$out" +exit 1 diff --git a/bundle/neomake/doc/neomake.txt b/bundle/neomake/doc/neomake.txt new file mode 100644 index 000000000..c2692a90b --- /dev/null +++ b/bundle/neomake/doc/neomake.txt @@ -0,0 +1,1056 @@ +*neomake.txt* - asynchronous make for Vim version 7.4+ and Neovim + + ███╗ ██╗███████╗ ██████╗ ███╗ ███╗ █████╗ ██╗ ██╗███████╗ + ████╗ ██║██╔════╝██╔═══██╗████╗ ████║██╔══██╗██║ ██╔╝██╔════╝ + ██╔██╗ ██║█████╗ ██║ ██║██╔████╔██║███████║█████╔╝ █████╗ + ██║╚██╗██║██╔══╝ ██║ ██║██║╚██╔╝██║██╔══██║██╔═██╗ ██╔══╝ + ██║ ╚████║███████╗╚██████╔╝██║ ╚═╝ ██║██║ ██║██║ ██╗███████╗ + ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ + + Run make tasks (such as linters and build tools) asynchronously. + +============================================================================== +CONTENTS *neomake* + + 1. Introduction ............................... |neomake-introduction| + 2. Commands ....................................... |neomake-commands| + 3. Configuration ............................. |neomake-configuration| + 3.1. Automake ..................................... |neomake-automake| + 4. Functions ..................................... |neomake-functions| + 5. Autocommands/Hooks ............................. |neomake-autocmds| + 6. Frequently Asked Questions (FAQ) .................... |neomake-faq| + +============================================================================== +1. Introduction *neomake-introduction* + +Neomake leverages Neovim's or Vim's |job-control| feature where available to +run programs like syntax checkers asynchronously. Where job control is not +available, it resorts to a synchronous |system()| call, making it possible to +run this plugin in both older Vims and Neovim. +This plugin is heavily inspired by Vim plugins such as Syntastic and +dispatch. + +============================================================================== +2. Commands *neomake-commands* + + *:Neomake* + *:NeomakeFile* +:Neomake [makers] Run a make command with the current file as input. If + no makers are specified, the default makers for the + current |filetype| are used. See + |neomake-configuration| for more on makers. + + *:Neomake!* + *:NeomakeProject* +:Neomake! [makers] Run a make command with no file as input. If no makers + are specified, the default top-level makers will be + used. If no default top-level makers exist, + 'makeprg' will be used. + + *:NeomakeSh* +:NeomakeSh {command} Run {command} in a shell (according to 'shell'). The + command output will be loaded into the quickfix list + when the job is complete. Example: > + :NeomakeSh find . -name '*.pyc' +< + *:NeomakeSh!* +:NeomakeSh! {command} Same as |:NeomakeSh|, but does not buffer the output. + Example: > + :NeomakeSh! while true; do date; sleep 1; done +< + *:NeomakeInfo* +:NeomakeInfo Display information, meant for debugging and inclusion + in bug reports / help requests. + + *:NeomakeListJobs* +:NeomakeListJobs List all running jobs in the format: > + job_id job_name +< + *:NeomakeCancelJob* +:NeomakeCancelJob {job_id} + Terminate a job identified by its job_id. + + *:NeomakeCancelJobs* +:NeomakeCancelJobs + Terminate all jobs. + + *:NeomakeClean* + *:NeomakeClean!* +:NeomakeClean[!] + Clean signs, highlights etc. for file-mode, or + project-mode (with bang). + +============================================================================== +2.1. Toggle commands *neomake-toggle* + +The following commands enable, disable or toggle Neomake globally, per tab or +per buffer by changing the `disabled` setting, which gets checked when Neomake +gets called via autocommands, e.g. with |neomake-automake| or custom +autocommands. You can still call e.g. |:Neomake| manually, and it will run. +In verbose mode (e.g. when called with |:verbose| (`:verb Neomake`)) the new +status gets displayed. + +*:NeomakeToggle* toggles Neomake globally. +*:NeomakeToggleBuffer* toggles Neomake for the current buffer. +*:NeomakeToggleTab* toggles Neomake for the current tab. + *neomake-disable* +*:NeomakeDisable* disables Neomake globally. +*:NeomakeDisableBuffer* disables Neomake for the current buffer. +*:NeomakeDisableTab* disables Neomake for the current tab. + *neomake-enable* +*:NeomakeEnable* enables Neomake globally. +*:NeomakeEnableBuffer* enables Neomake for the current buffer. +*:NeomakeEnableTab* enables Neomake for the current tab. + +*:NeomakeStatus* displays the current status. + +============================================================================== +3. Configuration *neomake-configuration* + +If you just want an easy way to run |:make| asynchronously, you're all set. +Just set your 'makeprg' and 'errorformat' as usual, and run |:Neomake!|. +If you want more, read on. + +3.1 Automaking *neomake-automake* + +To configure Neomake to automatically run on certain events you can use +`neomake#configure#automake()`. + +The first argument can either be a dictionary (mapping autocommand event +names to config dicts for fine grained control), or a string (as a shortcut to +configure certain modes). The 2nd argument is the default delay to use. + +String usage (simple setup):~ + + n: normal mode~ + This uses the |TextChanged| (falling back to |CursorHold|) and |InsertLeave| + events. + + i: insert mode~ + This uses the |TextChangedI| event (falling back to |CursorHoldI|). + + r: "read" mode - when a buffer gets read/open~ + This will hook into the |BufWinEnter|, |FileType| and |FileChangedShellPost| + events. + + w: "write" mode - when a buffer gets written~ + This uses the |BufWritePost| event, with an explicit timeout of 0. + +Examples: > + + " When writing a buffer. + call neomake#configure#automake('w') + " When writing a buffer, and on normal mode changes (after 750ms). + call neomake#configure#automake('nw', 750) + " When reading a buffer (after 1s), and when writing. + call neomake#configure#automake('rw', 1000) + +Dictionary usage (advanced setup):~ +> + call neomake#configure#automake({ + \ 'TextChanged': {}, + \ 'InsertLeave': {}, + \ 'BufWritePost': {'delay': 0}, + \ 'BufWinEnter': {}, + \ }, 500) +< +This will trigger Neomake on |TextChanged|, |InsertLeave|, |BufWritePost| and +|BufWinEnter|, with a delay of 500ms by default, but 0 for |BufWritePost|. + +You could do some advanced setup, based on if your laptop is running on +battery: > + function! MyOnBattery() + return readfile('/sys/class/power_supply/AC/online') == ['0'] + endfunction + if MyOnBattery() + call neomake#configure#automake('w') + else + call neomake#configure#automake('nrw', 1000) + endif +< + *neomake-automake-dynamic-delay* +The automake delay gets adjusted dynamically when timers or make runs get +aborted. This is meant to support the use case where you are doing multiple +changes in succession (e.g. |undo|). +This can be controlled with the experimental `automake.cancelation_delay` +setting, which has to be a list: > + call neomake#configure('automake.cancelation_delay', [0.2, 0.5, 3000]) +> +The first value gets multiplied with the number of restarted timers (before a +make was triggered). +The second value gets multiplied with canceled/restarted make runs. +The sum of those values plus 1 gets multiplied with the original/configured +delay. The third value is used as a maximum. +With the default settings from above this means that given a default delay of +500ms, 7 restarted timer, and 1 restarted make run, it would use a delay of +`(7*0.2 + 1*0.5 + 1) * 500 = 1450`. +The counts for restarted timers and make runs gets reset once a make run +finishes. + +Makers *neomake-makers* +A maker is an object that tells Neomake how to run a job for you. + + *neomake-makers-get_list_entries* +If a maker has a `get_list_entries` function, this gets used to retrieve +entries for the location or quickfix list directly. +The function gets passed a jobinfo (|neomake-object-jobinfo|) object, and +should return a list of entries that will be used to fill the +location/quickfix list: > + let maker = {'name': 'My maker'} + function! maker.get_list_entries(jobinfo) abort + return [ + \ {'text': 'Some error', 'lnum': 1, 'bufnr': a:jobinfo.bufnr}, + \ {'text': 'Some warning', 'type': 'W', 'lnum': 2, 'col': 1, + \ 'length': 5, 'filename': '/path/to/file'}, + \ ] + endfunction +< +The required keys for entries are `text` and `lnum`, and you should set one of +`bufnr` or `filename` (otherwise the entry will not be valid). +The `length` entry in the example is internal to Neomake, and sets the length +for an highlight (see |neomake-highlight|). + + *neomake-job-makers* +Otherwise a maker gets run as a job with a file as input ("file mode", good +for linting), or with no file as input ("project mode", good for building and +project-level tasks). + +Here is a sample maker definition: > + let g:neomake_make_maker = { + \ 'exe': 'make', + \ 'args': ['--build'], + \ 'errorformat': '%f:%l:%c: %m', + \ } + " Use the maker like this: + :Neomake! make +< + *neomake-makers-InitForJob* +You can configure a maker dynamically through a `InitForJob` function, which +gets the jobinfo (|neomake-object-jobinfo|) as its argument. +`self` refers to the maker instance therein, which is not copied (i.e. +mutating `self.args` would change it for following jobs also). +It is possible to return a new instance based on that (factory pattern): > + + function! MyCustomExe(jobinfo) abort + let maker = deepcopy(self) + call insert(maker.args, maker.exe) + let maker.exe = 'some_custom_wrapper' + return maker + endfunction + call neomake#config#set('ft.python.InitForJob', function('MyCustomExe')) +< + *neomake-makers-exe* + *neomake-makers-args* +`exe` has to be a string, while `args` can be a list or a string. +If `args` is a list, entries like '%' and '%:p' will be |expand()|ed, and +quoting/escaping is applied automatically. If you want to handle escaping +yourself, `args` should be a string. + +In the above example, the exe argument isn't strictly necessary, since Neomake +uses the name of the maker as the default value for it. If you want it to be +usable on an individual file, you should also include the filetype in the +name: > + let g:neomake_c_lint_maker = { + \ 'exe': 'lint', + \ 'args': ['--option', 'x'], + \ 'errorformat': '%f:%l:%c: %m', + \ } + + " Run this maker for the open file (runs "lint --option x myfile.c"): + :Neomake lint + + " Or run it on the whole project, executing the command from Vim's current + " working directory (runs "lint --option x"): + :Neomake! c_lint +< + *neomake-args-file* +When running a maker on a file with |:Neomake|, you may want to control where +in the `args` list the file's path will appear. To do this, insert '%t' in +the `args` list and use `append_file=0`: > + let g:neomake_c_lint_maker = { + \ 'exe': 'lint', + \ 'args': ['%t', '--option', 'x'], + \ 'append_file': 0, + \ 'errorformat': '%f:%l:%c: %m', + \ } +< +This will cause "lint /path/to/file.c --option x" to be run instead of +"lint --option x /path/to/file.c". + +`%t` gets replaced with the absolute path to the file (handling any temporary +file). + + *neomake-makers-processing* +A job maker's output gets processed in two ways: +1. through a maker's `process_output` function, or +2. via its `errorformat` (together with `mapexpr` and `postprocess`). + + *neomake-makers-process_output* +If a maker has a `process_output` function, this gets used to retrieve +entries for the location or quickfix list for the job's output directly. + +The function gets called with a `context` dictionary, with the following +entries: + - `output`: a list of lines + - `source`: the source of the output (`stderr`, `stdout`) + - `jobinfo`: the jobinfo object, see |neomake-object-jobinfo| +It should return a list of entries (dictionaries), where `text` and `lnum` +are required. `bufnr` defaults to the jobs's buffer. + +Using this method skips the processing based on `errorformat` (including +`mapexpr` and `postprocess`). + +See |neomake-makers-process_json| below for handling JSON output. + + *neomake-makers-process_json* +A maker's `process_json` function gets a |dict| with parsed JSON directly, +handling the JSON parsing and any errors before. + +The function gets called with a `context` dictionary, containing the following +entries: + - `json`: a dictionary with the parsed JSON + - `source`: the source of the output (`stderr`, `stdout`) + - `jobinfo`: the jobinfo object, see |neomake-object-jobinfo| +It should return a list of entries (dictionaries), where `text` and `lnum` +are required. `bufnr` defaults to the jobs's buffer. + +Using this method skips the processing based on `errorformat` (including +`mapexpr` and `postprocess`). + + *neomake-makers-filter_output* +A maker's `filter_output` function can filter any output before it gets +processed further. + +The function gets called with two arguments: the list of lines (to be modified +in place) and a context dictionary with the following entries: + - `source`: the source of the output (`stderr`, `stdout`) + - `jobinfo`: the jobinfo object, see |neomake-object-jobinfo| + + *neomake-makers-mapexpr* +You can define two optional properties on a maker object to process its +output: `mapexpr` is applied to the maker's output before any processing, and +`postprocess` is applied to each of the quickfix or location list entries. + +The `mapexpr` property gets passed directly into |map()| as the `expr` +argument: > + call map(lines, maker.mapexpr) + + "printf('[%s] %s', neomake_output_source, v:val)" +< + *neomake-makers-postprocess* +The `postprocess` property is a function (or list of functions) that get(s) +called for each entry in the location or quickfix list. +It allows to change entries there or remove them by setting the `valid` entry +to `-1`. + +Example: make all entries a warning where `nr` is in the range of 100-199: > + function PostprocessLintMaker(entry) + if a:entry.nr >= 100 && a:entry.nr < 200 + let a:entry.type = 'W' + endif + endfunction + let g:neomake_ft_lint_maker = { + \ 'exe': 'lint', + \ 'args': ['--option', 'x'], + \ 'errorformat': '%f:%l:%c:%n: %m', + \ 'postprocess': function('PostprocessLintMaker') + \ } +< +Example: remove some entry for a specific maker (using |expr-lambda|): > + let g:neomake_asciidoc_asciidoc_postprocess = { + \ entry -> entry.text =~# 'illegal system attribute name: font-style' + \ ? extend(entry, {'valid': -1}) + \ : entry} +< + +Builtin postprocessors are `neomake#postprocess#compress_whitespace`, which +fixes whitespace issues (which is useful with multiline error messages), +and `neomake#postprocess#generic_length`, which adds a length property (used +for highlights |neomake-highlight|) for entries, when the message refers to an +identifier at the entry's column. +See `neomake#makers#ft#text#PostprocessWritegood` for an example. + +Entries can be selectively removed in post-processing by setting its "valid" +property to `-1`. This removal will happen even if `remove_invalid_entries` +is disabled. This feature is meant for conditional removals and a simpler way +for end users to filter list entries. Makers should handle removals through +|errorformat| using '%-G' to remove items that should never appear in the +error list. + + *neomake-makers-buffer_output* +Default: 1 +By default Neomake will only process the output from makers when either the +output type changes (from stderr to stdout or vice versa), or at the end of +the job. + +If you have a maker that is expected to run longer, and you want to get +feedback as early as possible, you can set this to `0`. + +You can override this for a maker using e.g.: > + let g:neomake_ft_test_maker_buffer_output = 0 +< +Your results will appear earlier, but if the 'errorformat' is meant to parse +multiline output this will likely cause issues (depending on how the maker +flushes its output). + +To change the default for all makers use: > + call neomake#config#set('maker_defaults.buffer_output', 0) +< + *neomake-makers-remove_invalid_entries* +Default: 0 +This option filters invalid entries from makers from the location/quickfix +list (i.e. entries that do not match the 'errorformat', and that would show +up with a `||` prefix in the location/quickfix list): > + let g:neomake_ft_maker_remove_invalid_entries = 1 +< +NOTE: the default for this is 0, because unhandled/unexpected output might be +useful, e.g. when the program displays some error. +Makers should handle this properly through |errorformat|, e.g. by using '%-G' +(see |efm-ignore| and |neomake-faq-errorformat|). + +To change the default for all makers use: > + call neomake#config#set('maker_defaults.remove_invalid_entries, 1) +< + *neomake-makers-cwd* +The working directory of a maker defaults to the current working directory +of the make run (|getcwd()|). +The `cwd` property overrides this, and gets expanded in the context of the +current buffer. Special buffers (like fugitive blobs) get handled for values +starting with `%:` (typically used in this context), falling back to +|expand()|. See |filename-modifiers|. + > +Example: change to the buffer's directory: > + let g:neomake_my_example_maker = { + \ 'exe': 'pwd', + \ 'cwd': '%:p:h' + \ } +< + *neomake-makers-tempfile_enabled* +Default: 1 +This will pass a temporary file with the buffer's contents to the maker, in +case the buffer is not readable, modified, or has no filename. +A maker can specify the temporary file's name through the `tempfile_name` +property, and you can set it through the |neomake-makers-InitForJob| callback +(for advanced usage). +Otherwise it gets generated based on the original filename/filetype, and +falls back to using |tempname()|. + +You can configure this per buffer or maker as usual, e.g.: > + let g:neomake___tempfile_enabled = 0 +< + *neomake-makers-tempfile_dir* +Default: unset +You can configure the directory to use for temporary files (see +|neomake-makers-tempfile_enabled|). + +The default behavior is to use the same directory as the original file, so +that any config files (e.g. `setup.cfg` for Python tools) take effect. + +You can configure this per buffer or maker as usual, e.g.: > + let g:neomake___tempfile_dir = '/tmp/custom' +< +The value gets expanded (via `neomake#utils#ExpandArgs`), which allows for +the following to use the original file's directory structure (`%:p:h`): > + let g:neomake_tempfile_dir = '/tmp/custom%:p:h' +< + *neomake-makers-output_stream* +Default: "both" ("stdout", "stderr", "both") +The `output_stream` setting specifies what stream gets used for output from +the maker. +Any output on a stream not configured here gets reported as unexpected output. + + *neomake-makers-supports_stdin* +Default: 0 +With `supports_stdin = 1` a maker indicates that it can use stdin instead of a +temporary file. By default "-" is then used for the filename. + +`supports_stdin` can be a dict function on the maker, which will get the +current jobinfo as its argument, and should return 1 or 0. +This function can change `self.args`, which is useful to append options like +e.g. "['--stdin-display-name', '%:p']". +You can also change `self.tempfile_name` therein. +It can be useful to change the current working directory for the maker here, +e.g. when it does not use its `--stdin-display-name` (or similar) option +to look for its config. Use the jobinfo's `cd` method for this: > + function! maker.supports_stdin(jobinfo) abort + let self.args += ['--stdin-display-name', '%:.'] + call a:jobinfo.cd('%:h') + return 1 + endfunction +< + *neomake-makers-uses_stdin* +Default: 0 +`uses_stdin = 1` can be used to always use stdin for file arguments, +regardless of if a temporary file / stdin is required to be used. +It uses "-" as the default for "tempfile_name". + +Global Options *neomake-options* + +*g:neomake__maker* +*g:neomake___maker* +Define a new filetype or project-level maker. See |neomake-makers|. + + *neomake-makers-properties* +*g:neomake__* +*g:neomake___* +*b:neomake__* +*b:neomake___* +Configure properties for a maker where is one of `exe`, `args`, +`errorformat`, `buffer_output`, `remove_invalid_entries`, `append_file`, +or `supports_stdin`. + +This can also be set per buffer, e.g.: > + let g:neomake_javascript_jshint_exe = './myjshint' + let b:neomake_javascript_jshint_exe = './myotherjshint' +< + +The global defaults can be configured using `g:neomake_`, i.e. +*g:neomake_remove_invalid_entries* to remove invalid entries from the quickfix +/ location list (|neomake-makers-remove_invalid_entries|), unless explicitly +provided by the maker or overridden by your global/buffer setting. + +The internal defaults are: > + let defaults = { + \ 'exe': maker.name, + \ 'args': [], + \ 'errorformat': &errorformat, + \ 'buffer_output': 0, + \ 'remove_invalid_entries': 0 + \ } +< + +*g:neomake__enabled_makers* +*b:neomake__enabled_makers* +This setting will tell Neomake which makers to use by default for the given +filetype `` (when called without a maker as an argument, i.e. |:Neomake|). + +The default for this setting is the return value of the function +`neomake#makers#ft##EnabledMakers`. For Python this is defined in +`./autoload/neomake/makers/ft/python.vim`, and might return: > + ['python', 'frosted', 'pylama'] +< +This setting can also be defined per buffer, so the following snippet can be +used to configure a custom set of makers from your vimrc: > + let g:neomake_python_enabled_makers = ['pep8', 'pylint'] + augroup my_custom_maker + au! + au Filetype custom.py let b:neomake_python_enabled_makers = ['flake8'] + augroup END +< +Please refer to |autocmd-patterns| for help on defining the pattern +(`custom.py`) in this case. + +*g:neomake_enabled_makers* +*b:neomake_enabled_makers* +This setting will tell Neomake which makers to use by default when not +operating on a single file, or when no makers are defined for the filetype of +the current buffer. This effectively defaults to: > + let g:neomake_enabled_makers = ['makeprg'] +< +*g:neomake_open_list* +*b:neomake_open_list* +This setting will open the |location-list| or |quickfix| list (depending on +whether it is operating on a file) when adding entries. A value of 2 will +preserve the cursor position when the |location-list| or |quickfix| window is +opened. Defaults to 0. + +*g:neomake_list_height* +*b:neomake_list_height* +The maximum height of the |location-list| or |quickfix| list window opened by +Neomake. If there are fewer entries it will use that instead. +Defaults to 10. + +*g:neomake_echo_current_error* +This setting will |:echo| the error for the line your cursor is on, if any. +It uses a timer (if |timers| are available), and |CursorHold|/|CursorHoldI| +otherwise. +Defaults to 1. + +*g:neomake_virtualtext_current_error* +Use Neovim's virtualtext API to display the error for the current line next +to the text. This is experimental, and uses the same mechanism (timer) +as |g:neomake_echo_current_error|. +Defaults to 1 (only available on Neovim 0.3.2+). + +*g:neomake_virtualtext_prefix* +The prefix used with |g:neomake_virtualtext_current_error|. +Defaults to "❯ ". + +*g:neomake_cursormoved_delay* +Delay (in ms) for the timer used to echo the current error with +|g:neomake_echo_current_error|. +Defaults to 100. + +*g:neomake_serialize* +Setting this to 1 tells Neomake to run each enabled maker one after the other. +This is a good way to ensure messages don't get mixed up. This setting is +implied with non-async Vim versions. + +*g:neomake_serialize_abort_on_error* +Setting this to 1 tells Neomake to abort after the first error status is +encountered. This setting only works when |g:neomake_serialize| is on. + +*g:neomake_verbose* +Controls how verbose Neomake should be. Neomake log levels are as follows: + 0 - Errors only + 1 - Quiet message + 2 - Loud message (may log multiple messages at once, making the screen + shift momentarily) + 3 - Debug information (all messages). + This will also add time information to messages. +Each log level includes all the levels before it. + +Defaults to 1. + +'verbose' gets added to this setting, so you can use |:verbose| to increase +the verbosity temporarily: > + :3verb Neomake +< +*g:neomake_logfile* +Setting this to a file path will write all messages (regardless of the level +configured through |g:neomake_verbose|) into it. +This is useful for debugging/hacking, and when reporting issues. +It requires Vim 7.4.503+ (or Neovim) to work properly, otherwise it will not +append, but overwrite the file with each message. + + *neomake-signs* +*g:neomake_place_signs* +This setting enables the placement of signs next to items from the location +and quickfix list (i.e. errors/warnings etc recognized from the +'errorformat'). Defaults to 1. + +*g:neomake_error_sign* +*g:neomake_warning_sign* +*g:neomake_info_sign* +*g:neomake_message_sign* +These options allow you to control the appearance of the signs that are +placed into the |signs| column next to lines with messages. +These are dictionaries that represent the parameters provided by +|:sign-define|. Here is an example definition: > + let g:neomake_error_sign = { + \ 'text': 'E>', + \ 'texthl': 'ErrorMsg', + \ } +< +See the |:highlight| command to list the highlight groups available to you or +create new ones. + +Neomake uses the following defaults: > + + let g:neomake_error_sign = { + \ 'text': '✖', + \ 'texthl': 'NeomakeErrorSign', + \ } + let g:neomake_warning_sign = { + \ 'text': '‼', + \ 'texthl': 'NeomakeWarningSign', + \ } + let g:neomake_message_sign = { + \ 'text': '➤', + \ 'texthl': 'NeomakeMessageSign', + \ } + let g:neomake_info_sign = { + \ 'text': 'ℹ', + \ 'texthl': 'NeomakeInfoSign' + \ } +< + +Default |highlight-groups| are created with those names, but only if they do +not exist already, which allows you to customize them. This should typically +be done through the |ColorScheme| autoevent, which applies it after any color +scheme: > + + augroup my_neomake_signs + au! + autocmd ColorScheme * + \ hi NeomakeErrorSign ctermfg=white | + \ hi NeomakeWarningSign ctermfg=yellow + augroup END +< +You can use `neomake#utils#GetHighlight` to get e.g. the "bg" from +"SignColumn". See `neomake#signs#DefineHighlights` where this is used. + + *neomake-highlight* +*g:neomake_highlight_columns* +This setting enables highlighting of columns for items from the location and +quickfix list. Defaults to 1. + +*g:neomake_highlight_lines* +This setting enables highlighting of lines for items from the location and +quickfix list. Defaults to 0. + +If both |g:neomake_highlight_columns| and |g:neomake_highlight_lines| are +enabled, items with column information are highlighted using the column. + +The following highlighting groups are used: + - NeomakeError: links to "SpellBad" (|hl-SpellBad|) + - NeomakeWarning: links to "SpellCap" (|hl-SpellCap|) + - NeomakeInfo: links to "NeomakeWarning" + - NeomakeMessage: links to "NeomakeWarning" + +You can define them yourself: > + + augroup my_neomake_highlights + au! + autocmd ColorScheme * + \ highlight NeomakeError … | + \ highlight NeomakeWarning … + guisp=White + augroup END +> + +*g:airline#extensions#neomake#enabled* +Shows warning and error counts returned by |neomake#statusline#LoclistCounts| +in the warning and error sections of the vim-airline 'statusline'. Defaults +to 1. + +============================================================================== +4. Functions *neomake-functions* + +This list is non-exhaustive at the moment, but you may find some of these +functions useful. + +*neomake#Make* (options) +This is the main entrypoint to Neomake, used by the |:Neomake| (and +|:Neomake!|) command. + +`options` is a dictionary, and might include: +- `file_mode`: 1 if the makers should get run against a single file (typically + used for linting). Default: 1. +- `enabled_makers`: the makers to use (list). Default: uses configuration. + +Returns: a list of jobinfo objects (|neomake-object-jobinfo|). + +Deprecated interface (with different return value)~ +The old and deprecated API will accept the following arguments instead of the +`options` dict: filemode, enabled_makers[, exit_callback]. +The `exit_callback` (which should get replaced by using the +|NeomakeJobFinished| or |NeomakeFinished| hooks) gets the following dictionary +as its sole argument: > + { 'status': , + \ 'name': , + \ 'has_next': <1 if another maker follows, 0 otherwise> } +Returns: a list of job ids. + +*neomake#Sh* (command[, callback]) +This function is called by the |:NeomakeSh| command. It runs the specified +shell `command` according to 'shell'. |neomake#Sh| returns the single job id +that was created (-1 on Vim without asynchronous support); you can potentially +cancel this job with |neomake#CancelJob|. + +It also accepts a second, optional callback argument that is called when +the command exits. The callback is given the following dictionary as its +sole argument: > + { 'status': , + \ 'name': 'sh: ', + \ 'has_next': 0 } +< +The callback will receive a `jobinfo` object dict as `self` +(|dict-functions|). + +*neomake#ListJobs* +Invoked via |:NeomakeListJobs|. Echoes a list of running jobs in the format +(job_id, job_name). + +*neomake#CancelJob* +Invoked via |:NeomakeCancelJob|. Terminate a job identified by its job_id. +Example: > + let job_id = neomake#Sh("bash -c 'while true; do sleep 1; done'") + call neomake#CancelJob(job_id) + +*neomake#signs#RedefineErrorSign* +*neomake#signs#RedefineWarningSign* +These functions define the error sign and the warning sign respectively. They +optionally take a dictionary in the same format as |g:neomake_error_sign|. If +no such dictionary is provided, the default values will be used. These +functions may be useful if somehow |:Neomake| is being invoked before you +define |g:neomake_error_sign|. > + let g:neomake_error_sign = {'text': 'D:'} + call neomake#signs#RedefineErrorSign() +< + *neomake-statusline* +The main function for statusline integration is `neomake#statusline#get()`, +which caches the information retrieved from `neomake#statusline#get_status()`. + +*neomake#statusline#get()* [options] +The function requires the buffer number as first argument, and an optional +dictionary. You might want to use |g:actual_curbuf| for bufnr, if calling +`neomake#status#get()` from a statusline expression, but then highlights are +not evaluated, and you typically want to use this in a statusline function +(`'set statusline=%!MyStatusLine()'`) instead. + +Returns a string for a 'statusline'. + +The optional argument is a dictionary of options (see below). + +The following example creates a custom 'statusline' function, where `a:active` +may reflect if the window is the current one (implementation not provided): > + let neomake_status_str = neomake#statusline#get(bufnr, { + \ 'format_running': '… ({{running_job_names}})', + \ 'format_loclist_ok': + \ (a:active ? '%#NeomakeStatusGood#' : '%*').'✓', + \ 'format_quickfix_ok': '', + \ 'format_quickfix_issues': (a:active ? '%s' : ''), + \ 'format_status': '%%(%s' + \ .(a:active ? '%%#StatColorHi2#' : '%%*') + \ .'%%)', + \ }) +< +A simpler example: > + let neomake_status_str = neomake#statusline#get(bufnr, { + \ 'format_running': '… ({{running_job_names}})', + \ 'format_loclist_ok': '✓', + \ 'format_quickfix_ok': '', + \ 'format_quickfix_issues': '%s', + \ }) +< +You can use the following options: + +For location list items:~ + - format_loclist_unknown: format for when the status for location list + issues is unknown, i.e. Neomake was not run on the current buffer. + Default: `'?'` + - format_loclist_ok: format for when there are no location list issues. + Default: `'%#NeomakeStatusGood#✓%#NeomakeStatReset#'` (a checkmark using + the NeomakeStatusGood highlight group). + - format_loclist_type_X: format for location list issues of type X + (E, W, I, …). + Default: looks up "format_loclist_type_default" first, and then uses + `' {{type}}:{{count}} '`, with an existing highlight group as prefix + ("NeomakeStatColorTypeX" or "NeomakeStatColorDefault"), e.g. + - format_loclist_type_default: default format for location list issues if + "format_loclist_type_X" is not defined. + - format_loclist_issues: format for wrapping all location list issues. + Default: `'%s%%#NeomakeStatReset'` (used with |printf()|). + +For quickfix list items:~ + - format_quickfix_ok: format for no quickfix issues. + Default: `''` + - format_quickfix_type_X: format for quickfix list issues of type X + (E, W, I, …). + Default: `' {{type}}:{{count}} '` + Default: looks up "format_quickfix_type_default" first, and then uses + `' Q{{type}}:{{count}} '`, with an existing highlight group as prefix + ("NeomakeStatColorQuickfixTypeX" or "NeomakeStatColorQuickfixDefault"). + - format_quickfix_issues: format for wrapping all quickfix list issues. + You can use an empty string to skip displaying quickfix issues, which can + be useful for non-current windows. + Default: `'%s%%#NeomakeStatReset'` (used with |printf()|). + +Status related:~ + - format_status: used to wrap the whole status. + This is a |printf()| format string, where `%s` gets replaced with the + whole status (and any literal/non-printf `%` needs to be escaped as `%%`). + Default: not used / `'%s'` + - format_status_disabled: used to wrap the whole status when disabled. + This is a |printf()| format string, where `%s` gets replaced with the + whole status (and any literal/non-printf `%` needs to be escaped as `%%`). + Default: `'{{disabled_info}} %s'` + - format_disabled_info: The `disabled_info` placeholder from the + "format_status_disabled" argument. There `disabled_scope` placeholder is + available here. Default: `'{{disabled_scope}}-'` + - format_status_enabled: used to wrap the whole status when enabled. + This is a |printf()| format string, where `%s` gets replaced with the + whole status (and any literal/non-printf `%` needs to be escaped as `%%`). + Default: not used / `'%s'` + +General:~ + - format_lists: used to format the overall location list and quickfix list + sections (before format_status). + `{{lists_sep}}` is empty ("") with only a single list section, + and defaults to " " if both are not empty. + Default: `'{{loclist}}{{lists_sep}}{{quickfix}}'` + +Running jobs:~ + If any jobs are currently running in file or project mode, those get + displayed by default in the loclist or quickfix section. The following + options control its appearance: + + - format_running: used in case there are jobs running. Use 0 (as a number) + to disable this, but fall through to the last known status. + Default: `… ({{running_job_names}})` + - format_running_job_file: Wrap the running job name for file-level makers. + Default: not used / `'%s'` + - format_running_job_project: Wrap the running job name for project makers. + Default: `'%s!'`. + - running_jobs_separator: Separator for formatted running job names. + Default: `', '`. + +Advanced options:~ + + - use_highlights_with_defaults: include highlight attributes with default + options (e.g. "%#NeomakeStatusGood#" with "format_loclist_ok"). + Default: 1 + +You can use the following format placeholders: + - `{{running_job_names}}}`: comma-separated list of running jobs (typically + their maker names). + This gets built using `format_running_job_file`, + `format_running_job_project`, and `running_jobs_separator`. + - `{{disabled_scope}}`: When manually overriden, the scope of the disabling. + One of "b", "t", "g". + +*neomake#statusline#LoclistStatus* +*neomake#statusline#QflistStatus* +These functions return text for your 'statusline'. They each take an +optional first argument, which is the prefix text that will be shown if errors +or warnings exist. Example usage: > + set statusline+=\ %#ErrorMsg#%{neomake#statusline#QflistStatus('qf:\ ')} +< +The result of this will be something like 'qf: E:1, W:2' if there are errors +or warnings and the empty string otherwise. + +*neomake#statusline#LoclistCounts* +*neomake#statusline#QflistCounts* +These functions get the counts of errors by error type for the |location-list| +and the |quickfix| respectively. The return value is something like this: > + {'E': 2, 'W': 1, 'x': 5} + + function! MyOnNeomakeJobFinished() abort + let context = g:neomake_hook_context + if context.jobinfo.exit_code != 0 + echom printf('The job for maker %s exited non-zero: %s', + \ context.jobinfo.maker.name, context.jobinfo.exit_code) + endif + endfunction + augroup my_neomake_hooks + au! + autocmd User NeomakeJobFinished call MyOnNeomakeJobFinished() + augroup END +< +Note: you might want to use |autocmd-nested| (in particular when handling +opening of the location/quickfix window yourself, so that other autocommands +get triggered, e.g. |WinEnter| for the qf window that gets opened/created): > + augroup my_neomake_hooks + au! + autocmd User NeomakeFinished nested call MyOnNeomakeFinished() + augroup END +< + *NeomakeJobInit* +The NeomakeJobInit autocommand gets triggered before a job gets started. +You can use this to change the command (`jobinfo.argv`). +Context: + - `g:neomake_hook_context.jobinfo`: see |neomake-object-jobinfo|. + The `argv` entry contains the command to run (executable and arguments). + This can be a list or a string, depending on the maker and the job backend. + + *NeomakeJobStarted* +The NeomakeJobStarted autocommand gets triggered after a job started. +Context: + - `g:neomake_hook_context.jobinfo`: see |neomake-object-jobinfo|. + + *NeomakeCountsChanged* +The NeomakeCountsChanged user autocommand gets triggered after counts for the +location/quickfix list have changed, either because the list got reset or new +entries got added. +You can use this to e.g. update the statusline. +Context: + - `g:neomake_hook_context.reset`: 1 if the list got reset, 0 otherwise. + - `g:neomake_hook_context.jobinfo`: when the list is not reset; see + |neomake-object-jobinfo|. + + *NeomakeFinished* +The NeomakeFinished user autocommand gets triggered after all jobs of a build +have finished. +You can use this to e.g. close an empty location or quickfix window. +Context: + - `g:neomake_hook_context`: a dictionary with the following keys: + - `make_info`: make info, which contains all of the entries from below, + plus some more. (The object itself is not documented yet) + - `make_id`: the numeric ID of the make run. + - `options`: a dictionary (related to |neomake-object-jobinfo|): + - `file_mode` + - `bufnr` + - `ft` + - `finished_jobs`: a list of job infos (|neomake-object-jobinfo|) for the + finished jobs. + + *NeomakeJobFinished* +The NeomakeJobFinished autocommand gets triggered after a single job has +finished. +Context: + - `g:neomake_hook_context.jobinfo`: see |neomake-object-jobinfo|; `exit_code` + is available there. + +============================================================================== +5. Objects *neomake-objects* + + *neomake-object-jobinfo* +The `jobinfo` dictionary contains information about a job. +(this is experimental, so not everything is documented) + - `maker`: a dictionary containing information about the maker that ran + this job. See |neomake-object-maker|. + - `file_mode`: 1 for file mode, 0 for project/directory mode. + - `make_id`: the ID of the make run + - `get_pid()`: get the process ID (PID) of the job (-1 if not running + anymore). + + - Relevant for file mode: + - `bufnr`: the number of the buffer. + - `ft`: the filetype. + *neomake-object-maker* +The `maker` dictionary contains the following keys: +(this is experimental, so not everything is documented) + - `name`: name of the maker. + - `exe`: executable of the maker. + +============================================================================== +6. Frequently Asked Questions (FAQ) *neomake-faq* + +6.1 Other plugins overwrite the signs placed by Neomake~ + +When using quickfixsigns (https://github.com/tomtom/quickfixsigns_vim/) it +will also place signs for errors and warnings in the quickfix/location list, +and conflicts therefore with Neomake's own signs (see +|g:neomake_place_signs|). You can make quickfixsigns respect Neomake's signs +using this option: > + + let g:quickfixsigns_protect_sign_rx = '^neomake_' +< +6.2 How to configure the makers to be used?~ + +See |g:neomake__enabled_makers| (press `` on the link to go there). + + *neomake-faq-errorformat* +6.3 How to develop/debug the errorformat setting?~ + +Here are some tips to develop the 'errorformat' setting for makers: + +1. Get the output from the linter into a buffer (see also |:read!|). +2. Set the errorformat, e.g. `:let &efm = '%E%f:%l:%c\,%n: %m,%Z%m`. + See |errorformat| for documentation of the format itself. +3. Load the buffer into the quickfix list: `:cgetbuffer`. +4. Use |:copen| to open the quickfix window, and/or `:echo getqflist()` to + display the raw data. +5. Pay attention to the "`valid`" property of entries. + +vim: ft=help tw=78 isk+=<,>,\:,-,' diff --git a/bundle/neomake/plugin/neomake.vim b/bundle/neomake/plugin/neomake.vim new file mode 100644 index 000000000..781871a29 --- /dev/null +++ b/bundle/neomake/plugin/neomake.vim @@ -0,0 +1,50 @@ +if exists('g:loaded_neomake') || &compatible + finish +endif +let g:loaded_neomake = 1 + +command! -nargs=* -bang -bar -complete=customlist,neomake#cmd#complete_makers + \ Neomake call neomake#Make(1, []) + +" These commands are available for clarity +command! -nargs=* -bar -complete=customlist,neomake#cmd#complete_makers + \ NeomakeProject Neomake! +command! -nargs=* -bar -complete=customlist,neomake#cmd#complete_makers + \ NeomakeFile Neomake + +command! -nargs=+ -bang -complete=shellcmd + \ NeomakeSh call neomake#ShCommand(0, ) +command! NeomakeListJobs call neomake#ListJobs() +command! -bang -nargs=1 -complete=custom,neomake#cmd#complete_jobs + \ NeomakeCancelJob call neomake#CancelJob(, 0) +command! -bang NeomakeCancelJobs call neomake#CancelJobs(0) + +command! -bang -bar -nargs=? -complete=customlist,neomake#cmd#complete_makers + \ NeomakeInfo call neomake#debug#display_info(0, ) + +command! -bang -bar NeomakeClean call neomake#cmd#clean(1) + +" Enable/disable/toggle commands. +command! -bar NeomakeToggle call neomake#cmd#toggle(g:) +command! -bar NeomakeToggleBuffer call neomake#cmd#toggle(b:) +command! -bar NeomakeToggleTab call neomake#cmd#toggle(t:) +command! -bar NeomakeDisable call neomake#cmd#disable(g:) +command! -bar NeomakeDisableBuffer call neomake#cmd#disable(b:) +command! -bar NeomakeDisableTab call neomake#cmd#disable(t:) +command! -bar NeomakeEnable call neomake#cmd#enable(g:) +command! -bar NeomakeEnableBuffer call neomake#cmd#enable(b:) +command! -bar NeomakeEnableTab call neomake#cmd#enable(t:) + +command! NeomakeStatus call neomake#cmd#display_status() + +" NOTE: experimental, no default mappings. +" NOTE: uses -addr=lines (default), and therefore negative counts do not work +" (see https://github.com/vim/vim/issues/3654). +command! -bar -count=1 NeomakeNextLoclist call neomake#list#next(, 1) +command! -bar -count=1 NeomakePrevLoclist call neomake#list#prev(, 1) +command! -bar -count=1 NeomakeNextQuickfix call neomake#list#next(, 0) +command! -bar -count=1 NeomakePrevQuickfix call neomake#list#prev(, 0) + +call neomake#setup#setup_autocmds() + +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/syntax/neomake/python.vim b/bundle/neomake/syntax/neomake/python.vim new file mode 100644 index 000000000..c5f040eaa --- /dev/null +++ b/bundle/neomake/syntax/neomake/python.vim @@ -0,0 +1,8 @@ +syntax match neomakePythonLint "[EWFC]\d\+" containedin=ALL + +syntax keyword neomakePyLamaNames pycodestyle pydocstyle pyflakes mccabe pylint radon gjslint +syntax match neomakePyLamaLinter "\[\k\+]" contains=neomakePyLamaNames + +highlight default link neomakePythonLint ErrorMsg +highlight default link neomakePyLamaNames Special +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/syntax/neomake/qf.vim b/bundle/neomake/syntax/neomake/qf.vim new file mode 100644 index 000000000..f065eeb63 --- /dev/null +++ b/bundle/neomake/syntax/neomake/qf.vim @@ -0,0 +1,9 @@ +syntax clear + +let b:current_syntax = 'neomake_qf' + +highlight default link neomakeListNr LineNr +highlight default link neomakeCursorListNr CursorLineNr +highlight default link neomakeMakerName FoldColumn +highlight default link neomakeBufferName qfFileName +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/syntax/qf.vim b/bundle/neomake/syntax/qf.vim new file mode 100644 index 000000000..fe926b553 --- /dev/null +++ b/bundle/neomake/syntax/qf.vim @@ -0,0 +1,11 @@ +" Uses syntax runtime file to clear default syntax, before later Syntax +" autocommands. + +if !exists('*neomake#quickfix#FormatQuickfix') + " customqf is not used. + finish +endif + +if neomake#quickfix#is_enabled() + call neomake#quickfix#FormatQuickfix() +endif diff --git a/bundle/neomake/tests/action_queue.vader b/bundle/neomake/tests/action_queue.vader new file mode 100644 index 000000000..d394f035d --- /dev/null +++ b/bundle/neomake/tests/action_queue.vader @@ -0,0 +1,239 @@ +Include: include/setup.vader + +Execute (action queue: order on WinEnter): + function! F1(...) + return neomake#action_queue#add(['Timer', 'WinEnter'], [function('F1'), + \ a:000]) + endfunction + function! F2(...) + return neomake#action_queue#add(['WinEnter'], [function('F2'), + \ a:000]) + endfunction + let jobinfo = NeomakeTestsFakeJobinfo() + + call neomake#action_queue#add(['Timer', 'WinEnter'], [function('F1'), [jobinfo]]) + call neomake#action_queue#add(['WinEnter'], [function('F2'), [jobinfo]]) + + doautocmd WinEnter + + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling F1.', 3 + + call neomake#action_queue#clean(jobinfo) + delfunction F1 + delfunction F2 + +Execute (action queue: order on WinEnter with Timer): + let s:calls = [0, 0] + function! F1(...) + let s:calls[0] += 1 + " NOTE: copies a:000 to work around https://github.com/neovim/neovim/issues/9169. + return neomake#action_queue#add(['Timer', 'WinEnter'], [function('F1'), + \ copy(a:000)]) + endfunction + function! F2(...) + let s:calls[1] += 1 + " NOTE: copies a:000 to work around https://github.com/neovim/neovim/issues/9169. + return neomake#action_queue#add(['WinEnter'], [function('F2'), + \ copy(a:000)]) + endfunction + let jobinfo = NeomakeTestsFakeJobinfo() + + call neomake#action_queue#add(['Timer', 'WinEnter'], [function('F1'), [jobinfo]]) + call neomake#action_queue#add(['WinEnter'], [function('F2'), [jobinfo]]) + + if has('timers') + AssertNeomakeMessage '\V\^Retrying Timer event in 10ms' + NeomakeTestsWaitForMessage 'action queue: processing for Timer (1 items).', 3, {'winnr': 1} + else + doautocmd CursorHold + AssertNeomakeMessage 'action queue: processing for Timer (1 items).', 3, {'winnr': 1} + endif + AssertNeomakeMessage 'Queuing action F1 for Timer, WinEnter.' + AssertNeomakeMessage 'action queue: re-queuing F2 for not processed make_id.', 3 + + doautocmd WinEnter + + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling F1.', 3 + AssertNeomakeMessage 'action queue: re-queuing F2 for not processed make_id.', 3 + + call neomake#action_queue#clean(jobinfo) + + delfunction F1 + delfunction F2 + AssertEqual s:calls, [2, 0] + +Execute (action queue: re-queued with different events): + let s:calls = [0, 0] + function! F1(...) + let s:calls[0] += 1 + if s:calls[0] == 2 + return g:neomake#action_queue#processed + endif + " NOTE: copies a:000 to work around https://github.com/neovim/neovim/issues/9169. + return neomake#action_queue#add(['BufEnter', 'WinEnter'], [function('F1'), + \ copy(a:000)]) + endfunction + function! F2(...) + let s:calls[1] += 1 + if s:calls[1] == 2 + return g:neomake#action_queue#processed + endif + " NOTE: copies a:000 to work around https://github.com/neovim/neovim/issues/9169. + return neomake#action_queue#add(['WinEnter'], [function('F2'), + \ copy(a:000)]) + endfunction + + let jobinfo = NeomakeTestsFakeJobinfo() + call neomake#action_queue#add(['Timer', 'WinEnter'], [function('F1'), [jobinfo]]) + call neomake#action_queue#add(['WinEnter'], [function('F2'), [jobinfo]]) + + if has('timers') + AssertNeomakeMessage '\V\^Retrying Timer event in 10ms' + else + doautocmd CursorHold + endif + NeomakeTestsWaitForMessage 'action queue: processing for Timer (1 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'Queuing action F1 for BufEnter, WinEnter.' + AssertNeomakeMessage 'action queue: re-queuing F2 for not processed make_id.', 3 + + AssertEqual s:calls, [1, 0] + doautocmd WinEnter + AssertEqual s:calls, [2, 1] + + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling F1.', 3 + AssertNeomakeMessage 'action queue: calling F2.', 3 + AssertNeomakeMessage 'Queuing action F2 for WinEnter.', 3 + + AssertEqual s:calls, [2, 1] + AssertEqual len(g:neomake#action_queue#_s.action_queue), 1 + + doautocmd WinEnter + AssertEqual len(g:neomake#action_queue#_s.action_queue), 0 + + delfunction F1 + delfunction F2 + AssertEqual s:calls, [2, 2] + +Execute (action queue: logs errors (get_list_entries, WinEnter)): + function! F1(jobinfo,...) + if a:0 + return g:neomake#action_queue#processed + endif + throw 'error_in_F1' + endfunction + let jobinfo = NeomakeTestsFakeJobinfo() + + call neomake#action_queue#add(['Timer', 'WinEnter'], [function('F1'), [jobinfo]]) + + doautocmd WinEnter + + AssertNeomakeMessage 'action queue: processing for WinEnter (1 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling F1.', 3 + AssertNeomakeMessage 'Error during action queue processing: error_in_F1.', 0 + AssertNeomakeMessage '\v^CancelJob: job not found: \d+.', 0 + + call neomake#action_queue#clean(jobinfo) + delfunction F1 + +Execute (action queue: logs errors (get_list_entries, Timer)): + function! F1(jobinfo,...) + if a:0 + return g:neomake#action_queue#processed + endif + throw 'error_in_F1' + endfunction + let jobinfo = NeomakeTestsFakeJobinfo() + + call neomake#action_queue#add(['Timer', 'WinEnter'], [function('F1'), [jobinfo]]) + + if has('timers') + NeomakeTestsWaitForMessage 'action queue: processing for Timer (1 items).', 3, {'winnr': 1} + else + doautocmd CursorHold + endif + AssertNeomakeMessage 'action queue: calling F1.', 3 + AssertNeomakeMessage 'Error during action queue processing: error_in_F1.', 0 + AssertNeomakeMessage '\v^CancelJob: job not found: \d+.', 0 + + call neomake#action_queue#clean(jobinfo) + delfunction F1 + +Execute (action queue: logs errors (E48, WinEnter)): + function! F1(jobinfo,...) + if a:0 + return g:neomake#action_queue#processed + endif + sandbox bprevious + endfunction + let jobinfo = NeomakeTestsFakeJobinfo() + + call neomake#action_queue#add(['Timer', 'WinEnter'], [function('F1'), [jobinfo]]) + + doautocmd WinEnter + + AssertNeomakeMessage 'action queue: processing for WinEnter (1 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling F1.', 3 + AssertNeomakeMessage '\vError during action queue processing: .*E48' + AssertNeomakeMessage '\v^CancelJob: job not found: \d+.', 0 + + call neomake#action_queue#clean(jobinfo) + delfunction F1 + +Execute (action queue: handles make_info in clean_make_info queue check): + if !neomake#has_async_support() || !has('patch-v8.1.0342') + NeomakeTestsSkip 'no async support.' + else + new + call neomake#Make({'enabled_makers': [g:true_maker]}) + let make_info = values(neomake#GetStatus().make_info)[0] + function F(...) + return g:neomake#action_queue#processed + endfunction + call neomake#action_queue#add(['InsertLeave'], [function('F'), [make_info]]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage '\VQueuing clean_make_info for already queued actions: [''make \d\+'']', 3 + AssertNeomakeMessage 'Queuing action clean_make_info for any event.', 3 + AssertNeomakeMessage 'Skipping cleaning of make info for queued actions.', 3 + + doautocmd InsertLeave + + AssertNeomakeMessage 'action queue: calling F.' + AssertNeomakeMessage 'action queue: calling clean_make_info.' + bwipe + delfunction F + endif + +Execute (action queue: skips processing during internal autocommands): + if NeomakeAsyncTestsSetup() + Save g:neomake_open_list + let g:neomake_open_list = 2 + + new + + let s:calls = [] + function! F(...) + call add(s:calls, a:000) + return g:neomake#action_queue#processed + endfunction + let jobinfo = NeomakeTestsFakeJobinfo() + call neomake#action_queue#add(['WinEnter'], [function('F'), [jobinfo]]) + + call neomake#Make(1, [g:error_maker]) + let job = neomake#GetJobs()[-1] + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage 'Handling location list: executing lwindow.', 3, job + AssertNeomakeMessage 'action queue: skip processing for WinEnter (ignore_autocommands=1).', 3 + AssertNeomakeMessage 'list window has been opened (old count: 2, new count: 3, height: 1).', 3 + AssertNeomakeMessage 'action queue: skip processing for WinEnter (ignore_autocommands=1).', 3 + AssertNeomakeMessage 'action queue: skip processing for WinEnter (ignore_autocommands=1).', 3 + lclose + wincmd p + AssertNeomakeMessage '\vaction queue: processing for WinEnter' + wincmd p + bwipe + delfunction F + endif diff --git a/bundle/neomake/tests/all.vader b/bundle/neomake/tests/all.vader new file mode 100644 index 000000000..ba4cf6916 --- /dev/null +++ b/bundle/neomake/tests/all.vader @@ -0,0 +1,8 @@ +" Main file to run all Vader tests. +" +" This is split into main and isolated tests, because isolated tests need to be +" run seperately (since they are allowed to monkeypatch and re-source functions +" etc). + +Include (Main tests): main.vader +Include (Isolated tests): isolated.vader diff --git a/bundle/neomake/tests/args.vader b/bundle/neomake/tests/args.vader new file mode 100644 index 000000000..9a275ca90 --- /dev/null +++ b/bundle/neomake/tests/args.vader @@ -0,0 +1,108 @@ +Include: include/setup.vader + +Execute (maker.args as list gets escaped): + let maker = { + \ 'exe': '/usr/bin/printf', + \ 'args': ['%s\n', '1', '2', '3a 3b'], + \ 'errorformat': '%f: %m', + \ 'mapexpr': 'expand("%:p") . ": " . v:val', + \ } + + let fname = 'tests/fixtures/a filename with spaces' + new + edit tests/fixtures/a\ filename\ with\ spaces + let fname = bufname('%') + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['1', '2', '3a 3b', fname] + bwipe + +Execute (maker.args as string gets not escaped): + let maker = { + \ 'exe': '/usr/bin/printf', + \ 'args': "'%s\\n' 1 2 '3a 3b' 4", + \ 'errorformat': '%f: %m', + \ 'mapexpr': 'expand("%:p") . ": " . v:val', + \ } + + let fname = 'tests/fixtures/a filename with spaces' + new + edit tests/fixtures/a\ filename\ with\ spaces + let fname = expand('%') + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['1', '2', '3a 3b', '4', fname] + bwipe + +Execute (fname in args gets not expanded (command maker, args as list)): + let maker = { + \ 'exe': 'printf', + \ 'args': ['%s'], + \ 'errorformat': '%m', + \ } + new + lcd tests/fixtures + edit ~ + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), 'v:val.text'), ['~'] + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: printf '%s' '~'." + else + AssertNeomakeMessage "Starting [string]: printf '%s' '~'." + endif + bwipe + +Execute (fname in args gets not expanded (command maker, args as string)): + let maker = { + \ 'exe': 'printf', + \ 'args': '%s', + \ 'errorformat': '%m', + \ } + new + lcd tests/fixtures + edit ~ + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), 'v:val.text'), ['~'] + if neomake#has_async_support() + if has('nvim') + AssertNeomakeMessage "Starting async job [string]: printf %s '~'." + endif + else + AssertNeomakeMessage "Starting [string]: printf %s '~'." + endif + bwipe + +Execute (fname in args gets not expanded (maker from command string)): + let maker = neomake#utils#MakerFromCommand('printf %s') + let maker.errorformat = '%m' + new + lcd tests/fixtures + edit ~ + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), 'v:val.text'), ['~'] + let shell_argv = join(split(&shell) + split(&shellcmdflag)) + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: ".shell_argv." 'printf %s '\\''~'\\'''." + else + AssertNeomakeMessage "Starting [string]: ".shell_argv." 'printf %s '\\''~'\\'''." + endif + bwipe + +Execute (fname in args gets not expanded (maker from command list)): + let maker = neomake#utils#MakerFromCommand(['printf', '%s']) + let maker.errorformat = '%m' + new + lcd tests/fixtures + edit ~ + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), 'v:val.text'), ['~'] + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: printf '%s' '~'." + else + AssertNeomakeMessage "Starting [string]: printf '%s' '~'." + endif + bwipe diff --git a/bundle/neomake/tests/automake.vader b/bundle/neomake/tests/automake.vader new file mode 100644 index 000000000..eb234a463 --- /dev/null +++ b/bundle/neomake/tests/automake.vader @@ -0,0 +1,1631 @@ +Include: include/setup.vader + +Execute (Setup): + function! NeomakeTestsAssertAutomakeAutocommands(events) abort + let expected = [] + for e in a:events + call add(expected, 'neomake_automake '.e.': * call s:neomake_automake('''.e.''', expand(''''))') + endfor + + if exists('#neomake_automake') + redir => redir_output + silent au neomake_automake + redir END + let output = split(redir_output, "\n")[1:-1] + let sort_output = [] + for i in range(1, len(output), 2) + let sort_output += [output[i-1].': '.output[i]] + endfor + else + let sort_output = [] + endif + AssertEqual join(sort(expected), "\n"), join(sort(sort_output), "\n") + endfunction + call add(g:neomake_test_funcs_before, 'NeomakeTestsAssertAutomakeAutocommands') + + function! NeomakeTestsHandleSecondTextChanged() + if has('patch-8.0.1494') && !has('patch-8.0.1633') && !has('nvim-0.3.2') + AssertNeomakeMessage 'automake: ignoring first TextChanged.', 3 + doautocmd TextChanged + endif + endfunction + call add(g:neomake_test_funcs_before, 'NeomakeTestsHandleSecondTextChanged') + +Execute (augroup neomake_automake does not exist by default): + Assert !exists('#neomake_automake') + call neomake#configure#automake() + Assert !exists('#neomake_automake') + +Execute (short setup: 'n'): + call neomake#configure#automake('n') + if exists('##TextChanged') && has('timers') + let event = 'TextChanged' + else + let event = 'CursorHold' + AssertNeomakeMessage 'automake: using CursorHold instead of TextChanged.', 3 + endif + call NeomakeTestsAssertAutomakeAutocommands(['InsertLeave', event]) + Assert exists('#neomake_automake') + +Execute (short setup: 'i'): + call neomake#configure#automake('i') + if exists('##TextChangedI') && has('timers') + let event = 'TextChangedI' + else + let event = 'CursorHoldI' + AssertNeomakeMessage 'automake: using CursorHoldI instead of TextChangedI.', 3 + endif + call NeomakeTestsAssertAutomakeAutocommands([event]) + Assert exists('#neomake_automake'), 1 + +Execute (short setup: 'w'): + call neomake#configure#automake('w') + call NeomakeTestsAssertAutomakeAutocommands(['BufWritePost']) + if has('timers') + AssertEqual g:neomake, {'automake': {'events': {'BufWritePost': {'delay': 0}}}} + else + AssertEqual g:neomake, {'automake': {'events': {'BufWritePost': {}}}} + endif + +Execute (short setup: 'w' with delay): + call neomake#configure#automake('w', 100) + call NeomakeTestsAssertAutomakeAutocommands(['BufWritePost']) + if has('timers') + AssertEqual g:neomake, {'automake': {'events': + \ {'BufWritePost': {'delay': 0}}}, 'automake_delay': 100} + else + AssertEqual g:neomake, {'automake': {'events': + \ {'BufWritePost': {}}}, 'automake_delay': 0} + endif + +Execute (short setup: 'r'): + call neomake#configure#automake('r') + call NeomakeTestsAssertAutomakeAutocommands(['BufWinEnter', 'FileChangedShellPost', 'FileType']) + +Execute (short setup: reports unknown modes): + call neomake#configure#automake('z') + AssertNeomakeMessage 'unknown modes in string automake config (z): z.', 0 + call neomake#configure#automake('Xwz') + AssertNeomakeMessage 'unknown modes in string automake config (Xwz): X, z.', 0 + +Execute (setup: short vs. long): + call neomake#configure#automake('w', 500) + let short_config = copy(g:neomake) + unlet g:neomake + call neomake#configure#automake({ + \ 'BufWritePost': has('timers') ? {'delay': 0} : {}, + \ }, 500) + AssertEqual short_config, g:neomake + + " TODO: sync with doc" + unlet g:neomake + call neomake#configure#automake('nrw', 500) + let short_config = copy(g:neomake) + + unlet g:neomake + if exists('#TextChanged') + call neomake#configure#automake({ + \ 'TextChanged': {}, + \ 'InsertLeave': {}, + \ 'FileType': {}, + \ 'FileChangedShellPost': {}, + \ 'BufWritePost': {'delay': 0}, + \ 'BufWinEnter': {}, + \ }, 500) + else + call neomake#configure#automake({ + \ 'CursorHold': {}, + \ 'FileType': {}, + \ 'FileChangedShellPost': {}, + \ 'InsertLeave': {}, + \ 'BufWritePost': {}, + \ 'BufWinEnter': {}, + \ }, 0) + endif + AssertEqual short_config, g:neomake + +Execute (Automake supports custom buffer config): + new + set filetype=neomake_tests + Save g:neomake_test_enabledmakers + let g:neomake_test_enabledmakers = [g:entry_maker] + call g:NeomakeSetupAutocmdWrappers() + + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 0}}) + call neomake#configure#automake({'BufWinEnter': {'delay': 0}}) + + AssertEqual b:neomake.automake.events, {'CursorHold': {'delay': 0}} + AssertNeomakeMessage 'automake: registered events: BufWinEnter, CursorHold.' + + doautocmd BufWinEnter + AssertNeomakeMessage 'automake: automake for event BufWinEnter.' + AssertNeomakeMessage 'automake: event is not registered.' + AssertEqual g:neomake_test_finished, [] + doautocmd CursorHold + AssertEqual len(g:neomake_test_finished), 1 + + " Remove custom buffer config. + unlet b:neomake.automake.events + doautocmd BufWinEnter + AssertNeomakeMessage 'automake: automake for event BufWinEnter.' + AssertEqual len(g:neomake_test_finished), 1 + + " Not picked up from buffer var (for performance reasons). + AssertNeomakeMessage 'automake: event is not registered.' + + call neomake#configure#reset_automake_for_buffer() + doautocmd BufWinEnter + AssertNeomakeMessage 'automake: automake for event BufWinEnter.' + AssertEqual len(g:neomake_test_finished), 2 + + " Resetting global config resets. + call neomake#configure#automake({'BufWinEnter': {'delay': 0}}) + doautocmd BufWinEnter + AssertNeomakeMessage 'automake: automake for event BufWinEnter.' + AssertEqual len(g:neomake_test_finished), 3 + + " Changing buffer config resets tick. + call neomake#configure#automake_for_buffer({'BufWinEnter': {'delay': 0}}, 0, [g:entry_maker]) + AssertNeomakeMessage 'automake: resetting tick because of config changes.', 3 + doautocmd BufWinEnter + AssertNeomakeMessage 'entry_maker: getting entries via get_list_entries.' + + " Changing buffer options resets tick. + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 0}}, 0, [g:entry_maker]) + doautocmd CursorHold + AssertNeomakeMessage 'entry_maker: getting entries via get_list_entries.' + bwipe + +Execute (Automake config via dict): + call neomake#configure#automake({ + \ 'BufWinEnter': {'delay': 200}, + \ 'TextChanged': {'delay': 200}}) + + let expected = {'automake': {'events': {}}} + if has('timers') + let expected.automake.events.BufWinEnter = {'delay': 200} + else + AssertNeomakeMessage 'automake: timer support is required for automaking, removing event BufWinEnter.' + endif + if exists('##TextChanged') + if !has('timers') + AssertNeomakeMessage 'automake: timer support is required for automaking, removing event TextChanged.' + else + let expected.automake.events.TextChanged = {'delay': 200} + endif + else + AssertNeomakeMessage 'automake: event TextChanged does not exist.', 0 + endif + AssertEqual g:neomake, expected + +Execute (Error with unsupported events): + call neomake#configure#automake({ + \ 'EventDoesNotExist': {'delay': 10}}) + AssertNeomakeMessage 'automake: event EventDoesNotExist does not exist.', 0 + +Execute (Automake): + call g:NeomakeSetupAutocmdWrappers() + + call neomake#configure#automake('n', 10) + if exists('##TextChanged') && has('timers') + let event = 'TextChanged' + else + let event = 'CursorHold' + endif + + AssertEqual &buftype, 'nofile' + new + let bufnr = bufnr('%') + let b:neomake_tempfile_enabled = 1 + let len_before = len(g:neomake_test_messages) + setfiletype neomake_tests + AssertEqual len_before, len(g:neomake_test_messages), 'Nothing happened on FileType, since buffer is not configured.' + if exists('#TextChanged') + AssertNeomakeMessage 'automake: registered events: InsertLeave, TextChanged.' + else + AssertNeomakeMessage 'automake: registered events: CursorHold, InsertLeave.' + endif + normal! iline1 + + AssertNeomakeMessage 'Maker not found (for filetype neomake_tests): nonexisting.', 3 + AssertNeomakeMessage 'Exe (maker_without_exe) of auto-configured maker maker_without_exe is not executable, skipping.' + AssertNeomakeMessage 'automake: configured buffer for ft=neomake_tests (no enabled makers).', 3 + AssertNeomakeMessage 'automake: setting tick for new buffer.', 3 + AssertNeomakeMessage 'automake: no enabled makers.', 3 + + " TODO: better to have automake.ft.neomake_tests.enabled_makers ?! + call neomake#config#set('ft.neomake_tests.automake.enabled_makers', ['true']) + doautocmd FileType + AssertNeomakeMessage 'automake: configured buffer for ft=neomake_tests (true (global)).', 3 + AssertNeomakeMessage 'automake: resetting tick because of registration changes.', 3 + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), 0 + + doautocmd InsertLeave + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'automake: tick changed (new).', 3, {'bufnr': bufnr} + if has('timers') + NeomakeTestsWaitForNextFinishedJob + endif + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), 1 + + " 'jobs' in logged context. + AssertNeomakeMessage '\VCalling User autocmd NeomakeFinished with context: \.\*''jobs'': [''true'']\.\*}.', 3 + + " Tick was not reset on FileType-reconfig (no changes). + doautocmd FileType + AssertNeomakeMessage 'automake: configured buffer for ft=neomake_tests (true (global)).', 3 + doautocmd InsertLeave + if has('timers') + NeomakeTestsWaitForMessage 'automake: buffer was not changed.', 3 + endif + AssertEqual len(g:neomake_test_jobfinished), 1 + + normal! ifoo + NeomakeTestsWaitForNextFinishedJob + AssertEqual len(g:neomake_test_jobfinished), 2 + + " Should not run without changes to the buffer. + exe 'doautocmd' event + if event ==# 'TextChanged' + call NeomakeTestsHandleSecondTextChanged() + endif + NeomakeTestsWaitForMessage 'automake: handling event '.event.'.', 3 + AssertNeomakeMessage 'automake: buffer was not changed.' + AssertEqual len(g:neomake_test_jobfinished), 2 + + " Should run with changes to the buffer. + norm oline2 + exe 'doautocmd' event + NeomakeTestsWaitForNextFinishedJob + AssertEqual len(g:neomake_test_jobfinished), 3 + + norm oline4 + if has('timers') + AssertEqual len(g:neomake_test_jobfinished), 3 + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+).', 3, {'bufnr': bufnr} + let timer = g:neomake_test_matchlist[1] + exe 'doautocmd' event + AssertEqual len(g:neomake_test_jobfinished), 3 + AssertNeomakeMessage 'automake: stopped existing timer: '.timer.'.', 3, {'bufnr': bufnr} + NeomakeTestsWaitForNextFinishedJob + AssertNeomakeMessage 'automake: increasing delay (1/0 canceled timers/makes, rate=1.20): 10 => 12/3000.' + AssertNeomakeMessage 'automake: started timer (12ms): '.(timer+1).'.', 3, {'bufnr': bufnr} + endif + + AssertEqual len(g:neomake_test_jobfinished), 4 + + new + exe 'doautocmd' event + AssertNeomakeMessage 'automake: configured buffer for ft= (no enabled makers).' + if event ==# 'TextChanged' + call NeomakeTestsHandleSecondTextChanged() + endif + AssertNeomakeMessage 'automake: no enabled makers.' + + let b:neomake_automake_enabled_makers = ['foo'] + doautocmd FileType + AssertNeomakeMessage 'automake: configured buffer for ft= (no enabled makers).' + let b:neomake = {'automake': {'enabled_makers': ['configured_maker']}} + let n = len(g:neomake_test_messages) + exe 'doautocmd' event + let m = len(g:neomake_test_messages) + AssertEqual g:neomake_test_messages[n : m], [ + \ [3, 'automake: handling event '.event.'.', {'bufnr': bufnr('%'), 'winnr': winnr()}], + \ [3, 'automake: no enabled makers.', {'bufnr': bufnr('%'), 'winnr': winnr()}], + \ ] + + call neomake#configure#automake('nw') + normal! ifoo + AssertNeomakeMessage "Using setting automake.enabled_makers=['configured_maker'] from 'buffer'.", 3 + AssertNeomakeMessage 'Maker not found (for empty filetype): configured_maker.', 0 + AssertNeomakeMessage 'automake: configured buffer for ft= (no enabled makers).' + AssertNeomakeMessage 'automake: no enabled makers.' + + let tmpfile = tempname() + exe 'file' tmpfile + w + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage 'automake: handling event BufWritePost.', 3 + AssertNeomakeMessage 'automake: no enabled makers.', 3 + bwipe! + bwipe! + +Execute (Automake: skips non-default buftypes): + call neomake#configure#automake('n', 10) + if !exists('##TextChanged') || !has('timers') + AssertNeomakeMessage 'automake: using CursorHold instead of TextChanged.', 3 + let event = 'CursorHold' + else + let event = 'TextChanged' + endif + Assert exists('#neomake_automake') + new + setfiletype neomake_tests + Save g:neomake_test_enabledmakers + let g:neomake_test_enabledmakers = ['true'] + set buftype=nofile + + call g:NeomakeSetupAutocmdWrappers() + + exe 'doautocmd '.event + AssertNeomakeMessage 'automake: ignoring buffer with buftype=nofile.', 3 + AssertNeomakeMessage 'automake: buffer is ignored.' + AssertEqual len(g:neomake_test_jobfinished), 0 + + set buftype= + if exists('##OptionSet') + " OptionSet autocmd needs to be triggered manually in tests. + doauto OptionSet buftype + else + call neomake#configure#reset_automake_for_buffer() + endif + + exe 'doautocmd '.event + AssertNeomakeMessage '\Vautomake: configured buffer for ft=neomake_tests', 3 + if event ==# 'TextChanged' + call NeomakeTestsHandleSecondTextChanged() + endif + AssertNeomakeMessage 'automake: automake for event '.event.'.' + bwipe! + +Execute (neomake#configure#automake_for_buffer does not set up autocommands for no makers): + new + set buftype=nofile + call neomake#configure#automake_for_buffer('n', 10) + AssertNeomakeMessage 'automake: configured buffer for ft= (no enabled makers).' + AssertNeomakeMessage 'automake: registered events: .', 3 + Assert !exists('#neomake_automake') + bwipe + +Execute (neomake#configure#automake_for_buffer sets up autocommands with makers): + new + setfiletype neomake_tests + let g:neomake_test_enabledmakers = ['true'] + call neomake#configure#automake_for_buffer('n', 10) + AssertNeomakeMessage 'automake: configured buffer for ft=neomake_tests (true (default)).' + if exists('#TextChanged') + AssertNeomakeMessage 'automake: registered events: InsertLeave, TextChanged.' + else + AssertNeomakeMessage 'automake: registered events: CursorHold, InsertLeave.' + endif + bwipe + +Execute (neomake#configure#automake_for_buffer logs error for unknown maker): + new + " This is fine for now, since it is still considered to be experimental API. + call neomake#configure#automake_for_buffer('n', 0, ['another_maker']) + AssertNeomakeMessage 'Maker not found (for empty filetype): another_maker.' + bwipe + +Execute (neomake#configure#automake_for_buffer sets up BufWritePost without delay): + new + set buftype=nofile + set filetype=neomake_tests + let g:neomake_test_enabledmakers = ['true'] + call neomake#configure#automake_for_buffer('w') + call NeomakeTestsAssertAutomakeAutocommands(['BufWritePost']) + if has('timers') + AssertEqual b:neomake, {'automake': {'events': {'BufWritePost': {'delay': 0}}}} + else + AssertEqual b:neomake, {'automake': {'events': {'BufWritePost': {}}}} + endif + bwipe + +Execute (neomake#configure#automake_for_buffer sets up BufWritePost with delay): + new + set buftype=nofile + set filetype=neomake_tests + let g:neomake_test_enabledmakers = ['true'] + call neomake#configure#automake_for_buffer('w', 5) + call NeomakeTestsAssertAutomakeAutocommands(['BufWritePost']) + if has('timers') + AssertEqual b:neomake, {'automake': {'events': { + \ 'BufWritePost': {'delay': 0}}}, 'automake_delay': 5} + else + AssertNeomakeMessage 'automake: timer support is required for delayed events.', 1 + AssertEqual b:neomake, {'automake': {'events': { + \ 'BufWritePost': {}}}, 'automake_delay': 0} + endif + + " buftype=nofile is not ignored with custom/explicit config. + let tempname = tempname() + exe 'w' tempname + bwipe + exe 'bwipe' tempname + NeomakeCancelJobs! + +Execute (neomake#configure#automake_for_buffer skips non-default buftypes): + tabnew + let bufnr = bufnr('%') + set buftype=nofile + call neomake#configure#automake('r', 0) + AssertNeomakeMessage 'automake: registered events: FileChangedShellPost, FileType, BufWinEnter.', 3 + bwipe + +Execute (neomake#configure#automake_for_buffer can configure makers (dict)): + new + let bufnr = bufnr('%') + set buftype=nofile + call neomake#configure#automake_for_buffer('r', 0, {'makers': ['foo_maker']}) + AssertNeomakeMessage 'Maker not found (for empty filetype): foo_maker.', 0 + AssertNeomakeMessage 'automake: configured buffer for ft= (no enabled makers).', 3 + AssertNeomakeMessage 'automake: registered events: .', 3 + + let maker = {'name': 'my-maker'} + call neomake#configure#automake_for_buffer('r', 0, {'makers': [maker]}) + AssertNeomakeMessage 'Exe (my-maker) of maker my-maker is not executable.', 0 + + let maker = {'name': 'true'} + call neomake#configure#automake_for_buffer('r', 0, {'makers': [maker]}) + AssertNeomakeMessage 'automake: configured buffer for ft= (true (options)).', 3 + AssertNeomakeMessage 'automake: registered events: FileChangedShellPost, FileType, BufWinEnter.', 3 + bwipe + +Execute (neomake#configure#automake_for_buffer can configure makers (list)): + new + let bufnr = bufnr('%') + set buftype=nofile + call neomake#configure#automake_for_buffer('r', 0, ['maker_1', 'maker_2']) + AssertNeomakeMessage 'Maker not found (for empty filetype): maker_1.', 0 + AssertNeomakeMessage 'Maker not found (for empty filetype): maker_2.', 0 + + let maker1 = {'name': 'maker_1', 'exe': 'true'} + let maker2 = {'name': 'maker_2'} + call neomake#configure#automake_for_buffer('r', 0, [maker1, maker2]) + AssertNeomakeMessage 'Exe (maker_2) of maker maker_2 is not executable.', 0 + AssertNeomakeMessage 'automake: configured buffer for ft= (maker_1 (options)).', 3 + AssertNeomakeMessage 'automake: registered events: FileChangedShellPost, FileType, BufWinEnter.', 3 + bwipe + +Execute (neomake#configure#automake_for_buffer can configure makers (buffer var)): + new + set filetype=myft + let b:neomake_myft_my_maker_maker = {'name': 'my_maker', 'exe': 'true'} + call neomake#configure#automake_for_buffer('n', 300, ['my_maker']) + AssertNeomakeMessage 'automake: configured buffer for ft=myft (my_maker (options)).', 3 + + let b:neomake_myft_my_other_maker_maker = {'name': 'my_other_maker', 'exe': 'true'} + call neomake#configure#automake_for_buffer('n', 300, {'makers': ['my_other_maker']}) + AssertNeomakeMessage 'automake: configured buffer for ft=myft (my_other_maker (options)).', 3 + bwipe + +Execute (neomake#configure#automake_for_buffer can configure other buffers): + let maker = {'name': 'my_maker', 'exe': 'true'} + new + let bufnr = bufnr('%') + call neomake#configure#automake_for_buffer('n', 300, {'makers': [maker], 'bufnr': bufnr}) + AssertNeomakeMessage 'automake: configured buffer for ft= (my_maker (options)).', 3, {'bufnr': bufnr} + + " Configuration for another buffer. + let my_other_maker = {'name': 'my_other_maker', 'exe': 'true'} + new + call neomake#configure#automake_for_buffer('n', 300, {'makers': [my_other_maker], 'bufnr': bufnr}) + Assert !exists('b:neomake') + bwipe + AssertNeomakeMessage 'automake: configured buffer for ft= (my_other_maker (options)).', 3, {'bufnr': bufnr} + bwipe + +Execute (neomake#configure#automake_for_buffer re-uses configured makers): + new + call neomake#configure#automake_for_buffer({'InsertLeave': {'delay': 0}}, 0, [g:entry_maker]) + AssertNeomakeMessage 'automake: configured buffer for ft= (entry_maker (options)).', 3 + AssertNeomakeMessage 'automake: resetting tick because of config changes.', 3 + doautocmd InsertLeave + AssertNeomakeMessage 'entry_maker: getting entries via get_list_entries.', 2 + + call neomake#configure#automake_for_buffer({'InsertLeave': {'delay': 0}}, 0, [g:true_maker]) + AssertNeomakeMessage 'automake: resetting tick because of registration changes.', 3 + doautocmd InsertLeave + AssertNeomakeMessage 'Running makers: true-maker.', 3 + NeomakeTestsWaitForFinishedJobs + + let len_before = len(g:neomake_test_messages) + doautocmd FileType + AssertEqual len_before, len(g:neomake_test_messages), 'Nothing happened.' + bwipe + +Execute (Automake handles unchanged buffer): + " XXX: run for all?! + if !has('timers') + NeomakeTestsSkip 'Only with timers feature' + else + call g:NeomakeSetupAutocmdWrappers() + call neomake#configure#automake({ + \ 'TextChanged': {'delay': 10}}) + new + let g:neomake_test_enabledmakers = [g:sleep_maker] + set filetype=neomake_tests + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + let make_id = neomake#GetStatus().last_make_id + NeomakeTestsWaitForMessage '\vautomake: callback for timer \d+' + doautocmd TextChanged + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'automake: buffer was not changed.' + + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + bwipe + endif + +Execute (BufWritePost does not run for unchanged buffer): + call g:NeomakeSetupAutocmdWrappers() + + call neomake#configure#automake('w') + + new + let b:neomake_test_enabledmakers = ['success_entry_maker'] + set filetype=neomake_tests + + CallNeomake 1, [] + AssertEqual len(g:neomake_test_jobfinished), 1 + Assert !exists('b:_neomake_automake_tick') + + exe 'w' tempname() + AssertEqual len(g:neomake_test_jobfinished), 2 + Assert exists('b:_neomake_automake_tick') + + " Every write used to trigger a run (due to b:changedtick being incremented, + " https://github.com/vim/vim/issues/2764). + w + if has('patch-8.1.1498') || has('nvim-0.4') + AssertEqual len(g:neomake_test_jobfinished), 2 + else + AssertEqual len(g:neomake_test_jobfinished), 3 + endif + + let expected = len(g:neomake_test_jobfinished) + 1 + normal! ifoo + w + AssertEqual len(g:neomake_test_jobfinished), expected + + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), expected + bwipe + +Execute (BufWritePost does not run for unchanged buffer (delayed)): + call g:NeomakeSetupAutocmdWrappers() + + call neomake#configure#automake({'BufWritePost': {'delay': 5}}) + if !has('timers') + AssertNeomakeMessage 'automake: timer support is required for automaking, removing event BufWritePost.', 0 + else + new + let b:neomake_test_enabledmakers = ['success_entry_maker'] + set filetype=neomake_tests + exe 'w' tempname() + AssertNeomakeMessage '\vautomake: started timer \(5ms\): (\d+)' + NeomakeTestsWaitForNextFinishedJob + AssertEqual len(g:neomake_test_jobfinished), 1 + + " Every write used to trigger a run (due to b:changedtick being incremented, + " https://github.com/vim/vim/issues/2764). + w + if has('patch-8.1.1498') || has('nvim-0.4') + let offset_for_unchanged_write = 0 + else + let offset_for_unchanged_write = 1 + NeomakeTestsWaitForNextFinishedJob + endif + AssertEqual len(g:neomake_test_jobfinished), 1 + offset_for_unchanged_write + + normal! ifoo + w + NeomakeTestsWaitForNextFinishedJob + AssertEqual len(g:neomake_test_jobfinished), 2 + offset_for_unchanged_write + + bwipe + endif + +Execute (Automake stops previous jobs): + if NeomakeAsyncTestsSetup() + call neomake#configure#automake({ + \ 'TextChanged': {'delay': 10}}) + new + let maker = NeomakeTestsCommandMaker('sleep-maker', 'sleep .1; echo slept') + let g:neomake_test_enabledmakers = [maker] + + set filetype=neomake_tests + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + NeomakeTestsWaitForMessage '\vautomake: callback for timer \d+' + let first_make_id = neomake#GetStatus().last_make_id + AssertEqual [first_make_id], b:_neomake_automake_make_ids + + normal! ifoo + doautocmd TextChanged + NeomakeTestsWaitForMessage '\vautomake: started jobs: \[\d+\].' + AssertNeomakeMessage '\vautomake: stopping previous make runs: '.first_make_id + AssertNeomakeMessage 'automake: increasing delay (0/1 canceled timers/makes, rate=1.50): 10 => 15/3000.', 3 + AssertNeomakeMessage '\Vautomake: started timer (15ms):' + NeomakeTestsWaitForMessage '\vautomake: callback for timer \d+' + let second_make_id = neomake#GetStatus().last_make_id + Assert index(b:_neomake_automake_make_ids, second_make_id) > -1, 'Second make is registered' + NeomakeTestsWaitForFinishedJobs + bwipe! + endif + +Execute (Automake for normal mode handles ciw): + call g:NeomakeSetupAutocmdWrappers() + call neomake#configure#automake('n', 10) + new + if has('timers') + AssertEqual g:neomake, {'automake': {'events': { + \ 'InsertLeave': {}, 'TextChanged': {}}}, 'automake_delay': 10} + else + AssertEqual g:neomake, {'automake': {'events': { + \ 'CursorHold': {}, 'InsertLeave': {}}}, 'automake_delay': 0} + endif + let g:neomake_test_enabledmakers = [g:sleep_maker] + set filetype=neomake_tests + + normal! ifoo + if has('timers') + NeomakeTestsWaitForNextMessage + else + doautocmd CursorHold + endif + AssertNeomakeMessage 'Running makers: sleep-maker (auto).' + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + bwipe! + +Execute (Automake restarts if context changed (CursorHold)): + if !has('timers') + NeomakeTestsSkip 'only with timers feature' + else + new + norm! iword1 word2 + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 10}}) + doautocmd CursorHold + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + norm! ^ + NeomakeTestsWaitForMessage '\Vautomake: context/position changed: [\d\+, [0, 1, 11, 0], ''n''] => [\d\+, [0, 1, 1, 0], ''n''], restarting.', 3 + AssertNeomakeMessage 'automake: increasing delay (1/0 canceled timers/makes, rate=1.20): 10 => 12/3000.' + AssertNeomakeMessage '\Vautomake: started timer (12ms): \(\d\+\).' + let timer = g:neomake_test_matchlist[1] + bwipe! + AssertNeomakeMessage 'automake: stopped timer for cleaned buffer: '.timer.'.' + endif + +Execute (Automake restarts on InsertLeave if context and mode changed (CursorHold)): + if !has('timers') + NeomakeTestsSkip 'only with timers feature' + else + new + norm! iword1 word2 + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 10}}) + + let s:exited = 0 + function! s:exit_insert(...) + let s:exited = 1 + call feedkeys("\") + endfunction + call timer_start(100, function('s:exit_insert')) + + doautocmd CursorHold + call feedkeys('o', 'nx!') + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + + NeomakeTestsWaitForMessage '\Vautomake: context/position changed: [\d\+, [0, 1, 11, 0], ''n''] => [\d\+, [0, 2, 1, 0], ''i''], restarting on InsertLeave.', 3 + AssertNeomakeMessage 'automake: re-starting postponed automake.' + " Does not use delay/timer. + AssertNeomakeMessageAbsent '\Vautomake: increasing delay \.\*' + AssertNeomakeMessageAbsent '\Vautomake: started timer' + bwipe! + endif + +Execute (Automake restarts if popup menu is visible): + if !has('timers') + NeomakeTestsSkip 'only with timers feature' + else + new + file file_sleep_efm + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call append(0, ['word1', 'word2']) + + function s:close_pum(...) + try + NeomakeTestsWaitForMessage '\Vautomake: callback for timer \d\+ (via CursorHold).' + finally + call feedkeys("\\") + endtry + endfunction + + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 5}}) + doautocmd CursorHold + AssertNeomakeMessage '\vautomake: started timer \(5ms\): (\d+)' + let base_timer = g:neomake_test_matchlist[1] + + " Trigger popup menu. + let timer = timer_start(0, function('s:close_pum')) + try + call feedkeys("oword\", 'x!') + + AssertNeomakeMessage 'automake: postponing automake during completion.', 3 + AssertNeomakeMessage 'automake: re-starting postponed automake.' + AssertNeomakeMessage 'automake: tick changed (new).' + " +2 since we use timer_start above. + AssertNeomakeMessage 'automake: started timer (5ms): '.(base_timer + 2).'.' + NeomakeTestsWaitForMessage 'automake: callback for timer '.(base_timer + 2).' (via CursorHold).' + AssertNeomakeMessage 'automake: neomake_do_automake: CursorHold.' + AssertNeomakeMessage 'automake: tick changed (new).' + AssertNeomakeMessage 'automake: enabled makers: true-maker.' + AssertNeomakeMessage '\vautomake: updating tick: \d+.' + NeomakeTestsWaitForFinishedJobs + bwipe! + finally + call timer_stop(timer) + endtry + endif + +Execute (Automake cleans up buffer context when restarting after popup menu fails): + if !has('timers') + NeomakeTestsSkip 'only with timers feature' + else + new + file file_sleep_efm + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call append(0, ['word1', 'word2']) + + function! s:close_pum(...) + try + NeomakeTestsWaitForMessage '\Vautomake: callback for timer \d\+ (via CursorHold).' + finally + call feedkeys("\\") + endtry + endfunction + + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 5}}) + doautocmd CursorHold + AssertNeomakeMessage '\vautomake: started timer \(5ms\): (\d+)' + + " Trigger popup menu. + call timer_start(0, function('s:close_pum')) + noautocmd call feedkeys("oword\", 'x!') + + AssertNeomakeMessage 'automake: postponing automake during completion.' + + Assert exists('#neomake_automake_retry#InsertLeave#') + Assert exists('#neomake_automake_retry#CompleteDone#') + Assert exists('b:_neomake_postponed_automake_context') + doautocmd InsertLeave + Assert !exists('#neomake_automake_retry#InsertLeave#') + Assert !exists('#neomake_automake_retry#CompleteDone#') + Assert !exists('b:_neomake_postponed_automake_context') + AssertNeomakeMessage 'automake: postponed automake: unexpected step 2, cleaning up.', 3 + bwipe! + endif + +Execute (Timer callback ignores wiped buffer): + if !has('timers') + NeomakeTestsSkip 'only with timers feature' + else + new + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 5}}) + doautocmd CursorHold + AssertNeomakeMessage '\vautomake: started timer \(5ms\): (\d+)' + let timer = g:neomake_test_matchlist[1] + bwipe + AssertNeomakeMessage 'automake: stopped timer for cleaned buffer: '.timer.'.' + endif + +Execute (Timer callback ignores wiped buffer with noautocmd): + if !has('timers') + NeomakeTestsSkip 'only with timers feature' + else + new + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 5}}) + doautocmd CursorHold + AssertNeomakeMessage '\vautomake: started timer \(5ms\): (\d+)' + let timer = g:neomake_test_matchlist[1] + noautocmd bwipe + NeomakeTestsWaitForMessage 'automake: buffer does not exist anymore for timer '.timer.'.' + endif + +Execute (Toggling disables automaking): + new + let bufnr = bufnr('%') + let log_context = {'bufnr': bufnr} + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + NeomakeToggleBuffer + AssertNeomakeMessage 'automake: disabling buffer '.bufnr.'.', 3, log_context + AssertNeomakeMessage 'Neomake is disabled (buffer).', 3 + AssertNeomakeMessage 'automake: registered events: .', 3, log_context + call neomake#configure#automake({'InsertLeave': {'delay': 0}}) + AssertNeomakeMessage 'automake: registered events: InsertLeave.', 3, log_context + doautocmd InsertLeave + NeomakeTestsWaitForMessage "Using setting disabled=1 from 'buffer'.", 3, log_context + AssertNeomakeMessage 'automake: disabled (buffer).', 3, log_context + bwipe + +Execute (Handles timeout in another buffer): + if NeomakeAsyncTestsSetup() + new + let bufnr1 = bufnr('%') + set filetype=neomake_tests + let g:neomake_test_enabledmakers = [g:sleep_maker] + call neomake#configure#automake({ + \ 'TextChanged': {'delay': 10}}) + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + let timer = g:neomake_test_matchlist[1] + new + let bufnr2 = bufnr('%') + NeomakeTestsWaitForMessage printf('automake: callback for timer %d (via TextChanged).', timer) + AssertNeomakeMessage printf('automake: buffer changed: %d => %d, queueing make restart for BufEnter,WinEnter.', bufnr1, bufnr2) + AssertEqual split(neomake#utils#redir('au neomake_automake_retry * '), "\n")[1:], [ + \ 'neomake_automake_retry BufEnter', + \ ' ', + \ ' call s:do_postponed_automake(2)', + \ 'neomake_automake_retry WinEnter', + \ ' ', + \ ' call s:do_postponed_automake(2)', + \ ] + + wincmd p + AssertEqual split(neomake#utils#redir('au neomake_automake_retry * '), "\n")[1:], + \ [] + AssertNeomakeMessage '\Vautomake: started timer (10ms):', 3 + NeomakeCancelJobs! + wincmd p + bwipe + bwipe! + endif + +Execute (automake: cleans up autocommands for missing context): + if NeomakeAsyncTestsSetup() + new + set filetype=neomake_tests + let g:neomake_test_enabledmakers = [g:sleep_maker] + call neomake#configure#automake({'TextChanged': {'delay': 10}}) + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + + new + NeomakeTestsWaitForMessage '\Vautomake: callback for timer' + AssertNeomakeMessage '\Vautomake: buffer changed:' + + noautocmd wincmd p + unlet b:_neomake_postponed_automake_context + noautocmd wincmd p + + wincmd p + AssertNeomakeMessage 'automake: missing context information for postponed automake.', 3 + AssertEqual split(neomake#utils#redir('au neomake_automake_retry * '), "\n")[1:], + \ [] + wincmd p + bwipe + bwipe + AssertEqual len(g:neomake_test_finished), 0 + endif + +Execute (Error with non-existing configured maker): + new + let b:neomake = {'automake': {'enabled_makers': ['configured_maker']}} + call neomake#configure#automake({'CursorHold': {}}) + doautocmd CursorHold + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage 'automake: registered events: CursorHold.', 3 + AssertNeomakeMessage "Using setting automake.enabled_makers=['configured_maker'] from 'buffer'.", 3 + AssertNeomakeMessage 'Maker not found (for empty filetype): configured_maker.', 0 + AssertNeomakeMessage 'automake: configured buffer for ft= (no enabled makers).' + AssertNeomakeMessage 'automake: setting tick for new buffer.', 3 + AssertNeomakeMessage 'automake: handling event CursorHold.', 3 + AssertNeomakeMessage 'automake: no enabled makers.' + bwipe + +Execute (No warning with delay=0 if there is no timer support): + if has('timers') + NeomakeTestsSkip 'only without timers feature' + else + new + call neomake#configure#automake({'BufWritePost': {'delay': 5}}) + AssertNeomakeMessage 'automake: timer support is required for automaking, removing event BufWritePost.', 0 + AssertNeomakeMessage 'automake: registered events: .', 3 + + call neomake#configure#automake({'BufWritePost': {'delay': 0}}) + AssertNeomakeMessage 'automake: registered events: BufWritePost.', 3 + + call neomake#configure#automake_for_buffer('w', 5) + AssertNeomakeMessage 'automake: timer support is required for delayed events.', 1 + + call neomake#configure#automake_for_buffer('w', 0) + AssertNeomakeMessageAbsent 'automake: timer support is required for delayed events.', 1 + bwipe + endif + +Execute (Automake pre-creates maker_job instances): + new + let s:call_count = 0 + let maker = {'exe': 'true', 'cwd': '%:h'} + function maker.InitForJob(...) + let s:call_count += 1 + endfunction + let b:neomake_enabled_makers = [maker] + call neomake#configure#automake('n', 0) + + doautocmd InsertLeave + AssertNeomakeMessage 'cwd: '.getcwd().'.' + AssertNeomakeMessage '\v^automake: started jobs:' + NeomakeTestsWaitForFinishedJobs + AssertEqual s:call_count, 1 + + normal! ifoo + AssertNeomakeMessage '\v^automake: started jobs:' + " .fn gets called only once. + AssertEqual s:call_count, 1 + + " 'cwd' gets resolved with the pre-compiled job. + let tmpdir = tempname() + exe 'file '.tmpdir.'/file' + normal! ifoo + + let dir = fnamemodify(bufname('%'), ':h') + AssertNeomakeMessage printf( + \ '\v^unnamed_maker: could not change to maker''s cwd \(\%%:h\): .*%s', + \ escape(dir, '\')) + NeomakeTestsWaitForFinishedJobs + bwipe! + +Execute (neomake#configure#reset_automake stops timers): + if !has('timers') + NeomakeTestsSkip 'Only with timers feature' + else + new + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake({'TextChanged': {'delay': 10}}) + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + let timer = g:neomake_test_matchlist[1] + call neomake#configure#reset_automake() + AssertNeomakeMessage 'automake: stopped timer for cleaned buffer: '.timer.'.' + bwipe + endif + +Execute (Ignores first TextChanged event (Vim issue #2742)): + if !has('patch-8.0.1494') || has('patch-8.0.1633') || has('nvim-0.3.2') + NeomakeTestsSkip 'Only with affected patches (Vim issue #2742)' + else + call neomake#configure#automake('n') + new + doautocmd TextChanged + AssertNeomakeMessage 'automake: ignoring first TextChanged.' + doautocmd TextChanged + AssertNeomakeMessage 'automake: handling event TextChanged.' + bwipe + endif + +Execute (NeomakeDisableBuffer stops timers): + if !has('timers') + NeomakeTestsSkip 'Only with timers feature' + else + new + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake({'TextChanged': {'delay': 10}}) + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + let timer = g:neomake_test_matchlist[1] + NeomakeDisableBuffer + AssertNeomakeMessage 'automake: stopped timer for buffer: '.timer.'.', 3, {'bufnr': bufnr('%')} + + " Re-enabling it kept config. + NeomakeToggleBuffer + doautocmd TextChanged + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + bwipe + endif + +Execute (NeomakeDisable stops timers and keeps custom config): + if !has('timers') + NeomakeTestsSkip 'Only with timers feature' + else + new + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake_for_buffer({'InsertLeave': {'delay': 10}}) + AssertNeomakeMessage 'automake: registered events: InsertLeave.', 3 + + doautocmd InsertLeave + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)', 3 + let timer = g:neomake_test_matchlist[1] + NeomakeDisable + AssertNeomakeMessage 'automake: disabling globally.', 3 + AssertNeomakeMessage 'automake: stopping timers: '.timer.'.' + + " Re-enabling it kept config. + NeomakeEnable + let bufnr = bufnr('%') + AssertNeomakeMessage 'Neomake is enabled (global).' + AssertNeomakeMessage "Using setting automake.events={'InsertLeave': {'delay': 10}} from 'buffer'." + AssertNeomakeMessage 'automake: registered events: InsertLeave.' + doautocmd InsertLeave + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + bwipe + endif + +Execute (NeomakeDisableTab stops timers): + if !has('timers') + NeomakeTestsSkip 'Only with timers feature' + else + new + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake({'TextChanged': {'delay': 10}}) + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + let timer_buffer = g:neomake_test_matchlist[1] + + tabnew + set filetype=neomake_tests + let b:neomake_enabled_makers = [g:true_maker] + call neomake#configure#automake({'TextChanged': {'delay': 10}}) + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + let timer = g:neomake_test_matchlist[1] + NeomakeDisableTab + AssertNeomakeMessage 'automake: stopped timer for buffer: '.timer.'.', 3, {'bufnr': bufnr('%')} + bwipe + + NeomakeDisableBuffer + AssertNeomakeMessage 'automake: stopped timer for buffer: '.timer_buffer.'.', 3, {'bufnr': bufnr('%')} + + " Re-enabling it kept config. + NeomakeToggleBuffer + doautocmd TextChanged + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + bwipe + endif + +Execute (automake: display of error with O during maker run (TextChanged)): + if NeomakeAsyncTestsSetup() + Save g:neomake_test_enabledmakers + + new + set filetype=neomake_tests + normal! o + + let s:error_count = 0 + + let maker1 = copy(g:error_maker) + let maker1.name = 'mymaker1' + function! maker1.process_output(...) + let s:error_count += 1 + return [{'lnum': 1, 'text': 'error1:'.s:error_count}] + endfunction + + let maker2 = copy(g:sleep_maker) + let maker2.name = 'mymaker2' + function! maker2.process_output(...) + let s:error_count += 1 + if s:error_count < 3 + AssertEqual map(getloclist(0), 'v:val.text'), ['error1:'.(s:error_count-1)] + AssertEqual neomake#GetCurrentErrorMsg(), '' + normal! O + doautocmd TextChangedI + endif + return [{'lnum': 1, 'text': 'error2:'.s:error_count}] + endfunction + + let g:neomake_test_enabledmakers = [maker1, maker2] + call neomake#configure#automake({'TextChanged': {'delay': 10}}) + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + + AssertNeomakeMessage '\vautomake: started timer \(10ms\): (\d+)' + AssertEqual neomake#GetCurrentErrorMsg(), '' + + NeomakeTestsWaitForMessage '\Vautomake: callback for timer \d\+ (via TextChanged).', 3 + let make_info = values(neomake#GetStatus().make_info)[0] + let make_id = make_info.make_id + Assert exists('#neomake_automake_abort') + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage 'Processing 1 entries.', 3 + AssertNeomakeMessage 'mymaker1: completed with exit code 1.', 3 + AssertNeomakeMessage '\V\^Skipping cleaning of make info: 1 active jobs: [''Job \d\+: mymaker2''].', 3, make_info + + AssertNeomakeMessage 'exit: mymaker2: 0.', 3 + AssertNeomakeMessage 'automake: buffer was changed (TextChangedI), canceling make.', 3 + AssertNeomakeMessage 'Canceling make.', 3 + AssertNeomakeMessage 'Canceling job.', 3 + AssertNeomakeMessage 'Job exited already.', 3 + AssertNeomakeMessage '\V\^Skipping cleaning of make info: 1 active jobs: [''Job \d\+: mymaker2 [canceled]''].', 3 + AssertNeomakeMessage 'automake: queueing make restart for InsertLeave.', 3 + + " Restarts immediately on InsertLeave. + doautocmd InsertLeave + Assert !exists('#neomake_automake_abort#TextChanged') + Assert exists('#neomake_automake_abort#TextChangedI') + + NeomakeTestsWaitForMessage 'mymaker2: completed with exit code 0.', 3 + AssertNeomakeMessage 'Cleaning jobinfo.', 3 + AssertNeomakeMessage 'Cleaning make info.', 3 + + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), ['error1:3', 'error2:4'] + + " augroup still exists. + Assert exists('#neomake_automake_abort') + " Gets cleaned up on triggered autocmd without neomake_make_ids. + normal! o + doautocmd TextChangedI + Assert exists('#neomake_automake_abort') + Assert !exists('#neomake_automake_abort#TextChanged') + Assert !exists('#neomake_automake_abort#TextChangedI') + bwipe! + endif + +Execute (automake: restarts (BufWritePost)): + if NeomakeAsyncTestsSetup() + Save g:neomake g:neomake_test_enabledmakers + + new + set filetype=neomake_tests + + let s:error_count = 0 + + let maker1 = copy(g:error_maker) + let maker1.name = 'mymaker1' + function! maker1.process_output(...) + let s:error_count += 1 + if s:error_count == 1 + normal! o + doautocmd TextChangedI + doautocmd TextChanged + endif + return [{'lnum': 1, 'text': 'error1:'.s:error_count}] + endfunction + + let g:neomake_test_enabledmakers = [maker1] + call neomake#configure#automake('w') + doautocmd BufWritePost + + AssertNeomakeMessage 'automake: neomake_do_automake: BufWritePost.', 3 + let make_id = neomake#GetStatus().last_make_id + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage 'automake: buffer was changed (TextChangedI), canceling make.', 3, {'make_id': make_id} + AssertEqual len(g:neomake_test_finished), 0 + + doautocmd InsertLeave + AssertNeomakeMessage 'automake: neomake_do_automake: BufWritePost.', 3 + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Processing 1 entries.', 3 + AssertNeomakeMessage 'mymaker1: completed with exit code 1.', 3 + AssertEqual len(g:neomake_test_finished), 1 + + AssertEqual map(getloclist(0), 'v:val.text'), ['error1:2'] + bwipe! + endif + +Execute (automake: handles unexpected make_id): + if NeomakeAsyncTestsSetup() + Save g:neomake_test_enabledmakers + + new + set filetype=neomake_tests + + let maker1 = copy(g:error_maker) + function! maker1.process_output(...) + normal! o + doautocmd TextChangedI + return [{'lnum': 1, 'text': 'error1'}] + endfunction + + let g:neomake_test_enabledmakers = [maker1] + call neomake#configure#automake('w') + doautocmd BufWritePost + let b:_neomake_automake_changed_context[0] = -1 + + AssertNeomakeMessage 'automake: neomake_do_automake: BufWritePost.', 3 + let make_id = neomake#GetStatus().last_make_id + NeomakeTestsWaitForFinishedJobs + AssertEqual neomake#GetCurrentErrorMsg(), '' + + AssertNeomakeMessage 'automake: handle_changed_buffer: mismatched make_id: -1 != '.make_id.'.', 1 + AssertNeomakeMessage 'Processing 1 entries.', 3 + AssertNeomakeMessage 'error-maker: completed with exit code 1.', 3 + + AssertEqual map(getloclist(0), 'v:val.text'), ['error1'] + Assert !exists('b:_neomake_automake_changed_context') + bwipe! + endif + +Execute (automake: uses single list): + new + lgetexpr 'init' + + let s:count = 0 + let maker = {} + function! maker.get_list_entries(...) + let s:count += 1 + return [{'text': 'error'.s:count, 'lnum': 1}] + endfunction + + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 0}}, 0, [maker]) + doautocmd CursorHold + AssertEqual map(getloclist(0), 'v:val.text'), ['error1'] + AssertNeomakeMessage 'Creating location list for entries.', 3 + + normal! o + doautocmd CursorHold + if has('patch-7.4.2200') + AssertNeomakeMessage 'Reusing location list for entries.', 3 + else + AssertNeomakeMessage 'Creating location list for entries.', 3 + endif + AssertEqual map(getloclist(0), 'v:val.text'), ['error2'] + + lolder + if has('patch-7.4.2200') + AssertEqual map(getloclist(0), 'v:val.text'), ['init'] + + lnewer + AssertEqual map(getloclist(0), 'v:val.text'), ['error2'] + lgetexpr 'between' + AssertEqual map(getloclist(0), 'v:val.text'), ['between'] + + " Does not re-use non-current list. + normal! u + doautocmd CursorHold + AssertNeomakeMessage 'Creating location list for entries.', 3 + AssertEqual map(getloclist(0), 'v:val.text'), ['error3'] + let bufnr = bufnr('%') + lopen + AssertEqual w:quickfix_title, 'Neomake[auto]: buf:'.bufnr.' (unnamed_maker(1))' + lclose + + lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['between'] + lopen + Assert w:quickfix_title !~# 'Neomake' + lclose + + lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['error2'] + else + AssertEqual map(getloclist(0), 'v:val.text'), ['error1'] + endif + bwipe! + +Execute (automake: uses single list (efm)): + new + lgetexpr 'init' + + let s:count = 0 + let maker = copy(g:error_maker) + function! maker.postprocess(entry) + let s:count += 1 + let a:entry.text = 'error'.s:count + endfunction + + call neomake#configure#automake_for_buffer({'CursorHold': {'delay': 0}}, 0, [maker]) + doautocmd CursorHold + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), ['error1'] + if has('patch-8.0.1040') + AssertNeomakeMessage 'Creating location list for entries.', 3 + else + AssertNeomakeMessage 'Creating location list.', 3 + endif + + normal! o + doautocmd CursorHold + NeomakeTestsWaitForFinishedJobs + if has('patch-7.4.2200') + AssertNeomakeMessage 'Reusing location list for entries.', 3 + else + AssertNeomakeMessage 'Creating location list.', 3 + endif + AssertEqual map(getloclist(0), 'v:val.text'), ['error2'] + + lolder + if has('patch-7.4.2200') + AssertEqual map(getloclist(0), 'v:val.text'), ['init'] + + lnewer + AssertEqual map(getloclist(0), 'v:val.text'), ['error2'] + lgetexpr 'between' + AssertEqual map(getloclist(0), 'v:val.text'), ['between'] + + " Does not re-use non-current list. + normal! u + doautocmd CursorHold + NeomakeTestsWaitForFinishedJobs + if has('patch-8.0.1040') + AssertNeomakeMessage 'Creating location list for entries.', 3 + else + AssertNeomakeMessage 'Creating location list.', 3 + endif + AssertEqual map(getloclist(0), 'v:val.text'), ['error3'] + let bufnr = bufnr('%') + lopen + AssertEqual w:quickfix_title, 'Neomake[auto]: buf:'.bufnr.' (error-maker(1))' + lclose + + lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['between'] + lopen + Assert w:quickfix_title !~# 'Neomake' + lclose + + lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['error2'] + else + AssertEqual map(getloclist(0), 'v:val.text'), ['error1'] + endif + bwipe! + +Execute (automake: increasing delay): + if NeomakeAsyncTestsSetup() + call neomake#configure#automake({'TextChanged': {'delay': 10}}) + new + let maker = NeomakeTestsCommandMaker('sleep-maker', 'sleep 0.2; echo slept') + let g:neomake_test_enabledmakers = [maker] + + set filetype=neomake_tests + + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + AssertNeomakeMessage 'automake: automake for event TextChanged.' + + doautocmd TextChanged + AssertNeomakeMessage 'automake: automake for event TextChanged.' + AssertNeomakeMessage '\Vautomake: stopped existing timer:' + AssertNeomakeMessage 'automake: increasing delay (1/0 canceled timers/makes, rate=1.20): 10 => 12/3000.' + + doautocmd TextChanged + AssertNeomakeMessage 'automake: automake for event TextChanged.' + AssertNeomakeMessage '\Vautomake: stopped existing timer:' + AssertNeomakeMessage 'automake: increasing delay (2/0 canceled timers/makes, rate=1.40): 10 => 14/3000.' + + NeomakeTestsWaitForMessage '\Vautomake: started jobs:' + doautocmd TextChanged + AssertNeomakeMessage 'automake: automake for event TextChanged.' + AssertNeomakeMessage 'automake: buffer was not changed.' + + normal! o + doautocmd TextChanged + AssertNeomakeMessage 'automake: automake for event TextChanged.' + AssertNeomakeMessage '\Vautomake: stopping previous make runs:' + AssertNeomakeMessage 'automake: increasing delay (2/1 canceled timers/makes, rate=1.90): 10 => 19/3000.' + NeomakeTestsWaitForMessage '\Vautomake: started jobs:' + + normal! u + doautocmd TextChanged + AssertNeomakeMessage 'automake: handling event TextChanged.' + AssertNeomakeMessage 'automake: automake for event TextChanged.' + AssertNeomakeMessage '\Vautomake: stopping previous make runs:' + AssertNeomakeMessage 'automake: increasing delay (2/2 canceled timers/makes, rate=2.40): 10 => 24/3000.' + NeomakeTestsWaitForMessage '\Vautomake: started jobs:' + + AssertEqual b:_neomake_cancelations, [2, 2] + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual b:_neomake_cancelations, [0, 0] + bwipe + endif + +Execute (automake: restart via non-TextChangedI with delay): + if NeomakeAsyncTestsSetup() + call neomake#configure#automake({'CursorHold': {'delay': 10}}) + new + let maker = NeomakeTestsCommandMaker('sleep-maker', 'sleep 0.2; echo slept') + let g:neomake_test_enabledmakers = [maker] + + set filetype=neomake_tests + + doautocmd CursorHold + AssertNeomakeMessage 'automake: automake for event CursorHold.' + + doautocmd CursorHold + AssertNeomakeMessage 'automake: automake for event CursorHold.' + AssertNeomakeMessage '\Vautomake: stopped existing timer:' + AssertNeomakeMessage 'automake: increasing delay (1/0 canceled timers/makes, rate=1.20): 10 => 12/3000.' + + NeomakeTestsWaitForMessage '\Vautomake: started jobs:' + normal! o + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + AssertNeomakeMessage 'automake: buffer was changed (TextChanged), canceling make.' + AssertNeomakeMessage 'automake: restarting timer for original event CursorHold.', 3 + + normal! o + doautocmd TextChanged + AssertNeomakeMessage 'automake: increasing delay (1/1 canceled timers/makes, rate=1.70): 10 => 17/3000.' + NeomakeTestsWaitForMessage '\Vautomake: context/position changed: ' + AssertNeomakeMessage 'automake: increasing delay (2/1 canceled timers/makes, rate=1.90): 10 => 19/3000.' + NeomakeTestsWaitForMessage 'automake: neomake_do_automake: CursorHold.' + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + bwipe! + endif + +Execute (automake: restart via non-TextChangedI without delay): + if NeomakeAsyncTestsSetup() + call neomake#configure#automake({'BufWritePost': {'delay': 0}}) + + new + let g:neomake_test_enabledmakers = [g:sleep_maker] + + set filetype=neomake_tests + + doautocmd BufWritePost + AssertNeomakeMessage 'automake: automake for event BufWritePost.' + NeomakeTestsWaitForMessage 'Running makers: sleep-maker (auto).' + + call NeomakeTestsSetVimMessagesMarker() + normal! o + doautocmd TextChanged + call NeomakeTestsHandleSecondTextChanged() + AssertNeomakeMessage 'automake: restarting for original event (BufWritePost) without delay.', 3 + AssertNeomakeMessage 'automake: neomake_do_automake: BufWritePost.', 3 + + NeomakeTestsWaitForFinishedJobs + bwipe! + endif + +Execute (automake: creates/handles single cleanup autocmd per buffer): + new + Assert !exists('#neomake_automake_clean#BufWipeout') + + let makers = [g:true_maker] + + call neomake#configure#automake_for_buffer('n', 99, {'makers': makers}) + let autocmds_before = neomake#utils#redir('au neomake_automake_clean') + + call neomake#configure#automake_for_buffer('n', 99, {'makers': makers}) + AssertEqual neomake#utils#redir('au neomake_automake_clean'), autocmds_before + + " Trigger buffer setup. + doautocmd InsertLeave + AssertNeomakeMessage 'automake: configured buffer for ft= (true-maker (options)).' + AssertEqual neomake#utils#redir('au neomake_automake_clean'), autocmds_before + + call neomake#configure#reset_automake_for_buffer() + Assert !exists('#neomake_automake_clean#BufWipeout') + " No-op. + call neomake#configure#reset_automake_for_buffer() + + " Trigger buffer setup. + doautocmd InsertLeave + AssertNeomakeMessage 'automake: configured buffer for ft= (true-maker (options)).' + AssertEqual neomake#utils#redir('au neomake_automake_clean'), autocmds_before + + call neomake#configure#reset_automake() + Assert !exists('#neomake_automake_clean#BufWipeout') + bwipe + +Execute (BufWritePost via doautocmd is handled (e.g. vim-fugitive)): + call g:NeomakeSetupAutocmdWrappers() + call neomake#configure#automake('w') + + function! s:BufWriteCmd() abort + exe 'doautocmd BufWritePost '.expand('') + endfunction + augroup neomake_tests + au BufWriteCmd * call s:BufWriteCmd() + augroup END + + new + let b:neomake_test_enabledmakers = ['success_entry_maker'] + set filetype=neomake_tests + + exe 'w' tempname() + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), 1 + Assert exists('b:_neomake_automake_tick') + + " Setup tick for when :diffget was used (only changing it by one), in + " contrast to e.g. ":normal o". + let b:_neomake_automake_tick[0] = b:_neomake_automake_tick[0] - 1 + setlocal modified + update + AssertEqual len(g:neomake_test_jobfinished), 2 + bwipe! + +Execute (automake: skip automake with manual run (in init)): + if NeomakeAsyncTestsSetup() + call neomake#configure#automake({'BufWritePost': {'delay': 100}}) + + new + let bufnr = bufnr('%') + let g:neomake_test_enabledmakers = [g:entry_maker] + set filetype=neomake_tests + + call neomake#Make(1, [g:sleep_maker]) + doautocmd BufWritePost + AssertNeomakeMessage '\Vautomake: skipping for already running jobs: [''Job \d\+: sleep-maker''].', 3 + + NeomakeTestsWaitForFinishedJobs + let valid = has('patch-8.0.0580') + AssertEqualQf getloclist(0), [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'pattern': '', 'valid': valid, + \ 'vcol': 0, 'nr': -1, 'type': 'W', 'text': 'slept'}] + + " Next automake triggers run (not having updated tick). + doautocmd BufWritePost + AssertNeomakeMessage 'automake: automake for event BufWritePost.', 3 + NeomakeTestsWaitForNextFinishedJob + AssertEqualQf getloclist(0), [ + \ {'lnum': 1, 'bufnr': bufnr, 'col': 0, 'pattern': '', 'valid': 1, + \ 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'error'}] + bwipe! + endif + +Execute (automake: skip automake with manual run (in callback)): + if NeomakeAsyncTestsSetup() + call neomake#configure#automake({'BufWritePost': {'delay': 10}}) + + new + let bufnr = bufnr('%') + let g:neomake_test_enabledmakers = [g:entry_maker] + set filetype=neomake_tests + + doautocmd BufWritePost + AssertNeomakeMessage 'automake: automake for event BufWritePost.', 3 + call neomake#Make(1, [g:sleep_maker]) + + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage '\Vautomake: skipping for already running jobs: [''Job \d\+: sleep-maker''].', 3 + let valid = has('patch-8.0.0580') + AssertEqualQf getloclist(0), [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'pattern': '', 'valid': valid, + \ 'vcol': 0, 'nr': -1, 'type': 'W', 'text': 'slept'}] + + " Next automake triggers run (not having updated tick). + doautocmd BufWritePost + AssertNeomakeMessage 'automake: automake for event BufWritePost.', 3 + NeomakeTestsWaitForNextFinishedJob + AssertEqualQf getloclist(0), [ + \ {'lnum': 1, 'bufnr': bufnr, 'col': 0, 'pattern': '', 'valid': 1, + \ 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'error'}] + bwipe! + endif + +Execute (automake: abort automake with manual run): + if NeomakeAsyncTestsSetup() + call neomake#configure#automake({'BufWritePost': {'delay': 100}}) + + new + let bufnr = bufnr('%') + let g:neomake_test_enabledmakers = [g:sleep_maker] + set filetype=neomake_tests + + doautocmd BufWritePost + AssertNeomakeMessage 'automake: automake for event BufWritePost.' + NeomakeTestsWaitForMessage 'Running makers: sleep-maker (auto).' + + call neomake#Make(1, [g:entry_maker]) + let expected_loclist = [ + \ {'lnum': 1, 'bufnr': bufnr, 'col': 0, 'pattern': '', 'valid': 1, + \ 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'error'}] + AssertEqualQf getloclist(0), expected_loclist + NeomakeTestsWaitForFinishedJobs + AssertEqualQf getloclist(0), expected_loclist + bwipe! + endif diff --git a/bundle/neomake/tests/cancellation.vader b/bundle/neomake/tests/cancellation.vader new file mode 100644 index 000000000..09616c7a1 --- /dev/null +++ b/bundle/neomake/tests/cancellation.vader @@ -0,0 +1,293 @@ +Include: include/setup.vader + +Execute (neomake#CancelJob): + if NeomakeAsyncTestsSetup() + let job_id = neomake#Sh("sh -c 'while true; do sleep 0.01; done'") + let jobinfo = neomake#GetJob(job_id) + let job = has('nvim') ? jobinfo.nvim_job : string(jobinfo.vim_job) + AssertEqual neomake#CancelJob(job_id), 1 + AssertNeomakeMessage printf('Stopping %s job: %s.', + \ (has('nvim') ? 'Neovim' : 'Vim'), job), 3, jobinfo + + AssertEqual neomake#CancelJob(job_id), 0 + AssertNeomakeMessage 'Job was canceled already.', 2, jobinfo + + NeomakeTestsWaitForFinishedJobs + + if has('nvim-0.4.0') + let expected_status = 143 + elseif has('nvim') + let expected_status = 0 + else + let expected_status = -1 + endif + AssertNeomakeMessage '\Vexit: \.\*: '.expected_status.' (job was canceled).', 3, jobinfo + AssertNeomakeMessage 'Cleaning jobinfo.', 3, jobinfo + AssertNeomakeMessage 'Cleaning make info.' + + AssertEqual neomake#CancelJob(job_id), 0 + AssertNeomakeMessage 'CancelJob: job not found: '.job_id.'.', 0 + endif + +Execute (neomake#CancelJob with invalid job): + if NeomakeAsyncTestsSetup() + let job_id = neomake#Sh("sh -c 'sleep 1'") + let jobinfo = neomake#GetJob(job_id) + + " Stop the job manually. + if has('nvim') + call jobstop(jobinfo.nvim_job) + else + call ch_close(jobinfo.vim_job) + while job_status(jobinfo.vim_job) !=# 'dead' + sleep 10m + endwhile + endif + + AssertEqual len(neomake#GetJobs()), 1, 'There are jobs (1)' + let ret = neomake#CancelJob(job_id) + AssertEqual ret, 0, 'CancelJob returned 0.' + AssertEqual len(neomake#GetJobs()), 0, 'There are no more jobs' + AssertNeomakeMessageAbsent 'exit: job not found: '.job_id.'.' + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$', 3, jobinfo + if has('nvim') + if !has('nvim-0.5') + AssertNeomakeMessage '\vjobstop failed: Vim\(let\):E900: Invalid (job|channel) id.', 2, jobinfo + endif + else + AssertNeomakeMessage 'job_stop: job was not running anymore.', 2, jobinfo + endif + + let ret = neomake#CancelJob(job_id) + if has('nvim') + " Vim returns 1 via job_stop usually. + AssertEqual ret, 0, "CancelJob (2) returned ".ret + endif + AssertNeomakeMessage 'CancelJob: job not found: '.job_id.'.', 0, {} + if has('nvim') + " With Vim the exit callback is not invoked (since ch_close was used). + NeomakeTestsWaitForNextMessage + AssertNeomakeMessage 'exit: job not found: '.jobinfo.nvim_job.'.', 3, {} + else + NeomakeCancelJobs! + endif + let ret = neomake#CancelJob(job_id) + AssertEqual ret, 0, "CancelJob (3) returned ".ret + AssertNeomakeMessage 'CancelJob: job not found: '.job_id.'.', 0, {} + endif + +Execute (neomake#CancelJobs! removes canceled jobs): + if NeomakeAsyncTestsSetup() + let jobinfos = neomake#Make({'enabled_makers': [g:sleep_maker, g:sleep_maker]}) + let jobinfos[0].canceled = 1 + NeomakeCancelJobs! + AssertNeomakeMessage 'Canceling 2 jobs.', 3 + AssertNeomakeMessage 'Job was canceled already.', 2, jobinfos[0] + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$', 3, jobinfos[1] + AssertNeomakeMessage 'Cleaning jobinfo.', 3, jobinfos[1] + + NeomakeTestsWaitForMessage '\m^exit: job not found' + endif + +Execute (neomake#CancelJob! with invalid job): + if NeomakeAsyncTestsSetup() + let job_id = neomake#Sh("sh -c 'sleep 0.1'") + let jobinfo = neomake#GetJob(job_id) + + " Stop the job manually. + if has('nvim') + call jobstop(jobinfo.nvim_job) + else + let vim_job = jobinfo.vim_job + call job_stop(vim_job) + endif + + AssertEqual len(neomake#GetJobs()), 1, 'There are jobs' + let ret = neomake#CancelJob(job_id, 1) + + " Jobinfo should have been cleaned already. With Neovim it gets done + "" anyway, because jobstop fails. + Assert !len(neomake#GetJobs()), 'There are no jobs' + if has('nvim') + " Vim returns 1 via job_stop usually. + AssertEqual ret, 0, "CancelJob (1) returned ".ret + endif + AssertNeomakeMessageAbsent 'exit: job not found: '.job_id.'.' + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$', 3, jobinfo + if has('nvim') + if !has('nvim-0.5') + AssertNeomakeMessage '\vjobstop failed: Vim\(let\):E900: Invalid (job|channel) id.', 2, jobinfo + endif + endif + AssertEqual neomake#GetJobs(), [] + + AssertEqual neomake#CancelJob(job_id), 0 + AssertNeomakeMessageAbsent '\v^Stopping \w+ job: .+\.$', 3, jobinfo + AssertNeomakeMessage 'CancelJob: job not found: '.job_id.'.', 0 + + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessageAbsent 'exit: job not found: '.job_id.'.' + + if has('nvim') + NeomakeTestsWaitForMessage 'exit: job not found: '.jobinfo.nvim_job.'.', 3 + else + NeomakeTestsWaitForMessage '\vexit: job not found: channel \d+ closed \(\{''status'': ''dead''.*\.', 3 + endif + AssertEqual neomake#CancelJob(job_id, 1), 0 + AssertNeomakeMessage 'CancelJob: job not found: '.job_id.'.', 0 + endif + +Execute (neomake#CancelJob with trapped TERM): + if NeomakeAsyncTestsSetup() + let trap_sh = fnamemodify(g:vader_file, ':p:h').'/helpers/trap.sh' + let job_id = neomake#ShCommand(1, trap_sh) + let jobinfo = neomake#GetJob(job_id) + + " Ensure the script is running. + NeomakeTestsWaitForMessage '\voutput on stdout: \[''Started: (\d+)''', 3, jobinfo + let pid = g:neomake_test_matchlist[1] + + AssertEqual neomake#CancelJob(job_id), 1 + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$', 3, jobinfo + + NeomakeTestsWaitForMessage '\Moutput on stdout: \.\*''not stopping on SIGTERM''', 3, jobinfo + AssertNeomakeMessage 'Ignoring output (job was canceled).', 3, jobinfo + if has('nvim-0.4.0') + let expected_status = 137 + elseif has('nvim') + let expected_status = 0 + else + let expected_status = -1 + endif + NeomakeTestsWaitForMessage '\Vexit: \.\*: '.expected_status.' (job was canceled).', 3, jobinfo, {'timeout': 5000} + if !has('nvim') + AssertNeomakeMessage 'Forcefully killing still running Vim job.', 3, jobinfo, {'ignore_order': 1} + endif + + AssertEqual neomake#CancelJob(job_id), 0 + AssertNeomakeMessage 'CancelJob: job not found: '.job_id.'.', 0 + endif + +Execute (neomake#CancelMake stops all jobs): + if NeomakeAsyncTestsSetup() + let jobinfos = neomake#Make({'file_mode': 0, 'enabled_makers': [g:sleep_maker, g:sleep_maker]}) + let make_id = neomake#GetStatus().last_make_id + AssertEqual neomake#CancelMake(make_id), 1 + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$' + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$' + + if has('nvim-0.4.0') + let expected_status = 143 + elseif has('nvim') + let expected_status = 0 + else + let expected_status = -1 + endif + AssertNeomakeMessage 'exit: sleep-maker: '.expected_status.' (job was canceled).' + AssertNeomakeMessage 'Cleaning jobinfo.' + AssertNeomakeMessage 'exit: sleep-maker: '.expected_status.' (job was canceled).' + AssertNeomakeMessage 'Cleaning jobinfo.' + endif + +Execute (neomake#CancelMake handles invalid make id): + AssertEqual neomake#CancelMake(-1), 0 + AssertNeomakeMessage 'CancelMake: make not found: -1.', 0 + +Execute (neomake#CancelMake removes queued actions): + if NeomakeAsyncTestsSetup() + new + let maker = NeomakeTestsCommandMaker('silent-sleep-success', 'sleep .01') + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + new + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Cleaning jobinfo.', 3 + AssertNeomakeMessage 'Postponing final location list handling (in another window).', 3 + AssertNeomakeMessage 'Queuing action handle_locqf_list_for_finished_jobs for WinEnter.', 3 + + let log_context = neomake#GetStatus().make_info[jobinfo.make_id] + let log_context.make_id = jobinfo.make_id + call neomake#CancelAllMakes() + AssertNeomakeMessage 'Canceling make.', 3, log_context + AssertNeomakeMessage 'Removed 1 action queue entries.', 3 + AssertNeomakeMessage 'Skipping final processing for canceled make.' + call neomake#CancelMake(jobinfo.make_id) + AssertNeomakeMessage 'CancelMake: make not found: '.jobinfo.make_id.'.', 0 + bwipe + bwipe + endif + +Execute (neomake#CancelJob empties action queue): + if NeomakeAsyncTestsSetup() + new + let maker = copy(g:entry_maker) + function! maker.get_list_entries(...) + wincmd p + return [{'text': 'entry_text', 'lnum': 1}] + endfunction + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + let job_id = jobinfo.id + NeomakeTestsWaitForMessage 'Queuing action ProcessEntries for BufEnter, WinEnter.' + AssertNeomakeMessage "Skipping cleaning of job info because of queued actions: ['ProcessEntries', ['BufEnter', 'WinEnter']].", 3 + AssertNeomakeMessage 'Queuing action CleanJobinfo for WinEnter.' + call neomake#CancelJob(job_id) + AssertNeomakeMessage 'Removed 2 action queue entries.', 3 + AssertNeomakeMessage 'Removing job for get_list_entries.', 3, jobinfo + wincmd p + AssertNeomakeMessage 'Cleaning make info.', 3 + bwipe + Assert !exists('#neomake_event_queue#WinEnter'), 'autocmd does not exist' + endif + +Execute (neomake#CancelJob handles dict): + if NeomakeAsyncTestsSetup() + let jobinfo = neomake#Make({'enabled_makers': [g:sleep_maker]})[0] + Assert type(jobinfo), type({}) + AssertEqual neomake#CancelJob(jobinfo), 1 + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$', 3, jobinfo + NeomakeTestsWaitForFinishedJobs + endif + +Execute (neomake#CancelJob handles string with job_id at the beginning): + if NeomakeAsyncTestsSetup() + let jobinfo = neomake#Make({'enabled_makers': [g:sleep_maker]})[0] + AssertEqual neomake#CancelJob(jobinfo.id . ':'), 1 + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$', 3, jobinfo + NeomakeTestsWaitForFinishedJobs + endif + +Execute (neomake#CancelJob clears action queue for get_list_entries maker): + if NeomakeAsyncTestsSetup() + let maker = {} + function! maker.get_list_entries(...) abort dict + " causes E48 + sandbox bprevious + endfunction + + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + AssertNeomakeMessage 'Queuing action handle_get_list_entries for Timer, WinEnter.' + + " CancelJob returns 0, since it is processed directly. + AssertEqual neomake#CancelJob(jobinfo), 0 + AssertNeomakeMessage 'Canceling job.', 3, jobinfo + AssertNeomakeMessage 'Removed 1 action queue entries.', 3 + AssertNeomakeMessage 'Removing job for get_list_entries.', 3 + AssertNeomakeMessage 'Cleaning jobinfo.', 3 + AssertNeomakeMessage 'Cleaning make info.', 3 + endif + +Execute (CleanJobinfo with cancellation while in exit handler): + new + let maker = copy(g:error_maker) + let maker.name = 'mymaker1' + function! maker.process_output(...) + NeomakeCancelJobs + return [{'lnum': 1, 'text': 'still_processed'}] + endfunction + + CallNeomake 1, [maker] + AssertNeomakeMessage 'Canceling 1 jobs.', 3 + AssertNeomakeMessage 'Job exited already.', 3 + + AssertEqual map(getloclist(0), 'v:val.text'), [] + bwipe diff --git a/bundle/neomake/tests/clean.vader b/bundle/neomake/tests/clean.vader new file mode 100644 index 000000000..e3a0be293 --- /dev/null +++ b/bundle/neomake/tests/clean.vader @@ -0,0 +1,66 @@ +Include: include/setup.vader + +Execute (NeomakeClean: no-op): + NeomakeClean + NeomakeClean! + +Execute (NeomakeClean: file-mode): + Save g:neomake_open_list + let g:neomake_open_list = 2 + + new + let win_count = winnr('$') + CallNeomake 1, [g:entry_maker] + AssertEqual winnr('$'), win_count + 1, "loclist appeared" + + NeomakeClean + AssertEqual winnr('$'), win_count + 1, "loclist was not closed" + + lclose + bwipe + +Execute (NeomakeClean: file-mode (customqf)): + Save g:neomake_open_list + let g:neomake_open_list = 2 + + try + call neomake#quickfix#enable(1) + + new + let win_count = winnr('$') + CallNeomake 1, [g:entry_maker] + AssertEqual winnr('$'), win_count + 1, "loclist appeared" + + NeomakeClean + AssertEqual winnr('$'), win_count, "loclist was closed" + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (NeomakeClean: project-mode): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + CallNeomake 0, [g:entry_maker] + NeomakeClean! + cclose + bwipe + +Execute (NeomakeClean: project-mode (customqf)): + Save g:neomake_open_list + let g:neomake_open_list = 2 + + try + call neomake#quickfix#enable(1) + new + let win_count = winnr('$') + CallNeomake 0, [g:entry_maker] + AssertEqual winnr('$'), win_count + 1, "qflist appeared" + + NeomakeClean! + AssertEqual winnr('$'), win_count, "qflist was closed" + bwipe + finally + call neomake#quickfix#disable() + endtry diff --git a/bundle/neomake/tests/cmd_neomakeinfo.vader b/bundle/neomake/tests/cmd_neomakeinfo.vader new file mode 100644 index 000000000..9fa3d4e78 --- /dev/null +++ b/bundle/neomake/tests/cmd_neomakeinfo.vader @@ -0,0 +1,233 @@ +" Tests for the NeomakeInfo command. +Include: include/setup.vader + +Execute (:NeomakeInfo output end to end test): + if !(exists('*execute') && has('nvim-0.2.0')) + NeomakeTestsSkip 'Only with execute() support' + else + let info = split(neomake#utils#redir('NeomakeInfo'), '\n') + Assert len(filter(copy(info), "v:val =~ '\\v^#+ Settings$'")), 'Settings header exists' + endif + +Execute (:NeomakeInfo): + Save g:neomake_c_enabled_makers, g:neomaker_not_a_setting + let g:neomake_c_enabled_makers = ['doesnotexist'] + let g:neomaker_not_a_setting = 1 + Save &makeprg + let &makeprg = 'mycustom make %' + + let info = neomake#debug#_get_info_lines() + Assert len(filter(copy(info), "v:val =~ '\\v^#+ Settings$'")), 'Settings header exists' + Assert index(info, "g:neomake_c_enabled_makers = ['doesnotexist']") != -1, + \ 'neomake_c_enabled_makers setting gets reported' + AssertEqual filter(copy(info), "v:val =~ 'neomaker'"), [] + + Assert len(filter(copy(info), 'v:val =~# "^makeprg=mycustom make %, Last set from"')) == 1, + \ 'Contains &makeprg: '.string(info) + +Execute (:NeomakeInfo with FuncRef): + Save g:neomake_c_enabled_makers, g:neomake_c_doesnotexist_maker + new + set filetype=c + function! InitForJob(jobinfo) abort + endfunction + let g:neomake_c_enabled_makers = ['doesnotexist'] + let g:neomake_c_doesnotexist_maker = { + \ 'InitForJob': function('InitForJob'), + \ 'errorformat': 'custom_efm: %m'} + + let info = neomake#debug#_get_info_lines() + let idx = -1 + for line in [ + \ 'For the current filetype ("c", used with :Neomake):', + \ ' - doesnotexist', + \ ' - errorformat: ''custom_efm: %m''', + \ ' - exe: ''doesnotexist'''] + let i = index(info, line) + Assert i > idx, 'line not found: "'.line.'" (idx: '.idx.')'."\n".join(info, "\n") + let idx = i + endfor + Assert len(map(info, 'v:val =~# " - InitForJob: function.*"')), 'InitForJob not found' + delfunction InitForJob + bwipe + +Execute (:NeomakeInfo with unusual filetype): + new + set filetype=ft1.gentoo-package-keywords + let info = neomake#debug#_get_info_lines() + Assert index(info, 'NOTE: you can define g:neomake_ft1_gentoo_package_keywords_enabled_makers to configure it (or b:neomake_ft1_gentoo_package_keywords_enabled_makers).') != -1, 'Line was found' + bwipe + +Execute (:NeomakeInfo displays issues): + Save g:neomake_enabled_makers, g:neomake_mymaker_maker + + let g:neomake_enabled_makers = ['mymaker'] + let g:neomake_mymaker_maker = { + \ 'exe': 'doesnotexist', + \ 'errorformat': 'custom_efm: %m', + \ 'mapexpr': '', + \ 'postprocess': function('tr'), + \ 'process_output': function('tr'), + \ } + + let info = neomake#debug#_get_info_lines() + let idx = -1 + for line in [ + \ '#### Neomake debug information', + \ 'For the project (used with :Neomake!):', + \ ' - mymaker', + \ ' - errorformat: ''custom_efm: %m''', + \ ' - exe: ''doesnotexist''', + \ ' - ERRORS:', + \ " - maker's exe (doesnotexist) is not executable.", + \ ' - WARNINGS:', + \ ' - maker has mapexpr, but only process_output will be used.', + \ ' - maker has postprocess, but only process_output will be used.', + \ '#### :version', + \ '#### :messages', + \ ] + let i = index(info, line) + Assert i > idx, 'line not found: "'.line.'" (idx: '.idx.')'."\n".join(info, "\n") + let idx = i + endfor + +Execute (NeomakeInfo! copies to clipboard): + try + let save_reg = getreg('+') + catch + NeomakeTestsSkip 'Clipboard is not available: '.v:exception + return + endtry + + call NeomakeTestsSetVimMessagesMarker() + let restore = 1 + try + NeomakeInfo! + let info = split(getreg('+'), '\n') + if empty(info) + let restore = 0 + AssertNeomakeMessage "Could not set clipboard: Vim(call):E354: Invalid register name: '+'.", 0 + return + endif + finally + if restore + call setreg('+', save_reg, 'l') + endif + endtry + let idx = -1 + for line in [ + \ '#### Neomake debug information', + \ '#### :version', + \ '#### :messages', + \ ] + let i = index(info, line) + Assert i > idx, 'line not found: "'.line.'" (idx: '.idx.')'."\n".join(info, "\n") + let idx = i + endfor + + AssertEqual NeomakeTestsGetVimMessages(), [ + \ 'Copied Neomake info to clipboard ("+).'] + +Execute (NeomakeInfo displays new-style config): + Assert !exists('g:neomake') + new + + let info = neomake#debug#_get_info_lines() + let idx = -1 + for line in [ + \ '#### Neomake debug information', + \ '##### Settings', + \ '###### New-style (dict, overrides old-style)', + \ "g:neomake: unset", + \ 'b:neomake: unset', + \ ] + let i = index(info, line) + Assert i > idx, 'line not found: "'.line.'" (idx: '.idx.')'."\n".join(info, "\n") + let idx = i + endfor + + " Using neomake#config#get() should not trigger setting g:neomake. + AssertEqual neomake#config#get('doesnotexist'), g:neomake#config#undefined + let b:neomake = {} + let info = neomake#debug#_get_info_lines() + let idx = -1 + for line in [ + \ '#### Neomake debug information', + \ '##### Settings', + \ '###### New-style (dict, overrides old-style)', + \ "g:neomake: unset", + \ 'b:neomake: {}', + \ ] + let i = index(info, line) + Assert i > idx, 'line not found: "'.line.'" (idx: '.idx.')'."\n".join(info, "\n") + let idx = i + endfor + bwipe + +Execute (NeomakeInfo does not display message for filetype with no makers): + new + noautocmd set filetype=doesnotexist + + call NeomakeTestsSetVimMessagesMarker() + let info = neomake#debug#_get_info_lines() + let msgs = NeomakeTestsGetVimMessages() + bwipe + + AssertEqual msgs, [] + Assert index(info, 'For the current filetype ("doesnotexist", used with :Neomake):') > 0 + +Execute (NeomakeInfo with maker name): + " NOTE: Vim needs non-empty PATH for executable to be false! + " (https://github.com/vim/vim/pull/3283) + call g:NeomakeTestsSetPATH('/doesnotexist') + Assert !executable('make') + + new + noautocmd set filetype=neomake_tests + NeomakeInfo foo + AssertNeomakeMessage 'Maker not found: foo.', 0 + + call NeomakeTestsSetVimMessagesMarker() + NeomakeInfo makeprg + AssertEqual NeomakeTestsGetVimMessages(), [] + AssertEqual neomake#debug#get_maker_info('maker_with_nonstring_exe')[-2:], [ + \ ' - ERRORS:', + \ " - Non-string given for executable of maker maker_with_nonstring_exe: type 2.", + \ ] + + call NeomakeTestsSetVimMessagesMarker() + NeomakeInfo makeprg + AssertEqual NeomakeTestsGetVimMessages(), [] + AssertEqual neomake#debug#get_maker_info('makeprg')[-2:], [ + \ ' - ERRORS:', + \ " - maker's exe (make) is not executable.", + \ ] + + Save &makeprg + set makeprg=custommakeprg + NeomakeInfo makeprg + AssertEqual NeomakeTestsGetVimMessages(), [] + AssertEqual neomake#debug#get_maker_info('makeprg')[-2:], [ + \ ' - ERRORS:', + \ " - maker's exe (custommakeprg) is not executable.", + \ ] + + " Uses &shell when checking executable for makeprg with spaces. + Save &shell + set shell=customshell + set makeprg=custom\ make\ prg + NeomakeInfo makeprg + AssertEqual NeomakeTestsGetVimMessages(), [] + AssertEqual neomake#debug#get_maker_info('makeprg')[-2:], [ + \ ' - ERRORS:', + \ " - maker's exe (customshell) is not executable.", + \ ] + + let b:neomake_makeprg_exe = 'custom_exe' + NeomakeInfo makeprg + AssertEqual NeomakeTestsGetVimMessages(), [] + AssertEqual neomake#debug#get_maker_info('makeprg')[-2:], [ + \ ' - ERRORS:', + \ " - maker's exe (custom_exe) is not executable.", + \ ] + bwipe diff --git a/bundle/neomake/tests/compat.vader b/bundle/neomake/tests/compat.vader new file mode 100644 index 000000000..e99c2d784 --- /dev/null +++ b/bundle/neomake/tests/compat.vader @@ -0,0 +1,216 @@ +Include: include/setup.vader + +Execute (neomake#compat#uniq): + AssertEqual neomake#compat#uniq([]), [] + AssertEqual neomake#compat#uniq([1, 2]), [1, 2] + AssertEqual neomake#compat#uniq([1, 2, 1]), [1, 2, 1] + AssertEqual neomake#compat#uniq([1, 1, 2]), [1, 2] + AssertEqual neomake#compat#uniq([1, 1, 2, 2]), [1, 2] + AssertEqual neomake#compat#uniq([1, 1, 2, 2, '2']), [1, 2, '2'] + + AssertEqual neomake#compat#uniq([[1], [1]]), [[1]] + AssertEqual neomake#compat#uniq([{'a': 1}]), [{'a': 1}] + +Execute (neomake#compat#uniq modifies list in place): + let l = [5, 5] + call neomake#compat#uniq(l) + AssertEqual l, [5] + +Execute (neomake#compat#reltimefloat): + let r = neomake#compat#reltimefloat() + AssertEqual type(r), type(0.0) + let r2 = neomake#compat#reltimefloat() + Assert r2 > r, '2nd result is bigger' + +Execute (neomake#compat#systemlist): + let r = neomake#compat#systemlist(['echo 1']) + if has('nvim') + AssertEqual r, '' + if has('nvim-0.5.0') + AssertNeomakeMessage "systemlist error: Vim(return):E475: Invalid value for argument cmd: 'echo 1' is not executable.", 0 + endif + else + AssertEqual r, [&shell.': echo 1: command not found'] + AssertEqual v:shell_error, 127 + endif + + AssertEqual neomake#compat#systemlist(['echo', '1']), ['1'] + AssertEqual v:shell_error, 0 + AssertEqual neomake#compat#systemlist(['sh', '-c', 'echo 1; echo 2']), ['1', '2'] + AssertEqual v:shell_error, 0 + AssertEqual neomake#compat#systemlist(['echo', '1 2']), ['1 2'] + AssertEqual v:shell_error, 0 + AssertEqual neomake#compat#systemlist(['printf', '%s\n', '1', '2']), ['1', '2'] + AssertEqual v:shell_error, 0 + +Execute (neomake#compat#systemlist with empty args): + AssertEqual neomake#compat#systemlist(''), [] + AssertEqual neomake#compat#systemlist([]), [] + AssertEqual neomake#compat#systemlist('0'), [&shell.': 0: command not found'] + +Execute (neomake#compat#json_decode): + AssertEqual neomake#compat#json_decode(''), g:neomake#compat#json_none + Assert neomake#compat#json_decode('') is g:neomake#compat#json_none + + if has('nvim') + let expected_exception = 'Vim(return):E474: Unidentified byte: success' + elseif exists('*json_decode') + let expected_exception = 'Vim(return):E474: Invalid argument' + else + let expected_exception = 'Neomake: Failed to parse JSON input: invalid input' + endif + AssertThrows call neomake#compat#json_decode('success') + AssertEqual g:vader_exception, expected_exception + +Execute (neomake#compat#json_decode: handles newlines): + let json = '{"foo": '."\n".'"bar"}' + AssertEqual neomake#compat#json_decode(json), {'foo': 'bar'} + +Execute (neomake#compat#json_none): + AssertThrows call items(g:neomake#compat#json_none) + AssertEqual g:vader_exception, 'Vim(call):E715: Dictionary required' + Assert empty(g:neomake#compat#json_none), 'json_none is empty' + +Execute (neomake#compat#get_mode): + AssertEqual neomake#compat#get_mode(), 'n' + + norm! V + AssertEqual neomake#compat#get_mode(), 'V' + exe "norm! \" + AssertEqual neomake#compat#get_mode(), 'n' + + if has('nvim') + let nvim_exe = '/proc/'.getpid().'/exe' + let nvim_cmd = [nvim_exe, '-u', 'tests/vim/vimrc', '--headless'] + if has('nvim-0.3.0') + " Do not use --embed, which might cause it to hang with hit-enter prompt + " due to `echom` (while debugging). Requires Neovim 0.3.0+. + let nvim_cmd += ['--cmd', "call stdioopen({'rpc': v:true})"] + else + let nvim_cmd += ['--embed'] + endif + let nvim = jobstart(nvim_cmd, {'rpc': v:true}) + call rpcrequest(nvim, 'nvim_call_function', 'feedkeys', ['d', '!']) + call rpcrequest(nvim, 'nvim_eval', 'assert_equal(neomake#compat#get_mode(), "no")') + let rpc_errors = rpcrequest(nvim, 'nvim_eval', 'v:errors') + AssertEqual rpc_errors, [] + call jobstop(nvim) + elseif exists('*timer_start') + let b:mode_in_cb = '' + function s:CB(...) + let b:mode_in_cb = neomake#compat#get_mode() + call feedkeys("\") + endfunction + call timer_start(10, 's:CB') + call feedkeys('da', 'x!') + AssertEqual b:mode_in_cb, 'no' + AssertEqual neomake#compat#get_mode(), 'n' + endif + +Execute (neomake#compat#get_mode with insert mode completion (feedkeys)): + if has('timers') + new + file file_sleep_efm + normal! iword1 + normal! oword2 + + function! s:close_pum(...) + let s:mode = neomake#compat#get_mode() + let s:in_completion = neomake#compat#in_completion() + call feedkeys("\\") + endfunction + + call timer_start(10, 's:close_pum') + " NOTE: silent for Neovim (https://github.com/neovim/neovim/issues/9372). + silent call feedkeys("oword\", 'x!') + + if has('patch-8.0.0283') + AssertEqual s:mode, 'ic' + else + AssertEqual s:mode, 'i' + endif + AssertEqual getline('.'), 'word' + AssertEqual s:in_completion, 1 + bwipe! + endif + +Execute (neomake#compat#get_mode with insert mode completion (imap)): + new + file file_sleep_efm + normal! iword1 + normal! oword2 + + function s:save_mode() + let s:mode = neomake#compat#get_mode() + let s:in_completion = neomake#compat#in_completion() + return '' + endfunction + + " NOTE: silent for Neovim (https://github.com/neovim/neovim/issues/9372). + inoremap =s:save_mode() + + exe "normal oword\\\\" + if has('patch-8.0.0283') + AssertEqual s:mode, 'ic' + else + AssertEqual s:mode, 'i' + endif + AssertEqual s:in_completion, 1 + AssertEqual getline('.'), 'word' + + exe "normal oword\\\\" + AssertEqual s:mode, 'i' + AssertEqual s:in_completion, 0 + AssertEqual getline('.'), 'word' + bwipe! + +Execute (neomake#compat#glob_list): + AssertEqual neomake#compat#glob_list('doesnotexist'), [] + AssertEqual neomake#compat#glob_list(g:vader_file), [g:vader_file] + + Save &wildignore + let &wildignore = '*.vader' + AssertEqual fnamemodify(g:vader_file, ':e'), 'vader' + AssertEqual neomake#compat#glob_list(g:vader_file), [g:vader_file] + +Execute (neomake#compat#restore_prev_windows handles removed windows): + new + new + if exists('*win_getid') + let expected_msg = printf('Cannot restore previous windows (previous window with ID %d not found).', + \ win_getid()) + else + let expected_msg = 'Cannot restore previous windows (3 > 2).' + endif + call neomake#compat#save_prev_windows() + bwipe + call neomake#compat#restore_prev_windows() + AssertNeomakeMessage expected_msg, 3 + bwipe + +Execute (neomake#compat#restore_prev_windows triggers autocommands): + new + + let s:events = [] + augroup neomake_tests + au WinEnter * call add(s:events, ['WinEnter', winnr()]) + au WinLeave * call add(s:events, ['WinLeave', winnr()]) + augroup END + + let expected_events = [ + \ ['WinLeave', 2], ['WinEnter', 3], + \ ['WinLeave', 3], ['WinEnter', 2]] + new + wincmd p + AssertEqual s:events, expected_events + wincmd p + bwipe + + let s:events = [] + call neomake#compat#save_prev_windows() + new + call neomake#compat#restore_prev_windows() + AssertEqual s:events, expected_events + wincmd p + bwipe + bwipe diff --git a/bundle/neomake/tests/completion.vader b/bundle/neomake/tests/completion.vader new file mode 100644 index 000000000..0896c154c --- /dev/null +++ b/bundle/neomake/tests/completion.vader @@ -0,0 +1,146 @@ +Include: include/setup.vader + +Execute (neomake#cmd#complete_makers: completes makers for b:): + new + let b:neomake_c_lint_maker = { + \ 'exe': 'lint', + \ 'args': ['--option', 'x'], + \ 'errorformat': '%f:%l:%c: %m', + \ } + set filetype=c + call g:NeomakeTestsCreateExe('lint', []) + AssertEqual neomake#GetMaker('checkpatch').name, 'checkpatch' + Assert index(neomake#cmd#complete_makers('', 'Neomake '), 'lint') != -1, 'lint maker gets completed' + bwipe + +Execute (neomake#cmd#complete_makers: handles invalid ArgLead): + AssertEqual neomake#cmd#complete_makers('~', 'Neomake '), [] + +Execute (neomake#cmd#complete_makers: completes makers for g:): + Save g:neomake_c_lint_maker + new + let g:neomake_c_lint_maker = { + \ 'exe': 'lint', + \ 'args': ['--option', 'x'], + \ 'errorformat': '%f:%l:%c: %m', + \ } + set filetype=c + call g:NeomakeTestsCreateExe('lint', []) + Assert index(neomake#cmd#complete_makers('', 'Neomake '), 'lint') != -1, 'lint maker gets completed' + bwipe + +Execute (neomake#cmd#complete_makers: completes space after Neomake!): + AssertEqual neomake#cmd#complete_makers('', 'Neomake!'), [' '] + +Execute (neomake#cmd#complete_makers: completes all (executable) makers, preferring filetype): + call g:NeomakeTestsSetPATH('') + new + noautocmd set ft=rust + + for m in ['cargo', 'cargotest', 'rustc', 'cabal', 'clippy', 'gradle'] + call g:NeomakeTestsCreateExe(m, []) + endfor + + " Neomake! completes ft makers (first), and project makers. + AssertEqual neomake#cmd#complete_makers('', 'Neomake! '), [ + \ 'cargo', 'cargotest', 'rustc', 'cabal', 'clippy', 'gradle'] + + call g:NeomakeTestsCreateExe('mvn', []) + AssertEqual neomake#cmd#complete_makers('', 'Neomake! '), [ + \ 'cargo', 'cargotest', 'rustc', 'cabal', 'clippy', 'gradle', 'mvn'] + + " Neomake completes ft makers. + AssertEqual neomake#cmd#complete_makers('', 'Neomake '), [ + \ 'cargo', 'cargotest', 'rustc'] + + " Neomake completes ft makers with project makers when called again. + AssertEqual neomake#cmd#complete_makers('', 'Neomake '), [ + \ 'cargo', 'cargotest', 'rustc', 'cabal', 'clippy', 'gradle', 'mvn'] + + " Neomake with ArgLead completes ft makers. + AssertEqual neomake#cmd#complete_makers('c', 'Neomake c'), [ + \ 'cargo', 'cargotest'] + + " Neomake with ArgLead completes ft makers with project makers when called again. + AssertEqual neomake#cmd#complete_makers('c', 'Neomake c'), [ + \ 'cargo', 'cargotest', 'cabal', 'clippy'] + + " Neomake completes global makers when no filetype makers match. + AssertEqual neomake#cmd#complete_makers('g', 'Neomake g'), [ + \ 'gradle'] + + " Neomake with ArgLead completes ft makers only again afterwards. + AssertEqual neomake#cmd#complete_makers('c', 'Neomake c'), [ + \ 'cargo', 'cargotest'] + bwipe + +Execute (neomake#cmd#complete_makers: filter by maker.name): + new + noautocmd set filetype=neomake_tests + + let b:neomake_neomake_tests_custom_maker = { + \ 'name': 'some_custom_name', + \ 'exe': 'true', + \ } + + let all = neomake#cmd#complete_makers('', 'Neomake ') + Assert index(all, 'some_custom_name') == -1 + " Includes maker.name (appended with non-breaking-space). + Assert index(all, 'custom (some_custom_name)') != -1 + + let filtered = neomake#cmd#complete_makers('some_', 'Neomake some_') + AssertEqual filtered, [] + + let filtered = neomake#cmd#complete_makers('cust', 'Neomake cust') + " Does not include description for single match. + AssertEqual filtered, ['custom'] + + " Does not append maker.name if it matches completely. + let filtered = neomake#cmd#complete_makers('custom', 'Neomake custom') + AssertEqual filtered, ['custom'] + + " Completes with partial annotation. + let filtered = neomake#cmd#complete_makers('custom (some_custom_', 'Neomake custom (some_custom_') + AssertEqual filtered, ['custom (some_custom_name)'] + " A second time (for s:last_completion adding project makers). + let filtered = neomake#cmd#complete_makers('custom (some_custom_', 'Neomake custom (some_custom_') + AssertEqual filtered, ['custom (some_custom_name)'] + + " Completes with full annotation. + let filtered = neomake#cmd#complete_makers('custom (some_custom_name)', 'Neomake custom (some_custom_name)') + AssertEqual filtered, ['custom (some_custom_name)'] + + + " Includes description with multiple matches. + let b:neomake_neomake_tests_custom2_maker = { + \ 'name': 'another_custom_name', + \ 'exe': 'true', + \ } + let filtered = neomake#cmd#complete_makers('', 'Neomake ') + AssertEqual filtered[:1], [ + \ 'custom (some_custom_name)', + \ 'custom2 (another_custom_name)', + \ ] + let filtered = neomake#cmd#complete_makers('cust', 'Neomake cust') + AssertEqual filtered, [ + \ 'custom', + \ 'custom2', + \ ] + let filtered = neomake#cmd#complete_makers('custom', 'Neomake custom') + AssertEqual filtered, [ + \ 'custom', + \ 'custom2', + \ ] + bwipe + +Execute (neomake#cmd#complete_jobs): + if NeomakeAsyncTestsSetup() + AssertEqual neomake#cmd#complete_jobs(), '' + let job_ids = [neomake#Sh('sleep 0.1')] + AssertEqual neomake#cmd#complete_jobs(), job_ids[0].': sh: sleep 0.1' + let job_ids += [neomake#Sh('sleep 0.11')] + AssertEqual neomake#cmd#complete_jobs(), printf( + \ "%d: sh: sleep 0.1\n%d: sh: sleep 0.11", job_ids[0], job_ids[1]) + NeomakeCancelJobs + NeomakeTestsWaitForFinishedJobs + endif diff --git a/bundle/neomake/tests/config.vader b/bundle/neomake/tests/config.vader new file mode 100644 index 000000000..ea26708a0 --- /dev/null +++ b/bundle/neomake/tests/config.vader @@ -0,0 +1,307 @@ +Include: include/setup.vader + +Execute (neomake#config#get: basic): + new + + let maker = {'foo': 'maker'} + let jobinfo = {'maker': maker, 'bufnr': bufnr('%')} + + AssertEqual neomake#config#get('foo', 'default'), 'default' + let g:neomake = {} + AssertEqual neomake#config#get('foo', 'default'), 'default' + let g:neomake = {'foo': 'global'} + AssertEqual neomake#config#get('foo', 'default'), 'global' + AssertEqual neomake#config#get('b:foo', 'default'), 'default' + let b:neomake = {} + AssertEqual neomake#config#get('foo', 'default'), 'global' + AssertEqual neomake#config#get('b:foo', 'default'), 'default' + AssertEqual neomake#config#get('b:foo', 'default', jobinfo), 'maker' + let b:neomake = {'foo': 'buffer'} + AssertEqual neomake#config#get('foo', 'default'), 'buffer' + AssertEqual neomake#config#get('b:foo', 'default'), 'buffer' + AssertEqual neomake#config#get('b:foo', 'default', jobinfo), 'buffer' + + AssertEqual neomake#config#get('foo', 'default', jobinfo), 'buffer' + new + AssertEqual neomake#config#get('foo', 'default', jobinfo), 'buffer' + wincmd p + unlet b:neomake + AssertEqual neomake#config#get('foo', 'default', jobinfo), 'global' + wincmd p + AssertEqual neomake#config#get('foo', 'default', jobinfo), 'global' + unlet g:neomake + AssertEqual neomake#config#get('foo', 'default', jobinfo), 'maker' + let jobinfo.maker = {} + AssertEqual neomake#config#get('foo', 'default', jobinfo), 'default' + bwipe + bwipe + +Execute (neomake#config#get/set support list for name): + new + call neomake#config#set_buffer(bufnr('%'), ['ft', 'javascript.jsx', 'eslint', 'exe'], 'my_eslint') + AssertEqual b:neomake, {'ft': {'javascript.jsx': {'eslint': {'exe': 'my_eslint'}}}} + + noautocmd set filetype=javascript.jsx + AssertEqual neomake#config#get('eslint.exe', 'default'), 'my_eslint' + AssertEqual neomake#config#get('eslint.exe', 'default', {}), 'default' + AssertNeomakeMessage "Using setting eslint.exe='my_eslint' from 'buffer' (prefix: ['ft', 'javascript.jsx'])." + + AssertEqual neomake#config#get(['eslint', 'exe'], 'default'), 'my_eslint' + AssertNeomakeMessage "Using setting eslint.exe='my_eslint' from 'buffer' (prefix: ['ft', 'javascript.jsx'])." + AssertEqual neomake#config#get(['ft', 'javascript.jsx', 'eslint', 'exe'], 'default', {'bufnr': bufnr('%')}), 'my_eslint' + AssertNeomakeMessage "Using setting ft.javascript|jsx.eslint.exe='my_eslint' from 'buffer'." + bwipe + +Execute (neomake#config#get with filetypes): + new + set filetype=myft + + AssertEqual neomake#config#get('foo', []), [] + let g:neomake = {'foo': ['maker1']} + AssertEqual neomake#config#get('foo', 'default'), ['maker1'] + + let g:neomake = {'ft': {'myft': {'foo': ['foo_setting']}}} + AssertEqual neomake#config#get('foo', 'default'), ['foo_setting'] + AssertEqual neomake#config#get('foo', 'default', {'ft': ''}), 'default' + AssertEqual neomake#config#get('foo', 'default', {'ft': 'myft'}), ['foo_setting'] + bwipe + +Execute (neomake#config#get with filetype and maker name): + new + set filetype=myft + + let maker = {'name': 'maker_name', 'exe': 'maker_exe'} + let g:neomake = {'ft': {'myft': {'maker_name': {'exe': 'custom_exe'}}}} + + AssertEqual neomake#config#get('exe', 'default', {'maker': maker}), 'maker_exe' + AssertEqual neomake#config#get('exe', 'default', {'ft': 'myft', 'maker': maker}), 'custom_exe' + bwipe + +Execute (neomake#config#get with filetype prefix in maker): + new + let maker = { + \ 'name': 'maker_name', + \ 'exe': 'maker_exe', + \ 'ft': {'myft': {'exe': 'maker_myft_exe'}}} + AssertEqual neomake#config#get('exe', 'default', {'maker': maker}), 'maker_exe' + AssertEqual neomake#config#get('exe', 'default', {'maker': maker, 'ft': 'myft'}), 'maker_myft_exe' + + let b:neomake = {'ft': {'myft': {'maker_name': {'exe': 'buffer_exe'}}}} + AssertEqual neomake#config#get('exe', 'default', {'maker': maker, 'ft': 'myft'}), 'maker_myft_exe' + AssertEqual neomake#config#get('exe', 'default', {'maker': maker, 'ft': 'myft', 'bufnr': bufnr('%')}), 'buffer_exe' + + AssertEqual neomake#config#get('exe', 'default', {'maker': maker, 'ft': 'myft', 'maker_only': 1}), 'maker_myft_exe' + AssertEqual neomake#config#get('exe', 'default', {'maker': maker, 'ft': 'myft', 'maker_only': 1, 'bufnr': bufnr('%')}), 'buffer_exe' + + AssertEqual neomake#config#get('maker_name.exe', 'default', {'maker': maker, 'ft': 'myft', 'maker_only': 1}), 'maker_myft_exe' + AssertEqual neomake#config#get('maker_name.exe', 'default', {'maker': maker, 'ft': 'myft', 'maker_only': 1, 'bufnr': bufnr('%')}), 'buffer_exe' + bwipe + +Execute (neomake#config#get with b: prefix, no default and bufnr context): + new + let b:neomake = {'foo': 'bar'} + AssertEqual neomake#config#get('b:foo'), 'bar' + unlet b:neomake + + let b:neomake = {'automake': {'ignore_filetypes': ['startify']}} + AssertEqual neomake#config#get('b:automake.ignore_filetypes'), ['startify'] + + let bufnr = bufnr('%') + new + AssertEqual neomake#config#get('b:automake.ignore_filetypes', [], + \ {'bufnr': bufnr}), ['startify'] + bwipe + bwipe + +Execute (neomake#config#set): + Save g:neomake + let config = neomake#config#set('foo', 'bar') + AssertEqual config, {'foo': 'bar'} + AssertEqual g:neomake, {'foo': 'bar'} + unlet g:neomake + + call neomake#config#set('automake.ignore_filetypes', ['startify']) + AssertEqual g:neomake, {'automake': {'ignore_filetypes': ['startify']}} + +Execute (neomake#config#set: warn about unused "neomake" key): + Save g:neomake + AssertThrows call neomake#config#set('b:neomake.foo.bar', ['1']) + AssertEqual g:vader_exception, 'Neomake: config: "neomake" is not necessary with new-style config settings ([''neomake'', ''foo'', ''bar'']).' + + AssertThrows call neomake#config#set('neomake.foo.bar', ['2']) + AssertEqual g:vader_exception, 'Neomake: config: "neomake" is not necessary with new-style config settings ([''neomake'', ''foo'', ''bar'']).' + + AssertEqual b:neomake, {} + AssertEqual g:neomake, {} + +Execute (neomake#config#set_buffer): + new + let bufnr = bufnr('%') + call neomake#config#set_buffer(bufnr, 'foo', 'bar') + AssertEqual b:neomake, {'foo': 'bar'} + unlet b:neomake + + call neomake#config#set_buffer(bufnr, 'automake.ignore_filetypes', ['startify']) + let expected = {'automake': {'ignore_filetypes': ['startify']}} + AssertEqual b:neomake, expected + b# + + AssertEqual getbufvar(bufnr, 'neomake'), expected + b# + bwipe! + +Execute (neomake#config#set with b: prefix): + new + call neomake#config#set('b:foo', 'bar') + AssertEqual b:neomake, {'foo': 'bar'} + call neomake#config#set('b:foo2', 'baz') + AssertEqual b:neomake, {'foo': 'bar', 'foo2': 'baz'} + unlet b:neomake + + call neomake#config#set('b:automake.ignore_filetypes', ['startify']) + AssertEqual b:neomake, {'automake': {'ignore_filetypes': ['startify']}} + bwipe! + +Execute (neomake#config#get handles Funcref variables): + new + let s:funcref = function('tr') + + call neomake#config#set('b:function', s:funcref) + AssertEqual neomake#config#get('b:function'), s:funcref + AssertEqual neomake#config#get_with_source('b:function'), [s:funcref, 'buffer'] + + " Handles bufnr context. + let bufnr = bufnr('%') + new + AssertEqual neomake#config#get('b:function', 'default', {}), 'default' + AssertEqual neomake#config#get('b:function', 'default', {'bufnr': bufnr}), s:funcref + bwipe + bwipe + +Execute (neomake#config#get does not return a partial for funcs): + new + let b:neomake = {} + function b:neomake.func() + endfunction + AssertEqual neomake#config#get('b:func'), get(b:neomake, 'func') + bwipe + +Execute (neomake#config#{un,}set_dict): + let foo = {} + call neomake#config#set_dict(foo, 'bar.baz', 42) + AssertEqual foo, {'bar': {'baz': 42}} + + call neomake#config#unset_dict(foo, 'bar.baz') + AssertEqual foo, {'bar': {}} + call neomake#config#unset_dict(foo, 'bar') + AssertEqual foo, {} + +Execute (neomake#config#get does not create empty dicts during lookup): + new + let b:neomake = {'foo': 'bar'} + AssertEqual neomake#config#get('automake.setting', 'default'), 'default' + AssertEqual b:neomake, {'foo': 'bar'} + bwipe + +Execute (neomake#config#get handles non-dicts on the way): + new + let b:neomake = {'foo': {'bar': 'baz'}} + AssertEqual neomake#config#get('foo.bar', 'default'), 'baz' + AssertEqual neomake#config#get('foo.bar.baz', 'default'), 'default' + bwipe + +Execute (old-style config is used for maker defaults): + let maker = {'name': 'mymaker', 'args': ['default']} + + new + let b:neomake = {'some': 'config'} + AssertEqual neomake#GetMaker(maker).args, ['default'] + let b:neomake_mymaker_args = ['args1'] + AssertEqual neomake#GetMaker(maker).args, ['args1'] + + noautocmd set filetype=myft + AssertEqual neomake#GetMaker(maker).args, ['args1'] + let b:neomake_myft_mymaker_args = ['args2'] + AssertEqual neomake#GetMaker(maker).args, ['args2'] + + " New-style config overrides it. + call neomake#config#set('b:mymaker.args', ['new-style']) + AssertEqual neomake#GetMaker(maker).args, ['new-style'] + bwipe + +Execute (Maker's cwd can be configured via config): + let maker = {'name': 'mymaker'} + + new + Assert !has_key(neomake#GetMaker(maker), 'cwd') + + let b:neomake_mymaker_cwd = 'custom_cwd1' + AssertEqual neomake#GetMaker(maker).cwd, 'custom_cwd1' + + call neomake#config#set('b:mymaker.cwd', 'custom_cwd2') + AssertEqual neomake#GetMaker(maker).cwd, 'custom_cwd2' + bwipe + +Execute (neomake#config#get does not allow to extend undefined default return value): + let d = neomake#config#get('undefined') + AssertEqual d, g:neomake#config#undefined + AssertThrows call extend(neomake#config#get('undefined'), {'foo': 'bar'}) + AssertEqual g:vader_exception, 'Vim(call):E741: Value is locked: extend() argument' + +Execute (neomake#config#get should not set g:neomake): + call neomake#config#get('foo') + Assert !exists('g:neomake') + +Execute (neomake#config#get has default for "maker_defaults"): + let maker_defaults = neomake#config#get('maker_defaults') + AssertEqual sort(keys(maker_defaults)), [ + \ 'buffer_output', 'output_stream', 'remove_invalid_entries'] + + call extend(maker_defaults, {'additional': 'value'}) + let maker_defaults = neomake#config#get('maker_defaults') + AssertEqual sort(keys(maker_defaults)), [ + \ 'buffer_output', 'output_stream', 'remove_invalid_entries'] + +Execute (neomake#config#get returns a reference): + new + let d = neomake#config#get('b:foo', {}) + let d.foo = 'bar' + Assert !exists('b:neomake') + + call neomake#config#set('b:foo', {'k': 'orig'}) + let d = neomake#config#get('b:foo') + AssertEqual d, {'k': 'orig'} + let d.k = 'changed' + AssertEqual neomake#config#get('b:foo'), {'k': 'changed'} + bwipe + +Execute (neomake#config#get returns a copy for defaults): + new + let d = neomake#config#get('b:foo', {}) + let d.foo = 'bar' + Assert !exists('b:neomake') + + call neomake#config#set('b:foo', {'k': 'orig'}) + let d = neomake#config#get('b:foo') + AssertEqual d, {'k': 'orig'} + let d.k = 'changed' + AssertEqual neomake#config#get('b:foo'), {'k': 'changed'} + bwipe + +Execute (neomake#config#get can ignore buffer): + new + call neomake#config#set('b:foo', 42) + + AssertEqual neomake#config#get('foo'), 42 + AssertEqual neomake#config#get('b:foo'), 42 + + new + " 0 refers to the alternate buffer for the current window. + AssertEqual neomake#config#get('foo', 'default', {'bufnr': 0}), 42 + AssertEqual neomake#config#get('b:foo', 'default', {'bufnr': 0}), 42 + + " '' ignores buffer. + AssertEqual neomake#config#get('foo', 'default', {'bufnr': ''}), 'default' + AssertEqual neomake#config#get('b:foo', 'default', {'bufnr': ''}), 'default' + bwipe + bwipe diff --git a/bundle/neomake/tests/current_error.vader b/bundle/neomake/tests/current_error.vader new file mode 100644 index 000000000..526345bc9 --- /dev/null +++ b/bundle/neomake/tests/current_error.vader @@ -0,0 +1,25 @@ +Include: include/setup.vader + +Execute (neomake#EchoCurrentError): + Save g:neomake_echo_current_error, g:neomake_virtualtext_current_error + + new + normal! o + + CallNeomake 1, [g:entry_maker] + AssertEqual neomake#GetCurrentErrorMsg(), '' + AssertEqual neomake#utils#redir('call neomake#EchoCurrentError(1)'), '' + + normal k + let msg = 'entry_maker: error (E)' + AssertEqual neomake#GetCurrentErrorMsg(), msg + AssertEqual neomake#utils#redir('call neomake#EchoCurrentError(1)'), '' + + let g:neomake_echo_current_error = 1 + AssertEqual neomake#utils#redir('call neomake#EchoCurrentError(1)'), "\n".msg + " Not displayed if unchanged. + AssertEqual neomake#utils#redir('call neomake#EchoCurrentError()'), '' + + normal j + AssertEqual neomake#utils#redir('call neomake#EchoCurrentError()'), '' + bwipe! diff --git a/bundle/neomake/tests/customqf.vader b/bundle/neomake/tests/customqf.vader new file mode 100644 index 000000000..e5d20356c --- /dev/null +++ b/bundle/neomake/tests/customqf.vader @@ -0,0 +1,811 @@ +Include: include/setup.vader + +Execute (Displays custom formatted quickfix buffer): + call neomake#quickfix#enable(1) + try + new + let bufnr = bufnr('%') + noautocmd set filetype=python + Assert !hlexists('neomakePythonLint'), 'neomakePythonLint does not exist' + + call setloclist(0, [{ + \ 'lnum': 1, + \ 'bufnr': bufnr, + \ 'type': 'E', + \ 'text': 'E123 Line 1 nmcfg:{"name": "python", "short": "Alph"}', + \ }, + \ { + \ 'lnum': 2, + \ 'col': 5, + \ 'bufnr': bufnr, + \ 'type': '', + \ 'text': 'Line 2', + \ }, + \ { + \ 'bufnr': bufnr, + \ 'type': 'E', + \ 'text': 'No line', + \ }, + \ { + \ 'lnum': 4, + \ 'bufnr': bufnr, + \ 'type': 'W', + \ 'text': 'Line 4 (warning)', + \ }, + \ ]) + + lopen + let loclist_bufnr = bufnr('%') + AssertEqual b:current_syntax, 'neomake_qf' + Assert hlexists('neomakePythonLint'), 'neomakePythonLint does exists' + + AssertEqual getline(1, '$'), [ + \ 'Alph 1:- E123 Line 1', + \ 'Alph 2:5 Line 2', + \ 'Alph No line', + \ 'Alph 4:- Line 4 (warning)', + \ ] + + normal! 0 + " :normal! ignores autocmd's here? + doautocmd CursorMoved + AssertEqual expand(''), 'E123' + AssertEqual getpos('.')[1:2], [1, 10] + " Error code highlighted via syntax. + AssertEqual map(synstack(1, 10), 'synIDattr(v:val,"name")'), ['neomakePythonLint'] + + AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.loclist_bufnr.'.', 3 + AssertNeomakeMessage 'Placing sign: sign place 5001 line=2 name=neomake_file_err buffer='.loclist_bufnr.'.', 3 + AssertNeomakeMessage 'Placing sign: sign place 5002 line=4 name=neomake_file_warn buffer='.loclist_bufnr.'.', 3 + AssertEqual neomake#signs#by_lnum(loclist_bufnr), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_err']], + \ '4': [[5002, 'neomake_file_warn']], + \ } + if exists('*matchaddpos') + AssertEqual map(filter(getmatches(), "v:val.group == 'neomakeCursorListNr'"), 'v:val.pos1'), [[1, 6, 4]] + else + AssertEqual map(filter(getmatches(), "v:val.group == 'neomakeCursorListNr'"), 'v:val.pattern'), ['\%1c\%6c.\{4}'] + endif + + wincmd p + + " Test changing the location list while it's open + call setloclist(0, [{ + \ 'lnum': 1, + \ 'bufnr': 1, + \ 'text': 'E42 Line 1 nmcfg:{"name": "Beta", "short": "Beta"}', + \ }, + \ { + \ 'lnum': 2, + \ 'col': 5, + \ 'bufnr': 1, + \ 'text': 'Line 2', + \ }, + \ { + \ 'lnum': 3, + \ 'bufnr': 1, + \ 'text': 'Line 3 nmcfg:{"name": "Gamma", "short": "Gamm"}', + \ }, + \ { + \ 'lnum': 4, + \ 'col': 5, + \ 'bufnr': 1, + \ 'text': 'Line 4', + \ }]) + " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_err, lnum=1.', 3 + " AssertNeomakeMessage 'Reusing sign: id=5001, type=neomake_file_err, lnum=2.', 3 + AssertNeomakeMessage 'Upgrading sign for lnum=4: sign place 5002 name=neomake_file_err buffer='.loclist_bufnr.'.', 3 + AssertNeomakeMessage 'Reused 2 signs.', 3 + AssertNeomakeMessage 'Placing sign: sign place 5003 line=3 name=neomake_file_err buffer='.loclist_bufnr.'.', 3 + + wincmd p + + Assert hlexists('neomakePythonLint'), 'neomakePythonLint does exists' + if exists('*matchaddpos') + AssertEqual map(filter(getmatches(), "v:val.group == 'neomakeCursorListNr'"), 'v:val.pos1'), [[1, 6, 4]] + else + AssertEqual map(filter(getmatches(), "v:val.group == 'neomakeCursorListNr'"), 'v:val.pattern'), ['\%1c\%6c.\{4}'] + endif + + " Does not highlight E42 (no "python" maker/syntax in new list). + AssertEqual map(synstack(1, 10), 'synIDattr(v:val,"name")'), [] + + AssertEqual getline(1, '$'), [ + \ 'Beta 1:- E42 Line 1', + \ 'Beta 2:5 Line 2', + \ 'Gamm 3:- Line 3', + \ 'Gamm 4:5 Line 4'] + + normal! G0 + doautocmd CursorMoved + AssertEqual expand(''), 'Line' + AssertEqual getpos('.')[1:2], [4, 10] + + " Highlights E42 (with "python" maker/syntax in new list). + call setloclist(0, [{ + \ 'lnum': 1, + \ 'bufnr': 1, + \ 'text': 'E42 Line 1 nmcfg:{"name": "python", "short": "Beta"}', + \ }]) + AssertEqual map(synstack(1, 10), 'synIDattr(v:val,"name")'), ['neomakePythonLint'] + + close + finally + Assert exists('#neomake_qf'), '#neomake_qf exists' + call neomake#quickfix#disable() + Assert !exists('#neomake_qf'), '#neomake_qf does not exist' + bwipe + endtry + +Execute (Sets quickfix title (location list, command maker)): + call neomake#quickfix#enable(1) + try + new + set ft=neomake_tests + let bufnr = bufnr('%') + file custom_file + + let maker1 = copy(g:error_maker) + let maker1.short_name = 'errmkr' + let maker1.serialize = 1 + function! maker1.postprocess(entry) + if has('patch-7.4.2200') + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist" + AssertEqual getloclist(0, {'title': 1}).title, + \ 'neomake_test_init' + else + Assert getloclist(0, {'title': 1}).title + \ =~# '\V:\?Neomake[file]: custom_file (error-maker..., maker2?)' + endif + endif + let a:entry.bufnr = bufnr('%') + let a:entry.lnum = 1 + return a:entry + endfunction + + let maker2 = copy(g:error_maker) + let maker2.name = 'maker2' + function! maker2.postprocess(entry) + if has('patch-7.4.2200') + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist" + AssertEqual getloclist(0, {'title': 1}).title, + \ 'Neomake[file]: custom_file (error-maker..., maker2?)' + else + Assert getloclist(0, {'title': 1}).title + \ =~# '\V:\?Neomake[file]: custom_file (error-maker..., maker2?)' + endif + endif + return a:entry + endfunction + + CallNeomake 1, [maker1, maker2] + + if has('patch-7.4.2200') + AssertEqual getloclist(0, {'title': 1}).title, + \ 'Neomake[file]: custom_file (error-maker(1), maker2(1))' + endif + + " Location list entry contains marker. + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ 'error nmcfg:{''short'': ''errmkr'', ''name'': ''error-maker''}', + \ 'error nmcfg:{''short'': ''make'', ''name'': ''maker2''}'] + + lopen + AssertEqual w:quickfix_title, 'Neomake[file]: custom_file (error-maker(1), maker2(1))' + normal! G0 + doautocmd CursorMoved + AssertEqual expand(''), 'error' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (Sets quickfix title (location list, get_list_entries)): + call neomake#quickfix#enable(1) + try + new + set ft=neomake_tests + let bufnr = bufnr('%') + file custom_file + + let maker1 = copy(g:error_maker) + let maker1.short_name = 'errmkr' + function maker1.get_list_entries(...) + if has('patch-7.4.2200') + AssertEqual getloclist(0, {'title': 1}).title, 'neomake_test_init' + endif + return [{'lnum': 1, 'bufnr': bufnr('%'), 'text': 'error_msg_1'}] + endfunction + + let maker2 = {} + let maker2.name = 'maker2' + function maker2.get_list_entries(...) + if has('patch-7.4.2200') + AssertEqual getloclist(0, {'title': 1}).title, 'Neomake[file]: custom_file (error-maker..., maker2?)' + endif + return [{'lnum': 2, 'bufnr': bufnr('%'), 'text': 'error_msg_2'}] + endfunction + + CallNeomake 1, [maker1, maker2] + if has('patch-7.4.2200') + AssertEqual getloclist(0, {'title': 1}).title, 'Neomake[file]: custom_file (error-maker(1), maker2(1))' + endif + + " Location list entry contains marker. + AssertEqualQf [getloclist(0)[0]], [ + \ {'lnum': 1, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', + \ 'text': 'error_msg_1 nmcfg:{''short'': ''errmkr'', ''name'': ''error-maker''}'}] + + lopen + + " Title is always handled via FileType autocmd. + AssertEqual w:quickfix_title, 'Neomake[file]: custom_file (error-maker(1), maker2(1))' + + normal! G0 + doautocmd CursorMoved + AssertEqual expand(''), 'error_msg_2' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (Handles interleaving maker output and buffer names (quickfix)): + if !neomake#has_async_support() + NeomakeTestsSkip 'no async support.' + return + endif + + call neomake#quickfix#enable(1) + try + new + set ft=neomake_tests + let bufnr = bufnr('%') + + let s:flagfile = tempname() + let maker1 = NeomakeTestsCommandMaker('maker1', 'echo file1: maker1_1; ' + \ .'while ! [ -s '.fnameescape(s:flagfile).' ]; do sleep 0.01; done; ' + \ .'echo file1: maker1_2') + function maker1.process_output(...) + if filereadable(s:flagfile) + return [{'text': 'maker1_2', 'lnum': 2, 'bufnr': bufnr('%')}] + endif + call writefile([], s:flagfile) + return [{'text': 'maker1_1', 'lnum': 1, 'bufnr': bufnr('%')}] + endfunction + + if neomake#has_async_support() + let maker2 = NeomakeTestsCommandMaker('maker2', + \ 'while ! [ -e '.fnameescape(s:flagfile).' ]; do sleep 0.01; done; ' + \ .'echo file2: maker2_1') + function maker2.process_output(...) + call writefile([''], s:flagfile) + return [ + \ {'text': 'maker2_1', 'lnum': 1, 'bufnr': bufnr('%')}, + \ {'text': 'maker2_2', 'lnum': 2, 'filename': 'very_long_name_for_unlisted_buffer_via_filename_entry'}] + endfunction + else + let maker2 = NeomakeTestsCommandMaker('maker2', 'true') + endif + let maker1.errorformat = '%f: %m' + let maker1.buffer_output = 0 + let maker2.errorformat = '%f: %m' + CallNeomake {'enabled_makers': [maker1, maker2], 'file_mode': 0} + + let unlisted_bufnr = bufnr('very_long_name_for_unlisted_buffer_via_filename_entry') + + " Quickfix list entry contains marker. + let qflist = getqflist() + AssertEqual map(copy(qflist), '[v:val.bufnr, v:val.text]'), [ + \ [bufnr, 'maker1_1 nmcfg:{''short'': ''make'', ''name'': ''maker1''}'], + \ [bufnr, 'maker2_1 nmcfg:{''short'': ''make'', ''name'': ''maker2''}'], + \ [unlisted_bufnr, 'maker2_2'], + \ [bufnr, 'maker1_2 nmcfg:{''short'': ''make'', ''name'': ''maker1''}']] + + AssertEqual neomake#GetCurrentErrorMsg(), 'maker1: maker1_1 (W)' + + copen + + if has('patch-7.4.2200') + " Set according to finished_jobs. + AssertEqual w:quickfix_title, 'Neomake[project]: maker2(2), maker1(2)' + else + " Set via quickfix filetype, according to order of entries. + AssertEqual w:quickfix_title, 'Neomake[project]: maker1(2), maker2(2)' + endif + + doautocmd CursorMoved + " Empty bufname gets transformed to buf:X. + AssertEqual expand(''), '[buf:'.bufnr.']' + normal! W + AssertEqual expand(''), 'maker1_1' + normal! j0 + doautocmd CursorMoved + " Same buffer as previous entry: name omitted. + AssertEqual expand(''), 'maker2_1' + normal! j + AssertEqual expand(''), '[very_long_name…]' + normal! j + AssertEqual expand(''), '[buf:'.bufnr.']' + cclose + bwipe + exe unlisted_bufnr 'bwipe' + finally + call neomake#quickfix#disable() + endtry + +Execute (Handles empty entries): + let maker = {} + function maker.get_list_entries(...) + return [] + endfunction + CallNeomake {'enabled_makers': [maker]} + +Execute (Does not change current error text (command maker)): + call neomake#quickfix#enable(1) + try + new + CallNeomake 1, [g:error_maker] + AssertEqual neomake#GetCurrentErrorMsg(), 'error-maker: error (E)' + lopen + AssertEqual getline(1), 'erro 1:- error' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (Does not change current error text (entries maker)): + call neomake#quickfix#enable(1) + try + new + CallNeomake 1, [g:entry_maker] + AssertEqual neomake#GetCurrentErrorMsg(), 'entry_maker: error (E)' + lopen + AssertEqual getline(1), 'entr 1:- error' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (Disable custom formatted quickfix buffer): + call neomake#quickfix#enable(1) + call neomake#quickfix#disable() + call setloclist(0, [{ + \ 'lnum': 1, + \ 'bufnr': 1, + \ 'text': 'Line 1', + \ }, + \ { + \ 'lnum': 2, + \ 'col': 5, + \ 'bufnr': 1, + \ 'text': 'Line 2', + \ }]) + + lopen + + AssertEqual getline(1, '$'), + \ ['|1| Line 1', '|2 col 5| Line 2'] + + normal! 0 + doautocmd CursorMoved + AssertEqual expand(''), '|1|' + AssertEqual getpos('.')[1:2], [1, 1] + close + +Execute (neomake#quickfix#FormatQuickfix handles entries with config in text): + call neomake#quickfix#enable(1) + try + new + call setloclist(0, [{ + \ 'text': 'Text with marker nmcfg:{"name": "a", "short": "a"} nmcfg:{"name": "b", "short": "b"}', + \}]) + lopen + AssertEqual getline(1), 'b Text with marker nmcfg:{"name": "a", "short": "a"}' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (neomake#quickfix#FormatQuickfix handles entries without cfg (ending with curly brace)): + call neomake#quickfix#enable(1) + try + new + call setloclist(0, [ + \ {'text': 'text1 nmcfg:{"name": "maker", "short": "makr"}'}, + \ {'text': " 'something': 'X'}"} + \ ]) + lopen + AssertEqual getline(1), "makr text1" + AssertEqual getline(2), "makr 'something': 'X'}" + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (neomake#quickfix#FormatQuickfix handles entries without text): + call neomake#quickfix#enable(1) + try + new + call setloclist(0, [{ + \ 'text': ' nmcfg:{"name": "b", "short": "b"}', + \}]) + lopen + AssertEqual getline(1), 'b ' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (neomake#quickfix#FormatQuickfix handles entries without bufnr)): + call neomake#quickfix#enable(1) + try + new + file test_bufname + call setloclist(0, [ + \ {'text': 'msg1 nmcfg:{"name": "maker", "short": "makr"}', 'bufnr': 0}, + \ {'text': 'msg2', 'bufnr': bufnr('%')}, + \ {'text': 'msg3', 'bufnr': 0}, + \ {'text': 'msg4', 'bufnr': bufnr('%')}, + \ ]) + lopen + AssertEqual getline(1), "makr msg1" + AssertEqual getline(2), "makr msg2" + AssertEqual getline(3), "makr msg3" + AssertEqual getline(4), "makr msg4" + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (neomake#quickfix#FormatQuickfix logs exception from nmcfg)): + call neomake#quickfix#enable(1) + try + new + call setloclist(0, [{'text': 'text1 nmcfg:{undefined}'}]) + lopen + AssertEqual getline(1), '???? text1 nmcfg:{undefined}' + AssertNeomakeMessage 'Error when evaluating nmcfg ({undefined}): Vim(let):E121: Undefined variable: undefined.', 0 + AssertNeomakeMessage '\v\(in function neomake#quickfix#FormatQuickfix, line \d+\)', 3 + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (neomake#quickfix#FormatQuickfix reuses signs): + call neomake#quickfix#enable(1) + try + new + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'Text with marker nmcfg:{"name": "b", "short": "b"}', + \}]) + lopen + let loclist_bufnr = bufnr('%') + AssertEqual getline(1), 'b 1:- Text with marker' + AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.loclist_bufnr.'.', 3 + + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'Text with marker nmcfg:{"name": "b", "short": "b"}', + \}]) + " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_err, lnum=1.', 3, {'bufnr': loclist_bufnr} + AssertNeomakeMessage 'Reused 1 signs.', 3 + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (custom qf gets disabled with manual setloclist()): + call neomake#quickfix#enable(1) + try + new + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'Text with marker nmcfg:{"name": "b", "short": "b"}', + \}]) + lopen + let ll_bufnr = bufnr('%') + AssertEqual getline(1), 'b 1:- Text with marker' + doautocmd CursorMoved + + AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.ll_bufnr.'.' + + Assert !empty(filter(getmatches(), "v:val.group == 'neomakeMakerName'")), 'There are existing matches.' + AssertEqual b:current_syntax, 'neomake_qf' + + let s:au_called = [] + augroup neomake_tests + autocmd Syntax * call add(s:au_called, expand('')) + augroup END + + call setloclist(0, [{'text': 'something custom'}]) + AssertEqual s:au_called, ['qf'] + + AssertNeomakeMessage 'Resetting custom qf for non-Neomake change.', 3 + AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': ll_bufnr} + AssertEqual neomake#signs#by_lnum(ll_bufnr), {} + let matches = filter(getmatches(), "v:val.group == 'neomakeMakerName'") + Assert empty(matches), printf('Found unexpected matches: %s', string(matches)) + AssertEqual b:current_syntax, 'qf' + + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'Text with marker nmcfg:{"name": "b", "short": "b"}', + \}]) + Assert !empty(filter(getmatches(), "v:val.group == 'neomakeMakerName'")), 'There are existing matches again.' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (disabling it restores initial lines (in qf window)): + new + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'Text with marker nmcfg:{"name": "b", "short": "b"}', + \}]) + lopen + AssertEqual getline(1), '|1| Text with marker nmcfg:{"name": "b", "short": "b"}' + call neomake#quickfix#enable(1) + try + AssertEqual getline(1), 'b 1:- Text with marker' + call neomake#quickfix#disable() + AssertEqual getline(1), '|1| Text with marker nmcfg:{"name": "b", "short": "b"}' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (enabling does not touch existing lists (in another window)): + new + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'Text with marker nmcfg:{"name": "b", "short": "b"}', + \}]) + lopen + AssertEqual getline(1), '|1| Text with marker nmcfg:{"name": "b", "short": "b"}' + wincmd p + call neomake#quickfix#enable(1) + try + wincmd p + AssertEqual getline(1), '|1| Text with marker nmcfg:{"name": "b", "short": "b"}' + call neomake#quickfix#disable() + AssertEqual getline(1), '|1| Text with marker nmcfg:{"name": "b", "short": "b"}' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (enabling does not touch existing lists (in another window)): + new + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'Text with marker nmcfg:{"name": "b", "short": "b"}', + \}]) + lopen + AssertEqual getline(1), '|1| Text with marker nmcfg:{"name": "b", "short": "b"}' + call neomake#quickfix#enable(1) + try + AssertEqual getline(1), 'b 1:- Text with marker' + wincmd p + call neomake#quickfix#disable() + wincmd p + AssertEqual getline(1), 'b 1:- Text with marker' + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (Enables customqf on VimEnter): + if exists('#neomake_qf') + au! neomake_qf + endif + try + call neomake#quickfix#enable() + Assert exists('#neomake_qf#VimEnter') + call setloclist(0, [{ + \ 'lnum': 1, + \ 'bufnr': 1, + \ 'text': 'Line 1 nmcfg:{"name": "python", "short": "Alph"}', + \ }]) + lopen + AssertEqual b:current_syntax, 'qf' + doautocmd VimEnter + AssertEqual b:current_syntax, 'neomake_qf' + lclose + finally + call neomake#quickfix#disable() + endtry + +Execute (Does not use quickfix list with empty location list): + call neomake#quickfix#enable(1) + try + call setqflist([{ + \ 'text': 'Line 1 nmcfg:{"name": "python", "short": "Alph"}', + \ 'lnum': 1, + \ }]) + lopen + + if has('patch-7.4.2200') + Assert !exists('b:neomake_qf') + AssertEqual b:current_syntax, 'qf' + else + " XXX: needs list refactoring to fix this properly. + Assert exists('b:neomake_qf') + AssertEqual b:current_syntax, 'neomake_qf' + endif + + lclose + + copen + Assert exists('b:neomake_qf') + AssertEqual b:current_syntax, 'neomake_qf' + cclose + finally + call neomake#quickfix#disable() + endtry + +Execute (Formats quickfix list if opened already): + Save g:neomake_open_list + let g:neomake_open_list = 2 + + call neomake#quickfix#enable(1) + try + new + + let maker1 = copy(g:error_maker) + let maker1.short_name = 'mkr1' + let maker1.serialize = 1 " For predictable order. + + let maker2 = copy(g:error_maker) + let maker2.name = 'mkr2' + + CallNeomake 1, [maker1, maker2] + + wincmd j + AssertEqual getline('.'), 'mkr1 1:- error' + doautocmd CursorMoved + AssertEqual expand(''), 'error' + + normal! j + AssertEqual getline('.'), 'mkr2 1:- error' + AssertEqual expand(''), 'error' + + AssertNeomakeMessage 'Handling location list: executing lwindow.', 3 + AssertNeomakeMessage 'list window has been opened (old count: 2, new count: 3, height: 1).', 3 + AssertNeomakeMessage 'Handling location list: executing lwindow.', 3 + AssertNeomakeMessage 'Resizing existing quickfix window: 3resize 2.', 3 + + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (custom qf with new window / buffer): + call neomake#quickfix#enable(1) + try + new + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'Text with marker nmcfg:{"name": "b", "short": "b"}', + \}]) + lopen + AssertEqual map(filter(getmatches(), "v:val.group == 'neomakeMakerName'"), 'v:val.pattern'), ['.*\%<2c'] + if exists('*matchaddpos') + AssertEqual map(filter(getmatches(), "v:val.group == 'neomakeCursorListNr'"), 'v:val.pos1'), [[1, 3, 4]] + else + AssertEqual map(filter(getmatches(), "v:val.group == 'neomakeCursorListNr'"), 'v:val.pattern'), ['\%1c\%3c.\{4}'] + endif + AssertEqual b:current_syntax, 'neomake_qf' + + tab split + if exists('##WinNew') + Assert !empty(filter(getmatches(), "v:val.group == 'neomakeMakerName'")), 'Expected matches (2).' + AssertEqual b:current_syntax, 'neomake_qf' + endif + doautocmd CursorMoved + if exists('##WinNew') + Assert !empty(filter(getmatches(), "v:val.group == 'neomakeMakerName'")), 'Expected matches (3).' + endif + Assert !empty(filter(getmatches(), "v:val.group == 'neomakeCursorListNr'")), 'Expected matches (3).' + AssertEqual b:current_syntax, 'neomake_qf' + + enew + let matches = filter(getmatches(), "v:val.group == 'neomakeMakerName'") + Assert empty(matches), printf('Found unexpected matches: %s', string(matches)) + bwipe + + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (customqf allows for custom syntax): + let s:syn_au_called = 0 + augroup neomake_tests + au Syntax * let s:syn_au_called = 1 + au Syntax * syn match MyError /error/ containedin=ALL + augroup END + + call neomake#quickfix#enable(1) + try + new + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'E123 error nmcfg:{"name": "python", "short": "py"}', + \}]) + lopen + + AssertEqual getline('.'), 'py 1:- E123 error' + AssertEqual map(synstack(1, 8), 'synIDattr(v:val,"name")'), ['neomakePythonLint'] + + " :normal! ignores autocmd's here? + doautocmd CursorMoved + AssertEqual expand(''), 'E123' + normal! w + AssertEqual expand(''), 'error' + AssertEqual getpos('.')[1:2], [1, 13] + AssertEqual map(synstack(1, 13), 'synIDattr(v:val,"name")'), ['MyError'] + AssertEqual s:syn_au_called, 1 + + lclose + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (customqf gets formatted with disabled syntax): + let s:syn_au_called = 0 + augroup neomake_tests + au Syntax * let s:syn_au_called = 1 + augroup END + + call neomake#quickfix#enable(1) + syntax off + try + new + let syn_before = neomake#utils#redir('syn') + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'E123 error nmcfg:{"name": "python", "short": "py"}', + \}]) + lopen + + AssertEqual getline('.'), 'py 1:- E123 error' + AssertEqual map(synstack(1, 8), 'synIDattr(v:val,"name")'), [] + + " :normal! ignores autocmd's here? + doautocmd CursorMoved + AssertEqual expand(''), 'E123' + normal! w + AssertEqual expand(''), 'error' + AssertEqual getpos('.')[1:2], [1, 13] + AssertEqual map(synstack(1, 13), 'synIDattr(v:val,"name")'), [] + AssertEqual s:syn_au_called, 0 + + AssertEqual syn_before, neomake#utils#redir('syn') + + lclose + bwipe + finally + call neomake#quickfix#disable() + syntax on + endtry diff --git a/bundle/neomake/tests/cwd.vader b/bundle/neomake/tests/cwd.vader new file mode 100644 index 000000000..54c903ccc --- /dev/null +++ b/bundle/neomake/tests/cwd.vader @@ -0,0 +1,520 @@ +Include: include/setup.vader + +Execute (neomake#Make handles invalid cwd): + let maker = { + \ 'name': 'custom_maker', + \ 'exe': 'true', + \ 'cwd': '/doesnotexist', + \ } + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage "custom_maker: could not change to maker's cwd (/doesnotexist): Vim(cd):E344: Can't find directory \"/doesnotexist\" in cdpath.", 0 + +Execute (neomake#Make handles invalid cwd (serialized)): + let maker = { + \ 'name': 'custom_maker', + \ 'exe': 'true', + \ 'cwd': '/doesnotexist', + \ 'serialize': 1, + \ } + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage "custom_maker: could not change to maker's cwd (/doesnotexist): Vim(cd):E344: Can't find directory \"/doesnotexist\" in cdpath.", 0 + +Execute (cwd gets compared with trailing slash removed): + let cwd = getcwd() + let maker1 = {'name': 'maker1', 'exe': 'true', 'cwd': cwd.'/', 'append_file': 0} + let maker2 = {'name': 'maker2', 'exe': 'true', 'cwd': cwd, 'append_file': 0} + + new + call neomake#Make(1, [maker1]) + lcd build + call neomake#Make(1, [maker2]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'cwd: '.cwd.'.' + AssertNeomakeMessage 'cwd: '.cwd.' (changed).' + bwipe + +Execute (tcd is handled properly): + if exists(':tcd') != 2 + NeomakeTestsSkip 'no :tcd' + else + let maker = NeomakeTestsCommandMaker('sleep-maker', 'sleep .01') + for d in ['build/path1', 'build/path2'] + if !isdirectory(d) + call mkdir(d, 'p') + endif + endfor + try + tabnew + let tab1 = tabpagenr() + let tab1_bufnr = bufnr('%') + tcd build/path1 + let dir1 = getcwd() + + tabnew + tcd ../../build/path2 + let tab2 = tabpagenr() + let dir2 = getcwd() + + call neomake#Make(1, [maker]) + + exe 'tabnext' tab1 + AssertEqual dir1, getcwd() + call neomake#Make(1, [maker]) + + exe 'tabnext' tab2 + AssertEqual dir2, getcwd() + + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Postponing final location list handling (in another window).' + AssertNeomakeMessage 'Queuing action handle_locqf_list_for_finished_jobs for WinEnter.', 3 + + exe 'tabnext' tab1 + AssertNeomakeMessage 'Cleaning make info.', 3 + AssertNeomakeMessage 'action queue: processed 1 items.', 3, {'bufnr': tab1_bufnr} + NeomakeTestsWaitForRemovedJobs + finally + if exists('tab2') + bwipe + endif + if exists('tab1') + bwipe + endif + endtry + endif + +Execute (tempfile with pwd): + let maker = NeomakeTestsCommandMaker('pwd', 'pwd; printf') + let maker.cwd = '%:p:h' + let maker.errorformat = '%m' + let maker.append_file = 1 + new + let b:neomake_tempfile_enabled = 1 + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage 'Processing 2 lines of output.', 3 + AssertNeomakeMessage '\v^Removing temporary file: "(.*)".$' + let tempfile_name = g:neomake_test_matchlist[1] + + " NOTE: getcwd() resolves symlinks. + AssertEqual map(getloclist(0), 'resolve(v:val.text)'), [getcwd(), tempfile_name] + bwipe + +Execute (cwd handles fugitive buffer): + NeomakeTestsLoadPlugin 'vim-fugitive' + let maker = NeomakeTestsCommandMaker('pwd', 'pwd; ls') + let maker.cwd = '%:p:h' + let maker.errorformat = '%m' + let maker.append_file = 1 + new + edit autoload/neomake/debug.vim + let expected_cwd = fnamemodify(bufname('%'), ':p:h') + let orig_abs_bufname = expand('%:p') + Gedit + Assert bufname('%') =~# '^fugitive://', 'Unexpected bufname: '.bufname('%') + + let b:neomake_tempfile_enabled = 1 + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage '\v^Using tempfile for unreadable buffer: "(.*)"', 3 + let tempfile_name = g:neomake_test_matchlist[1] + " Temporary file gets created in maker's cwd, and displays full name. + AssertEqual fnamemodify(tempfile_name, ':h'), fnamemodify(orig_abs_bufname, ':h') + + AssertNeomakeMessage printf('cwd: %s/autoload/neomake (changed).', getcwd()), 3 + AssertNeomakeMessage printf('Removing temporary file: "%s".', fnamemodify(tempfile_name, ':p')) + + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ expected_cwd, fnamemodify(tempfile_name, ':t')] + bwipe + bwipe autoload/neomake/debug.vim + if exists('*VimFtpluginUndo') + delfunction VimFtpluginUndo + endif + +Execute (cwd gets expanded correctly: relative and in another buffer): + if NeomakeAsyncTestsSetup() + let maker = NeomakeTestsCommandMaker('pwd', 'pwd; ls') + let maker.cwd = '%:.:h' + let maker.errorformat = '%m' + let maker.append_file = 1 + new + edit tests/fixtures/errors.py + let b:neomake_serialize = 1 + let expected_cwd = expand('%:p:h') + + let jobinfo = neomake#Make(1, [g:sleep_maker, maker])[0] + new + let current_bufnr = bufnr('%') + + lcd build + NeomakeTestsWaitForFinishedJobs + bwipe + + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ 'slept', expected_cwd, 'errors.py'] + bwipe + AssertNeomakeMessage 'Skipped pending job output for another buffer (current='.current_bufnr.').', 3 + endif + +Execute (cwd per maker and serialize via dict): + let maker1 = {'name': 'maker1', 'exe': 'pwd', 'cwd': tempname()} + let maker2 = {'name': 'maker2', 'exe': 'pwd', 'cwd': tempname()} + call mkdir(maker1.cwd) + call mkdir(maker2.cwd) + + call neomake#Make({ + \ 'file_mode': 0, + \ 'enabled_makers': [maker1, maker2], + \ 'serialize': 1}) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getqflist(), 'v:val.text'), [maker1.cwd, maker2.cwd] + +Execute (get_list_entries: filename with cwd (non-existing file)): + let tempdir = tempname() + let slash = neomake#utils#Slash() + let subdir = tempdir . slash . 'project' . slash . 'sub' + call mkdir(subdir, 'p', 0700) + + new + file project/sub/file_in_subdir_1 + let bufnr = bufnr('%') + + let maker = {'cwd': '%:p:h'} + function! maker.get_list_entries(...) abort dict + return [{ + \ 'filename': 'file_in_subdir_1', + \ 'lnum': 23, + \ 'col': 42, + \ 'text': 'error message', + \ 'type': 'E', + \ }] + endfunction + + " uses unlisted buffer if file does not exist + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqualQf getloclist(0), [{ + \ 'lnum': 23, + \ 'bufnr': bufnr + 1, + \ 'col': 42, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'error message'}] + let unlisted_bufnr = bufnr+1 + let bwipe_buffers = [unlisted_bufnr] + AssertEqual bufname(unlisted_bufnr), 'file_in_subdir_1' + Assert !buflisted(unlisted_bufnr), 'buffer is unlisted (1)' + + " uses unlisted buffer if file does not exist (cwd matches) + let orig_cwd = getcwd() + exe 'lcd' tempdir + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + if has('patch-7.4.2017') + let expected_bufnr = unlisted_bufnr + else + let expected_bufnr = unlisted_bufnr + 1 + let bwipe_buffers += [expected_bufnr] + endif + AssertEqualQf getloclist(0), [{ + \ 'lnum': 23, + \ 'bufnr': expected_bufnr, + \ 'col': 42, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'error message'}] + AssertEqual bufname(unlisted_bufnr), orig_cwd.'/file_in_subdir_1' + Assert !buflisted(unlisted_bufnr), 'buffer is unlisted (2)' + + for b in bwipe_buffers + exe 'bwipe' b + endfor + bwipe + +Execute (get_list_entries: filename with cwd): + let tempdir = tempname() + let slash = neomake#utils#Slash() + let subdir = tempdir . slash . 'project' . slash . 'sub' + call mkdir(subdir, 'p', 0700) + + let maker = {'cwd': '%:p:h'} + function! maker.get_list_entries(...) abort dict + return [{ + \ 'filename': 'file_in_subdir_2', + \ 'lnum': 23, + \ 'col': 42, + \ 'text': 'error message', + \ 'type': 'E', + \ }] + endfunction + + new + let bufnr = bufnr('%') + exe 'lcd' tempdir + write project/sub/file_in_subdir_2 + AssertEqual expand('%:p'), tempdir.'/project/sub/file_in_subdir_2' + Assert filereadable('project/sub/file_in_subdir_2'), 'file is readable' + + CallNeomake 1, [maker] + AssertNeomakeMessage 'Updating entry bufnr: 0 => '.bufnr.'.' + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 23, + \ 'bufnr': bufnr('%'), + \ 'col': 42, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'error message'}] + bwipe + +Execute (process_output: filename with cwd): + let tempdir = tempname() + let slash = neomake#utils#Slash() + let subdir = tempdir . slash . 'project' . slash . 'sub' + call mkdir(subdir, 'p', 0700) + + let maker = {'exe': 'printf', 'args': '1', 'cwd': '%:p:h'} + function! maker.process_output(...) abort dict + return [{ + \ 'filename': 'file_in_subdir_3', + \ 'lnum': 23, + \ 'col': 42, + \ 'text': 'error message', + \ 'type': 'E', + \ }] + endfunction + + new + let bufnr = bufnr('%') + exe 'lcd' tempdir + write project/sub/file_in_subdir_3 + AssertEqual expand('%:p'), tempdir.'/project/sub/file_in_subdir_3' + Assert filereadable('project/sub/file_in_subdir_3'), 'file is readable' + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage 'Updating entry bufnr: 0 => '.bufnr.'.' + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 23, + \ 'bufnr': bufnr('%'), + \ 'col': 42, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'error message'}] + bwipe + +Execute (process_output: gets executed in maker cwd): + let s:called = 0 + let s:cwd = tempname() + call mkdir(s:cwd) + + let maker = copy(g:error_maker) + let maker.cwd = s:cwd + function! maker.process_output(context) + let s:called = 1 + AssertEqual getcwd(), s:cwd + return [] + endfunction + + CallNeomake 0, [maker] + AssertEqual s:called, 1 + +Execute (legacy errorformat maker: filename with cwd): + let tempdir = tempname() + let slash = neomake#utils#Slash() + let subdir = tempdir . slash . 'project' . slash . 'sub' + call mkdir(subdir, 'p', 0700) + + let maker = { + \ 'exe': 'printf', + \ 'args': '"file_in_subdir_4:23:42:E:error message"', + \ 'errorformat': '%f:%l:%c:%t:%m', + \ 'cwd': '%:p:h'} + + new + let bufnr = bufnr('%') + exe 'lcd' tempdir + write project/sub/file_in_subdir_4 + AssertEqual expand('%:p'), tempdir.'/project/sub/file_in_subdir_4' + Assert filereadable('project/sub/file_in_subdir_4'), 'file is readable' + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 23, + \ 'bufnr': bufnr('%'), + \ 'col': 42, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'error message'}] + bwipe + +Execute (legacy errorformat maker: filename with cwd (error: removed)): + if v:version < 705 && !(v:version == 704 && has('patch1107')) + NeomakeTestsSkip 'cannot delete direcories easily' + return + endif + let tempdir = tempname() + let slash = neomake#utils#Slash() + let subdir = tempdir . slash . 'project' . slash . 'sub' + call mkdir(subdir, 'p', 0700) + + let maker = NeomakeTestsCommandMaker('print_error', + \ 'printf "file_in_subdir_5:23:42:E:error message"') + call extend(maker, { + \ 'errorformat': '%f:%l:%c:%t:%m', + \ 'cwd': '%:p:h'}) + + new + exe 'lcd' tempdir + write project/sub/file_in_subdir_5 + let tempfile = expand('%:p') + let bufnr = bufnr('%') + AssertEqual tempfile, tempdir.'/project/sub/file_in_subdir_5' + Assert filereadable('project/sub/file_in_subdir_5'), 'file is readable' + + call neomake#Make(1, [maker]) + + if neomake#has_async_support() + " Delete the file and dir to trigger the cd error. + let tempfile_dir = fnamemodify(tempfile, ':h') + AssertEqual 0, delete(tempfile) + AssertEqual 0, delete(tempfile_dir, 'd') + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage printf("Could not change to job's cwd (%%:p:h): %s", + \ printf("Vim(lcd):E344: Can't find directory \"%s\" in cdpath.", tempfile_dir)) + + " A new unlisted buffer should have been created. + try + " try/catch for 'throw' in 'msg' setting. + let loclist_bufnr = bufnr('^file_in_subdir_5$') + catch + Assert 0, printf('could not find file_in_subdir_5 unlisted buffer: %s: %s', + \ v:exception, neomake#utils#redir('ls!')) + endtry + Assert !buflisted(loclist_bufnr), 'buffer is unlisted' + AssertNotEqual bufnr('%'), loclist_bufnr + + let expected_bufnr = loclist_bufnr + else + let expected_bufnr = bufnr('%') + endif + + " Filtering out 'shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory' + AssertEqualQf filter(getloclist(0), "v:val.text !~# '^shell-init'"), [{ + \ 'lnum': 23, + \ 'bufnr': expected_bufnr, + \ 'col': 42, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'error message'}] + if exists('loclist_bufnr') + exe 'bwipe' loclist_bufnr + endif + bwipe + + AssertNeomakeMessage 'Placing sign: sign place 5000 line=23 name=neomake_file_err buffer='.expected_bufnr.'.' + +Execute (legacy errorformat maker: filename with cwd (error: maker rmdir)): + let tempdir = tempname() + call mkdir(tempdir, 'p', 0700) + + let maker = NeomakeTestsCommandMaker('remove_dir_and_print_error', + \ printf('rmdir %s && printf "file_in_subdir_6:23:42:E:error message"', tempdir)) + call extend(maker, { + \ 'errorformat': '%f:%l:%c:%t:%m', + \ 'cwd': tempdir}) + + new + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage printf("Could not change to job's cwd (%s): %s", + \ tempdir, + \ printf("Vim(cd):E344: Can't find directory \"%s\" in cdpath.", tempdir)) + + " A new unlisted buffer should have been created. + let unlisted_bufnr = bufnr('^file_in_subdir_6$') + Assert !buflisted(unlisted_bufnr), 'buffer is unlisted' + AssertNotEqual bufnr('%'), unlisted_bufnr + + " Filtering out 'shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory' + AssertEqualQf filter(getloclist(0), "v:val.text !~# '^shell-init'"), [{ + \ 'lnum': 23, + \ 'bufnr': unlisted_bufnr, + \ 'col': 42, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'error message'}] + bwipe + exe 'bwipe' unlisted_bufnr + +Execute (cwd): + new + file tests/fixtures/a\ filename\ with\ spaces + let maker = { + \ 'name': 'custom_maker', + \ 'exe': 'ls', + \ 'cwd': '%:p:h', + \ } + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage printf('cwd: %s/tests/fixtures (changed).', getcwd()), 3 + AssertEqual map(getloclist(0), 'v:val.text'), ['a filename with spaces'] + bwipe + +Execute (cwd (tempfile)): + new + file tests/fixtures/doesnotexist + let bufname = bufname('%') + let maker = { + \ 'name': 'custom_maker', + \ 'exe': 'ls', + \ 'cwd': '%:p:h', + \ } + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage '\v^Using tempfile for unreadable buffer: "(.*)"', 3 + let tempfile_name = g:neomake_test_matchlist[1] + + " Temporary file gets created in maker's cwd, and displays full name. + let tempfile_abs = fnamemodify(bufname, ':p') + AssertEqual fnamemodify(tempfile_name, ':h'), fnamemodify(tempfile_abs, ':h') + AssertNeomakeMessage printf('cwd: %s/tests/fixtures (changed).', getcwd()), 3 + AssertEqual map(getloclist(0), 'v:val.text'), [fnamemodify(tempfile_name, ':t')] + + AssertNeomakeMessage printf('Removing temporary file: "%s/tests/fixtures/%s".', + \ getcwd(), fnamemodify(tempfile_name, ':t')) + Assert !filereadable(printf('tests/fixtures/%s', tempfile_name)) + bwipe diff --git a/bundle/neomake/tests/debug.vader b/bundle/neomake/tests/debug.vader new file mode 100644 index 000000000..406305e19 --- /dev/null +++ b/bundle/neomake/tests/debug.vader @@ -0,0 +1,110 @@ +Include: include/setup.vader + +Execute (neomake#debug#validate_maker): + let maker = {'exe': 'true'} + function maker.process_json() + endfunction + function maker.process_output() + endfunction + + AssertEqual neomake#debug#validate_maker(maker), { + \ 'errors': [], + \ 'warnings': [ + \ 'maker has process_json and process_output, but only process_json will be used.', + \ ]} + + let maker.mapexpr = 'v:val' + let maker.postprocess = function('tr') + let maker.errorformat = '%m' + AssertEqual neomake#debug#validate_maker(maker), { + \ 'errors': [], + \ 'warnings': [ + \ 'maker has process_json and process_output, but only process_json will be used.', + \ 'maker has mapexpr, but only process_json will be used.', + \ 'maker has postprocess, but only process_json will be used.', + \ 'maker has errorformat, but only process_json will be used.', + \ ]} + +Execute (neomake#debug#validate_maker: validates maker name): + let maker = {'exe': 'true'} + + AssertEqual neomake#debug#validate_maker(maker), { + \ 'errors': [], + \ 'warnings': [], + \ } + + let maker.name = 'good' + AssertEqual neomake#debug#validate_maker(maker), { + \ 'errors': [], + \ 'warnings': [], + \ } + + let maker.name = 'AlsoGood' + AssertEqual neomake#debug#validate_maker(maker), { + \ 'errors': [], + \ 'warnings': [], + \ } + + let maker.name = 'also_good' + AssertEqual neomake#debug#validate_maker(maker), { + \ 'errors': [], + \ 'warnings': [], + \ } + + let maker.name = 'invalid name' + AssertEqual neomake#debug#validate_maker(maker), { + \ 'errors': [printf('Invalid maker name: %s (should match %s)', + \ string(maker.name), string(g:neomake#core#valid_maker_name_pattern))], + \ 'warnings': [], + \ } + +Execute (neomake#debug#pprint): + AssertEqual neomake#debug#pprint(''), "''" + AssertEqual neomake#debug#pprint([1, 2, 3]), "[\n 1,\n 2,\n 3,\n]" + AssertEqual neomake#debug#pprint([{}]), "[\n {},\n]" + AssertEqual neomake#debug#pprint([{'foo': ['bar', 'baz']}]), + \ "[\n {\n 'foo': [\n 'bar',\n 'baz',\n ],\n },\n]" + AssertEqual neomake#debug#pprint([[], []]), "[\n [],\n [],\n]" + + " Uses neomake#utils#fix_self_ref for dicts. + let d = {'foo': 'bar'} + let d.self = d + Assert neomake#debug#pprint(d) =~# "\\V'self': ''" + +Execute (neomake#debug#validate_maker with exe as function): + let maker = neomake#GetMaker('maker_with_nonstring_exe', 'neomake_tests') + AssertEqual neomake#debug#validate_maker(maker), { + \ 'errors': ['Non-string given for executable of maker maker_with_nonstring_exe: type 2.'], + \ 'warnings': []} + +Execute (neomake#debug#get_maker_info: version output): + new + noautocmd set filetype=neomake_tests + + let exe = g:NeomakeTestsCreateExe('echo_maker', ['#!'.&shell, 'echo line 1', 'echo line 2']) + let b:neomake_echo_maker_exe = exe + + let info = neomake#debug#get_maker_info('echo_maker') + AssertEqual info[-1], printf( + \ " - version information (%s --version): line 1\n line 2", + \ exe) + + let exe = g:NeomakeTestsCreateExe('echo_maker', ['#!'.&shell, 'exit 123']) + let info = neomake#debug#get_maker_info('echo_maker') + AssertEqual info[-1], printf( + \ ' - version information (%s --version): failed to get version information (123)', + \ exe) + bwipe + +Execute (neomake#debug#get_maker_info: error with missing maker): + let info = neomake#debug#get_maker_info('doesnotexist') + AssertEqual info, [] + AssertNeomakeMessage 'Maker not found: doesnotexist.', 0 + +Execute (neomake#debug#get_maker_info: displays maker for another filetype): + let info = neomake#debug#get_maker_info('python') + AssertEqual info[0], 'python (filetype python)' + +Execute (neomake#debug#get_maker_info: displays project maker): + let info = neomake#debug#get_maker_info('clippy') + AssertEqual info[0], 'clippy (project maker)' diff --git a/bundle/neomake/tests/env.vader b/bundle/neomake/tests/env.vader new file mode 100644 index 000000000..9132b31f0 --- /dev/null +++ b/bundle/neomake/tests/env.vader @@ -0,0 +1,73 @@ +Include: include/setup.vader + +Execute (NEOMAKE_FILE with tempfile): + let maker = { + \ 'exe': 'cat', + \ 'args': '$NEOMAKE_FILE', + \ 'append_file': 1, + \ 'errorformat': '%m'} + new + normal! iline1 + let b:neomake_tempfile_enabled = 1 + + call neomake#Make(1, [maker]) + AssertEqual $NEOMAKE_FILE, '' + if has('patch-8.0.0902') && has('patch-8.0.1832') + Assert !exists('$NEOMAKE_FILE') + endif + NeomakeTestsWaitForFinishedJobs + + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line1'] + bwipe! + +Execute (NEOMAKE_FILE with tempfile gets restored): + let maker = { + \ 'exe': 'cat', + \ 'args': '$NEOMAKE_FILE', + \ 'append_file': 1, + \ 'errorformat': '%m'} + new + normal! iline1 + let b:neomake_tempfile_enabled = 1 + + Save $NEOMAKE_FILE + let $NEOMAKE_FILE = 'orig' + call neomake#Make(1, [maker]) + AssertEqual $NEOMAKE_FILE, 'orig' + NeomakeTestsWaitForFinishedJobs + + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line1'] + bwipe! + +Execute (NEOMAKE_FILE with tempfile gets only used with append_file): + let maker = { + \ 'exe': 'echo', + \ 'args': 'NEOMAKE_FILE:$NEOMAKE_FILE', + \ 'append_file': 0, + \ 'errorformat': '%m'} + new + let b:neomake_tempfile_enabled = 1 + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqual map(getloclist(0), 'v:val.text'), ['NEOMAKE_FILE:'] + bwipe! + +Execute (NEOMAKE_FILE with real file): + let maker = { + \ 'exe': 'echo', + \ 'args': 'NEOMAKE_FILE:$NEOMAKE_FILE', + \ 'append_file': 1, + \ 'errorformat': '%m'} + new + edit tests/fixtures/a\ filename\ with\ spaces + let fname = expand('%') + let b:neomake_tempfile_enabled = 0 + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ 'NEOMAKE_FILE:'.fname.' '.fname] + bwipe! diff --git a/bundle/neomake/tests/errors.vader b/bundle/neomake/tests/errors.vader new file mode 100644 index 000000000..b6c1e7a71 --- /dev/null +++ b/bundle/neomake/tests/errors.vader @@ -0,0 +1,202 @@ +Include: include/setup.vader + +Execute (Error with no filename): + new + set ft=neomake_tests + let b:neomake_neomake_tests_enabled_makers = ['true'] + let b:neomake_neomake_tests_true_tempfile_enabled = 0 + + Neomake + let make_id = neomake#GetStatus().last_make_id + AssertNeomakeMessage 'no file name.', 0 + bwipe + +Execute (Error with no filename (serialized)): + new + set ft=neomake_tests + let b:neomake_neomake_tests_enabled_makers = ['true', g:entry_maker] + let b:neomake_neomake_tests_true_tempfile_enabled = 0 + let b:neomake_neomake_tests_true_serialize = 1 + let b:neomake_neomake_tests_true_serialize_abort_on_error = 1 + + Neomake + let make_id = neomake#GetStatus().last_make_id + AssertNeomakeMessage 'no file name.', 0 + AssertNeomakeMessage 'Aborting next makers: entry_maker.' + bwipe + +Execute (Error with non-existing filename): + new + file doesnotexist + set ft=neomake_tests + let b:neomake_neomake_tests_enabled_makers = ['true'] + let b:neomake_neomake_tests_true_tempfile_enabled = 0 + + let fname = fnamemodify(bufname('%'), ':p') + Neomake + bwipe! + let make_id = neomake#GetStatus().last_make_id + AssertNeomakeMessage 'file is not readable ('.fname.')', 0 + +Execute (Error with non-existing filename for 2nd maker): + call g:NeomakeSetupAutocmdWrappers() + + new + file doesnotexist + set ft=neomake_tests + let b:neomake_neomake_tests_enabled_makers = ['true'] + let b:neomake_neomake_tests_true_tempfile_enabled = 0 + + let maker1 = { + \ 'exe': 'true', + \ 'name': 'true_maker', + \ 'errorformat': '%m', + \ 'append_file': 0, + \ } + let maker2 = copy(maker1) + let maker2.append_file = 1 + let maker2.tempfile_enabled = 0 + let maker3 = copy(maker1) + + let fname = fnamemodify(bufname('%'), ':p') + call neomake#Make(1, [maker1, maker2, maker3]) + let make_id = neomake#GetStatus().last_make_id + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'file is not readable ('.fname.')', 0 + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 2 + bwipe! + +Execute (maker.exe gets checked): + call NeomakeTestsSetVimMessagesMarker() + + let maker = {'exe': 'doesnotexist'} + let maker_non_string_exe = {} + function maker_non_string_exe.exe() + return 'true' + endfunction + CallNeomake 1, [maker, maker_non_string_exe] + + let log_context = {'make_id': neomake#GetStatus().last_make_id, 'bufnr': bufnr('%')} + AssertNeomakeMessage 'Exe (doesnotexist) of maker unnamed_maker is not executable.', 0, log_context + AssertNeomakeMessage 'Non-string given for executable of maker unnamed_maker: type 2.', 0, log_context + AssertNeomakeMessage 'Nothing to make: no valid makers.' + AssertEqual len(g:neomake_test_messages), 4 + + " Is still an error on second invocation (not autoconfigured). + CallNeomake 1, [maker, maker_non_string_exe] + let make_id = neomake#GetStatus().last_make_id + let log_context = {'make_id': neomake#GetStatus().last_make_id, 'bufnr': bufnr('%')} + AssertNeomakeMessage 'Exe (doesnotexist) of maker unnamed_maker is not executable.', 0, log_context + AssertNeomakeMessage 'Non-string given for executable of maker unnamed_maker: type 2.', 0, log_context + AssertNeomakeMessage 'Nothing to make: no valid makers.', 3, log_context + AssertEqual len(g:neomake_test_messages), 8 + + " Error gets logged as debug message if auto-enabled. + let maker.auto_enabled = 1 + let maker_non_string_exe.auto_enabled = 1 + CallNeomake 1, [maker, maker_non_string_exe] + let make_id = neomake#GetStatus().last_make_id + let log_context = {'make_id': neomake#GetStatus().last_make_id, 'bufnr': bufnr('%')} + AssertNeomakeMessage 'Exe (doesnotexist) of auto-configured maker unnamed_maker is not executable, skipping.', 3, log_context + AssertNeomakeMessage 'Non-string given for executable of maker unnamed_maker: type 2.', 3, log_context + AssertNeomakeMessage 'Nothing to make: no valid makers.', 3, log_context + AssertEqual len(g:neomake_test_messages), 12 + + AssertEqual NeomakeTestsGetVimMessages(), [] + +Execute (maker.exe gets checked (auto-enabled)): + new + set ft=neomake_tests + let b:neomake_test_enabledmakers = ['nonexisting', 'maker_without_exe', 'maker_with_nonstring_exe'] + CallNeomake 1 + let make_id = neomake#GetStatus().last_make_id + + let log_context = {'make_id': make_id, 'bufnr': bufnr('%')} + AssertNeomakeMessage 'Maker not found (for filetype neomake_tests): nonexisting.', 3, log_context + AssertNeomakeMessage 'Exe (maker_without_exe) of auto-configured maker maker_without_exe is not executable, skipping.', 3, log_context + AssertNeomakeMessage 'Non-string given for executable of maker maker_with_nonstring_exe: type 2.', 3, log_context + AssertNeomakeMessage 'Nothing to make: no valid makers.', 3, log_context + Assert len(g:neomake_test_messages), 3 + bwipe + +Execute (neomake#GetMaker with non-existent maker throws errors): + AssertThrows call neomake#GetMaker('non-existent') + AssertEqual g:vader_exception, 'Neomake: Invalid maker name: "non-existent"' + AssertThrows call neomake#GetMaker('nonexistent') + AssertEqual g:vader_exception, 'Neomake: Maker not found (without filetype): nonexistent' + AssertThrows call neomake#GetMaker('nonexistent', '') + AssertEqual g:vader_exception, 'Neomake: Maker not found (for empty filetype): nonexistent' + AssertThrows call neomake#GetMaker('nonexistent', 'c') + AssertEqual g:vader_exception, 'Neomake: Maker not found (for filetype c): nonexistent' + AssertEqual len(g:neomake_test_messages), 0 + +Execute (Errors from neomake#GetMaker get handled by neomake#Make): + CallNeomake 1, ['g:invalid-name'] + AssertNeomakeMessage 'Invalid maker name: "g:invalid-name".', 0 + CallNeomake 0, ['nonexistent'] + AssertNeomakeMessage 'Maker not found (without filetype): nonexistent.', 0 + +Execute (Error from neomake#GetMaker for non-dict maker): + new + let b:neomake_mymaker_maker = 0 + AssertThrows call neomake#GetMaker('mymaker') + AssertEqual g:vader_exception, 'Neomake: Got non-dict for maker mymaker: 0' + + CallNeomake 0, ['mymaker'] + let make_id = neomake#GetStatus().last_make_id + AssertNeomakeMessage 'Got non-dict for maker mymaker: 0.', 0, {'make_id': make_id, 'bufnr': bufnr('%')} + AssertNeomakeMessage 'Nothing to make: no valid makers.', 3 + AssertNeomakeMessage 'Cleaning make info.', 3 + bwipe + +Execute (Empty maker gets handled in s:Make): + CallNeomake {'enabled_makers': []} + " TODO: level: more visible in this case?! + AssertNeomakeMessage 'Nothing to make: no valid makers.', 3 + + CallNeomake {'enabled_makers': [{}]} + AssertNeomakeMessage 'Exe (unnamed_maker) of maker unnamed_maker is not executable.', 0 + AssertNeomakeMessage 'Nothing to make: no valid makers.', 3 + +Execute (NeomakeSh handles invalid shell): + if neomake#has_async_support() + NeomakeTestsSkip 'Only for non-async' + else + Save &shell + call g:NeomakeTestsCreateExe('cmd.exe', []) + let &shell = 'cmd.exe' + call neomake#Sh('dir ..') + AssertNeomakeMessage '\v^Could not run cmd.exe -c "dir .." 2>.*: Vim\(let\):E484: .*\.$', 0 + endif + +Execute (neomake#Make with non-existing bufnr/winid/winnr): + AssertThrows call neomake#Make({'bufnr': 1234, 'file_mode': 1}) + AssertEqual g:vader_exception, 'Neomake: winid or winnr are required for non-current buffer.' + + AssertThrows call neomake#Make({'bufnr': 1234, 'file_mode': 1, 'winid': 1234, 'enabled_makers': []}) + AssertEqual g:vader_exception, 'Neomake: buffer 1234 does not exist.' + + AssertThrows call neomake#Make({'bufnr': bufnr('%'), 'file_mode': 1, 'winid': 1234, 'enabled_makers': []}) + if exists('*win_getid') + AssertEqual g:vader_exception, 'Neomake: window id 1234 does not exist.' + else + AssertEqual g:vader_exception, 'Vim(if):E117: Unknown function: win_id2tabwin' + endif + + AssertThrows call neomake#Make({'bufnr': bufnr('%'), 'file_mode': 1, 'winnr': 1234, 'enabled_makers': []}) + AssertEqual g:vader_exception, 'Neomake: window 1234 does not exist.' + + " winid/winnr with file_mode=0. + AssertThrows call neomake#Make({'bufnr': bufnr('%'), 'file_mode': 0, 'winnr': 1234, 'enabled_makers': []}) + AssertEqual g:vader_exception, 'Neomake: do not use winnr with file_mode=0.' + + AssertThrows call neomake#Make({'bufnr': bufnr('%'), 'file_mode': 0, 'winid': 1234, 'enabled_makers': []}) + AssertEqual g:vader_exception, 'Neomake: do not use winid with file_mode=0.' + + " Valid. + if exists('*win_getid') + call neomake#Make({'bufnr': bufnr('%'), 'file_mode': 1, 'winid': win_getid(), 'enabled_makers': []}) + endif + call neomake#Make({'bufnr': bufnr('%'), 'file_mode': 1, 'winnr': winnr(), 'enabled_makers': []}) + NeomakeCancelJobs! diff --git a/bundle/neomake/tests/filetypes.vader b/bundle/neomake/tests/filetypes.vader new file mode 100644 index 000000000..63b2300c6 --- /dev/null +++ b/bundle/neomake/tests/filetypes.vader @@ -0,0 +1,106 @@ +Include: include/setup.vader + +Execute (GetEnabledMakers for javascript.jsx): + AssertEqual map(neomake#GetEnabledMakers('javascript.jsx'), 'v:val.name'), + \ ['jshint', 'jscs', executable('eslint_d') ? 'eslint_d' : 'eslint'] + +Execute (GetEnabledMakers for jsx.javascript): + AssertEqual map(neomake#GetEnabledMakers('jsx.javascript'), 'v:val.name'), + \ ['jshint', executable('eslint_d') ? 'eslint_d' : 'eslint'] + +Execute (GetEnabledMakers for javascript): + AssertEqual map(neomake#GetEnabledMakers('javascript'), 'v:val.name'), + \ ['jshint', 'jscs', executable('eslint_d') ? 'eslint_d' : 'eslint'] + +Execute (GetEnabledMakers for jsx): + AssertEqual map(neomake#GetEnabledMakers('jsx'), 'v:val.name'), + \ ['jshint', executable('eslint_d') ? 'eslint_d' : 'eslint'] + + +Execute (GetMakers for javascript.jsx): + AssertEqual neomake#GetMakers('javascript.jsx'), + \ ['eslint', 'eslint_d', 'flow', 'gjslint', 'jscs', 'jshint', 'rjsx', 'semistandard', 'standard', 'stylelint', 'tsc', 'xo', 'jsxhint'] + +Execute (GetMakers for jsx.javascript): + " jsxhint comes first, since it is defined in jsx.vim. + let expected = ['jsxhint', 'stylelint', 'eslint', 'eslint_d', 'flow', 'gjslint', 'jscs', 'jshint', 'rjsx', 'semistandard', 'standard', 'tsc', 'xo'] + AssertEqual neomake#GetMakers('jsx.javascript'), expected + + new + let b:neomake_jsx_javascript_foo_maker = {'name': 'foo'} + AssertEqual neomake#GetMakers('jsx.javascript'), ['foo'] + expected + + " NOTE: Shortcoming with old-style config: makes "javascript_foo" a possible + " maker for ft=jsx. + AssertEqual neomake#GetMaker('javascript_foo', 'jsx').name, 'foo' + bwipe + +Execute (GetMakers for javascript): + AssertEqual neomake#GetMakers('javascript'), + \ ['eslint', 'eslint_d', 'flow', 'gjslint', 'jscs', 'jshint', 'rjsx', 'semistandard', 'standard', 'stylelint', 'tsc', 'xo'] + +Execute (GetMakers for jsx): + AssertEqual neomake#GetMakers('jsx'), ['jsxhint', 'stylelint'] + filter(neomake#GetMakers('javascript'), "v:val != 'stylelint'") + +Execute (standard maker in javascript.jsx): + new + set filetype=javascript.jsx + AssertEqual map(neomake#GetEnabledMakers('jsx'), 'v:val.name'), [ + \ 'jshint', executable('eslint_d') ? 'eslint_d' : 'eslint'] + let b:neomake_javascript_enabled_makers = ['standard'] + let b:neomake_javascript_standard_exe = 'custom-javascript' + let b:neomake_jsx_jshint_exe = 'true' + let b:neomake_jsx_eslint_exe = 'true' + AssertEqual map(neomake#GetEnabledMakers('javascript'), 'v:val.name'), ['standard'] + AssertEqual map(neomake#GetEnabledMakers('jsx'), 'v:val.name'), ['standard'] + AssertEqual map(neomake#GetEnabledMakers('jsx.javascript'), 'v:val.name'), ['standard'] + Neomake + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Exe (custom-javascript) of maker standard is not executable.', 0 + + function! s:F() abort + return map(copy(neomake#GetEnabledMakers('jsx.javascript')), + \ '[v:val.name, v:val.exe]') + endfunction + AssertEqual s:F(), [['standard', 'custom-javascript']] + let b:neomake_jsx_enabled_makers = ['standard'] + AssertEqual s:F(), [['standard', 'custom-javascript']] + + let b:neomake_jsx_standard_exe = 'exe1' + AssertEqual s:F(), [['standard', 'exe1']] + + let b:neomake_jsx_javascript_standard_exe = 'exe2' + AssertEqual s:F(), [['standard', 'exe2']] + + Neomake + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Exe (custom-javascript) of maker standard is not executable.', 0 + bwipe + +Execute (standard maker in javascript.jsx): + new + let b:neomake_jsx_javascript_enabled_makers = ['standard'] + AssertEqual map(neomake#GetEnabledMakers('jsx.javascript'), 'v:val.name'), ['standard'] + let b:neomake_javascript_jsx_enabled_makers = ['standard'] + AssertEqual map(neomake#GetEnabledMakers('javascript.jsx'), 'v:val.name'), ['standard'] + bwipe + +Execute (makers are picked up via SupersetOf for jsx): + new + let b:neomake_javascript_enabled_makers = ['eslint'] + let b:neomake_jsx_enabled_makers = ['flow'] + + let maker = neomake#GetMaker('flow', 'jsx.javascript') + AssertEqual maker.name, 'flow' + + let maker = neomake#GetMaker('jsxhint', 'jsx') + AssertEqual maker.name, 'jsxhint' + AssertEqual maker.exe, 'jsxhint' + + let b:neomake_javascript_jshint_exe = 'customexe' + AssertEqual neomake#GetMaker('jshint', 'javascript').exe, 'customexe' + AssertThrows call neomake#GetMaker('jsxhint', 'javascript') + AssertEqual g:vader_exception, 'Neomake: Maker not found (for filetype javascript): jsxhint' + " Should not use jshint_exe config. + AssertEqual neomake#GetMaker('jsxhint', 'jsx').exe, 'jsxhint' + bwipe diff --git a/bundle/neomake/tests/filter_output.vader b/bundle/neomake/tests/filter_output.vader new file mode 100644 index 000000000..1c540435a --- /dev/null +++ b/bundle/neomake/tests/filter_output.vader @@ -0,0 +1,64 @@ +Include: include/setup.vader + +Execute (filter_output can filter messages on stderr): + let maker = NeomakeTestsCommandMaker('stderr_and_stdout', + \ 'echo stderr >&2; echo stdout; echo stderr2 >&2') + + CallNeomake 0, [maker] + AssertEqual sort(map(getqflist(), 'v:val.text')), ['stderr', 'stderr2', 'stdout'] + + function maker.filter_output(lines, context) + if a:context.source ==# 'stderr' + call filter(a:lines, "v:val !=# 'stderr'") + endif + endfunction + + CallNeomake 0, [maker] + AssertEqual map(getqflist(), 'v:val.text'), ['stdout', 'stderr2'] + +Execute (filter_output can be set for a buffer): + let maker = NeomakeTestsCommandMaker('stderr_and_stdout', + \ 'echo stderr >&2; echo stdout; echo stderr2 >&2') + function! maker.filter_output(lines, context) + Assert 0, 'should not get called' + endfunction + + new + set ft=neomake_tests + + let s:override_called = 0 + let s:maker = maker + function NeomakeTestF(lines, context) dict + let s:override_called = 1 + AssertEqual self.name, 'stderr_and_stdout' + endfunction + let b:neomake_neomake_tests_stderr_and_stdout_filter_output = function('NeomakeTestF') + + CallNeomake 0, [maker] + AssertEqual sort(map(getqflist(), 'v:val.text')), ['stderr', 'stderr2', 'stdout'] + AssertEqual s:override_called, 1, 's:override was called' + delfunction NeomakeTestF + bwipe + +Execute (filter_output can be used to filter unexpected output): + let maker = NeomakeTestsCommandMaker('stderr_and_stdout', + \ 'echo stderr >&2; echo stdout; echo stderr2 >&2') + let maker.output_stream = 'stdout' + + CallNeomake 0, [maker] + AssertNeomakeMessage 'stderr_and_stdout: unexpected output on stderr: stderr\nstderr2.', 3 + if neomake#has_async_support() + AssertNeomakeMessage 'stderr_and_stdout: unexpected output. See :messages for more information.', 0 + else + AssertNeomakeMessage 'stderr_and_stdout: unexpected output.', 0 + endif + ' + AssertEqual sort(map(getqflist(), 'v:val.text')), ['stdout'] + + function! maker.filter_output(lines, context) + if a:context.source ==# 'stderr' + call filter(a:lines, 'v:val !~# "^stderr"') + endif + endfunction + CallNeomake 0, [maker] + AssertEqual sort(map(getqflist(), 'v:val.text')), ['stdout'] diff --git a/bundle/neomake/tests/fixtures/a filename with spaces b/bundle/neomake/tests/fixtures/a filename with spaces new file mode 100644 index 000000000..a29bdeb43 --- /dev/null +++ b/bundle/neomake/tests/fixtures/a filename with spaces @@ -0,0 +1 @@ +line1 diff --git a/bundle/neomake/tests/fixtures/errors.py b/bundle/neomake/tests/fixtures/errors.py new file mode 100644 index 000000000..c361281f8 --- /dev/null +++ b/bundle/neomake/tests/fixtures/errors.py @@ -0,0 +1 @@ +invalid_syntax( diff --git a/bundle/neomake/tests/fixtures/errors.sh b/bundle/neomake/tests/fixtures/errors.sh new file mode 100644 index 000000000..a07d7837a --- /dev/null +++ b/bundle/neomake/tests/fixtures/errors.sh @@ -0,0 +1,5 @@ +#! /bin/bash + +a='$var' + +foo( diff --git a/bundle/neomake/tests/fixtures/input/puppet-lint/err_and_warn.pp b/bundle/neomake/tests/fixtures/input/puppet-lint/err_and_warn.pp new file mode 100644 index 000000000..c3a37da04 --- /dev/null +++ b/bundle/neomake/tests/fixtures/input/puppet-lint/err_and_warn.pp @@ -0,0 +1,7 @@ +class foo { + file { "bar": + ensure => 'file', + mode => '0666' + } +} + diff --git a/bundle/neomake/tests/fixtures/input/puppet/syntax-error-eoi.pp b/bundle/neomake/tests/fixtures/input/puppet/syntax-error-eoi.pp new file mode 100644 index 000000000..71ac466d0 --- /dev/null +++ b/bundle/neomake/tests/fixtures/input/puppet/syntax-error-eoi.pp @@ -0,0 +1,7 @@ +# Syntax error at end of input (line number is not given) +class foo { + file { 'bar': + ensure => 'file', + mode => '0666' + } + diff --git a/bundle/neomake/tests/fixtures/input/puppet/syntax-error.pp b/bundle/neomake/tests/fixtures/input/puppet/syntax-error.pp new file mode 100644 index 000000000..531a24c01 --- /dev/null +++ b/bundle/neomake/tests/fixtures/input/puppet/syntax-error.pp @@ -0,0 +1,8 @@ +# Syntax error at line 3 +class foo + file { 'bar': + ensure => 'file', + mode => '0666' + } +} + diff --git a/bundle/neomake/tests/fixtures/input/xmllint/missingdtd.xml b/bundle/neomake/tests/fixtures/input/xmllint/missingdtd.xml new file mode 100644 index 000000000..b2e0192cf --- /dev/null +++ b/bundle/neomake/tests/fixtures/input/xmllint/missingdtd.xml @@ -0,0 +1,6 @@ + + + + + b text + diff --git a/bundle/neomake/tests/fixtures/input/xmllint/validity-error.xml b/bundle/neomake/tests/fixtures/input/xmllint/validity-error.xml new file mode 100644 index 000000000..b9f55a0a1 --- /dev/null +++ b/bundle/neomake/tests/fixtures/input/xmllint/validity-error.xml @@ -0,0 +1 @@ + diff --git a/bundle/neomake/tests/fixtures/output/puppet-lint/err_and_warn.pp.exitcode b/bundle/neomake/tests/fixtures/output/puppet-lint/err_and_warn.pp.exitcode new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/puppet-lint/err_and_warn.pp.exitcode @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/bundle/neomake/tests/fixtures/output/puppet-lint/err_and_warn.pp.stderr b/bundle/neomake/tests/fixtures/output/puppet-lint/err_and_warn.pp.stderr new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/neomake/tests/fixtures/output/puppet-lint/err_and_warn.pp.stdout b/bundle/neomake/tests/fixtures/output/puppet-lint/err_and_warn.pp.stdout new file mode 100644 index 000000000..20dc6f997 --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/puppet-lint/err_and_warn.pp.stdout @@ -0,0 +1,4 @@ +tests/fixtures/input/puppet-lint/err_and_warn.pp:4:10:warning:[arrow_alignment] indentation of => is not properly aligned (expected in column 12, but found it in column 10) +tests/fixtures/input/puppet-lint/err_and_warn.pp:1:7:error:[autoloader_layout] foo not in autoload module layout +tests/fixtures/input/puppet-lint/err_and_warn.pp:2:10:warning:[double_quoted_strings] double quoted string containing no variables +tests/fixtures/input/puppet-lint/err_and_warn.pp:1:1:warning:[documentation] class not documented diff --git a/bundle/neomake/tests/fixtures/output/puppet/syntax-error-eoi.pp.exitcode b/bundle/neomake/tests/fixtures/output/puppet/syntax-error-eoi.pp.exitcode new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/puppet/syntax-error-eoi.pp.exitcode @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/bundle/neomake/tests/fixtures/output/puppet/syntax-error-eoi.pp.stderr b/bundle/neomake/tests/fixtures/output/puppet/syntax-error-eoi.pp.stderr new file mode 100644 index 000000000..599ca27c7 --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/puppet/syntax-error-eoi.pp.stderr @@ -0,0 +1 @@ +Error: Could not parse for environment production: Syntax error at end of input (file: /tmp/neomake-tests/tests/fixtures/input/puppet/syntax-error-eoi.pp) diff --git a/bundle/neomake/tests/fixtures/output/puppet/syntax-error-eoi.pp.stdout b/bundle/neomake/tests/fixtures/output/puppet/syntax-error-eoi.pp.stdout new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/neomake/tests/fixtures/output/puppet/syntax-error.pp.exitcode b/bundle/neomake/tests/fixtures/output/puppet/syntax-error.pp.exitcode new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/puppet/syntax-error.pp.exitcode @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/bundle/neomake/tests/fixtures/output/puppet/syntax-error.pp.stderr b/bundle/neomake/tests/fixtures/output/puppet/syntax-error.pp.stderr new file mode 100644 index 000000000..0e07860e9 --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/puppet/syntax-error.pp.stderr @@ -0,0 +1 @@ +Error: Could not parse for environment production: Syntax error at 'file' (file: /tmp/neomake-tests/tests/fixtures/input/puppet/syntax-error.pp, line: 3, column: 3) diff --git a/bundle/neomake/tests/fixtures/output/puppet/syntax-error.pp.stdout b/bundle/neomake/tests/fixtures/output/puppet/syntax-error.pp.stdout new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/neomake/tests/fixtures/output/xmllint/missingdtd.xml.exitcode b/bundle/neomake/tests/fixtures/output/xmllint/missingdtd.xml.exitcode new file mode 100644 index 000000000..e440e5c84 --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/xmllint/missingdtd.xml.exitcode @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/bundle/neomake/tests/fixtures/output/xmllint/missingdtd.xml.stderr b/bundle/neomake/tests/fixtures/output/xmllint/missingdtd.xml.stderr new file mode 100644 index 000000000..3000fdff2 --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/xmllint/missingdtd.xml.stderr @@ -0,0 +1,9 @@ +tests/fixtures/input/xmllint/missingdtd.xml:2: warning: failed to load external entity "tests/fixtures/input/xmllint/missingdtdref" + + ^ +tests/fixtures/input/xmllint/missingdtd.xml:5: namespace error : Namespace prefix xlink for href on b is not defined + b text + ^ +warning: failed to load external entity "tests/fixtures/input/xmllint/missingdtdref" +validity error : Could not load the external subset "missingdtdref" +Document tests/fixtures/input/xmllint/missingdtd.xml does not validate diff --git a/bundle/neomake/tests/fixtures/output/xmllint/missingdtd.xml.stdout b/bundle/neomake/tests/fixtures/output/xmllint/missingdtd.xml.stdout new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/neomake/tests/fixtures/output/xmllint/validity-error.xml.exitcode b/bundle/neomake/tests/fixtures/output/xmllint/validity-error.xml.exitcode new file mode 100644 index 000000000..e440e5c84 --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/xmllint/validity-error.xml.exitcode @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/bundle/neomake/tests/fixtures/output/xmllint/validity-error.xml.stderr b/bundle/neomake/tests/fixtures/output/xmllint/validity-error.xml.stderr new file mode 100644 index 000000000..9d0f174b3 --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/xmllint/validity-error.xml.stderr @@ -0,0 +1,2 @@ +validity error : no DTD found! +Document tests/fixtures/input/xmllint/validity-error.xml does not validate diff --git a/bundle/neomake/tests/fixtures/output/xmllint/validity-error.xml.stdout b/bundle/neomake/tests/fixtures/output/xmllint/validity-error.xml.stdout new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/neomake/tests/fixtures/output/zsh/parse-error.zsh.exitcode b/bundle/neomake/tests/fixtures/output/zsh/parse-error.zsh.exitcode new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/zsh/parse-error.zsh.exitcode @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/bundle/neomake/tests/fixtures/output/zsh/parse-error.zsh.stderr b/bundle/neomake/tests/fixtures/output/zsh/parse-error.zsh.stderr new file mode 100644 index 000000000..ac4bbbdb9 --- /dev/null +++ b/bundle/neomake/tests/fixtures/output/zsh/parse-error.zsh.stderr @@ -0,0 +1 @@ +tests/fixtures/input/zsh/parse-error.zsh:2: parse error near `\n' diff --git a/bundle/neomake/tests/fixtures/output/zsh/parse-error.zsh.stdout b/bundle/neomake/tests/fixtures/output/zsh/parse-error.zsh.stdout new file mode 100644 index 000000000..e69de29bb diff --git a/bundle/neomake/tests/fixtures/rust/cargo_error.json b/bundle/neomake/tests/fixtures/rust/cargo_error.json new file mode 100644 index 000000000..783e9aa8e --- /dev/null +++ b/bundle/neomake/tests/fixtures/rust/cargo_error.json @@ -0,0 +1 @@ +{"message":{"children":[{"children":[],"code":null,"level":"note","message":"expected type `&str`","rendered":null,"spans":[]},{"children":[],"code":null,"level":"note","message":" found type `&proc_macro::TokenStream`","rendered":null,"spans":[]}],"code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variables\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","message":"mismatched types","rendered":null,"spans":[{"byte_end":437,"byte_start":435,"column_end":48,"column_start":46,"expansion":{"def_site_span":{"byte_end":537,"byte_start":181,"column_end":3,"column_start":1,"expansion":null,"file_name":"lib.rs","is_primary":false,"label":null,"line_end":23,"line_start":14,"suggested_replacement":null,"text":[{"highlight_end":28,"highlight_start":1,"text":"macro_rules! create_derive("},{"highlight_end":55,"highlight_start":1,"text":" ($mod_:ident, $trait_:ident, $fn_name: ident) => {"},{"highlight_end":38,"highlight_start":1,"text":" #[proc_macro_derive($trait_)]"},{"highlight_end":61,"highlight_start":1,"text":" pub fn $fn_name(input: TokenStream) -> TokenStream {"},{"highlight_end":27,"highlight_start":1,"text":" let s = input;"},{"highlight_end":59,"highlight_start":1,"text":" let ast = syn::parse_macro_input(&s).unwrap();"},{"highlight_end":70,"highlight_start":1,"text":" $mod_::expand(&ast, stringify!($trait_)).parse().unwrap()"},{"highlight_end":10,"highlight_start":1,"text":" }"},{"highlight_end":6,"highlight_start":1,"text":" }"},{"highlight_end":3,"highlight_start":1,"text":");"}]},"macro_decl_name":"create_derive!","span":{"byte_end":579,"byte_start":539,"column_end":41,"column_start":1,"expansion":null,"file_name":"lib.rs","is_primary":false,"label":null,"line_end":25,"line_start":25,"suggested_replacement":null,"text":[{"highlight_end":41,"highlight_start":1,"text":"create_derive!(from, From, from_derive);"}]}},"file_name":"lib.rs","is_primary":true,"label":"expected str, found struct `proc_macro::TokenStream`","line_end":19,"line_start":19,"suggested_replacement":null,"text":[{"highlight_end":48,"highlight_start":46,"text":" let ast = syn::parse_macro_input(&s).unwrap();"}]}]},"package_id":"derive_more 0.4.0 (path+file:///home/jelte/fun/derive_more)","reason":"compiler-message","target":{"kind":["proc-macro"],"name":"derive_more","src_path":"/home/jelte/fun/derive_more/lib.rs"}} diff --git a/bundle/neomake/tests/fixtures/rust/cargo_error_children.json b/bundle/neomake/tests/fixtures/rust/cargo_error_children.json new file mode 100644 index 000000000..2d9c9840a --- /dev/null +++ b/bundle/neomake/tests/fixtures/rust/cargo_error_children.json @@ -0,0 +1 @@ +{"message":{"children":[{"children":[],"code":null,"level":"help","message":"message: Only structs and enums can derive From","rendered":null,"spans":[]}],"code":null,"level":"error","message":"custom derive attribute panicked","rendered":null,"spans":[{"byte_end":151,"byte_start":147,"column_end":14,"column_start":10,"expansion":{"def_site_span":null,"macro_decl_name":"#[derive(From)]","span":{"byte_end":151,"byte_start":147,"column_end":14,"column_start":10,"expansion":null,"file_name":"from.rs","is_primary":false,"label":null,"line_end":11,"line_start":11,"suggested_replacement":null,"text":[{"highlight_end":14,"highlight_start":10,"text":"#[derive(From)]"}]}},"file_name":"from.rs","is_primary":true,"label":null,"line_end":11,"line_start":11,"suggested_replacement":null,"text":[{"highlight_end":14,"highlight_start":10,"text":"#[derive(From)]"}]}]},"package_id":"derive_more 0.6.1 (path+file:///home/jelte/fun/derive_more)","reason":"compiler-message","target":{"kind":["test"],"name":"from","src_path":"/home/jelte/fun/derive_more/tests/from.rs"}} diff --git a/bundle/neomake/tests/fixtures/rust/cargo_error_primary_span.json b/bundle/neomake/tests/fixtures/rust/cargo_error_primary_span.json new file mode 100644 index 000000000..e04f1e00f --- /dev/null +++ b/bundle/neomake/tests/fixtures/rust/cargo_error_primary_span.json @@ -0,0 +1,3 @@ +{"message":{"children":[],"code":{"code":"E0061","explanation":"\nThe number of arguments passed to a function must match the number of arguments\nspecified in the function signature.\n\nFor example, a function like:\n\n```\nfn f(a: u16, b: &str) {}\n```\n\nMust always be called with exactly two arguments, e.g. `f(2, \"test\")`.\n\nNote that Rust does not have a notion of optional function arguments or\nvariadic functions (except for its C-FFI).\n"},"level":"error","message":"this function takes 1 parameter but 2 parameters were supplied","rendered":"error[E0061]: this function takes 1 parameter but 2 parameters were supplied\n --> build/main.rs:6:5\n |\n1 | fn foo(i : i32) {\n | --------------- defined here\n...\n6 | foo(1, 1);\n | ^^^^^^^^^ expected 1 parameter\n\n","spans":[{"byte_end":15,"byte_start":0,"column_end":16,"column_start":1,"expansion":null,"file_name":"build/main.rs","is_primary":false,"label":"defined here","line_end":1,"line_start":1,"suggested_replacement":null,"suggestion_applicability":null,"text":[{"highlight_end":16,"highlight_start":1,"text":"fn foo(i : i32) {"}]},{"byte_end":67,"byte_start":58,"column_end":14,"column_start":5,"expansion":null,"file_name":"build/main.rs","is_primary":true,"label":"expected 1 parameter","line_end":6,"line_start":6,"suggested_replacement":null,"suggestion_applicability":null,"text":[{"highlight_end":14,"highlight_start":5,"text":" foo(1, 1);"}]}]},"package_id":"testfoo 0.1.0 (path+file:///home/dpc/tmp/testfoo)","reason":"compiler-message","target":{"crate_types":["bin"],"edition":"2015","kind":["bin"],"name":"testfoo","src_path":"/home/dpc/tmp/testfoo/build/main.rs"}} +{"message":{"children":[],"code":null,"level":"error","message":"aborting due to previous error","rendered":"error: aborting due to previous error\n\n","spans":[]},"package_id":"testfoo 0.1.0 (path+file:///home/dpc/tmp/testfoo)","reason":"compiler-message","target":{"crate_types":["bin"],"edition":"2015","kind":["bin"],"name":"testfoo","src_path":"/home/dpc/tmp/testfoo/build/main.rs"}} +{"message":{"children":[],"code":null,"level":"","message":"For more information about this error, try `rustc --explain E0061`.","rendered":"For more information about this error, try `rustc --explain E0061`.\n","spans":[]},"package_id":"testfoo 0.1.0 (path+file:///home/dpc/tmp/testfoo)","reason":"compiler-message","target":{"crate_types":["bin"],"edition":"2015","kind":["bin"],"name":"testfoo","src_path":"/home/dpc/tmp/testfoo/build/main.rs"}} diff --git a/bundle/neomake/tests/fixtures/rust/cargo_error_without_span.json b/bundle/neomake/tests/fixtures/rust/cargo_error_without_span.json new file mode 100644 index 000000000..6e78d470b --- /dev/null +++ b/bundle/neomake/tests/fixtures/rust/cargo_error_without_span.json @@ -0,0 +1 @@ + {"message":{"children":[],"code":null,"level":"error","message":"aborting due to 18 previous errors","rendered":null,"spans":[]},"package_id":"derive_more 0.4.0 (path+file:///home/jelte/fun/derive_more)","reason":"compiler-message","target":{"kind":["proc-macro"],"name":"derive_more","src_path":"/home/jelte/fun/derive_more/lib.rs"}} diff --git a/bundle/neomake/tests/fixtures/rust/cargo_info.json b/bundle/neomake/tests/fixtures/rust/cargo_info.json new file mode 100644 index 000000000..24fb8f776 --- /dev/null +++ b/bundle/neomake/tests/fixtures/rust/cargo_info.json @@ -0,0 +1 @@ +{"features":["default"],"filenames":["/home/jelte/fun/derive_more/target/debug/deps/libunicode_xid-2c56e0ed90f93244.rlib"],"package_id":"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)","profile":{"debug_assertions":true,"debuginfo":true,"opt_level":"0","test":false},"reason":"compiler-artifact","target":{"kind":["lib"],"name":"unicode-xid","src_path":"/home/jelte/.cargo/registry/github.com-1ecc6299db9ec823/unicode-xid-0.0.3/lib.rs"}} diff --git a/bundle/neomake/tests/fixtures/rust/cargo_warning.json b/bundle/neomake/tests/fixtures/rust/cargo_warning.json new file mode 100644 index 000000000..42866d0e9 --- /dev/null +++ b/bundle/neomake/tests/fixtures/rust/cargo_warning.json @@ -0,0 +1 @@ +{"message":{"children":[],"code":null,"level":"warning","message":"unused import: `Variant`, #[warn(unused_imports)] on by default","rendered":null,"spans":[{"byte_end":8504,"byte_start":8497,"column_end":31,"column_start":24,"expansion":null,"file_name":"add_assign_like.rs","is_primary":true,"label":null,"line_end":2,"line_start":2,"suggested_replacement":null,"text":[{"highlight_end":31,"highlight_start":24,"text":"use syn::{Body, Ident, Variant, VariantData, MacroInput};"}]}]},"package_id":"derive_more 0.4.0 (path+file:///home/jelte/fun/derive_more)","reason":"compiler-message","target":{"kind":["proc-macro"],"name":"derive_more","src_path":"/home/jelte/fun/derive_more/lib.rs"}} diff --git a/bundle/neomake/tests/fixtures/rust/cargotest_with_failures b/bundle/neomake/tests/fixtures/rust/cargotest_with_failures new file mode 100644 index 000000000..cf3e02979 --- /dev/null +++ b/bundle/neomake/tests/fixtures/rust/cargotest_with_failures @@ -0,0 +1,20 @@ +error[E0433]: failed to resolve. Maybe a missing `extern crate non;`? + --> src/lib.rs:5:13 + | +5 | use non::existent::module; + | ^^^ Maybe a missing `extern crate non;`? + +warning: unused import: `non::existent::module` + --> src/lib.rs:5:13 + | +5 | use non::existent::module; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: #[warn(unused_imports)] on by default + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. + +To learn more, run the command again with --verbose. + diff --git a/bundle/neomake/tests/fixtures/vim/func-with-errors.vim b/bundle/neomake/tests/fixtures/vim/func-with-errors.vim new file mode 100644 index 000000000..38a7d728a --- /dev/null +++ b/bundle/neomake/tests/fixtures/vim/func-with-errors.vim @@ -0,0 +1,7 @@ +function! Foo() + if l:something + let foo = 1 + endif + echom foo . 'bar' +endfunction +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/tests/fixtures/vim/func-with-errors.vim.output b/bundle/neomake/tests/fixtures/vim/func-with-errors.vim.output new file mode 100644 index 000000000..cfe117f7c --- /dev/null +++ b/bundle/neomake/tests/fixtures/vim/func-with-errors.vim.output @@ -0,0 +1,2 @@ +tests/fixtures/vim/func-with-errors.vim:2:6:Error: EVL101: undefined variable `l:something` +tests/fixtures/vim/func-with-errors.vim:5:9:Error: EVL104: variable may not be initialized on some execution path: `l:foo` diff --git a/bundle/neomake/tests/fixtures/~ b/bundle/neomake/tests/fixtures/~ new file mode 100644 index 000000000..8d94924eb --- /dev/null +++ b/bundle/neomake/tests/fixtures/~ @@ -0,0 +1 @@ +" Test fixture file for ':edit ~' diff --git a/bundle/neomake/tests/ft_asciidoc.vader b/bundle/neomake/tests/ft_asciidoc.vader new file mode 100644 index 000000000..3bc5a07f7 --- /dev/null +++ b/bundle/neomake/tests/ft_asciidoc.vader @@ -0,0 +1,32 @@ +Include: include/setup.vader + +Execute (asciidoc): + Save &errorformat + let &errorformat = neomake#makers#ft#asciidoc#asciidoc().errorformat + new + file t.asciidoc + + lgetexpr + \ "asciidoc: WARNING: t.asciidoc: line 1: include file not found: /etc/asciidoc/asciidoc.css\n". + \ 'asciidoc: ERROR: t.asciidoc: line 2: only book doctypes can contain level 0 sections' + + AssertEqualQf getloclist(0), [ + \ {'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 0, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'W', + \ 'pattern': '', + \ 'text': 'include file not found: /etc/asciidoc/asciidoc.css'}, + \ {'lnum': 2, + \ 'bufnr': bufnr('%'), + \ 'col': 0, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'only book doctypes can contain level 0 sections'}] + bwipe diff --git a/bundle/neomake/tests/ft_cs.vader b/bundle/neomake/tests/ft_cs.vader new file mode 100644 index 000000000..6d4eebb53 --- /dev/null +++ b/bundle/neomake/tests/ft_cs.vader @@ -0,0 +1,32 @@ +Include: include/setup.vader + +Execute (cs: msbuild: errorformat): + Save &errorformat + let &errorformat = neomake#makers#ft#cs#msbuild().errorformat + new + file FooBar.cs + + lgetexpr "FooBar.cs(21,63): error CS1002: ; expected [Foo\Foobar.csproj]" + AssertEqualQf getloclist(0), [{ + \ 'lnum': 21, + \ 'bufnr': bufnr('%'), + \ 'col': 63, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': 1002, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': "; expected"}] + + lgetexpr "FooBar.cs(25,29): warning CS0168: The variable 'ex' is declared but never used [Foo\Foobar.csproj]" + AssertEqualQf getloclist(0), [{ + \ 'lnum': 25, + \ 'bufnr': bufnr('%'), + \ 'col': 29, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': 168, + \ 'type': 'W', + \ 'pattern': '', + \ 'text': "The variable 'ex' is declared but never used"}] + bwipe diff --git a/bundle/neomake/tests/ft_css.vader b/bundle/neomake/tests/ft_css.vader new file mode 100644 index 000000000..814e33ab1 --- /dev/null +++ b/bundle/neomake/tests/ft_css.vader @@ -0,0 +1,79 @@ +Include: include/setup.vader + +Execute (csslint: errorformat): + new + file file1 + let output = [ + \ "file1: line 315, col 1, Warning - Don't use IDs in selectors. (ids)", + \ "file1: Warning - You have 2 h1s, 3 h2s defined in this stylesheet. (unique-headings)'", + \ ] + + Save &errorformat + let &errorformat = neomake#makers#ft#css#csslint().errorformat + lgetexpr output + AssertEqualQf getloclist(0), [ + \ {'lnum': 315, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'W', 'pattern': '', + \ 'text': 'Don''t use IDs in selectors. (ids)'}, + \ {'lnum': 0, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'W', 'pattern': '', + \ 'text': 'You have 2 h1s, 3 h2s defined in this stylesheet. (unique-headings)'''}] + bwipe + +Execute (stylelint): + let bufname1 = tempname() + let bufname2 = tempname() + call writefile([], bufname1) + call writefile([], bufname2) + + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#css#stylelint(), [ + \ bufname1, + \ ' 6:5 ✖ Expected indentation of 1 tab indentation ', + \ ' 7:9 ✖ Expected indentation of 2 tabs indentation ', + \ '', + \ bufname2, + \ ' 45:2 ✖ Expected empty line before rule rule-empty-line-before', + \ '', + \ '/doesnotexist', + \ ' 26:36 ✖ Unexpected unit "px" unit-whitelist ', + \]) + + new + CallNeomake 1, [maker] + let buf1 = bufnr(bufname1) + let buf2 = bufnr(bufname2) + + " Without this patch entries are invalid always after setqflist/setloclist. + let valid_after_setlist = has('patch-8.0.0580') + + " Keeps non-existing filenames and entries (without bufnr). + " https://github.com/vim/vim/issues/2334 + AssertEqual map(getloclist(0), '[v:val.valid, v:val.bufnr, v:val.text]'), [ + \ [1, buf1, 'Expected indentation of 1 tab [indentation]'], + \ [1, buf1, 'Expected indentation of 2 tabs [indentation]'], + \ [1, buf2, 'Expected empty line before rule [rule-empty-line-before]'], + \ [0, 0, '/doesnotexist'], + \ [valid_after_setlist, 0, 'Unexpected unit "px" [unit-whitelist]'] + \ ] + bwipe + exe buf1 'bwipe' + exe buf2 'bwipe' + +Execute (stylelint: error with no config): + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#css#stylelint(), [ + \ 'Error: No configuration provided for /path/to/foo.css', + \ ' at module.exports (/usr/lib/node_modules/stylelint/lib/utils/configurationError.js:8:28)', + \ ' at stylelint._fullExplorer.load.then.then.config (/usr/lib/node_modules/stylelint/lib/getConfigForFile.js:46:15)', + \ ' at ', + \]) + + new + CallNeomake 1, [maker] + + let bufnr = bufnr('/path/to/foo.css') + AssertEqualQf getloclist(0), [{ + \ 'lnum': 0, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'E', 'pattern': '', + \ 'text': 'Error: No configuration provided for /path/to/foo.css'}] + bwipe + exe bufnr.'bwipe' diff --git a/bundle/neomake/tests/ft_elixir.vader b/bundle/neomake/tests/ft_elixir.vader new file mode 100644 index 000000000..07eb18b3a --- /dev/null +++ b/bundle/neomake/tests/ft_elixir.vader @@ -0,0 +1,23 @@ +Include: include/setup.vader + +Execute (Credo: postprocess: type): + function! s:F(entry) + call neomake#makers#ft#elixir#PostprocessCredo(a:entry) + return a:entry + endfunction + AssertEqual s:F({'type': 'C'}).type, 'W' + AssertEqual s:F({'type': 'F'}).type, 'W' + + let g:neomake_elixir_credo_config_typemap = {'F': 'Z'} + AssertEqual s:F({'type': 'F'}).type, 'Z' + +Execute (Mix: postprocess: line is never higher than buffer size): + function! s:F(entry) + call neomake#makers#ft#elixir#PostprocessEnforceMaxBufferLine(a:entry) + return a:entry + endfunction + norm! ggdG + norm! iline1 + norm! oline2 + AssertEqual s:F({'lnum': 3}).lnum, 2 + AssertEqual s:F({'lnum': 1}).lnum, 1 diff --git a/bundle/neomake/tests/ft_elm.vader b/bundle/neomake/tests/ft_elm.vader new file mode 100644 index 000000000..b4e60c0e3 --- /dev/null +++ b/bundle/neomake/tests/ft_elm.vader @@ -0,0 +1,34 @@ +Include: include/setup.vader + +Execute (elmMake parses success message): + let json = 'Successfully generated /dev/null' + + let result = neomake#makers#ft#elm#elmMake().process_output({'output': [json]}) + + AssertEqual [], result + +Execute (elmMake parses error message): + let json = '[{"tag":"BAD MAIN TYPE","overview":"The `main` value has an unsupported type.","subregion":null,"details":"I need Html, Svg, or a Program so I have something to render on screen, but you\ngave me:\n\n String","region":{"start":{"line":6,"column":1},"end":{"line":6,"column":5}},"type":"error","file":"Bingo.elm"}]' + + let result = neomake#makers#ft#elm#elmMake().process_output({'output': [json]}) + + AssertEqual [{ + \ 'type': 'E', + \ 'lnum': 6, + \ 'col': 1, + \ 'length': 4, + \ 'filename': 'Bingo.elm', + \ 'text': 'BAD MAIN TYPE : The `main` value has an unsupported type.'}], result + +Execute (elmMake parses warning message): + let json = '[{"tag":"unused import","overview":"Module `Html` is unused.","details":"Best to remove it. Don''t save code quality for later!","region":{"start":{"line":3,"column":1},"end":{"line":3,"column":12}},"type":"warning","file":"Bingo.elm"}]' + + let result = neomake#makers#ft#elm#elmMake().process_output({'output': [json]}) + + AssertEqual [{ + \ 'type': 'W', + \ 'lnum': 3, + \ 'col': 1, + \ 'length': 11, + \ 'filename': 'Bingo.elm', + \ 'text': 'unused import : Module `Html` is unused.'}], result diff --git a/bundle/neomake/tests/ft_erlang.vader b/bundle/neomake/tests/ft_erlang.vader new file mode 100644 index 000000000..02bc2598f --- /dev/null +++ b/bundle/neomake/tests/ft_erlang.vader @@ -0,0 +1,162 @@ +Include: include/setup.vader + +Execute (erlc: common settings): + new + file src/myapp.erl + + let args = neomake#makers#ft#erlang#GlobPaths() + AssertEqual args[:-2], ['-pa', 'ebin', '-I', 'include', '-I', 'src', '-o'] + let output_dir = args[-1] + Assert isdirectory(output_dir) + bwipe + +Execute (erlc: output to _build/neomake if _build is present): + let old_cwd = getcwd() + try + let root = tempname() + call mkdir(root, 'p') + execute 'cd ' . root + + call mkdir('_build', 'p') + new + file src/myapp.erl + + let args = neomake#makers#ft#erlang#GlobPaths() + let output_dir = args[-1] + Assert output_dir =~# '/_build/neomake$' + Assert isdirectory(output_dir) + bwipe + finally + execute 'cd ' . old_cwd + endtry + +Execute (erlc: rebar3 default profile - no rebar.config): + let old_cwd = getcwd() + try + let root = tempname() + call mkdir(root, 'p') + execute 'cd ' . root + + call mkdir('_build/default/lib/dep1/ebin', 'p') + new + file src/myapp.erl + + let args = neomake#makers#ft#erlang#GlobPaths() + let dep1_ebin_opt = args[6:7] + let dep1_include_opt = args[8:9] + AssertEqual ['-pa', root . '/_build/default/lib/dep1/ebin'], dep1_ebin_opt + AssertEqual ['-I', root . '/_build/default/lib/dep1/include'], dep1_include_opt + bwipe + finally + execute 'cd ' . old_cwd + endtry + + +Execute (erlc: rebar3 default profile): + let old_cwd = getcwd() + try + let root = tempname() + call mkdir(root, 'p') + execute 'cd ' . root + + call mkdir('_build/default/lib/dep1/ebin', 'p') + write rebar.config + bwipe rebar.config + new + file src/myapp.erl + + let args = neomake#makers#ft#erlang#GlobPaths() + let dep1_ebin_opt = args[6:7] + let dep1_include_opt = args[8:9] + AssertEqual ['-pa', root . '/_build/default/lib/dep1/ebin'], dep1_ebin_opt + AssertEqual ['-I', root . '/_build/default/lib/dep1/include'], dep1_include_opt + bwipe + finally + execute 'cd ' . old_cwd + endtry + +Execute (erlc: rebar3 test profile): + let old_cwd = getcwd() + try + let root = tempname() + call mkdir(root, 'p') + execute 'cd ' . root + + call mkdir('_build/test/lib/dep1/ebin', 'p') + new + file test/myapp_SUITE.erl + + let args = neomake#makers#ft#erlang#GlobPaths() + let dep1_ebin_opt = args[6:7] + let dep1_include_opt = args[8:9] + AssertEqual ['-pa', root . '/_build/test/lib/dep1/ebin'], dep1_ebin_opt + AssertEqual ['-I', root . '/_build/test/lib/dep1/include'], dep1_include_opt + bwipe + finally + execute 'cd ' . old_cwd + endtry + +Execute (erlc: rebar2/erlang.mk deps/ present): + let old_cwd = getcwd() + try + let root = tempname() + call mkdir(root, 'p') + execute 'cd ' . root + + call mkdir('deps/dep1/ebin', 'p') + new + file src/myapp.erl + + let args = neomake#makers#ft#erlang#GlobPaths() + let dep1_ebin_opt = args[6:7] + let dep1_include_opt = args[8:9] + AssertEqual ['-pa', root . '/deps/dep1/ebin'], dep1_ebin_opt + AssertEqual ['-I', root . '/deps/dep1/include'], dep1_include_opt + bwipe + finally + execute 'cd ' . old_cwd + endtry + +Execute (erlc: buffer local extra deps): + let old_cwd = getcwd() + try + let root = tempname() + call mkdir(root, 'p') + execute 'cd ' . root + + call mkdir('deps.local/dep1/ebin', 'p') + new + file src/myapp.erl + let b:neomake_erlang_erlc_extra_deps = ['deps.local'] + + let args = neomake#makers#ft#erlang#GlobPaths() + let dep1_ebin_opt = args[6:7] + let dep1_include_opt = args[8:9] + AssertEqual ['-pa', 'deps.local/dep1/ebin'], dep1_ebin_opt + AssertEqual ['-I', 'deps.local/dep1/include'], dep1_include_opt + bwipe + finally + execute 'cd ' . old_cwd + endtry + +Execute (erlc: buffer local profile override): + let old_cwd = getcwd() + try + let root = tempname() + call mkdir(root, 'p') + execute 'cd ' . root + + call mkdir('_build/test/lib/dep1/ebin', 'p') + new + file config/not_a_SUITE_file.erl + let b:neomake_erlang_erlc_rebar3_profile = 'test' + + let args = neomake#makers#ft#erlang#GlobPaths() + let dep1_ebin_opt = args[6:7] + let dep1_include_opt = args[8:9] + AssertEqual ['-pa', root . '/_build/test/lib/dep1/ebin'], dep1_ebin_opt + AssertEqual ['-I', root . '/_build/test/lib/dep1/include'], dep1_include_opt + bwipe + finally + execute 'cd ' . old_cwd + endtry diff --git a/bundle/neomake/tests/ft_go.vader b/bundle/neomake/tests/ft_go.vader new file mode 100644 index 000000000..508482d6a --- /dev/null +++ b/bundle/neomake/tests/ft_go.vader @@ -0,0 +1,57 @@ +Include: include/setup.vader + +Execute (go: go): + new + file build/proxier.go + + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#go#go(), [ + \ 'proxier.go:24:2: cannot find package "bytes" in any of:', + \ ' /home/user/bin/go1.x/src/bytes (from $GOROOT)', + \ ' /home/user/go/src/bytes (from $GOPATH)', + \ ]) + CallNeomake 1, [maker] + + AssertNeomakeMessage printf('cwd: %s/build (changed).', getcwd()) + AssertNeomakeMessage 'Processing 3 lines of output.' + AssertNeomakeMessage 'Processing 1 entries.' + AssertEqualQf getloclist(0), [ + \ {'lnum': 24, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'E', 'pattern': '', + \ 'text': 'cannot find package "bytes" in any of: ' + \ .'/home/user/bin/go1.x/src/bytes (from $GOROOT) ' + \ .'/home/user/go/src/bytes (from $GOPATH)'}] + bwipe + +Execute (go: go: filters "[no test files]"): + new + file rain.go + + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#go#go(), [ + \ '? github.com/cenkalti/rain/rainrpc [no test files]', + \ ]) + CallNeomake 1, [maker] + + AssertEqual getloclist(0), [] + bwipe + +Execute (go: gometalinter): + new + file git.go + + let &efm = neomake#makers#ft#go#gometalinter().errorformat + lgetexpr 'git.go:17::warning: Subprocess launching with variable.,HIGH,HIGH (gas)' + AssertEqualQf getloclist(0), [ + \ {'lnum': 17, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'Subprocess launching with variable.,HIGH,HIGH (gas)'}, + \ ] + bwipe + +Execute (go: golangci_lint): + new + file main.go + + let &efm = neomake#makers#ft#go#golangci_lint().errorformat + lgetexpr 'main.go:288:7: no new variables on left side of := (typecheck)' + AssertEqualQf getloclist(0), [ + \ {'lnum': 288, 'bufnr': bufnr('%'), 'col': 7, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'no new variables on left side of := (typecheck)'}, + \ ] + bwipe diff --git a/bundle/neomake/tests/ft_haskell.vader b/bundle/neomake/tests/ft_haskell.vader new file mode 100644 index 000000000..63e3ba9bc --- /dev/null +++ b/bundle/neomake/tests/ft_haskell.vader @@ -0,0 +1,39 @@ +Include: include/setup.vader + +Execute (neomake#makers#ft#haskell#HlintEntryProcess): + function! s:F(text) + let entry = {'text': a:text} + call neomake#makers#ft#haskell#HlintEntryProcess(entry) + return entry.text + endfunction + + let simple = + \"Use fmap\n + \ Found:\n + \ liftM\n + \ Why not:\n + \ fmap" + + let extra_whitespace = + \"Use fmap\n + \ Found:\n + \ liftM\n + \ Why not:\n + \ fmap" + + AssertEqual s:F(simple), 'Use fmap | Found: liftM | Why not: fmap' + AssertEqual s:F(extra_whitespace), 'Use fmap | Found: liftM | Why not: fmap' + + let multiline_code = + \"Use fromMaybe\n + \ Found:\n + \ case findIndex (not . null) xs of\n + \ Just ix -> ix\n + \ Nothing -> -1\n + \ Why not:\n + \ fromMaybe (-1) (findIndex (not . null) xs)" + + AssertEqual s:F(multiline_code), + \ 'Use fromMaybe | ' . + \ 'Found: case findIndex (not . null) xs of Just ix -> ix Nothing -> -1 | ' . + \ 'Why not: fromMaybe (-1) (findIndex (not . null) xs)' diff --git a/bundle/neomake/tests/ft_html.vader b/bundle/neomake/tests/ft_html.vader new file mode 100644 index 000000000..e56520c70 --- /dev/null +++ b/bundle/neomake/tests/ft_html.vader @@ -0,0 +1,17 @@ +Include: include/setup.vader + +Execute (html: htmlhint): + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#html#htmlhint(), [ + \ 'test.html:1:1: Doctype must be declared first. [error/doctype-first]', + \ 'test.html:11:1: Tag must be paired, missing: [

], open tag match failed [

] on line 8. [error/tag-pair]', + \ '', + \ '99 problems', + \ ]) + new + file test.html + CallNeomake 1, [maker] + AssertEqualQf getloclist(0), [ + \ {'lnum': 1, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'W', 'pattern': '', 'text': 'Doctype must be declared first. [error/doctype-first]'}, + \ {'lnum': 11, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'W', 'pattern': '', 'text': 'Tag must be paired, missing: [

], open tag match failed [

] on line 8. [error/tag-pair]'} + \ ] + bwipe diff --git a/bundle/neomake/tests/ft_idris.vader b/bundle/neomake/tests/ft_idris.vader new file mode 100644 index 000000000..0578ca6c9 --- /dev/null +++ b/bundle/neomake/tests/ft_idris.vader @@ -0,0 +1,30 @@ +Include: include/setup.vader + +Execute (idris: makers): + AssertEqual neomake#GetMakers('idris'), ['idris'] + +Execute (idris: errorformat): + " Test errorformat itself. + let idris_output = + \"t.idr:6:1-4:When checking left hand side of xor:\n + \When checking an application of Main.xor:\n + \ Type mismatch between\n + \ Integer (Type of 5)\n + \ and\n + \ Bool (Expected type)" + + Save &errorformat + let &errorformat = neomake#makers#ft#idris#idris().errorformat + lgetexpr idris_output + AssertEqual len(getloclist(0)), 1 + AssertEqual getloclist(0)[0].text, "4:When checking left hand side of xor:\n + \Type mismatch between\n + \Integer (Type of 5)\n + \and\n + \Bool (Expected type)" + + let entry = getloclist(0)[0] + call call(neomake#makers#ft#idris#idris().postprocess, [entry]) + AssertEqual entry.text, 'Type mismatch between Integer (Type of 5) and Bool (Expected type)' + AssertEqual entry.length, 3 + bwipe t.idr diff --git a/bundle/neomake/tests/ft_javascript.vader b/bundle/neomake/tests/ft_javascript.vader new file mode 100644 index 000000000..68fb84d5d --- /dev/null +++ b/bundle/neomake/tests/ft_javascript.vader @@ -0,0 +1,101 @@ +Include: include/setup.vader + +Execute (javascript: eslint: errorformat): + Save &errorformat + let &errorformat = neomake#makers#ft#javascript#eslint().errorformat + new + file errors.js + let bufnr = bufnr('%') + + let output = [ + \ "errors.js: line 2, col 10, Error - 'some_unused_var' is defined but never used. (no-unused-vars)", + \ '', + \ '1 problem', + \ ] + + lgetexpr output + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, + \ 'bufnr': bufnr, + \ 'col': 10, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': "'some_unused_var' is defined but never used. (no-unused-vars)"}] + + let output = [ + \ "errors.js: line 2, col 10, Error - 'some_unused_var' is defined but never used. (no-unused-vars)", + \ "errors.js: line 3, col 20, Warning - Missing semicolon. (semi)", + \ '', + \ '2 problems', + \ ] + + lgetexpr output + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, + \ 'bufnr': bufnr, + \ 'col': 10, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': "'some_unused_var' is defined but never used. (no-unused-vars)", + \ }, { + \ 'lnum': 3, + \ 'bufnr': bufnr, + \ 'col': 20, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'W', + \ 'pattern': '', + \ 'text': 'Missing semicolon. (semi)'}] + bwipe + +Execute (javascript: standard: errorformat): + Save &errorformat + let &errorformat = neomake#makers#ft#javascript#standard().errorformat + + new + file /path/to/file.js + let output = [ + \ 'standard: Use JavaScript Standard Style (https://standardjs.com)', + \ 'standard: Run `standard --fix` to automatically fix some problems.', + \ ' /path/to/file.js:1:1: Expected an assignment or function call and instead saw an expression. (no-unused-expressions)', + \ ] + lgetexpr output + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'W', 'pattern': '', + \ 'text': 'Expected an assignment or function call and instead saw an expression. (no-unused-expressions)'}] + bwipe + +Execute (javascript: flow: no errors): + new + let flow_maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#javascript#flow(), [ + \ 'No errors!', + \ ]) + CallNeomake 1, [flow_maker] + AssertEqual getloclist(0), [] + bwipe + +Execute (javascript: flow: no trailing newline): + new + file index.js + let flow_maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#javascript#flow(), [ + \ 'File "index.js", line 9, characters 10-11', + \ 'Error: Cannot call `list` because a callable signature is missing in exports [1].', + \ '', + \ ]) + CallNeomake 1, [flow_maker] + AssertEqualQf getloclist(0), [ + \ {'lnum': 9, 'bufnr': bufnr('%'), 'col': 10, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'E', 'pattern': '', + \ 'text': 'Error: Cannot call `list` because a callable signature is missing in exports [1].'}, + \ ] + " Replaced newline in log message. + AssertNeomakeMessage "\\VModified list entry 1 (postprocess): {'changed': {'text': ['11\\\\nError: Cannot call `list` because a callable signature is missing in exports [1].', 'Error: Cannot call `list` because a callable signature is missing in exports [1].']}, 'added': {'length': 2}}." + bwipe diff --git a/bundle/neomake/tests/ft_markdown.vader b/bundle/neomake/tests/ft_markdown.vader new file mode 100644 index 000000000..ddf9a48ff --- /dev/null +++ b/bundle/neomake/tests/ft_markdown.vader @@ -0,0 +1,66 @@ +Include: include/setup.vader + +Execute (markdown: vale): + new + file README.md + let mock = [ + \ '{', + \ ' "README.md": [', + \ ' {', + \ ' "Check": "vale.Hedging",', + \ ' "Description": "",', + \ ' "Line": 22,', + \ ' "Link": "",', + \ " \"Message\": \"Consider removing 'probably'\",", + \ ' "Severity": "warning",', + \ ' "Span": [', + \ ' 45,', + \ ' 52', + \ ' ],', + \ ' "Hide": false,', + \ ' "Match": ""', + \ ' }', + \ ' ]', + \ '}', + \ '', + \ ] + let vale_maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#markdown#vale(), mock) + CallNeomake 1, [vale_maker] + AssertEqualQf getloclist(0), [ + \ { + \ 'lnum': 22, + \ 'bufnr': bufnr('%'), + \ 'col': 45, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'W', + \ 'pattern': '', + \ 'text': "Consider removing 'probably'" + \ } + \ ] + bwipe + + +Execute (markdown: mdl): + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#markdown#mdl(), [ + \ 'README.md:1: MD033 Inline HTML', + \ '', + \ 'A detailed description of the rules is available at https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md', + \ ]) + + new + noautocmd file README.md + CallNeomake 1, [maker] + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 0, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': 33, + \ 'type': 'W', + \ 'pattern': '', + \ 'text': 'Inline HTML (MD033)', + \ }] + bwipe diff --git a/bundle/neomake/tests/ft_perl.vader b/bundle/neomake/tests/ft_perl.vader new file mode 100644 index 000000000..9a11f35ad --- /dev/null +++ b/bundle/neomake/tests/ft_perl.vader @@ -0,0 +1,27 @@ +Include: include/setup.vader + +Execute (perl: errorformat): + let perl_output = + \"Global symbol \"$value\" requires explicit package name at /home/test/test.pl line 3.\n + \/home/test/test.pl had compilation errors." + + Save &errorformat + let &errorformat = neomake#makers#ft#perl#perl().errorformat + lgetexpr perl_output + AssertEqual len(getloclist(0)), 1 + AssertEqual getloclist(0)[0].text, 'Global symbol "$value" requires explicit package name' + + let syntax_ok = "/home/test/test.pl syntax OK" + lgetexpr syntax_ok + AssertEqual getloclist(0), [] + bwipe /home/test/test.pl + +Execute (perl: postprocess): + let entry = {'text': 'text', 'pattern': ''} + + call neomake#makers#ft#perl#PerlEntryProcess(entry) + AssertEqual entry.text, 'text' + + let entry.pattern = 'pattern' + call neomake#makers#ft#perl#PerlEntryProcess(entry) + AssertEqual entry.text, 'text pattern' diff --git a/bundle/neomake/tests/ft_php.vader b/bundle/neomake/tests/ft_php.vader new file mode 100644 index 000000000..c56cb8db7 --- /dev/null +++ b/bundle/neomake/tests/ft_php.vader @@ -0,0 +1,91 @@ +Include: include/setup.vader + +Execute (php): + let php_output = + \"Fatal error: Call to undefined function hello() in /app/src/hello.php on line 1" + + Save &errorformat + let &errorformat = neomake#makers#ft#php#php().errorformat + lgetexpr php_output + + let loclist = getloclist(0) + AssertEqual len(loclist), 1 + AssertEqual loclist[0].lnum, 1 + AssertEqual loclist[0].type, 'E' + AssertEqual loclist[0].text, 'Call to undefined function hello()' + bwipe /app/src/hello.php + +Execute (phpcs): + let phpcs_output = + \"\"/app/src/TaskService.php\",28,6,error,\"Missing @return tag in functioncomment\",PEAR.Commenting.FunctionComment.MissingReturn,5,0\n + \\"/app/src/TaskService.php\",36,5,error,\"Missing short description in doc comment\",Generic.Commenting.DocComment.MissingShort,5,0" + + Save &errorformat + let &errorformat = neomake#makers#ft#php#phpcs().errorformat + lgetexpr phpcs_output + + let loclist = getloclist(0) + AssertEqual len(loclist), 2 + AssertEqual loclist[0].lnum, 28 + AssertEqual loclist[0].col, 6 + AssertEqual loclist[0].text, 'Missing @return tag in functioncomment' + AssertEqual loclist[0].type, 'e' + AssertEqual loclist[1].lnum, 36 + AssertEqual loclist[1].col, 5 + AssertEqual loclist[1].text, 'Missing short description in doc comment' + AssertEqual loclist[1].type, 'e' + bwipe /app/src/TaskService.php + +Execute (phpmd): + let phpmd_output = + \"/app/src/AppBundle/Controller/DefaultController.php:16 Avoid unused parameters such as '$request'.\n + \/app/src/AppBundle/Controller/DefaultController.php:48 Avoid variables with short names like $id. Configured minimumlength is 3." + + Save &errorformat + let &errorformat = neomake#makers#ft#php#phpmd().errorformat + lgetexpr phpmd_output + + let loclist = getloclist(0) + AssertEqual len(loclist), 2 + AssertEqual loclist[0].lnum, 16 + AssertEqual loclist[0].text, "Avoid unused parameters such as '$request'." + AssertEqual loclist[0].type, 'W' + AssertEqual loclist[1].lnum, 48 + AssertEqual loclist[1].text, "Avoid variables with short names like $id. Configured minimumlength is 3." + AssertEqual loclist[1].type, 'W' + bwipe /app/src/AppBundle/Controller/DefaultController.php + +Execute (phpstan): + let phpstan_output = + \"/app/src/hello.php:6:Function dsdsd not found" + + Save &errorformat + let &errorformat = neomake#makers#ft#php#phpstan().errorformat + lgetexpr phpstan_output + + let loclist = getloclist(0) + AssertEqual len(loclist), 1 + AssertEqual loclist[0].lnum, 6 + AssertEqual loclist[0].text, "Function dsdsd not found" + AssertEqual loclist[0].type, 'E' + bwipe /app/src/hello.php + +Execute (php: psalm): + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#php#psalm(), [ + \ 'test.php:85: [E0001] MismatchingDocblockParamType: Parameter $questionnaire has wrong type ''App\Services\Service'', should be ''App\Service'' (column 15)', + \ 'test.php:179: [W0001] RedundantCondition: Found a redundant condition when evaluating $existingQuestion and trying to reconcile it with a non-falsy assertion (column 44)', + \]) + new + noautocmd file test.php + let bufnr = bufnr('%') + CallNeomake 1, [maker] + AssertEqualQf getloclist(0), [ + \ {'lnum': 85, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': 1, 'type': 'E', 'pattern': '', + \ 'text': 'MismatchingDocblockParamType: Parameter $questionnaire has wrong type ''App\Services\Service'', should be ''App\Service'' (column 15)' + \ }, { + \ 'lnum': 179, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': 1, 'type': 'W', 'pattern': '', + \ 'text': 'RedundantCondition: Found a redundant condition when evaluating $existingQuestion and trying to reconcile it with a non-falsy assertion (column 44)', + \ }] + bwipe diff --git a/bundle/neomake/tests/ft_puppet.vader b/bundle/neomake/tests/ft_puppet.vader new file mode 100644 index 000000000..0326d89f3 --- /dev/null +++ b/bundle/neomake/tests/ft_puppet.vader @@ -0,0 +1,91 @@ +Include: include/setup.vader + +Execute (puppet: syntax error: end of input): + new + let maker = NeomakeTestsFixtureMaker('neomake#makers#ft#puppet#puppet', + \ 'tests/fixtures/input/puppet/syntax-error-eoi.pp') + CallNeomake 1, [maker] + + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'lnum': 0, + \ 'bufnr': bufnr, + \ 'col': 0, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'Syntax error at end of input' + \ }] + bwipe + +Execute (puppet: syntax error in specific line): + new + let maker = NeomakeTestsFixtureMaker('neomake#makers#ft#puppet#puppet', + \ 'tests/fixtures/input/puppet/syntax-error.pp') + CallNeomake 1, [maker] + + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'lnum': 3, + \ 'bufnr': bufnr, + \ 'col': 3, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': "Syntax error at 'file'" + \ }] + bwipe + +Execute (puppet-lint): + new + let maker = NeomakeTestsFixtureMaker('neomake#makers#ft#puppet#puppetlint', + \ 'tests/fixtures/input/puppet-lint/err_and_warn.pp') + CallNeomake 1, [maker] + + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [ { + \ 'lnum': 4, + \ 'bufnr': bufnr, + \ 'col': 10, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'w', + \ 'pattern': '', + \ 'text': '[arrow_alignment] indentation of => is not properly aligned (expected in column 12, but found it in column 10)' + \ } , { + \ 'lnum': 1, + \ 'bufnr': bufnr, + \ 'col': 7, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'e', + \ 'pattern': '', + \ 'text': '[autoloader_layout] foo not in autoload module layout' + \ } , { + \ 'lnum': 2, + \ 'bufnr': bufnr, + \ 'col': 10, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'w', + \ 'pattern': '', + \ 'text': '[double_quoted_strings] double quoted string containing no variables' + \ } , { + \ 'lnum': 1, + \ 'bufnr': bufnr, + \ 'col': 1, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'w', + \ 'pattern': '', + \ 'text': '[documentation] class not documented' + \ }] + bwipe diff --git a/bundle/neomake/tests/ft_purescript.vader b/bundle/neomake/tests/ft_purescript.vader new file mode 100644 index 000000000..59d656f92 --- /dev/null +++ b/bundle/neomake/tests/ft_purescript.vader @@ -0,0 +1,53 @@ +Include: include/setup.vader + +Execute (pulp parses success message): + new + file src/Main.purs + let output = [ + \ '* Building project in /home/test/purescript/', + \ '{"warnings":[],"errors":[]}', + \ '* Build successful.', + \ ] + let result = neomake#makers#ft#purescript#pulp().process_output({'output': output}) + AssertEqual [], result + bwipe + +Execute (pulp parses error message): + new + file src/Main.purs + let output = [ + \ '* Building project in /home/test/purescript/', + \ '{"warnings":[],"errors":[{"position":{"startLine":4,"startColumn":1,"endLine":4,"endColumn":14},"message":" Type variable a is undefined.\n\nwhile checking the kind of a -> a\nin value declaration foo\n","errorCode":"UndefinedTypeVariable","errorLink":"https://github.com/purescript/documentation/blob/master/errors/UndefinedTypeVariable.md","filename":"src/Other.purs","moduleName":"Other","suggestion":null}]}', + \ 'Compiling Other', + \ '* ERROR: Subcommand terminated with exit code 1', + \ ] + let result = neomake#makers#ft#purescript#pulp().process_output({'output': output}) + AssertEqual [{ + \ 'lnum': 4, + \ 'filename': 'src/Other.purs', + \ 'col': 1, + \ 'length': 13, + \ 'type': 'E', + \ 'text': "UndefinedTypeVariable : Type variable a is undefined.\n\nwhile checking the kind of a -> a\nin value declaration foo\n", + \ }], result + bwipe + +Execute (pulp parses warning message): + new + file src/Main.purs + let output = [ + \ '* Building project in /home/test/purescript', + \ '{"warnings":[{"position":{"startLine":3,"startColumn":1,"endLine":3,"endColumn":40},"message":" The import of module Prelude contains the following unused references:\n\n unit\n pure\n bind\n\n It could be replaced with:\n\n import Prelude (Unit)\n","errorCode":"UnusedExplicitImport","errorLink":"https://github.com/purescript/documentation/blob/master/errors/UnusedExplicitImport.md","filename":"src/Main.purs","moduleName":"Main","suggestion":{"replacement":"import Prelude (Unit)\n","replaceRange":{"startLine":3,"startColumn":1,"endLine":3,"endColumn":40}}}],"errors":[]}', + \ 'Compiling Main', + \ '* Build successful', + \ ] + let result = neomake#makers#ft#purescript#pulp().process_output({'output': output}) + AssertEqual [{ + \ 'lnum': 3, + \ 'filename': 'src/Main.purs', + \ 'col': 1, + \ 'type': 'W', + \ 'length': 39, + \ 'text': "UnusedExplicitImport : The import of module Prelude contains the following unused references:\n\n unit\n pure\n bind\n\n It could be replaced with:\n\n import Prelude (Unit)\n", + \ }], result + bwipe diff --git a/bundle/neomake/tests/ft_python.vader b/bundle/neomake/tests/ft_python.vader new file mode 100644 index 000000000..f706a1083 --- /dev/null +++ b/bundle/neomake/tests/ft_python.vader @@ -0,0 +1,434 @@ +Include: include/setup.vader + +Execute (python: errorformat): + new + e tests/fixtures/errors.py + call neomake#config#set('b:ft.python.python.exe', 'python3') + Neomake python + NeomakeTestsWaitForFinishedJobs + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 16, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'unexpected EOF while parsing'}] + bwipe + +Execute (python: pylama: errorformat): + Save &errorformat + let &errorformat = neomake#makers#ft#python#pylama().errorformat + new + file file1.py + lgetexpr "file1.py:16:1: [C] C901 'load_library' is too complex (13) [mccabe]" + AssertEqualQf getloclist(0), [ + \ {'lnum': 16, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'C', 'pattern': '', + \ 'text': 'C901 ''load_library'' is too complex (13) [mccabe]'}] + + let e = getloclist(0)[0] + call neomake#makers#ft#python#PylamaEntryProcess(e) + AssertEqualQf [e], [{ + \ 'lnum': 16, + \ 'bufnr': bufnr('%'), + \ 'col': 1, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': 901, + \ 'type': 'I', + \ 'pattern': '', + \ 'text': "C901 'load_library' is too complex (13) [mccabe]"}] + bwipe + +Execute (python: pylama: cwd): + let tempdir = tempname() + call mkdir(tempdir) + + new + exe 'lcd '.tempdir + let maker = neomake#makers#ft#python#pylama() + if has_key(maker, 'cwd') + " Might happen with e.g. an existing /tmp/setup.cwd.. + call vader#log(printf('NOTE: got cwd already: %s', maker.cwd)) + endif + + call mkdir('pylama/subdir', 'p') + call writefile([], 'pylama/setup.cfg') + lcd pylama/subdir + let maker = neomake#makers#ft#python#pylama() + AssertEqual maker.cwd, tempdir . neomake#utils#Slash() . 'pylama' + bwipe + +Execute (python: flake8: errorformat/postprocess: F811): + Save &errorformat + let &errorformat = neomake#makers#ft#python#flake8().errorformat + + new + file file1.py + norm Iimport os + norm oimport os . path as os + norm ofrom os import os + lgetexpr "file1.py:2:1: F811 redefinition of unused 'os' from line 1" + + AssertEqualQf getloclist(0), [ + \ {'lnum': 2, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, + \ 'nr': 811, 'type': 'F', 'pattern': '', + \ 'text': "redefinition of unused 'os' from line 1"}] + + let e = getloclist(0)[0] + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqualQf [e], [{ + \ 'lnum': 2, + \ 'bufnr': bufnr('%'), + \ 'col': 21, + \ 'pattern': '', + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'length': 2, + \ 'type': 'E', + \ 'text': "F811 redefinition of unused 'os' from line 1"}] + + lgetexpr "file1.py:3:1: F811 redefinition of unused 'os' from line 2" + + AssertEqualQf getloclist(0), [ + \ {'lnum': 3, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, + \ 'nr': 811, 'type': 'F', 'pattern': '', + \ 'text': "redefinition of unused 'os' from line 2"}] + + let e = getloclist(0)[0] + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqualQf [e], [{ + \ 'lnum': 3, + \ 'bufnr': bufnr('%'), + \ 'col': 16, + \ 'pattern': '', + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'length': 2, + \ 'type': 'E', + \ 'text': "F811 redefinition of unused 'os' from line 2"}] + bwipe! + +Execute (python: flake8: format of current error msg): + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#python#flake8(), [ + \ 'file1.py:1:1: F811 redefinition of unused ''os'' from line 1', + \ ]) + let maker.name = 'flake8' + new + file file1.py + CallNeomake 1, [maker] + AssertEqual line('.'), 1 + AssertEqual neomake#GetCurrentErrorMsg(), + \ 'flake8: F811 redefinition of unused ''os'' from line 1 (E)' + bwipe + +Execute (flake8: postprocess for F821 in continuous f-strings): + new + let bufnr = bufnr('%') + file t-undefined-in-fstring.py + call append(0, [ + \ 'bar', + \ 'BAZ = 1', + \ 'foo = (f"prefix {foo}"', + \ ' f"prefix {BAZ} {baz} {obj.attr} {f(arg)}")', + \ ]) + + " Output from flake8: + " t-undefined-in-fstring.py:1:1: F821 undefined name 'bar' + " t-undefined-in-fstring.py:3:9: F821 undefined name 'baz' + " t-undefined-in-fstring.py:3:9: F821 undefined name 'obj' + " t-undefined-in-fstring.py:3:9: F821 undefined name 'f' + " t-undefined-in-fstring.py:3:11: F821 undefined name 'arg' + " t-undefined-in-fstring.py:3:18: F821 undefined name 'foo' + + let e = {'lnum': 1, 'bufnr': bufnr, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': 821, 'type': 'F', 'pattern': '', 'text': 'F821 undefined name ''bar'''} + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqual [e.lnum, e.col, e.length], [1, 1, 3] + + " Correct for first line in f-string. + let e = {'lnum': 3, 'bufnr': bufnr, 'col': 18, 'valid': 1, 'vcol': 0, 'nr': 821, 'type': 'F', 'pattern': '', 'text': 'F821 undefined name ''foo'''} + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqual [e.lnum, e.col, e.length], [3, 18, 3] + + " Needs adjustment for second line in f-string. + let e = {'lnum': 3, 'bufnr': bufnr, 'col': 9, 'valid': 1, 'vcol': 0, 'nr': 821, 'type': 'F', 'pattern': '', 'text': 'F821 undefined name ''baz'''} + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqual [e.lnum, e.col, e.length], [4, 24, 3] + + " Needs adjustment for second line in f-string, handling objects. + let e = {'lnum': 3, 'bufnr': bufnr, 'col': 9, 'valid': 1, 'vcol': 0, 'nr': 821, 'type': 'F', 'pattern': '', 'text': 'F821 undefined name ''obj'''} + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqual [e.lnum, e.col, e.length], [4, 30, 3] + + " Needs adjustment for second line in f-string, handling func. + let e = {'lnum': 3, 'bufnr': bufnr, 'col': 9, 'valid': 1, 'vcol': 0, 'nr': 821, 'type': 'F', 'pattern': '', 'text': 'F821 undefined name ''f'''} + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqual [e.lnum, e.col, e.length], [4, 41, 1] + + " Needs adjustment for second line in f-string, handling func arg. + let e = {'lnum': 3, 'bufnr': bufnr, 'col': 11, 'valid': 1, 'vcol': 0, 'nr': 821, 'type': 'F', 'pattern': '', 'text': 'F821 undefined name ''arg'''} + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqual [e.lnum, e.col, e.length], [4, 43, 3] + + " Something that cannot be found. + let e = {'lnum': 3, 'bufnr': bufnr, 'col': 9, 'valid': 1, 'vcol': 0, 'nr': 821, 'type': 'F', 'pattern': '', 'text': 'F821 undefined name ''cannotbefound'''} + call neomake#makers#ft#python#Flake8EntryProcess(e) + AssertEqual [e.lnum, e.col], [3, 9] + Assert !has_key(e, 'length') + bwipe! + +Execute (python: flake8: neomake#makers#ft#python#Flake8EntryProcess): + let bufnr = bufnr('%') + let entry = {'type': 'F', 'nr': 841, 'text': "local variable 'foo' is assigned to but never used", 'lnum': 1, 'col': 1, 'bufnr': bufnr} + call neomake#makers#ft#python#Flake8EntryProcess(entry) + AssertEqual entry.type, 'W' + + let entry = {'type': 'F', 'nr': 999, 'text': "something", 'lnum': 1, 'col': 1, 'bufnr': bufnr} + call neomake#makers#ft#python#Flake8EntryProcess(entry) + AssertEqual entry.type, 'E' + + let entry = {'type': 'F', 'nr': 404, 'text': "not found", 'lnum': 1, 'col': 1, 'bufnr': bufnr} + call neomake#makers#ft#python#Flake8EntryProcess(entry) + AssertEqual entry.type, 'W' + + let entry = {'type': 'F', 'nr': 407, 'text': "no future", 'lnum': 1, 'col': 1, 'bufnr': bufnr} + call neomake#makers#ft#python#Flake8EntryProcess(entry) + AssertEqual entry.type, 'E' + +Execute (python: flake8): + Save &errorformat + let &errorformat = neomake#makers#ft#python#flake8().errorformat + + new + file foo/bar.py + lgetexpr 'foo/bar.py:90:1: I001 isort found an import in the wrong position' + let llist = getloclist(0) + let bufnr = bufnr('%') + AssertEqualQf llist, [ + \ {'lnum': 90, 'bufnr': bufnr, 'col': 1, 'valid': 1, 'vcol': 0, + \ 'nr': 1, 'type': 'I', 'pattern': '', + \ 'text': 'isort found an import in the wrong position'}] + let entry = llist[0] + call neomake#makers#ft#python#Flake8EntryProcess(entry) + AssertEqualQf [entry], [{'lnum': 90, 'bufnr': bufnr, 'col': 1, 'valid': 1, + \ 'vcol': 0, 'nr': -1, 'type': 'I', 'pattern': '', + \ 'text': 'I1 isort found an import in the wrong position'}] + bwipe + +Execute (python: flake8: supports_stdin): + new + noautocmd setfiletype python + + let b:neomake = {'flake8': {'exe': 'echo', 'errorformat': '%m'}} + CallNeomake 1, ['flake8'] + AssertNeomakeMessage '\vStarting .{-}: echo --format\=default --stdin-display-name '''' -.', 2 + AssertEqual getloclist(0)[0].text, + \ '-1 --format=default --stdin-display-name -' + bwipe + +Execute (python: flake8: supports_stdin: changes cwd (non-existing)): + new + let tempdir = tempname() + let fname = tempdir.neomake#utils#Slash().'fname' + exe 'file' fname + noautocmd setfiletype python + + let b:neomake = {'flake8': {'exe': 'echo', 'errorformat': '%m'}} + CallNeomake 1, ['flake8'] + AssertNeomakeMessage printf('\Vjobinfo.cd(): error when trying to change cwd to %s:', tempdir) + AssertNeomakeMessage printf('\vStarting .{-}: echo --format\=default --stdin-display-name %s -.', fname), 2 + AssertNeomakeMessage printf('cwd: %s.', getcwd()) + AssertEqual getloclist(0)[0].text, + \ printf('-1 --format=default --stdin-display-name %s -', fname) + bwipe + +Execute (python: flake8: supports_stdin: changes cwd (existing)): + new + let fname = tempname() + let tempdir = fnamemodify(fname, ':h') + exe 'file' fname + noautocmd setfiletype python + + let b:neomake = {'flake8': {'exe': 'echo', 'errorformat': '%m'}} + CallNeomake 1, ['flake8'] + AssertNeomakeMessage printf('\vStarting .{-}: echo --format\=default --stdin-display-name %s -.', fname), 2 + AssertNeomakeMessage printf('cwd: %s (changed).', tempdir) + AssertEqual getloclist(0)[0].text, + \ printf('-1 --format=default --stdin-display-name %s -', fname) + bwipe + +Execute (python: flake8: supports_stdin: does not change cwd with buffer in subdir): + new + let cwd = tempname() + let fdir = cwd.neomake#utils#Slash().'subdir' + call mkdir(fdir, 'p') + let fname = fdir.neomake#utils#Slash().'fname' + exe 'file' fname + exe 'lcd' cwd + noautocmd setfiletype python + + let b:neomake = {'flake8': {'exe': 'echo', 'errorformat': '%m'}} + CallNeomake 1, ['flake8'] + AssertNeomakeMessageAbsent '\Verror when trying to change cwd' + AssertNeomakeMessage printf('\vStarting .{-}: echo --format\=default --stdin-display-name %s -.', + \ fname), 2 + AssertNeomakeMessage printf('cwd: %s.', cwd) + AssertEqual getloclist(0)[0].text, + \ printf('-1 --format=default --stdin-display-name %s -', fname) + bwipe + +Execute (python: pylint): + let entry = {'type': 'F', 'col': 1} + call neomake#makers#ft#python#PylintEntryProcess(entry) + AssertEqual entry.type, 'E' + AssertEqual entry.col, 2 + + let entry = {'type': 'E', 'col': 1} + call neomake#makers#ft#python#PylintEntryProcess(entry) + AssertEqual entry.type, 'E' + AssertEqual entry.col, 2 + + let entry = {'type': 'W', 'col': 1} + call neomake#makers#ft#python#PylintEntryProcess(entry) + AssertEqual entry.type, 'W' + AssertEqual entry.col, 2 + + let entry = {'type': 'R', 'col': 1} + call neomake#makers#ft#python#PylintEntryProcess(entry) + AssertEqual entry.type, 'W' + AssertEqual entry.col, 2 + + let entry = {'type': 'C', 'col': 1} + call neomake#makers#ft#python#PylintEntryProcess(entry) + AssertEqual entry.type, 'W' + AssertEqual entry.col, 2 + + let entry = {'type': 'I', 'col': 1} + call neomake#makers#ft#python#PylintEntryProcess(entry) + AssertEqual entry.type, 'I' + AssertEqual entry.col, 2 + +Execute (python: pylint: filters expected msgs on stderr): + let stderr = [ + \ 'No config file found, using default configuration', + \ 'Using config file /Users/liyong/.pylintrc', + \ 'Some unexpected error', + \ ] + let maker = neomake#GetMaker('pylint', 'python') + let output = copy(stderr) + call maker.filter_output(output, {'source': 'stderr'}) + AssertEqual output, [ + \ 'Some unexpected error', + \ ] + let output = copy(stderr) + call maker.filter_output(output, {'source': 'stdout'}) + AssertEqual output, stderr + +Execute (python: pylint: filters Python warnings): + let stderr = [ + \ '/usr/lib/python3.6/inspect.py:79: Warning: gsignal.c:1675: parameter 1 of type '''' for signal "GstBus::sync_message" is not a value type', + \ ' return isinstance(object, type)', + \ '/usr/lib/python3.6/inspect.py:79: Warning: gsignal.c:1675: parameter 1 of type '''' for signal "GstBus::message" is not a value type', + \ ' return isinstance(object, type)', + \ 'Some unexpected error', + \ '/usr/lib/python3.6/inspect.py:79: Warning: g_param_spec_boxed: assertion ''G_TYPE_IS_BOXED (boxed_type)'' failed', + \ ' return isinstance(object, type)', + \ '/usr/lib/python3.6/inspect.py:79: Warning: validate_pspec_to_install: assertion ''G_IS_PARAM_SPEC (pspec)'' failed', + \ ' return isinstance(object, type)', + \ 'Another unexpected error', + \ ] + let maker = neomake#GetMaker('pylint', 'python') + let output = copy(stderr) + call maker.filter_output(output, {'source': 'stderr'}) + AssertEqual output, [ + \ 'Some unexpected error', + \ 'Another unexpected error', + \ ] + let output = copy(stderr) + call maker.filter_output(output, {'source': 'stdout'}) + AssertEqual output, stderr + +Execute (neomake#makers#ft#python#FilterPythonWarnings): + let lines = [ + \ '/usr/lib/python3.6/inspect.py:79: Warning: gsignal.c:1675: parameter 1 of type '''' for signal "GstBus::sync_message" is not a value type', + \ 'this is not a source location', + \] + call neomake#makers#ft#python#FilterPythonWarnings(lines, {'source': 'stderr'}) + AssertEqual lines, [ + \ 'this is not a source location', + \ ] + +Execute (neomake#makers#ft#python#FilterPythonWarnings: FutureWarning): + let lines = [ + \ '/some/.venv 37 with space/lib/python3.7/site-packages/pycodestyle.py:113: FutureWarning: Possible nested set at position 1', + \ " EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')", + \ ] + call neomake#makers#ft#python#FilterPythonWarnings(lines, {'source': 'stderr'}) + AssertEqual lines, [] + +Execute (python: mypy: handles --py2): + call g:NeomakeTestsSetPATH('') + let base_args = [ + \ '--show-column-numbers', + \ '--show-error-codes', + \ '--check-untyped-defs', + \ '--ignore-missing-imports' + \ ] + + " Defaults to py3. + call neomake#makers#ft#python#DetectPythonVersion() + let maker = neomake#makers#ft#python#mypy() + AssertEqual maker.args, base_args + AssertNeomakeMessage '\v^Failed to detect Python version: .*', 0 + + " Appends --py2 with Python 2. + call g:NeomakeTestsCreateExe('python', ['#!/bin/sh', 'echo Python 2.7.14']) + call neomake#makers#ft#python#DetectPythonVersion() + let maker = neomake#makers#ft#python#mypy() + AssertEqual maker.args, base_args + ['--py2'] + + " Does not append --py2 with Python 3. + call g:NeomakeTestsCreateExe('python', ['#!/bin/sh', 'echo Python 3.6.4']) + call neomake#makers#ft#python#DetectPythonVersion() + let maker = neomake#makers#ft#python#mypy() + AssertEqual maker.args, base_args + +Execute (python: mypy): + let maker = neomake#GetMaker('mypy', 'python') + + let base_args = [ + \ '--show-column-numbers', + \ '--show-error-codes', + \ '--check-untyped-defs', + \ '--ignore-missing-imports' + \ ] + + let options = {'file_mode': 1} + let bound_maker = neomake#core#instantiate_maker(maker, options, 0) + AssertEqual bound_maker.args, ['--follow-imports=silent'] + base_args + + new + let b:neomake = {'project_root': 'fake_project_root'} + let options = {'file_mode': 0, 'bufnr': bufnr('%')} + let bound_maker = neomake#core#instantiate_maker(maker, options, 0) + AssertEqual bound_maker.args, base_args + ['fake_project_root'] + + let b:neomake = {'project_root': ''} + let options = {'file_mode': 0, 'bufnr': bufnr('%')} + let bound_maker = neomake#core#instantiate_maker(maker, options, 0) + AssertEqual bound_maker.args, base_args + ['.'] + + let jobinfo = NeomakeTestsFakeJobinfo() + AssertEqual bound_maker.supports_stdin(jobinfo), 0 + let fname = bound_maker._get_fname_for_buffer(jobinfo) + AssertNeomakeMessage '\vUsing tempfile for unnamed buffer: "(.*)".', 3 + let tmpfile = g:neomake_test_matchlist[1] + AssertEqual fname, tmpfile + + bwipe diff --git a/bundle/neomake/tests/ft_rst.vader b/bundle/neomake/tests/ft_rst.vader new file mode 100644 index 000000000..f8770d4c6 --- /dev/null +++ b/bundle/neomake/tests/ft_rst.vader @@ -0,0 +1,150 @@ +Include: include/setup.vader + +Execute (rst: rstlint: errorformat): + Save &errorformat + let &errorformat = neomake#makers#ft#rst#rstlint().errorformat + new + file file.rst + let output = [ + \ 'ERROR file.rst:40 Error in "code-block" directive:', + \ 'unknown option: "linenos".', + \ ] + lgetexpr output + AssertEqualQf getloclist(0), [ + \ {'lnum': 40, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'E', 'pattern': '', + \ 'text': 'Error in "code-block" directive:'."\n".'unknown option: "linenos".', + \ }] + + " Newline gets trimmed when going through postprocess. + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rst#rstlint(), output) + CallNeomake 1, [maker] + AssertEqualQf getloclist(0), [ + \ {'lnum': 40, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'E', 'pattern': '', + \ 'text': 'Error in "code-block" directive: unknown option: "linenos".', + \ }] + bwipe + +Execute (rst: sphinx: enabled based on conf.py): + call g:NeomakeTestsSetPATH('') + + AssertEqual neomake#makers#ft#rst#EnabledMakers(), ['rstlint', 'rstcheck'] + + new + call g:NeomakeTestsCreateExe('sphinx-build', []) + AssertEqual neomake#makers#ft#rst#EnabledMakers(), ['rstlint', 'rstcheck'] + AssertNeomakeMessage 'sphinx: skipping setting of source_dir for empty bufname.', 3 + + let bufnr = bufnr('%') + noautocmd set filetype=rst + CallNeomake 1, ['sphinx'] + AssertNeomakeMessage 'sphinx: skipping setting of source_dir for empty bufname.', 3 + AssertNeomakeMessage '\Vsphinx: could not find conf.py', 0 + Assert !exists('b:neomake.sphinx') + + let tempdir = tempname() + let slash = neomake#utils#Slash() + call mkdir(tempdir.slash.'doc', 'p') + + exe 'lcd '.fnameescape(tempdir) + file doc/test.rst + + " Uses conf.py from project root also. + call writefile([], 'conf.py') + " To please neomake#utils#get_project_root(). + call writefile([], 'Makefile') + call neomake#makers#ft#rst#EnabledMakers() + AssertNeomakeMessage printf("sphinx: setting b:neomake.sphinx.source_dir='%s'.", getcwd()), 3, {'bufnr': bufnr} + + call writefile([], 'doc'.slash.'conf.py') + unlet b:neomake.sphinx + let expected_srcdir = getcwd() . slash . 'doc' + let maker = neomake#GetMaker('sphinx', 'rst') + AssertEqual maker.args[-2], expected_srcdir + AssertNeomakeMessage printf("sphinx: setting b:neomake.sphinx.source_dir='%s'.", expected_srcdir), 3, {'bufnr': bufnr} + AssertEqual neomake#makers#ft#rst#EnabledMakers(), ['sphinx'] + bwipe + +Execute (rst: sphinx: handles docutils warnings and adds first additional line): + new + file build/some.rst + let b:neomake = {'sphinx': {'source_dir': 'sphinx_source_dir'}} + + let output = [ + \ 'WARNING: /some/path/inline.rst:8: (ERROR/3) Malformed table.', + \ 'No bottom table border found.', + \ '', + \ '======================= ====================================================================', + \ '/some/path/inline.rst:9: WARNING: Block quote ends without a blank line; unexpected unindent.', + \ 'WARNING: /some/path/inline.rst:40: (ERROR/3) Error in "code-block" directive:', + \ 'unknown option: "linenoss".', + \ '', + \ '.. code-block:: lua', + \ ' :linenoss:', + \ '', + \ ' -- luacheck: globals g1 g2, ignore foo', + \ ' local foo = g1(g2) -- No warnings emitted.', + \ '', + \ ' -- The following unused function is not reported.', + \ ' local function f() -- luacheck: ignore', + \ ' -- luacheck: globals g3', + \ ' g3() -- No warning.', + \ ' end', + \ '', + \ ' g3() -- Warning is emitted as the inline option defining g3 only affected function f.', + \ ' WARNING: /some/path/inline.rst:2: (WARNING/2) Title underline too short.', + \ '', + \ 'Command line interface', + \ '=====================', + \ '', + \ 'build/some.rst:70: WARNING: numfig is disabled. :numref: is ignored.', + \ 'build/some.rst:71: WARNING: numfig is disabled. :numref: is ignored.', + \ ] + + let maker = neomake#makers#ft#rst#sphinx() + call extend(maker, { + \ 'exe': 'printf', 'args': ['%s\n'] + output, + \ 'append_file': 0, 'output_stream': 'stdout'}) + CallNeomake 1, [maker] + + let unlisted_bufnr = bufnr('/some/path/inline.rst') + let bufnr = bufnr('%') + + AssertEqualQf getloclist(0), [ + \ {'lnum': 8, 'bufnr': unlisted_bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'E', 'pattern': '', + \ 'text': 'Malformed table. No bottom table border found.'}, + \ {'lnum': 9, 'bufnr': unlisted_bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'W', 'pattern': '', + \ 'text': 'Block quote ends without a blank line; unexpected unindent.'}, + \ {'lnum': 40, 'bufnr': unlisted_bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'E', 'pattern': '', + \ 'text': 'Error in "code-block" directive: unknown option: "linenoss".'}, + \ {'lnum': 70, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'W', 'pattern': '', + \ 'text': 'numfig is disabled. :numref: is ignored.'}, + \ {'lnum': 71, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'W', 'pattern': '', + \ 'text': 'numfig is disabled. :numref: is ignored.'} + \ ] + exe 'bwipe' unlisted_bufnr + bwipe + +Execute (rst: sphinx: errorformat): + new + file foo.rst + let b:neomake = {'sphinx': {'source_dir': 'sphinx_source_dir'}} + + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rst#sphinx(), [], [ + \ 'foo.rst:20: WARNING: Problems with "include" directive path:', + \ "InputError: [Errno 2] No such file or directory: '_include.rst'.", + \ ]) + CallNeomake 1, [maker] + + AssertEqualQf getloclist(0), [ + \ {'lnum': 20, 'bufnr': bufnr('%'), 'col': 0, 'pattern': '', 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'W', + \ 'text': 'Problems with "include" directive path: InputError: [Errno 2] No such file or directory: ''_include.rst''.'}, + \ ] + bwipe diff --git a/bundle/neomake/tests/ft_rust.vader b/bundle/neomake/tests/ft_rust.vader new file mode 100644 index 000000000..5ea652e40 --- /dev/null +++ b/bundle/neomake/tests/ft_rust.vader @@ -0,0 +1,162 @@ +Include: include/setup.vader + +Execute (rust: cargo: handles code correctly): + let null = g:neomake#compat#json_null + let true = g:neomake#compat#json_true + + let json = join([ + \ '{"reason":"compiler-message"', + \ '"package_id":"inko 0.3.0 (path+file:///home/yorickpeterse/Projects/inko/inko/vm)"', + \ '"target":{"kind":["lib"]', + \ '"crate_types":["lib"]', + \ '"name":"libinko"', + \ '"src_path":"/home/yorickpeterse/Projects/inko/inko/vm/src/lib.rs"', + \ '"edition":"2015"}', + \ '"message":{"message":"field is never used: `stealer`"', + \ '"code":{"code":"dead_code","explanation":null}', + \ '"level":"warning"', + \ '"spans":[{"file_name":"src/scheduling/scheduler.rs","byte_start":83,"byte_end":102,"line_start":4,"line_end":4,"column_start":5,"column_end":24,"is_primary":true,"text":[{"text":" stealer: Stealer,","highlight_start":5,"highlight_end":24}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}]', + \ '"children":[{"message":"#[warn(dead_code)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null}]', + \ '"rendered":"warning: field is never used: `stealer`\\n --> src/scheduling/scheduler.rs:4:5\\n |\\n4 | stealer: Stealer,\\n | ^^^^^^^^^^^^^^^^^^^\\n |\\n = note: #[warn(dead_code)] on by default\\n\\n"}}', + \ ], ',') + + let context = {'output': [json]} + let errors = neomake#makers#ft#rust#CargoProcessOutput(context) + AssertEqual errors, [ + \ {'lnum': 4, 'col': 5, 'filename': 'src/scheduling/scheduler.rs', + \ 'type': 'W', + \ 'maker_name': 'cargo', 'length': 19, + \ 'text': 'field is never used: `stealer`. #[warn(dead_code)] on by default'}] + +Execute (cargo skip non json line): + new + file build/lib.rs + let cargo = neomake#makers#ft#rust#cargo() + let cargo.exe = 'printf' + let cargo.args = ['error: Could not compile `derive_more`.'] + + CallNeomake 1, [cargo] + AssertEqual [], getloclist(0) + bwipe + +Execute (cargo info message): + new + file build/lib.rs + let cargo = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rust#cargo(), + \ '../tests/fixtures/rust/cargo_info.json') + + CallNeomake 1, [cargo] + AssertEqual [], getloclist(0) + bwipe + +Execute (cargo error without span): + new + file build/lib.rs + let cargo = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rust#cargo(), + \ '../tests/fixtures/rust/cargo_error_without_span.json') + + CallNeomake 1, [cargo] + AssertEqual [], getloclist(0) + bwipe + +Execute (cargo: uses primary span): + new + file build/main.rs + let cargo = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rust#cargo(), + \ 'tests/fixtures/rust/cargo_error_primary_span.json') + let cargo.cwd = getcwd() + + CallNeomake 1, [cargo] + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 6, 'bufnr': bufnr('%'), 'col': 5, 'valid': 1, 'vcol': 0, 'nr': 61, + \ 'type': 'E', 'pattern': '', + \ 'text': 'this function takes 1 parameter but 2 parameters were supplied: expected 1 parameter', + \ }] + bwipe + +Execute (rust: cargo: uses directory with Cargo.toml as cwd): + new + let maker = neomake#makers#ft#rust#cargo() + Assert !has_key(maker, 'cwd') + let maker = maker.InitForJob(NeomakeTestsFakeJobinfo()) + AssertEqual maker.cwd, '%:p:h' + AssertNeomakeMessage "Failed to get cargo metadata for workspace using 'cargo metadata --no-deps --format-version 1'.", 3 + + let tempdir = tempname() + let slash = neomake#utils#Slash() + let subdir = tempdir . slash . 'subdir' + call mkdir(subdir, 'p') + let cargo_toml = tempdir . slash . 'Cargo.toml' + call writefile([], cargo_toml) + + exe 'lcd' subdir + let maker = neomake#makers#ft#rust#cargo() + let maker = maker.InitForJob(NeomakeTestsFakeJobinfo()) + AssertEqual maker.cwd, tempdir + bwipe + +Execute (rust: cargo: uses cargo workspace_root as cwd): + new + call g:NeomakeTestsCreateExe('cargo', [ + \ 'echo ''{"workspace_root": "/cargo_workspace_root"}''']) + let maker = neomake#makers#ft#rust#cargo() + let maker = maker.InitForJob(NeomakeTestsFakeJobinfo()) + AssertEqual maker.cwd, '/cargo_workspace_root' + bwipe + +Execute (rust: cargo: handles cd'ing before querying workspace_root metadata): + new + let tempdir = tempname() + call mkdir(tempdir) + exe printf('file %s/fake.rs', fnameescape(tempdir)) + + call g:NeomakeTestsCreateExe('cargo', [ + \ printf('[ "$PWD" = "%s" ] && echo ''{"workspace_root": "%s"}''', + \ tempdir, tempdir)]) + let maker = neomake#makers#ft#rust#cargo() + let maker = maker.InitForJob(NeomakeTestsFakeJobinfo()) + AssertEqual maker.cwd, tempdir + bwipe + +Execute (rust: cargo: logs error when cd'ing fails): + new + file /doesnotexist/fake.rs + + let maker = neomake#makers#ft#rust#cargo() + let maker = maker.InitForJob(NeomakeTestsFakeJobinfo()) + AssertNeomakeMessage '\Vs:get_cargo_workspace_root: failed to cd to buffer directory: Vim(cd):E344: ', 3 + AssertEqual maker.cwd, '%:p:h' + bwipe + +Execute (rust: cargotest detect failures): + new + file src/lib.rs + let cargotest = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rust#cargotest(), + \ 'tests/fixtures/rust/cargotest_with_failures') + let cargotest.cwd = getcwd() + + CallNeomake 1, [cargotest] + + AssertEqual map(getloclist(0), '[v:val.type, v:val.valid, v:val.text]'), [ + \ ['E', 1, 'failed to resolve. Maybe a missing `extern crate non;`?'], + \ ['W', 1, 'unused import: `non::existent::module`'], + \ ] + bwipe + +Execute (rust: cargotest: uses directory with Cargo.toml as cwd): + let maker = neomake#makers#ft#rust#cargotest() + + let tempdir = tempname() + let slash = neomake#utils#Slash() + let subdir = tempdir . slash . 'subdir' + call mkdir(subdir, 'p') + let cargo_toml = tempdir . slash . 'Cargo.toml' + call writefile([], cargo_toml) + + new + exe 'lcd' subdir + let maker = neomake#makers#ft#rust#cargotest() + let maker = maker.InitForJob(NeomakeTestsFakeJobinfo()) + AssertEqual maker.cwd, tempdir + bwipe diff --git a/bundle/neomake/tests/ft_sh.vader b/bundle/neomake/tests/ft_sh.vader new file mode 100644 index 000000000..67b31a756 --- /dev/null +++ b/bundle/neomake/tests/ft_sh.vader @@ -0,0 +1,116 @@ +Include: include/setup.vader + +Execute (sh: shellcheck): + new + " Unless -s is specified, shellcheck checks shebangs on its own and issues a + " warning for unsupported dialects. + call setline(1, '#!/bin/sh') + let default_args = ['-fgcc', '-x'] + AssertEqual default_args, neomake#makers#ft#sh#shellcheck().args + call setline(1, '#!/bin/dash') + AssertEqual default_args, neomake#makers#ft#sh#shellcheck().args + call setline(1, '#!/bin/bash') + AssertEqual default_args, neomake#makers#ft#sh#shellcheck().args + call setline(1, '#!/bin/ksh') + AssertEqual default_args, neomake#makers#ft#sh#shellcheck().args + + " Shellcheck also checks for a directive denoting the appropriate shell + call setline(1, '#shellcheck shell=sh') + AssertEqual default_args, neomake#makers#ft#sh#shellcheck().args + call setline(1, '') " reset shebang for next tests + + " If extension is .ksh, force 'ksh'. + silent file test.ksh + AssertEqual default_args + ['-s', 'ksh'], neomake#makers#ft#sh#shellcheck().args + + " If extension is .sh, use variables to detect the dialect. (:h ft-sh-syntax) + silent file test.sh + let g:is_sh = 1 + AssertEqual default_args + ['-s', 'sh'], neomake#makers#ft#sh#shellcheck().args + unlet g:is_sh + let g:is_kornshell = 1 + AssertEqual default_args + ['-s', 'ksh'], neomake#makers#ft#sh#shellcheck().args + unlet g:is_kornshell + let g:is_posix = 1 + AssertEqual default_args + ['-s', 'ksh'], neomake#makers#ft#sh#shellcheck().args + unlet g:is_posix + AssertEqual default_args + ['-s', 'bash'], neomake#makers#ft#sh#shellcheck().args + + " Use 'bash' for everything else. + call setline(1, '#!/usr/bin/env foo') + silent file foo + AssertEqual default_args + ['-s', 'bash'], neomake#makers#ft#sh#shellcheck().args + silent file foo.bash + AssertEqual default_args + ['-s', 'bash'], neomake#makers#ft#sh#shellcheck().args + silent file foo.xxx + AssertEqual default_args + ['-s', 'bash'], neomake#makers#ft#sh#shellcheck().args + let g:is_sh = 1 + AssertEqual default_args + ['-s', 'bash'], neomake#makers#ft#sh#shellcheck().args + unlet g:is_sh + let g:is_kornshell = 1 + AssertEqual default_args + ['-s', 'bash'], neomake#makers#ft#sh#shellcheck().args + unlet g:is_kornshell + + " The following should never happen in practice. + set ft= + AssertEqual default_args + ['-s', 'bash'], neomake#makers#ft#sh#shellcheck().args + set ft=nadda + AssertEqual default_args + ['-s', 'bash'], neomake#makers#ft#sh#shellcheck().args + bwipe! + bwipe test.sh test.ksh foo foo.bash + +Execute (Test Neomake on errors.sh with shellcheck): + call g:NeomakeSetupAutocmdWrappers() + + " From shellcheck 0.4.6. + let shellcheck_output = [ + \ "errors.sh:3:1: warning: a appears unused. Verify it or export it. [SC2034]", + \ "errors.sh:3:3: note: Expressions don't expand in single quotes, use double quotes for that. [SC2016]", + \ "errors.sh:5:4: error: '(' is invalid here. Did you forget to escape it? [SC1036]", + \ "errors.sh:5:4: error: Parsing stopped here. Invalid use of parentheses? [SC1088]", + \ "errors.sh:5:4: error: Trying to declare parameters? Don't. Use () and refer to params as $1, $2.. [SC1065]", + \ ] + + let maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#sh#shellcheck(), shellcheck_output) + let maker.name = 'shellcheck' + + new + edit tests/fixtures/errors.sh + let bufnr = bufnr('%') + CallNeomake 1, [maker] + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Running makers: shellcheck.' + AssertEqualQf getloclist(0), [{ + \ 'lnum': 3, 'bufnr': bufnr, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': 2034, + \ 'type': 'w', 'pattern': '', 'text': 'a appears unused. Verify it or export it.', + \ }, { + \ 'lnum': 3, 'bufnr': bufnr, 'col': 3, 'valid': 1, 'vcol': 0, 'nr': 2016, + \ 'type': 'I', 'pattern': '', 'text': 'Expressions don''t expand in single quotes, use double quotes for that.', + \ }, { + \ 'lnum': 5, 'bufnr': bufnr, 'col': 4, 'valid': 1, 'vcol': 0, 'nr': 1036, + \ 'type': 'e', 'pattern': '', 'text': '''('' is invalid here. Did you forget to escape it?', + \ }, { + \ 'lnum': 5, 'bufnr': bufnr, 'col': 4, 'valid': 1, 'vcol': 0, 'nr': 1088, + \ 'type': 'e', 'pattern': '', 'text': 'Parsing stopped here. Invalid use of parentheses?', + \ }, { + \ 'lnum': 5, 'bufnr': bufnr, 'col': 4, 'valid': 1, 'vcol': 0, 'nr': 1065, + \ 'type': 'e', 'pattern': '', 'text': 'Trying to declare parameters? Don''t. Use () and refer to params as $1, $2..', + \ }] + + " Compare real output with expected one." + " if executable('shellcheck') + " let real_output = neomake#compat#systemlist('cd tests/fixtures && shellcheck -fgcc -x errors.sh') + " if real_output != shellcheck_output + " call neomake#log#error('expected output changed:') + " AssertEqual real_output, shellcheck_output + " endif + bwipe + +Execute (shellcheck copies base maker): + let maker = neomake#makers#ft#sh#shellcheck() + AssertEqual maker.args, ['-fgcc', '-x', '-s', 'bash'] + + let maker.args = ['changed'] + + let maker = neomake#makers#ft#sh#shellcheck() + AssertEqual maker.args, ['-fgcc', '-x', '-s', 'bash'] diff --git a/bundle/neomake/tests/ft_sql.vader b/bundle/neomake/tests/ft_sql.vader new file mode 100644 index 000000000..674240b02 --- /dev/null +++ b/bundle/neomake/tests/ft_sql.vader @@ -0,0 +1,22 @@ +Include: include/setup.vader + +Execute (sqlint): + let sqlint_output = + \"sql/V1__BaseSchema.sql:1:1:ERROR syntax error at or near #\n + \sql/V1__BaseSchema.sql:22:13:WARNING syntax warning at or near alterUser" + + Save &errorformat + let &errorformat = neomake#makers#ft#sql#sqlint().errorformat + lgetexpr sqlint_output + + let loclist = getloclist(0) + AssertEqual len(loclist), 2 + AssertEqual loclist[0].lnum, 1 + AssertEqual loclist[0].col, 1 + AssertEqual loclist[0].text, 'syntax error at or near #' + AssertEqual loclist[0].type, 'E' + AssertEqual loclist[1].lnum, 22 + AssertEqual loclist[1].col, 13 + AssertEqual loclist[1].text, 'syntax warning at or near alterUser' + AssertEqual loclist[1].type, 'W' + bwipe sql/V1__BaseSchema.sql diff --git a/bundle/neomake/tests/ft_text.vader b/bundle/neomake/tests/ft_text.vader new file mode 100644 index 000000000..f69eccede --- /dev/null +++ b/bundle/neomake/tests/ft_text.vader @@ -0,0 +1,89 @@ +Include: include/setup.vader + +Execute (writegood: postprocess: length): + function! s:F(entry) + if !has_key(a:entry, 'col') + let a:entry.col = 0 + endif + call neomake#makers#ft#text#PostprocessWritegood(a:entry) + return a:entry + endfunction + AssertEqual s:F({'text': '"Currently" can weaken meaning'}).length, 9 + AssertEqual s:F({'text': '"Currently" can "weaken" meaning'}).length, 9 + Assert !has_key(s:F({'text': '"Currently can weaken meaning'}), 'length') + +Execute (writegood: postprocess increments column): + function! s:F(entry) + call neomake#makers#ft#text#PostprocessWritegood(a:entry) + return a:entry + endfunction + AssertEqual s:F({'col': 2, 'text': 'foo'}), {'col': 3, 'text': 'foo'} + +Execute (proselint): + new + file file.txt + Save &errorformat + let &errorformat = neomake#makers#ft#text#proselint().errorformat + call append(0, [ + \ "file.txt:1:1: typography.symbols.ellipsis '...' is an approximation, use the ellipsis symbol '…'.", + \ "file.txt:2:9: uncomparables.misc Comparison of an uncomparable: 'very unique.' is not comparable.", + \ "file.txt:2:9: weasel_words.very Substitute 'damn' every time you're inclined to write 'very;' your editor will delete it and the writing will be just as it should be."]) + norm! Gdd + lgetbuffer + AssertEqualQf getloclist(0), [ + \ {'lnum': 1, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'typography.symbols.ellipsis ''...'' is an approximation, use the ellipsis symbol ''…''.'}, + \ {'lnum': 2, 'bufnr': bufnr('%'), 'col': 9, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'uncomparables.misc Comparison of an uncomparable: ''very unique.'' is not comparable.'}, + \ {'lnum': 2, 'bufnr': bufnr('%'), 'col': 9, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'weasel_words.very Substitute ''damn'' every time you''re inclined to write ''very;'' your editor will delete it and the writing will be just as it should be.'}, + \ ] + + norm! ggdGcc... + + function! s:F(entry) + call neomake#makers#ft#text#proselint().postprocess(a:entry) + return a:entry + endfunction + AssertEqual 3, s:F(getloclist(0)[0]).length + + let maker = neomake#GetMaker('proselint', 'text') + let maker.append_file = 0 + let maker.exe = 'echo' + let maker.args = ["file.txt:1:1: typography.symbols.ellipsis '...' is an approximation, use the ellipsis symbol '…'."] + + call neomake#highlights#ResetFile(bufnr('%')) + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + let highlights = neomake#highlights#_get() + if has('nvim') + Assert has_key(highlights['file'], bufnr('%')) + else + AssertEqual highlights, {'file': {bufnr('%'): { + \ 'NeomakeError': [], 'NeomakeInfo': [], 'NeomakeMessage': [], + \ 'NeomakeWarning': [[1, 1, 3]]}}, 'project': {}} + endif + bwipe! + +Execute (writegood: handles wrapped message): + Save &errorformat + let &errorformat = neomake#makers#ft#text#writegood().errorformat + lgetexpr [ + \ 'README.md:1:73:"be', + \ 'used" may be passive voice', + \ 'README.md:2:1:something else'] + + let bufnr = bufnr('README.md') + AssertEqualQf getloclist(0), [ + \ {'lnum': 1, 'bufnr': bufnr, 'col': 73, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': "\"be\nused\" may be passive voice"}, + \ {'lnum': 2, 'bufnr': bufnr, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'something else'}] + exe 'bwipe' bufnr + +Execute (writegood: handles empty lines): + Save &errorformat + let &errorformat = neomake#makers#ft#text#writegood().errorformat + lgetexpr [''] + AssertEqual getloclist(0), [] diff --git a/bundle/neomake/tests/ft_typescript.vader b/bundle/neomake/tests/ft_typescript.vader new file mode 100644 index 000000000..dfa290478 --- /dev/null +++ b/bundle/neomake/tests/ft_typescript.vader @@ -0,0 +1,82 @@ +Include: include/setup.vader + +Execute (typescript: tslint): + Save &errorformat + let &errorformat = neomake#makers#ft#typescript#tslint().errorformat + new + file t.ts + + " tslint adds newlines before/after. + let output = [ + \ '', + \ "WARNING: t.ts[1, 1]: Calls to 'console.log' are not allowed.", + \ "ERROR: t.ts[1, 15]: Missing semicolon", + \ "WARNING: t.ts:2:1 - Calls to 'console.log' are not allowed.", + \ "ERROR: t.ts:2:15 - Missing semicolon", + \ '', + \ ] + lgetexpr join(output, "\n") + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 1, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'W', + \ 'pattern': '', + \ 'text': 'Calls to ''console.log'' are not allowed.' + \ }, { + \ 'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 15, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'Missing semicolon', + \ }, { + \ 'lnum': 2, + \ 'bufnr': bufnr('%'), + \ 'col': 1, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'W', + \ 'pattern': '', + \ 'text': 'Calls to ''console.log'' are not allowed.' + \ }, { + \ 'lnum': 2, + \ 'bufnr': bufnr('%'), + \ 'col': 15, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'Missing semicolon', + \ }] + bwipe + +Execute (typescript: tsc): + Save &errorformat + let &errorformat = neomake#makers#ft#typescript#tsc().errorformat + new + file t.ts + + lgetexpr + \ "t.ts(13,7): error TS2322: Type '0' is not assignable to type 'string'." + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 13, + \ 'bufnr': bufnr('%'), + \ 'col': 7, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'TS2322: Type ''0'' is not assignable to type ''string''.'}] + bwipe diff --git a/bundle/neomake/tests/ft_vim.vader b/bundle/neomake/tests/ft_vim.vader new file mode 100644 index 000000000..d8973314d --- /dev/null +++ b/bundle/neomake/tests/ft_vim.vader @@ -0,0 +1,102 @@ +Include: include/setup.vader + +Execute (Vint: generic postprocessing for highlights): + new + file file1.vim + norm! iecho l:undefined_var + norm! oecho unused_var + norm! osome unexpected_token + + let vint_maker = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#vim#vint(), [ + \ "file1.vim:1:6:warning:Undefined variable: l:undefined_var (ProhibitUsingUndeclaredVariable)", + \ "file1.vim:2:6:warning:Unused variable: unused_var (ProhibitUnusedVariable)", + \ "file1.vim:3:6:error:unexpected token: unexpected_token (SyntaxError)", + \ ]) + let vint_maker.append_file = 0 + + call neomake#highlights#ResetFile(bufnr('%')) + AssertEqual neomake#highlights#_get(), {'file': {}, 'project': {}} + + call neomake#Make(1, [vint_maker]) + NeomakeTestsWaitForFinishedJobs + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, + \ 'bufnr': bufnr, + \ 'col': 6, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'w', + \ 'pattern': '', + \ 'text': 'Undefined variable: l:undefined_var (ProhibitUsingUndeclaredVariable)' + \ }, { + \ 'lnum': 2, + \ 'bufnr': bufnr, + \ 'col': 6, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'w', + \ 'pattern': '', + \ 'text': 'Unused variable: unused_var (ProhibitUnusedVariable)' + \ }, { + \ 'lnum': 3, + \ 'bufnr': bufnr, + \ 'col': 6, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'e', + \ 'pattern': '', + \ 'text': 'unexpected token: unexpected_token (SyntaxError)' + \ }] + + " Test that length has been used with the highlight. + let highlights = neomake#highlights#_get() + if has('nvim') + AssertEqual has_key(highlights['file'], bufnr), 1, "highlight for file" + else + AssertEqual highlights.file[bufnr], { + \ 'NeomakeWarning': [[1, 6, 15], [2, 6, 10]], + \ 'NeomakeError': [[3, 6, 16]], + \ 'NeomakeInfo': [], + \ 'NeomakeMessage': [], + \ } + endif + bwipe! + +Execute (vimlint: errorformat): + Save &efm + let &efm = neomake#makers#ft#vim#vimlint().errorformat + + new + file testfile.vim + lgetexpr 'testfile.vim:33:12:Error: EVP_0: unexpected EOL' + AssertEqualQf getloclist(0), [{ + \ 'lnum': 33, 'bufnr': bufnr('%'), 'col': 12, 'valid': 1, 'vcol': 0, + \ 'nr': 0, 'type': 'E', 'pattern': '', 'text': 'unexpected EOL'}] + + lgetexpr 'testfile.vim:2:0:Error: EVP_E171: Missing :endif: TOPLEVEL' + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': 171, 'type': 'E', 'pattern': '', 'text': 'Missing :endif: TOPLEVEL'}] + + lgetexpr 'testfile.vim:1:1:Error: EVL204: constant in conditional context' + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, + \ 'nr': 204, 'type': 'E', 'pattern': '', 'text': 'constant in conditional context'}] + + lgetexpr 'testfile.vim:2:1:Warning: EVL204: constant in conditional context' + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, + \ 'nr': 204, 'type': 'W', 'pattern': '', 'text': 'constant in conditional context'}] + bwipe + +Execute (vint: handles error with version check): + let exe = g:NeomakeTestsCreateExe('vint', [ + \ '#!/bin/sh', 'echo "Traceback (most recent call last):" >&2']) + + let maker = neomake#makers#ft#vim#vint() + let maker.exe = exe + AssertEqual maker.supports_stdin({}), 0 diff --git a/bundle/neomake/tests/ft_xml.vader b/bundle/neomake/tests/ft_xml.vader new file mode 100644 index 000000000..5bf5b8ac9 --- /dev/null +++ b/bundle/neomake/tests/ft_xml.vader @@ -0,0 +1,47 @@ +Include: include/setup.vader + +Execute (xml: xmllint: uses stdin and handles generic validity error): + new + let b:neomake_tests_massage_buffer = 0 + file example.xml + let fname = expand('%:p') + let maker = NeomakeTestsFixtureMaker('neomake#makers#ft#xml#xmllint', + \ 'tests/fixtures/input/xmllint/validity-error.xml') + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using stdin for unreadable buffer (-).', 3 + AssertNeomakeMessage 'exit: xmllint-fixture: 3.', 3 + AssertEqual getloclist(0), [] + bwipe + +Execute (xml: xmllint: missing dtd): + new + let b:neomake_tests_massage_buffer = 0 + let maker = NeomakeTestsFixtureMaker('neomake#makers#ft#xml#xmllint', + \ 'tests/fixtures/input/xmllint/missingdtd.xml') + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).', 3 + AssertNeomakeMessage 'exit: xmllint-fixture: 3.', 3 + AssertNeomakeMessage '\vUsed bufnr from stdin buffer \d+ \(tests/fixtures/input/xmllint/missingdtd.xml\) for 2 entries: 1, 2.' + + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, + \ 'bufnr': bufnr, + \ 'col': 36, + \ 'valid': 1, + \ 'vcol': 1, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'warning: failed to load external entity "tests/fixtures/input/xmllint/missingdtdref"' + \ }, { + \ 'lnum': 5, + \ 'bufnr': bufnr, + \ 'col': 37, + \ 'valid': 1, + \ 'vcol': 1, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'namespace error : Namespace prefix xlink for href on b is not defined'}] + bwipe diff --git a/bundle/neomake/tests/helpers/trap.sh b/bundle/neomake/tests/helpers/trap.sh new file mode 100644 index 000000000..b85c33eb1 --- /dev/null +++ b/bundle/neomake/tests/helpers/trap.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# +# A test script that ignores SIGTERM. + +trap 'echo not stopping on SIGTERM' TERM +# trap 'echo stopping on SIGHUP; exit' HUP + +echo "Started: $$" +c=0 +while true; do + c=$((c + 1)) + echo $c + sleep .1 +done diff --git a/bundle/neomake/tests/highlights.vader b/bundle/neomake/tests/highlights.vader new file mode 100644 index 000000000..3b6ec7131 --- /dev/null +++ b/bundle/neomake/tests/highlights.vader @@ -0,0 +1,132 @@ +Include: include/setup.vader + +Execute (No error when matches are cleared manually): + new + + call neomake#highlights#AddHighlight({'bufnr': bufnr('%'), 'type': 'E', 'col': 1, 'lnum': 1}, 'file') + if !has('nvim') + AssertEqual w:neomake_highlights, [] + endif + doautocmd BufEnter + if !has('nvim') + AssertEqual len(w:neomake_highlights), 1 + endif + call clearmatches() + " No-op in Neovim (same as BufEnter above), but should be defined. + call neomake#highlights#ShowHighlights() + if !has('nvim') + AssertEqual len(w:neomake_highlights), 1 + AssertEqual w:neomake_highlights[0], getmatches()[0].id + + if exists('*matchaddpos') + AssertEqual getmatches(), + \ [{'group': 'NeomakeError', 'id': 5, 'priority': 10, 'pos1': [1, 1, 1]}] + else + AssertEqual getmatches(), + \ [{'group': 'NeomakeError', 'pattern': '\%1l\%1c.\{1}', 'priority': 10, 'id': 5}] + endif + endif + bwipe + +Execute (neomake#highlights#AddHighlight with off-columns): + " This documents the current behavior. + " I have tried to limit it to the length of the current line etc, but it + " seems to better use the given values as-is. + " Currently it will highlight an empty line completely, if there is an error + " reported for column 1. + new + let bufnr = bufnr('%') + let entry = {'bufnr': bufnr, 'type': 'E', 'col': 1, 'lnum': 1} + + call neomake#highlights#AddHighlight(entry, 'file') + let highlights = neomake#highlights#_get()['file'][bufnr] + if !has('nvim') + AssertEqual highlights['NeomakeError'], [[1, 1, 1]] + endif + + normal! ifoo + + call neomake#highlights#ResetFile(bufnr) + call neomake#highlights#AddHighlight(entry, 'file') + let highlights = neomake#highlights#_get()['file'][bufnr] + if !has('nvim') + AssertEqual highlights['NeomakeError'], [[1, 1, 1]] + endif + + call neomake#highlights#ResetFile(bufnr) + AssertEqual has_key(neomake#highlights#_get()['file'], bufnr), 0 + + let entry = {'bufnr': bufnr, 'type': 'E', 'col': 1, 'lnum': 1, 'length': 4} + call neomake#highlights#AddHighlight(entry, 'file') + let highlights = neomake#highlights#_get()['file'][bufnr] + if !has('nvim') + AssertEqual highlights['NeomakeError'], [[1, 1, 4]] + endif + bwipe! + +Execute (neomake#highlights#AddHighlight handles entries with line=0, col=0): + Save g:neomake_highlight_lines + let entry = {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 0, 'col': 0} + lockvar entry + + let g:neomake_highlight_lines = 0 + call neomake#highlights#AddHighlight(entry, 'file') + let g:neomake_highlight_lines = 1 + call neomake#highlights#AddHighlight(entry, 'file') + +Execute (neomake#highlights#AddHighlight handles entries with line=0, col=1): + Save g:neomake_highlight_lines + let entry = {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 0, 'col': 1} + lockvar entry + + let g:neomake_highlight_lines = 0 + call neomake#highlights#AddHighlight(entry, 'file') + let g:neomake_highlight_lines = 1 + call neomake#highlights#AddHighlight(entry, 'file') + +Execute (neomake#highlights#AddHighlight: handles both col/line): + Save g:neomake_highlight_lines + Save g:neomake_highlight_columns + + let g:neomake_highlight_columns = 1 + let g:neomake_highlight_lines = 1 + + new + let bufnr = bufnr('%') + + " Highlights column if present in entry. + let entry = {'bufnr': bufnr, 'type': 'E', 'col': 1, 'lnum': 1} + + call neomake#highlights#AddHighlight(entry, 'file') + let highlights = neomake#highlights#_get()['file'][bufnr] + if !has('nvim') + AssertEqual highlights['NeomakeError'], [[1, 1, 1]] + endif + + " Highlights line if column is not present in entry. + let entry = {'bufnr': bufnr, 'type': 'E', 'col': 0, 'lnum': 1} + + call neomake#highlights#ResetFile(bufnr) + call neomake#highlights#AddHighlight(entry, 'file') + let highlights = neomake#highlights#_get()['file'][bufnr] + if !has('nvim') + AssertEqual highlights['NeomakeError'], [1] + endif + bwipe! + +Execute (Highlights get (re-)defined on ColorScheme event): + if exists('g:colors_name') + let colorscheme = g:colors_name + let had_colorscheme = 1 + else + let colorscheme = 'default' + let had_colorscheme = 0 + endif + let orig = neomake#utils#redir('hi NeomakeError') + exe 'colorscheme' colorscheme + let new = neomake#utils#redir('hi NeomakeError') + if had_colorscheme + AssertEqual orig, new + else + Assert stridx(new, 'cleared') == -1, 'highlight is not cleared.' + endif diff --git a/bundle/neomake/tests/hooks-queue.vader b/bundle/neomake/tests/hooks-queue.vader new file mode 100644 index 000000000..0fec5322f --- /dev/null +++ b/bundle/neomake/tests/hooks-queue.vader @@ -0,0 +1,154 @@ +Include: include/setup.vader + +Execute (hook handling gets queued for global g:neomake_hook_context): + call g:NeomakeSetupAutocmdWrappers() + let maker = copy(g:success_maker) + + " Change to initial window to trigger processing there. + let s:finished_called = [] + function! s:OnFinished(...) + wincmd p + let s:finished_called += [a:000] + endfunction + augroup neomake_tests + au User NeomakeFinished nested call s:OnFinished() + augroup END + + new + let s:win1 = winnr() + call neomake#Make({'enabled_makers': [maker]}) + norm! V + NeomakeTestsWaitForFinishedJobs + new + call neomake#Make({'enabled_makers': [maker]}) + NeomakeTestsWaitForFinishedJobs + wincmd p + + bwipe + exe s:win1 . 'wincmd w' + bwipe + + Assert !exists('g:neomake_hook_context'), 'Hook context was cleaned.' + AssertEqual len(g:neomake_test_jobfinished), 2 + AssertEqual len(s:finished_called), 2 + + " Timer events do not cause it to finish, but get reset, so that no error is + " reported. + if neomake#has_async_support() + AssertNeomakeMessage 's:process_action_queue: decrementing timer tries for non-Timer event.', 3 + AssertNeomakeMessage 'action queue: skipping clean_make_info for not processed make_id.', 3 + endif + +Execute (hook handling gets queued for global g:neomake_hook_context (with postprocessing)): + call g:NeomakeSetupAutocmdWrappers() + let maker = copy(g:success_maker) + let maker.postprocess = ['neomake#postprocess#compress_whitespace'] + + " Change to initial window to trigger processing there. + let s:finished_called = [] + function! s:OnFinished(...) + wincmd p + let s:finished_called += [a:000] + endfunction + augroup neomake_tests + au User NeomakeFinished nested call s:OnFinished() + augroup END + + new + let s:win1 = winnr() + call neomake#Make({'enabled_makers': [maker]}) + norm! V + NeomakeTestsWaitForFinishedJobs + new + call neomake#Make({'enabled_makers': [maker]}) + NeomakeTestsWaitForFinishedJobs + wincmd p + + bwipe + exe s:win1 . 'wincmd w' + bwipe + + Assert !exists('g:neomake_hook_context'), 'Hook context was cleaned.' + AssertEqual len(g:neomake_test_jobfinished), 2 + AssertEqual len(s:finished_called), 2 + + if neomake#has_async_support() + AssertNeomakeMessage 'action queue: skipping clean_make_info for not processed make_id.', 3 + endif + +Execute (Nested neomake#utils#hook must not be nested (directly)): + function! s:nested_hook_cb(c) + AssertEqual g:neomake_hook_context, {'context': a:c} + let next = a:c + 1 + call neomake#utils#hook('Event'.next, {'context': next}) + endfunction + + augroup neomake_tests + au User Event1 call s:nested_hook_cb(1) + au User Event2 call s:nested_hook_cb(2) + au User Event3 call s:nested_hook_cb(3) + augroup END + call neomake#utils#hook('Event1', {'context': 1}) + AssertNeomakeMessage "Calling User autocmd Event1 with context: {'context': 1}.", 3 + AssertNeomakeMessage 'Queuing action handle_hook for Timer, BufEnter, WinEnter, InsertLeave, CursorHold, CursorHoldI.', 3 + doautocmd InsertLeave + AssertNeomakeMessage "Calling User autocmd Event2 with context: {'context': 2}.", 3 + AssertNeomakeMessage 'Queuing action handle_hook for Timer, BufEnter, WinEnter, InsertLeave, CursorHold, CursorHoldI.', 3 + doautocmd InsertLeave + AssertNeomakeMessage "Calling User autocmd Event3 with context: {'context': 3}.", 3 + +Execute (neomake#utils#hook: reports exception): + augroup neomake_tests + au User Event1 throw 'Exception' + augroup END + call neomake#utils#hook('Event1', {'context': 1}) + AssertNeomakeMessage "Calling User autocmd Event1 with context: {'context': 1}.", 3 + AssertNeomakeMessage 'Error during User autocmd for Event1: Exception.', 0 + Assert !exists('g:neomake_hook_context'), 'g:neomake_hook_context was cleared' + +Execute (neomake#utils#hook: context is locked): + augroup neomake_tests + au User Event1 let g:neomake_hook_context = 'changed' + augroup END + + call neomake#utils#hook('Event1', {'context': 'fake'}) + AssertNeomakeMessage 'Error during User autocmd for Event1: Vim(let):E741: Value is locked: g:neomake_hook_context.', 0 + Assert !exists('g:neomake_hook_context'), 'g:neomake_hook_context was cleared' + +Execute (Does not nest hooks / User autocommands): + if NeomakeAsyncTestsSetup() + new + + augroup neomake_tests + autocmd User NeomakeJobFinished nested call s:OnNeomakeJobFinished() + augroup END + + function! s:OnNeomakeJobFinished() abort + let jobinfo = g:neomake_hook_context.jobinfo + if jobinfo.maker.name == 'maker1' + NeomakeTestsWaitForMessage '\v^Queuing User autocmd NeomakeCountsChanged for nested invocation ', 3 + AssertNeomakeMessage 'Queuing action handle_hook for Timer, BufEnter, WinEnter, InsertLeave, CursorHold, CursorHoldI.', 3 + AssertNeomakeMessage '\V\^Retrying Timer event in 10ms', 3 + endif + " call neomake#log#debug('OnNeomakeJobFinished finished.') + endfunction + + let maker1 = NeomakeTestsCommandMaker('maker1', 'echo error1; exit 1') + let maker1.errorformat = '%E%m' + let maker2 = NeomakeTestsCommandMaker('maker2', 'sleep .1; echo error2; exit 2') + let maker2.errorformat = '%E%m' + + CallNeomake 1, [maker1, maker2] + + AssertEqual map(getloclist(0), 'v:val.text'), ['error1', 'error2'] + + doautocmd WinEnter + AssertNeomakeMessage 'action queue: calling handle_hook.' + AssertNeomakeMessage '\VCalling User autocmd NeomakeCountsChanged with context: ', 3 + AssertNeomakeMessage 'action queue: calling CleanJobinfo.', 3 + AssertNeomakeMessage 'Cleaning jobinfo.', 3 + AssertNeomakeMessage '\VCalling User autocmd NeomakeJobFinished with context: ', 3 + AssertNeomakeMessage '\VCalling User autocmd NeomakeFinished with context: ', 3 + AssertNeomakeMessage 'Cleaning make info.' + bwipe + endif diff --git a/bundle/neomake/tests/hooks.vader b/bundle/neomake/tests/hooks.vader new file mode 100644 index 000000000..db32cdcb6 --- /dev/null +++ b/bundle/neomake/tests/hooks.vader @@ -0,0 +1,104 @@ +Include: include/setup.vader + +Execute (Hook execution gets logged): + call g:NeomakeSetupAutocmdWrappers() + + au! neomake_tests User NeomakeCountsChanged + + let maker = extend(neomake#utils#MakerFromCommand('echo done'), { + \ 'errorformat': '%m'}) + + call neomake#Make(0, [maker]) + let make_id = neomake#GetStatus().last_make_id + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage '\mCalling User autocmd NeomakeFinished with context: {''options'': ', 3 + AssertEqual map(copy(g:neomake_test_finished), 'sort(keys(v:val))'), [ + \ ['finished_jobs', 'make_id', 'make_info', 'options']] + +Execute (NeomakeJobFinished): + if NeomakeAsyncTestsSetup() + let maker = extend(neomake#utils#MakerFromCommand('echo done; exit 7'), { + \ 'errorformat': '%m'}) + call neomake#Make(0, [maker]) + let jobinfo = neomake#GetJobs()[-1] + NeomakeTestsWaitForFinishedJobs + AssertEqual g:neomake_test_jobfinished, [{'jobinfo': jobinfo}] + AssertEqual jobinfo.exit_code, 7 + AssertEqual jobinfo.file_mode, 0 + AssertEqual jobinfo.bufnr, bufnr('%') + endif + +Execute (NeomakeJobStarted can renice process): + if NeomakeAsyncTestsSetup() + let maker = NeomakeTestsCommandMaker('nice-sleep', 'sleep .1') + + function! s:NeomakeTestJobStarted(context) abort + AssertEqual keys(a:context), ['jobinfo'] + let pid = a:context.jobinfo.get_pid() + call system(printf('renice 19 %d', pid)) + endfunction + augroup neomake_tests + au User NeomakeJobStarted call s:NeomakeTestJobStarted(g:neomake_hook_context) + augroup END + + let job = neomake#Make(0, [maker]) + let pid = neomake#GetJob(job[0]).get_pid() + + " Prefer procfs, since 'ps' in busybox cannot select a single PID. + let proc_stat = printf('/proc/%d/stat', pid) + if filereadable(proc_stat) + let niceness = split(readfile(proc_stat)[0])[18] + else + let niceness = substitute(system(printf('ps -o nice= %d', pid)), '\v\s+|\n', '', 'g') + endif + AssertEqual niceness, '19' + + if has('nvim') && !has('nvim-0.2.0') + " Really wait for jobs to finish, otherwise it fails when reloading + " autoload/neomake.vim with E127 (Cannot redefine function) later. + NeomakeTestsWaitForRemovedJobs + else + NeomakeCancelJobs! + endif + endif + +Execute (NeomakeJobInit can make processes nicer): + " Create a maker that writes its niceness to stdout. + " Prefer procfs, since 'ps' in busybox cannot select a single PID. + let proc_stat = printf('/proc/%d/stat', getpid()) + if filereadable(proc_stat) + let get_niceness_cmd = 'cat /proc/$$/stat | cut -f19 -d\ ' + else + let get_niceness_cmd = printf('ps -o nice= %d | tr -d \ ', pid) + endif + let maker = NeomakeTestsCommandMaker('nice-sleep', get_niceness_cmd) + + " Hook into NeomakeJobInit. + function! s:NeomakeTestJobInit(context) abort + AssertEqual keys(a:context), ['jobinfo'] + + let jobinfo = a:context.jobinfo + AssertEqual jobinfo.maker.name, 'nice-sleep' + + " argv can be a list or string. + if type(jobinfo.argv) == type([]) + let jobinfo.argv = ['nice', '-n18'] + jobinfo.argv + else + let jobinfo.argv = 'nice -n 18 '.jobinfo.argv + endif + endfunction + augroup neomake_tests + au User NeomakeJobInit call s:NeomakeTestJobInit(g:neomake_hook_context) + augroup END + + call neomake#Make(0, [maker]) + NeomakeTestsWaitForFinishedJobs + if neomake#has_async_support() + AssertNeomakeMessage printf("Starting async job: nice -n18 %s -c 'cat /proc/$$/stat | cut -f19 -d\\ '.", &shell), 2 + else + AssertNeomakeMessage printf("Starting [string]: nice -n 18 %s -c 'cat /proc/$$/stat | cut -f19 -d\\ '.", &shell) + endif + + let niceness = getqflist()[0].text + AssertEqual niceness, '18' diff --git a/bundle/neomake/tests/include/init.vim b/bundle/neomake/tests/include/init.vim new file mode 100644 index 000000000..04119b0b3 --- /dev/null +++ b/bundle/neomake/tests/include/init.vim @@ -0,0 +1,698 @@ +" Sourced by ./setup.vader. +" Keeping this in a separate file is better for performance. + +function! s:wait_for_jobs(filter) + let max = 45 + while 1 + let jobs = copy(neomake#GetJobs()) + if !empty(a:filter) + let jobs = filter(jobs, a:filter) + endif + if empty(jobs) + break + endif + let max -= 1 + if max == 0 + for j in jobs + call vader#log('Remaining job: '.string(neomake#utils#fix_self_ref(j))) + endfor + throw len(jobs).' jobs did not finish after 3s.' + endif + exe 'sleep' (max < 25 ? 100 : max < 35 ? 50 : 10).'m' + endwhile +endfunction +command! NeomakeTestsWaitForFinishedJobs call s:wait_for_jobs("!get(v:val, 'finished')") +command! NeomakeTestsWaitForRemovedJobs call s:wait_for_jobs('') + +function! s:wait_for_next_message() + let max = 45 + let n = len(g:neomake_test_messages) + while 1 + let max -= 1 + if max == 0 + throw 'No new message appeared after 3s.' + endif + exe 'sleep' (max < 25 ? 100 : max < 35 ? 50 : 10).'m' + if len(g:neomake_test_messages) != n + break + endif + endwhile +endfunction +command! NeomakeTestsWaitForNextMessage call s:wait_for_next_message() + +function! s:wait_for_message(...) + let max = 45 + let n = g:neomake_test_messages_last_idx + 1 + let timeout = get(a:0 > 3 ? a:4 : {}, 'timeout', 3000) + if timeout < 300 + throw 'NeomakeTestsWaitForMessage: timeout should be at least 300 (ms), got: '.string(timeout) + endif + let error = '' + let total_slept = 0 + while 1 + let max -= 1 + if max == 0 + if empty(error) + let error = printf('No new message appeared after %dms.', timeout) + endif + let error .= ' (total wait time: '.total_slept.'m)' + throw error + endif + let ms = (max < 25 ? (timeout/30)+1 : max < 35 ? (timeout/60)+1 : (timeout/300)+1) + let total_slept += ms + exe 'sleep' ms.'m' + if len(g:neomake_test_messages) > n + try + call call('s:AssertNeomakeMessage', a:000) + catch + let error = v:exception + let n = len(g:neomake_test_messages) + continue + endtry + break + endif + endwhile +endfunction +command! -nargs=+ NeomakeTestsWaitForMessage call s:wait_for_message() + +function! s:wait_for_finished_job() + if !neomake#has_async_support() && !has('timers') + return + endif + if !exists('#neomake_tests') + call g:NeomakeSetupAutocmdWrappers() + endif + let max = 45 + let n = len(g:neomake_test_jobfinished) + let start = neomake#compat#reltimefloat() + while 1 + let max -= 1 + if max == 0 + throw printf('No job finished after %.3fs.', neomake#compat#reltimefloat() - start) + endif + exe 'sleep' (max < 25 ? 10 : max < 35 ? 5 : 1).'m' + if len(g:neomake_test_jobfinished) != n + break + endif + endwhile +endfunction +command! NeomakeTestsWaitForNextFinishedJob call s:wait_for_finished_job() + +command! -nargs=* RunNeomake Neomake + \ | NeomakeTestsWaitForFinishedJobs +command! -nargs=* RunNeomakeProject NeomakeProject + \ | NeomakeTestsWaitForFinishedJobs +command! -nargs=* CallNeomake call neomake#Make() + \ | NeomakeTestsWaitForFinishedJobs + +" NOTE: NeomakeSh does not use '-bar'. +command! -nargs=* RunNeomakeSh call RunNeomakeSh() +function! RunNeomakeSh(...) + call call('neomake#Sh', a:000) + NeomakeTestsWaitForFinishedJobs +endfunction + +let s:tempname = tempname() + +function! g:NeomakeTestsCreateExe(name, ...) + let lines = a:0 ? a:1 : ['#!/bin/sh'] + let path_separator = exists('+shellslash') ? ';' : ':' + let dir_separator = exists('+shellslash') ? '\' : '/' + let tmpbindir = s:tempname . dir_separator . 'neomake-vader-tests' + let exe = tmpbindir.dir_separator.a:name + if $PATH !~# tmpbindir . path_separator + if !isdirectory(tmpbindir) + call mkdir(tmpbindir, 'p', 0770) + endif + call g:NeomakeTestsSetPATH(tmpbindir . ':' . $PATH) + endif + call writefile(lines, exe) + if exists('*setfperm') + call setfperm(exe, 'rwxrwx---') + else + " XXX: Windows support + call system('/bin/chmod 770 '.shellescape(exe)) + Assert !v:shell_error, 'Got shell_error with chmod: '.v:shell_error + endif + return exe +endfunction + +let s:saved_path = 0 +function! g:NeomakeTestsSetPATH(path) abort + if !s:saved_path + Save $PATH + let s:saved_path = 1 + endif + let $PATH = a:path +endfunction + +function! s:AssertNeomakeMessage(msg, ...) + let level = a:0 ? a:1 : -1 + let context = a:0 > 1 ? copy(a:2) : -1 + let options = a:0 > 2 ? a:3 : {} + let found_but_before = -1 + let found_but_context_diff = [] + let ignore_order = get(options, 'ignore_order', 0) + let found_but_other_level = -1 + let idx = -1 + for msg_entry in g:neomake_test_messages + let [l, m, info] = msg_entry + let r = 0 + let idx += 1 + if a:msg[0] ==# '\' + let g:neomake_test_matchlist = matchlist(m, a:msg) + let matches = len(g:neomake_test_matchlist) + else + let matches = m ==# a:msg + endif + if matches + if level == -1 + let r = 1 + else + if l == level + let r = 1 + else + let found_but_other_level = l + endif + endif + endif + if r + if !ignore_order && idx <= g:neomake_test_messages_last_idx + let found_but_before = g:neomake_test_messages_last_idx - idx + let r = 0 + endif + endif + if !r + continue + endif + + if type(context) == type({}) + let context_diff = [] + " Only compare entries relevant for messages. + call filter(context, "index(['id', 'make_id', 'bufnr', 'winnr'], v:key) != -1") + for [k, v] in items(info) + if !has_key(context, k) + continue + endif + let expected = context[k] + try + let same = v ==# expected + catch + call add(context_diff, printf( + \ 'Could not compare context entries (expected: %s, actual: %s): %s', + \ string(expected), string(v), v:exception)) + unlet v " for Vim without patch-7.4.1546 + continue + endtry + if !same + call add(context_diff, printf('Got unexpected value for context.%s: ' + \ ."expected '%s', but got '%s'.", k, string(expected), string(v))) + endif + unlet v " for Vim without patch-7.4.1546 + endfor + let missing = filter(copy(context), 'index(keys(info), v:key) == -1') + for [k, expected] in items(missing) + call add(context_diff, printf('Missing entry for context.%s: ' + \ ."expected '%s', but got nothing.", k, string(expected))) + endfor + let found_but_context_diff = context_diff + if !empty(context_diff) + if ignore_order + continue + endif + throw join(context_diff, "\n") + endif + endif + let g:neomake_test_messages_last_idx = idx + " Make it count as a successful assertion. + Assert 1 + call add(g:_neomake_test_asserted_messages, msg_entry) + return 1 + endfor + if found_but_before != -1 || found_but_other_level != -1 + let msgs = [] + if found_but_other_level != -1 + let msgs += ['for level '.found_but_other_level] + endif + if found_but_before != -1 + let msgs += [printf('%d entries before last asserted one', found_but_before)] + endif + let msg = printf('Message %s was found, but %s.', string(a:msg), join(msgs, ' and ')) + throw msg + endif + if !empty(found_but_context_diff) + throw join(found_but_context_diff, "\n") + endif + throw "Message '".a:msg."' not found." +endfunction +command! -nargs=+ AssertNeomakeMessage call s:AssertNeomakeMessage() + +function! s:AssertNeomakeWarning(msg) + call vader#assert#equal(v:warningmsg, 'Neomake: '.a:msg) + AssertNeomakeMessage 'Neomake warning: '.a:msg, 3 + Assert index(NeomakeTestsGetVimMessages(), v:warningmsg) != -1, 'v:warningmsg was not found in messages. Call NeomakeTestsSetVimMessagesMarker() before.' + let v:warningmsg = '' + call neomake#log#reset_warnings() +endfunction +command! -nargs=1 AssertNeomakeWarning call s:AssertNeomakeWarning() + +function! s:AssertEqualQf(actual, expected, ...) abort + let expected = a:expected + if has('patch-8.0.1782') || has('nvim-0.4.0') + let expected = map(copy(expected), "extend(v:val, {'module': ''})") + endif + call call('vader#assert#equal', [a:actual, expected] + a:000) +endfunction +command! -nargs=1 AssertEqualQf call s:AssertEqualQf() + +function! s:AssertNeomakeMessageAbsent(msg, ...) + try + call call('s:AssertNeomakeMessage', [a:msg] + a:000) + catch /^Message/ + return 1 + endtry + throw 'Found unexpected message: '.a:msg +endfunction +command! -nargs=+ AssertNeomakeMessageAbsent call s:AssertNeomakeMessageAbsent() + +function! s:NeomakeTestsResetMessages() + let g:neomake_test_messages = [] + let g:neomake_test_messages_last_idx = -1 +endfunction +command! NeomakeTestsResetMessages call s:NeomakeTestsResetMessages() + +function! g:NeomakeSetupAutocmdWrappers() + let g:neomake_test_finished = [] + function! s:OnNeomakeFinished(context) + let g:neomake_test_finished += [a:context] + endfunction + + let g:neomake_test_jobfinished = [] + function! s:OnNeomakeJobFinished(context) + let g:neomake_test_jobfinished += [a:context] + endfunction + + let g:neomake_test_countschanged = [] + function! s:OnNeomakeCountsChanged(context) + let g:neomake_test_countschanged += [a:context] + endfunction + + augroup neomake_tests + au! + au User NeomakeFinished call s:OnNeomakeFinished(g:neomake_hook_context) + au User NeomakeJobFinished call s:OnNeomakeJobFinished(g:neomake_hook_context) + au User NeomakeCountsChanged call s:OnNeomakeCountsChanged(g:neomake_hook_context) + augroup END +endfunction + +command! -nargs=1 -bar NeomakeTestsSkip call vader#log('SKIP: ' . ) + +function! NeomakeAsyncTestsSetup() + if neomake#has_async_support() + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + return 1 + endif + NeomakeTestsSkip 'no async support.' +endfunction + +function! NeomakeTestsCommandMaker(name, cmd) + let maker = neomake#utils#MakerFromCommand(a:cmd) + return extend(maker, { + \ 'name': a:name, + \ 'errorformat': '%m', + \ 'append_file': 0}) +endfunction + +let s:jobinfo_count = 0 + +function! NeomakeTestsFakeJobinfo() abort + let s:jobinfo_count += 1 + let make_id = -42 + let jobinfo = neomake#jobinfo#new() + let maker = copy(g:neomake#config#_defaults.maker_defaults) + let maker.name = 'fake_jobinfo_name' + + let make_options = { + \ 'file_mode': 1, + \ 'bufnr': bufnr('%'), + \ } + call extend(jobinfo, extend(copy(make_options), { + \ 'id': s:jobinfo_count, + \ 'ft': '', + \ 'make_id': make_id, + \ 'maker': maker, + \ }, 'force')) + let make_info = neomake#GetStatus().make_info + let make_info[make_id] = { + \ 'make_id': make_id, + \ 'options': make_options, + \ 'verbosity': get(g:, 'neomake_verbose', 1), + \ 'jobs_queue': [jobinfo], + \ 'active_jobs': [], + \ 'finished_jobs': []} + return jobinfo +endfunction + +" Fixtures +let g:sleep_efm_maker = { + \ 'name': 'sleep_efm_maker', + \ 'exe': 'sh', + \ 'args': ['-c', 'sleep 0.01; echo file_sleep_efm:1:E:error message; ' + \ .'echo file_sleep_efm:2:W:warning; ' + \ .'echo file_sleep_efm:1:E:error2'], + \ 'errorformat': '%f:%l:%t:%m', + \ 'append_file': 0, + \ } +let g:sleep_maker = NeomakeTestsCommandMaker('sleep-maker', 'sleep .05; echo slept') +let g:error_maker = NeomakeTestsCommandMaker('error-maker', 'echo error; false') +let g:error_maker.errorformat = '%E%m' +function! g:error_maker.postprocess(entry) abort + let a:entry.bufnr = bufnr('') + let a:entry.lnum = 1 +endfunction +let g:success_maker = NeomakeTestsCommandMaker('success-maker', 'echo success') +let g:success_maker.errorformat = '%-Gsuccess' +let g:true_maker = NeomakeTestsCommandMaker('true-maker', 'true') +let g:entry_maker = {'name': 'entry_maker'} +function! g:entry_maker.get_list_entries(_jobinfo) abort + return get(g:, 'neomake_test_getlistentries', [ + \ {'text': 'error', 'lnum': 1, 'type': 'E', 'bufnr': bufnr('%')}]) +endfunction +let g:success_entry_maker = {} +function! g:success_entry_maker.get_list_entries(_jobinfo) abort + return [] +endfunction +let g:doesnotexist_maker = {'exe': 'doesnotexist'} + +" A maker that generates incrementing errors. +let g:neomake_test_inc_maker_counter = 0 +let s:shell_argv = split(&shell) + split(&shellcmdflag) +function! s:IncMakerInitForJobs(_jobinfo) dict + let g:neomake_test_inc_maker_counter += 1 + let cmd = '' + for i in range(g:neomake_test_inc_maker_counter) + let cmd .= 'echo b'.g:neomake_test_inc_maker_counter.' '.g:neomake_test_inc_maker_counter.':'.i.': buf: '.shellescape(bufname('%')).'; ' + endfor + let self.args = s:shell_argv[1:] + [cmd] + let self.name = 'incmaker_' . g:neomake_test_inc_maker_counter +endfunction +let g:neomake_test_inc_maker = { + \ 'name': 'incmaker', + \ 'exe': s:shell_argv[0], + \ 'InitForJob': function('s:IncMakerInitForJobs'), + \ 'errorformat': '%E%f %m', + \ 'append_file': 0, + \ } + +let s:vim_msgs_marker = '== neomake_tests_marker ==' +function! NeomakeTestsSetVimMessagesMarker() + echom s:vim_msgs_marker +endfunction + +function! NeomakeTestsGetVimMessages() + let msgs = split(neomake#utils#redir('messages'), "\n") + let idx = index(reverse(msgs), s:vim_msgs_marker) + call NeomakeTestsSetVimMessagesMarker() + if idx <= 0 + return [] + endif + return reverse(msgs[0 : idx-1]) +endfunction + +function! NeomakeTestsGetMakerWithOutput(base_maker, stdout, ...) abort + if type(a:stdout) == type([]) + let stdout_file = tempname() + call writefile(a:stdout, stdout_file) + else + let stdout_file = a:stdout + endif + + let maker = copy(a:base_maker) + + if a:0 + let stderr = a:1 + if type(stderr) == type([]) + let stderr_file = tempname() + call writefile(stderr, stderr_file) + else + let stderr_file = a:1 + endif + if a:0 > 1 + let exitcode = a:2 + else + let exitcode = 0 + endif + let maker.exe = &shell + let maker.args = [&shellcmdflag, printf( + \ 'cat %s; cat %s >&2; exit %d', + \ fnameescape(stdout_file), fnameescape(stderr_file), exitcode)] + else + let maker.exe = 'cat' + let maker.args = [stdout_file] + endif + + let maker.append_file = 0 + let maker.name = printf('%s-mocked', get(a:base_maker, 'name', 'unnamed_maker')) + return maker +endfunction + +let s:fixture_root = '/tmp/neomake-tests' + +function! NeomakeTestsFixtureMaker(func, fname) abort + let output_base = getcwd().'/'.substitute(a:fname, '^tests/fixtures/input/', 'tests/fixtures/output/', '') + let stdout = printf('%s.stdout', output_base) + let stderr = printf('%s.stderr', output_base) + let exitcode = readfile(printf('%s.exitcode', output_base))[0] + + let maker = call(a:func, []) + let maker.exe = &shell + let maker.args = [&shellcmdflag, printf( + \ 'cat %s; cat %s >&2; exit %d', + \ fnameescape(stdout), fnameescape(stderr), exitcode)] + let maker.name = printf('%s-fixture', substitute(a:func, '^.*#', '', '')) + + " Massage current buffer. + if get(b:, 'neomake_tests_massage_buffer', 1) + " Write the input file to the temporary root. + let test_fname = s:fixture_root . '/' . a:fname + let test_fname_dir = fnamemodify(test_fname, ':h') + if !isdirectory(test_fname_dir) + call mkdir(test_fname_dir, 'p') + endif + call writefile(readfile(a:fname), test_fname, 'b') + exe 'file ' . s:fixture_root . '/' . a:fname + exe 'lcd '.s:fixture_root + endif + + return maker +endfunction + +function! s:After() + if exists('#neomake_automake') + au! neomake_automake + endif + if exists('#neomake_tests') + autocmd! neomake_tests + augroup! neomake_tests + endif + + Restore + unlet! g:expected " for old Vim with Vader, that does not wrap tests in a function. + + let errors = g:neomake_test_errors + + " Stop any (non-canceled) jobs. Canceled jobs might take a while to call the + " exit handler, but that is OK. + let jobs = filter(neomake#GetJobs(), "!get(v:val, 'canceled', 0)") + if !empty(jobs) + call neomake#log#debug('=== teardown: canceling jobs.') + for job in jobs + call neomake#CancelJob(job.id, !neomake#has_async_support()) + endfor + call add(errors, 'There were '.len(jobs).' jobs left: ' + \ .string(map(jobs, "v:val.make_id.'.'.v:val.id"))) + try + NeomakeTestsWaitForRemovedJobs + catch + call add(errors, printf('Error while waiting for removed jobs: %s', v:exception)) + endtry + endif + + " Check for unexpected errors/warnings. + for [level, name] in [[0, 'error'], [1, 'warning']] + let msgs = filter(copy(g:neomake_test_messages), + \ 'v:val[0] == level && v:val[1] !=# ''automake: timer support is required for delayed events.''') + let asserted_msgs = filter(copy(g:_neomake_test_asserted_messages), + \ 'v:val[0] == level') + let unexpected = [] + for msg in msgs + let asserted_idx = index(asserted_msgs, msg) + if asserted_idx == -1 + call add(unexpected, msg) + else + call remove(asserted_msgs, asserted_idx) + endif + endfor + if !empty(unexpected) + call add(errors, printf('found %d unexpected %s messages: %s', + \ len(unexpected), name, string(unexpected))) + endif + endfor + + let status = neomake#GetStatus() + let make_info = status.make_info + if has_key(make_info, -42) + unlet make_info[-42] + endif + if !empty(make_info) + try + call add(errors, printf('make_info is not empty (%d): %s', + \ len(make_info), + \ neomake#utils#fix_self_ref(make_info))) + call neomake#CancelAllMakes(1) + catch + call add(errors, v:exception) + endtry + for k in keys(make_info) + call remove(make_info, k) + endfor + endif + let actions = filter(copy(status.action_queue), '!empty(v:val)') + if !empty(actions) + call add(errors, printf('action_queue is not empty: %d entries: %s', + \ len(actions), string(status.action_queue))) + try + call neomake#CancelAllMakes(1) + catch + call add(errors, v:exception) + endtry + + " Ensure action_queue is empty, which might not happen via canceling + " (non-existing) makes. + call remove(status.action_queue, 0, -1) + endif + + if exists('g:neomake#action_queue#_s.action_queue_timer') + call add(errors, printf('action_queue_timer exists: %s', string(g:neomake#action_queue#_s))) + endif + + if winnr('$') > 1 + let error = 'More than 1 window after tests: ' + \ .string(map(range(1, winnr('$')), + \ "[winbufnr(v:val), bufname(winbufnr(v:val)), getbufvar(winbufnr(v:val), '&bt')]")) + try + for b in neomake#compat#uniq(sort(tabpagebuflist())) + if bufname(b) !=# '[Vader-workbench]' + exe 'bwipe!' b + endif + endfor + " In case there are two windows with Vader-workbench. + if winnr('$') > 1 + only + endif + catch + Log "Error while cleaning windows: ".v:exception.' (in '.v:throwpoint.').' + endtry + call add(errors, error) + elseif bufname(winbufnr(1)) !=# '[Vader-workbench]' + call add(errors, 'Vader-workbench has been renamed (too many bwipe commands?): '.bufname(winbufnr(1))) + endif + + " Ensure that all w:neomake_make_ids lists have been removed. + for t in [tabpagenr()] + range(1, tabpagenr()-1) + range(tabpagenr()+1, tabpagenr('$')) + for w in range(1, tabpagewinnr(t, '$')) + let val = gettabwinvar(t, w, 'neomake_make_ids') + if !empty(val) " '' (default) or [] (used and emptied). + call add(errors, 'neomake_make_ids left for tab '.t.', win '.w.': '.string(val)) + call settabwinvar(t, w, 'neomake_make_ids', []) + endif + unlet val " for Vim without patch-7.4.1546 + endfor + endfor + + let new_buffers = filter(range(1, bufnr('$')), 'bufexists(v:val) && index(g:neomake_test_buffers_before, v:val) == -1') + if !empty(new_buffers) && has('patch-8.1.0877') + " Filter out unlisted qf buffers, which Vim keeps around. + let new_new_buffers = [] + for b in new_buffers + if !buflisted(b) && getbufvar(b, '&ft') ==# 'qf' + exe 'bwipe!' b + continue + endif + call add(new_new_buffers, b) + endfor + let new_buffers = new_new_buffers + endif + if !empty(new_buffers) + let curbuffers = neomake#utils#redir('ls!') + call add(errors, 'Unexpected/not wiped buffers: '.join(new_buffers, ', ')."\ncurrent buffers:".curbuffers) + for b in new_buffers + exe 'bwipe!' b + endfor + endif + + " Check that no new global functions are defined. + let neomake_output_func_after = neomake#utils#redir('function /\C^[A-Z]') + let funcs = map(split(neomake_output_func_after, '\n'), + \ "substitute(v:val, '\\v^function (.*)\\(.*$', '\\1', '')") + let new_funcs = filter(copy(funcs), 'index(g:neomake_test_funcs_before, v:val) == -1') + if !empty(new_funcs) + call add(errors, 'New global functions (use script-local ones, or :delfunction to clean them): '.string(new_funcs)) + call extend(g:neomake_test_funcs_before, new_funcs) + endif + + " Remove any new augroups, ignoring "neomake_*". + let augroups = split(substitute(neomake#utils#redir('augroup'), '^[ \n]\+', '', ''), '\s\+') + let new_augroups = filter(copy(augroups), 'v:val !~# ''^neomake_'' && index(g:neomake_test_augroups_before, v:val) == -1') + if !empty(new_augroups) + for augroup in new_augroups + exe 'augroup '.augroup + au! + exe 'augroup END' + exe 'augroup! '.augroup + endfor + endif + + " Check that no highlights are left. + let highlights = neomake#highlights#_get() + " Ignore unlisted qf buffers that Vim keeps around + " (having ft='' (likely due to bwipe above)). + if has('patch-8.1.0877') + call filter(highlights['file'], 'buflisted(v:key)') + endif + if highlights != {'file': {}, 'project': {}} + call add(errors, printf('Highlights were not reset (use a new buffer): %s', highlights)) + let highlights.file = {} + let highlights.project = {} + endif + + if exists('#neomake_event_queue') + call add(errors, '#neomake_event_queue is not empty: ' . neomake#utils#redir('au neomake_event_queue')) + autocmd! neomake_event_queue + augroup! neomake_event_queue + endif + + if !empty(v:warningmsg) + call add(errors, printf('There was a v:warningmsg: %s', v:warningmsg)) + let v:warningmsg = '' + call neomake#log#reset_warnings() + endif + + if exists('g:neomake#action_queue#_s.action_queue_timer') + call timer_stop(g:neomake#action_queue#_s.action_queue_timer) + unlet g:neomake#action_queue#_s.action_queue_timer + endif + + if !empty(errors) + if get(g:, 'vader_case_ok', 1) + call map(errors, "printf('%d. %s', v:key+1, v:val)") + throw len(errors)." error(s) in teardown:\n".join(errors, "\n") + else + Log printf('NOTE: %d error(s) in teardown (ignored with failing test).', len(errors)) + endif + endif + echom '' +endfunction +command! NeomakeTestsGlobalAfter call s:After() +" vim: ts=4 sw=4 et diff --git a/bundle/neomake/tests/include/setup.vader b/bundle/neomake/tests/include/setup.vader new file mode 100644 index 000000000..b3d024644 --- /dev/null +++ b/bundle/neomake/tests/include/setup.vader @@ -0,0 +1,64 @@ +" Setup and helpers for all tests. + +Before: + Save g:neomake + + let g:neomake_test_messages = [] + let g:neomake_test_errors = [] + let g:_neomake_test_asserted_messages = [] + let g:neomake_test_log_all_messages = 1 + let g:neomake_test_messages_last_idx = -1 + let g:neomake_test_buffers_before = filter(range(1, bufnr('$')), 'bufexists(v:val)') + + if has('patch-7.4.2200') + call setloclist(0, [], ' ', {'title': 'neomake_test_init'}) + call setqflist([], ' ', {'title': 'neomake_test_init'}) + else + call setloclist(0, []) + call setqflist([]) + endif + + " One-time setup. + if exists(':NeomakeTestsWaitForFinishedJobs') != 2 + if !exists('g:loaded_neomake') + " When running a .vader file manually, without Neomake being loaded. + let plugin_dir = fnamemodify(g:vader_current_file, ':p:h:h:h') + let &runtimepath .= ','.plugin_dir + exe 'source' plugin_dir.'/plugin/neomake.vim' + endif + + exe 'source' finddir('include', fnamemodify(g:vader_file, ':p:h').';').'/init.vim' + + " Work around https://github.com/vim/vim/issues/1676. + if has('patch-7.4.2017') && (!has('patch-8.0.0607') && !has('nvim-0.2.1')) + Log 'NOTE: using cache busting to work around Vim issue 1676.' + let g:neomake_test_cache_bust = [0, 0] + endif + + " Save list of already defined (and whitelisted functions). + " This gets used to check that no new global functions are left over + " on teardown. + let g:neomake_test_funcs_before = map(split(neomake#utils#redir('function /\C^[A-Z]'), '\n'), + \ "substitute(v:val, '\\v^function (.*)\\(.*$', '\\1', '')") + + call extend(g:neomake_test_funcs_before, [ + \ 'GetVimIndent', 'GetVimIndentIntern', + \ 'GetPythonIndent', + \ 'GetJavascriptIndent', + \ 'GetShIndent', + \ 'FugitiveReloadCheck', + \ ]) + + let g:neomake_test_augroups_before = split(substitute(neomake#utils#redir('augroup'), '^[ \n]\+', '', ''), '\s\+') + endif + +After: + NeomakeTestsGlobalAfter + + " Work around https://github.com/vim/vim/issues/1676. + if exists('g:neomake_test_cache_bust') + let bust_name = 'bust_cache_'.g:neomake_test_cache_bust[1] + lgetexpr bust_name.':1676:workaround_vim_issue' + exe 'bwipe' bust_name + let g:neomake_test_cache_bust = [0, g:neomake_test_cache_bust[1]+1] + endif diff --git a/bundle/neomake/tests/integration.vader b/bundle/neomake/tests/integration.vader new file mode 100644 index 000000000..7ede11fd0 --- /dev/null +++ b/bundle/neomake/tests/integration.vader @@ -0,0 +1,1044 @@ +Include: include/setup.vader + +Execute (Neomake with unknown maker): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + Neomake doesnotexist + let make_id = neomake#GetStatus().last_make_id + let bufnr = bufnr('%') + let msgs = g:neomake_test_messages + AssertEqual len(msgs), 4 + if exists('*win_getid') + AssertEqual msgs[0], [3, "Calling Make with options {'ft': '', 'file_mode': 1, 'winid': ".win_getid().", 'enabled_makers': ['doesnotexist']}.", {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}] + else + AssertEqual msgs[0], [3, "Calling Make with options {'ft': '', 'file_mode': 1, 'enabled_makers': ['doesnotexist']}.", {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}] + endif + AssertEqual msgs[1], [0, 'Maker not found (for empty filetype): doesnotexist.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}], + AssertEqual msgs[2], [3, 'Nothing to make: no valid makers.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}], + AssertEqual msgs[3], [3, 'Cleaning make info.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}] + " ACK the error. + AssertNeomakeMessage 'Maker not found (for empty filetype): doesnotexist.', 0 + +Execute (Neomake with unknown maker (file_mode=0)): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + Neomake! doesnotexist + let make_id = neomake#GetStatus().last_make_id + let bufnr = bufnr('%') + let msgs = g:neomake_test_messages + AssertEqual len(msgs), 4 + AssertEqual msgs[0], [3, "Calling Make with options {'ft': '', 'file_mode': 0, 'enabled_makers': ['doesnotexist']}.", {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}] + AssertEqual msgs[1], [0, 'Maker not found (without filetype): doesnotexist.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}], + AssertEqual msgs[2], [3, 'Nothing to make: no valid makers.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}], + AssertEqual msgs[3], [3, 'Cleaning make info.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}] + " ACK the error. + AssertNeomakeMessage 'Maker not found (without filetype): doesnotexist.', 0 + +Execute (Neomake with unknown maker for multiple fts): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + new + set filetype=ft1.ft2 + Neomake doesnotexist + let make_id = neomake#GetStatus().last_make_id + let bufnr = bufnr('%') + let msgs = g:neomake_test_messages + if exists('*win_getid') + AssertEqual msgs[0], [3, "Calling Make with options {'ft': 'ft1.ft2', 'file_mode': 1, 'winid': ".win_getid().", 'enabled_makers': ['doesnotexist']}.", {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}] + else + AssertEqual msgs[0], [3, "Calling Make with options {'ft': 'ft1.ft2', 'file_mode': 1, 'enabled_makers': ['doesnotexist']}.", {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}] + endif + AssertEqual msgs[1:], [ + \ [0, 'Maker not found (for filetype ft1.ft2): doesnotexist.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}], + \ [3, 'Nothing to make: no valid makers.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}], + \ [3, 'Cleaning make info.', {'make_id': make_id, 'bufnr': bufnr, 'winnr': winnr()}]] + bwipe + " ACK the error. + AssertNeomakeMessage 'Maker not found (for filetype ft1.ft2): doesnotexist.', 0 + +Execute (neomake#Make in file mode with no filetype and no makers): + AssertEqual &ft, '' + AssertEqual neomake#Make(1, []), [] + let make_id = neomake#GetStatus().last_make_id + AssertNeomakeMessage 'Nothing to make: no enabled file mode makers (filetype=).', + \ 1, {'make_id': make_id, 'bufnr': bufnr('%')} + Assert len(g:neomake_test_messages), 1 + +Execute (neomake#Make in project mode with no filetype and no makers): + Save &makeprg + let &makeprg = 'sh -c "sleep 0.1"' + let job_ids = neomake#Make(0, []) + AssertEqual len(job_ids), 1 + let jobs = neomake#GetJobs() + if neomake#has_async_support() + let jobs_by_ids = neomake#GetJobs(job_ids) + let job_by_id = neomake#GetJob(job_ids[0]) + AssertEqual len(jobs), 1 + AssertEqual jobs, [job_by_id] + AssertEqual jobs, jobs_by_ids + AssertEqual job_by_id.maker.name, 'makeprg' + NeomakeTestsWaitForFinishedJobs + else + AssertEqual len(jobs), 0 + endif + + " New interface to neomake#Make (dict). + let jobinfos = neomake#Make({'file_mode': 0}) + AssertEqual len(jobinfos), 1 + let jobs = neomake#GetJobs() + if neomake#has_async_support() + let job_ids = map(copy(jobinfos), 'v:val.id') + let jobs_by_ids = neomake#GetJobs(job_ids) + let job_by_id = neomake#GetJob(job_ids[0]) + AssertEqual len(jobs), 1 + AssertEqual jobs, [job_by_id] + AssertEqual jobs, jobs_by_ids + AssertEqual job_by_id.maker.name, 'makeprg' + AssertEqual job_by_id, jobinfos[0] + NeomakeTestsWaitForFinishedJobs + else + AssertEqual len(jobs), 0 + endif + +Execute (Reports exit status: 7): + call neomake#Sh("sh -c 'exit 7'") + let exit_msg = 'sh: sh -c ''exit 7'': completed with exit code 7.' + if neomake#has_async_support() + let jobinfo = neomake#GetJobs()[-1] + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'exit: sh: sh -c ''exit 7'': 7.', 3, jobinfo + AssertNeomakeMessage exit_msg, 3, jobinfo + else + " XXX: jobinfo gets used in messages, but is hard to get here, so we do not + " compare it. + AssertNeomakeMessage 'exit: sh: sh -c ''exit 7'': 7.', 3 + AssertThrows AssertNeomakeMessage exit_msg, 3 + AssertEqual g:vader_exception, 'Vim(call):E121: Undefined variable: exit_msg' + endif + +Execute (neomake#Sh: job_id): + let job_id = neomake#Sh('true') + Assert job_id > 0, 'Correct job_id: '.job_id + NeomakeTestsWaitForFinishedJobs + +Execute (Neomake picks up custom maker correctly): + let g:neomake_c_lint_maker = { + \ 'exe': 'echo', + \ 'args': ['%:p', '--foo', 'bar'], + \ 'append_file': 0, + \ 'errorformat': '%f:%l:%c: %m', + \ } + new + file file1 + let fname = expand('%:p') + Save &filetype + set filetype=c + + Neomake lint + if neomake#has_async_support() + AssertNeomakeMessage printf("Starting async job: echo %s --foo bar.", fname) + NeomakeTestsWaitForFinishedJobs + else + AssertNeomakeMessage printf('Starting [string]: echo %s --foo bar.', fname) + endif + bwipe + +Execute (Test Neomake on errors.sh with one maker): + call g:NeomakeSetupAutocmdWrappers() + new + edit tests/fixtures/errors.sh + AssertEqual getline(1), '#! /bin/bash' + + call g:NeomakeTestsCreateExe('shellcheck', []) + let enabled_makers = neomake#GetEnabledMakers('sh') + call map(enabled_makers, 'v:val.name') + AssertEqual enabled_makers, ['sh', 'shellcheck'] + + AssertEqual len(g:neomake_test_finished), 0 + AssertEqual len(g:neomake_test_countschanged), 0 + RunNeomake sh + AssertNotEqual getloclist(0), [], 'loclist was not filled' + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_countschanged), 1 + + let bufnr = bufnr('%') + RunNeomake sh + AssertEqual len(g:neomake_test_countschanged), 3 + for idx in range(0, len(g:neomake_test_countschanged)) + AssertEqual [idx, g:neomake_test_countschanged[1].file_mode], [idx, 1] + AssertEqual [idx, g:neomake_test_countschanged[1].bufnr], [idx, bufnr] + endfor + + " Basic verification that signs are placed. + AssertNeomakeMessage 'Placing sign: sign place 5000 line=5 name=neomake_file_err buffer='.bufnr.'.', 3, {'bufnr': bufnr} + " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_err, lnum=5.', 3, {'bufnr': bufnr} + AssertNeomakeMessage 'Reused 1 signs.', 3 + + AssertEqual neomake#signs#by_lnum(bufnr), {'5': [[5000, 'neomake_file_err']]} + bwipe + +Execute (NeomakeCountsChanged gets triggered with skipped entries): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + call g:NeomakeSetupAutocmdWrappers() + new + edit tests/fixtures/errors.sh + let b:neomake_sh_shellcheck_maker = {'exe': 'echo', 'args': 'skipped_entry: '} + RunNeomake sh shellcheck + AssertEqual len(g:neomake_test_countschanged), 2 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Running makers: sh, shellcheck.' + AssertNeomakeMessage printf( + \ '\VSkipped 1 entries without bufnr: [{''lnum'': 0, ''bufnr'': 0, \.\*''text'': ''skipped_entry: %s''}].', + \ expand('%')), 3 + bwipe + +Execute (Neomake: handle result for current window): + call g:NeomakeSetupAutocmdWrappers() + new + file file_sleep_efm + let orig_winnr = winnr() + call neomake#Make(1, [g:sleep_efm_maker]) + if neomake#has_async_support() + new + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Queuing action process_pending_output for BufEnter, WinEnter.', 3 + AssertNeomakeMessage 'Output left to be processed, not cleaning job yet.', 3 + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_finished), 0, "output pending" + AssertEqual map(getloclist(0), 'v:val.text'), [] + let bufnr = bufnr('%') + Assert exists('#neomake_event_queue'), 'action queue exists' + quit + AssertNeomakeMessage 'action queue: processing for WinEnter (1 items).', 3, {'winnr': 2} + Assert !exists('#neomake_event_queue'), 'action queue does not exist' + AssertEqual winnr(), orig_winnr + AssertEqual map(getloclist(0), 'v:val.text'), ['error message', 'warning', 'error2'] + endif + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_countschanged), 1 + bwipe + if exists('bufnr') + exe 'bwipe' bufnr + endif + +Execute (Neomake: handle output for removed window): + if NeomakeAsyncTestsSetup() + new + file file_sleep_efm + let bufnr = bufnr('%') + call neomake#Make(1, [g:sleep_efm_maker]) + let jobinfo = neomake#GetJobs()[0] + let make_info = values(neomake#GetStatus().make_info)[0] + let make_bufnr = bufnr('%') + quit + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_countschanged), 0, + \ "counts changed (".len(g:neomake_test_countschanged).")" + AssertEqual len(g:neomake_test_finished), 0 + AssertNeomakeMessage 'Skipped pending job output for another buffer (current='.bufnr('%').').', 3, {'bufnr': make_bufnr} + AssertNeomakeMessage 'Output left to be processed, not cleaning job yet.' + + new + AssertEqual len(g:neomake_test_finished), 0 + AssertNeomakeMessage 'Skipped pending job output for another buffer (current='.bufnr('%').').', 3, {'bufnr': make_bufnr} + + " Opening the buffer in another window should process its output. + exe 'b' bufnr + doautocmd BufEnter + AssertNeomakeMessage "Processing pending output for job's buffer in new window." + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist" + AssertNeomakeMessage 'Creating location list for entries.', 3, make_info + else + AssertNeomakeMessage 'Creating location list.', 3, make_info + endif + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual map(getloclist(0), 'v:val.text'), ['error message', 'warning', 'error2'] + bwipe # + exe 'bwipe' bufnr + endif + +Execute (Neomake: handle wiped buffer): + " Check that there is no error, e.g. for highlights. + if NeomakeAsyncTestsSetup() + new + laddexpr 'init_loclist' + new + edit tests/fixtures/errors.sh + let bufnr = bufnr('%') + + call neomake#Make(1, [g:sleep_maker]) + bwipe + let jobinfo = neomake#GetJobs()[0] + let make_info = values(neomake#GetStatus().make_info)[0] + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_countschanged), 0, + \ "counts changed (".len(g:neomake_test_countschanged).")" + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'No buffer found for output!', 2 + AssertNeomakeMessage 'Cleaning jobinfo.', 3, jobinfo + AssertNeomakeMessage 'No buffer found for location list!', 2 + AssertNeomakeMessage 'Cleaning make info.', 3 + AssertEqual neomake#CancelJob(jobinfo.id), 0, "stale job was removed" + AssertNeomakeMessage 'CancelJob: job not found: ' . jobinfo.id . '.', 0 + AssertEqual getloclist(0)[0].text, 'init_loclist' + bwipe + endif + +Execute (Neomake: handle wiped buffer without output): + " Check that there is no error, e.g. for highlights. + if NeomakeAsyncTestsSetup() + new + laddexpr 'init_loclist' + new + let bufnr = bufnr('%') + let jobinfo = neomake#Make({'enabled_makers': [g:true_maker]})[0] + bwipe + let make_info = values(neomake#GetStatus().make_info)[0] + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_countschanged), 0, 'counts changed ('.len(g:neomake_test_countschanged).')' + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Cleaning jobinfo.', 3, jobinfo + AssertNeomakeMessage 'File-level errors cleaned.', 3, make_info + AssertNeomakeMessage 'No buffer found for location list!', 2, {'make_id': jobinfo.make_id, 'bufnr': jobinfo.bufnr} + AssertNeomakeMessage 'Cleaning make info.', 3 + AssertEqual getloclist(0)[0].text, 'init_loclist' + bwipe + endif + +Execute (Neomake: handle pending output across windows/buffers): + " Check that there is no error, e.g. for highlights. + if NeomakeAsyncTestsSetup() + new + AssertEqual winnr(), 2 + edit tests/fixtures/errors.sh + let bufnr = bufnr('%') + Neomake sh + let make_bufnr = bufnr('%') + new + let jobinfo = neomake#GetJobs()[0] + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Output left to be processed, not cleaning job yet.' + + " Trigger processing of pending output. + new + let new_bufnr = bufnr('%') + AssertNeomakeMessage 'Skipped pending job output for another buffer (current='.bufnr('%').').', 3, {'bufnr': make_bufnr} + AssertEqual len(g:neomake_test_jobfinished), 0 + AssertEqual len(g:neomake_test_finished), 0 + exe 'b' bufnr + AssertNeomakeMessage 'Skipped pending job output (not in origin window).', 3, jobinfo + quit + AssertNeomakeMessage 'Skipped pending job output for another buffer (current='.bufnr('%').').', 3, {'bufnr': make_bufnr} + bwipe + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual neomake#CancelJob(jobinfo.id), 0, "stale job was removed" + AssertNeomakeMessage 'CancelJob: job not found: ' . jobinfo.id . '.', 0 + exe 'bwipe' bufnr + exe 'bwipe' new_bufnr + endif + +Execute (NeomakeSh: true): + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + AssertEqual g:neomake_test_countschanged, [] + let bufnr = bufnr('%') + RunNeomakeSh true + AssertEqual g:neomake_test_countschanged, [] + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual getqflist(), [] + + call g:NeomakeSetupAutocmdWrappers() + RunNeomakeSh true + AssertEqual g:neomake_test_countschanged, [] + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual getqflist(), [] + +Execute (NeomakeSh: echo foo): + call g:NeomakeSetupAutocmdWrappers() + AssertEqual g:neomake_test_countschanged, [] + let bufnr = bufnr('%') + RunNeomakeSh echo foo + AssertEqualQf getqflist(), + \ [{'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': '', 'pattern': '', 'text': 'foo'}] + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual g:neomake_test_countschanged[0].jobinfo.bufnr, bufnr + AssertEqual g:neomake_test_countschanged[0].jobinfo.file_mode, 0 + AssertEqual g:neomake_test_countschanged[0].reset, 0 + AssertEqual sort(keys(g:neomake_test_countschanged[0])), ['jobinfo', 'reset'] + +Execute (NeomakeSh: non-existing command): + call g:NeomakeSetupAutocmdWrappers() + RunNeomakeSh 'nonexistingcommand' + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual len(getqflist()), 1 + AssertNeomakeMessage "exit: sh: 'nonexistingcommand': 127.", 3 + if neomake#has_async_support() + AssertNeomakeMessage 'sh: ''nonexistingcommand'': completed with exit code 127.', 3 + endif + let qflist_text = getqflist()[0].text + AssertNotEqual match(qflist_text, 'command not found'), -1, "error in qflist: ".qflist_text + +Execute (NeomakeSh!: handle unfinished output on exit): + call g:NeomakeSetupAutocmdWrappers() + NeomakeSh! sh -c 'echo 1; printf 2; sleep 0.01; echo -n 3' + if neomake#has_async_support() + for i in range(0, 10) + if len(g:neomake_test_countschanged) == 1 + AssertEqual map(getqflist(), 'v:val.text'), ['1'], + \ "only the first line should be there (buffer_output=0)" + break + endif + sleep 20m + endfor + AssertNotEqual i, 20, 'counts should have changed after 200ms: i='.i + NeomakeTestsWaitForFinishedJobs + endif + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(getqflist(), 'v:val.text'), ['1', '23'] + AssertEqual len(g:neomake_test_countschanged), 2 + +Execute (NeomakeSh: buffers output): + call g:NeomakeSetupAutocmdWrappers() + NeomakeSh sh -c 'echo 1; printf 2; sleep 0.01; echo -n 3' + if neomake#has_async_support() + for i in range(0, 10) + if len(g:neomake_test_countschanged) + break + endif + sleep 5m + endfor + AssertNotEqual i, 10, "counts should have changed after 50ms" + NeomakeTestsWaitForFinishedJobs + endif + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(getqflist(), 'v:val.text'), ['1', '23'] + AssertEqual len(g:neomake_test_countschanged), 1 + +Execute (NeomakeSh: project: handle removed window on exit (quit)): + call g:NeomakeSetupAutocmdWrappers() + new + let bufnr = bufnr('%') + NeomakeSh sh -c 'sleep 0.01; echo finished' + let make_id = neomake#GetStatus().last_make_id + quit + if neomake#has_async_support() + AssertEqual len(g:neomake_test_finished), 0 + NeomakeTestsWaitForFinishedJobs + endif + AssertEqual map(getqflist(), 'v:val.text'), ['finished'] + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_countschanged), 1 + exe 'bwipe' bufnr + +Execute (NeomakeSh: project: handle removed window on exit (bwipe)): + call g:NeomakeSetupAutocmdWrappers() + new + let bufnr = bufnr('%') + NeomakeSh sh -c 'sleep 0.01; echo finished' + let make_id = neomake#GetStatus().last_make_id + bwipe + Assert bufnr != bufnr('%'), 'buffer has been wiped' + if neomake#has_async_support() + AssertEqual len(g:neomake_test_finished), 0 + NeomakeTestsWaitForFinishedJobs + endif + AssertEqual map(getqflist(), 'v:val.text'), ['finished'] + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_countschanged), 1 + +Execute (NeomakeListJobs with job cancellation): + let maker1 = NeomakeTestsCommandMaker('cmd maker 1', 'sleep .5') + let maker2 = NeomakeTestsCommandMaker('cmd maker 2', 'sleep .1; echo job2') + let maker3 = {'exe': 'sleep', 'args': '.1', 'append_file': 0, 'name': ''} + let job1 = neomake#Make({'enabled_makers': [maker1]})[0] + let job2 = neomake#Make({'enabled_makers': [maker2], 'name': 'My custom name'})[0] + let job3 = neomake#Make({'enabled_makers': [maker3]})[0] + + let info = split(neomake#utils#redir('NeomakeListJobs'), '\n') + if neomake#has_async_support() + let make_info_3 = neomake#GetStatus().make_info[job3.make_id] + AssertEqual info, [ + \ 'make_id | job_id | name/maker', + \ printf('%7d | %6d | cmd maker 1', job1.make_id, job1.id), + \ printf('%7d | %6d | My custom name (cmd maker 2)', job2.make_id, job2.id), + \ printf('%7d | %6d | neomake_%d', job3.make_id, job3.id, job3.id), + \ ] + AssertEqual map(copy(neomake#GetJobs()), 'v:val.as_string()'), [ + \ 'Job '.job1.id.': cmd maker 1', + \ 'Job '.job2.id.': My custom name', + \ 'Job '.job3.id.': neomake_'.job3.id] + call neomake#CancelJob(job1.id) + AssertEqual map(copy(neomake#GetJobs()), 'v:val.as_string()'), [ + \ 'Job '.job1.id.': cmd maker 1 [canceled]', + \ 'Job '.job2.id.': My custom name', + \ 'Job '.job3.id.': neomake_'.job3.id] + normal! V + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Not processing output for mode "V".' + AssertEqual map(copy(neomake#GetJobs()), 'v:val.as_string()'), [ + \ 'Job '.job2.id.': My custom name [finished]'] + exe "normal! \" + " flaky on vim-master?! + AssertNeomakeMessage 'Cleaning jobinfo.', 3, job3, {'ignore_order': 1} + AssertNeomakeMessage 'Postponing final location list handling for mode "V".', 3, make_info_3 + AssertNeomakeMessage 'Queuing action handle_locqf_list_for_finished_jobs for CursorHold, WinEnter.', 3, make_info_3 + AssertNeomakeMessage 'Skipping cleaning of make info for queued actions.', 3 + + doautocmd CursorHold + AssertNeomakeMessage 'action queue: processing for CursorHold (2 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'Processing 1 lines of output.', 3 + AssertNeomakeMessage 'action queue: processed 2 items.', 3 + + NeomakeTestsWaitForFinishedJobs + else + AssertEqual info, ['This Vim version has no support for jobs.'] + endif + +Execute (Having an invalid &errorformat is OK): + Save &errorformat + let &efm = '%E%W' + NeomakeSh sh -c 'true' + NeomakeTestsWaitForFinishedJobs + +Execute (Neomake with windo): + if NeomakeAsyncTestsSetup() + Assert winnr() == 1, "Starting at window 1" + tabnew + file b1 + topleft new + file b2 + topleft new + file b3 + AssertEqual winnr(), 1 + windo call neomake#Make(1, [g:neomake_test_inc_maker]) + 3wincmd w + AssertEqual getloclist(3), [] + + NeomakeTestsWaitForFinishedJobs + AssertEqual getloclist(1), [] + AssertEqual getloclist(2), [] + let ll_3 = getloclist(3)[0].text + 1wincmd w + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 1} + let ll_1 = getloclist(1)[0].text + 2wincmd w + let ll_2 = getloclist(2)[0].text + Assert ll_3 > ll_2, "Loclist 3 is newer than 2" + Assert ll_2 > ll_1, "Loclist 2 is newer than 1" + AssertEqual neomake#statusline#LoclistCounts(winbufnr(1)), {'E': 3} + AssertEqual neomake#statusline#LoclistCounts(winbufnr(2)), {'E': 2} + AssertEqual neomake#statusline#LoclistCounts(winbufnr(3)), {'E': 1} + tabclose + bwipe b1 + bwipe b2 + bwipe b3 + endif + +Execute (NeomakeSh: two jobs after each other): + if NeomakeAsyncTestsSetup() + NeomakeSh sh -c 'echo 1' + NeomakeSh sh -c 'echo 2' + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 2 + " NOTE: 2nd job clears list. + " TODO: add a command/option to skip that, e.g. NeomakeSh -append?! + AssertEqual len(getqflist()), 1, 'only one quickfix entry' + AssertEqual len(g:neomake_test_finished), 2, 'two jobs have run' + endif + +Execute (Neomake!: two jobs after each other): + if NeomakeAsyncTestsSetup() + Save g:neomake_maker1_maker + let g:neomake_maker1_maker = { + \ 'name': '1', + \ 'exe': 'sh', + \ 'args': ['-c', 'echo 1'], + \ 'errorformat': '%m', + \ } + Save g:neomake_maker2_maker + let g:neomake_maker2_maker = { + \ 'name': '2', + \ 'exe': 'sh', + \ 'args': ['-c', 'echo 2'], + \ 'errorformat': '%m', + \ } + new + let b:neomake_enabled_makers = ['maker1', 'maker2'] + Neomake! maker1 maker2 + NeomakeTestsWaitForFinishedJobs + AssertEqual sort(map(getqflist(), 'v:val.text')), ['1', '2'] + AssertEqual len(g:neomake_test_countschanged), 2, 'counts have changed: '.len(g:neomake_test_countschanged) + AssertEqual len(g:neomake_test_finished), 1 + bwipe + endif + +Execute (Neomake!: non-existing and proper job): + if NeomakeAsyncTestsSetup() + " TODO: Trigger failed job (but raising an exception) with Vim. + " Should find a way to trigger a "failed" job by itself! + " Save g:neomake_extend_job_opts_vim + " let g:neomake_extend_job_opts_vim = { + " \ 'in_io': 'file', + " \ 'in_name': '/doesnotexist', + " \ } + Save g:neomake_maker1_maker + let g:neomake_maker1_maker = { + \ 'name': '1', + \ 'exe': 'doesnotexist', + \ 'args': [], + \ 'errorformat': '%m', + \ } + Save g:neomake_maker2_maker + let g:neomake_maker2_maker = neomake#utils#MakerFromCommand('echo 1') + new + let b:neomake_enabled_makers = ['maker1', 'maker2'] + Neomake! maker1 maker2 + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage "Exe (doesnotexist) of maker 1 is not executable." + AssertEqual map(getqflist(), 'v:val.text'), ['1'] + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_countschanged), 1, + \ 'counts have changed' + bwipe + endif + +Execute (Neomake#Make: error with failing job via jobstart/argv): + call g:NeomakeSetupAutocmdWrappers() + + let maker = {'exe': 'true'} + function! maker._get_argv(...) dict + return neomake#has_async_support() ? ['doesnotexist'] : 'doesnotexist' + endfunction + + call neomake#Make(0, [maker]) + NeomakeTestsWaitForFinishedJobs + + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: doesnotexist." + else + AssertNeomakeMessage "Starting [string]: doesnotexist." + endif + + if has('nvim-0.5') + AssertNeomakeMessage "Failed to start Neovim job: ['doesnotexist']: Vim(let):E475: Invalid value for argument cmd: 'doesnotexist' is not executable.", 0 + elseif has('nvim-0.1.8') + AssertNeomakeMessage "Failed to start Neovim job: Executable not found: ['doesnotexist'].", 0 + elseif has('nvim') + AssertNeomakeMessage 'Failed to start Neovim job: [''doesnotexist'']: ' + \ .'Vim(let):E902: "doesnotexist" is not an executable.' + elseif neomake#has_async_support() + AssertNeomakeMessage 'Vim job failed to run: executing job failed: No such file or directory.' + else + AssertNeomakeMessage 'exit: unnamed_maker: 127.', 3 + endif + + if neomake#has_async_support() + AssertEqual len(g:neomake_test_jobfinished), 0 + AssertEqual len(g:neomake_test_finished), 0 + else + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + endif + " make IDs should have been removed from the window. + AssertEqual w:neomake_make_ids, [] + + +Execute (Neomake#Make: error with failing job via jobstart/argv + true): + call g:NeomakeSetupAutocmdWrappers() + + let maker = {'exe': 'true'} + function! maker._get_argv(...) dict + return neomake#has_async_support() ? ['doesnotexist'] : 'doesnotexist' + endfunction + + call neomake#Make(0, [maker, {'exe': 'true'}]) + NeomakeTestsWaitForFinishedJobs + + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: doesnotexist." + else + AssertNeomakeMessage "Starting [string]: doesnotexist." + endif + + if has('nvim-0.5') + AssertNeomakeMessage "Failed to start Neovim job: ['doesnotexist']: Vim(let):E475: Invalid value for argument cmd: 'doesnotexist' is not executable.", 0 + elseif has('nvim-0.1.8') + AssertNeomakeMessage "Failed to start Neovim job: Executable not found: ['doesnotexist'].", 0 + elseif has('nvim') + AssertNeomakeMessage 'Failed to start Neovim job: [''doesnotexist'']: ' + \ .'Vim(let):E902: "doesnotexist" is not an executable.' + elseif neomake#has_async_support() + AssertNeomakeMessage 'Vim job failed to run: executing job failed: No such file or directory.' + else + AssertNeomakeMessage 'exit: unnamed_maker: 127.', 3 + endif + + if neomake#has_async_support() + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + else + AssertEqual len(g:neomake_test_jobfinished), 2 + AssertEqual len(g:neomake_test_finished), 1 + endif + +Execute (Neomake#Make: error with Vim for unknown opt): + if has('nvim') || !neomake#has_async_support() + NeomakeTestsSkip 'Only for vim-async.' + else + let maker = {'exe': 'true', 'vim_job_opts': {'invalid-job-opt': 1}} + CallNeomake 0, [maker] + AssertNeomakeMessage "Failed to start Vim job: ['true']: Vim(let):E475: Invalid argument: invalid-job-opt.", 0 + endif + +Execute (Neomake! for project maker via g:neomake_enabled_makers): + Save g:neomake_enabled_makers, g:neomake_mycargo_maker + let g:neomake_enabled_makers = ['mycargo'] + let g:neomake_mycargo_maker = { + \ 'exe': 'echo', + \ 'args': ['mycargo'], + \ } + Neomake! + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getqflist(), 'v:val.text'), ['mycargo'] + +Execute (Neomake: remove_invalid_entries and default entry type): + let maker = neomake#utils#MakerFromCommand('echo invalid; echo "E: valid"') + call extend(maker, { + \ 'name': 'custom_maker', + \ 'remove_invalid_entries': 1, + \ 'errorformat': 'E: %m', + \ 'append_file': 0, + \ }) + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage "\\vRemoving invalid entry: invalid \\(\\{'lnum': 0, 'bufnr': 0, .*\\}\\)." + + let valid = has('patch-8.0.0580') + AssertEqualQf getloclist(0), + \ [{'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': valid, 'vcol': 0, 'nr': -1, 'type': 'W', 'pattern': '', 'text': 'valid'}] + +Execute (Neomake: entry.valid < 0 and configured entry type): + let maker = neomake#utils#MakerFromCommand('echo invalid; echo "E: valid"; echo invalid_but_kept; echo invalid_but_kept_as_valid') + call extend(maker, { + \ 'name': 'custom_maker', + \ 'remove_invalid_entries': 0, + \ 'errorformat': 'E: %m', + \ 'append_file': 0, + \ 'default_entry_type': 'I', + \ }) + + function maker.postprocess(entry) abort + if !a:entry.valid + if a:entry.text == 'invalid_but_kept' + let a:entry.type = 'I' + elseif a:entry.text == 'invalid_but_kept_as_valid' + let a:entry.valid = 1 + else + let a:entry.valid = -1 + endif + endif + endfunction + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Processing 4 lines of output.' + AssertNeomakeMessage "\\vRemoving invalid entry: invalid \\(\\{'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': -1, .*\\}\\)." + AssertNeomakeMessage 'Processing 3 entries.' + + " Without this patch entries are invalid always after setqflist/setloclist. + let valid = has('patch-8.0.0580') + AssertEqualQf getloclist(0), [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': valid, 'vcol': 0, 'nr': -1, 'type': 'I', 'pattern': '', 'text': 'valid'}, + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 0, 'vcol': 0, 'nr': -1, 'type': 'I', 'pattern': '', 'text': 'invalid_but_kept'}, + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': valid, 'vcol': 0, 'nr': -1, 'type': 'I', 'pattern': '', 'text': 'invalid_but_kept_as_valid'}] + +Execute (Neomake: append_file from settings and empty entry type): + let maker = { + \ 'exe': 'echo', + \ 'args': ['output'], + \ 'name': 'custom_maker', + \ 'errorformat': '%m', + \ 'default_entry_type': '', + \ } + new + edit tests/fixtures/errors.sh + set ft=myft + + call neomake#Make(1, [maker]) + let bufname = bufname('%') + NeomakeTestsWaitForFinishedJobs + AssertEqualQf getloclist(0), + \ [{'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'output '.bufname}] + + Save g:neomake_myft_custom_maker_maker, g:neomake_myft_custom_maker_append_file + let g:neomake_myft_custom_maker_maker = copy(maker) + let g:neomake_myft_custom_maker_append_file = 0 + RunNeomake custom_maker + AssertEqualQf getloclist(0), + \ [{'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'output'}] + let g:neomake_myft_custom_maker_append_file = 1 + RunNeomake custom_maker + AssertEqualQf getloclist(0), + \ [{'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'output '.bufname}] + + let maker.append_file = 0 + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqualQf getloclist(0), + \ [{'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'output '.bufname}] + + unlet g:neomake_myft_custom_maker_append_file + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqualQf getloclist(0), + \ [{'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'output'}] + bwipe + +Execute (Quickfix list should be cleared only after maker finished): + cgetexpr 'init' + AssertEqual getqflist()[0].text, 'init' + + NeomakeSh echo finished + if neomake#has_async_support() + AssertEqual getqflist()[0].text, 'init' + else + AssertEqual getqflist()[0].text, 'finished' + endif + NeomakeTestsWaitForFinishedJobs + if neomake#has_async_support() + AssertEqual getqflist()[0].text, 'finished' + endif + +Execute (neomake#Sh: exit_callback): + Save g:neomake_test_cb + let g:neomake_test_cb = [] + function! NeomakeTestsAfterExit(job_status) dict + call add(g:neomake_test_cb, [self, a:job_status]) + endfunction + call neomake#Sh('true', function('NeomakeTestsAfterExit')) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_cb), 1 + AssertEqual g:neomake_test_cb[0][1], {'status': 0, 'name': 'sh: true', 'has_next': 0} + delfunction NeomakeTestsAfterExit + +Execute (neomake#Make: exit_callback): + Save g:neomake_test_cb + let g:neomake_test_cb = [] + function! NeomakeTestsAfterExit(job_status) dict + call add(g:neomake_test_cb, [self, a:job_status]) + endfunction + let maker = {'exe': 'true', 'serialize': 1} + call neomake#Make(0, [maker, maker], function('NeomakeTestsAfterExit')) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_cb), 2 + AssertEqual g:neomake_test_cb[0][1], {'status': 0, 'name': 'unnamed_maker', 'has_next': 1} + AssertEqual g:neomake_test_cb[1][1], {'status': 0, 'name': 'unnamed_maker', 'has_next': 0} + delfunction NeomakeTestsAfterExit + +Execute (neomake#Make: exit_callback with maker names): + Save g:neomake_test_cb + let g:neomake_test_cb = [] + function! NeomakeTestsAfterExit(job_status) dict + call add(g:neomake_test_cb, [self, a:job_status]) + endfunction + Save g:neomake_mymaker_maker + let g:neomake_mymaker_maker = {'exe': 'true'} + call neomake#Make(0, ['mymaker'], function('NeomakeTestsAfterExit')) + NeomakeTestsWaitForFinishedJobs + AssertEqual g:neomake_test_cb[0][1], {'status': 0, 'name': 'mymaker', 'has_next': 0} + delfunction NeomakeTestsAfterExit + +Execute (neomake#Make: exit_callback with unknown function (E700)): + call neomake#Make({ + \ 'enabled_makers': [g:true_maker], + \ 'exit_callback': 'NeomakeUnknownFunction', + \ }) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Error during exit_callback: Vim(let):E700: Unknown function: NeomakeUnknownFunction.' + +Execute (neomake#Make: exit_callback with wrong script function): + function! s:NeomakeScriptFunction() + endfunction + call neomake#Make({ + \ 'enabled_makers': [g:true_maker], + \ 'exit_callback': function('s:NeomakeScriptFunction'), + \ }) + NeomakeTestsWaitForFinishedJobs + + if v:version > 703 || (v:version == 703 && has('patch1058')) + AssertNeomakeMessage '\mError during exit_callback: Vim(call):E118: Too many arguments for function: .*NeomakeScriptFunction.', 0 + else + AssertNeomakeMessage '\mError during exit_callback: Vim(call):E117: Unknown function: s:NeomakeScriptFunction.', 0 + endif + +Execute (Location list should be cleared only after first output): + call g:NeomakeSetupAutocmdWrappers() + lgetexpr 'init' + + let s:au_called = [] + function! OnNeomakeJobFinished() abort + if empty(s:au_called) + call add(s:au_called, 1) + call vader#assert#equal([map(getloclist(0), 'v:val.text'), + \ len(g:neomake_test_finished), + \ len(g:neomake_test_countschanged)], + \ [['init'], 0, 0]) + endif + endfunction + augroup neomake_tests + autocmd User NeomakeJobFinished call OnNeomakeJobFinished() + augroup END + + let maker_success = NeomakeTestsCommandMaker('success-maker', 'true') + let maker_success.serialize = 1 + let maker_sleep = NeomakeTestsCommandMaker('sleep-maker', 'sleep .01; echo slept') + + call neomake#Make(1, [maker_success, maker_sleep]) + + if neomake#has_async_support() + NeomakeTestsWaitForNextFinishedJob + else + AssertEqual getloclist(0)[0].text, 'slept' + endif + NeomakeTestsWaitForFinishedJobs + AssertEqual s:au_called, [1] + AssertEqual getloclist(0)[0].text, 'slept' + AssertEqual len(g:neomake_test_countschanged), 1 + delfunction OnNeomakeJobFinished + +Execute (Location list should be cleared after jobs finished): + call g:NeomakeSetupAutocmdWrappers() + lgetexpr 'init' + + let maker_success = NeomakeTestsCommandMaker('success-maker', 'true') + + call neomake#Make(1, [maker_success]) + NeomakeTestsWaitForFinishedJobs + + AssertEqual getloclist(0), [] + AssertEqual len(g:neomake_test_countschanged), 0 + +Execute (Highlights should be cleared after successful run): + call g:NeomakeSetupAutocmdWrappers() + lgetexpr 'init' + + let maker_success = NeomakeTestsCommandMaker('success-maker', 'true') + let maker_error = NeomakeTestsCommandMaker('error-maker', 'echo error') + let maker_error.errorformat = '%E%m' + function! maker_error.postprocess(entry) abort + let e = a:entry + let a:entry.lnum = 1 + let a:entry.col = 1 + let a:entry.length = 5 + let a:entry.bufnr = bufnr('%') + endfunction + + call neomake#Make(1, [maker_error]) + NeomakeTestsWaitForFinishedJobs + + AssertEqual getloclist(0)[0].text, 'error' + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 1, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'error'}] + + let highlights = neomake#highlights#_get() + if has('nvim') + let orig_highlight = highlights['file'][bufnr('%')] + else + AssertEqual highlights, { + \ 'file': {bufnr('%'): {'NeomakeError': [[1, 1, 5]], 'NeomakeInfo': [], + \ 'NeomakeMessage': [], 'NeomakeWarning': []}}, + \ 'project': {}} + endif + AssertEqual len(highlights['file']), 1 + + call neomake#Make(1, [maker_success]) + NeomakeTestsWaitForFinishedJobs + + let highlights = neomake#highlights#_get() + Assert !has_key(highlights['file'], bufnr('%')), 'highlight not present' + +Execute (neomake#GetCurrentErrorMsg (get_list_entries)): + new + let maker = {'name': 'my_maker'} + function maker.get_list_entries(...) + let bufnr = bufnr('%') + return [ + \ {'lnum': 1, 'col': 1, 'text': 'error 1.1', 'bufnr': bufnr}, + \ {'lnum': 2, 'col': 1, 'text': 'error 2.1', 'bufnr': bufnr, 'nr': 42}, + \ {'lnum': 3, 'col': 1, 'text': 'error 3.1', 'bufnr': bufnr, 'nr': -1, 'type': ''}, + \ {'lnum': 3, 'col': 2, 'text': 'error 3.2', 'bufnr': bufnr, 'nr': 0, 'type': ''}, + \ {'lnum': 4, 'col': 1, 'text': 'error 4.1', 'bufnr': bufnr, 'type': 'E'}, + \ ] + endfunction + CallNeomake 1, [maker] + + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 1.1 (W)' + normal! o + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 2.1 (W42)' + normal! o + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 3.1' + normal! o + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 4.1 (E)' + normal! k + normal! A12 + normal! l + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 3.2 (0)' + + " Successful maker clears error(s) in file mode. + CallNeomake 1, [g:true_maker] + AssertEqual neomake#GetCurrentErrorMsg(), '' + + " Successful maker clears error(s) in project mode. + CallNeomake 0, [maker] + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 3.2 (0)' + + CallNeomake 0, [g:true_maker] + AssertEqual neomake#GetCurrentErrorMsg(), '' + bwipe! + +Execute (neomake#GetCurrentErrorMsg (cmd maker)): + new + noautocmd file fname + let cmd_maker = NeomakeTestsGetMakerWithOutput({}, [ + \ 'fname:1:1:error 1.1', + \ 'fname:2:1:NR42:error 2.1', + \ 'fname:3:1:E:error 3.1', + \ 'fname:3:2:error 3.2', + \ ]) + let cmd_maker.errorformat = '%f:%l:%c:NR%n:%m,%f:%l:%c:%t:%m,%f:%l:%c:%m' + let cmd_maker.name = 'my_maker' + CallNeomake 1, [cmd_maker] + + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 1.1 (W)' + normal! o + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 2.1 (W42)' + normal! o + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 3.1 (E)' + normal! A12 + normal! l + AssertEqual neomake#GetCurrentErrorMsg(), 'my_maker: error 3.2 (W)' + bwipe! + +Execute (Neomake! clippy): + call g:NeomakeTestsCreateExe('cargo') + RunNeomakeProject clippy + AssertNeomakeMessage 'Running makers: clippy.', 3 diff --git a/bundle/neomake/tests/isolated.vader b/bundle/neomake/tests/isolated.vader new file mode 100644 index 000000000..ab5b81b7e --- /dev/null +++ b/bundle/neomake/tests/isolated.vader @@ -0,0 +1,15 @@ +~ Isolated tests (run separately with coverage) +Include: isolated/compat-get_argv-on-emulated-windows.vader +Include: isolated/configure.vader +Include: isolated/ft_help.vader +Include: isolated/ft_vim.vader +Include: isolated/highlights.vader +Include: isolated/logging.vader +Include: isolated/modes.vader +Include: isolated/tempfiles-cleanup.vader +Include: isolated/resets-ignore_automake_events.vader +Include: isolated/completion-handles-throw.vader +Include: isolated/statusline-highlights.vader +Include: isolated/sign-highlights.vader +Include: isolated/customqf.vader +Include: isolated/signs.vader diff --git a/bundle/neomake/tests/isolated/compat-get_argv-on-emulated-windows.vader b/bundle/neomake/tests/isolated/compat-get_argv-on-emulated-windows.vader new file mode 100644 index 000000000..34649c72c --- /dev/null +++ b/bundle/neomake/tests/isolated/compat-get_argv-on-emulated-windows.vader @@ -0,0 +1,39 @@ +Include: ../include/setup.vader + +Execute (neomake#compat#get_argv on (emulated) Windows): + Save &shell, &shellcmdflag + set shell=cmd.exe + set shellcmdflag=/c + function! neomake#utils#IsRunningWindows() + return 1 + endfunction + runtime autoload/neomake/compat.vim + + let out = neomake#compat#get_argv('sh', ['-c', 'echo 1'], 1) + AssertEqual out, 'cmd.exe /c sh -c "echo 1"' + + " Does not get wrapped in shell twice. + let out = neomake#compat#get_argv('cmd.exe', ['/c', 'echo 1'], 1) + AssertEqual out, 'cmd.exe /c echo 1' + let out = neomake#compat#get_argv('cmd.exe', ['/c', 'echo', '1'], 1) + AssertEqual out, 'cmd.exe /c echo 1' + let out = neomake#compat#get_argv('cmd.exe', ['/c', 'echo "1 1"'], 1) + AssertEqual out, 'cmd.exe /c echo "1 1"' + let out = neomake#compat#get_argv('cmd.exe', ['/c', 'echo', '"1 1"'], 1) + AssertEqual out, 'cmd.exe /c echo "1 1"' + + " Handled correctly with MakerFromCommand/NeomakeSh. + let maker = neomake#utils#MakerFromCommand('echo "1 2"') + let maker = neomake#GetMaker(maker) + let jobinfo = NeomakeTestsFakeJobinfo() + let jobinfo.file_mode = 0 + AssertEqual maker._get_argv(jobinfo), 'cmd.exe /c echo "1 2"' + +Execute (neomake#compat#dev_null on (emulated) Windows): + AssertEqual g:neomake#compat#dev_null, 'NUL' + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/utils.vim + runtime autoload/neomake/compat.vim + endif diff --git a/bundle/neomake/tests/isolated/completion-handles-throw.vader b/bundle/neomake/tests/isolated/completion-handles-throw.vader new file mode 100644 index 000000000..323f3faf4 --- /dev/null +++ b/bundle/neomake/tests/isolated/completion-handles-throw.vader @@ -0,0 +1,27 @@ +Include: ../include/setup.vader + +Execute (neomake#cmd#complete_makers: handles error from maker): + new + noautocmd set filetype=neomake_tests + + " Smoke test. + let completions = neomake#cmd#complete_makers('tru', 'Neomake tru') + AssertEqual completions, ['true'] + + let s:called = 0 + function! neomake#makers#ft#neomake_tests#true() abort + let s:called = 1 + throw 'Neomake: some error' + endfunction + + let completions = neomake#cmd#complete_makers('tru', 'Neomake tru') + AssertEqual completions, [] + AssertNeomakeMessage 'Could not get maker true: some error.', 3 + + AssertEqual s:called, 1 + bwipe + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/makers/ft/neomake_tests.vim + endif diff --git a/bundle/neomake/tests/isolated/configure.vader b/bundle/neomake/tests/isolated/configure.vader new file mode 100644 index 000000000..00163da2d --- /dev/null +++ b/bundle/neomake/tests/isolated/configure.vader @@ -0,0 +1,6 @@ +Include: ../include/setup.vader + +Execute (Loading autoload/neomake/configure.vim sets up default settings): + Assert !exists('g:neomake') + runtime! autoload/neomake/configure.vim + AssertEqual g:neomake, {'automake': {'ignore_filetypes': ['startify']}} diff --git a/bundle/neomake/tests/isolated/customqf.vader b/bundle/neomake/tests/isolated/customqf.vader new file mode 100644 index 000000000..d9d490567 --- /dev/null +++ b/bundle/neomake/tests/isolated/customqf.vader @@ -0,0 +1,15 @@ +Execute (syntax/qf.vim handles unused customqf): + if exists('*neomake#quickfix#FormatQuickfix') + delfunction neomake#quickfix#FormatQuickfix + delfunction neomake#quickfix#is_enabled + endif + + call setloclist(0, [{ + \ 'lnum': 1, + \ 'text': 'E123 error nmcfg:{"name": "python", "short": "py"}', + \}]) + lopen + lclose + + " Does not autoload files. + Assert !exists('*neomake#quickfix#is_enabled') diff --git a/bundle/neomake/tests/isolated/ft_help.vader b/bundle/neomake/tests/isolated/ft_help.vader new file mode 100644 index 000000000..9e12a16ff --- /dev/null +++ b/bundle/neomake/tests/isolated/ft_help.vader @@ -0,0 +1,6 @@ +Include: ../include/setup.vader + +Execute (neomake#makers#ft#help#EnabledMakers): + call g:NeomakeTestsCreateExe('vimhelplint', []) + runtime autoload/neomake/makers/ft/help.vim + AssertEqual ['writegood', 'vimhelplint'], neomake#makers#ft#help#EnabledMakers() diff --git a/bundle/neomake/tests/isolated/ft_vim.vader b/bundle/neomake/tests/isolated/ft_vim.vader new file mode 100644 index 000000000..19b141296 --- /dev/null +++ b/bundle/neomake/tests/isolated/ft_vim.vader @@ -0,0 +1,30 @@ +Include: ../include/setup.vader + +Execute (vint: detects stdin support): + runtime autoload/neomake/makers/ft/vim.vim + function! neomake#compat#systemlist(...) + return '' + endfunction + let maker = neomake#GetMaker('vint', 'vim') + AssertEqual maker.supports_stdin({}), 0 + + runtime autoload/neomake/makers/ft/vim.vim + function! neomake#compat#systemlist(...) + return ['0.3.19'] + endfunction + let maker = neomake#GetMaker('vint', 'vim') + AssertEqual maker.supports_stdin({}), 0 + AssertEqual index(maker.args, '--stdin-display-name'), -1 + + runtime autoload/neomake/makers/ft/vim.vim + function! neomake#compat#systemlist(...) + return ['0.4a'] + endfunction + let maker = neomake#GetMaker('vint', 'vim') + AssertEqual maker.supports_stdin({}), 1 + AssertEqual maker.args[-2:], ['--stdin-display-name', '%:.'] + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/compat.vim + endif diff --git a/bundle/neomake/tests/isolated/highlights.vader b/bundle/neomake/tests/isolated/highlights.vader new file mode 100644 index 000000000..e7e018ca4 --- /dev/null +++ b/bundle/neomake/tests/isolated/highlights.vader @@ -0,0 +1,279 @@ +Include: ../include/setup.vader + +Execute (Setup: monkeypatch autoload/neomake/highlights.vim): + " Monkeypatch to check setting of length. + runtime autoload/neomake/highlights.vim + Save g:neomake_tests_highlight_lengths + let g:neomake_tests_highlight_lengths = [] + + function! neomake#highlights#AddHighlight(entry, ...) abort + let bufnr = get(a:entry, 'bufnr', -1) + if !has_key(g:neomake_tests_highlight_lengths, bufnr) + let g:neomake_tests_highlight_lengths[bufnr] = [] + endif + call add(g:neomake_tests_highlight_lengths[bufnr], + \ [get(a:entry, 'lnum', -1), get(a:entry, 'length', -1)]) + endfunction + +Execute (vimlint: length postprocessing): + let g:neomake_tests_highlight_lengths = {} + new + noautocmd edit tests/fixtures/vim/func-with-errors.vim + let maker = neomake#makers#ft#vim#vimlint() + let maker.exe = 'cat' + let maker.args = 'tests/fixtures/vim/func-with-errors.vim.output' + let maker.append_file = 0 + + CallNeomake 1, [maker] + + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, + \ 'bufnr': bufnr, + \ 'col': 6, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': 101, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'undefined variable `l:something`', + \ }, { + \ 'lnum': 5, + \ 'bufnr': bufnr, + \ 'col': 9, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': 104, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'variable may not be initialized on some execution path: `l:foo`', + \ }] + + AssertEqual {string(bufnr): [[2, 11], [5, 3]]}, g:neomake_tests_highlight_lengths + bwipe + +Execute (vint: highlights syntax error for command): + let g:neomake_tests_highlight_lengths = {} + new + file file1.vim + norm! iwhile 1 + norm! oendfor + let vint_maker = neomake#makers#ft#vim#vint() + let vint_maker.exe = 'printf' + let vint_maker.args = ["file1.vim:2:1:error:E588: :endfor without :for (SyntaxError)"] + let vint_maker.append_file = 0 + + CallNeomake 1, [vint_maker] + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, + \ 'bufnr': bufnr, + \ 'col': 1, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': 588, + \ 'type': 'e', + \ 'pattern': '', + \ 'text': ':endfor without :for (SyntaxError)'}] + bwipe! + AssertEqual {string(bufnr): [[2, 6]]}, g:neomake_tests_highlight_lengths + +Execute (get_list_entries: based on example from doc): + let g:neomake_tests_highlight_lengths = {} + new + call g:NeomakeSetupAutocmdWrappers() + let buf1 = bufnr('%') + file get_list_entries_buf1 + + let winnr = winnr() + + let maker = {'name': 'My maker', 'my_orig_bufnr': buf1} + function! maker.get_list_entries(jobinfo) abort + " Change bufnr. + new + return [ + \ {'text': 'Some error', 'lnum': 1, 'bufnr': a:jobinfo.bufnr}, + \ {'text': 'Some warning without bufnr', 'type': 'W', 'lnum': 2, + \ 'col': 1, 'length': 5}, + \ {'text': 'Some warning', 'type': 'W', 'lnum': 2, 'col': 1, + \ 'bufnr': a:jobinfo.maker.my_orig_bufnr, 'length': 2}, + \ {'text': 'Some info', 'type': 'I', 'lnum': 3, 'col': 1, + \ 'filename': '/path/to/file'}, + \ {'text': 'Some non-type', 'type': '', 'lnum': 4, 'col': 1, 'length': 23, + \ 'filename': 'get_list_entries_buf1'}, + \ ] + endfunction + call neomake#Make(1, [maker]) + AssertNeomakeMessage 'Queuing action ProcessEntries for BufEnter, WinEnter.' + AssertEqual {}, g:neomake_tests_highlight_lengths, 'No highlights have been added yet' + AssertEqual [], getloclist(0) + + wincmd p + AssertEqual winnr, winnr() + + let llist = getloclist(0) + + " Check that unlisted buffer was created for filename. + let unlisted_bufnr = bufnr('/path/to/file') + Assert !empty(unlisted_bufnr), 'Unlisted buffer was created (1)' + Assert !buflisted(unlisted_bufnr), 'Unlisted buffer was created (2)' + + AssertEqual { + \ string(buf1): [[1, -1], [2, 2], [4, 23]], + \ string(unlisted_bufnr): [[3, -1]]}, g:neomake_tests_highlight_lengths + + " Check that existing buffer was used for filename. + AssertEqual llist[4].bufnr, buf1, 'get_list_entries_buf1 was picked up' + + AssertNeomakeMessage "Entry 2 differs after adding: {'changed': {'valid': [1, 0]}}.", 3 + AssertNeomakeMessage "Entry 4 differs after adding: {'changed': {'bufnr': [0, ".unlisted_bufnr."]}, 'removed': {'filename': '/path/to/file'}}.", 3 + AssertNeomakeMessage "Entry 5 differs after adding: {'changed': {'bufnr': [0, ".buf1."]}, 'removed': {'filename': 'get_list_entries_buf1'}}.", 3 + + AssertEqualQf llist, [ + \ {'lnum': 1, 'bufnr': buf1, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'Some error'}, + \ {'lnum': 2, 'bufnr': 0, 'col': 1, 'valid': 0, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'Some warning without bufnr'}, + \ {'lnum': 2, 'bufnr': buf1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'Some warning'}, + \ {'lnum': 3, 'bufnr': unlisted_bufnr, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'I', 'pattern': '', 'text': 'Some info'}, + \ {'lnum': 4, 'bufnr': buf1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': '', 'pattern': '', 'text': 'Some non-type'} ] + wincmd p + bwipe + bwipe + exe 'bwipe '.unlisted_bufnr + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + +Execute (cargo error message): + let g:neomake_tests_highlight_lengths = {} + new + file build/lib.rs + let cargo = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rust#cargo(), + \ '../tests/fixtures/rust/cargo_error.json') + + call neomake#Make(1, [cargo]) + NeomakeTestsWaitForFinishedJobs + + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'type': 'E', + \ 'bufnr': bufnr, + \ 'nr': 308, + \ 'lnum': 19, + \ 'col': 46, + \ 'valid': 1, + \ 'vcol': 0, + \ 'pattern': '', + \ 'text': 'mismatched types: expected str, found struct `proc_macro::TokenStream`' + \ }, { + \ 'type': 'E', + \ 'bufnr': bufnr, + \ 'nr': 308, + \ 'lnum': 25, + \ 'col': 1, + \ 'valid': 1, + \ 'vcol': 0, + \ 'pattern': '', + \ 'text': 'mismatched types: expected str, found struct `proc_macro::TokenStream`' + \ }, { + \ 'type': 'I', + \ 'bufnr': bufnr, + \ 'nr': 308, + \ 'lnum': 25, + \ 'col': 1, + \ 'valid': 1, + \ 'vcol': 0, + \ 'pattern': '', + \ 'text': 'found type `&proc_macro::TokenStream`' + \ }] + + " TODO: should not call it for the same highlight twice?! + AssertEqual {string(bufnr): [[19, 2], [25, 40], [25, 40]]}, g:neomake_tests_highlight_lengths + bwipe + +Execute (cargo warning message): + let g:neomake_tests_highlight_lengths = {} + new + file build/add_assign_like.rs + let cargo = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rust#cargo(), + \ '../tests/fixtures/rust/cargo_warning.json') + + call neomake#Make(1, [cargo]) + NeomakeTestsWaitForFinishedJobs + + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'type': 'W', + \ 'bufnr': bufnr, + \ 'nr': -1, + \ 'lnum': 2, + \ 'col': 24, + \ 'valid': 1, + \ 'vcol': 0, + \ 'pattern': '', + \ 'text': 'unused import: `Variant`, #[warn(unused_imports)] on by default'}] + AssertEqual {string(bufnr): [[2, 7]]}, g:neomake_tests_highlight_lengths + bwipe + +Execute (cargo warning for file that is not open): + let g:neomake_tests_highlight_lengths = {} + new + file build/some_other_file.rs + + " Uses build/add_assign_like.rs. + let cargo = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rust#cargo(), + \ '../tests/fixtures/rust/cargo_warning.json') + + call neomake#Make(1, [cargo]) + NeomakeTestsWaitForFinishedJobs + + let unlisted_bufnr = bufnr('^build/add_assign_like.rs$') + AssertNotEqual -1, unlisted_bufnr + + AssertEqualQf getloclist(0), [{ + \ 'type': 'W', + \ 'bufnr': unlisted_bufnr, + \ 'nr': -1, + \ 'lnum': 2, + \ 'col': 24, + \ 'valid': 1, + \ 'vcol': 0, + \ 'pattern': '', + \ 'text': 'unused import: `Variant`, #[warn(unused_imports)] on by default'}] + AssertEqual {string(unlisted_bufnr): [[2, 7]]}, g:neomake_tests_highlight_lengths + bwipe + exe 'bwipe' unlisted_bufnr + +Execute (cargo error message children): + let g:neomake_tests_highlight_lengths = {} + new + file tests/from.rs + let cargo = NeomakeTestsGetMakerWithOutput(neomake#makers#ft#rust#cargo(), + \ '../tests/fixtures/rust/cargo_error_children.json') + + call neomake#Make(1, [cargo]) + NeomakeTestsWaitForFinishedJobs + + let bufnr = bufnr('%') + AssertEqualQf getloclist(0), [{ + \ 'type': 'E', + \ 'bufnr': bufnr, + \ 'nr': -1, + \ 'lnum': 11, + \ 'col': 10, + \ 'valid': 1, + \ 'vcol': 0, + \ 'pattern': '', + \ 'text': 'custom derive attribute panicked. message: Only structs and enums can derive From'}] + AssertEqual {string(bufnr): [[11, 4]]}, g:neomake_tests_highlight_lengths + bwipe + +Execute (Teardown: undo monkeypatching): + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/highlights.vim + endif diff --git a/bundle/neomake/tests/isolated/logging.vader b/bundle/neomake/tests/isolated/logging.vader new file mode 100644 index 000000000..19d8145ba --- /dev/null +++ b/bundle/neomake/tests/isolated/logging.vader @@ -0,0 +1,143 @@ +Include: ../include/setup.vader + +Execute (Setup: simulate non-testing): + Save g:neomake_verbose + " Unset g:neomake_test_messages for s:is_testing in autoload/neomake/log.vim. + unlet g:neomake_test_messages + unlet! g:neomake_verbose + call NeomakeTestsSetVimMessagesMarker() + runtime autoload/neomake/log.vim + runtime autoload/neomake.vim + let g:neomake_test_messages = [] + +Execute (neomake#GetMakeOptions works without testing): + let jobinfo = NeomakeTestsFakeJobinfo() + AssertEqual keys(neomake#GetMakeOptions(jobinfo.make_id)), + \ ['options', 'jobs_queue', 'verbosity', 'finished_jobs', 'make_id', 'active_jobs'] + +Execute (neomake#log#error uses echohl): + Save g:neomake_verbose + let g:neomake_verbose = 1 + call NeomakeTestsSetVimMessagesMarker() + call neomake#log#error('some error with context.', {}) + call neomake#log#error('some error without context.') + AssertEqual NeomakeTestsGetVimMessages(), [ + \ 'Neomake: some error with context.', + \ 'Neomake: some error without context.', + \ ] + + let g:neomake_verbose = 3 + call neomake#log#warning('some warning with context.', {}) + call neomake#log#warning('some warning without context.') + AssertEqual NeomakeTestsGetVimMessages(), [ + \ 'Neomake: [-.-:-:1] some warning with context.', + \ 'Neomake: some warning without context.', + \ ] + +Execute (neomake#log#debug handles missing make_options): + let s:log_calls = [] + function! neomake#log#warning(...) + let s:log_calls += [a:000] + endfunction + + call neomake#log#debug('msg1') + AssertEqual NeomakeTestsGetVimMessages(), [] + + " Non-existing make_id should not make it verbose. + call neomake#log#debug('msg1', {'make_id': -42}) + AssertEqual s:log_calls, [['warning: missing make_info key: -42.']] + AssertEqual NeomakeTestsGetVimMessages(), [] + + let g:neomake_verbose = 3 + let s:log_calls = [] + call neomake#log#debug('msg1', {'make_id': -42}) + AssertEqual s:log_calls, [['warning: missing make_info key: -42.']] + let msgs = NeomakeTestsGetVimMessages() + AssertEqual len(msgs), 1 + Assert msgs[0] =~# '\VNeomake\.\*: [-42.-:-:1] msg1', 'msg matches ('.msgs[0].')' + + " Produces no message with level 0. + let g:neomake_verbose = 0 + let s:log_calls = [] + call neomake#log#debug('msg1', {'make_id': -42}) + AssertEqual s:log_calls, [['warning: missing make_info key: -42.']] + AssertEqual NeomakeTestsGetVimMessages(), [] + +Execute (neomake#log#debug_obj does not call neomake#utils#Stringify if not necessary): + Save g:neomake_verbose + unlet! g:neomake_verbose + + let s:calls = [] + function! neomake#utils#Stringify(...) + let s:calls += [a:000] + endfunction + + call neomake#log#debug_obj('msg', 'obj') + AssertEqual s:calls, [] + + let g:neomake_verbose = 3 + call neomake#log#debug_obj('msg', 'obj') + AssertEqual s:calls, [['obj']] + +Execute (reltime_lastmsg: cover all cases): + if has('patch-7.4.503') + Save g:neomake_logfile + let g:neomake_logfile = tempname() + + let s:cur = 0 + let s:diffs = [0, 9, 99, 999, 9999, 99999] + function! neomake#compat#reltimefloat(...) + let s:cur += remove(s:diffs, 0) + return s:cur + endfunction + + call neomake#log#debug('msg1.') + call neomake#log#debug('msg2.') + call neomake#log#debug('msg3.') + call neomake#log#debug('msg4.') + call neomake#log#debug('msg5.') + + let log_msgs = readfile(g:neomake_logfile) + call map(log_msgs, 'substitute(v:val, ''\v^\d\d:\d\d:\d\d \d+ '', ''HH:MM:SS PID '', '''')') + AssertEqual log_msgs, [ + \ 'HH:MM:SS PID [D ] msg1.', + \ 'HH:MM:SS PID [D +9.00] msg2.', + \ 'HH:MM:SS PID [D +99.0] msg3.', + \ 'HH:MM:SS PID [D +999] msg4.', + \ 'HH:MM:SS PID [D +9999] msg5.', + \ ] + else + NeomakeTestsSkip 'only with patch-7.4.503' + endif + +Execute (neomake#log#indent): + Save g:neomake_verbose + + AssertThrows call neomake#log#indent(-1) + AssertEqual g:vader_exception, 'invalid offset (already 0)' + + call neomake#log#indent(1) + call NeomakeTestsSetVimMessagesMarker() + call neomake#log#error('error1.') + call neomake#log#error('error2.', {'bufnr': 1}) + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake: error1.', 'Neomake: error2.'] + + let g:neomake_verbose = 2 + call NeomakeTestsSetVimMessagesMarker() + call neomake#log#error('error1.') + call neomake#log#error('error2.', {'bufnr': 1}) + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake: error1.', 'Neomake: error2.'] + + let g:neomake_verbose = 3 + call NeomakeTestsSetVimMessagesMarker() + call neomake#log#debug('debug1.') + call neomake#log#debug('debug2.', {'bufnr': 1}) + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake: debug1.', 'Neomake: [-.-:1:1] debug2.'] + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/utils.vim + runtime autoload/neomake/log.vim + runtime autoload/neomake/compat.vim + runtime autoload/neomake.vim + endif diff --git a/bundle/neomake/tests/isolated/modes.vader b/bundle/neomake/tests/isolated/modes.vader new file mode 100644 index 000000000..7c3504b6d --- /dev/null +++ b/bundle/neomake/tests/isolated/modes.vader @@ -0,0 +1,36 @@ +Include: ../include/setup.vader + +Execute (Output is not processed in operator-pending mode (Vim)): + if NeomakeAsyncTestsSetup() + new + file file_sleep_efm + + " Simulate operator-pending mode ('no'). + function! neomake#compat#get_mode() + return 'no' + endfunction + + call neomake#Make(0, [g:sleep_efm_maker])[0] + let jobinfo = neomake#GetJobs()[-1] + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Not processing output for mode "no".', 3 + AssertNeomakeMessage 'sleep_efm_maker: completed with exit code 0.' + AssertEqual getqflist(), [], 'Quickfix list has not been updated' + + runtime autoload/neomake/compat.vim + AssertEqual neomake#compat#get_mode(), 'n' + + doautocmd CursorHold + AssertNeomakeMessage 'Processing 3 lines of output.', 3, jobinfo + AssertNeomakeMessage 'Processed 1 pending outputs.', 3, jobinfo + AssertEqual map(getqflist(), 'v:val.text'), ['error message', 'warning', 'error2'] + NeomakeTestsWaitForRemovedJobs + call neomake#signs#ResetProject() + call neomake#signs#CleanAllOldSigns('project') + bwipe + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/compat.vim + endif + endif diff --git a/bundle/neomake/tests/isolated/resets-ignore_automake_events.vader b/bundle/neomake/tests/isolated/resets-ignore_automake_events.vader new file mode 100644 index 000000000..26c47a1be --- /dev/null +++ b/bundle/neomake/tests/isolated/resets-ignore_automake_events.vader @@ -0,0 +1,25 @@ +Include: ../include/setup.vader + +Execute (Resets ignore_automake_events always): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + + augroup neomake_tests + autocmd BufWritePost * CallNeomake 1, [g:error_maker] + augroup END + + function! neomake#compat#save_prev_windows() abort + throw 'some error' + endfunction + + doautocmd BufWritePost + AssertNeomakeMessage 'Error during output processing for error-maker: some error.', 0 + doautocmd BufWritePost + AssertNeomakeMessage 'Error during output processing for error-maker: some error.', 0 + bwipe + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/compat.vim + endif diff --git a/bundle/neomake/tests/isolated/sign-highlights.vader b/bundle/neomake/tests/isolated/sign-highlights.vader new file mode 100644 index 000000000..2b9418fdd --- /dev/null +++ b/bundle/neomake/tests/isolated/sign-highlights.vader @@ -0,0 +1,115 @@ +Include: ../include/setup.vader + +Execute (neomake#signs#DefineHighlights: SignColumn bg=NONE): + hi clear Error + hi clear Normal + hi clear LineNr + highlight LineNr ctermfg=250 guifg=#c2c2c3 + highlight! link SignColumn LineNr + AssertEqual neomake#utils#GetHighlight('SignColumn', 'bg'), 'NONE' + AssertEqual neomake#utils#GetHighlight('SignColumn', 'bg', 'Normal'), 'NONE' + + " Normal and Error are not defined. + call neomake#signs#DefineHighlights() + let highlights = sort(filter(split(neomake#utils#redir('hi'), '\n'), + \ 'v:val =~# ''^NeomakeErrorSignDefault''')) + AssertEqual highlights, [ + \ 'NeomakeErrorSignDefault xxx cleared', + \ ] + + " Normal is not defined, only fg for Error. + highlight Error ctermfg=166 guifg=#e45649 + + call neomake#signs#DefineHighlights() + let highlights = sort(filter(split(neomake#utils#redir('hi'), '\n'), + \ 'v:val =~# ''^NeomakeErrorSignDefault''')) + AssertEqual highlights, [ + \ 'NeomakeErrorSignDefault xxx cleared', + \ ] + + highlight Normal ctermfg=23 ctermbg=255 guifg=#494b53 guibg=#fafafa + AssertEqual neomake#utils#GetHighlight('SignColumn', 'bg', 'Normal'), '255' + + call neomake#signs#DefineHighlights() + let highlights = sort(filter(split(neomake#utils#redir('hi'), '\n'), + \ 'v:val =~# ''^NeomakeError''')) + + AssertEqual highlights, [ + \ 'NeomakeError xxx links to SpellBad', + \ 'NeomakeErrorSign xxx links to NeomakeErrorSignDefault', + \ 'NeomakeErrorSignDefault xxx ctermfg=166 ctermbg=255 guifg=#e45649 guibg=#fafafa', + \ ] + +Execute (neomake#signs#DefineHighlights with "NONE" SignColumn, no Normal): + hi clear Normal + hi clear SignColumn + highlight SignColumn ctermfg=250 guifg=#c2c2c3 + highlight Error cterm=bold ctermfg=166 ctermbg=255 gui=bold guifg=#e45649 guibg=#fafafa + + call neomake#signs#DefineHighlights() + let highlights = sort(filter(split(neomake#utils#redir('hi'), '\n'), + \ 'v:val =~# ''^NeomakeErrorSignDefault''')) + + AssertEqual highlights, [ + \ 'NeomakeErrorSignDefault xxx ctermfg=255 guifg=#fafafa', + \ ] + +Execute (neomake#signs#DefineHighlights: checks same gui bg/fg separately): + hi clear Normal + highlight Normal ctermbg=1 guibg=#aaaaaa + if substitute(neomake#utils#redir('hi Normal'), '^\s+', '', '') !=# 'Normal xxx ctermbg=1 guibg=#aaaaaa' + NeomakeTestsSkip 'Setting ctermbg on Normal is buggy' " nvim 0.1.7 + else + hi clear Error + hi clear SignColumn + + call neomake#signs#DefineHighlights() + let highlights = sort(filter(split(neomake#utils#redir('hi'), '\n'), + \ 'v:val =~# ''^NeomakeErrorSignDefault''')) + AssertEqual highlights, [ + \ 'NeomakeErrorSignDefault xxx ctermbg=1 guibg=#aaaaaa', + \ ] + + highlight Error ctermbg=1 guibg=#bbbbbb + call neomake#signs#DefineHighlights() + let highlights = sort(filter(split(neomake#utils#redir('hi'), '\n'), + \ 'v:val =~# ''^NeomakeErrorSignDefault''')) + AssertEqual highlights, [ + \ 'NeomakeErrorSignDefault xxx ctermbg=1 guifg=#bbbbbb guibg=#aaaaaa', + \ ] + + highlight SignColumn ctermbg=166 guifg=#bbbbbb + call neomake#signs#DefineHighlights() + let highlights = sort(filter(split(neomake#utils#redir('hi'), '\n'), + \ 'v:val =~# ''^NeomakeErrorSignDefault''')) + AssertEqual highlights, [ + \ 'NeomakeErrorSignDefault xxx ctermfg=1 ctermbg=166 guifg=#bbbbbb guibg=#aaaaaa', + \ ] + endif + +Execute (neomake#signs#DefineHighlights: all NONE): + hi clear Error + hi clear Normal + hi clear SignColumn + + call neomake#signs#DefineHighlights() + let highlights = sort(filter(split(neomake#utils#redir('hi'), '\n'), + \ 'v:val =~# ''^NeomakeErrorSignDefault''')) + + AssertEqual highlights, [ + \ 'NeomakeErrorSignDefault xxx cleared', + \ ] + +Execute (neomake#utils#GetHighlight: correct mode with reverse): + highlight clear NeomakeTest + highlight NeomakeTest ctermfg=0 guifg=black ctermbg=7 guibg=white + AssertEqual neomake#utils#GetHighlight('NeomakeTest', 'fg'), '0' + AssertEqual neomake#utils#GetHighlight('NeomakeTest', 'fg#'), 'black' + + highlight NeomakeTest cterm=reverse + AssertEqual neomake#utils#GetHighlight('NeomakeTest', 'fg'), '7' + AssertEqual neomake#utils#GetHighlight('NeomakeTest', 'fg#'), 'black' + + highlight NeomakeTest cterm=NONE gui=reverse + AssertEqual neomake#utils#GetHighlight('NeomakeTest', 'fg'), '0' + AssertEqual neomake#utils#GetHighlight('NeomakeTest', 'fg#'), 'white' diff --git a/bundle/neomake/tests/isolated/signs.vader b/bundle/neomake/tests/isolated/signs.vader new file mode 100644 index 000000000..c95223aa3 --- /dev/null +++ b/bundle/neomake/tests/isolated/signs.vader @@ -0,0 +1,19 @@ +Include: ../include/setup.vader + +Execute (Signs are not wiped when buffer gets wiped with removed augroup): + new + au! neomake_signs + let buf = bufnr('%') + call neomake#signs#PlaceSigns(bufnr('%'), + \ [{'type': 'E', 'bufnr': buf, 'lnum': 1}], 'file') + AssertEqual neomake#signs#by_lnum(bufnr('%')), {'1': [[5000, 'neomake_file_err']]} + bwipe + + AssertEqual neomake#signs#by_lnum(buf), {} + call neomake#signs#ResetFile(buf) + AssertNeomakeMessage 'Skipped cleaning of old signs in non-existing buffer '.buf.': {5000: neomake_file_err}.', 3 + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/signs.vim + endif diff --git a/bundle/neomake/tests/isolated/statusline-highlights.vader b/bundle/neomake/tests/isolated/statusline-highlights.vader new file mode 100644 index 000000000..edb0ac3b2 --- /dev/null +++ b/bundle/neomake/tests/isolated/statusline-highlights.vader @@ -0,0 +1,48 @@ +Include: ../include/setup.vader + +Execute (statusline highlights for quickfix items): + call neomake#statusline#ResetCountsForProject() + + new + let bufnr = bufnr('%') + + let item = {'type': 'E'} + call neomake#statusline#AddQflistCount(item) + + AssertEqual neomake#statusline#get_status(bufnr, {}), + \ '? %#NeomakeStatColorQuickfixTypeE# QE:1 %#NeomakeStatReset#' + + let item = {'type': 'I'} + call neomake#statusline#AddQflistCount(item) + AssertEqual neomake#statusline#get_status(bufnr, {}), + \ '? %#NeomakeStatColorQuickfixTypeE# QE:1 %#NeomakeStatColorQuickfixDefault# QI:1 %#NeomakeStatReset#' + + " Cleared highlight is still used (since it exists). + " Could use neomake#utils#highlight_is_defined maybe. + highlight clear NeomakeStatColorDefault + AssertEqual neomake#statusline#get_status(bufnr, {}), + \ '? %#NeomakeStatColorQuickfixTypeE# QE:1 %#NeomakeStatColorQuickfixDefault# QI:1 %#NeomakeStatReset#' + + AssertEqual neomake#statusline#get_status(bufnr, { + \ 'format_quickfix_type_E': 'errors:{{count}} ', + \ }), + \ '? errors:1 %#NeomakeStatColorQuickfixDefault# QI:1 %#NeomakeStatReset#' + + AssertEqual neomake#statusline#get_status(bufnr, { + \ 'format_quickfix_type_E': 'errors:{{count}} ', + \ 'format_quickfix_type_default': '{{type}}:{{count}} ', + \ }), + \ '? errors:1 I:1 %#NeomakeStatReset#' + + AssertEqual neomake#statusline#get_status(bufnr, { + \ 'format_quickfix_issues': '%s', + \ 'format_quickfix_type_E': 'errors:{{count}} ', + \ 'format_quickfix_type_default': '{{type}}:{{count}} ', + \ }), + \ '? errors:1 I:1 ' + bwipe + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake/statusline.vim + endif diff --git a/bundle/neomake/tests/isolated/tempfiles-cleanup.vader b/bundle/neomake/tests/isolated/tempfiles-cleanup.vader new file mode 100644 index 000000000..a56c2e17a --- /dev/null +++ b/bundle/neomake/tests/isolated/tempfiles-cleanup.vader @@ -0,0 +1,40 @@ +Include: ../include/setup.vader + +Execute (Ensure that temporary files are not being left around): + new + let maker = {'exe': 'true'} + call neomake#Make(1, [maker]) + AssertNeomakeMessage '\vUsing tempfile for unnamed buffer: "([^"]+)".' + let tmpfile = g:neomake_test_matchlist[1] + + if neomake#has_async_support() + Assert filereadable(tmpfile) + else + AssertNeomakeMessage printf('Removing temporary file: "%s".', tmpfile) + endif + new + + if !has('nvim') || has('nvim-0.2.0') + " Neovim fails to reload it: Error: Vim(function):E127: Cannot redefine function 22_nvim_output_handler: It is in use + runtime autoload/neomake.vim + endif + + if neomake#has_async_support() + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Postponing final location list handling (in another window).', 3 + Assert filereadable(tmpfile) + endif + + doautocmd neomake VimLeave + AssertNeomakeMessage 'Calling VimLeave.', 3 + if neomake#has_async_support() + AssertNeomakeMessage printf('Removing temporary file: "%s".', tmpfile) + endif + Assert !filereadable(tmpfile) + bwipe + bwipe + + " Restore if not profiling. + if !v:profiling + runtime autoload/neomake.vim + endif diff --git a/bundle/neomake/tests/jobinfo.vader b/bundle/neomake/tests/jobinfo.vader new file mode 100644 index 000000000..d055ce756 --- /dev/null +++ b/bundle/neomake/tests/jobinfo.vader @@ -0,0 +1,73 @@ +Include: include/setup.vader + +Execute (jobinfo.get_pid): + if NeomakeAsyncTestsSetup() + let maker = NeomakeTestsCommandMaker('echo-pid-and-sleep', 'echo $$; sleep 10') + let maker.buffer_output = 0 + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + NeomakeTestsWaitForMessage '\v^output on stdout: \[''(\d+)'', ''''\].' + let pid = +g:neomake_test_matchlist[1] + AssertEqual jobinfo.get_pid(), pid + + call neomake#CancelJob(jobinfo.id) + if has('nvim-0.4.0') + let expected_status = 143 + elseif has('nvim') + let expected_status = 0 + else + let expected_status = -1 + endif + NeomakeTestsWaitForMessage '\Vexit: echo-pid-and-sleep: '.expected_status.' (job was canceled).' + NeomakeTestsWaitForFinishedJobs + AssertEqual jobinfo.get_pid(), -1 + endif + +Execute (jobinfo.cd: handles/keeps trailing slash with root dir): + new + let jobinfo = neomake#jobinfo#new() + let tmpdir = fnamemodify(tempname(), ':h') + exe 'lcd '.tmpdir + Assert haslocaldir() + + let root = fnamemodify('/', ':p') + + call jobinfo.cd('/') + AssertEqual jobinfo.cwd, root + + " Should not :lcd again (verified manually). + call jobinfo.cd('/') + AssertEqual jobinfo.cwd, root + + AssertEqual getcwd(), root + + " Empty dir defaults to current cwd. + call jobinfo.cd('') + AssertEqual getcwd(), root + AssertEqual jobinfo.cwd, root + + call jobinfo.cd(tmpdir) + AssertEqual getcwd(), tmpdir + AssertEqual jobinfo.cwd, tmpdir + bwipe + +Execute (jobinfo.cd: empty dir defaults to $HOME): + new + let root = fnamemodify('/', ':p') + exe 'lcd '.root + + let jobinfo = neomake#jobinfo#new() + Assert !has_key(jobinfo, 'cwd') + + Save $HOME + let $HOME = '/doesnotexist' + + let r = jobinfo.cd('') + Assert r =~# '\VVim(lcd):E344:' + Assert !has_key(jobinfo, 'cwd') + + let $HOME = fnamemodify(tempname(), ':h') + AssertEqual jobinfo.cd(''), '' + + AssertEqual getcwd(), $HOME + AssertEqual jobinfo.cwd, $HOME + bwipe diff --git a/bundle/neomake/tests/json.vader b/bundle/neomake/tests/json.vader new file mode 100644 index 000000000..c8959a148 --- /dev/null +++ b/bundle/neomake/tests/json.vader @@ -0,0 +1,28 @@ +Include: include/setup.vader + +Execute (neomake#compat#json_decode): + AssertEqual neomake#compat#json_decode('{}'), {} + + let json = '{"dict":{"children":[],"null":null,"true":true,"false":false}}' + + AssertEqual neomake#compat#json_decode(json), { + \ 'dict': { + \ 'false': g:neomake#compat#json_false, + \ 'true': g:neomake#compat#json_true, + \ 'children': [], + \ 'null': g:neomake#compat#json_null}} + + if exists('v:null') + AssertEqual g:neomake#compat#json_null, v:null + AssertEqual g:neomake#compat#json_true, v:true + AssertEqual g:neomake#compat#json_false, v:false + else + AssertEqual type(g:neomake#compat#json_null), type([]) + AssertEqual type(g:neomake#compat#json_null[0]), type(function('tr')) + AssertEqual g:neomake#compat#json_true, 1 + AssertEqual g:neomake#compat#json_false, 0 + endif + +Execute (neomake#compat#json_null cannot be changed): + AssertThrows let g:neomake#compat#json_null = 'changed' + AssertEqual g:vader_exception, 'Vim(let):E741: Value is locked: g:neomake#compat#json_null' diff --git a/bundle/neomake/tests/list-entries.vader b/bundle/neomake/tests/list-entries.vader new file mode 100644 index 000000000..ea00d1cd1 --- /dev/null +++ b/bundle/neomake/tests/list-entries.vader @@ -0,0 +1,12 @@ +Include: include/setup.vader + +Execute (default_entry_type is only used for valid/recognized entries): + let maker = {'exe': 'printf', 'args': ['%s\n', 'errorfile:msg', 'info']} + let maker.remove_invalid_entries = 0 + let maker.errorformat = '%f:%m' + + CallNeomake 0, [maker] + AssertEqual map(getqflist(), '[v:val.text, v:val.type]'), [ + \ ['msg', 'W'], + \ ['info', '']] + bwipe errorfile diff --git a/bundle/neomake/tests/list.vader b/bundle/neomake/tests/list.vader new file mode 100644 index 000000000..0099baf03 --- /dev/null +++ b/bundle/neomake/tests/list.vader @@ -0,0 +1,576 @@ +Include: include/setup.vader + +Execute (list: default for debug): + Save g:neomake_test_messages, g:neomake_debug_list, g:neomake_verbose + + unlet! g:neomake_test_messages + unlet! g:neomake_debug_list + unlet! g:neomake_verbose + + AssertEqual neomake#list#List('loclist').debug, 0 + let g:neomake_debug_list = 1 + AssertEqual neomake#list#List('loclist').debug, 1 + + let g:neomake_test_messages = [] + let g:neomake_debug_list = 0 + AssertEqual neomake#list#List('loclist').debug, 0 + + unlet g:neomake_debug_list + AssertEqual neomake#list#List('loclist').debug, 1 + + unlet g:neomake_test_messages + let g:neomake_verbose = 3 + AssertEqual neomake#list#List('loclist').debug, 1 + + Restore + +Execute (List: basic: loclist): + new + normal! oline2 + normal! gg0 + let maker = {} + function! maker.get_list_entries(...) + let b = bufnr('%') + return [ + \ {'text': '1', 'lnum': 1, 'bufnr': b}, + \ {'text': '2', 'lnum': 2, 'col': 3, 'bufnr': b}, + \ ] + endfunction + CallNeomake 1, [maker] + AssertNeomakeMessage 'Adding 2 list entries.', 3 + + let list1 = neomake#list#get() + + " Location list window can be found after make run has finished. + " (via last_make_id without patch-7.4.1895). + if has('patch-7.4.1895') + AssertEqual list1._get_loclist_win(), win_getid() + else + AssertEqual list1._get_loclist_win(), winnr() + endif + + AssertEqual getpos('.'), [0, 1, 1, 0] + NeomakeNextLoclist + AssertEqual getpos('.'), [0, 2, 3, 0] + NeomakePrevLoclist + AssertEqual getpos('.'), [0, 1, 1, 0] + AssertNeomakeMessageAbsent 'Creating new List object.' + + " Knows about loclist in new window for the same buffer. + split + AssertNeomakeMessageAbsent 'Creating new List object.' + AssertEqual neomake#list#get(), list1 + + bwipe! + +Execute (List: basic: quickfix): + new + normal! oline2 + normal! gg0 + let maker = {} + function! maker.get_list_entries(...) + let b = bufnr('%') + return [ + \ {'text': '1', 'lnum': 1, 'bufnr': b}, + \ {'text': '2', 'lnum': 2, 'col': 3, 'bufnr': b}, + \ ] + endfunction + CallNeomake 0, [maker] + + AssertEqual getpos('.'), [0, 1, 1, 0] + NeomakeNextQuickfix + AssertEqual getpos('.'), [0, 2, 3, 0] + NeomakePrevQuickfix + AssertEqual getpos('.'), [0, 1, 1, 0] + AssertNeomakeMessageAbsent 'Creating new List object.' + bwipe! + +Execute (Sorting by location): + let list = neomake#list#List('loclist') + AssertEqual list.sort_by_location(), [] + + let input = [ + \ {'lnum': 1, 'col': 2, 'bufnr': 1, 'type': ''}, + \ {'lnum': 1, 'col': 5, 'bufnr': 2, 'type': ''}, + \ {'lnum': 2, 'col': 1, 'bufnr': 1, 'type': ''}, + \ {'lnum': 3, 'col': 5, 'bufnr': 1, 'type': ''}, + \ {'lnum': 1, 'col': 2, 'bufnr': 1, 'type': 'E'}, + \ ] + call list.add_entries(input) + + AssertEqual list.sort_by_location(), [ + \ {'lnum': 1, 'col': 2, 'bufnr': 1, 'type': 'E'}, + \ {'lnum': 1, 'col': 2, 'bufnr': 1, 'type': ''}, + \ {'lnum': 2, 'col': 1, 'bufnr': 1, 'type': ''}, + \ {'lnum': 3, 'col': 5, 'bufnr': 1, 'type': ''}, + \ {'lnum': 1, 'col': 5, 'bufnr': 2, 'type': ''}, + \ ] + AssertEqual input[-1].lnum, 1, 'does not sort list in-place' + + " Sorts newly added entries. + call list.add_entries([ + \ {'lnum': 1, 'col': 1, 'bufnr': 1, 'type': 'W'}, + \ ]) + AssertEqual list._sorted_entries_by_location, [ + \ {'lnum': 1, 'col': 1, 'bufnr': 1, 'type': 'W'}, + \ {'lnum': 1, 'col': 2, 'bufnr': 1, 'type': 'E'}, + \ {'lnum': 1, 'col': 2, 'bufnr': 1, 'type': ''}, + \ {'lnum': 2, 'col': 1, 'bufnr': 1, 'type': ''}, + \ {'lnum': 3, 'col': 5, 'bufnr': 1, 'type': ''}, + \ {'lnum': 1, 'col': 5, 'bufnr': 2, 'type': ''}, + \ ] + +Execute (list: error with duplicate nmqfidx (debug=1)): + let list = neomake#list#List('loclist') + AssertEqual list.debug, 1 + call list.add_entries([ + \ {'lnum': 1, 'col': 1, 'bufnr': 1, 'type': 'W'}, + \ ]) + let list.entries[0].nmqfidx = 2 + call list.add_entries([ + \ {'lnum': 1, 'col': 1, 'bufnr': 1, 'type': 'W'}, + \ ]) + AssertNeomakeMessage 'Duplicate qf indexes in list entries: [2, 2].', 0 + +Execute (list: no error with duplicate nmqfidx (debug=0)): + let list = neomake#list#List('loclist') + let list.debug = 0 + call list.add_entries([ + \ {'lnum': 1, 'col': 1, 'bufnr': 1, 'type': 'W'}, + \ ]) + let list.entries[0].nmqfidx = 2 + call list.add_entries([ + \ {'lnum': 1, 'col': 1, 'bufnr': 1, 'type': 'W'}, + \ ]) + +Execute (quickfix list: gets local and sorts): + Save g:_neomake_info + unlet g:_neomake_info + + let list = neomake#list#List('quickfix') + AssertEqual list.sort_by_location(), [] + + call setqflist([ + \ {'lnum': 1, 'col': 2, 'bufnr': 1}, + \ {'lnum': 1, 'col': 5, 'bufnr': 1}, + \ {'lnum': 2, 'col': 1, 'bufnr': 1}, + \ {'lnum': 3, 'col': 5, 'bufnr': 1}, + \ {'lnum': 1, 'col': 1, 'bufnr': 1}, + \ ]) + + let list = neomake#list#get_qflist() + AssertEqual map(list.sort_by_location(), '[v:val.lnum, v:val.col, v:val.bufnr]'), [ + \ [1, 1, 1], + \ [1, 2, 1], + \ [1, 5, 1], + \ [2, 1, 1], + \ [3, 5, 1], + \ ] + +Execute (neomake#list#next): + new + let bufnr = bufnr('%') + normal! iline1 + normal! oline2 + normal! oline3 + normal! gg^ + + call setloclist(0, [ + \ {'lnum': 1, 'col': 1, 'bufnr': bufnr, 'text': 'idx1'}, + \ {'lnum': 1, 'col': 5, 'bufnr': bufnr, 'text': 'idx2'}, + \ {'lnum': 2, 'col': 1, 'bufnr': bufnr, 'text': 'idx3'}, + \ {'lnum': 3, 'col': 5, 'bufnr': bufnr, 'text': 'idx4'}, + \ {'lnum': 1, 'col': 2, 'bufnr': bufnr, 'text': 'idx5'}, + \ ]) + AssertEqual map(getloclist(0), '[v:val.lnum, v:val.text]'), + \ [[1, 'idx1'], [1, 'idx2'], [2, 'idx3'], [3, 'idx4'], [1, 'idx5']], + \ 'Sane lnums' + + Assert !exists('b:_neomake_info.loclist') + Assert !exists('w:_neomake_info.loclist') + + AssertEqual getpos('.'), [0, 1, 1, 0] + NeomakeNextLoclist + AssertEqual getpos('.'), [0, 1, 2, 0] + + NeomakePrevLoclist + AssertEqual getpos('.'), [0, 1, 1, 0] + NeomakePrevLoclist + AssertNeomakeMessage 'No more previous items.' + + 3NeomakeNextLoclist + AssertEqual getpos('.'), [0, 2, 1, 0] + + " Goes to last entry, without error message (like with :lnext). + 99NeomakeNextLoclist + AssertEqual getpos('.'), [0, 3, 5, 0] + + " Error message when at last entry already (like with :lnext). + 99NeomakeNextLoclist + AssertEqual getpos('.'), [0, 3, 5, 0] + AssertNeomakeMessage 'No more next items.' + + " count=0 gets handles as 1. + 0NeomakePrevLoclist + AssertEqual getpos('.'), [0, 2, 1, 0] + 0NeomakeNextLoclist + AssertEqual getpos('.'), [0, 3, 5, 0] + bwipe! + +Execute (neomake#list#_diff_new_entries): + AssertEqual neomake#list#_diff_new_entries([], []), {} + AssertEqual neomake#list#_diff_new_entries([{}], [{'valid': 0}]), {'0': {'changed': {'valid': [1, 0]}}} + AssertEqual neomake#list#_diff_new_entries([{}, {}], [{}, {'valid': 0}]), {'1': {'changed': {'valid': [1, 0]}}} + + " Handles different lengths. + AssertEqual neomake#list#_diff_new_entries([{}], []), {} + AssertEqual neomake#list#_diff_new_entries([], [{}]), {} + + AssertEqual neomake#list#_diff_new_entries([{'length': 1}], [{}]), {} + + AssertEqual neomake#list#_diff_new_entries([{'text': 'error'}], [{'text': 'error', 'valid': 1, 'pattern': ''}]), + \ {} + +Execute (Does not create list unnecessarily): + if !has('patch-8.0.1040') " 'efm' in setqflist/getqflist + NeomakeTestsSkip 'only with efm parsing' + else + new + lgetexpr 'init' + let list = neomake#list#ListForMake({'options': {'file_mode': 1}}) + let jobinfo = NeomakeTestsFakeJobinfo() + let jobinfo.maker.errorformat = '%m' + call list.add_lines_with_efm([], jobinfo) + AssertEqual map(getloclist(0), 'v:val.text'), ['init'] + bwipe + endif + +Execute (list: error handling): + new + let orig_bufnr = bufnr('%') + let list = neomake#list#List('loclist') + + let threw = 0 + try + call list._get_loclist_win() + catch + AssertEqual v:exception, 'cannot handle type=loclist without make_info' + let threw = 1 + endtry + AssertEqual threw, 1 + + " Invalid location list qfid (loclist). + let jobinfo = NeomakeTestsFakeJobinfo() + let list.make_info = neomake#GetStatus().make_info[-42] + + let threw = 0 + try + call list._get_fn_args('get') + catch + let threw = 1 + AssertEqual v:exception, 'Neomake: could not find location list for make_id -42.' + endtry + AssertEqual threw, 1 + + " Uses winid from make_info. + let list.make_info.options.winid = 1234 + if has('patch-7.4.1895') + AssertEqual list._get_fn_args('get'), [['getloclist', [1234]]] + else + let g:list = list + AssertThrows call g:list._get_fn_args('get') + AssertEqual g:vader_exception, 'Neomake: could not find location list for make_id -42.' + unlet g:list + endif + unlet list.make_info.options.winid + + AssertEqual list._get_loclist_win(1), -1 + + " location list from another tab + tabnew + let w:neomake_make_ids = [-42] + tabprev + let threw = 0 + try + call list._get_fn_args('get') + catch + let threw = 1 + AssertEqual v:exception, 'Neomake: trying to use location list from another tab (current=3 != target=4).' + endtry + AssertEqual threw, 1 + AssertEqual list._get_loclist_win(1), -1 + tabnext + bwipe + + new + let w:neomake_make_ids = [-42] + AssertEqual list._get_fn_args('get'), [['getloclist', [0]]] + AssertEqual list.need_init, 1 + + let fns_args = list._get_fn_args('set', ['item'], ' ') + let title = 'Neomake[file]: buf:'.orig_bufnr.' (fake_jobinfo_name?)' + if has('patch-7.4.2200') && has('patch-8.0.0657') + let context = remove(fns_args[0][1][3], 'context') + AssertEqual keys(context), ['neomake'] + AssertEqual keys(context.neomake), ['make_info'] + AssertEqual fns_args, + \ [['setloclist', [0, [], ' ', {'title': title, 'items': ['item']}]]] + elseif has('patch-7.4.2200') + AssertEqual fns_args, + \ [['setloclist', [0, ['item'], ' ']], ['setloclist', [0, [], 'a', {'title': title}]]] + else + AssertEqual fns_args, + \ [['setloclist', [0, ['item'], ' ']]] + endif + + wincmd p + + Assert !has_key(list, 'qfid') + call list._call_qf_fn('set', [], ' ') + + if has('patch-8.0.1023') + let list.qfid = list.qfid + 1 + let list.make_info.options.winid = 1234 + + Assert !list._has_valid_qf() + + let threw = 0 + try + call list._get_fn_args('get') + catch + let threw = 1 + AssertEqual v:exception, printf('Neomake: qfid %d for location list (1234) has become invalid.', list.qfid) + endtry + AssertEqual threw, 1 + + " Invalid location list qfid (qflist). + let list.type = 'quickfix' + + let threw = 0 + try + call list._get_fn_args('get') + catch + let threw = 1 + AssertEqual v:exception, printf('Neomake: qfid %d for quickfix list has become invalid.', list.qfid) + endtry + AssertEqual threw, 1 + endif + wincmd p + bwipe + bwipe + +Execute (list: add_lines_with_efm uses own list): + new + + let jobinfo = NeomakeTestsFakeJobinfo() + let jobinfo.maker.errorformat = '%m' + let make_info = neomake#GetStatus().make_info[-42] + let w:neomake_make_ids = [-42] + + let list = neomake#list#ListForMake(make_info) + call list.add_lines_with_efm(['error1'], jobinfo) + + AssertEqual map(getloclist(0), 'v:val.text'), ['error1'] + + " Create new location list. + lgetexpr 'new_list' + + call list.add_lines_with_efm(['error2'], jobinfo) + + if has('patch-8.0.1040') + AssertEqual map(getloclist(0), 'v:val.text'), ['new_list'] + lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['error1', 'error2'] + else + " TODO: check/fix this via nmcfg marker." + AssertEqual map(getloclist(0), 'v:val.text'), ['new_list', 'error2'] + lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['error1'] + endif + bwipe + +Execute (list: title): + new + let job1 = NeomakeTestsFakeJobinfo() + let job1.maker.name = 'job1' + + let make_info = neomake#GetStatus().make_info[-42] + let w:neomake_make_ids = [-42] + + let list = neomake#list#ListForMake(make_info) + + let prefix = 'Neomake[file]: buf:'.bufnr('%') + AssertEqual list._get_title(), prefix.' (job1?)' + + let job2 = NeomakeTestsFakeJobinfo() + let job2.maker.name = 'job2' + let list.make_info.active_jobs = [job2] + AssertEqual list._get_title(), prefix.' (job2..., job1?)' + + " Finished jobs with no entries are not displayed." + let job3 = NeomakeTestsFakeJobinfo() + let job3.maker.name = 'job3' + let list.make_info.finished_jobs = [job3] + AssertEqual list._get_title(), prefix.' (job3✓, job2..., job1?)' + + call list.add_entries_for_job([{'text': 'e2', 'bufnr': bufnr('%')}], job2) + AssertEqual list._get_title(), prefix.' (job3✓, job2...(1), job1?)' + + call list.add_entries_for_job([{'text': 'e3', 'bufnr': bufnr('%')}], job3) + AssertEqual list._get_title(), prefix.' (job3(1), job2...(1), job1?)' + + AssertEqual neomake#list#get_title('', 0, 'maker_info'), 'Neomake: maker_info' + AssertEqual neomake#list#get_title('prefix', 0, 'maker_info'), 'Neomake[prefix]: maker_info' + AssertEqual neomake#list#get_title('', 0, ''), 'Neomake' + AssertEqual neomake#list#get_title('prefix', 0, ''), 'Neomake[prefix]' + bwipe + +Execute (list: handles nmcfg marker): + call neomake#quickfix#enable(1) + try + new + let job1 = NeomakeTestsFakeJobinfo() + let job1.maker.name = 'job1' + let job2 = NeomakeTestsFakeJobinfo() + let job2.maker.name = 'job2' + + let make_info = neomake#GetStatus().make_info[-42] + let w:neomake_make_ids = [-42] + + let list = neomake#list#ListForMake(make_info) + + call list.add_entries_for_job([{'text': 'e1', 'bufnr': bufnr('%')}], job1) + AssertEqual map(getloclist(0), 'v:val.text'), ["e1 nmcfg:{'short': 'job1', 'name': 'job1'}"] + + call list.add_entries_for_job([{'text': 'e2', 'bufnr': bufnr('%')}], job1) + " NOTE: could be optimized to not add nmcfg in this case, but difficult + " when list needs to be replaced. + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ "e1 nmcfg:{'short': 'job1', 'name': 'job1'}", + \ "e2 nmcfg:{'short': 'job1', 'name': 'job1'}", + \ ] + call list.add_entries_for_job([{'text': 'e3', 'bufnr': bufnr('%')}], job2) + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ "e1 nmcfg:{'short': 'job1', 'name': 'job1'}", + \ "e2 nmcfg:{'short': 'job1', 'name': 'job1'}", + \ "e3 nmcfg:{'short': 'job2', 'name': 'job2'}", + \ ] + + " Setting entries directly manages nmcfg. + let before = getloclist(0) + call list._replace_qflist_entries(list.entries) + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ "e1 nmcfg:{'short': 'job1', 'name': 'job1'}", + \ 'e2', + \ "e3 nmcfg:{'short': 'job2', 'name': 'job2'}", + \ ] + bwipe + finally + call neomake#quickfix#disable() + endtry + +Execute (list: handles invalid errorformat): + Save &errorformat + new + + " NOTE: needs to be global for lgetexpr. + set errorformat=foo:%m:%l + + let jobinfo = NeomakeTestsFakeJobinfo() + let make_info = neomake#GetStatus().make_info[-42] + let w:neomake_make_ids = [-42] + + let list = neomake#list#ListForMake(make_info) + + let jobinfo.maker.errorformat = ['invalid'] + call list.add_lines_with_efm(['foo:msg:42'], jobinfo) + if has('patch-8.0.1040') + AssertNeomakeMessage "Failed to get items via efm-parsing. Invalid errorformat? (['invalid'])", 0, jobinfo + else + AssertNeomakeMessage "\\VFailed to set errorformat (['invalid']): \\.\\*", 0, jobinfo + endif + + " Falls back to default errorformat. + AssertEqual map(getloclist(0), '[v:val.text, v:val.lnum]'), [['msg', 42]] + bwipe + +Execute (list: can reuse location list): + " Not really used (automake uses location lists), but can be covered. + let jobinfo = NeomakeTestsFakeJobinfo() + let make_info = neomake#GetStatus().make_info[-42] + let make_info.options.file_mode = 1 + let list = neomake#list#ListForMake(make_info) + + new + let w:neomake_make_ids = [-42] + + call list._call_qf_fn('set', [{'text': 'e1', 'lnum': 1, 'bufnr': bufnr('%')}], ' ') + AssertEqual map(getloclist(0), 'v:val.text'), ['e1'] + + let list = neomake#list#ListForMake(make_info) + " let list.need_init = 1 + let list.reset_existing_qflist = 1 + call list._call_qf_fn('set', [{'text': 'e2', 'lnum': 1, 'bufnr': bufnr('%')}], ' ') + AssertEqual map(getloclist(0), 'v:val.text'), ['e2'] + + AssertNeomakeMessage 'Reusing location list for entries.' + AssertNeomakeMessage '\V\^list: call: set: [0, [\.\*], ''r''' + bwipe + +Execute (list: can reuse quickfix list): + " Not really used (automake uses location lists), but can be covered. + let jobinfo = NeomakeTestsFakeJobinfo() + let make_info = neomake#GetStatus().make_info[-42] + let make_info.options.file_mode = 0 + let list = neomake#list#ListForMake(make_info) + AssertEqual list.type, 'quickfix' + + call list._call_qf_fn('set', [{'text': 'e1', 'lnum': 1, 'bufnr': bufnr('%')}], ' ') + AssertEqual map(getqflist(), 'v:val.text'), ['e1'] + + let list.need_init = 1 + let list.reset_existing_qflist = 1 + call list._call_qf_fn('set', [{'text': 'e2', 'lnum': 1, 'bufnr': bufnr('%')}], ' ') + AssertEqual map(getqflist(), 'v:val.text'), ['e2'] + + AssertNeomakeMessage 'Reusing quickfix list for entries.' + AssertNeomakeMessage '\V\^list: call: set: [[\.\*], ''r''' + +Execute (list: reused with automake (qflist)): + if !has('patch-7.4.2200') + NeomakeTestsSkip 'only with title support.' + else + Save g:neomake_enabled_makers + let g:neomake_enabled_makers = [g:true_maker] + + " Simulate previous automake run. + " (file_mode=0 should look at quickfix title only) + call setloclist(0, [], ' ', {'title': 'Neomake[auto]'}) + + augroup neomake_tests + au CursorHold * Neomake! + augroup END + doautocmd CursorHold + NeomakeTestsWaitForFinishedJobs + copen + " Does not use "auto" by default, even though triggered through autocommand. + " (apparently since `expand('')` is empty in tests). + AssertEqual w:quickfix_title, 'Neomake[project]: true-maker✓' + + " Uses "auto" with options.automake. + wincmd p + call neomake#Make({'file_mode': 0, 'enabled_makers': [g:true_maker], 'automake': 1}) + NeomakeTestsWaitForFinishedJobs + copen + AssertEqual w:quickfix_title, 'Neomake[auto]: true-maker✓' + + " Re-uses list with "auto" in qf title. + wincmd p + call neomake#Make({'file_mode': 0, 'enabled_makers': [g:true_maker], 'automake': 1}) + NeomakeTestsWaitForFinishedJobs + copen + Assert w:quickfix_title =~# '\V:\?Neomake[auto]', 'unexpected title: '.w:quickfix_title + AssertNeomakeMessage 'Reusing quickfix list for entries.', 3 + + cclose + endif diff --git a/bundle/neomake/tests/lists.vader b/bundle/neomake/tests/lists.vader new file mode 100644 index 000000000..9cae0d65a --- /dev/null +++ b/bundle/neomake/tests/lists.vader @@ -0,0 +1,849 @@ +Include: include/setup.vader + +Execute (Postprocessing updates list): + new + edit tests/fixtures/errors.sh + Save &filetype + set ft=sh + RunNeomake sh + let list = getloclist(0) + AssertNotEqual list, [], 'loclist is not empty' + + let maker = neomake#makers#ft#sh#sh() + function maker.postprocess(entry) + let a:entry.text .= ' SUFFIX' + endfunction + CallNeomake 1, [maker] + let expected_list = map(list, 'extend(v:val, {"text": v:val.text." SUFFIX"})') + AssertEqual getloclist(0), expected_list + bwipe + +Execute (AddExprCallback with changed windows inbetween): + if NeomakeAsyncTestsSetup() + Save g:neomake_tests_postprocess_count + let g:neomake_tests_postprocess_count = 0 + + Save g:neomake_verbose + " For the 'Modified list entry' debug message. + let g:neomake_verbose = 3 + + let options = { + \ 'buffer_output': 0, + \ 'append_file': 0, + \ } + function options.postprocess(entry) + let a:entry.text .= ' SUFFIX:'.(g:neomake_tests_postprocess_count/2) + let g:neomake_tests_postprocess_count += 1 + endfunction + let maker_1 = neomake#utils#MakerFromCommand('echo 1a; sleep .1; echo 1b') + call extend(maker_1, extend(copy(options), {'name': 'maker1'})) + let maker_2 = neomake#utils#MakerFromCommand('echo 2') + call extend(maker_2, extend(copy(options), {'name': 'maker2'})) + + " Start 2 makers. + call neomake#Make(1, [maker_1, maker_2]) + " Wait until partly finished. + let maxwait = 50 + while g:neomake_tests_postprocess_count < 2 && maxwait + sleep 10m + let maxwait -= 1 + endwhile + Assert maxwait > 0, 'postprocessing was not triggered' + AssertEqual g:neomake_tests_postprocess_count, 2, 'postprocess count is != 2: '.g:neomake_tests_postprocess_count + let loclist_texts = map(getloclist(0), 'v:val.text') + AssertEqual sort(copy(loclist_texts)), ['1a SUFFIX:0', '2 SUFFIX:0'] + + " Start maker in new window (same winnr!) + topleft new + call neomake#Make(1, [maker_2]) + " Go to previous window, let previous job finish. + wincmd j + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Output left to be processed, not cleaning job yet.' + AssertEqual map(getloclist(0), 'v:val.text'), + \ loclist_texts + ['1b SUFFIX:1'] + wincmd k + AssertEqual map(getloclist(0), 'v:val.text'), ['2 SUFFIX:1'] + bwipe + AssertNeomakeMessage "Modified list entry 1 (postprocess): {'changed': {'text': ['2', '2 SUFFIX:1']}}." + endif + +Execute (Goes back to original window after opening list): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let winnr = winnr() + let wincount = winnr('$') + CallNeomake 1, [g:error_maker] + NeomakeTestsWaitForFinishedJobs + + AssertEqual winnr, winnr() + AssertEqual wincount + 1, winnr('$'), 'Location list appeared' + AssertEqual map(getloclist(0), '[v:val.text, v:val.type]'), [['error', 'E']] + + CallNeomake 1, [g:true_maker] + AssertEqual getloclist(0), [] + AssertEqual wincount, winnr('$'), 'Location list was closed' + bwipe + +Execute (open_list=2 handling with get_list_entries maker and invalid entries): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let winnr = winnr() + let wincount = winnr('$') + + let maker1 = {} + function! maker1.get_list_entries(...) + return [{'type': 'E', 'lnum': 1, 'text': 'error1'}] + endfunction + let maker2 = {} + function! maker2.get_list_entries(...) + return [{'type': 'E', 'lnum': 2, 'text': 'error2'}] + endfunction + CallNeomake 1, [maker1, maker2] + AssertEqual map(getloclist(0), '[v:val.text, v:val.type, v:val.valid]'), [ + \ ['error1', 'E', 0], + \ ['error2', 'E', 0]] + + AssertEqual winnr, winnr() + + if has('patch-7.4.379') + AssertEqual wincount, winnr('$'), 'Location list did not appear for invalid entries' + else + AssertEqual wincount + 1, winnr('$'), 'Location list appeared for invalid entries (fixed in 7.4.379)' + endif + + CallNeomake 1, [g:true_maker] + AssertEqual getloclist(0), [] + bwipe + +Execute (open_list=2 handling with get_list_entries maker and invalid entries (qflist)): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let winnr = winnr() + let wincount = winnr('$') + + let maker1 = {} + function! maker1.get_list_entries(...) + return [{'type': 'E', 'lnum': 1, 'text': 'error1'}] + endfunction + let maker2 = {} + function! maker2.get_list_entries(...) + return [{'type': 'E', 'lnum': 2, 'text': 'error2'}] + endfunction + CallNeomake 0, [maker1, maker2] + AssertEqual map(getqflist(), '[v:val.text, v:val.type, v:val.valid]'), [ + \ ['error1', 'E', 0], + \ ['error2', 'E', 0]] + + AssertEqual winnr, winnr() + + if has('patch-7.4.379') + AssertEqual wincount, winnr('$'), 'Quickfix list did not appear for invalid entries' + else + AssertEqual wincount + 1, winnr('$'), 'Quickfix list appeared for invalid entries (fixed in 7.4.379)' + endif + + CallNeomake 0, [g:true_maker] + AssertEqual getqflist(), [] + bwipe + +Execute (open_list=2 handling with get_list_entries maker and valid entries): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let winnr = winnr() + let wincount = winnr('$') + + let maker = {} + function! maker.get_list_entries(...) + return [{'type': 'E', 'lnum': 1, 'text': 'error', 'bufnr': bufnr('%')}] + endfunction + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), '[v:val.text, v:val.type, v:val.valid]'), [['error', 'E', 1]] + + AssertEqual winnr, winnr() + AssertEqual wincount + 1, winnr('$'), 'Location list appeared' + + CallNeomake 1, [g:true_maker] + AssertEqual getloclist(0), [] + AssertEqual wincount, winnr('$'), 'Location list was closed' + bwipe + +Execute (Stays in location window with :lwindow in QuickFixCmdPost (like vim-qf)): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let winnr = winnr() + let wincount = winnr('$') + + augroup neomake_tests + " Simulates vim-qf, opening the list on errors automatically. + " Should be fixed in vim-qf (https://github.com/romainl/vim-qf/pull/48). + autocmd QuickFixCmdPost laddexpr lwindow + augroup END + + call neomake#Make(1, [g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), '[v:val.text, v:val.type]'), [['error', 'E']] + + AssertEqual wincount + 1, winnr('$'), 'Location list appeared' + + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist + AssertEqual winnr, winnr() + else + " Not what you expect when being unaware of the autocmd, but it is like that. + AssertNotEqual winnr, winnr() + endif + exe winnr.'wincmd w' + lclose + bwipe + +Execute (Goes back to original window after opening list (wincmd in postprocess)): + if NeomakeAsyncTestsSetup() + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + new + let winnr = winnr() + let wincount = winnr('$') + + let maker = copy(g:error_maker) + function! maker.postprocess(...) + 2wincmd w + endfunction + + let s:called = 0 + augroup neomake_tests + autocmd QuickFixCmdPost * let s:called = 1 | AssertEqual len(g:neomake_test_jobfinished), 0 + augroup END + + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + let make_info = values(neomake#GetStatus().make_info)[0] + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Processing 1 lines of output.' + let log_context = deepcopy(make_info) + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist + let log_context.options.winnr = winnr-1 + AssertNeomakeMessage 'Creating location list for entries.', 3, log_context + else + let log_context.options.winnr = winnr + AssertNeomakeMessage 'Creating location list.', 3, log_context + endif + AssertNeomakeMessage 'Postponing location list processing.', 3, jobinfo + AssertNeomakeMessage 'Queuing action ProcessEntries for BufEnter, WinEnter.', 3 + AssertEqual map(getloclist(winnr), '[v:val.text, v:val.type]'), [['error', 'E']] + AssertEqual s:called, 0 + AssertEqual 2, winnr() + + AssertNotEqual wincount + 1, winnr('$'), 'Location list has not appeared yet' + Assert exists('#neomake_event_queue#WinEnter'), 'autocmd was setup' + + " Go to first window for wincmd-p check. + 1wincmd w + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling ProcessEntries.' + AssertNeomakeMessage 'Postponing location list processing.' + AssertNeomakeMessage 'Queuing action ProcessEntries for BufEnter, WinEnter.' + AssertNeomakeMessage 'action queue: skipping CleanJobinfo for not processed job_id.', 3 + AssertNeomakeMessage 'action queue: processed 0 items.' + exe winnr.'wincmd w' + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 3} + AssertEqual wincount + 1, winnr('$'), 'Location list has appeared' + + AssertNeomakeMessage 'action queue: calling ProcessEntries.', 3 + AssertNeomakeMessage 'Processing 1 entries.', 3 + AssertNeomakeMessage 'Handling location list: executing lwindow.', 3, jobinfo + AssertNeomakeMessage 'action queue: calling CleanJobinfo.', 3, jobinfo + AssertNeomakeMessage 'action queue: processed 2 items.' + + Assert !exists('#neomake_event_queue#WinEnter'), 'autocmd was deleted' + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist + AssertEqual s:called, 0 + else + AssertEqual s:called, 1 + endif + + wincmd p + AssertEqual 1, winnr() + 3wincmd w + lclose + bwipe + bwipe + endif + +Execute (Goes back to original window after opening list (wincmd in process_output)): + " Like above, but calls QuickfixCmdPost only after job has finished. + if NeomakeAsyncTestsSetup() + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + new + let winnr = winnr() + let wincount = winnr('$') + + let maker = copy(g:error_maker) + function! maker.process_output(...) + 2wincmd w + return [{'text': 'error', 'type': 'E', 'lnum': 1, 'bufnr': bufnr('%')}] + endfunction + + let s:called = 0 + augroup neomake_tests + autocmd QuickFixCmdPost * let s:called = 1 | AssertEqual len(g:neomake_test_jobfinished), 1 + augroup END + + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Processing 1 lines of output.' + AssertNeomakeMessage 'Postponing location list processing.', 3, jobinfo + AssertNeomakeMessage 'Queuing action ProcessEntries for BufEnter, WinEnter.', 3 + AssertEqual getloclist(winnr), [] + AssertEqual s:called, 0 + AssertEqual 2, winnr() + + AssertNotEqual wincount + 1, winnr('$'), 'Location list has not appeared yet' + Assert exists('#neomake_event_queue#WinEnter'), 'autocmd was setup' + + " Go to first window for wincmd-p check. + 1wincmd w + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling ProcessEntries.' + AssertNeomakeMessage 'Postponing location list processing.' + AssertNeomakeMessage 'Queuing action ProcessEntries for BufEnter, WinEnter.' + AssertNeomakeMessage 'action queue: skipping CleanJobinfo for not processed job_id.', 3 + AssertNeomakeMessage 'action queue: processed 0 items.' + exe winnr.'wincmd w' + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 3} + AssertEqual wincount + 1, winnr('$'), 'Location list has appeared' + AssertEqual map(getloclist(winnr), '[v:val.text, v:val.type]'), [['error', 'E']] + + AssertNeomakeMessage 'action queue: calling ProcessEntries.', 3 + AssertNeomakeMessage 'Processing 1 entries.', 3 + AssertNeomakeMessage 'Creating location list for entries.' + AssertNeomakeMessage 'Handling location list: executing lwindow.', 3, jobinfo + AssertNeomakeMessage 'action queue: calling CleanJobinfo.', 3, jobinfo + AssertNeomakeMessage 'action queue: processed 2 items.' + + Assert !exists('#neomake_event_queue#WinEnter'), 'autocmd was deleted' + AssertEqual s:called, 0, "s:AddExprCallback is not called" + + wincmd p + AssertEqual 1, winnr() + 3wincmd w + lclose + bwipe + bwipe + endif + +Execute (Goes back to original window after opening list (mapexpr)): + " Like above, but calls QuickfixCmdPost only after job has finished. + if NeomakeAsyncTestsSetup() + try + call map([], function('tr')) + catch + NeomakeTestsSkip 'Cannot use funcref with map' + return + endtry + + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + new + let winnr = winnr() + let wincount = winnr('$') + + let maker = copy(g:error_maker) + function! maker.mapexpr(k, v) + 2wincmd w + return a:v + endfunction + + let s:called = 0 + augroup neomake_tests + autocmd QuickFixCmdPost * let s:called = 1 | AssertEqual len(g:neomake_test_jobfinished), 0 + augroup END + + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Processing 1 lines of output.' + AssertNeomakeMessage 'Postponing location list processing.', 3, jobinfo + AssertNeomakeMessage 'Queuing action AddExprCallback for BufEnter, WinEnter.', 3 + AssertEqual getloclist(winnr), [] + AssertEqual s:called, 0 + AssertEqual 2, winnr() + + AssertNotEqual wincount + 1, winnr('$'), 'Location list has not appeared yet' + Assert exists('#neomake_event_queue#WinEnter'), 'autocmd was setup' + + " Go to first window for wincmd-p check. + 1wincmd w + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling AddExprCallback.' + AssertNeomakeMessage 'Postponing location list processing.' + AssertNeomakeMessage 'Queuing action AddExprCallback for BufEnter, WinEnter.' + AssertNeomakeMessage 'action queue: skipping CleanJobinfo for not processed job_id.', 3 + AssertNeomakeMessage 'action queue: processed 0 items.' + exe winnr.'wincmd w' + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 3} + AssertEqual wincount + 1, winnr('$'), 'Location list has appeared' + AssertEqual map(getloclist(winnr), '[v:val.text, v:val.type]'), [['error', 'E']] + + AssertNeomakeMessage 'action queue: calling AddExprCallback.', 3 + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist + AssertNeomakeMessage 'Creating location list for entries.' + else + AssertNeomakeMessage 'Creating location list.' + endif + AssertNeomakeMessage 'Processing 1 entries.', 3 + AssertNeomakeMessage 'Handling location list: executing lwindow.', 3, jobinfo + AssertNeomakeMessage 'action queue: calling CleanJobinfo.', 3, jobinfo + AssertNeomakeMessage 'action queue: processed 2 items.' + + Assert !exists('#neomake_event_queue#WinEnter'), 'autocmd was deleted' + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist + AssertEqual s:called, 0 + else + AssertEqual s:called, 1 + endif + + wincmd p + AssertEqual 1, winnr() + 3wincmd w + lclose + bwipe + bwipe + endif + +Execute (open_list=1 with job: just opens location window): + Save g:neomake_open_list + let g:neomake_open_list = 1 + new + new + let winnr = winnr() + let wincount = winnr('$') + + call neomake#Make(1, [g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(winnr), '[v:val.text, v:val.type]'), [['error', 'E']] + AssertEqual wincount + 1, winnr('$'), 'Location list has appeared' + + Assert !exists('#neomake_event_queue#WinEnter'), 'autocmd was not setup' + AssertNeomakeMessage 'Handling location list: executing lwindow.' + AssertEqual winheight(winnr()), 1 + + AssertEqual winnr(), winnr('$'), 'In location window.' + wincmd p + + call neomake#Make(1, [g:true_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual wincount, winnr('$'), 'Location list has been closed' + exe winnr 'wincmd w' + bwipe + bwipe + +Execute (open_list=0: does not open location window): + if exists('#neomake_event_queue') + autocmd! neomake_event_queue + augroup! neomake_event_queue + endif + Save g:neomake_open_list + let g:neomake_open_list = 0 + new + let wincount = winnr('$') + + call neomake#Make(1, [g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), '[v:val.text, v:val.type]'), [['error', 'E']] + AssertEqual wincount, winnr('$'), 'Location list has not appeared' + + Assert !exists('#neomake_event_queue#WinEnter'), 'autocmd was not setup' + Assert !exists('#neomake_event_queue'), 'augroup does not exist' + bwipe + +Execute (open_list=1 with height=0: does not open location window): + Save g:neomake_open_list, g:neomake_list_height + let g:neomake_open_list = 1 + let g:neomake_list_height = 0 + new + let wincount = winnr('$') + + call neomake#Make(1, [g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), '[v:val.text, v:val.type]'), [['error', 'E']] + AssertEqual wincount, winnr('$'), 'Location list has not appeared' + + Assert !exists('#neomake_event_queue#WinEnter'), 'autocmd was not setup' + Assert !exists('#neomake_event_queue'), 'augroup does not exist' + bwipe + +Execute (open_list=2 uses minimum from list_height and entries): + Save g:neomake_open_list, g:neomake_list_height + let g:neomake_open_list = 1 + let g:neomake_list_height = 3 + new + let wincount = winnr('$') + + let entry_maker = {} + function entry_maker.get_list_entries(...) + let buf = bufnr('%') + return [ + \ {'text': '1', 'bufnr': buf, 'lnum': 1}, + \ {'text': '2', 'bufnr': buf, 'lnum': 1}, + \ {'text': '3', 'bufnr': buf, 'lnum': 1}, + \ {'text': '4', 'bufnr': buf, 'lnum': 1}, + \ ] + endfunction + call neomake#Make(1, [entry_maker]) + AssertEqual map(getloclist(0), 'v:val.text'), ['1', '2', '3', '4'] + AssertEqual winheight(winnr()), 3 + + " Does not change already open window. + function! entry_maker.get_list_entries(...) + let buf = bufnr('%') + return [ + \ {'text': '1', 'bufnr': buf, 'lnum': 1}, + \ {'text': '2', 'bufnr': buf, 'lnum': 1}, + \ ] + endfunction + call neomake#Make(1, [entry_maker]) + AssertEqual map(getloclist(0), 'v:val.text'), ['1', '2'] + AssertEqual winheight(winnr()), 3 + + lclose + function! entry_maker.get_list_entries(...) + let buf = bufnr('%') + return [ + \ {'text': '1', 'bufnr': buf, 'lnum': 1}, + \ {'text': '2', 'bufnr': buf, 'lnum': 1}, + \ ] + endfunction + call neomake#Make(1, [entry_maker]) + AssertEqual map(getloclist(0), 'v:val.text'), ['1', '2'] + AssertEqual winheight(winnr()), 2 + lclose + + Assert !exists('#neomake_event_queue#WinEnter'), 'autocmd was not setup' + Assert !exists('#neomake_event_queue'), 'augroup does not exist' + bwipe + +Execute (location list gets created with entries from first job, closed only after all jobs finished): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let wincount = winnr('$') + + let b:neomake_serialize = 1 + call neomake#Make(1, [g:error_maker, g:true_maker]) + if neomake#has_async_support() + NeomakeTestsWaitForNextFinishedJob + AssertEqual map(getloclist(0), '[v:val.text, v:val.type, v:val.valid]'), [['error', 'E', 1]] + AssertEqual wincount + 1, winnr('$'), 'Location list has appeared' + NeomakeTestsWaitForFinishedJobs + endif + AssertEqual map(getloclist(0), '[v:val.text, v:val.type, v:val.valid]'), [['error', 'E', 1]] + AssertEqual wincount + 1, winnr('$'), 'Location list has appeared' + + let flagfile = tempname() + let maker1 = NeomakeTestsCommandMaker('maker1', 'true') + if neomake#has_async_support() + let maker2 = NeomakeTestsCommandMaker('maker2', 'while ! [ -e '.fnameescape(flagfile).' ]; do sleep 0.01; done') + else + let maker2 = NeomakeTestsCommandMaker('maker2', 'true') + endif + let b:neomake_serialize = 1 + call neomake#Make(1, [maker1, maker2]) + if neomake#has_async_support() + NeomakeTestsWaitForNextFinishedJob + AssertEqual wincount + 1, winnr('$'), 'Location list was not closed' + AssertEqual map(getloclist(0), '[v:val.text, v:val.type, v:val.valid]'), [['error', 'E', 1]] + call writefile([], flagfile) + NeomakeTestsWaitForFinishedJobs + endif + AssertEqual getloclist(0), [] + AssertEqual wincount, winnr('$'), 'Location list was closed' + bwipe + +Execute (empty location list is handled with :lopen): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let wincount = winnr('$') + + let b:neomake_serialize = 1 + let maker = {'exe': 'printf', 'args': ['%s\n', 'filtered_line'], 'errorformat': '%-G%.%#'} + CallNeomake 1, [maker] + AssertNeomakeMessage 'Processing 2 lines of output.', 3 + AssertNeomakeMessageAbsent 'Processing 0 entries.', 3 + + AssertEqual map(getloclist(0), 'v:val.text'), [] + + CallNeomake 1, [ g:true_maker] + AssertEqual map(getloclist(0), 'v:val.text'), [] + bwipe + +Execute (adjusts height of list for second maker): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let wincount = winnr('$') + + let b:neomake_serialize = 1 + CallNeomake 1, [g:error_maker, g:error_maker] + + AssertEqual len(getloclist(0)), 2 + AssertNeomakeMessage 'Resizing existing quickfix window: 3resize 2.' + + let qf_win = winnr('$') + AssertEqual getwinvar(qf_win, '&filetype'), 'qf' + AssertEqual winheight(qf_win), 2 + lclose + bwipe + +Execute (logs not found window): + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let wincount = winnr('$') + + " open/create location window already, which makes Neomake not set + " w:neomake_window_for_make_id therein. + lopen + AssertEqual winheight(winnr()), 10 + wincmd p + let b:neomake_serialize = 1 + CallNeomake 1, [g:error_maker, g:error_maker] + + AssertEqual len(getloclist(0)), 2 + AssertNeomakeMessage 'Could not find corresponding quickfix window.' + AssertEqual 1, len(filter(copy(g:neomake_test_messages), 'v:val[1] == "Could not find corresponding quickfix window."')) + + let qf_win = winnr('$') + AssertEqual getwinvar(qf_win, '&filetype'), 'qf' + AssertEqual winheight(qf_win), 10 + lclose + bwipe + +Execute (Handles :lwindow closing the list window): + if !has('patch-7.4.379') + NeomakeTestsSkip 'Not without 7.4.379' + else + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let wincount = winnr('$') + + " Create/open location list manually (no need to run a job for it). + " (Using a job would also not fix it with 7.4.379 currently) + call setloclist(0, [{'bufnr': bufnr('%'), 'lnum': 1, 'col': 1, 'text': 'error'}]) + lwindow + AssertEqual len(getloclist(0)), 1 + let qf_win = winnr('$') + Assert qf_win > wincount, 'Location list was opened' + + " Run a maker with unrecognized/invalid entries only. + " NOTE: this runs it from the location list window. + let maker = {} + function! maker.get_list_entries(...) + return [{'bufnr': bufnr('%'), 'lnum': 0, 'col': 0}] + endfunction + + CallNeomake 1, [maker] + AssertEqual len(getloclist(0)), 1 + let qf_win = winnr('$') + + AssertEqual qf_win, wincount, 'Location list was closed for unrecognized/invalid entries' + AssertNeomakeMessage 'list window has been closed (old count: 3, new count: 2).', 3 + bwipe + endif + +Execute (Handles :cwindow closing the list window): + if !has('patch-7.4.379') + NeomakeTestsSkip 'Not without 7.4.379' + else + Save g:neomake_open_list + let g:neomake_open_list = 2 + new + let wincount = winnr('$') + + " Create/open location list manually (no need to run a job for it). + " (Using a job would also not fix it with 7.4.379 currently) + call setqflist([{'bufnr': bufnr('%'), 'lnum': 1, 'col': 1, 'text': 'error'}]) + cwindow + AssertEqual len(getqflist()), 1 + let qf_win = winnr('$') + Assert qf_win > wincount, 'Location list was opened' + + " Run a maker with unrecognized/invalid entries only. + " NOTE: this runs it from the location list window. + let maker = {} + function! maker.get_list_entries(...) + return [{'bufnr': bufnr('%'), 'lnum': 0, 'col': 0}] + endfunction + + CallNeomake 0, [maker] + AssertEqual len(getqflist()), 1 + let qf_win = winnr('$') + + AssertEqual qf_win, wincount, 'Quickfix list was closed for unrecognized/invalid entries' + AssertNeomakeMessage 'list window has been closed (old count: 3, new count: 2).', 3 + bwipe + endif + +Execute (Quiet with no QuickfixCmdPost autocommands): + new + if exists('#QuickfixCmdPost') + Assert 0, 'Unexpected automd: '.neomake#utils#redir('au QuickfixCmdPost') + endif + call NeomakeTestsSetVimMessagesMarker() + + CallNeomake 1, [g:error_maker] + Assert len(getloclist(0)) + AssertEqual NeomakeTestsGetVimMessages(), [] + + augroup neomake_tests + au QuickfixCmdPost *vimgrep* let foo = 1 + augroup END + CallNeomake 1, [g:error_maker] + Assert len(getloclist(0)) + AssertEqual NeomakeTestsGetVimMessages(), [] + + let s:called = 0 + augroup neomake_tests + au QuickfixCmdPost ladd* let s:called = 1 + augroup END + CallNeomake 1, [g:error_maker] + Assert len(getloclist(0)) + AssertEqual NeomakeTestsGetVimMessages(), [] + if has('patch-8.0.1040') + AssertEqual s:called, 0 + else + AssertEqual s:called, 1 + endif + bwipe + +Execute (open_list and list_height can be buffer settings): + new + let b:neomake_open_list = 2 + let b:neomake_list_height = 2 + + let winnr = winnr() + let wincount = winnr('$') + + " Maker with three entries. + let maker = {} + function! maker.get_list_entries(...) + return [ + \ {'lnum': 1, 'bufnr': bufnr('%'), 'type': 'E', 'text': '1'}, + \ {'lnum': 1}, + \ {'lnum': 1}] + endfunction + CallNeomake 1, [maker] + + AssertEqual winnr, winnr() + AssertEqual wincount + 1, winnr('$'), 'Location list appeared' + AssertEqual map(getloclist(0), '[v:val.text, v:val.type]'), + \ [['1', 'E'], ['', 'W'], ['', 'W']] + + AssertEqual winheight(wincount + 1), 2 + lclose + bwipe + +Execute (postprocess: removing all entries): + new + AssertEqual getloclist(0), [] + let maker = copy(g:error_maker) + function! maker.postprocess(entry) abort + let a:entry.valid = -1 + endfunction + + CallNeomake 1, [maker] + AssertNeomakeMessage 'Processing 1 lines of output.' + AssertNeomakeMessage '\v^Removing invalid entry: error .*' + AssertEqual getloclist(0), [] + bwipe + +Execute (uses only its own list (loclist)): + new + let maker1 = {} + function! maker1.get_list_entries(...) + lgetexpr 'new_list_1' + return [{'lnum': 1, 'bufnr': bufnr('%'), 'type': 'E', 'text': '1'}] + endfunction + let maker2 = {} + function! maker2.get_list_entries(...) + lgetexpr 'new_list_2' + return [{'lnum': 1, 'bufnr': bufnr('%'), 'type': 'E', 'text': '2'}] + endfunction + CallNeomake 1, [maker1, maker2] + + if has('patch-8.0.1023') + AssertEqual map(getloclist(0), 'v:val.text'), ['new_list_2'] + silent lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['1', '2'] + silent lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['new_list_1'] + else + AssertEqual map(getloclist(0), 'v:val.text'), ['new_list_2', '2'] + silent lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['1'] + silent lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['new_list_1'] + endif + bwipe + +Execute (uses only its own list (qflist)): + new + let maker1 = {} + function! maker1.get_list_entries(...) + cgetexpr 'new_list_1' + return [{'lnum': 1, 'bufnr': bufnr('%'), 'type': 'E', 'text': '1'}] + endfunction + let maker2 = {} + function! maker2.get_list_entries(...) + cgetexpr 'new_list_2' + return [{'lnum': 1, 'bufnr': bufnr('%'), 'type': 'E', 'text': '2'}] + endfunction + CallNeomake 0, [maker1, maker2] + + if has('patch-8.0.1023') + AssertEqual map(getqflist(), 'v:val.text'), ['new_list_2'] + silent colder + AssertEqual map(getqflist(), 'v:val.text'), ['1', '2'] + silent colder + AssertEqual map(getqflist(), 'v:val.text'), ['new_list_1'] + else + AssertEqual map(getqflist(), 'v:val.text'), ['new_list_2', '2'] + silent colder + AssertEqual map(getqflist(), 'v:val.text'), ['1'] + silent colder + AssertEqual map(getqflist(), 'v:val.text'), ['new_list_1'] + endif + bwipe + +Execute (creates single list for clean maker): + new + lgetexpr 'init' + CallNeomake 1, [g:true_maker] + AssertEqual getloclist(0), [] + silent lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['init'] + bwipe + +Execute (use_list: make option): + new + lgetexpr 'init' + CallNeomake {'file_mode': 1, 'use_list': 0, 'enabled_makers': [g:error_maker]} + AssertEqual map(getloclist(0), 'v:val.text'), ['init'] + bwipe + +Execute (use_list: enabled via all makers having use_list=0): + new + let maker = copy(g:error_maker) + let maker.use_list = 0 + lgetexpr 'init' + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), 'v:val.text'), ['init'] + bwipe diff --git a/bundle/neomake/tests/log.vader b/bundle/neomake/tests/log.vader new file mode 100644 index 000000000..89931f8b1 --- /dev/null +++ b/bundle/neomake/tests/log.vader @@ -0,0 +1,41 @@ +Include: include/setup.vader + +Execute (neomake#log#debug writes to logfile always): + Save g:neomake_verbose, g:neomake_logfile + let neomake_verbose = 0 + let g:neomake_logfile = tempname() + call neomake#log#debug('msg1.') + call neomake#log#debug('msg2.') + if has('patch-7.4.503') + let logfile_msg = readfile(g:neomake_logfile)[1] + else + let logfile_msg = readfile(g:neomake_logfile)[0] + endif + " Also allow for small delay (on CI). + Assert logfile_msg =~# '\v\d\d:\d\d:\d\d \d+ \[D (\+0.0\d| )\] msg2.$', 'unexpected msg: '.logfile_msg + + call neomake#log#debug('msg3.') + sleep 10m + call neomake#log#debug('msg4.', {}) + let logfile_msg = readfile(g:neomake_logfile)[-1] + Assert logfile_msg =~# '\v\d\d:\d\d:\d\d \d+ \[D \+0.\d\d\] \[-.-:-:\d+\] msg4.$', 'Message does not match: '.logfile_msg + +Execute (neomake#log#debug unsets logfile in case of errors): + Save g:neomake_logfile + let g:neomake_logfile = '/does/not/exist' + call neomake#log#debug('msg1.') + AssertNeomakeMessage '\vError when trying to write to logfile /does/not/exist: Vim\(call\):E.*. Unsetting g:neomake_logfile.', 0 + Assert !exists('g:neomake_logfile'), 'g:neomake_logfile has been unset.' + +Execute (neomake#log#debug is picky about punctuation): + call neomake#log#debug('msg1') + AssertEqual g:neomake_test_errors, ['Log msg does not end with punctuation: "msg1".'] + let g:neomake_test_errors = [] + +Execute (neomake#log#debug throws with missing make_options in tests): + " Non-existing make_id should not make it verbose. + AssertEqual g:neomake_test_errors, [] + call neomake#log#debug('msg1.', {'make_id': -42}) + AssertEqual len(g:neomake_test_errors), 1 + Assert g:neomake_test_errors[0] =~# '\v^GetMakeOptions failed: Vim\(let\):E716: Key not present in Dictionary: -42 \(in function .*\)$' + let g:neomake_test_errors = [] diff --git a/bundle/neomake/tests/main.vader b/bundle/neomake/tests/main.vader new file mode 100644 index 000000000..f1779615e --- /dev/null +++ b/bundle/neomake/tests/main.vader @@ -0,0 +1,77 @@ +" Main entry point to run main Vader tests (without isolated ones). +" Use all.vader to run all tests. +" +" You can run the included files by themselves (since they also source +" include/setup.vader). + +~ Features +Include (:NeomakeInfo): cmd_neomakeinfo.vader +Include (Automaking): automake.vader +Include (Action queue): action_queue.vader +Include (Cancellation): cancellation.vader +Include (Compat): compat.vader +Include (Completion): completion.vader +Include (Config): config.vader +Include (Clean command): clean.vader +Include (Current working dir): cwd.vader +Include (Current error): current_error.vader +Include (Custom Quickfix): customqf.vader +Include (Debug/Checks/Feedback): debug.vader +Include (Environment variables): env.vader +Include (Error handling): errors.vader +Include (Filetype handling): filetypes.vader +Include (Filter output): filter_output.vader +Include (Highlights): highlights.vader +Include (Hooks): hooks.vader +Include (Hooks get queued): hooks-queue.vader +Include (Integration tests): integration.vader +Include (Jobinfo): jobinfo.vader +Include (JSON): json.vader +Include (List): list.vader +Include (Lists): lists.vader +Include (List entries): list-entries.vader +Include (Logging): log.vader +Include (Makeprg): makeprg.vader +Include (Maker args): args.vader +Include (Maker errors): maker_errors.vader +Include (Makers): makers.vader +Include (Mapexpr): mapexpr.vader +Include (Postprocess): postprocess.vader +Include (Processing): processing.vader +Include (Serialize): serialize.vader +Include (Signs): signs.vader +Include (Statusline): statusline.vader +Include (Stdin): stdin.vader +Include (Temporary files): tempfiles.vader +Include (Toggling): toggle.vader +Include (Utils: project root): utils_projectroot.vader +Include (Utils): utils.vader +Include (Verbosity): verbosity.vader +Include (Vim/Neovim behavior): vim_and_neovim_behavior.vader + +~ Filetype specific +Include (Asciidoc): ft_asciidoc.vader +Include (Cs): ft_cs.vader +Include (Css): ft_css.vader +Include (Elixir): ft_elixir.vader +Include (Elm): ft_elm.vader +Include (Erlang): ft_erlang.vader +Include (Go): ft_go.vader +Include (HTML): ft_html.vader +Include (Haskell): ft_haskell.vader +Include (Idris): ft_idris.vader +Include (JavaScript): ft_javascript.vader +Include (Markdown): ft_markdown.vader +Include (Perl): ft_perl.vader +Include (PHP): ft_php.vader +Include (Puppet): ft_puppet.vader +Include (PureScript): ft_purescript.vader +Include (Python): ft_python.vader +Include (ReStructuredText): ft_rst.vader +Include (Rust): ft_rust.vader +Include (Shell): ft_sh.vader +Include (SQL): ft_sql.vader +Include (Text): ft_text.vader +Include (TypeScript): ft_typescript.vader +Include (Vim): ft_vim.vader +Include (XML): ft_xml.vader diff --git a/bundle/neomake/tests/makeprg.vader b/bundle/neomake/tests/makeprg.vader new file mode 100644 index 000000000..222225e4e --- /dev/null +++ b/bundle/neomake/tests/makeprg.vader @@ -0,0 +1,27 @@ +Include: include/setup.vader + +Execute (makeprg: exe): + Save &makeprg + let &makeprg = 'my-make' + + let makers = neomake#GetEnabledMakers() + AssertEqual len(makers), 1 + let maker = makers[0] + AssertEqual maker.exe, 'my-make' + AssertEqual maker.args, [] + + let jobinfo = NeomakeTestsFakeJobinfo() + let jobinfo.file_mode = 0 + AssertEqual maker.args, [] + AssertEqual maker.append_file, 0 + +Execute (makeprg: exe and args): + Save &makeprg + let &makeprg = 'my-make with-arg' + + let makers = neomake#GetEnabledMakers() + AssertEqual len(makers), 1 + let maker = makers[0] + AssertEqual maker.exe, &shell + AssertEqual maker.args, [&shellcmdflag, 'my-make with-arg'] + AssertEqual maker.append_file, 0 diff --git a/bundle/neomake/tests/maker_errors.vader b/bundle/neomake/tests/maker_errors.vader new file mode 100644 index 000000000..c24cc40c9 --- /dev/null +++ b/bundle/neomake/tests/maker_errors.vader @@ -0,0 +1,35 @@ +Include: include/setup.vader + +Execute (Handles unexpected output on stderr from maker): + Save g:neomake_logfile + let g:neomake_logfile = tempname() + + let maker = NeomakeTestsCommandMaker('stderr_maker', 'echo failed to run >&2; echo because something bad happened >&2') + let maker.output_stream = 'stdout' + + call NeomakeTestsSetVimMessagesMarker() + CallNeomake 1, [maker] + if neomake#has_async_support() + AssertNeomakeMessage 'stderr_maker: unexpected output. See :messages for more information.', 0 + else + AssertNeomakeMessage 'stderr_maker: unexpected output.', 0 + endif + + let messages_lines = NeomakeTestsGetVimMessages() + AssertEqual messages_lines[-2:-1], [ + \ 'Neomake: stderr_maker: unexpected output on stderr: failed to run', + \ 'because something bad happened'] + + if !has('patch-7.4.503') + NeomakeTestsSkip 'Cannot check logfile contents.' + else + let log_lines = readfile(g:neomake_logfile) + let found = 0 + for line in log_lines + if line =~# '\v^\d+:\d+:\d+ \d+ \[D .*\] stderr_maker: unexpected output on stderr: failed to run\\nbecause something bad happened.$' + let found = 1 + break + endif + endfor + AssertEqual found, 1, 'Found unexpected-output msg' + endif diff --git a/bundle/neomake/tests/makers.vader b/bundle/neomake/tests/makers.vader new file mode 100644 index 000000000..b5738562f --- /dev/null +++ b/bundle/neomake/tests/makers.vader @@ -0,0 +1,1094 @@ +Include: include/setup.vader + +Execute (neomake#GetMakers): + AssertEqual neomake#GetMakers('non-existent'), [] + AssertEqual neomake#GetMakers('pug'), ['puglint'] + + let sh_makers = ['checkbashisms', 'dash', 'sh', 'shellcheck'] + AssertEqual sort(neomake#GetMakers('sh')), sh_makers + + Save g:neomake_sh_enabled_makers + let g:neomake_sh_enabled_makers = ['sh'] + AssertEqual sort(neomake#GetMakers('sh')), sh_makers + +Execute (neomake#GetMakers uses makers from buffer vars): + new + let b:neomake_ft1_my_custom_maker = {} + let b:neomake_ft1_my_custom2_maker = {} + let b:neomake_ft2_my_custom2_maker = {} + + AssertEqual neomake#GetMakers('ft1'), ['my_custom', 'my_custom2'] + AssertEqual neomake#GetMakers('ft2'), ['my_custom2'] + AssertEqual neomake#GetMakers('ft1.ft2'), ['my_custom', 'my_custom2'] + bwipe + +Execute (neomake#GetMakers uses makers from new-style config): + new + noautocmd set filetype=myft + let maker1 = {'name': 'maker1'} + let maker2 = {'name': 'maker2'} + call neomake#config#set('b:ft.myft.my_custom.maker', maker1) + call neomake#config#set('b:ft.myft.my_custom2.maker', maker2) + + AssertEqual neomake#GetMaker('my_custom').name, 'maker1' + AssertNeomakeMessage "Using setting maker={'name': 'maker1'} from 'buffer' (prefix: ['ft', 'myft', 'my_custom']).", 3 + + AssertEqual neomake#GetMaker('my_custom2').name, 'maker2' + AssertNeomakeMessage "Using setting maker={'name': 'maker2'} from 'buffer' (prefix: ['ft', 'myft', 'my_custom2']).", 3 + + AssertEqual neomake#GetMakers('myft'), ['my_custom', 'my_custom2'] + AssertNeomakeMessage "Using setting ft.myft={'my_custom': {'maker': {'name': 'maker1'}}, 'my_custom2': {'maker': {'name': 'maker2'}}} from 'buffer'.", 3 + bwipe + +Execute (neomake#GetMakers new-style config with old-style): + new + noautocmd set filetype=myft + + let maker1 = {'name': 'maker1'} + call neomake#config#set('b:ft.myft.my_custom.maker', maker1) + + let maker2 = {'name': 'maker2'} + let b:neomake_myft_my_custom_maker = maker2 + + " Maker name is not duplicated. + AssertEqual neomake#GetMakers('myft'), ['my_custom'] + + " GetMaker prefers new-style config. + AssertEqual neomake#GetMaker('my_custom').name, 'maker1' + bwipe + +Execute (neomake#GetMaker uses defined errorformat with makeprg): + Save &errorformat + let &errorformat = '%Gcustom' + AssertEqual neomake#GetMaker('makeprg', '').errorformat, '%Gcustom' + +Execute (neomake#GetMaker defaults to current filetype): +" Save &errorformat +" let &errorformat = '%Gcustom' +" AssertEqual neomake#GetMaker('makeprg', '').errorformat, '%Gcustom' + +Execute (neomake#GetMaker uses defaults from b:/g:): + Save g:neomake_test_remove_invalid_entries + Save b:neomake_test_remove_invalid_entries + + let maker = {'name': 'test'} + + " Default. + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 0, + \ "default is ok" + + let maker.remove_invalid_entries = 1 + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 1 + let g:neomake_test_remove_invalid_entries = 2 + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 2 + let b:neomake_test_remove_invalid_entries = 3 + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 3 + +Execute (neomake#GetMaker uses defaults from b:/g: based on maker): + Save g:neomake_test_remove_invalid_entries + + let maker = {'name': 'test'} + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 0 + let maker.remove_invalid_entries = 1 + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 1 + let g:neomake_test_remove_invalid_entries = 2 + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 2 + let b:neomake_test_remove_invalid_entries = 3 + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 3 + +Execute (neomake#GetMaker uses maker_defaults): + let maker = {'name': 'test'} + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 0 + + call neomake#config#set('maker_defaults.remove_invalid_entries', 1) + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 1 + + " maker_defaults uses hard-coded defaults when only set partially/loaded. + AssertEqual neomake#GetMaker(maker).buffer_output, 1 + + " maker_defaults uses hard-coded defaults always. + call neomake#config#set('maker_defaults', {}) + AssertEqual neomake#GetMaker(maker).remove_invalid_entries, 0 + +Execute (neomake#GetMaker from g:neomake_foo_maker): + let g:neomake_custom_maker = { + \ 'exe': 'my-exe' + \ } + let maker = neomake#GetMaker('custom') + AssertEqual maker.exe, 'my-exe' + AssertEqual maker.name, 'custom' + +Execute (neomake#GetMaker without name): + let maker = neomake#GetMaker({}) + AssertEqual maker.exe, 'unnamed_maker' + AssertEqual maker.name, 'unnamed_maker' + +Execute (Instantiate all default makers): + " This is meant to catch issues like https://github.com/neomake/neomake/pull/555. + let glob_args = [fnamemodify(g:vader_file, ':p:h') + \ .'/../autoload/neomake/makers/ft/*.vim', 1, 1] + " NOTE: not using a list to support older Vim (on Travis). + let ft_makers = split(call('glob', glob_args[0:-2]), '\n') + + " For vim makers' EnabledMakers to use neomake_checks. + new + noautocmd edit autoload/neomake/makers/ft/vim.vim + + let errors_by_file = {} + let file_errors = [] + for maker_file in ft_makers + let ft = fnamemodify(maker_file, ':t:r') + if ft ==# 'haskell' + NeomakeTestsSkip 'Skipping haskell - expensive setup' + continue + endif + + let f = 'neomake#makers#ft#'.ft.'#EnabledMakers' + try + let enabled_makers = call(f, []) + catch /^Vim(let):E119:/ + try + let enabled_makers = call(f, [{'file_mode': 1, 'bufnr': bufnr('%')}]) + catch + call add(file_errors, 'Error when calling '.f.'(options): '.v:exception) + endtry + catch + call add(file_errors, 'Error when calling '.f.': '.v:exception) + endtry + + let makers = neomake#GetMakers(ft) + + " Check that all enabled makers are actually available. + " Skip neomake_tests, which has "nonexisting" there. + if ft !=# 'neomake_tests' + for m in enabled_makers + if index(makers, m) == -1 + call add(file_errors, printf( + \ 'Enabled maker %s missing in available makers: %s', + \ string(m), string(makers))) + endif + endfor + endif + + if ft ==# 'rst' + " Skip sphinx, would throw an error; it is tested separately. + " TODO: align with clippy maker, which only uses neomake#log#error + " (https://github.com/neomake/neomake/issues/1453). + call filter(makers, "v:val !=# 'sphinx'") + endif + for m in makers + try + let maker = neomake#GetMaker(m, ft) + catch + call add(file_errors, 'Could not load maker '.string(m).' for filetype '.ft.': '.v:exception) + continue + endtry + + " Validate maker. + let error_with_validate_maker = 1 + try + let issues = neomake#debug#validate_maker(extend(maker, {'exe': 'true'})) + let error_with_validate_maker = 0 + finally + if error_with_validate_maker + call vader#log(printf('Error with: %s!', m)) + endif + endtry + if !empty(issues.errors) + call add(file_errors, 'Maker '.string(m).' for filetype '.ft.' has errors: '.join(issues.errors)) + endif + if !empty(issues.warnings) + call add(file_errors, 'Maker '.string(m).' for filetype '.ft.' has warnings: '.join(issues.warnings)) + endif + endfor + + if !empty(file_errors) + let errors_by_file[maker_file] = copy(file_errors) + let file_errors = [] + endif + endfor + Assert empty(file_errors) + + let errors = [] + for m in neomake#GetProjectMakers() + try + let maker = neomake#GetMaker(m) + catch + call add(errors, 'Could not load project maker '.string(m).': '.v:exception) + continue + endtry + + " Validate maker. + let issues = neomake#debug#validate_maker(extend(maker, {'exe': 'true'})) + if !empty(issues.errors) + call add(errors, 'Project maker '.string(m).' has errors: '.join(issues.errors)) + endif + if !empty(issues.warnings) + call add(errors, 'Project maker '.string(m).' has warnings: '.join(issues.warnings)) + endif + endfor + + Assert empty(errors), "Errors when loading makers:\n - ".join(errors, "\n - ") + if !empty(errors_by_file) + let msg = '' + for [fname, errors] in items(errors_by_file) + let msg .= "\n - ".fnamemodify(fname, ':p:.').":\n" + let msg .= ' - '.join(errors, "\n - ") + endfor + Assert 0, "Errors when loading makers (per file):".msg + endif + AssertEqual exists('*neomake#makers#ft#neomake_tests#EnabledMakers'), 1 + bwipe + +Execute (neomake#GetEnabledMakers without make_id): + Save g:neomake_myft_enabled_makers + let g:neomake_myft_enabled_makers = ['nonexisting_custom'] + let makers = neomake#GetEnabledMakers('myft') + AssertNeomakeMessage 'Maker not found (for filetype myft): nonexisting_custom.', 0, {} + +Execute (Neomake with non-existing maker (configured)): + Save g:neomake_verbose, g:neomake_myft_enabled_makers + let g:neomake_verbose = 3 + let g:neomake_myft_enabled_makers = ['nonexisting_custom'] + + new + noautocmd set filetype=myft + let make_id_before = neomake#GetStatus().last_make_id + RunNeomake + let make_id = neomake#GetStatus().last_make_id + let log_context = {'make_id': make_id, 'bufnr': bufnr('%')} + if exists('*win_getid') + AssertNeomakeMessage "Calling Make with options {'ft': 'myft', 'file_mode': 1, 'winid': ".win_getid()."}.", 3, log_context + else + AssertNeomakeMessage "Calling Make with options {'ft': 'myft', 'file_mode': 1}.", 3, log_context + endif + AssertNeomakeMessage 'Maker not found (for filetype myft): nonexisting_custom.', 0, log_context + AssertNeomakeMessage 'Nothing to make: no enabled file mode makers (filetype=myft).', 1, log_context + AssertEqual len(g:neomake_test_messages), 3 + AssertEqual make_id_before + 1, neomake#GetStatus().last_make_id + bwipe + +Execute (Neomake with non-existing default makers): + call g:NeomakeSetupAutocmdWrappers() + new + set filetype=neomake_tests + Save g:neomake_test_enabledmakers + let g:neomake_test_enabledmakers = ['maker_without_exe', 'nonexisting'] + RunNeomake + AssertNeomakeMessage 'Maker not found (for filetype neomake_tests): nonexisting.', 3 + AssertNeomakeMessage "Exe (maker_without_exe) of auto-configured maker maker_without_exe is not executable, skipping.", 3 + AssertNeomakeMessage 'Nothing to make: no valid makers.', 3 + AssertEqual 0, len(g:neomake_test_jobfinished) + AssertEqual 0, len(g:neomake_test_finished) + bwipe + +Execute (Neomake with non-existing default maker handles following makers): + call g:NeomakeSetupAutocmdWrappers() + new + set filetype=neomake_tests + Save g:neomake_test_enabledmakers + let g:neomake_test_enabledmakers = ['maker_without_exe', 'echo_maker'] + RunNeomake + AssertNeomakeMessage "Exe (maker_without_exe) of auto-configured maker maker_without_exe is not executable, skipping.", 3 + AssertNeomakeMessage 'Running makers: echo_maker (auto).' + AssertEqual 1, len(g:neomake_test_jobfinished), 'echo_maker should have run' + AssertEqual 1, len(g:neomake_test_finished) + + RunNeomake + AssertNeomakeMessage "Exe (maker_without_exe) of auto-configured maker maker_without_exe is not executable, skipping.", 3 + bwipe + +Execute (Neomake with non-existing default makers, explicitly called): + Save &filetype + set filetype=neomake_tests + + RunNeomake maker_without_exe + AssertNeomakeMessage "Exe (maker_without_exe) of maker maker_without_exe is not executable.", 0 + + RunNeomake maker_without_exe + AssertNeomakeMessage "Exe (maker_without_exe) of maker maker_without_exe is not executable.", 0 + +Execute (neomake#GetEnabledMakers with defaults): + new + set filetype=neomake_tests + let makers = neomake#GetEnabledMakers(&ft) + AssertEqual map(copy(makers), 'v:val.auto_enabled'), [1] + AssertNeomakeMessage 'Maker not found (for filetype neomake_tests): nonexisting.', 3 + AssertEqual len(g:neomake_test_messages), 1 + bwipe + +Execute (neomake#GetEnabledMakers with configuration): + Save &filetype + set filetype=neomake_tests + + Save b:neomake_neomake_tests_enabled_makers + let b:neomake_neomake_tests_enabled_makers = ['maker_without_exe'] + + let makers = neomake#GetEnabledMakers(&ft) + AssertEqual map(copy(makers), 'v:val.auto_enabled'), [0] + AssertEqual len(g:neomake_test_messages), 0 + +Execute (neomake#GetEnabledMakers without filetype): + Save g:neomake_enabled_makers + unlet! g:neomake_enabled_makers + + AssertEqual map(neomake#GetEnabledMakers(''), 'v:val.name'), [] + + AssertEqual map(neomake#GetEnabledMakers(), 'v:val.name'), ['makeprg'] + + Save &makeprg + set makeprg= + AssertEqual map(neomake#GetEnabledMakers(), 'v:val.name'), [] + + Save g:neomake_mymaker_maker + let g:neomake_mymaker_maker = {} + let g:neomake_enabled_makers = ['mymaker'] + let makers = neomake#GetEnabledMakers() + AssertEqual map(copy(makers), '[v:val.name, v:val.auto_enabled]'), + \ [['mymaker', 0]] + + " Should use a more specific maker based on &filetype. + set filetype=myft + let g:neomake_myft_mymaker_maker = {} + let makers = neomake#GetEnabledMakers() + AssertEqual map(copy(makers), '[v:val.name, v:val.auto_enabled]'), + \ [['mymaker', 0]] + + " Should fallback to global maker if not found through filetype. + unlet g:neomake_myft_mymaker_maker + let makers = neomake#GetEnabledMakers() + AssertEqual map(copy(makers), '[v:val.name, v:val.auto_enabled]'), + \ [['mymaker', 0]] + + AssertEqual len(g:neomake_test_messages), 0 + +Execute (neomake#GetMaker errors): + AssertThrows call neomake#GetMaker('cargo', 'foo') + AssertEqual g:vader_exception, 'Neomake: Maker not found (for filetype foo): cargo' + +Execute (neomake#GetMaker for project maker): + Save g:neomake_enabled_makers + let g:neomake_enabled_makers = ['cargo'] + set ft=myft + + AssertThrows call neomake#GetMaker('cargo', 'foo') + AssertEqual g:vader_exception, 'Neomake: Maker not found (for filetype foo): cargo' + +Execute (maker.InitForJob can set env var): + let maker = { + \ 'exe': 'sh', + \ 'args': ['-c', 'echo MYENV:$MYENV'], + \ 'append_file': 0, + \ 'errorformat': '%m', + \ 'name': 'echo_env_maker', + \ } + function! maker.InitForJob(jobinfo) + let self.args = ['MYENV=custom', self.exe] + self.args + let self.exe = 'env' + let self.errorformat = '%m' + return self + endfunction + + let prev_maker = deepcopy(maker) + call neomake#Make(1, [maker]) + AssertEqual maker, prev_maker + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), ['MYENV:custom'] + +Execute (maker.InitForJob can be a buffer setting (old-style)): + new + let maker = {'name': 'mymaker'} + + let s:called = 0 + function! MyInit(jobinfo) dict + let s:called = 1 + let self.exe = 'doesnotexist' + endfunction + + let b:neomake_mymaker_InitForJob = function('MyInit') + + CallNeomake 1, [maker] + AssertEqual s:called, 1 + AssertNeomakeMessage 'Exe (doesnotexist) of maker mymaker is not executable.', 0 + delfunction MyInit + bwipe + +Execute (maker.InitForJob can be a buffer setting (new-style)): + new + noautocmd set filetype=neomake_tests + let maker = {'name': 'mymaker'} + + let s:called = 0 + function! MyInit(jobinfo) dict + let s:called = 1 + let self.exe = 'doesnotexist' + endfunction + + call neomake#config#set('b:ft.neomake_tests.InitForJob', function('MyInit')) + + CallNeomake 1, [maker] + AssertEqual s:called, 1 + AssertNeomakeMessage 'Exe (doesnotexist) of maker mymaker is not executable.', 0 + delfunction MyInit + bwipe + +Execute (Using maker.fn results in deprecation warning): + let maker = {} + function! maker.fn(jobinfo) abort + let self.exe = 'doesnotexist' + endfunction + + call NeomakeTestsSetVimMessagesMarker() + CallNeomake 1, [maker] + + AssertNeomakeWarning "Please use 'InitForJob' instead of 'fn' for maker unnamed_maker." + AssertNeomakeMessage 'Exe (doesnotexist) of maker unnamed_maker is not executable.', 0 + +Execute (Using maker.args as function results in deprecation warning): + let maker = {} + let maker.args = function('getcwd') + + call NeomakeTestsSetVimMessagesMarker() + CallNeomake 1, [maker] + + AssertNeomakeWarning "Please use 'InitForJob' instead of 'args' for maker unnamed_maker." + AssertNeomakeMessage 'Exe (unnamed_maker) of maker unnamed_maker is not executable.', 0 + +Execute (Using maker.args.fn as function results in deprecation warning): + let maker = {} + let maker.args = {} + function! maker.args.fn() abort + return ['deprecated'] + endfunction + + call NeomakeTestsSetVimMessagesMarker() + CallNeomake 1, [maker] + + AssertNeomakeWarning "Please use 'InitForJob' instead of 'args.fn' for maker unnamed_maker." + AssertNeomakeMessage 'Exe (unnamed_maker) of maker unnamed_maker is not executable.', 0 + +Execute (Set env from maker config): + Save g:neomake_rust_cargo_maker + + let maker = neomake#GetMaker('cargo', 'rust') + let maker.args = ['-c', 'env MYENV:$MYENV'] + [maker.exe] + maker.args + let maker.exe = 'sh' + + let g:neomake_rust_cargo_maker = maker + + let makers = neomake#GetEnabledMakers('rust') + AssertEqual makers[0].name, 'cargo' + AssertEqual makers[0], extend(maker, {'auto_enabled': 1}) + +Execute (Correct function binding from base maker): + let maker = neomake#GetMaker({'name': 'maker1'}) + AssertEqual maker.exe, 'maker1' + " Not sure about this one, but it asserts that there is no dict in the string + " representation of the object's function, when dumping the object. This was + " different before, when assigning the function from the base maker dict. + Assert string(maker) =~# '\v''_get_argv'': function\(''\d+''\),', 'Simple _get_argv' + +Execute (Makers: process_output): + new + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + + Save g:neomake_test_entries + let g:neomake_test_entries = [{ + \ 'bufnr': bufnr('%'), + \ 'filename': 'not_used_with_valid_bufnr', + \ 'lnum': 23, + \ 'pattern': '', + \ 'col': 42, + \ 'vcol': 0, + \ 'nr': 4711, + \ 'text': 'error message', + \ 'type': 'E', + \ }] + + let maker = { + \ 'name': 'mymaker', + \ 'exe': 'printf', + \ 'args': ['maker_output'], + \ 'append_file': 0} + function! maker.process_output(context) abort + AssertEqual ['maker_output'], a:context.output + AssertEqual 'stdout', a:context.source + return deepcopy(g:neomake_test_entries) + endfunction + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + let expected = copy(g:neomake_test_entries)[0] + " valid=1 gets added + let expected.valid = 1 + " filename is removed + unlet expected.filename + AssertEqualQf getloclist(0), [expected] + + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + bwipe + +Execute (Makers: get_list_entries): + new + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + + Save g:neomake_test_entries + let g:neomake_test_entries = [{ + \ 'bufnr': bufnr('%'), + \ 'filename': 'not_used_with_valid_bufnr', + \ 'lnum': 23, + \ 'pattern': '', + \ 'col': 42, + \ 'vcol': 0, + \ 'nr': 4711, + \ 'text': 'error message', + \ 'type': 'E', + \ }] + + let maker = {} + function! maker.get_list_entries(...) abort dict + let jobinfo = a:1 + AssertEqual sort(keys(jobinfo.maker)), ['auto_enabled', 'get_list_entries', 'name'] + Assert !has_key(self, 'errorformat'), 'errorformat is not required' + AssertEqual jobinfo.maker.auto_enabled, 0 + return deepcopy(g:neomake_test_entries) + endfunction + + let maker = neomake#GetMaker(maker) + let jobinfos = neomake#Make(1, [maker]) + Assert len(jobinfos), 1 + + " valid=1 gets added + let expected = map(copy(g:neomake_test_entries), "extend(v:val, {'valid': 1})") + " filename and maker_name is removed + let expected = map(expected, "filter(v:val, 'v:key != \"filename\"')") + AssertEqualQf getloclist(0), g:neomake_test_entries + + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + bwipe + +Execute (Makers: auto_enabled is kept if provided): + new + set filetype=neomake_tests + let b:neomake_neomake_tests_enabled_makers = [ + \ {'name': 'custom', 'auto_enabled': 1}, + \ ] + AssertEqual map(neomake#GetEnabledMakers('neomake_tests'), '[v:val.name, v:val.auto_enabled]'), + \ [['custom', 1]] + bwipe + +Execute (Makers: get_list_entries with non-list return value): + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + + let maker = {} + function! maker.get_list_entries(...) abort dict + endfunction + + CallNeomake 1, [maker] + AssertNeomakeMessage 'unnamed_maker: getting entries via get_list_entries.' + AssertNeomakeMessage 'The get_list_entries method for maker unnamed_maker did not return a list, but: 0.', 0 + + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + +Execute (Makers: get_list_entries with exception): + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + + let maker = {} + function! maker.get_list_entries(...) abort dict + throw "TEST_ERROR" + return [1] + endfunction + + CallNeomake 1, [maker] + AssertNeomakeMessage 'Error during get_list_entries for unnamed_maker: TEST_ERROR.' + AssertNeomakeMessage '\m^(in function .*)$', 3 + + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + +Execute (Makers: process_output with non-list return value): + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + + let maker = copy(g:success_maker) + function! maker.process_output(...) abort dict + endfunction + + CallNeomake 1, [maker] + AssertNeomakeMessage "Calling maker's process_output method with 1 lines of output on stdout.", 3 + AssertNeomakeMessage 'The process_output method for maker success-maker did not return a list, but: 0.', 0 + + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + +Execute (Makers: process_json with invalid JSON): + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + + let maker = copy(g:success_maker) + function! maker.process_json(...) abort dict + endfunction + + CallNeomake 1, [maker] + if has('nvim') + AssertNeomakeMessage "Failed to decode JSON: Vim(return):E474: Unidentified byte: success (output: 'success').", 0 + elseif exists('*json_decode') + AssertNeomakeMessage "Failed to decode JSON: Vim(return):E474: Invalid argument (output: 'success').", 0 + else + AssertNeomakeMessage "Failed to decode JSON: Failed to parse JSON input: invalid input (output: 'success').", 0 + endif + +Execute (Makers: process_json with non-list return value): + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + + let maker = NeomakeTestsCommandMaker('json-maker', 'echo ''{"foo": 1, "bar": 2}''') + function! maker.process_json(...) abort dict + endfunction + + CallNeomake 1, [maker] + + AssertNeomakeMessage "Calling maker's process_json method with 2 JSON entries.", 3 + AssertNeomakeMessage 'The process_json method for maker json-maker did not return a list, but: 0.', 0 + + function! maker.process_json(...) abort dict + return [0] + endfunction + CallNeomake 1, [maker] + AssertNeomakeMessage 'The process_json method for maker json-maker did not return a list of dicts, but: [0].', 0 + + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_jobfinished), 2 + AssertEqual len(g:neomake_test_finished), 2 + +Execute (Makers: get_list_entries with sandbox exception): + call neomake#statusline#ResetCounts() + call g:NeomakeSetupAutocmdWrappers() + + let maker = {} + let maker.should_throw = 1 + function! maker.get_list_entries(...) abort dict + if self.should_throw + " causes E48 + sandbox bprevious + endif + return [1] + endfunction + + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + AssertNeomakeMessage '\mError during pcall: Vim(bprevious):E48: Not allowed in sandbox:' + AssertNeomakeMessage '\m^(in function .*)$', 3 + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_jobfinished), 0 + AssertEqual len(g:neomake_test_finished), 0 + + let jobinfo.maker.should_throw = 0 + if has('timers') + AssertNeomakeMessage '\V\^Retrying Timer event in 10ms', 3 + else + AssertNeomakeMessage 'Retrying Timer event on CursorHold(I).' + doautocmd CursorHold + endif + NeomakeTestsWaitForMessage 'The get_list_entries method for maker unnamed_maker did not return a list of dicts, but: [1].', 0 + + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + +Execute (pcall aborts after 3 attempts per job): + new + call g:NeomakeSetupAutocmdWrappers() + + let maker = {'name': 'maker1'} + function! maker.get_list_entries(...) abort dict + " causes E48 + sandbox bprevious + endfunction + + let maker2 = {'_tries': 0, 'name': 'maker2'} + function! maker2.get_list_entries(...) abort dict + let self._tries += 1 + if self._tries <= 3 + " causes E48 + sandbox bprevious + endif + return [{'bufnr': bufnr('%'), 'text': 'error', 'lnum': 1, 'type': 'E'}] + endfunction + + call NeomakeTestsSetVimMessagesMarker() + let jobs = neomake#Make({'enabled_makers': [maker, maker2]}) + + " Calls both makers initially. + AssertNeomakeMessage 'maker1: getting entries via get_list_entries.' + AssertNeomakeMessage '\mError during pcall: Vim(bprevious):E48: Not allowed in sandbox:', 3, jobs[0] + AssertNeomakeMessage '\m^(in function .*)$', 3 + if has('timers') + AssertNeomakeMessage '\V\^Retrying Timer event in 10ms', 3, jobs[0] + else + AssertNeomakeMessage 'Retrying Timer event on CursorHold(I).', 3, jobs[0] + endif + AssertNeomakeMessage '\mError during pcall: Vim(bprevious):E48: Not allowed in sandbox:', 3, jobs[1] + if has('timers') + AssertNeomakeMessage '\V\^Retrying Timer event in 10ms', 3, jobs[1] + else + AssertNeomakeMessage 'Retrying Timer event on CursorHold(I).', 3, jobs[1] + doautocmd CursorHold + endif + + " Then the first maker is called only. + NeomakeTestsWaitForMessage '\mError during pcall: Vim(bprevious):E48: Not allowed in sandbox:', 3, jobs[0] + if has('timers') + NeomakeTestsWaitForMessage '\V\^Retrying Timer event in 20ms', 3, jobs[0] + else + AssertNeomakeMessage 'Retrying Timer event on CursorHold(I).' + doautocmd CursorHoldI + endif + AssertNeomakeMessage 'action queue: skipping handle_get_list_entries for not processed make_id.', 3, jobs[1] + + " Then the second one first (skipped, not re-queued). + NeomakeTestsWaitForMessage '\mError during pcall: Vim(bprevious):E48: Not allowed in sandbox:', 3, jobs[1] + if has('timers') +" NeomakeTestsWaitForMessage '\V\^Retrying Timer event in 30ms', 3, jobs[0] + NeomakeTestsWaitForMessage 'action queue: skipping handle_get_list_entries for not processed make_id.', 3, jobs[0] + else + AssertNeomakeMessage 'Retrying Timer event on CursorHold(I).' + doautocmd CursorHold + doautocmd CursorHold + doautocmd CursorHold + endif + + NeomakeTestsWaitForMessage 'Giving up handling Timer callbacks after 3 attempts. Please report this. See :messages for more information.', 0, jobs[0] + AssertNeomakeMessage '\m^(in function .*neomake#action_queue#add,.*)$', 3 + + " Now maker2 gets processed (after giving up on maker1). + if has('timers') + NeomakeTestsWaitForMessage 'Processing 1 entries.', 3, jobs[1] + else + AssertNeomakeMessage 'Processing 1 entries.', 3, jobs[1] + endif + + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(copy(g:neomake_test_jobfinished), 'v:val.jobinfo.maker.name'), ['maker2'] + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual map(getloclist(0), 'v:val.text'), ['error'] + + let vim_msgs = NeomakeTestsGetVimMessages() + Assert vim_msgs[-1] =~# '\vNeomake error in: function .*neomake#action_queue#add, line \d+' + AssertEqual len(vim_msgs), 1 + bwipe + +Execute (Makers: get_list_entries via config): + call g:NeomakeSetupAutocmdWrappers() + let maker = {'name': 'mymaker', 'exe': 'doesnotexist'} + + Save g:neomake_test_entries + let g:neomake_test_entries = [{ + \ 'filename': 'unloaded_filename_without_bufnr', + \ 'lnum': 23, + \ 'pattern': '', + \ 'col': 42, + \ 'vcol': 0, + \ 'nr': 4711, + \ 'text': 'error message', + \ 'type': 'E', + \ }] + + function! NeomakeTestGetEntries(...) abort dict + let a = a:000 + Assert !has_key(self, 'errorformat'), 'errorformat is not required' + return deepcopy(g:neomake_test_entries) + endfunction + + new + let bufnr = bufnr('%') + set filetype=neomake_tests + let b:neomake_neomake_tests_enabled_makers = [maker] + let b:neomake_neomake_tests_mymaker_get_list_entries = function('NeomakeTestGetEntries') + RunNeomake + + " valid=1 gets added + let expected = map(copy(g:neomake_test_entries), "extend(v:val, {'valid': 1})") + " filename is removed + let expected = map(expected, "filter(v:val, 'v:key != \"filename\"')") + " Unlisted buffer gets added for filename. + let unlisted_bufnr = bufnr('unloaded_filename_without_bufnr') + Assert !empty(unlisted_bufnr), 'unlisted_bufnr is not empty' + let expected[0].bufnr = unlisted_bufnr + + AssertEqualQf getloclist(0), expected + + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + bwipe + bwipe unloaded_filename_without_bufnr + delfunction NeomakeTestGetEntries + +Execute (neomake#Make can be called with dict): + call neomake#Make({}) + AssertNeomakeMessage 'Nothing to make: no enabled file mode makers (filetype=).', 1 + +Execute (neomake#Make uses current filetype by default): + new + set ft=neomake_tests + let b:neomake_neomake_tests_true_append_file = 0 + let s:au_called = [] + augroup neomake_tests + autocmd User NeomakeJobFinished AssertEqual g:neomake_hook_context.jobinfo.ft, 'neomake_tests' + autocmd User NeomakeJobFinished call add(s:au_called, 1) + augroup END + call neomake#Make({'enabled_makers': ['true']}) + NeomakeTestsWaitForFinishedJobs + AssertEqual s:au_called, [1] + bwipe + +Execute (Neomake/Neomake! run ft maker in project mode): + call g:NeomakeSetupAutocmdWrappers() + new + edit tests/fixtures/a\ filename\ with\ spaces + set ft=neomake_tests + let fname = bufname('%') + + Neomake echo_args + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Running makers: echo_args.' + AssertEqual map(getloclist(0), 'v:val.text'), [fname] + + Neomake! echo_args + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Running makers: echo_args.' + AssertEqual map(getqflist(), 'v:val.text'), [''] + + call neomake#config#set('b:append_file', 1) + CallNeomake 0, ['echo_args'] + AssertNeomakeMessage 'Running makers: echo_args.' + AssertNeomakeMessage "Using setting append_file=1 from 'buffer'.", 3 + AssertEqual map(getqflist(), 'v:val.text'), [fname] + + AssertEqual map(getloclist(0), 'v:val.text'), [fname] + + AssertEqual map(copy(g:neomake_test_jobfinished), 'v:val.jobinfo.file_mode'), [1, 0, 0] + bwipe + +Execute (Maker can pass opts for jobstart/job_start): + if NeomakeAsyncTestsSetup() + if !has('nvim') && !(has('patch-8.0.0902') && has('patch-8.0.1832')) + NeomakeTestsSkip 'Requires patch 8.0.0902/8.0.1832 for Vim.' + else + let maker = {'exe': 'sh', 'args': ['-c', 'echo $TERM']} + if has('nvim') + let maker.nvim_job_opts = { + \ 'pty': 1, + \ 'TERM': 'custom-term', + \ } + else + let maker.vim_job_opts = { + \ 'pty': 1, + \ 'env': {'TERM': 'custom-term'}, + \ } + endif + + CallNeomake 0, [maker] + AssertEqualQf getqflist(), [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 0, 'vcol': 0, 'nr': -1, + \ 'type': '', 'pattern': '', 'text': 'custom-term'}] + endif + endif + +Execute (Maker can override output handler via opts for jobstart/job_start): + if NeomakeAsyncTestsSetup() + let s:output = [] + function s:on_stdout(job_or_channel, output, ...) + let lines = has('nvim') ? a:output[:-2] : split(a:output, '\n') + let s:output += lines + endfunction + + let maker = {'exe': 'printf', 'args': ['%s\n', 'line1', 'line2']} + + if has('nvim') + let maker.nvim_job_opts = { + \ 'on_stdout': function('s:on_stdout'), + \ } + else + let maker.vim_job_opts = { + \ 'out_cb': function('s:on_stdout'), + \ } + endif + + CallNeomake 0, [maker] + AssertEqual getqflist(), [] + AssertEqual s:output, ['line1', 'line2'] + endif + +Execute (Job can be skipped via InitForJob): + call g:NeomakeSetupAutocmdWrappers() + new + let maker = {} + function! maker.InitForJob(...) abort + throw 'Neomake: skip_job: some reason' + endfunction + CallNeomake 1, [maker] + AssertEqual len(g:neomake_test_finished), 0 + AssertEqual len(g:neomake_test_jobfinished), 0 + AssertNeomakeMessage 'unnamed_maker: skipping job: some reason.', 3 + + " Next job gets executed after skipping through InitForJob. + let maker2 = {} + CallNeomake 1, [maker, g:entry_maker] + + AssertNeomakeMessage 'unnamed_maker: skipping job: some reason.', 3 + AssertNeomakeMessage 'entry_maker: getting entries via get_list_entries.', 2 + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + bwipe! + +Execute (Makers: compare list entry defaults): + " setloclist: => nr=0 + new + call setloclist(0, [{}]) + let list1 = getloclist(0) + AssertEqualQf list1, [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'pattern': '', 'valid': 0, + \ 'vcol': 0, 'nr': 0, 'type': '', 'text': ''}] + bwipe + + " lgetexpr: => nr=-1 (needs text implicitly) + new + let &l:efm = '%m' + lgetexpr 'hastext' + let list2 = getloclist(0) + AssertEqualQf list2, [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'pattern': '', 'valid': 0, + \ 'vcol': 0, 'nr': -1, 'type': '', 'text': 'hastext'}] + bwipe + + " get_list_entries, without text: => nr=0, type=W (default) + new + let maker = {} + function! maker.get_list_entries(...) + return [{}] + endfunction + CallNeomake 1, [maker] + let list3 = getloclist(0) + " AssertEqualQf list3, list1 + AssertEqualQf list3, [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'pattern': '', 'valid': 0, + \ 'vcol': 0, 'nr': 0, 'type': 'W', 'text': ''}] + bwipe + + " get_list_entries, with text: => nr=-1, type=W (default) + new + let maker = {} + function! maker.get_list_entries(...) + return [{'text': 'hastext'}] + endfunction + CallNeomake 1, [maker] + let list4 = getloclist(0) + " AssertEqualQf list4, list2 + AssertEqualQf list4, [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'pattern': '', 'valid': 0, + \ 'vcol': 0, 'nr': -1, 'type': 'W', 'text': 'hastext'}] + bwipe + + " cmd maker, without text: => nr=-1 + " This is not consistent - due to appending?! + new + let cmd_maker = NeomakeTestsGetMakerWithOutput({}, ['']) + CallNeomake 1, [cmd_maker] + let list5 = getloclist(0) + AssertEqualQf list5, [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'pattern': '', 'valid': 0, + \ 'vcol': 0, 'nr': -1, 'type': '', 'text': ''}] + bwipe + + " cmd maker, with text: => nr=-1 + new + let cmd_maker = NeomakeTestsGetMakerWithOutput({}, ['hastext']) + CallNeomake 1, [cmd_maker] + let list6 = getloclist(0) + AssertEqualQf list6, list2 + bwipe + +Execute (neomake#core#instantiate_maker: does not use copy for self): + let maker = { + \ 'args': [], + \ 'init_call_count': 0, + \ } + function! maker.InitForJob(...) abort + let self.init_call_count += 1 + let self.args += ['arg_for_job'] + endfunction + + let bound_maker = neomake#core#instantiate_maker(maker, {}, 0) + AssertEqual bound_maker.args, ['arg_for_job'] + let bound_maker = neomake#core#instantiate_maker(maker, {}, 0) + AssertEqual bound_maker.args, ['arg_for_job', 'arg_for_job'] + AssertEqual maker.init_call_count, 2 + AssertEqual bound_maker.init_call_count, 2 + + " deepcopy in InitForJob. + let maker = { + \ 'args': [], + \ 'init_call_count': 0, + \ } + function! maker.InitForJob(...) abort + let self.init_call_count += 1 + let maker = deepcopy(self) + let maker.args += ['arg_for_job'] + return maker + endfunction + let bound_maker = neomake#core#instantiate_maker(maker, {}, 0) + AssertEqual bound_maker.args, ['arg_for_job'] + let bound_maker = neomake#core#instantiate_maker(maker, {}, 0) + AssertEqual bound_maker.args, ['arg_for_job'] + AssertEqual maker.init_call_count, 2 + AssertEqual bound_maker.init_call_count, 2 + + " copy in InitForJob (mutates args). + let maker = { + \ 'args': [], + \ 'init_call_count': 0, + \ } + function! maker.InitForJob(...) abort + let self.init_call_count += 1 + let maker = copy(self) + let maker.args += ['arg_for_job'] + return maker + endfunction + let bound_maker = neomake#core#instantiate_maker(maker, {}, 0) + AssertEqual bound_maker.args, ['arg_for_job'] + let bound_maker = neomake#core#instantiate_maker(maker, {}, 0) + AssertEqual bound_maker.args, ['arg_for_job', 'arg_for_job'] + AssertEqual maker.init_call_count, 2 + AssertEqual bound_maker.init_call_count, 2 + + " copy in InitForJob (copied args). + let maker = { + \ 'args': [], + \ 'init_call_count': 0, + \ } + function! maker.InitForJob(...) abort + let self.init_call_count += 1 + let maker = copy(self) + let maker.args = maker.args + ['arg_for_job'] + return maker + endfunction + let bound_maker = neomake#core#instantiate_maker(maker, {}, 0) + AssertEqual bound_maker.args, ['arg_for_job'] + let bound_maker = neomake#core#instantiate_maker(maker, {}, 0) + AssertEqual bound_maker.args, ['arg_for_job'] + AssertEqual maker.init_call_count, 2 + AssertEqual bound_maker.init_call_count, 2 diff --git a/bundle/neomake/tests/mapexpr.vader b/bundle/neomake/tests/mapexpr.vader new file mode 100644 index 000000000..75bc0d553 --- /dev/null +++ b/bundle/neomake/tests/mapexpr.vader @@ -0,0 +1,48 @@ +Include: include/setup.vader + +Execute (mapexpr: output source in mapexpr): + let maker = neomake#utils#MakerFromCommand('echo on_stdout; echo on_stderr>&2') + let maker.mapexpr = "printf('[%s] %s', neomake_output_source, v:val)" + let maker.output_stream = 'both' + call neomake#Make(0, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqual sort(map(getqflist(), 'v:val.text')), sort( + \ ['[stderr] on_stderr', '[stdout] on_stdout']) + NeomakeTestsWaitForFinishedJobs + +Execute (mapexpr: file mode vars): + let maker = neomake#utils#MakerFromCommand('echo on_stdout') + new + edit tests/fixtures/errors.sh + let bufname = expand('%:p') + let bufdir = fnamemodify(bufname, ':h') + let maker.mapexpr = "printf('%s (%s): %s', neomake_bufname, neomake_bufdir, v:val)" + CallNeomake 0, [maker] + + AssertEqual map(getqflist(), 'v:val.text'), [ + \ printf('%s (%s): on_stdout', bufname, bufdir)] + bwipe + +Execute (mapexpr: file mode vars with cd): + if NeomakeAsyncTestsSetup() + let maker = neomake#utils#MakerFromCommand('sleep 0.01; echo on_stdout') + new + edit tests/fixtures/errors.sh + let maker.mapexpr = "printf('[bufname:%s, bufdir:%s, cwd: %s]: %s', " + \ ."neomake_bufname, neomake_bufdir, getcwd(), v:val)" + let start_cwd = getcwd() + let maker.append_file = 0 + call neomake#Make(1, [maker]) + lcd build + NeomakeTestsWaitForFinishedJobs + lcd - + + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ printf('[bufname:%s, bufdir:%s, cwd: %s]: %s', + \ start_cwd.'/tests/fixtures/errors.sh', + \ start_cwd.'/tests/fixtures', + \ start_cwd, + \ 'on_stdout')] + bwipe + endif diff --git a/bundle/neomake/tests/postprocess.vader b/bundle/neomake/tests/postprocess.vader new file mode 100644 index 000000000..d8338ab3b --- /dev/null +++ b/bundle/neomake/tests/postprocess.vader @@ -0,0 +1,443 @@ +Include: include/setup.vader + +Execute (neomake#postprocess#generic_length): + new + norm! iimport foo bar + let entry = { + \ 'bufnr': bufnr('%'), + \ 'lnum': 1, + \ 'col': 8, + \ 'text': "Some error about 'foo bar' happened"} + + " Default pattern matches 'foo bar'. + let this = {'postprocess': {}} + let new = deepcopy(entry) + call call('neomake#postprocess#generic_length', [new], this) + AssertEqual new.length, 7 + + " Handles non-existing buffer. + let new = deepcopy(entry) + let new.bufnr = entry.bufnr + 1 + call call('neomake#postprocess#generic_length', [new], this) + AssertEqual has_key(new, 'length'), 0 + + " Skips handling without linenr. + let new = deepcopy(entry) + let new.lnum = 0 + call call('neomake#postprocess#generic_length', [new], this) + AssertEqual has_key(new, 'length'), 0 + + " Skips handling with unmatched col. + let new = deepcopy(entry) + let new.col += 1 + call call('neomake#postprocess#generic_length', [new], this) + AssertEqual has_key(new, 'length'), 0 + + " Custom pattern does not match. + let this = {'pattern': 'NOMATCH'} + let new = deepcopy(entry) + call call('neomake#postprocess#generic_length', [new], this) + AssertEqual has_key(new, 'length'), 0 + AssertEqual entry, new + + " Custom pattern does match. + let this = {'pattern': 'foo'} + let new = deepcopy(entry) + call call('neomake#postprocess#generic_length', [new], this) + AssertEqual new.length, 3 + + " Handles entry for another buffer. + new + let this = {'postprocess': {}} + let new = deepcopy(entry) + call call('neomake#postprocess#generic_length', [new], this) + AssertEqual new.length, 7 + bwipe! + bwipe! + +Execute (Postprocess: called with dict+maker as self for list): + new + file file1.vim + norm! ifoo = bar - 5 + + let g:neomake_test_called = [] + function! NeomakeTestPostprocess(entry) abort dict + call add(g:neomake_test_called, [self, g:neomake_postprocess_context]) + endfunction + + let maker = { + \ 'exe': 'printf', + \ 'args': ['file1.vim:1:7: check: bar!'], + \ 'errorformat': '%E%f:%l:%c: %m', + \ 'append_file': 0, + \ '_maker_marker': 1, + \ 'postprocess': [{ + \ 'fn': function('neomake#postprocess#generic_length'), + \ 'pattern': '\vcheck: \zs\k+\ze', + \ }, + \ 'NeomakeTestPostprocess', + \ {'fn': 'NeomakeTestPostprocess', 'pattern': 'custom_pattern', + \ 'custom_var': 42}] + \ } + + AssertEqual neomake#highlights#_get(), {'file': {}, 'project': {}} + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 7, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'check: bar!'}] + + " Test that length has been used with the highlight. + let highlights = neomake#highlights#_get() + if has('nvim') + AssertEqual has_key(highlights['file'], bufnr('%')), 1, "highlight for file" + else + AssertEqual highlights.file[bufnr('%')].NeomakeError, [[1, 7, 3]] + endif + + AssertEqual len(g:neomake_test_called), 2 + AssertEqual g:neomake_test_called[0][0]._maker_marker, 1 + AssertEqual g:neomake_test_called[0][1].jobinfo.maker._maker_marker, 1 + AssertEqual g:neomake_test_called[1][0].pattern, 'custom_pattern' + AssertEqual g:neomake_test_called[1][0].custom_var, 42 + AssertEqual g:neomake_test_called[1][1].jobinfo.maker._maker_marker, 1 + bwipe! + delfunction NeomakeTestPostprocess + +Execute (Postprocess: called with dict+maker as self for non-list): + Save g:neomake_test_called + let g:neomake_test_called = [] + + let maker = { + \ 'exe': 'printf', + \ 'args': ['file1.vim:1:7: check: bar!'], + \ 'errorformat': '%E%f:%l:%c: %m', + \ 'append_file': 0, + \ '_maker_marker': 1, + \ } + function! maker.postprocess(entry) abort dict + call add(g:neomake_test_called, [self, g:neomake_postprocess_context]) + endfunction + + new + file file1.vim + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 7, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'check: bar!'}] + AssertEqual len(g:neomake_test_called), 1 + AssertEqual g:neomake_test_called[0][1].jobinfo.maker._maker_marker, 1 + bwipe + +Execute (Postprocess: removes entries with valid -1): + Save g:neomake_test_called + let g:neomake_test_called = [] + + let maker = { + \ 'exe': 'printf', + \ 'args': [join([ + \ 'file1.vim:1:7: check: bar!', + \ 'file1.vim:2:5: check: foo!', + \ 'file1.vim:1:7: check: bar!'], '\n')], + \ 'errorformat': '%E%f:%l:%c: %m', + \ 'append_file': 0, + \ '_maker_marker': 1, + \ } + function! maker.postprocess(entry) abort dict + call add(g:neomake_test_called, [self, g:neomake_postprocess_context]) + if a:entry.text ==# 'check: bar!' + let a:entry.valid = -1 + endif + endfunction + + new + file file1.vim + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqual len(g:neomake_test_called), 3 + AssertEqual g:neomake_test_called[0][1].jobinfo.maker._maker_marker, 1 + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, + \ 'bufnr': bufnr('%'), + \ 'col': 5, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'check: foo!'}] + bwipe + +Execute (Postprocess: can be disabled with empty string): + let maker = { + \ 'exe': 'printf', + \ 'args': ['success'], + \ 'errorformat': '%E%m', + \ 'append_file': 0, + \ 'postprocess': '', + \ } + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqual map(getloclist(0), 'v:val.text'), ['success'] + +Execute (Postprocess: can be disabled with empty list): + let maker = { + \ 'exe': 'printf', + \ 'args': ['success'], + \ 'errorformat': '%E%m', + \ 'append_file': 0, + \ 'postprocess': [], + \ } + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqual map(getloclist(0), 'v:val.text'), ['success'] + +Execute (maker.postprocess interface for obj): + let postprocessobj = {'property': 1} + + Save g:neomake_test_called + let g:neomake_test_called = [] + function! postprocessobj.fn(entry) abort + AssertEqual self.property, 1 + AssertEqual sort(keys(self)), ['fn', 'property'] + let self.called = 1 + AssertEqual ['jobinfo'], keys(g:neomake_postprocess_context) + endfunction + + let maker = neomake#makers#ft#neomake_tests#echo_maker() + let maker = neomake#GetMaker(maker) + let maker.postprocess = postprocessobj + call neomake#Make(0, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual 1, postprocessobj.called, 'Property could be set' + Assert 1, g:neomake_test_called + +Execute (maker.postprocess interface for maker): + call g:NeomakeSetupAutocmdWrappers() + Save g:neomake_test_called + let g:neomake_test_called = [] + let maker = neomake#makers#ft#neomake_tests#echo_maker() + function! maker.postprocess(entry) abort + try + let self.called = 1 + catch + call add(g:neomake_test_called, v:exception) + endtry + AssertEqual g:neomake_postprocess_context.jobinfo.maker, self + endfunction + + call neomake#Make(0, [maker]) + NeomakeTestsWaitForFinishedJobs + Assert !has_key(maker, 'called'), 'Property not set, since maker was copied' + AssertEqual ['Vim(let):E741: Value is locked: self.called = 1'], g:neomake_test_called + AssertEqual len(g:neomake_test_finished), 1 + +Execute (neomake#postprocess#generic_length for multiple matches): + if !exists('*matchstrpos') + NeomakeTestsSkip 'only supported with matchstrpos' + else + new + norm! i... + let entry = {'text': "'...' is bad, use '…'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], {}) + AssertEqual entry.length, 3 + + let entry = {'text': "'…' is better than '...'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], {}) + AssertEqual entry.length, 3 + + let entry = {'text': "'…''...'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], {}) + AssertEqual entry.length, 3 + + " Now reversed. + " Note that is uses bytes, so the length for '…' is also 3 here. + norm! cc… + let entry = {'text': "'...' is bad, use '…'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], {}) + AssertEqual entry.length, 3 + + let entry = {'text': "'…' is better than '...'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], {}) + AssertEqual entry.length, 3 + + let entry = {'text': "'…''...'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], {}) + AssertEqual entry.length, 3 + + let entry = {'text': "'...''…'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], {}) + AssertEqual entry.length, 3 + + let entry = {'text': "STARTfooENDSTART…END", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], { + \ 'pattern': "\\v(START)\\zs.{-}\\ze(END)" + \ }) + AssertEqual entry.length, 3 + + " Should use the best/longest match. + norm! ccchairman + let entry = {'text': "sexism.misc Gender bias. Use 'chair' instead of 'chairman'.", + \ 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')} + call call('neomake#postprocess#generic_length', [entry], {}) + AssertEqual entry.length, len('chairman') + bwipe! + endif + +Execute (Postprocess: can be lambda): + if !has('lambda') + NeomakeTestsSkip 'no lambda feature' + else + let maker = { + \ 'exe': 'printf', + \ 'args': ['file1.vim:1:7: check: bar!\nfile1.vim:2:5: check: foo!'], + \ 'errorformat': '%E%f:%l:%c: %m', + \ 'append_file': 0, + \ 'postprocess': {entry -> entry.text ==# 'check: bar!' ? extend(entry, {'valid': -1}) : entry} + \ } + + new + file file1.vim + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 2, + \ 'bufnr': bufnr('%'), + \ 'col': 5, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'E', + \ 'pattern': '', + \ 'text': 'check: foo!'}] + bwipe + endif + +Execute (Postprocess: lambda from maker): + if !has('lambda') + NeomakeTestsSkip 'no lambda feature' + else + let maker = { + \ 'exe': 'printf', + \ 'args': ['%s\n', + \ 'WARNING: file.adoc: line 162: illegal system attribute name: font-style', + \ 'WARNING: file.adoc: line 1: something else'], + \ 'errorformat': '%tARNING: %f: line %l: %m', + \ 'append_file': 0, + \ } + let maker.postprocess = { + \ entry -> entry.text =~# 'illegal system attribute name: font-style' + \ ? extend(entry, {'valid': -1}) : entry} + + new + file file.adoc + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, + \ 'bufnr': bufnr('%'), + \ 'col': 0, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': 'W', + \ 'pattern': '', + \ 'text': 'something else'}] + bwipe + endif + +Execute (Postprocess: lambda from conf): + if !has('lambda') + NeomakeTestsSkip 'no lambda feature' + else + let maker = { + \ 'name': 'mymaker', + \ 'exe': 'printf', + \ 'args': ['%s\n', + \ 'WARNING: file.adoc: line 162: illegal system attribute name: font-style', + \ 'WARNING: file.adoc: line 1: something else'], + \ 'errorformat': '%tARNING: %f: line %l: %m', + \ 'append_file': 0, + \ } + new + file file.adoc + set ft=myft + let b:neomake_myft_mymaker_postprocess = { + \ entry -> entry.text =~# 'illegal system attribute name: font-style' + \ ? extend(entry, {'valid': -1}) : entry} + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), ['something else'] + bwipe + endif + +Execute (Hook context gets cleaned on error in postprocess): + call NeomakeTestsSetVimMessagesMarker() + let maker = copy(g:error_maker) + function! maker.postprocess(entry) + throw 'error from postprocess' + endfunction + call neomake#Make({'enabled_makers': [maker]}) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Error during output processing for error-maker: error from postprocess.', 0 + let vim_msgs = NeomakeTestsGetVimMessages() + Assert vim_msgs[-1] =~# 'Neomake error in: function .*', 'message found' + AssertEqual len(vim_msgs), 1 + Assert !exists('g:neomake_postprocess_context'), 'Hook context was cleaned.' + +Execute (neomake#postprocess#compress_whitespace): + function! s:F(text) + let entry = {'text': a:text} + call neomake#postprocess#compress_whitespace(entry) + return entry.text + endfunction + AssertEqual s:F('foo'), 'foo' + AssertEqual s:F(' foo'), 'foo' + AssertEqual s:F('foo '), 'foo' + AssertEqual s:F('foo bar '), 'foo bar' + AssertEqual s:F("foo\nbar "), 'foo bar' + AssertEqual s:F("foo\r\nbar "), 'foo bar' + AssertEqual s:F("foo\n bar "), 'foo bar' + AssertEqual s:F("foo\n bar \r\n"), 'foo bar' + +Execute (neomake#postprocess#remove_duplicates): + let maker = {'postprocess': copy(g:neomake#postprocess#remove_duplicates)} + + let entries = [ + \ {'bufnr': 1, 'lnum': 1, 'text': 'one'}, + \ {'bufnr': 1, 'lnum': 2, 'text': 'two'}, + \ {'bufnr': 1, 'lnum': 1, 'text': 'one'}, + \ ] + + call maker.postprocess.fn(entries[0]) + AssertEqual maker.postprocess._seen_entries, [entries[0]] + call maker.postprocess.fn(entries[1]) + AssertEqual maker.postprocess._seen_entries, entries[0:1] + call maker.postprocess.fn(entries[2]) + AssertEqual maker.postprocess._seen_entries, entries[0:1] + + AssertEqual entries[2].valid, -1 diff --git a/bundle/neomake/tests/processing.vader b/bundle/neomake/tests/processing.vader new file mode 100644 index 000000000..725cdb775 --- /dev/null +++ b/bundle/neomake/tests/processing.vader @@ -0,0 +1,1145 @@ +Include: include/setup.vader + +" TODO: not really necessary (likely), but provides better/easier test results. +Execute (get_list_entries: basic end-to-end test): + let s:counter = 0 + let maker = {} + function! maker.get_list_entries(...) abort dict + let s:counter += 1 + return [{ + \ 'lnum': 23, + \ 'col': 42, + \ 'text': printf('error_msg_%d', s:counter), + \ 'type': 'E', + \ }] + endfunction + + CallNeomake 1, [maker] + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), 'v:val.text'), ['error_msg_2'] + lolder + AssertEqual map(getloclist(0), 'v:val.text'), ['error_msg_1'] + +Execute (Output is only processed in normal/insert mode (loclist)): + if NeomakeAsyncTestsSetup() + new + lgetexpr 'init' + file file_sleep_efm + call neomake#Make(1, [g:sleep_efm_maker]) + norm! V + NeomakeTestsWaitForFinishedJobs + AssertEqual map(copy(getloclist(0)), 'v:val.text'), ['init'], 'Location list has not been updated' + " with Vim + " AssertNeomakeMessage 'exit (delayed): sleep_efm_maker: 0' + AssertNeomakeMessage 'Not processing output for mode "V".' + AssertNeomakeMessage 'sleep_efm_maker: completed with exit code 0.' + AssertEqual mode(), 'V' + exe "norm! \" + AssertEqual mode(), 'n' + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_finished), 0 + Assert exists('#neomake_event_queue#CursorHold'), 'neomake_event_queue augroup exists' + doautocmd CursorHold + sleep 100m + Assert !exists('#neomake_event_queue#CursorHold'), 'neomake_event_queue is empty' + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Processing 3 lines of output.' + AssertEqual map(getloclist(0), 'v:val.text'), ['error message', 'warning', 'error2'] + bwipe + endif + +Execute (Output is only processed in normal/insert mode (qflist)): + if NeomakeAsyncTestsSetup() + new + file file_sleep_efm + call neomake#Make(0, [g:sleep_efm_maker])[0] + let jobinfo = neomake#GetJobs()[-1] + norm! V + NeomakeTestsWaitForFinishedJobs + AssertEqual getqflist(), [], 'Quickfix list has not been updated' + AssertNeomakeMessage 'sleep_efm_maker: completed with exit code 0.' + AssertEqual mode(), 'V' + exe "norm! \" + AssertEqual mode(), 'n' + doautocmd CursorHold + AssertNeomakeMessage 'Processing 3 lines of output.' + AssertNeomakeMessage 'Processed 1 pending outputs.', 3, jobinfo + AssertEqual map(getqflist(), 'v:val.text'), ['error message', 'warning', 'error2'] + NeomakeTestsWaitForRemovedJobs + call neomake#signs#ResetProject() + call neomake#signs#CleanAllOldSigns('project') + bwipe + endif + +Execute (Output is not processed with visible popup menu): + if NeomakeAsyncTestsSetup() + new + file file_sleep_efm + normal! iword1 + normal! oword2 + + function! s:close_pum(...) + NeomakeTestsWaitForMessage 'Not processing output during completion.', 3 + call neomake#log#debug('test: closing PUM.') + call feedkeys("\", 'x') + call feedkeys("\") + endfunction + + call neomake#Make(0, [g:sleep_efm_maker])[0] + let jobinfo = neomake#GetJobs()[-1] + + call timer_start(1, 's:close_pum') + call neomake#log#debug('test: opening PUM.') + call feedkeys("oword\", 'x!') + + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'sleep_efm_maker: completed with exit code 0.' + AssertNeomakeMessage 'action queue: processing for CompleteDone (1 items).', 3, {'winnr': 2} + AssertNeomakeMessage 'Processing 3 lines of output.' + AssertNeomakeMessage 'Processed 1 pending outputs.', 3, jobinfo + AssertEqual map(getqflist(), 'v:val.text'), ['error message', 'warning', 'error2'] + bwipe! + endif + +Execute (Location list handling is postponed with visible popup menu): + if NeomakeAsyncTestsSetup() + new + file file_sleep_efm + normal! iword1 + normal! oword2 + + function! s:close_pum(...) + NeomakeTestsWaitForMessage 'Postponing final location list handling during completion.', 3 + AssertNeomakeMessage 'Queuing action handle_locqf_list_for_finished_jobs for CompleteDone.' + call neomake#log#debug('tests: closing popupmenu.') + call feedkeys("\") + endfunction + + let maker = NeomakeTestsCommandMaker('silent-sleep-success', 'sleep .01') + call neomake#Make(1, [maker]) + + call timer_start(100, 's:close_pum') + call feedkeys("oword\", 'x!') + + NeomakeTestsWaitForMessage 'tests: closing popupmenu.', 3 + + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'action queue: processing for CompleteDone (1 items).', 3, {'winnr': 2} + AssertNeomakeMessage 'action queue: processed 1 items.', 3 + AssertEqual getloclist(0), [] + bwipe! + endif + +Execute (Location list is only cleared in normal/insert mode on success): + if NeomakeAsyncTestsSetup() + new + lgetexpr 'init' + let maker = NeomakeTestsCommandMaker('silent-sleep-success', 'sleep .01') + call neomake#Make(1, [maker]) + norm! V + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), ['init'], 'Location list has not been updated' + + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 0 + + AssertNeomakeMessage 'Cleaning jobinfo.', 3 + AssertNeomakeMessage 'File-level errors cleaned.', 3 + AssertNeomakeMessage 'Postponing final location list handling for mode "V".' + AssertNeomakeMessage 'Queuing action handle_locqf_list_for_finished_jobs for CursorHold, WinEnter.' + + AssertEqual mode(), 'V' + exe "norm! \" + AssertEqual mode(), 'n' + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_finished), 0 + doautocmd CursorHold + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Cleaning location list.', 3 + AssertEqual map(getloclist(0), 'v:val.text'), [] + bwipe + endif + +Execute (Location list is not cleared in operator-pending mode (Vim)): + if has('nvim') + NeomakeTestsSkip 'only for Vim' + elseif NeomakeAsyncTestsSetup() + new + lgetexpr 'init' + file file_sleep_efm + let maker = NeomakeTestsCommandMaker('silent-sleep-success', 'sleep .01') + call neomake#Make(1, [maker]) + + " Trigger operator-pending mode ('no'). + let b:cb_called = 0 + function! s:callback_in_operator_pending_mode(...) + let b:cb_called = mode(1) + call feedkeys("\") + endfunction + call timer_start(100, 's:callback_in_operator_pending_mode') + call feedkeys('da', 'x!') + + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), ['init'], 'Location list has not been updated' + + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 0 + + AssertNeomakeMessage 'Cleaning jobinfo.', 3 + AssertNeomakeMessage 'File-level errors cleaned.', 3 + AssertNeomakeMessage 'Postponing final location list handling for mode "no".' + AssertEqual b:cb_called, 'no' + AssertNeomakeMessage 'Queuing action handle_locqf_list_for_finished_jobs for CursorHold, WinEnter.' + + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_finished), 0 + doautocmd CursorHold + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Cleaning location list.', 3 + AssertEqual map(getloclist(0), 'v:val.text'), [] + bwipe + endif + +Execute (Location list is only cleared in same window on success): + if NeomakeAsyncTestsSetup() + new + let win = winnr() + lgetexpr 'init' + file file_sleep_efm + let maker = NeomakeTestsCommandMaker('silent-sleep-success', 'sleep .01') + call neomake#Make(1, [maker]) + new + let win2 = winnr() + lgetexpr 'init2' + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(win), 'v:val.text'), ['init'], 'Location list has not been updated' + AssertEqual map(getloclist(win2), 'v:val.text'), ['init2'], 'Location list has not been updated' + AssertNeomakeMessage 'Cleaning jobinfo.', 3 + AssertNeomakeMessage 'Postponing final location list handling (in another window).' + AssertNeomakeMessage 'Queuing action handle_locqf_list_for_finished_jobs for WinEnter.' + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_finished), 0 + + wincmd p + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Cleaning location list.', 3 + AssertEqual map(getloclist(0), 'v:val.text'), [] + AssertEqual map(getloclist(win2), 'v:val.text'), ['init2'], 'Location list has not been updated' + wincmd p + bwipe + bwipe + endif + +Execute (Output is only processed in normal/insert mode (from loclist)): + if NeomakeAsyncTestsSetup() + new + file file_sleep_efm + call neomake#Make(1, [g:sleep_efm_maker]) + lopen + AssertEqual &buftype, 'quickfix' + AssertEqual winnr(), 3 + AssertEqual line('$'), 1 + norm! V + NeomakeTestsWaitForFinishedJobs + AssertEqual getloclist(0), [], 'Location list has not been updated' + AssertNeomakeMessage 'sleep_efm_maker: completed with exit code 0.' + AssertEqual mode(), 'V' + exe "norm! \" + AssertEqual mode(), 'n' + doautocmd CursorHold + AssertEqual getloclist(0), [] + AssertNeomakeMessage 'action queue: processing for CursorHold (1 items).', 3 + AssertNeomakeMessage 'action queue: calling process_pending_output.', 3 + AssertNeomakeMessage 'Skipped pending job output for another buffer (current='.bufnr('%').').', 3 + + wincmd p + AssertNeomakeMessage 'Processing 3 lines of output.' + AssertEqual map(getloclist(0), 'v:val.text'), ['error message', 'warning', 'error2'] + AssertNeomakeMessage 'Processed 1 pending outputs.', 3 + + let ll_bufnr = bufnr('file_sleep_efm') + AssertEqual map(getloclist(0), 'v:val.bufnr'), [ll_bufnr, ll_bufnr, ll_bufnr] + lclose + bwipe + endif + +Execute (Output gets not processed while in loclist): + if NeomakeAsyncTestsSetup() + new + file file_sleep_efm + call neomake#Make(1, [g:sleep_efm_maker]) + lopen + AssertEqual &buftype, 'quickfix' + AssertEqual winnr(), 3 + NeomakeTestsWaitForFinishedJobs + AssertEqual winnr(), 3 + + AssertEqual len(g:neomake_test_finished), 0 + AssertEqual len(g:neomake_test_countschanged), 0 + AssertEqual getloclist(0), [] + + lclose + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_countschanged), 1 + AssertEqual map(getloclist(0), 'v:val.text'), ['error message', 'warning', 'error2'] + bwipe + endif + +Execute (Unbuffered output handled correctly (loclist)): + if NeomakeAsyncTestsSetup() + " Produce intersected output: 1_1, 2_1, 1_2, 2_2, … + let s:tmpfile1 = tempname() + let s:tmpfile2 = tempname() + call writefile([], s:tmpfile2) + let maker_1 = extend(neomake#utils#MakerFromCommand( + \ 'for i in $(seq 1 3); do while [ -e '.s:tmpfile1.' ]; do sleep 0.1; done; echo 1_$i; touch '.s:tmpfile1.'; done'), { + \ 'name': 'maker1', 'buffer_output': 0, 'errorformat': '%m', 'append_file': 0}) + let maker_2 = extend(neomake#utils#MakerFromCommand( + \ 'for i in $(seq 1 3); do while [ -e '.s:tmpfile2.' ]; do sleep 0.1; done; echo 2_$i; touch '.s:tmpfile2.'; done'), { + \ 'name': 'maker2', 'buffer_output': 0, 'errorformat': '%m', 'append_file': 0}) + + function! s:process_output(context) + if a:context.jobinfo.maker.name ==# 'maker1' + call delete(s:tmpfile2) + else + call delete(s:tmpfile1) + endif + return [{'text': join(a:context.output), 'lnum': 1}] + endfunction + let maker_1.process_output = function('s:process_output') + let maker_2.process_output = function('s:process_output') + + + let [jobinfo1, jobinfo2] = neomake#Make({'enabled_makers': [maker_1, maker_2]}) + Assert jobinfo1.id < jobinfo2.id, "jobinfo1 before jobinfo2" + NeomakeTestsWaitForRemovedJobs + AssertEqual len(g:neomake_test_countschanged), 6 + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['1_1', '2_1', '1_2', '2_2', '1_3', '2_3'] + endif + +Execute (Unbuffered output handled correctly (qflist)): + if NeomakeAsyncTestsSetup() + " Produce intersected output: 1_1, 2_1, 1_2, 2_2, … + let s:tmpfile1 = tempname() + let s:tmpfile2 = tempname() + call writefile([], s:tmpfile2) + let maker_1 = extend(neomake#utils#MakerFromCommand( + \ 'for i in $(seq 1 3); do while [ -e '.s:tmpfile1.' ]; do sleep 0.1; done; echo 1_$i; touch '.s:tmpfile1.'; done'), { + \ 'name': 'maker1', 'buffer_output': 0, 'errorformat': '%m', 'append_file': 0}) + let maker_2 = extend(neomake#utils#MakerFromCommand( + \ 'for i in $(seq 1 3); do while [ -e '.s:tmpfile2.' ]; do sleep 0.1; done; echo 2_$i; touch '.s:tmpfile2.'; done'), { + \ 'name': 'maker2', 'buffer_output': 0, 'errorformat': '%m', 'append_file': 0}) + + function! s:process_output(context) + if a:context.jobinfo.maker.name ==# 'maker1' + call delete(s:tmpfile2) + else + call delete(s:tmpfile1) + endif + return [{'text': join(a:context.output), 'lnum': 1}] + endfunction + let maker_1.process_output = function('s:process_output') + let maker_2.process_output = function('s:process_output') + + let [jobinfo1, jobinfo2] = neomake#Make({'file_mode': 0, 'enabled_makers': [maker_1, maker_2]}) + Assert jobinfo1.id < jobinfo2.id, "jobinfo1 before jobinfo2" + NeomakeTestsWaitForRemovedJobs + AssertEqual len(g:neomake_test_countschanged), 6 + AssertEqual map(getqflist(), 'v:val.text'), + \ ['1_1', '2_1', '1_2', '2_2', '1_3', '2_3'] + endif + +Execute (Sleep in postprocess gets handled correctly): + " This tests the workarounds for issues with both Vim and Neovim. + " https://github.com/vim/vim/issues/1320 + " https://github.com/neovim/neovim/issues/5889 + " Reproduces flakiness with https://github.com/neomake/neomake/issues/899. + call neomake#statusline#ResetCounts() + if NeomakeAsyncTestsSetup() + let s:postprocess_count = 0 + function! s:postprocess(entry) dict + let s:postprocess_count += 1 + if s:postprocess_count == 1 + exe 'sleep 300m' + endif + endfunction + + let maker = extend(neomake#utils#MakerFromCommand( + \ 'echo out-1; sleep 0.1; echo out-22; sleep 0.1; echo out-333'), { + \ 'buffer_output': 0, 'errorformat': '%m', + \ 'append_file': 0, + \ 'postprocess': function('s:postprocess')}) + + let jobinfo = neomake#Make(1, [maker])[0] + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Processing 1 lines of output.', 3, jobinfo + if !has('nvim-0.2.0') + AssertNeomakeMessage 'exit (delayed): unnamed_maker: 0.', 3, jobinfo + AssertNeomakeMessage '\VCalling User autocmd NeomakeCountsChanged with context:', 3 + endif + + if has('nvim-0.4.0') + " Neovim refactored event processing, so that the job's 2nd sleep finishes + " before the one in the first postprocessing. + " https://github.com/neovim/neovim/commit/d4938743e6aef04c83d02907048768d0d79aaa30 + let expected_final_countchanges = 2 + AssertNeomakeMessage "output on stdout: ['out-22', 'out-333', ''].", 3, jobinfo + AssertNeomakeMessage 'Processing 2 lines of output.', 3, jobinfo + else + let expected_final_countchanges = 3 + AssertNeomakeMessage "output on stdout: ['out-22', ''].", 3, jobinfo + AssertNeomakeMessage 'Processing 1 lines of output.', 3, jobinfo + AssertNeomakeMessage '\VCalling User autocmd NeomakeCountsChanged with context:', 3 + + AssertNeomakeMessage "output on stdout: ['out-333', ''].", 3, jobinfo + AssertNeomakeMessage 'Processing 1 lines of output.', 3, jobinfo + AssertNeomakeMessage '\VCalling User autocmd NeomakeCountsChanged with context:', 3 + endif + + if !has('nvim-0.2.0') + AssertNeomakeMessage 'Trigger delayed exit.', 3, jobinfo + endif + + AssertEqual map(getloclist(0), 'v:val.text'), ['out-1', 'out-22', 'out-333'] + let c = s:postprocess_count + AssertEqual c, 3, 'postprocess count should be 3, but is '.c + AssertEqual len(g:neomake_test_countschanged), expected_final_countchanges + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + endif + +Execute (Pending output with restarted job when not in normal/insert mode (loclist)): + if NeomakeAsyncTestsSetup() + let g:neomake_test_inc_maker_counter = 0 + + new + file b1 + let jobinfo1 = neomake#Make({'enabled_makers': [g:neomake_test_inc_maker]})[0] + let make_id = neomake#GetStatus().last_make_id + norm! V + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Not processing output for mode "V".', 3 + exe "norm! \" + call neomake#Make(1, [g:neomake_test_inc_maker]) + + " Maker is different because of name. + AssertNeomakeMessageAbsent 'Canceling already running job (' + \ .make_id.'.'.jobinfo1.id.') for the same maker.', 2, {'make_id': make_id+1} + AssertNeomakeMessageAbsent 'Removing already finished job', 3, jobinfo1 + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['2:0: buf: b1', '2:1: buf: b1'] + doautocmd CursorHold + + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['1:0: buf: b1'] + + silent lolder + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['2:0: buf: b1', '2:1: buf: b1'] + AssertEqual len(g:neomake_test_finished), 2 + AssertEqual len(g:neomake_test_jobfinished), 2 + bwipe + bwipe b2 + endif + +Execute (Pending output with restarted job when not in normal/insert mode (quickfix)): + if NeomakeAsyncTestsSetup() + let g:neomake_test_inc_maker_counter = 0 + + new + file b1 + let jobinfo1 = neomake#Make({'file_mode': 0, 'enabled_makers': [g:neomake_test_inc_maker]})[0] + let make_id = neomake#GetStatus().last_make_id + norm! V + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Not processing output for mode "V".', 3 + exe "norm! \" + call neomake#Make(0, [g:neomake_test_inc_maker]) + + " Maker is different because of name. + AssertNeomakeMessageAbsent 'Canceling already running job (' + \ .make_id.'.'.jobinfo1.id.') for the same maker.', 2, {'make_id': make_id+1} + AssertNeomakeMessageAbsent 'Removing already finished job', 3, jobinfo1 + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + + AssertEqual map(getqflist(), 'v:val.text'), + \ ['2:0: buf: b1', '2:1: buf: b1'] + doautocmd CursorHold + + AssertEqual map(getqflist(), 'v:val.text'), + \ ['1:0: buf: b1'] + + silent colder + AssertEqual map(getqflist(), 'v:val.text'), + \ ['2:0: buf: b1', '2:1: buf: b1'] + + AssertEqual len(g:neomake_test_finished), 2 + AssertEqual len(g:neomake_test_jobfinished), 2 + bwipe + bwipe b2 + endif + +Execute (Second make finishes before first (qflist)): + let maker1 = NeomakeTestsCommandMaker('maker1', 'sleep .1; echo 1') + let maker2 = NeomakeTestsCommandMaker('maker2', 'echo 2') + call neomake#Make(0, [maker1]) + call neomake#Make(0, [maker2]) + NeomakeTestsWaitForFinishedJobs + + if neomake#has_async_support() + AssertEqual map(getqflist(), 'v:val.text'), ['1'] + silent colder + endif + AssertEqual map(getqflist(), 'v:val.text'), ['2'] + +Execute (Second make finishes before first (loclist)): + let maker1 = NeomakeTestsCommandMaker('maker1', 'sleep .1; echo 1') + let maker2 = NeomakeTestsCommandMaker('maker2', 'echo 2') + call neomake#Make(1, [maker1]) + call neomake#Make(1, [maker2]) + NeomakeTestsWaitForFinishedJobs + + if neomake#has_async_support() + AssertEqual map(getloclist(0), 'v:val.text'), ['1'] + silent lolder + endif + AssertEqual map(getloclist(0), 'v:val.text'), ['2'] + +Execute (Handle finished job that got canceled (#1158)): + call g:NeomakeSetupAutocmdWrappers() + norm! V + call neomake#Make(0, [g:success_maker]) + if neomake#has_async_support() + NeomakeTestsWaitForFinishedJobs + endif + AssertNeomakeMessage 'Not processing output for mode "V".', 3 + let jobs = neomake#Make(0, [g:success_maker]) + AssertNeomakeMessage '\mCanceling already running job (\d\+.\d\+) for the same maker.' + AssertEqual len(g:neomake_test_jobfinished), 0 + call neomake#CancelJob(jobs[0]) + if neomake#has_async_support() + NeomakeTestsWaitForFinishedJobs + endif + +Execute (Job does not get restarted when canceled): + if NeomakeAsyncTestsSetup() + let maker = NeomakeTestsCommandMaker('mymaker', 'echo output; sleep .1; echo output2') + let jobinfo = neomake#Make({'enabled_makers': [maker], 'buffer_output': 0})[0] + NeomakeTestsWaitForMessage "output on stdout: ['output', ''].", 3, jobinfo + call neomake#CancelJob(jobinfo.id) + + let jobinfo2 = neomake#Make({'enabled_makers': [maker], 'buffer_output': 0})[0] + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage "output on stdout: ['output', ''].", 3, jobinfo2 + if has('nvim-0.4.0') + let expected_status = 143 + elseif has('nvim') + let expected_status = 0 + else + let expected_status = -1 + endif + AssertNeomakeMessage 'exit: mymaker: '.expected_status.' (job was canceled).', 3, jobinfo, {'ignore_order': 1} + + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_countschanged), 3 + endif + +Execute (100 lines of output should not get processed one by one): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + " This would be the case when using Vim's 'nl' mode. + call g:NeomakeSetupAutocmdWrappers() + let maker = NeomakeTestsCommandMaker('echo_100', 'i=100; while ((i--)); do echo $i; done') + let maker.buffer_output = 0 + call neomake#Make(0, [maker]) + NeomakeTestsWaitForFinishedJobs + let c = g:neomake_test_countschanged + Assert len(c) < 50, 'There were 50+ count changes: '.len(c) + AssertNeomakeMessage '\v^Skipped \d+ entries without bufnr: .*\.' + +Execute (Mixed newlines get handled correctly): + let maker = { + \ 'exe': 'printf', + \ 'args': 'line1\\nline2\\r\\nline3', + \ 'errorformat': '%m', + \ } + call neomake#Make(0, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getqflist(), 'v:val.text'), + \ ['line1', 'line2', 'line3'] + +Execute (Exception in process_output gets logged as error): + if NeomakeAsyncTestsSetup() + let maker = { + \ 'exe': 'printf', + \ 'args': ['foo'], + \ 'append_file': 0} + function! maker.process_output(context) abort + throw "TEST_ERROR" + endfunction + + let jobinfo = neomake#Make(1, [maker])[0] + + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Processing 1 lines of output.', 3, jobinfo + AssertNeomakeMessage 'Error during output processing for unnamed_maker: TEST_ERROR.', 0, jobinfo + endif + +Execute (Already running job gets restarted in case of exception): + if NeomakeAsyncTestsSetup() + Save g:neomake_test_counter + let g:neomake_test_counter = 0 + + let maker = { + \ 'exe': 'printf', + \ 'args': ['foo'], + \ 'append_file': 0} + function! maker.process_output(context) abort + let g:neomake_test_counter += 1 + if g:neomake_test_counter == 1 + throw 'NeomakeTestsException' + endif + return [] + endfunction + + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + let make_id = neomake#GetStatus().last_make_id + + AssertThrows NeomakeTestsWaitForFinishedJobs + AssertEqual g:vader_exception, 'NeomakeTestsException' + AssertNeomakeMessage 'Processing 1 lines of output.' + + AssertEqual len(neomake#GetJobs()), 1, 'The job has not been cleaned because of the exception.' + + " Restart, which should work directly. + let maker.some_new_key = 1 + Assert values(neomake#_get_s().jobs)[0].maker != maker + call neomake#Make(1, [maker]) + + AssertNeomakeMessage printf('Canceling already running job (%d.%d) for the same maker.', + \ make_id, jobinfo.id), 2, {'make_id': make_id+1} + AssertNeomakeMessage 'Job exited already.', 3, jobinfo + AssertNeomakeMessage "Starting async job: printf foo." + + " Needs careful cleanup after exception. + NeomakeTestsWaitForMessage 'Cleaning jobinfo.' + NeomakeCancelJobs! + endif + +Execute (process_output: gets delayed for location list): + let maker = {'exe': 'echo', 'args': 'ignored', 'append_file': 0} + function! maker.process_output(context) + return [{ + \ 'bufnr': bufnr('%'), + \ 'lnum': 23, + \ 'pattern': '', + \ 'col': 42, + \ 'vcol': 0, + \ 'nr': 4711, + \ 'text': 'error message', + \ 'type': 'E', + \ }] + endfunction + + new + let bufnr = bufnr('%') + + call neomake#Make(1, [maker]) + if neomake#has_async_support() + new + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Output left to be processed, not cleaning job yet.' + AssertEqual getloclist(0), [] + bwipe + endif + AssertEqual getloclist(0)[0].bufnr, bufnr + bwipe + +Execute (get_list_entries: delayed for location list (but in current context)): + new + let maker = {} + function! maker.get_list_entries(context) + return [{ + \ 'bufnr': bufnr('%'), + \ 'lnum': 23, + \ 'pattern': '', + \ 'col': 42, + \ 'vcol': 0, + \ 'nr': 4711, + \ 'text': 'error message', + \ 'type': 'E', + \ }] + endfunction + + augroup neomake_tests + au User NeomakeJobFinished call neomake#log#debug('Changing to window 2.') + au User NeomakeJobFinished 2wincmd w + augroup END + + let win2_bufnr = bufnr('%') + new + let b:neomake_serialize = 1 + let bufnr = bufnr('%') + + call neomake#Make(1, [g:sleep_maker, maker]) + NeomakeTestsWaitForMessage 'unnamed_maker: getting entries via get_list_entries.', 2 + AssertNeomakeMessage 'Postponing location list processing.', 3 + AssertEqual getloclist(0), [] + AssertEqual winnr(), 2 + AssertNeomakeMessage "Skipping cleaning of job info because of queued actions: ['ProcessEntries', ['BufEnter', 'WinEnter']].", 3 + let valid = has('patch-8.0.0580') + AssertEqualQf getloclist(3), [{ + \ 'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': valid, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'slept'}] + + 3wincmd w + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, {'winnr': 3} + AssertNeomakeMessage 'Cleaning jobinfo.' + AssertNeomakeMessage '\VCalling User autocmd NeomakeJobFinished with context:', 3 + + AssertEqual winnr(), 2 + AssertEqual map(getloclist(3), '[v:val.bufnr, v:val.text, v:val.type]'), [ + \ [0, 'slept', 'W'], + \ [win2_bufnr, 'error message', 'E']] + 3wincmd w + bwipe + bwipe + +Execute (Pending output gets processed in order of jobs (project first)): + if NeomakeAsyncTestsSetup() + let maker1 = NeomakeTestsCommandMaker('project_maker', 'sleep .1; echo project_maker') + let maker2 = NeomakeTestsCommandMaker('file_maker', 'echo file_maker') + + call neomake#Make(0, [maker1]) + call neomake#Make(1, [maker2]) + norm! V + + NeomakeTestsWaitForFinishedJobs + exe "norm! \" + doautocmd CursorHold + NeomakeTestsWaitForRemovedJobs + AssertNeomakeMessage 'Not processing output for mode "V".' + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist" + AssertNeomakeMessage 'Creating location list for entries.' + AssertNeomakeMessage 'Creating quickfix list for entries.' + else + AssertNeomakeMessage 'Creating location list.' + AssertNeomakeMessage 'Creating quickfix list.' + endif + + AssertEqual map(getloclist(0), 'v:val.text'), ['file_maker'] + AssertEqual map(getqflist(), 'v:val.text'), ['project_maker'] + endif + +Execute (Pending output gets processed in order of jobs (file mode first)): + if NeomakeAsyncTestsSetup() + let maker1 = NeomakeTestsCommandMaker('project_maker', 'sleep .1; echo project_maker') + let maker2 = NeomakeTestsCommandMaker('file_maker', 'echo file_maker') + + call neomake#Make(1, [maker2]) + call neomake#Make(0, [maker1]) + norm! V + + NeomakeTestsWaitForFinishedJobs + exe "norm! \" + doautocmd CursorHold + NeomakeTestsWaitForRemovedJobs + AssertNeomakeMessage 'Not processing output for mode "V".' + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist" + AssertNeomakeMessage 'Creating location list for entries.' + AssertNeomakeMessage 'Creating quickfix list for entries.' + else + AssertNeomakeMessage 'Creating location list.' + AssertNeomakeMessage 'Creating quickfix list.' + endif + + AssertEqual map(getloclist(0), 'v:val.text'), ['file_maker'] + AssertEqual map(getqflist(), 'v:val.text'), ['project_maker'] + endif + +" Execute (): +" if NeomakeAsyncTestsSetup() +" let maker1 = NeomakeTestsCommandMaker('sleep', 'sleep .1') +" let maker2 = NeomakeTestsCommandMaker('true', 'true') +" new +" lgetexpr 'init' +" file file_sleep_efm +" call neomake#Make(1, [maker1, maker2]) +" norm! V +" NeomakeTestsWaitForFinishedJobs +" AssertEqual map(copy(getloclist(0)), 'v:val.text'), ['init'], 'Location list has not been updated' +" " with Vim +" " AssertNeomakeMessage 'exit (delayed): sleep_efm_maker: 0' +" " AssertNeomakeMessage 'sleep_efm_maker: completed with exit code 0.' +" AssertEqual mode(), 'V' +" exe "norm! \" +" AssertEqual mode(), 'n' +" AssertEqual len(g:neomake_test_countschanged), 0 +" AssertEqual len(g:neomake_test_finished), 0 +" doautocmd CursorHold +" AssertEqual len(g:neomake_test_countschanged), 1 +" AssertEqual len(g:neomake_test_finished), 1, "b" +" AssertNeomakeMessage 'Processing 3 lines of output.' +" AssertEqual map(copy(getloclist(0)), 'v:val.text'), ['error message', 'warning', 'error2'] +" bwipe +" endif + +Execute (get_list_entries job processes entries while in tabline function): + if NeomakeAsyncTestsSetup() + Save &tabline + + Save g:entry_maker + let g:entry_maker = {} + function! g:entry_maker.get_list_entries(jobinfo) abort + return get(g:, 'neomake_test_getlistentries', [ + \ {'bufnr': bufnr('%'), 'text': 'error', 'lnum': 1, 'type': 'E'}]) + endfunction + + function! s:NeomakeTestTabline() + sleep 500m + endfunction + + new + set tabline=%!s:NeomakeTestTabline() + + Save g:neomake_test_jobinfo + function! s:NeomakeTestF(...) abort + call neomake#Make(1, [g:entry_maker]) +" let g:neomake_test_jobinfo = neomake#GetJob(neomake#Make(1, [g:entry_maker])[0]) + endfunction + + call timer_start(100, function('s:NeomakeTestF')) + redraw + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + bwipe + endif + +Execute (action queue handles E48 in process_output): + let maker = {'exe': 'echo', 'args': 'output', 'append_file': 0} + function! maker.process_output(...) + " causes E48 + sandbox bprevious + endfunction + new + let jobinfo = neomake#Make(1, [maker]) + AssertEqual len(neomake#GetJobs()), 1, 'There is one job.' + + NeomakeTestsWaitForMessage 'exit: unnamed_maker: 0.' + AssertNeomakeMessage 'Processing 1 lines of output.' + AssertNeomakeMessage 'Error during pcall: Vim(bprevious):E48: Not allowed in sandbox: sandbox bprevious.', 3 + AssertNeomakeMessage 'Queuing action ProcessJobOutput for Timer, WinEnter.' + if has('timers') + NeomakeTestsWaitForMessage '\v^Retrying Timer event in 10ms \(timer (\d+)\)' + " Ensure that the action queue is not triggered via timer already. + " XXX: still flaky with vim-74-xenial + let timer = +g:neomake_test_matchlist[1] + call neomake#log#debug(printf('tests: manually stopping timer %d.', timer)) + call timer_stop(timer) + else + AssertNeomakeMessage 'Retrying Timer event on CursorHold(I).' + endif + let async = neomake#has_async_support() + if async + AssertNeomakeMessage 'unnamed_maker: completed with exit code 0.' + endif + AssertNeomakeMessage "Skipping cleaning of job info because of queued actions: ['ProcessJobOutput', ['Timer', 'WinEnter']].", 3 + AssertNeomakeMessage 'Queuing action CleanJobinfo for WinEnter.' + + bwipe + + AssertNeomakeMessage 'action queue: processing for WinEnter (2 items).', 3, 3, {'winnr': 1} + AssertNeomakeMessage 'action queue: calling ProcessJobOutput.', 3 + AssertNeomakeMessage 'Postponing location list processing.', 3 + AssertNeomakeMessage 'Queuing action ProcessJobOutput for BufEnter, WinEnter.', 3 + AssertNeomakeMessage 'action queue: skipping CleanJobinfo for not processed job_id.', 3 + AssertNeomakeMessage 'action queue: processed 0 items.', 3 + AssertNeomakeMessage 'action queue: processing for BufEnter (1 items).', 3, 3, {'winnr': 1} + + call neomake#CancelAllMakes() + AssertNeomakeMessage 'Removed 2 action queue entries.', 3, jobinfo + if async + AssertNeomakeMessage 'Removing already finished job.', 3, jobinfo + endif + AssertNeomakeMessage 'Cleaning jobinfo.', 3, jobinfo + +Execute (job finishes while in tabline function): + if !neomake#has_async_support() || !has('patch-v8.1.0342') + NeomakeTestsSkip 'only for async without patch v8.1.0342.' + else + Save &tabline, g:neomake_test_flagfile + + let g:neomake_test_flagfile = tempname() + + function! s:NeomakeTestTabline() + call writefile(['1'], g:neomake_test_flagfile) + NeomakeTestsWaitForFinishedJobs + call neomake#log#debug('tabline_end.') + endfunction + + new + let maker1 = NeomakeTestsCommandMaker('sleep', printf( + \ 'while ! [ -e %s ]; do sleep 0.01; done; echo finished_in_tabline; rm %s', + \ fnameescape(g:neomake_test_flagfile), fnameescape(g:neomake_test_flagfile))) + let jobinfo = neomake#GetJob(neomake#Make(1, [maker1])[0]) + set tabline=%!s:NeomakeTestTabline() + redrawstatus + + NeomakeTestsWaitForMessage 'Error during pcall: Vim(laddexpr):E523: Not allowed here: laddexpr a:lines.', 3 + AssertNeomakeMessage '\v\(in function .*\.\.\\d+_NeomakeTestTabline\[\d+\]\.\..*\)', 3 + AssertNeomakeMessage 'Queuing action process_pending_output for Timer, WinEnter.', 3 + + AssertNeomakeMessage "Skipping cleaning of job info because of queued actions: ['process_pending_output', ['Timer', 'WinEnter']]." + AssertNeomakeMessage 'Queuing action CleanJobinfo for WinEnter.' + AssertNeomakeMessage 'tabline_end.', 3 + sleep 20m + AssertNeomakeMessage 'action queue: processing for Timer (1 items).', 3, {'winnr': 2} + AssertNeomakeMessage 'action queue: calling process_pending_output.', 3 + + " Restore here already for vim8090 (E117: Unknown function: s:NeomakeTestTabline) + Restore &tabline + doautocmd WinEnter + AssertNeomakeMessage 'action queue: processing for WinEnter (1 items).', 3, {'winnr': 2} + AssertNeomakeMessageAbsent 'action queue: processing for Timer (0 items).', 3, {'winnr': 2} + AssertNeomakeMessage 'action queue: calling CleanJobinfo.', 3 + + AssertEqual map(getloclist(0), 'v:val.text'), ['finished_in_tabline'] + bwipe + Assert exists('#neomake_statusline'), 'statusline augroup was created' + Assert exists('#neomake_statusline#ColorScheme'), 'ColorScheme autocmd was created' + endif + +Execute (get_list_entries job processes entries while in tabline function): + if NeomakeAsyncTestsSetup() + Save &tabline + + Save g:entry_maker + let g:entry_maker = {} + function! g:entry_maker.get_list_entries(jobinfo) abort + return get(g:, 'neomake_test_getlistentries', [ + \ {'bufnr': bufnr('%'), 'text': 'error', 'lnum': 1, 'type': 'E'}]) + endfunction + + let g:neomake_test_tabline = 0 + function! s:NeomakeTestTabline() + AssertEqual len(g:neomake_test_finished), 0 + let g:neomake_test_tabline = 1 + sleep 10m + AssertEqual len(g:neomake_test_finished), 1 + endfunction + + new + set tabline=%!s:NeomakeTestTabline() + + Save g:neomake_test_jobinfo + function! s:NeomakeTestF(...) abort + call neomake#Make(1, [g:entry_maker]) + endfunction + + call timer_start(0, function('s:NeomakeTestF')) + redraw + NeomakeTestsWaitForFinishedJobs + AssertEqual g:neomake_test_tabline, 1 + AssertEqual len(g:neomake_test_finished), 1 + bwipe + endif + +Execute (make info gets cleaned when last job fails to start): + call g:NeomakeSetupAutocmdWrappers() + new + let b:neomake_serialize = 1 + let b:neomake_tempfile_enabled = 0 + set ft=neomake_tests + RunNeomake echo_maker true + bwipe + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertNeomakeMessage 'no file name.', 0 + +Execute (neomake#Make ignores calls during autocommands): + Save g:neomake_open_list + let g:neomake_open_list = 2 + + Save g:neomake_test_enabledmakers + let g:neomake_test_enabledmakers = ['process_output_error'] + + new + setf neomake_tests + + call g:NeomakeSetupAutocmdWrappers() + augroup neomake_tests + autocmd WinEnter * call neomake#log#debug('WinEnter: '.winnr().': '.&ft.'.') + autocmd WinEnter * Neomake + augroup END + + let win1 = winnr() + let job1 = neomake#Make({}) + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage 'Processing 1 lines of output.', 3 + AssertNeomakeMessage 'Handling location list: executing lwindow.', 3 + AssertNeomakeMessage 'Ignoring Make through autocommand due to ignore_autocommands=1.', 3, {'winnr': 3} + AssertNeomakeMessage 'Ignoring Make through autocommand due to ignore_autocommands=1.', 3, {'winnr': 1} + AssertNeomakeMessage 'Ignoring Make through autocommand due to ignore_autocommands=1.', 3, {'winnr': 2} + + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + + lclose + bwipe + AssertNeomakeMessage 'WinEnter: 1: .', 3 + AssertNeomakeMessage 'Nothing to make: no enabled file mode makers (filetype=).', 3 + +Execute (Neovim: detects buffered output feature): + if has('nvim-0.3.0') + AssertEqual neomake#_get_s().nvim_can_buffer_output, 1 + else + AssertEqual neomake#_get_s().nvim_can_buffer_output, 0 + + if has('nvim') + " Test that specialized handlers are used, i.e. no output with wrong + " nvim_can_buffer_output. + let s = neomake#_get_s() + let s.nvim_can_buffer_output = 1 + + let maker = {'buffer_output': 1, 'exe': 'printf', 'args': 'output'} + CallNeomake 0, [maker] + AssertEqual getqflist(), [] + + let s.nvim_can_buffer_output = 0 + endif + endif + +Execute (Output (order) is handled correctly with pending output): + let maker = neomake#utils#MakerFromCommand('i=0; while ((i < 4)); do i=$((i+1)); echo $i; sleep 0.1; done') + let maker.errorformat = '%m' + let maker.buffer_output = 0 + call neomake#Make(0, [maker]) + + if neomake#has_async_support() + NeomakeTestsWaitForMessage 'Processing 1 entries.', 3 + AssertEqual map(getqflist(), 'v:val.text'), ['1'] + norm! V + AssertEqual mode(), 'V' + NeomakeTestsWaitForMessage 'Not processing output for mode "V".' + AssertNeomakeMessage 'Queuing action process_pending_output for BufEnter, WinEnter, InsertLeave, CursorHold, CursorHoldI.', 3 + NeomakeTestsWaitForMessage 'Not processing output for mode "V".' + AssertNeomakeMessageAbsent 'Queuing action process_pending_output for BufEnter, WinEnter, InsertLeave, CursorHold, CursorHoldI.', 3 + AssertEqual map(getqflist(), 'v:val.text'), ['1'] + exe "norm! \" + AssertEqual mode(), 'n' + NeomakeTestsWaitForMessage 'Processed 2 pending outputs.', 3 + AssertNeomakeMessage 'Removed 1 action queue entries for process_pending_output.' + AssertNeomakeMessage 'Processing 1 entries.', 3 + NeomakeTestsWaitForFinishedJobs + else + AssertNeomakeMessage 'Processing 4 lines of output.' + endif + AssertEqual map(getqflist(), 'v:val.text'), ['1', '2', '3', '4'] + +Execute (get_list_entries: not finished when being retried): + let maker = {} + let s:count = 0 + function maker.get_list_entries(...) + let s:count += 1 + if s:count == 1 + sandbox bprevious + endif + return [{'lnum': 2, 'bufnr': bufnr('%'), 'text': 'error'}] + endfunction + new + call neomake#Make(1, [maker]) + if has('timers') + NeomakeTestsWaitForFinishedJobs + else + doautocmd CursorHoldI + endif + AssertEqual s:count, 2 + AssertNeomakeMessage '\vError during pcall:.*' + bwipe + +Execute (handles terminal mode, requeues for BufEnter/WinEnter): + if !exists(':terminal') + NeomakeTestsSkip 'only with :terminal' + else + new + let make_bufnr = bufnr('%') + + let s:exited = 0 + function! s:exit_insert(...) + NeomakeTestsWaitForMessage 'exit: error-maker: 1.' + let s:exited = 1 + call feedkeys("\\", 'x') + new + endfunction + call timer_start(100, function('s:exit_insert')) + call neomake#Make(1, [g:error_maker]) + + " Neovim replaces the current buffer, while Vim opens a new window. + if has('nvim') + new + endif + terminal + + " For whatever reason(s) Neovim needs feedkeys, and Vim startinsert. + if has('nvim') + call feedkeys('i', 'x!') + else + startinsert + while !s:exited + sleep 100m + endwhile + endif + + NeomakeTestsWaitForFinishedJobs + AssertEqual s:exited, 1 + AssertNeomakeMessage 'Not processing output for mode "t".' + AssertNeomakeMessage 'Queuing action process_pending_output for BufEnter, WinEnter, InsertLeave, CursorHold, CursorHoldI.' + AssertNeomakeMessage 'action queue: processing for WinEnter (1 items).' + AssertNeomakeMessage 'Skipped pending job output for another buffer (current='.bufnr('%').').', 3, {'bufnr': make_bufnr} + + " Requeues for BufEnter/WinEnter only. + AssertNeomakeMessage 'Queuing action process_pending_output for BufEnter, WinEnter.' + + bwipe + AssertNeomakeMessage 'Skipped pending job output for another buffer (current='.bufnr('%').').', 3, {'bufnr': make_bufnr} + bwipe! + AssertEqual map(getloclist(0), 'v:val.text'), ['error'] + bwipe + endif + +Execute (process_json with action queue / pending outputs): + if NeomakeAsyncTestsSetup() + let s:called = 0 + + let maker = NeomakeTestsCommandMaker('json-maker', 'echo ''{}''') + function! maker.process_json(context) abort dict + let s:called += 1 + AssertEqual a:context.json, {} + return [] + endfunction + + call neomake#Make({'enabled_makers': [maker]}) + norm! V + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage "output on stdout: ['{}', ''].", 3 + AssertNeomakeMessage 'Not processing output for mode "V".', 3 + exe "norm! \" + doautocmd CursorHold + AssertNeomakeMessage "Calling maker's process_json method with 0 JSON entries.", 3 + AssertNeomakeMessage 'Processed 1 pending outputs.', 3 + AssertEqual s:called, 1 + endif diff --git a/bundle/neomake/tests/serialize.vader b/bundle/neomake/tests/serialize.vader new file mode 100644 index 000000000..af4fa9d1a --- /dev/null +++ b/bundle/neomake/tests/serialize.vader @@ -0,0 +1,401 @@ +Include: include/setup.vader + +Execute (NeomakeSh: simple serialized makers): + new + call g:NeomakeSetupAutocmdWrappers() + Save g:neomake_serialize + let g:neomake_serialize = 1 + + call neomake#Make(1, [g:sleep_maker, g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['slept', 'error'] + AssertNeomakeMessage 'Running makers: sleep-maker, error-maker.', 3 + AssertNeomakeMessage 'exit: sleep-maker: 0.' + AssertNeomakeMessage 'exit: error-maker: 1.' + bwipe + +Execute (NeomakeSh: simple serialized makers: two buffers in parallel): + if NeomakeAsyncTestsSetup() + let sleep_maker1 = NeomakeTestsCommandMaker('sleep-maker1', 'sleep .01; echo slept1') + let sleep_maker2 = NeomakeTestsCommandMaker('sleep-maker2', 'sleep .05; echo slept2') + + call g:NeomakeSetupAutocmdWrappers() + Save g:neomake_serialize + let g:neomake_serialize = 1 + + new + call neomake#Make(1, [sleep_maker1, g:error_maker]) + new + call neomake#Make(1, [sleep_maker2, g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['slept2', 'error'] + AssertNeomakeMessage 'Running makers: sleep-maker1, error-maker.', 3 + AssertNeomakeMessage 'Running makers: sleep-maker2, error-maker.', 3 + AssertNeomakeMessage 'exit: sleep-maker1: 0.' + AssertNeomakeMessage 'exit: error-maker: 1.' + AssertNeomakeMessage 'exit: sleep-maker2: 0.' + AssertNeomakeMessage 'exit: error-maker: 1.' + + bwipe + AssertEqual len(g:neomake_test_finished), 2 + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['slept1', 'error'] + bwipe + endif + +Execute (NeomakeSh: simple serialized maker with error): + new + call g:NeomakeSetupAutocmdWrappers() + Save g:neomake_serialize + let g:neomake_serialize = 1 + + call neomake#Make(1, [g:error_maker, g:success_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['error'] + AssertNeomakeMessage 'Running makers: error-maker, success-maker.', 3 + AssertNeomakeMessage 'exit: error-maker: 1.' + AssertNeomakeMessage 'exit: success-maker: 0.' + bwipe + +Execute (NeomakeSh: serialized with global abort): + new + call g:NeomakeSetupAutocmdWrappers() + + Save g:neomake_serialize + let g:neomake_serialize = 1 + Save g:neomake_serialize_abort_on_error + let g:neomake_serialize_abort_on_error = 1 + + call neomake#Make(1, [g:error_maker, g:success_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), ['error'] + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Aborting next makers: success-maker.', 2 + bwipe + +Execute (NeomakeSh: serialized with buffer overriding global abort): + call g:NeomakeSetupAutocmdWrappers() + new + + Save g:neomake_serialize + let g:neomake_serialize = 1 + Save g:neomake_serialize_abort_on_error + let g:neomake_serialize_abort_on_error = 1 + let b:neomake_serialize_abort_on_error = 0 + + call neomake#Make(0, [g:error_maker, g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), 2 + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(getqflist(), 'v:val.text'), ['error', 'error'] + bwipe + +Execute (NeomakeSh: serialized with abort from maker): + new + call g:NeomakeSetupAutocmdWrappers() + + let error_abort_maker = copy(g:error_maker) + let error_abort_maker.serialize = 1 + let error_abort_maker.serialize_abort_on_error = 1 + + call neomake#Make(1, [error_abort_maker, g:success_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), 1 + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage 'Aborting next makers: success-maker.' + AssertEqual map(getloclist(0), 'v:val.text'), ['error'] + bwipe + +Execute (NeomakeSh: serialized with previous buffer overriding global abort): + if NeomakeAsyncTestsSetup() + new + Save g:neomake_serialize, b:neomake_serialize_abort_on_error + let g:neomake_serialize = 1 + let b:neomake_serialize_abort_on_error = 1 + call neomake#Make(1, [g:sleep_maker, g:error_maker, g:success_maker]) + + let bufnr = bufnr('%') + new + NeomakeTestsWaitForFinishedJobs + AssertEqual getloclist(0), [] + + wincmd p + + AssertEqual map(getloclist(0), 'v:val.text'), ['slept', 'error'] + wincmd p + bwipe + bwipe + AssertNeomakeMessage 'Aborting next makers: success-maker.' + endif + +Execute (NeomakeSh: serialized after doesnotexist: continue): + if NeomakeAsyncTestsSetup() + new + Save g:neomake_serialize + let g:neomake_serialize = 1 + + call neomake#Make(0, [g:doesnotexist_maker, g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(getqflist(), 'v:val.text'), ['error'] + + AssertNeomakeMessage 'Exe (doesnotexist) of maker unnamed_maker is not executable.' + bwipe + endif + +Execute (NeomakeSh: serialized after doesnotexist with abort: continue): + call g:NeomakeSetupAutocmdWrappers() + Save g:neomake_serialize + let g:neomake_serialize = 1 + + let g:doesnotexist_maker.serialize_abort_on_error = 1 + call neomake#Make(0, [g:doesnotexist_maker, g:success_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + AssertNeomakeMessage "Exe (doesnotexist) of maker unnamed_maker is not executable." + +Execute (Neomake#Make cancels previous jobs): + if NeomakeAsyncTestsSetup() + new + let first_jobs = neomake#Make({'file_mode': 0, 'enabled_makers': [g:sleep_maker, g:error_maker]}) + AssertEqual len(first_jobs), 2 + let make_id = neomake#GetStatus().last_make_id + let bufnr = bufnr('%') + let second_jobs = neomake#Make(0, [g:sleep_maker, g:error_maker]) + AssertEqual has_key(neomake#GetStatus().make_info, make_id), 0 + + for jobinfo in first_jobs + AssertNeomakeMessage printf('Canceling already running job (%d.%d) for the same maker.', + \ make_id, jobinfo.id), 2, {'make_id': make_id+1} + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$', 3, jobinfo + endfor + + NeomakeTestsWaitForFinishedJobs + AssertEqual has_key(neomake#GetStatus().make_info, make_id), 0 + AssertEqual len(g:neomake_test_jobfinished), 2 + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual map(getqflist(), 'v:val.text'), ['error', 'slept'] + + AssertEqual neomake#GetStatus().last_make_id, make_id + 1, 'two make instance' + + " Restarted job should use new make_id. + AssertNeomakeMessage printf("Starting async job: %s -c 'echo error; false'.", &shell), + \ 2, {'id': second_jobs[1], 'make_id': make_id+1, 'bufnr': bufnr} + bwipe + endif + +Execute (Neomake#Make cancels previous jobs (serialized)): + if NeomakeAsyncTestsSetup() + new + let first_jobs = neomake#Make({ + \ 'file_mode': 0, + \ 'serialize': 1, + \ 'enabled_makers': [g:true_maker, g:sleep_maker]}) + AssertEqual len(first_jobs), 1 + let make_id = neomake#GetStatus().last_make_id + let bufnr = bufnr('%') + + NeomakeTestsWaitForNextMessage +" let second_jobs = neomake#Make(0, [g:error_maker, g:sleep_maker]) + let second_jobs = neomake#Make({ + \ 'file_mode': 0, + \ 'serialize': 1, + \ 'enabled_makers': [g:error_maker, g:sleep_maker]}) + AssertNeomakeMessage 'Running makers: error-maker, sleep-maker.' + AssertEqual has_key(neomake#GetStatus().make_info, make_id), 0 + + AssertNeomakeMessage printf('Canceling already running job (%d.%d) for the same maker.', + \ make_id, first_jobs[0].id + 1), 2, {'make_id': make_id+1} + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$', 3 + + NeomakeTestsWaitForFinishedJobs + AssertEqual has_key(neomake#GetStatus().make_info, make_id), 0 + AssertEqual len(g:neomake_test_jobfinished), 3 + AssertEqual len(g:neomake_test_finished), 2 + + AssertEqual map(getqflist(), 'v:val.text'), ['error', 'slept'] + + AssertEqual neomake#GetStatus().last_make_id, make_id + 1, 'two make instance' + + " Restarted job should use new make_id. + AssertNeomakeMessage printf("Starting async job: %s -c 'echo error; false'.", &shell), + \ 2, {'id': second_jobs[0].id, 'make_id': make_id+1, 'bufnr': bufnr} + bwipe + endif + +Execute (Neomake#Make starts new jobs before waiting for the old to finish): + if NeomakeAsyncTestsSetup() + let maker = NeomakeTestsCommandMaker('sleep', 'sleep .1') + call neomake#Make(0, [maker]) + call neomake#Make(0, [maker]) + let start = reltime() + let last_jobinfo = neomake#Make(0, [maker])[0] + NeomakeTestsWaitForFinishedJobs + let end = reltime() + let duration = reltimefloat(end) - reltimefloat(start) + Assert duration < 0.3, printf( + \ 'Jobs have been restarted before being stopped (%.2f).', duration) + + AssertNeomakeMessage 'Running makers: sleep.' + AssertNeomakeMessage '\m^Starting async job:' + AssertNeomakeMessage 'Running makers: sleep.' + AssertNeomakeMessage '\m^Canceling already running job' + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$' + AssertNeomakeMessage '\m^Starting async job:' + AssertNeomakeMessage 'Running makers: sleep.' + AssertNeomakeMessage '\m^Canceling already running job' + AssertNeomakeMessage '\v^Stopping \w+ job: .+\.$' + AssertNeomakeMessage '\m^Starting async job:' + AssertNeomakeMessage '\mexit: job not found:' + AssertNeomakeMessage '\mexit: job not found:' + AssertNeomakeMessage 'exit: sleep: 0.', 3, last_jobinfo, {'ignore_order': 1} + + let restart_messages = filter(copy(g:neomake_test_messages), + \ "v:val[1] =~# '\\vCanceling already running job \\(\\d+\\.\\d+\\) for the same maker.'") + AssertEqual len(restart_messages), 2, 'Jobs have not been restarted: '.string(restart_messages) + endif + +Execute (Neomake#Make does not cancel maker from same run): + if NeomakeAsyncTestsSetup() + new + call neomake#Make(0, [g:error_maker, g:error_maker]) + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getqflist(), 'v:val.text'), ['error', 'error'] + bwipe + endif + +Execute (Neomake#Make handles cwd properly): + if NeomakeAsyncTestsSetup() + Save g:neomake_serialize + let g:neomake_serialize = 1 + + let orig_cwd = getcwd() + + new + edit tests/fixtures/errors.sh + let file1 = expand('%:p') + + cd build + try + let cwd = fnamemodify(getcwd(), ':t') + + " Create a new window/buffer, with a different working dir. + new + file file2 + if !isdirectory('dir1') + call mkdir('dir1', '', 0770) + endif + lcd dir1 + wincmd p + + let maker1 = NeomakeTestsCommandMaker('maker1', 'echo maker_1 ${PWD##*/}: ') + let maker1.append_file = 1 + function! maker1.exit_callback(cb_dict) dict + let g:neomake_test_exit_cb += [self, a:cb_dict] + " Change to other window with different cwd. + wincmd p + endfunction + let g:neomake_test_exit_cb = [] + let maker2 = NeomakeTestsCommandMaker('maker2', 'echo maker_2 ${PWD##*/}: ') + let maker2.append_file = 1 + let maker3 = { + \ 'name': 'maker3', + \ 'errorformat': '%m', + \ 'exe': 'printf', + \ 'args': ['maker_3 %s'], + \ 'append_file': 1} + + let jobs = neomake#Make({'enabled_makers': [maker1, maker2, maker3]}) + AssertEqual len(jobs), 1, "Only one job has been started initially" + let jobinfo1 = jobs[0] + NeomakeTestsWaitForFinishedJobs + " Trigger processing. + wincmd p + + " Cleanup. + wincmd p + bwipe + finally + exe 'cd '.orig_cwd + endtry + + Assert !has_key(g:neomake_test_jobfinished[2].jobinfo.maker, 'tempfile_name'), 'No tempfile is used' + + AssertEqual g:neomake_test_exit_cb[0], jobinfo1 + AssertEqual g:neomake_test_exit_cb[1], {'status': 0, 'name': 'maker1', 'has_next': 1} + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['maker_1 build: '.file1, 'maker_2 build: '.file1, 'maker_3 '.file1] + bwipe + endif + +Execute (Uses correct maker filetypes when started in another buffer): + if NeomakeAsyncTestsSetup() + Save g:neomake_serialize + let g:neomake_serialize = 1 + + new + set filetype=orig_ft + + let maker1 = NeomakeTestsCommandMaker('maker1', 'true') + function! maker1.exit_callback(job_status) dict + new + set filetype=another_ft + endfunction + + let maker2 = NeomakeTestsCommandMaker('maker2', 'true') + function! maker2.exit_callback(job_status) dict + let g:neomake_test_exit_cb = [self, a:job_status] + AssertEqual &filetype, 'another_ft' + bwipe + endfunction + + CallNeomake 1, [maker1, maker2] + AssertEqual g:neomake_test_exit_cb[1], {'status': 0, 'name': 'maker2', 'has_next': 0} + AssertEqual g:neomake_test_exit_cb[0].ft, 'orig_ft' + bwipe + endif + +Execute (serialize: waits for intermediate job to start): + new + let maker1 = {'name': 'maker1', 'exe': 'true'} + let maker2 = NeomakeTestsCommandMaker('sleep-maker', 'sleep .05; echo slept; exit 1') + let maker2.serialize = 1 + let maker2.serialize_abort_on_error = 1 + let maker3 = {'name': 'maker3', 'exe': 'true'} + + let jobs = neomake#Make({'enabled_makers': [maker1, maker2, maker3]}) + NeomakeTestsWaitForFinishedJobs + + if neomake#has_async_support() + AssertNeomakeMessage 'waiting for job '.jobs[1].id.' to finish.' + endif + AssertNeomakeMessage 'Aborting next makers: maker3.' + + let title = neomake#list#get()._get_title() + AssertEqual title, 'Neomake[file]: buf:'.bufnr('%').' (maker1✓, sleep-maker!(1), maker3-)' + AssertEqual map(getloclist(0), 'v:val.text'), ['slept'] + bwipe + +Execute (serialize: canceling aborts following jobs / cleans make info): + if NeomakeAsyncTestsSetup() + new + let maker1 = copy(g:sleep_maker) + let maker1.serialize = 1 + let maker2 = g:true_maker + + call neomake#Make(1, [maker1, maker2]) + + NeomakeTestsWaitForMessage 'Running makers: sleep-maker, true-maker.', 3 + call neomake#CancelMake() + AssertNeomakeMessage 'Canceling make.', 3 + AssertNeomakeMessage 'Aborting next makers: true-maker.' + NeomakeTestsWaitForMessage 'Cleaning make info.', 3 + bwipe + endif diff --git a/bundle/neomake/tests/signs.vader b/bundle/neomake/tests/signs.vader new file mode 100644 index 000000000..ec3d8c969 --- /dev/null +++ b/bundle/neomake/tests/signs.vader @@ -0,0 +1,575 @@ +Include: include/setup.vader + +Execute (neomake#signs#RedefineErrorSign): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + new + file file1 + let bufnr = bufnr('%') + let maker = neomake#utils#MakerFromCommand( + \ 'echo file1: E: error without line; echo file1:2: W: warning') + call extend(maker, { + \ 'name': 'custom_maker', + \ 'errorformat': '%E%f:%l: %t: %m,%E%f: %t: %m', + \ 'append_file': 0, + \ }, 'error') + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Placing sign: sign place 5000 line=2 name=neomake_file_warn buffer='.bufnr('%').'.' + + AssertNeomakeMessage '\vCould not place signs for 1 entries without line number: \[.*\].', 3 + + " Test #736. + call neomake#signs#RedefineErrorSign({'text': 'X', 'texthl': 'ErrorMsg'}) + let sign = substitute(neomake#utils#redir('sign list neomake_file_err'), '\v^[\n]*', '', '') + AssertEqual split(sign), ['sign', 'neomake_file_err', 'text=X', 'texthl=ErrorMsg'] + AssertEqual neomake#signs#by_lnum(bufnr('%')), {'2': [[5000, 'neomake_file_warn']]} + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_warn, lnum=2.' + AssertNeomakeMessage 'Reused 1 signs.', 3, {'bufnr': bufnr} + AssertNeomakeMessage 'Cleaning 0 old signs.', 3, {'bufnr': bufnr} + AssertEqual neomake#signs#by_lnum(bufnr('%')), {'2': [[5000, 'neomake_file_warn']]} + + call neomake#signs#Reset(bufnr, 'file') + call neomake#signs#CleanAllOldSigns('file') + AssertNeomakeMessage 'Cleaning 1 old signs.', 3 + AssertEqual neomake#signs#by_lnum(bufnr), {} + bwipe + +Execute (Placing signs in project mode): + new + let maker = neomake#utils#MakerFromCommand('echo 1:1: W: warning') + call extend(maker, { + \ 'name': 'custom_maker', + \ 'errorformat': '%E%f:%l: %t: %m', + \ }, 'error') + file 1 + let bufnr = bufnr('%') + call neomake#Make(0, [maker]) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_project_warn buffer='.bufnr.'.' + bd + + call neomake#signs#Reset(bufnr, 'project') + call neomake#signs#CleanAllOldSigns('project') + AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} + AssertEqual neomake#signs#by_lnum(bufnr), {} + exe 'bwipe' bufnr + +Execute (Signs are not re-used / wiped across modes): + new + let bufnr = bufnr('%') + AssertEqual neomake#signs#by_lnum(bufnr), {} + call neomake#signs#PlaceSigns(bufnr('%'), + \ [{'type': 'E', 'bufnr': bufnr('%'), 'lnum': 1}], 'file') + call neomake#signs#PlaceSigns(bufnr('%'), + \ [{'type': 'W', 'bufnr': bufnr('%'), 'lnum': 1}], 'project') + + AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.bufnr.'.' + AssertNeomakeMessage 'Placing sign: sign place 5001 line=1 name=neomake_project_warn buffer='.bufnr.'.' + call neomake#signs#ResetProject() + AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} + call neomake#signs#CleanAllOldSigns('project') + AssertNeomakeMessage 'Removing signs: {file: {}, project: {}}.' + + AssertEqual neomake#signs#by_lnum(bufnr), {'1': [[5000, 'neomake_file_err']]} + call neomake#signs#RedefineSign('neomake_file_warn', {}) + bwipe + +Execute (Signs are wiped when buffer gets wiped): + new + call neomake#signs#PlaceSigns(bufnr('%'), + \ [{'type': 'E', 'bufnr': bufnr('%'), 'lnum': 1}], 'file') + bwipe + " Should not cause 'E158: Invalid buffer name' + call neomake#signs#RedefineSign('neomake_file_err', {}) + +Execute (neomake#signs#by_lnum): + new + let bufnr = bufnr('%') + exe 'sign place 5000 name=neomake_file_err line=1 buffer='.bufnr + exe 'sign place 5001 name=neomake_file_warn line=2 buffer='.bufnr + exe 'sign place 5002 name=neomake_file_info line=3 buffer='.bufnr + AssertEqual neomake#signs#by_lnum(bufnr('%')), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']], + \ '3': [[5002, 'neomake_file_info']]} + + " Visible (last placed sign) is first in list. + exe 'sign place 5003 name=neomake_file_info line=1 buffer='.bufnr + AssertEqual neomake#signs#by_lnum(bufnr('%')), { + \ '1': [[5003, 'neomake_file_info'], [5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']], + \ '3': [[5002, 'neomake_file_info']]} + bwipe + +Execute (neomake#signs#by_lnum for invalid bufnr): + AssertEqual neomake#signs#by_lnum(9999), {} + AssertEqual neomake#signs#by_lnum('9999'), {} + +Execute (neomake#signs#PlaceSigns): + new + let bufnr = bufnr('%') + let entries = [ + \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}] + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr('%')), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']], + \ '3': [[5002, 'neomake_file_info']]} + + let entries = [ + \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'E', 'bufnr': bufnr}] + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']], + \ '3': [[5002, 'neomake_file_err']]} + + let entries = [ + \ {'lnum': 2, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'W', 'bufnr': bufnr}, + \ {'lnum': 4, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 4, 'type': 'I', 'bufnr': bufnr}] + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_err']], + \ '3': [[5002, 'neomake_file_warn']], + \ '4': [[5003, 'neomake_file_err']]} + + call neomake#signs#Reset(bufnr, 'file') + call neomake#signs#CleanOldSigns(bufnr, 'file') + AssertEqual neomake#signs#by_lnum(bufnr), {} + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '2': [[5000, 'neomake_file_err']], + \ '3': [[5001, 'neomake_file_warn']], + \ '4': [[5002, 'neomake_file_err']]} + + let entries = [ + \ {'lnum': 4, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'W', 'bufnr': bufnr}, + \ {'lnum': 2, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 2, 'type': 'I', 'bufnr': bufnr}] + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '2': [[5000, 'neomake_file_err']], + \ '3': [[5001, 'neomake_file_warn']], + \ '4': [[5002, 'neomake_file_err']]} + + let entries = [ + \ {'lnum': 4, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'W', 'bufnr': bufnr}, + \ {'lnum': 2, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 5, 'type': 'I', 'bufnr': bufnr}] + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '2': [[5000, 'neomake_file_err']], + \ '3': [[5001, 'neomake_file_warn']], + \ '4': [[5002, 'neomake_file_err']], + \ '5': [[5003, 'neomake_file_info']]} + + call neomake#signs#Reset(bufnr, 'file') + call neomake#signs#CleanOldSigns(bufnr, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr), {} + bwipe + +Execute (neomake#signs#PlaceSigns with E and I (E after I)): + new + file foo + bwipe + Save g:neomake_place_signs_count + let g:neomake_place_signs_count = 1 + + new + let bufnr = bufnr('%') + let entries = [ + \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'E', 'bufnr': bufnr}] + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr('%')), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']], + \ '3': [[5002, 'neomake_file_err']]} + bwipe + +Execute (neomake#signs#PlaceSigns with E and I (E before I)): + Save g:neomake_place_signs_count + let g:neomake_place_signs_count = 1 + + new + let bufnr = bufnr('%') + let entries = [ + \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}] + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr('%')), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']], + \ '3': [[5002, 'neomake_file_err']]} + bwipe + +Execute (neomake#signs#PlaceSigns handles multiple signs per line): + Save g:neomake_place_signs_count + let g:neomake_place_signs_count = -1 + + new + let bufnr = bufnr('%') + let entries = [ + \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, + \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}, + \ {'lnum': 3, 'type': 'E', 'bufnr': bufnr}] + call neomake#signs#PlaceSigns(bufnr, entries, 'file') + + AssertEqual neomake#signs#by_lnum(bufnr('%')), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']], + \ '3': [[5002, 'neomake_file_err']]} + bwipe + +Execute (Signs get handled across multiple get_list_entries jobs): + new + let bufnr = bufnr('%') + let maker1 = {'_idx': 'maker1'} + function! maker1.get_list_entries(jobinfo) abort dict + return map(copy(g:neomake_test_entries[self._idx]), + \ "extend(v:val, {'bufnr': bufnr('%')}, 'keep')") + endfunction + let maker2 = copy(maker1) + let maker2._idx = 'maker2' + let g:neomake_test_entries = { + \ 'maker1': [{'type': 'E', 'lnum': 1, 'text': 'error'}], + \ 'maker2': [{'type': 'W', 'lnum': 2, 'text': 'warning'}]} + + call neomake#Make(1, [maker1]) + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']]} + + call neomake#Make(1, [maker1, maker2]) + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']]} + + call neomake#Make(1, [maker1]) + AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']]} + + call neomake#Make(1, [maker1, maker2]) + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_warn']]} + bwipe + +Execute (next sign_id based on max): + new + let bufnr = bufnr('%') + exe 'sign place 5002 line=1 name=neomake_file_warn buffer='.bufnr + exe 'sign place 5001 line=2 name=neomake_file_warn buffer='.bufnr + call neomake#signs#PlaceSigns(bufnr, [{'lnum': 3, 'type': 'W'}], 'file') + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5002, 'neomake_file_warn']], + \ '2': [[5001, 'neomake_file_warn']], + \ '3': [[5003, 'neomake_file_warn']]} + bwipe + +Execute (file mode signs get placed when job finishes): + if NeomakeAsyncTestsSetup() + new + file signs.test + let bufnr = bufnr('%') + let options = { + \ 'errorformat': '%f:%l:%t:%m', + \ 'mapexpr': "bufname('%').':'.v:val"} + let maker1 = NeomakeTestsCommandMaker('maker1', 'echo 1:I:msg1; echo 3:W:msg2') + call extend(maker1, options) + let maker2 = NeomakeTestsCommandMaker('maker2', 'sleep .1; echo 1:W:msg3; echo 2:E:msg4') + call extend(maker2, options) + + call neomake#Make(1, [maker1, maker2]) + NeomakeTestsWaitForNextFinishedJob + + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_info']], + \ '3': [[5001, 'neomake_file_warn']]} + NeomakeTestsWaitForFinishedJobs + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_warn']], + \ '2': [[5002, 'neomake_file_err']], + \ '3': [[5001, 'neomake_file_warn']]} + bwipe + endif + +Execute (project mode signs get placed when job finishes): + if NeomakeAsyncTestsSetup() + new + file signs1.test + let bufnr1 = bufnr('%') + new + file signs2.test + let bufnr2 = bufnr('%') + let maker1 = NeomakeTestsCommandMaker('maker1', + \ 'echo signs1.test:1:I:msg1; echo signs2.test:3:W:msg2') + let maker1.errorformat = '%f:%l:%t:%m' + let maker2 = NeomakeTestsCommandMaker('maker2', + \ 'sleep .1; echo signs1.test:1:W:msg3; echo signs2.test:2:E:msg4') + let maker2.errorformat = '%f:%l:%t:%m' + + call neomake#Make(0, [maker1, maker2]) + NeomakeTestsWaitForNextFinishedJob + + AssertEqual neomake#signs#by_lnum(bufnr1), { + \ '1': [[5000, 'neomake_project_info']]} + AssertEqual neomake#signs#by_lnum(bufnr2), { + \ '3': [[5000, 'neomake_project_warn']]} + NeomakeTestsWaitForFinishedJobs + AssertEqual neomake#signs#by_lnum(bufnr1), { + \ '1': [[5000, 'neomake_project_warn']]} + AssertEqual neomake#signs#by_lnum(bufnr2), { + \ '2': [[5001, 'neomake_project_err']], + \ '3': [[5000, 'neomake_project_warn']]} + + " Verify sign handling with a file mode maker on top. + let maker = {'_bufnr': bufnr1} + function maker.get_list_entries(...) + return [{'bufnr': self._bufnr, 'lnum': 1, 'type': 'E'}] + endfunction + CallNeomake {'file_mode': 1, 'enabled_makers': [maker]} + AssertNeomakeMessage 'Placing sign: sign place 5001 line=1 name=neomake_file_err buffer='.bufnr1.'.' + if has('patch-8.1.0384') || has('netbeans_intg') + AssertEqual neomake#signs#by_lnum(bufnr1), { + \ '1': [[5001, 'neomake_file_err'], [5000, 'neomake_project_warn']]} + endif + call neomake#signs#ResetFile(bufnr1) + call neomake#signs#CleanAllOldSigns('file') + AssertEqual neomake#signs#by_lnum(bufnr1), { + \ '1': [[5000, 'neomake_project_warn']]} + bwipe + bwipe + endif + +Execute (Highlights for signs get (re-)defined on ColorScheme event): + if exists('g:colors_name') + let colorscheme = g:colors_name + let had_colorscheme = 1 + else + let colorscheme = 'default' + let had_colorscheme = 0 + endif + let orig = neomake#utils#redir('hi NeomakeErrorSignDefault') + exe 'colorscheme' colorscheme + let new = neomake#utils#redir('hi NeomakeErrorSignDefault') + if had_colorscheme + AssertEqual orig, new + else + Assert stridx(new, 'cleared') == -1, 'highlight is not cleared.' + endif + +Execute (neomake#signs#PlaceSigns keeps sign moved by lnum): + new + let bufnr = bufnr('%') + function! s:place_sign(lnum) + let bufnr = bufnr('%') + call neomake#signs#PlaceSigns(bufnr, [ + \ {'lnum': a:lnum, 'type': 'E', 'bufnr': bufnr}], 'file') + endfunction + + call s:place_sign(1) + AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.bufnr.'.' + AssertEqual neomake#signs#by_lnum(bufnr), {'1': [[5000, 'neomake_file_err']]} + + normal! O + AssertEqual neomake#signs#by_lnum(bufnr), {'2': [[5000, 'neomake_file_err']]} + + call neomake#signs#Reset(bufnr, 'file') + call s:place_sign(2) + " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_err, lnum=2.' + AssertNeomakeMessage 'Reused 1 signs.', 3, {'bufnr': bufnr} + call neomake#signs#CleanOldSigns(bufnr, 'file') + AssertNeomakeMessage 'Cleaning 0 old signs.', 3, {'bufnr': bufnr} + + call neomake#signs#Reset(bufnr, 'file') + AssertEqual neomake#signs#by_lnum(bufnr), {'2': [[5000, 'neomake_file_err']]} + call neomake#signs#CleanOldSigns(bufnr, 'file') + AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} + AssertEqual neomake#signs#by_lnum(bufnr), {} + bwipe! + +Execute (CleanOldSigns removes unplaced sign from s:placed_signs): + new + let bufnr = bufnr('%') + + let s:call_count = 0 + let maker = {} + function maker.get_list_entries(...) + let s:call_count += 1 + let bufnr = bufnr('%') + let entries = [ + \ {'lnum': 1, 'text': '1', 'bufnr': bufnr, 'type': 'E'}, + \ ] + if s:call_count != 2 + let entries += [ + \ {'lnum': 2, 'text': '2', 'bufnr': bufnr, 'type': 'E'}, + \ ] + endif + return entries + endfunction + + normal! 3o + + CallNeomake 1, [maker] + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_err']], + \ } + + CallNeomake 1, [maker] + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']], + \ } + AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} + + CallNeomake 1, [maker] + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_err']], + \ '2': [[5001, 'neomake_file_err']], + \ } + " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_err, lnum=1.', 3 + AssertNeomakeMessage 'Reused 1 signs.', 3 + AssertNeomakeMessage 'Placing sign: sign place 5001 line=2 name=neomake_file_err buffer='.bufnr.'.' + bwipe! + +Execute (neomake#signs#PlaceSigns handles lowercase and fallback entry type): + new + let bufnr = bufnr('%') + call neomake#signs#PlaceSigns(bufnr, [ + \ {'type': 'w', 'bufnr': bufnr, 'lnum': 1}, + \ {'type': 'i', 'bufnr': bufnr, 'lnum': 2}, + \ {'type': 'm', 'bufnr': bufnr, 'lnum': 3}, + \ {'type': 'e', 'bufnr': bufnr, 'lnum': 4}, + \ {'type': 'x', 'bufnr': bufnr, 'lnum': 5}, + \ ], 'file') + + AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_warn buffer='.bufnr.'.' + AssertNeomakeMessage 'Placing sign: sign place 5001 line=2 name=neomake_file_info buffer='.bufnr.'.' + AssertNeomakeMessage 'Placing sign: sign place 5002 line=3 name=neomake_file_msg buffer='.bufnr.'.' + AssertNeomakeMessage 'Placing sign: sign place 5003 line=4 name=neomake_file_err buffer='.bufnr.'.' + AssertNeomakeMessage 'Placing sign: sign place 5004 line=5 name=neomake_file_err buffer='.bufnr.'.' + AssertEqual neomake#signs#by_lnum(bufnr), { + \ '1': [[5000, 'neomake_file_warn']], + \ '2': [[5001, 'neomake_file_info']], + \ '3': [[5002, 'neomake_file_msg']], + \ '4': [[5003, 'neomake_file_err']], + \ '5': [[5004, 'neomake_file_err']], + \ } + bwipe + +Execute (Signs should be placed with QuickfixCmdPost already (loclist)): + new + + let s:calls = [] + function OnQuickfixCmdPost() + call add(s:calls, neomake#signs#by_lnum(bufnr('%'))) + endfunction + + augroup neomake_tests + autocmd QuickfixCmdPost laddexpr call OnQuickfixCmdPost() + augroup END + + CallNeomake 1, [g:error_maker] + + let signs = neomake#signs#by_lnum(bufnr('%')) + AssertEqual signs, {'1': [[5000, 'neomake_file_err']]} + + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist + AssertEqual s:calls, [] + else + AssertEqual s:calls, [signs] + endif + bwipe + delfunction OnQuickfixCmdPost + +Execute (Signs should be placed with QuickfixCmdPost already (qflist)): + new + + let s:calls = [] + function OnQuickfixCmdPost() + call add(s:calls, neomake#signs#by_lnum(bufnr('%'))) + endfunction + + augroup neomake_tests + autocmd QuickfixCmdPost caddexpr call OnQuickfixCmdPost() + augroup END + + CallNeomake 0, [g:error_maker] + + let signs = neomake#signs#by_lnum(bufnr('%')) + AssertEqual signs, {'1': [[5000, 'neomake_project_err']]} + + if has('patch-8.0.1040') " 'efm' in setqflist/getqflist + AssertEqual s:calls, [] + else + AssertEqual s:calls, [signs] + endif + bwipe + delfunction OnQuickfixCmdPost + +Execute (neomake#signs#PlaceSigns: prevents re-used signs from being cleaned): + new + let bufnr = bufnr('%') + + call neomake#signs#PlaceSigns(bufnr('%'), + \ [{'type': 'E', 'bufnr': bufnr('%'), 'lnum': 1}], 'file') + AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.bufnr.'.' + + call neomake#signs#Reset(bufnr, 'file') + + call neomake#signs#PlaceSigns(bufnr('%'), + \ [{'type': 'W', 'bufnr': bufnr('%'), 'lnum': 1}], 'file') + AssertNeomakeMessage 'Upgrading sign for lnum=1: sign place 5000 name=neomake_file_warn buffer='.bufnr.'.' + + call neomake#signs#Reset(bufnr, 'file') + + AssertNeomakeMessage 'Cleaning 0 old signs.', 3 + bwipe + +Execute (Uses base sign id with only other signs): + new + sign define testsign + exe 'sign place 99 line=1 name=testsign buffer='.bufnr('%') + AssertEqual neomake#signs#by_lnum(bufnr('%')), {'1': [[99, 'testsign']]} + + let maker = {} + function! maker.get_list_entries(...) + return [{'lnum': 2, 'bufnr': bufnr('%')}] + endfunction + CallNeomake 1, [maker] + AssertEqual neomake#signs#by_lnum(bufnr('%')), { + \ '1': [[99, 'testsign']], + \ '2': [[5000, 'neomake_file_warn']], + \ } + sign undefine testsign + bwipe! diff --git a/bundle/neomake/tests/statusline.vader b/bundle/neomake/tests/statusline.vader new file mode 100644 index 000000000..3a09a9c61 --- /dev/null +++ b/bundle/neomake/tests/statusline.vader @@ -0,0 +1,230 @@ +Include: include/setup.vader + +Execute (LoclistCounts): + call neomake#statusline#ResetCounts() + call neomake#statusline#ResetCountsForBuf(99) + call neomake#statusline#AddLoclistCount(99, {'type': 'E', 'bufnr': 99}) + call neomake#statusline#AddLoclistCount(99, {'type': 'W', 'bufnr': 99}) + AssertEqual neomake#statusline#LoclistCounts(), {} + " With 'buf ==# "all"' this matched 0. + AssertEqual neomake#statusline#LoclistCounts(0), {} + + " 0 could refer to current buffer, but does not currently. + let curbufnr = bufnr('%') + call neomake#statusline#AddLoclistCount(curbufnr, {'type': 'E', 'bufnr': curbufnr}) + AssertEqual neomake#statusline#LoclistCounts(0), {} + + AssertEqual neomake#statusline#LoclistCounts(1), {} + AssertEqual neomake#statusline#LoclistCounts(99), {'E': 1, 'W': 1} + AssertEqual filter(neomake#statusline#LoclistCounts('all'), 'v:key == 99'), + \ {'99': {'E': 1, 'W': 1}} + +Execute (neomake#statusline#ResetCounts): + call neomake#statusline#ResetCounts() + call neomake#statusline#AddLoclistCount(99, {'type': 'E', 'bufnr': 99}) + call neomake#statusline#AddLoclistCount(99, {'type': 'W', 'bufnr': 99}) + AssertEqual neomake#statusline#LoclistCounts('all'), {'99': {'E': 1, 'W': 1}} + call neomake#statusline#AddQflistCount({'type': 'S', 'bufnr': 99}) + AssertEqual neomake#statusline#QflistCounts(), {'S': 1} + + call neomake#statusline#ResetCounts() + AssertEqual neomake#statusline#LoclistCounts('all'), {} + AssertEqual neomake#statusline#QflistCounts(), {} + +Execute (LoclistCounts returns number): + call g:NeomakeSetupAutocmdWrappers() + new + let bufnr = bufnr('%') + call neomake#statusline#AddLoclistCount(bufnr, {'type': 'E', 'bufnr': bufnr}) + AssertEqual neomake#statusline#LoclistCounts(bufnr), {'E': 1} + AssertEqual [], g:neomake_test_countschanged + call neomake#statusline#ResetCountsForBuf(bufnr) + AssertEqual bufnr, g:neomake_test_countschanged[0].bufnr + call setbufvar(g:neomake_test_countschanged[0].bufnr, 'test', 1) + AssertEqual 1, getbufvar(g:neomake_test_countschanged[0].bufnr, 'test') + bwipe + +Execute (LoclistCounts for wiped buffer should clean s:loclist_counts): + call g:NeomakeSetupAutocmdWrappers() + new + let bufnr = bufnr('%') + call neomake#statusline#AddLoclistCount(bufnr, {'type': 'E', 'bufnr': bufnr}) + AssertEqual neomake#statusline#LoclistCounts(bufnr), {'E': 1} + bwipe + AssertEqual neomake#statusline#LoclistCounts(bufnr), {'E': 1} + AssertEqual [], g:neomake_test_countschanged + + call neomake#statusline#ResetCounts() + AssertEqual bufnr, g:neomake_test_countschanged[0].bufnr + call setbufvar(g:neomake_test_countschanged[0].bufnr, 'test', 1) + AssertEqual '', getbufvar(g:neomake_test_countschanged[0].bufnr, 'test') + +Execute (neomake#statusline#get_status): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + call neomake#statusline#ResetCounts() + new + let bufnr = bufnr('') + AssertEqual neomake#statusline#get_status(bufnr, {}), '?' + + AssertEqual neomake#statusline#get_status(bufnr, {'format_loclist_unknown': '{{running_job_names}}'}), '' + " {{running_jobs}} is only available with 'format_running' (internally). + AssertEqual neomake#statusline#get_status(bufnr, {'format_loclist_unknown': '{{running_jobs}}'}), '{{running_jobs}}' + AssertNeomakeMessage "Error when formatting '{{running_jobs}}': Unknown statusline format: {{running_jobs}}.", 0 + + call neomake#Make({'enabled_makers': [g:sleep_maker]}) + if neomake#has_async_support() + AssertEqual neomake#statusline#get_status(bufnr, {}), '… (sleep-maker)' + AssertEqual neomake#statusline#get_status(bufnr, {'format_running': '...'}), '...' + AssertEqual neomake#statusline#get_status(bufnr, {'format_running': ''}), '' + " format_running=0 disables display of running state. + AssertEqual neomake#statusline#get_status(bufnr, {'format_running': 0}), '?' + AssertEqual neomake#statusline#get_status(bufnr, {'format_running': '{{running_job_names}}'}), 'sleep-maker' + + Assert neomake#statusline#get_status(bufnr, {'format_running': '{{running_jobs}}'}) =~# '\m^{''', '{{running_jobs}} is replaced in format_running' + + AssertEqual neomake#statusline#get_status(bufnr, {'format_lists': '{{quickfix}}'}), '' + AssertEqual neomake#statusline#get_status(bufnr, {'format_lists': '{{loclist}}'}), '… (sleep-maker)' + " lists_sep is ignored for single list. + AssertEqual neomake#statusline#get_status(bufnr, {'lists_sep': 'IGNORED'}), '… (sleep-maker)' + + call neomake#statusline#get_status(bufnr(''), {'format_running': 'Neomake: {{does_not_exist}}'}) + AssertNeomakeMessage "Error when formatting 'Neomake: {{does_not_exist}}': Unknown statusline format: {{does_not_exist}}.", 0 + + " Start project make. + call neomake#Make({'file_mode': 0, 'enabled_makers': [g:sleep_maker]}) + AssertEqual neomake#statusline#get_status(bufnr, {}), '… (sleep-maker) … (sleep-maker!)' + " Swapped default, no lists_sep. + AssertEqual neomake#statusline#get_status(bufnr, {'format_lists': '{{quickfix}} {{loclist}}'}), '… (sleep-maker!) … (sleep-maker)' + " Custom lists_sep. + AssertEqual neomake#statusline#get_status(bufnr, {'lists_sep': '//'}), '… (sleep-maker)//… (sleep-maker!)' + + " Start project makers. + call neomake#Make({'file_mode': 0, 'enabled_makers': [g:sleep_maker, g:sleep_maker]}) + AssertEqual neomake#statusline#get_status(bufnr, { + \ 'running_jobs_separator': '_SEP_', + \ 'format_running_job_project': 'project:%s', + \ 'format_running_job_file': 'file:%s', + \ }), '… (file:sleep-maker) … (project:sleep-maker_SEP_project:sleep-maker)' + + NeomakeTestsWaitForFinishedJobs + else + AssertEqual neomake#statusline#get_status(bufnr, {'format_running': '...'}), '%#NeomakeStatusGood#✓%#NeomakeStatReset#' + AssertEqual neomake#statusline#get_status(bufnr, {'format_loclist_ok': 'dandy!'}), 'dandy!' + AssertEqual neomake#statusline#get_status(bufnr, {'format_loclist_ok': '{{running_job_names}}'}), '' + + " Start project makers. + call neomake#Make({'file_mode': 0, 'enabled_makers': [g:sleep_maker, g:sleep_maker]}) + endif + + AssertNeomakeMessage '\v^Skipped 1 entries without bufnr:', 3 + + call neomake#statusline#get_status(bufnr(''), {'format_loclist_ok': 'Neomake: {{does_not_exist}}'}) + AssertNeomakeMessage "Error when formatting 'Neomake: {{does_not_exist}}': Unknown statusline format: {{does_not_exist}}.", 0 + call neomake#statusline#get_status(bufnr(''), {'format_loclist_ok': '{{foo}} {{bar}}'}) + AssertNeomakeMessage "Errors when formatting '{{foo}} {{bar}}': Unknown statusline format: {{foo}}., Unknown statusline format: {{bar}}.", 0 + + " NOTE: warning is counted with quickfix list, but skipped with location list, because it has no bufnr. + let expected = '%#NeomakeStatusGood#✓%#NeomakeStatReset# %#NeomakeStatColorQuickfixTypeW# QW:2 %#NeomakeStatReset#' + AssertEqual neomake#statusline#get_status(bufnr, {}), expected + AssertEqual neomake#statusline#get(bufnr, {}), expected + + call neomake#statusline#ResetCountsForBuf(bufnr) + let expected = '? %#NeomakeStatColorQuickfixTypeW# QW:2 %#NeomakeStatReset#' + AssertEqual neomake#statusline#get_status(bufnr, {}), expected + AssertEqual neomake#statusline#get(bufnr, {}), expected + + call neomake#statusline#ResetCountsForProject() + AssertEqual neomake#statusline#get_status(bufnr, {}), '?' + AssertEqual neomake#statusline#get(bufnr, {}), '?' + + CallNeomake 0, [g:success_maker] + AssertEqual neomake#statusline#get_status(bufnr, {'format_quickfix_ok': 'OK!'}), '? OK!' + bwipe + +Execute (neomake#statusline#get: clears cache with new job (file mode)): + new + let bufnr = bufnr('%') + CallNeomake {'enabled_makers': [g:error_maker]} + AssertEqual neomake#statusline#get(bufnr), '%#NeomakeStatColorTypeE# E:1 %#NeomakeStatReset#' + + call neomake#Make({'enabled_makers': [g:success_maker]}) + if neomake#has_async_support() + AssertEqual neomake#statusline#get(bufnr), '… (success-maker)' + NeomakeTestsWaitForFinishedJobs + endif + AssertEqual neomake#statusline#get(bufnr), '%#NeomakeStatusGood#✓%#NeomakeStatReset#' + bwipe + +Execute (neomake#statusline#get: clears cache with new job (project mode)): + new + let bufnr = bufnr('%') + CallNeomake {'file_mode': 0, 'enabled_makers': [g:error_maker]} + AssertEqual neomake#statusline#get(bufnr), '? %#NeomakeStatColorQuickfixTypeE# QE:1 %#NeomakeStatReset#' + + call neomake#Make({'file_mode': 0, 'enabled_makers': [g:true_maker]}) + if neomake#has_async_support() + AssertEqual neomake#statusline#get(bufnr), '? … (true-maker!)' + endif + call neomake#Make({'file_mode': 0, 'enabled_makers': [g:success_maker]}) + if neomake#has_async_support() + AssertEqual neomake#statusline#get(bufnr), '? … (true-maker!, success-maker!)' + NeomakeTestsWaitForFinishedJobs + endif + " Unknown status, only project makers have been run. + AssertEqual neomake#statusline#get(bufnr), '?' + bwipe + +Execute (neomake#statusline#get: clears cache with canceled job: keeps '?'): + if neomake#has_async_support() + new + let bufnr = bufnr('%') + call neomake#Make({'file_mode': 0, 'enabled_makers': [g:sleep_maker]}) + AssertEqual neomake#statusline#get(bufnr), '? … (sleep-maker!)' + NeomakeCancelJobs + AssertEqual neomake#statusline#get(bufnr), '? … (sleep-maker!)' + NeomakeTestsWaitForFinishedJobs + AssertEqual neomake#statusline#get(bufnr), '?' + bwipe + else + NeomakeTestsSkip 'no async support.' + endif + +Execute (neomake#statusline#get: disabling/enabling: clears cache): + new + let bufnr = bufnr('%') + AssertEqual neomake#statusline#get(bufnr), '?' + NeomakeDisableBuffer + AssertEqual neomake#statusline#get(bufnr), 'b- ?' + AssertNeomakeMessage "Using setting disabled=1 from 'buffer' (statusline#get).", 3, {'bufnr': bufnr} + + NeomakeToggleBuffer + AssertEqual neomake#statusline#get(bufnr), '?' + + CallNeomake 1, [g:true_maker] + AssertEqual neomake#statusline#get(bufnr), '%#NeomakeStatusGood#✓%#NeomakeStatReset#' + + " no-op + NeomakeEnableBuffer + AssertEqual neomake#statusline#get(bufnr), '%#NeomakeStatusGood#✓%#NeomakeStatReset#' + bwipe + +Execute (neomake#statusline#get: use_highlights_with_defaults): + new + let bufnr = bufnr('%') + AssertEqual neomake#statusline#get(bufnr, {'use_highlights_with_defaults': 0}), '?' + CallNeomake 1, [g:success_entry_maker] + AssertEqual neomake#statusline#get(bufnr, {'use_highlights_with_defaults': 0}), '✓' + AssertEqual neomake#statusline#get(bufnr, {'use_highlights_with_defaults': 1}), + \ '%#NeomakeStatusGood#✓%#NeomakeStatReset#' + bwipe + +Execute (statusline: uses user-configured highlights): + new + let bufnr = bufnr('%') + hi NeomakeStatColorTypeW ctermfg=Black ctermbg=Black cterm=none + let orig = neomake#utils#redir('hi NeomakeStatColorTypeW') + CallNeomake 1, [g:success_entry_maker] + AssertEqual neomake#utils#redir('hi NeomakeStatColorTypeW'), orig + bwipe diff --git a/bundle/neomake/tests/stdin.vader b/bundle/neomake/tests/stdin.vader new file mode 100644 index 000000000..75d6b2e03 --- /dev/null +++ b/bundle/neomake/tests/stdin.vader @@ -0,0 +1,407 @@ +Include: include/setup.vader + +Execute (stdin maker): + let maker = {'exe': 'cat', 'supports_stdin': 1, 'errorformat': '%f:%m'} + new + " Stdin should be used also when tempfiles are disabled. + let b:neomake_tempfile_enabled = 0 + normal! ifile1.test:line1 + normal! ofile1.test:line2 + call neomake#Make(1, [maker]) + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: cat -.", 2 + NeomakeTestsWaitForFinishedJobs + endif + AssertNeomakeMessage 'cwd: '.getcwd().'.', 3 + AssertNeomakeMessage '\moutput on stdout: [''file1.test:line1.*' + AssertNeomakeMessage '\vUsed bufnr from stdin buffer (\d+) \(file1.test\) for 2 entries: 1, 2.' + let tempbuf = g:neomake_test_matchlist[1] + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line2'] + AssertNeomakeMessage "Wiping out 1 unlisted/remapped buffers: ['".tempbuf."']." + bwipe! + +Execute (stdin maker (args as string)): + let maker = {'exe': 'cat', 'args': '', 'supports_stdin': 1, 'errorformat': '%f:%m'} + new + " Stdin should be used also when tempfiles are disabled. + let b:neomake_tempfile_enabled = 0 + normal! ifile1.test:line1 + normal! ofile1.test:line2 + call neomake#Make(1, [maker]) + if neomake#has_async_support() + if has('nvim') + AssertNeomakeMessage "Starting async job [string]: cat -.", 2 + else + let shell_argv = join(split(&shell) + split(&shellcmdflag)) + AssertNeomakeMessage 'Starting async job: '.shell_argv." 'cat -'.", 2 + endif + NeomakeTestsWaitForFinishedJobs + endif + AssertNeomakeMessage '\moutput on stdout: [''file1.test:line1.*' + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line2'] + bwipe! + +Execute (stdin maker (disabled tempfiles)): + let maker = {'exe': 'cat', 'supports_stdin': 1, 'tempfile_name': '-'} + new + " Stdin should be used also when tempfiles are disabled. + let b:neomake_tempfile_enabled = 0 + normal! iline1 + normal! oline2 + call neomake#Make(1, [maker]) + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).' + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: cat -.", 2 + NeomakeTestsWaitForFinishedJobs + else + AssertNeomakeMessage 'Starting [string]: cat -.', 2 + endif + AssertNeomakeMessage '\moutput on stdout: [''line1.*' + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line2'] + bwipe! + +Execute (stdin maker (project mode: append_file)): + let maker = {'exe': 'cat', 'supports_stdin': 1, 'tempfile_name': '-', + \ 'append_file': 1} + new + " Stdin should be used also when tempfiles are disabled. + let b:neomake_tempfile_enabled = 0 + normal! iline1 + normal! oline2 + call neomake#Make(0, [maker]) + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: cat -.", 2 + NeomakeTestsWaitForFinishedJobs + else + AssertNeomakeMessage 'Starting [string]: cat -.', 2 + endif + AssertNeomakeMessage '\moutput on stdout: [''line1.*' + AssertEqual map(getqflist(), 'v:val.text'), ['line1', 'line2'] + bwipe! + +Execute (stdin maker (project mode: uses_filename)): + let maker = {'exe': 'cat', 'args': '$NEOMAKE_FILE', 'supports_stdin': 1, + \ 'uses_filename': 1} + new + " Stdin should be used also when tempfiles are disabled. + let b:neomake_tempfile_enabled = 0 + normal! iline1 + normal! oline2 + call neomake#Make(0, [maker]) + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).' + if neomake#has_async_support() + if has('nvim') + AssertNeomakeMessage "Starting async job [string]: cat $NEOMAKE_FILE.", 2 + else + let shell_argv = join(split(&shell) + split(&shellcmdflag)) + AssertNeomakeMessage 'Starting async job: '.shell_argv." 'cat $NEOMAKE_FILE'.", 2 + endif + NeomakeTestsWaitForFinishedJobs + else + AssertNeomakeMessage 'Starting [string]: cat $NEOMAKE_FILE.', 2 + endif + AssertNeomakeMessage '\moutput on stdout: [''line1.*' + AssertEqual map(getqflist(), 'v:val.text'), ['line1', 'line2'] + bwipe! + +Execute (stdin maker: supports_stdin can be a callback adding args): + let maker = {'exe': 'printf', 'args': ['%s\n']} + function maker.supports_stdin(jobinfo) + let self.args += ['added_arg'] + return 1 + endfunction + new + set buftype=nofile + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).' + AssertEqual map(getloclist(0), 'v:val.text'), ['added_arg', '-'] + bwipe + +Execute (stdin maker: supports_stdin can be a callback adding args (maker from command string)): + let maker = neomake#utils#MakerFromCommand('printf "%s\n"') + function maker.supports_stdin(jobinfo) + AssertEqual self.__command_is_string, 1 + let self.args[-1] .= ' added_arg' + return 1 + endfunction + new + set buftype=nofile + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).' + AssertEqual map(getloclist(0), 'v:val.text'), ['added_arg', '-'] + bwipe + +Execute (stdin maker: supports_stdin can be a callback adding args (maker from command list)): + let maker = neomake#utils#MakerFromCommand(['printf', '%s\n']) + function maker.supports_stdin(jobinfo) + AssertEqual self.__command_is_string, 0 + let self.args += ['added_arg'] + return 1 + endfunction + new + set buftype=nofile + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).' + AssertEqual map(getloclist(0), 'v:val.text'), ['added_arg', '-'] + bwipe + +Execute (stdin maker: supports_stdin can be a callback adding args, and setting tempfile_name): + let maker = {'exe': 'printf', 'args': ['%s\n']} + function maker.supports_stdin(jobinfo) + let self.args += ['added_arg', '%:p'] + let self.tempfile_name = 'custom_tempfile' + return 1 + endfunction + let fname = tempname() + new + exe 'file '.fname + set buftype=nofile + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using stdin for unreadable buffer (custom_tempfile).' + AssertEqual map(getloclist(0), 'v:val.text'), ['added_arg', fname, 'custom_tempfile'] + bwipe + +Execute (stdin maker: supports_stdin can be a callback returning 0): + let maker = {'exe': 'printf', 'args': ['%s\n']} + function maker.supports_stdin(jobinfo) + return 0 + endfunction + new + set buftype=nofile + CallNeomake 1, [maker] + AssertNeomakeMessage '\v^Using tempfile for unnamed buffer: "(.*)".$' + let tempfile_name = g:neomake_test_matchlist[1] + AssertEqual map(getloclist(0), 'v:val.text'), [tempfile_name] + bwipe + +Execute (stdin maker: supports_stdin can be a callback returning 0 and change args): + let maker = {'exe': 'printf', 'args': ['%s\n']} + function maker.supports_stdin(jobinfo) + let self.args += ['added_arg'] + return 0 + endfunction + new + set buftype=nofile + CallNeomake 1, [maker] + AssertNeomakeMessage '\v^Using tempfile for unnamed buffer: "(.*)".$' + let tempfile_name = g:neomake_test_matchlist[1] + AssertEqual map(getloclist(0), 'v:val.text'), ['added_arg', tempfile_name] + bwipe + +Execute (stdin maker: uses neomake#utils#get_buffer_lines for buffer_lines): + let maker = {'exe': 'cat', 'supports_stdin': 1} + new + set buftype=nofile + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).' + AssertEqual map(getloclist(0), 'v:val.text'), [] + + normal! o + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), 'v:val.text'), ['', ''] + bwipe + +Execute (stdin maker: does not use buffer's cwd by default): + let maker = {'exe': 'true', 'supports_stdin': 1} + let fname = tempname() + new + exe 'file '.fname + + CallNeomake 1, [maker] + AssertNeomakeMessage printf('cwd: %s.', getcwd()), 3 + + CallNeomake 0, [extend(copy(maker), {'uses_filename': 1})] + AssertNeomakeMessage printf('cwd: %s.', getcwd()), 3 + + let maker.cwd = '.' + CallNeomake 1, [maker] + AssertNeomakeMessage printf('cwd: %s.', getcwd()), 3 + bwipe + +Execute (stdin maker: can use buffer's cwd): + let maker = {'exe': 'cat', 'name': 'flake8'} + function maker.supports_stdin(jobinfo) abort + call a:jobinfo.cd('%:h') + return 1 + endfunction + let fname = tempname() + new + exe 'file '.fname + + let orig_cwd = getcwd() + + CallNeomake 1, [maker] + AssertNeomakeMessage printf('cwd: %s (changed).', fnamemodify(fname, ':h')), 3 + AssertEqual orig_cwd, getcwd() + + CallNeomake 0, [extend(copy(maker), {'uses_filename': 1})] + AssertNeomakeMessage printf('cwd: %s (changed).', fnamemodify(fname, ':h')), 3 + + " Can be set using config (absolute). + let b:neomake_flake8_cwd = orig_cwd + CallNeomake 1, [maker] + AssertNeomakeMessage printf('jobinfo.cd(): keeping cwd from setting: %s.', string(orig_cwd)) + AssertNeomakeMessage printf('cwd: %s.', getcwd()), 3 + + " Can be set using config (relative). + let b:neomake_flake8_cwd = '.' + CallNeomake 1, [maker] + AssertNeomakeMessage "jobinfo.cd(): keeping cwd from setting: '.'." + AssertNeomakeMessage printf('cwd: %s.', getcwd()), 3 + + " Overridden by conf. + let maker.cwd = '..' + CallNeomake 1, [maker] + AssertNeomakeMessage printf('cwd: %s.', getcwd()), 3 + + unlet b:neomake_flake8_cwd + let maker.cwd = '.' + CallNeomake 1, [maker] + AssertNeomakeMessage printf('cwd: %s.', getcwd()), 3 + bwipe + +Execute (stdin maker: can always use stdin): + let maker = { + \ 'name': 'stdin_maker', + \ 'exe': 'cat', + \ 'uses_stdin': 1, + \ 'errorformat': '%f:%m'} + new + call setline(1, ['file1.test:line1', 'file1.test:line2']) + + CallNeomake 1, [maker] + + AssertNeomakeMessage 'Using uses_stdin (1) from setting.', 3 + + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: cat -.", 2 + NeomakeTestsWaitForFinishedJobs + endif + AssertNeomakeMessage 'cwd: '.getcwd().'.', 3 + AssertNeomakeMessage '\moutput on stdout: [''file1.test:line1.*' + AssertNeomakeMessage '\vUsed bufnr from stdin buffer (\d+) \(file1.test\) for 2 entries: 1, 2.' + let tempbuf = g:neomake_test_matchlist[1] + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line2'] + AssertNeomakeMessage "Wiping out 1 unlisted/remapped buffers: ['".tempbuf."']." + + " uses_stdin can be changed via settings. + call neomake#config#set('b:uses_stdin', 0) + call neomake#config#set('b:stdin_maker.exe', 'true') + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using uses_stdin (0) from setting.', 3 + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: true.", 2 + else + AssertNeomakeMessage "Starting [string]: true.", 2 + endif + AssertEqual map(getloclist(0), 'v:val.text'), [] + + " tempfile_name can be changed via settings. + " NOTE: vim81 fails with "Vim(call):E631: ch_sendraw(): write failed" if the + " process does not have stdin open. + call neomake#config#set('b:uses_stdin', 1) + call neomake#config#set('b:tempfile_name', '-') + call neomake#config#set('b:stdin_maker.exe', 'cat') + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using uses_stdin (1) from setting.', 3 + AssertNeomakeMessage "Using setting tempfile_name='-' from 'buffer'.", 3 + if neomake#has_async_support() + AssertNeomakeMessage 'Starting async job: cat -.', 2 + else + AssertNeomakeMessage "Starting [string]: cat -.", 2 + endif + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line2'] + bwipe! + +Execute (stdin maker: can always use stdin (append_file=0, not setting uses_filename)): + let maker = { + \ 'name': 'stdin_maker', + \ 'exe': 'cat', + \ 'args': ['-'], + \ 'uses_stdin': 1, + \ 'append_file': 0, + \ 'errorformat': '%f:%m'} + new + call setline(1, ['file1.test:line1', 'file1.test:line2']) + + CallNeomake 1, [maker] + + AssertNeomakeMessage 'Using uses_stdin (1) from setting.', 3 + + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: cat -.", 2 + NeomakeTestsWaitForFinishedJobs + endif + AssertNeomakeMessage 'cwd: '.getcwd().'.', 3 + AssertNeomakeMessage '\moutput on stdout: [''file1.test:line1.*' + AssertNeomakeMessage '\vUsed bufnr from stdin buffer (\d+) \(file1.test\) for 2 entries: 1, 2.' + let tempbuf = g:neomake_test_matchlist[1] + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line2'] + AssertNeomakeMessage "Wiping out 1 unlisted/remapped buffers: ['".tempbuf."']." + + " uses_stdin can be changed via settings. + call neomake#config#set('b:uses_stdin', 0) + call neomake#config#set('b:stdin_maker.exe', 'true') + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using uses_stdin (0) from setting.', 3 + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: true -.", 2 + else + AssertNeomakeMessage "Starting [string]: true -.", 2 + endif + AssertEqual map(getloclist(0), 'v:val.text'), [] + + " tempfile_name can be changed via settings. + " NOTE: vim81 fails with "Vim(call):E631: ch_sendraw(): write failed" if the + " process does not have stdin open. + call neomake#config#set('b:uses_stdin', 1) + call neomake#config#set('b:tempfile_name', '-') + call neomake#config#set('b:stdin_maker.exe', 'cat') + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using uses_stdin (1) from setting.', 3 + AssertNeomakeMessage "Using setting tempfile_name='-' from 'buffer'.", 3 + if neomake#has_async_support() + AssertNeomakeMessage 'Starting async job: cat -.', 2 + else + AssertNeomakeMessage "Starting [string]: cat -.", 2 + endif + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line2'] + bwipe! + +Execute (supports_stdin can be a setting): + new + let b:neomake_mymaker_supports_stdin = 1 + let maker = neomake#create_maker_object({'name': 'mymaker'}, 'vim') + let jobinfo = NeomakeTestsFakeJobinfo() + AssertEqual maker._get_fname_for_buffer(jobinfo), '-' + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).', 3 + bwipe + +Execute (supports_stdin: adjusted args get expanded correctly): + new + new + let buf1 = bufnr('%') + let s:tmpdir = fnamemodify(tempname(), ':h') + file testfile + + let maker1 = copy(g:error_maker) + let maker1.serialize = 1 + function maker1.process_output(...) + " Change buffer. + wincmd p + return [] + endfunction + + let maker2 = {'exe': 'echo'} + function maker2.supports_stdin(jobinfo) abort + let self.args += ['%:t'] + return 1 + endfunction + + call neomake#Make(1, [maker1, maker2]) + NeomakeTestsWaitForMessage 'Using stdin for unreadable buffer (-).', 3, {'bufnr': buf1} + wincmd p + NeomakeTestsWaitForFinishedJobs + AssertEqual map(getloclist(0), 'v:val.text'), ['testfile -'] + bwipe + bwipe diff --git a/bundle/neomake/tests/tempfiles.vader b/bundle/neomake/tests/tempfiles.vader new file mode 100644 index 000000000..5b7d103cd --- /dev/null +++ b/bundle/neomake/tests/tempfiles.vader @@ -0,0 +1,791 @@ +Include: include/setup.vader + +Execute (Neomake uses temporary file for unsaved buffer): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + new + norm iline1 + norm oline2 + + let maker = { + \ 'exe': 'cat', + \ 'append_file': 1, + \ 'errorformat': '%m', + \ 'tempfile_enabled': 1, + \ 'default_entry_type': '', + \ } + call neomake#Make(1, [maker]) + if neomake#has_async_support() + let make_info = values(neomake#GetStatus().make_info)[0] + let temp_file = make_info.tempfiles[0] + AssertEqual fnamemodify(temp_file, ':h:h'), fnamemodify(tempname(), ':h') + AssertEqual getfperm(temp_file), 'rw-------' + NeomakeTestsWaitForFinishedJobs + endif + + AssertNeomakeMessage '\vSkipped 2 entries without bufnr: .*\.', 3 + + AssertEqualQf getloclist(0), [{ + \ 'lnum': 0, + \ 'bufnr': 0, + \ 'col': 0, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': '', + \ 'pattern': '', + \ 'text': 'line1'}, + \ { + \ 'lnum': 0, + \ 'bufnr': 0, + \ 'col': 0, + \ 'valid': 1, + \ 'vcol': 0, + \ 'nr': -1, + \ 'type': '', + \ 'pattern': '', + \ 'text': 'line2'}] + + if neomake#has_async_support() + AssertEqual filereadable(temp_file), 0, 'temp_file was removed' + AssertNeomakeMessage 'Removing temporary file: "'.temp_file.'".' + else + AssertEqual len(filter(copy(g:neomake_test_messages), "v:val[1] =~# '^Removing temporary file:'")), 1, 'msg found' + endif + bwipe! + +Execute (Uses temporary file for unreadable buffer): + new + file doesnotexist + set ft=neomake_tests + let b:neomake_neomake_tests_enabled_makers = ['true'] + let b:neomake_neomake_tests_true_tempfile_enabled = 1 + + if exists('*setfperm') + let s:validated = 0 + function! s:validate_tempfile() + let s:validated = 1 + let tempfile = g:neomake_hook_context.jobinfo.tempfile + AssertEqual getfperm(tempfile), 'rw-------' + endfunction + augroup neomake_tests + au User NeomakeJobFinished call s:validate_tempfile() + augroup END + endif + + RunNeomake + + AssertNeomakeMessage '\v^Using tempfile for unreadable buffer: "(.*)"', 3 + let tempfile_name = g:neomake_test_matchlist[1] + AssertEqual fnamemodify(tempfile_name, ':t'), printf( + \ '.doesnotexist@neomake_%d_%d', getpid(), neomake#GetStatus().last_make_id) + AssertEqual fnamemodify(tempfile_name, ':h'), getcwd() + if exists('*setfperm') + AssertEqual s:validated, 1 + endif + bwipe + +Execute (Uses permissions of original file): + if !exists('*setfperm') + NeomakeTestsSkip 'no setfperm support.' + else + new + let fname = tempname() + call writefile([], fname) + call setfperm(fname, '---rw----') + exe 'edit '.fname + + silent normal! O + + set ft=neomake_tests + let b:neomake_neomake_tests_enabled_makers = ['true'] + let b:neomake_neomake_tests_true_tempfile_enabled = 1 + + let s:validated = 0 + function! s:validate_tempfile() + let tempfile = g:neomake_hook_context.jobinfo.tempfile + AssertEqual getfperm(tempfile), '---rw----' + let s:validated = 1 + endfunction + augroup neomake_tests + au User NeomakeJobFinished call s:validate_tempfile() + augroup END + + RunNeomake + + AssertNeomakeMessage '\v^Using tempfile for modified buffer: "(.*)"', 3 + let tempfile_name = g:neomake_test_matchlist[1] + AssertEqual glob(tempfile_name), '' + AssertEqual s:validated, 1 + + AssertEqual v:warningmsg, 'W10: Warning: Changing a readonly file' + let v:warningmsg = '' + bwipe! + endif + +Execute (Only 2nd maker uses temporary file): + call g:NeomakeSetupAutocmdWrappers() + + new + file doesnotexist.ext.ext2 + + let maker1 = { + \ 'exe': 'true', + \ 'name': 'true_maker', + \ 'errorformat': '%m', + \ 'append_file': 0, + \ 'tempfile_enabled': 1, + \ } + let maker2 = copy(maker1) + let maker2.append_file = 1 + let maker3 = copy(maker1) + + let fname = fnamemodify(bufname('%'), ':p') + call neomake#Make(1, [maker1, maker2, maker3]) + let make_id = neomake#GetStatus().last_make_id + + let bufnr = bufnr('%') + AssertNeomakeMessage '\v^Using tempfile for unreadable buffer: "(.*)"', 3 + let tempfile_name = g:neomake_test_matchlist[1] + AssertEqual fnamemodify(tempfile_name, ':t'), printf( + \ '.doesnotexist.ext.ext2@neomake_%d_%d.ext2', getpid(), neomake#GetStatus().last_make_id) + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 3 + bwipe + +Execute (Maker can specify temporary file to use via fn): + Save g:neomake_test_tempfile + let g:neomake_test_tempfile = tempname() . '/injected/with/subdir' + + let maker = { + \ 'exe': 'true', + \ } + function! maker.fn(jobinfo) abort dict + let self.tempfile_name = g:neomake_test_tempfile + endfunction + + new + file unreadable_and_modified + normal! iline1 + let bufnr = bufnr('%') + let maker = neomake#GetMaker(maker) + AssertEqual maker.args, [] + let jobinfo = NeomakeTestsFakeJobinfo() + call maker.fn(jobinfo) + + AssertEqual maker.args, [] + call maker._get_argv(jobinfo) + AssertEqual maker.args, [] + AssertEqual maker.tempfile_name, g:neomake_test_tempfile + AssertNeomakeMessage '\m^Using tempfile for modified buffer: "'.g:neomake_test_tempfile.'"', 3, jobinfo + Assert filereadable(g:neomake_test_tempfile), 'tempfile has been created' + let make_info = values(neomake#GetStatus().make_info)[0] + AssertEqual make_info.tempfiles, [maker.tempfile_name] + AssertEqual readfile(g:neomake_test_tempfile), ['line1'] + bwipe! + +Execute (Maker can use '-' as temporary filename): + let maker = { + \ 'exe': 'true', + \ 'tempfile_name': '-', + \ } + + new + let maker = neomake#GetMaker(maker) + let jobinfo = NeomakeTestsFakeJobinfo() + if neomake#has_async_support() + AssertEqual maker._get_argv(jobinfo), ['true', '-'] + else + AssertEqual maker._get_argv(jobinfo), 'true -' + endif + AssertNeomakeMessage 'Using tempfile for unnamed buffer: "-".', 3 + Assert !has_key(jobinfo, 'supports_stdin') + AssertEqual jobinfo.tempfile, fnamemodify('-', ':p') + CallNeomake 1, [maker] + AssertNeomakeMessage printf('Removing temporary file: "%s".', jobinfo.tempfile) + bwipe + +Execute (Maker cannot use '-' as tempfile_name (with supports_stdin)): + let maker = { + \ 'exe': 'true', + \ 'supports_stdin': 1, + \ 'tempfile_name': '-', + \ } + + new + let maker = neomake#GetMaker(maker) + let jobinfo = NeomakeTestsFakeJobinfo() + if neomake#has_async_support() + AssertEqual maker._get_argv(jobinfo), ['true', '-'] + else + AssertEqual maker._get_argv(jobinfo), 'true -' + endif + AssertNeomakeMessage 'Using stdin for unnamed buffer (-).', 3 + AssertEqual jobinfo.uses_stdin, 1 + Assert !has_key(jobinfo, 'tempfile') + + CallNeomake 1, [maker] + bwipe + +Execute (Maker can use '' as tempfile_name (with supports_stdin)): + let maker = { + \ 'exe': 'true', + \ 'supports_stdin': 1, + \ 'tempfile_name': '', + \ } + + new + let maker = neomake#GetMaker(maker) + let jobinfo = NeomakeTestsFakeJobinfo() + if neomake#has_async_support() + AssertEqual maker._get_argv(jobinfo), ['true'] + else + AssertEqual maker._get_argv(jobinfo), 'true' + endif + AssertNeomakeMessage 'Using stdin for unnamed buffer ().', 3 + AssertEqual jobinfo.uses_stdin, 1 + Assert !has_key(jobinfo, 'tempfile') + bwipe + +Execute (Previously existing temporary dir is kept): + let tempname = tempname() + call mkdir(tempname, '', 0700) + let tempfile_name = tempname.'/injected/with/subdir and spaces' + let maker = { + \ 'exe': 'true', + \ 'tempfile_name': tempfile_name, + \ } + + new + normal! iline1 + + call neomake#Make(1, [maker]) + if neomake#has_async_support() + Assert filereadable(tempfile_name), 'tempfile has been created' + AssertEqual readfile(tempfile_name), ['line1'] + endif + + AssertNeomakeMessage 'Using tempfile for unnamed buffer: "'.tempfile_name.'".', 3 + NeomakeTestsWaitForFinishedJobs + if neomake#has_async_support() + AssertNeomakeMessage printf("Starting async job: true '%s'.", tempfile_name) + else + AssertNeomakeMessage printf("Starting [string]: true '%s'.", tempfile_name) + endif + AssertNeomakeMessage 'Removing temporary file: "'.tempfile_name.'".' + Assert !filereadable(tempfile_name), 'tempfile has been removed' + Assert isdirectory(tempname), 'tempfile dir has not been removed' + + if v:version >= 705 || (v:version == 704 && has('patch1107')) + Assert !isdirectory(tempname.'/injected'), 'first created tempfile dir has been removed' + else + Assert isdirectory(tempname.'/injected'), 'tempfile dirs are not removed' + endif + bwipe! + +Execute (maker._get_argv uses jobinfo for bufnr): + let maker = neomake#GetMaker({'name': 'my_maker', 'append_file': 1}) + + new + let b:neomake_tempfile_enabled = 1 + let bufnr = bufnr('%') + let jobinfo = NeomakeTestsFakeJobinfo() + call maker._get_argv(jobinfo) + let make_info = values(neomake#GetStatus().make_info)[0] + Assert !empty(make_info.tempfiles), 'make_info has tempfiles' + + let jobinfo = NeomakeTestsFakeJobinfo() + let maker = neomake#GetMaker({'name': 'my_maker', 'append_file': 1}) + edit tests/fixtures/errors.py + call maker._get_argv(jobinfo) + Assert !has_key(jobinfo, 'tempfile_name') + + wincmd p + let jobinfo = NeomakeTestsFakeJobinfo() + let jobinfo.bufnr = bufnr + + let expected = ['my_maker', fnameescape(fnamemodify(bufname(bufnr), ':.'))] + if neomake#has_async_support() + AssertEqual expected, maker._get_argv(jobinfo) + else + AssertEqual join(expected), maker._get_argv(jobinfo) + endif + wincmd p + bwipe + +Execute (_get_fname_for_buffer handles modified buffer with disabled tempfiles): + new + let bufname = 'tests/fixtures/a filename with spaces' + edit tests/fixtures/a\ filename\ with\ spaces + let b:neomake_tempfile_enabled = 0 + set modified + let maker = neomake#GetMaker({}) + let jobinfo = NeomakeTestsFakeJobinfo() + let caught = 0 + try + call maker._get_fname_for_buffer(jobinfo) + catch + let caught = 1 + AssertEqual v:exception, 'Neomake: skip_job: buffer is modified, but temporary files are disabled.' + endtry + AssertEqual caught, 1 + bwipe! + +Execute (_get_fname_for_buffer does not add trailing newline): + new + let maker = neomake#GetMaker({}) + let jobinfo = NeomakeTestsFakeJobinfo() + let b:neomake_tempfile_enabled = 1 + call maker._get_fname_for_buffer(jobinfo) + let make_info = values(neomake#GetStatus().make_info)[0] + let temp_file = make_info.tempfiles[0] + AssertEqual readfile(make_info.tempfiles[0]), [] + + let jobinfo = NeomakeTestsFakeJobinfo() + let make_info = values(neomake#GetStatus().make_info)[0] + normal! iline1 + call maker._get_fname_for_buffer(jobinfo) + AssertEqual readfile(make_info.tempfiles[0]), ['line1'] + bwipe! + +Execute (same tempfile is used for all jobs (serialized)): + if NeomakeAsyncTestsSetup() + new + let maker = NeomakeTestsCommandMaker('echo_file', 'cat') + let maker.append_file = 1 + let maker2 = NeomakeTestsCommandMaker('echo_file', 'cat') + let maker2.append_file = 1 + let maker2.tempfile_name = tempname() + let b:neomake_tempfile_enabled = 1 + let b:neomake_serialize = 1 + normal! iline1 + AssertEqual len(g:neomake_test_jobfinished), 0 + + call neomake#Make(1, [maker, g:sleep_maker, maker2, maker, g:sleep_maker]) + let make_info = values(neomake#GetStatus().make_info)[0] + NeomakeTestsWaitForNextFinishedJob + normal! oline2 + NeomakeTestsWaitForNextFinishedJob + + AssertNotEqual make_info.tempfiles, [maker2.tempfile_name] + AssertEqual readfile(make_info.tempfiles[0]), readfile(maker2.tempfile_name) + + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), 5 + + AssertEqual [ + \ 'cat '.make_info.tempfiles[0], + \ 'sleep .05; echo slept', + \ 'cat '.maker2.tempfile_name, + \ 'cat '.make_info.tempfiles[0], + \ 'sleep .05; echo slept'], map(copy(g:neomake_test_jobfinished), + \ 'v:val.jobinfo.argv[-1]') + + AssertEqual map(getloclist(0), 'v:val.text'), + \ ['line1', 'slept', 'line1', 'line1', 'slept'] + bwipe! + endif + +Execute (same tempfile contents is used for all jobs): + if NeomakeAsyncTestsSetup() + new + let b:neomake_serialize = 1 + let b:neomake_tempfile_enabled = 1 + let maker1 = {'name': 'maker1', 'exe': 'cat', 'append_file': 1} + let maker2 = {'name': 'maker2', 'exe': 'cat', 'append_file': 1} + + Save g:maker2_tempfile + let g:maker2_tempfile = tempname() + function! maker2.InitForJob(jobinfo) + let self.tempfile_name = g:maker2_tempfile + endfunction + + Save g:maker2_tempfile_contents, g:global_tempfile_contents + augroup neomake_tests + autocmd User NeomakeJobFinished + \ let m = g:neomake_hook_context.jobinfo.maker + \ | if m.name == 'maker2' + \ | let g:maker2_tempfile_contents = readfile(m.tempfile_name) + \ | endif + autocmd User NeomakeFinished + \ let make_info = values(neomake#GetStatus().make_info)[0] + \ | let g:global_tempfile_contents = readfile(make_info.tempfiles[0]) + augroup END + + normal! iline1 + + call neomake#Make(1, [maker1, maker2]) + let make_info = values(neomake#GetStatus().make_info)[0] + + normal! oline2 + let g:neomake_test_messages = [] + NeomakeTestsWaitForFinishedJobs + let jobinfo1 = g:neomake_test_jobfinished[0].jobinfo + let jobinfo2 = g:neomake_test_jobfinished[1].jobinfo + + AssertEqual len(g:neomake_test_jobfinished), 2 + AssertNeomakeMessage 'Using tempfile for unnamed buffer: "'.g:maker2_tempfile.'".' + + let bound_maker2 = g:neomake_test_jobfinished[1].jobinfo.maker + AssertEqual bound_maker2.tempfile_name, g:maker2_tempfile + AssertNotEqual make_info.tempfiles[0], bound_maker2.tempfile_name + AssertEqual g:global_tempfile_contents, g:maker2_tempfile_contents + AssertEqual make_info.tempfiles, [jobinfo1.filename, jobinfo2.filename] + AssertEqual make_info.tempfiles, [jobinfo1.tempfile, jobinfo2.tempfile] + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line1'] + bwipe! + endif + +Execute (First maker uses actual file, 2nd modified tempfile): + if NeomakeAsyncTestsSetup() + new + edit tests/fixtures/a\ filename\ with\ spaces + + let b:neomake_serialize = 1 + let maker1 = {'name': 'maker1', 'exe': 'cat', 'append_file': 1} + let maker2 = {'name': 'maker2', 'exe': 'cat', 'append_file': 1} + + let maker2.tempfile_name = tempname() + + Save g:maker2_tempfile_contents, g:global_tempfile_contents + augroup neomake_tests + autocmd User NeomakeJobFinished + \ let m = g:neomake_hook_context.jobinfo.maker + \ | if m.name == 'maker2' + \ | let g:maker2_tempfile_contents = readfile(m.tempfile_name) + \ | endif + autocmd User NeomakeFinished + \ let make_info = values(neomake#GetStatus().make_info)[0] + \ | let g:global_tempfile_contents = readfile(make_info.tempfiles[0]) + augroup END + + let b:neomake_tempfile_enabled = 1 + let b:neomake_serialize = 1 + call neomake#Make(1, [maker1, maker2]) + + normal! oline2 + let make_info = values(neomake#GetStatus().make_info)[0] + + let g:neomake_test_messages = [] + NeomakeTestsWaitForFinishedJobs + let jobinfo1 = g:neomake_test_jobfinished[0].jobinfo + let jobinfo2 = g:neomake_test_jobfinished[1].jobinfo + Assert !has_key(jobinfo1, 'tempfile'), 'Job 1 has no tempfile' + + AssertEqual len(g:neomake_test_jobfinished), 2 + AssertNeomakeMessage 'Using tempfile for modified buffer: "'.maker2.tempfile_name.'".' + + let bound_maker2 = g:neomake_test_jobfinished[1].jobinfo.maker + AssertEqual bound_maker2.tempfile_name, maker2.tempfile_name + AssertEqual make_info.tempfiles, [bound_maker2.tempfile_name] + AssertEqual g:global_tempfile_contents, g:maker2_tempfile_contents + AssertEqual make_info.tempfiles, [jobinfo2.filename] + AssertEqual make_info.tempfiles, [jobinfo2.tempfile] + AssertEqual map(getloclist(0), 'v:val.text'), ['line1', 'line1', 'line2'] + bwipe! + endif + +Execute (Existing bufnr is kept with tempfiles): + let maker = NeomakeTestsCommandMaker('echo-error', "printf '%s:1:error'") + let maker.errorformat = '%f:%l:%m' + let maker.append_file = 1 + + new + let bufnr = bufnr('%') + let b:neomake_tempfile_enabled = 1 + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage '\v^Using tempfile for unnamed buffer: "(.*)".$' + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'error'}] + + let tempfile_name = g:neomake_test_matchlist[1] + Assert !bufexists(tempfile_name), 'temporary buffer has been removed' + bwipe + +Execute (Temporary buffer is not wiped if opened): + Save g:neomake_verbose + let g:neomake_verbose = 3 + + let maker = NeomakeTestsCommandMaker('echo-error', 'printf ''%s:1:error\nanother_file:2:another_error''') + let maker.errorformat = '%f:%l:%m' + let maker.append_file = 1 + + new + let bufnr = bufnr('%') + let tempfile_bufnr = bufnr + 1 + let b:neomake_tempfile_enabled = 1 + let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + + " Open the tempfile in a new buffer. + new + AssertNeomakeMessage '\v^Using tempfile for unnamed buffer: "(.*)".$' + let tempfile_name = g:neomake_test_matchlist[1] + Assert !bufexists(tempfile_name), 'temporary buffer does not exist yet' + exe 'e' tempfile_name + + NeomakeTestsWaitForFinishedJobs + wincmd p + + let unlisted_bufnr = bufnr('^another_file$') + AssertNotEqual unlisted_bufnr, -1 + + AssertEqualQf getloclist(0), [ + \ {'lnum': 1, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'error'}, + \ {'lnum': 2, 'bufnr': unlisted_bufnr, 'col': 0, 'valid': 1, 'vcol': 0, + \ 'nr': -1, 'type': 'W', 'pattern': '', 'text': 'another_error'}] + + Assert bufexists(tempfile_name), 'temporary buffer has not been wiped' + bwipe + exe 'bwipe' tempfile_name + exe 'bwipe' unlisted_bufnr + + AssertNeomakeMessageAbsent '\VModified list entry' + AssertNeomakeMessage printf( + \ 'Used bufnr from temporary buffer %d (%s) for 1 entries: 1.', + \ tempfile_bufnr, tempfile_name), 3 + AssertNeomakeMessage 'WARN: seen entries with bufnr different from jobinfo.bufnr ('.bufnr.'): {'''.unlisted_bufnr.''': 1}, current bufnr: '.bufnr.'.' + +Execute (unlisted buffers created for tempfiles get wiped): + if NeomakeAsyncTestsSetup() + new + let maker1 = NeomakeTestsCommandMaker('echo_file 1', 'cat') + let maker1.append_file = 1 + let maker1.tempfile_name = tempname() + let maker1.errorformat = '%f: %m' + let maker2 = NeomakeTestsCommandMaker('echo_file 2', 'cat') + let maker2.append_file = 1 + let maker2.tempfile_name = tempname() + let maker2.errorformat = '%m: %f' + let b:neomake_tempfile_enabled = 1 + let b:neomake_serialize = 1 + call setline(1, maker1.tempfile_name.': '.maker2.tempfile_name) + + call NeomakeTestsSetVimMessagesMarker() + call neomake#Make(1, [maker1, maker2]) + let make_info = values(neomake#GetStatus().make_info)[0] + NeomakeTestsWaitForFinishedJobs + AssertEqual len(g:neomake_test_jobfinished), 2 + + AssertEqual [ + \ 'cat '.maker1.tempfile_name, + \ 'cat '.maker2.tempfile_name], map(copy(g:neomake_test_jobfinished), + \ 'v:val.jobinfo.argv[-1]') + + AssertEqual map(getloclist(0), 'v:val.text'), + \ [maker2.tempfile_name, maker1.tempfile_name] + + AssertNeomakeMessage printf( + \ '\vUsed bufnr from temporary buffer (\d+) \(%s\) for 1 entries: 1.', + \ maker1.tempfile_name) + let buf1 = g:neomake_test_matchlist[1] + AssertNeomakeMessage printf( + \ '\vUsed bufnr from temporary buffer (\d+) \(%s\) for 1 entries: 1.', + \ maker2.tempfile_name) + let buf2 = g:neomake_test_matchlist[1] + + AssertNeomakeMessage printf('Wiping out 2 unlisted/remapped buffers: [%d, %d].', buf1, buf2), 3 + AssertEqual NeomakeTestsGetVimMessages(), [] + + Assert !bufexists(maker1.tempfile_name) + Assert !bufexists(maker2.tempfile_name) + bwipe! + endif + +Execute (Handles tempfiles for bufnames with brackets): + let maker = NeomakeTestsCommandMaker('echo-error', "echo 1:msg") + let maker.errorformat = '%l:%m %f' + let maker.append_file = 1 + + new + exe 'file \[fname-with-brackets\]' + let bufnr = bufnr('%') + let b:neomake_tempfile_enabled = 1 + + call neomake#Make(1, [maker]) + NeomakeTestsWaitForFinishedJobs + + AssertNeomakeMessage '\v^Using tempfile for unreadable buffer: "(.*)".$' + let tempfile_name = g:neomake_test_matchlist[1] + let tempfile_relname = fnamemodify(tempfile_name, ':.') + Assert stridx(tempfile_name, getcwd().neomake#utils#Slash().'.[fname-with-brackets]') == 0, 'tempfile_name is correct' + let tempfile_bufnr = bufnr+1 + + AssertNeomakeMessage printf( + \ 'Used bufnr from temporary buffer %d (%s) for 1 entries: 1.', + \ tempfile_bufnr, tempfile_relname) + AssertNeomakeMessage printf( + \ 'Wiping out 1 unlisted/remapped buffers: [%d].', tempfile_bufnr) + AssertEqualQf getloclist(0), [{ + \ 'lnum': 1, 'bufnr': bufnr, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, + \ 'type': 'W', 'pattern': '', 'text': 'msg'}] + + Assert !bufexists(tempfile_bufnr), 'temporary buffer has been removed' + bwipe + +Execute (Uses temporary dir for non-writable directory): + new + file /non-writable-dir/file + let b:neomake_tempfile_enabled = 1 + norm! iline1 + CallNeomake 1, [extend(copy(g:true_maker), {'uses_filename': 1})] + AssertNeomakeMessage 'Running makers: true-maker.', 3 + AssertNeomakeMessage 'Using temporary directory for non-writable parent directory.', 3 + bwipe! + +Execute (Expands % in cwd according to actual file): + let tmpdir = tempname() + call mkdir(tmpdir, 'p', 0550) + new + exe 'file '.tmpdir.'/file' + let b:neomake_tempfile_enabled = 1 + norm! iline1 + let maker = {'exe': 'pwd', 'cwd': '%:h', 'uses_filename': 1, 'append_file': 0} + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using temporary directory for non-writable parent directory.', 3 + AssertNeomakeMessage printf('cwd: %s (changed).', tmpdir) + AssertEqual map(getloclist(0), 'v:val.text'), [tmpdir] + bwipe! + +Execute (Expands % in args according to actual file, and replaces %t with tempfile (list)): + let tmpdir = tempname() + call mkdir(tmpdir, 'p', 0550) + new + exe 'file '.tmpdir.'/file' + let b:neomake_tempfile_enabled = 1 + norm! iline1 + let maker = {'exe': 'printf', 'args': ['%s\n', '%:h', '%t'], 'uses_filename': 1, 'append_file': 0} + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using temporary directory for non-writable parent directory.', 3 + AssertNeomakeMessage '\v^Using tempfile for modified buffer: "(.*)"', 3 + let tempfile_name = g:neomake_test_matchlist[1] + AssertEqual map(getloclist(0), 'v:val.text'), [tmpdir, tempfile_name] + bwipe! + +Execute (Does not expand % in args as string): + let tmpdir = tempname() + call mkdir(tmpdir, 'p', 0550) + new + exe 'file '.tmpdir.'/file' + let b:neomake_tempfile_enabled = 1 + norm! iline1 + let maker = {'exe': 'printf', 'args': '%s %:h', 'uses_filename': 1, 'append_file': 0} + CallNeomake 1, [maker] + AssertNeomakeMessage 'Using temporary directory for non-writable parent directory.', 3 + AssertEqual map(getloclist(0), 'v:val.text'), ['%:h'] + bwipe! + +Execute (Warns when removal of tempfiles fails): + if neomake#has_async_support() + new + let maker = {'exe': 'true'} + call neomake#Make(1, [maker]) + AssertNeomakeMessage '\v^Using tempfile for unnamed buffer: "(.*)"', 3 + let tempfile_name = g:neomake_test_matchlist[1] + call delete(tempfile_name) + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage printf('Failed to remove temporary file: "%s" (-1).', tempfile_name), 1 + bwipe + else + NeomakeTestsSkip 'no async support.' + endif + +Execute (Filemode maker with tempfile_enabled=0 gets not run on modified buffer): + call g:NeomakeSetupAutocmdWrappers() + + new + file fname + set modified + let maker1 = {'name': 'maker1', 'exe': 'true', 'tempfile_enabled': 0} + let maker2 = {'name': 'maker2', 'exe': 'true'} + CallNeomake 1, [maker1, maker2] + AssertEqual len(g:neomake_test_finished), 1 + AssertEqual len(g:neomake_test_jobfinished), 1 + + AssertNeomakeMessage 'Skipping job: buffer is modified, but temporary files are disabled.', 3 + bwipe! + +Execute (Massages tempfile buffer with file_mode=0 and append_file=1): + new + let maker = {'exe': 'echo', 'args': ['error']} + let maker.errorformat = '%m %f' + let maker.append_file = 1 + CallNeomake 0, [maker] + AssertNeomakeMessage '\VUsing tempfile for unnamed buffer:', 3 + AssertEqual map(getqflist(), '[v:val.text, v:val.bufnr]'), [['error', bufnr('%')]] + bwipe + +Execute (Maps/sets bufnr via filename from temporary file): + new + let maker = {'exe': 'echo', 'args': ['']} + + function maker.process_output(context) + let tempfile = a:context.output[0][1:] + return [{'filename': tempfile, 'lnum': 1, 'text': 'err'}] + endfunction + + CallNeomake 1, [maker] + + AssertEqual map(getloclist(0), '[v:val.bufnr, v:val.lnum, v:val.text]'), + \ [[bufnr('%'), 1, 'err']] + + AssertNeomakeMessage 'Mapped 1 bufnrs from temporary files.', 3 + bwipe + +Execute (tempfile_dir can be configured: unnamed buffer): + let slash = neomake#utils#Slash() + let maker = neomake#GetMaker({'tempfile_enabled': 1}) + let temp_base = fnamemodify(tempname(), ':h') + + new + " Unnamed buffer gets tempfile based on tempname(). + let fname = maker._get_tempfilename(NeomakeTestsFakeJobinfo()) + AssertEqual fnamemodify(fname, ':t'), 'neomaketmp.' + AssertEqual fname[:len(temp_base)-1], temp_base + + " Dir can be configured globally. + let b:neomake_tempfile_dir = '/custom/global/dir' + let fname = maker._get_tempfilename(NeomakeTestsFakeJobinfo()) + AssertEqual fname, '/custom/global/dir/neomaketmp.' + + " Dir can be configured per buffer. + let b:neomake_tempfile_dir = '/custom/buffer/dir' + let fname = maker._get_tempfilename(NeomakeTestsFakeJobinfo()) + AssertEqual fname, '/custom/buffer/dir/neomaketmp.' + bwipe + +Execute (tempfile_dir can be configured: named buffer): + let slash = neomake#utils#Slash() + let maker = neomake#GetMaker({'tempfile_enabled': 1}) + + new + file buffer_name.foo.ext + + " Dir can be configured globally. + let b:neomake_tempfile_dir = '/custom/global/dir' + let fname = maker._get_tempfilename(NeomakeTestsFakeJobinfo()) + AssertEqual fname, '/custom/global/dir/buffer_name.foo.ext' + + " Dir can be configured per buffer. + let b:neomake_tempfile_dir = '/custom/buffer/dir' + let fname = maker._get_tempfilename(NeomakeTestsFakeJobinfo()) + AssertEqual fname, '/custom/buffer/dir/buffer_name.foo.ext' + bwipe + +Execute (tempfile_dir gets expanded): + let slash = neomake#utils#Slash() + let maker = neomake#GetMaker({'tempfile_enabled': 1}) + + new + file buffer_name.foo.ext + + let b:neomake_tempfile_dir = '/custom%:p:h' + let fname = maker._get_tempfilename(NeomakeTestsFakeJobinfo()) + AssertEqual fname, '/custom'.getcwd().slash.'buffer_name.foo.ext' + bwipe diff --git a/bundle/neomake/tests/toggle.vader b/bundle/neomake/tests/toggle.vader new file mode 100644 index 000000000..6cc69b0ed --- /dev/null +++ b/bundle/neomake/tests/toggle.vader @@ -0,0 +1,165 @@ +Include: include/setup.vader + +Execute (Toggle commands): + Save &verbose + + tabnew + call NeomakeTestsSetVimMessagesMarker() + + NeomakeToggle + AssertEqual g:neomake.disabled, 1 + AssertEqual neomake#config#get_with_source('disabled'), [1, 'global'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (global).'] + + NeomakeToggleTab + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake.disabled, 1 + AssertEqual neomake#config#get_with_source('disabled'), [1, 'tab'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (tab) [global: disabled].'] + + NeomakeToggleBuffer + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake.disabled, 1 + AssertEqual b:neomake.disabled, 1 + AssertEqual neomake#config#get_with_source('disabled'), [1, 'buffer'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (buffer) [tab: disabled] [global: disabled].'] + + NeomakeEnableBuffer + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake.disabled, 1 + AssertEqual b:neomake.disabled, 0 + AssertEqual neomake#config#get_with_source('disabled'), [0, 'buffer'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is enabled (buffer) [tab: disabled] [global: disabled].'] + + NeomakeToggleBuffer + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake.disabled, 1 + AssertEqual b:neomake.disabled, 1 + AssertEqual neomake#config#get_with_source('disabled'), [1, 'buffer'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (buffer) [tab: disabled] [global: disabled].'] + + NeomakeToggleBuffer + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake.disabled, 1 + AssertEqual b:neomake, {} + AssertEqual neomake#config#get_with_source('disabled'), [1, 'tab'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (tab) [global: disabled].'] + + NeomakeEnableTab + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake.disabled, 0 + AssertEqual b:neomake, {} + AssertEqual neomake#config#get_with_source('disabled'), [0, 'tab'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is enabled (tab) [global: disabled].'] + + NeomakeToggleTab + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake.disabled, 1 + AssertEqual b:neomake, {} + AssertEqual neomake#config#get_with_source('disabled'), [1, 'tab'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (tab) [global: disabled].'] + + NeomakeToggleTab + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake, {} + AssertEqual b:neomake, {} + AssertEqual neomake#config#get_with_source('disabled'), [1, 'global'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (global).'] + + NeomakeEnable + AssertEqual g:neomake.disabled, 0 + AssertEqual t:neomake, {} + AssertEqual b:neomake, {} + AssertEqual neomake#config#get_with_source('disabled'), [0, 'global'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is enabled (global).'] + + NeomakeToggle + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake, {} + AssertEqual b:neomake, {} + AssertEqual neomake#config#get_with_source('disabled'), [1, 'global'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (global).'] + + NeomakeDisable + AssertEqual g:neomake.disabled, 1 + AssertEqual t:neomake, {} + AssertEqual b:neomake, {} + AssertEqual neomake#config#get_with_source('disabled'), [1, 'global'] + " No message since it was not changed. + AssertEqual NeomakeTestsGetVimMessages(), [] + + NeomakeToggle + Assert !has_key(g:neomake, 'disabled') + AssertEqual t:neomake, {} + AssertEqual b:neomake, {} + AssertEqual neomake#config#get_with_source('disabled'), + \ [g:neomake#config#undefined, 'default'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is enabled.'] + bwipe + +Execute (NeomakeStatus with disabling commands): + tabnew + call NeomakeTestsSetVimMessagesMarker() + + NeomakeStatus + Assert exists('#neomake'), 'neomake augroup exists' + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is enabled.'] + + NeomakeDisable + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (global).'] + Assert !exists('#neomake'), 'neomake augroup has been removed' + " Can be disabled again (no error when trying to delete augroup). + NeomakeDisable + AssertEqual NeomakeTestsGetVimMessages(), [] + NeomakeStatus + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (global).'] + + NeomakeDisableTab + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (tab) [global: disabled].'] + NeomakeStatus + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (tab) [global: disabled].'] + + silent NeomakeDisableBuffer + AssertEqual NeomakeTestsGetVimMessages(), [] + NeomakeStatus + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (buffer) [tab: disabled] [global: disabled].'] + + NeomakeEnable + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (buffer) [tab: disabled] [global: enabled].'] + Assert exists('#neomake'), 'neomake augroup exists' + NeomakeStatus + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (buffer) [tab: disabled] [global: enabled].'] + bwipe + +Execute (Neomake via autocommand uses 'disabled' setting): + new + NeomakeDisableBuffer + + augroup neomake_tests + autocmd BufWritePost * Neomake + augroup END + doautocmd BufWritePost + AssertNeomakeMessage 'Make through autocommand disabled via buffer.', 3 + bwipe + +Execute (NeomakeBufferEnable after NeomakeDisable): + Save g:neomake + + new + call NeomakeTestsSetVimMessagesMarker() + + NeomakeDisable + try + AssertEqual g:neomake.disabled, 1 + AssertEqual neomake#config#get_with_source('disabled'), [1, 'global'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is disabled (global).'] + + NeomakeEnableBuffer + AssertEqual g:neomake.disabled, 1 + AssertEqual b:neomake.disabled, 0 + AssertEqual neomake#config#get_with_source('disabled'), [0, 'buffer'] + AssertEqual NeomakeTestsGetVimMessages(), ['Neomake is enabled (buffer) [global: disabled].'] + finally + NeomakeEnable + bwipe + endtry diff --git a/bundle/neomake/tests/utils.vader b/bundle/neomake/tests/utils.vader new file mode 100644 index 000000000..3cf5581c7 --- /dev/null +++ b/bundle/neomake/tests/utils.vader @@ -0,0 +1,1148 @@ +Include: include/setup.vader + +Execute (NeomakeTestsCreateExe creates exe): + Assert !executable('boobar'), 'boobar is not executable' + call g:NeomakeTestsCreateExe('boobar', []) + Assert executable('boobar'), 'boobar is now executable' + +Execute (NeomakeTestsCreateExe overrides existing exe): + let true = system('which true') + Assert executable('true'), 'true is now executable' + call g:NeomakeTestsCreateExe('true', []) + AssertNotEqual system('which true'), true + +Execute (neomake#utils#GetSetting serialize): + let s:maker = {'name': 'mymaker'} + function! s:GetSetting() + return neomake#utils#GetSetting('serialize', s:maker, 'default', + \ 'myft', bufnr('%')) + endfunction + + new + " Do not trigger checking new-style config. + Save g:neomake + unlet! g:neomake + + Save g:neomake_serialize, b:neomake_serialize + Save g:neomake_mymaker_serialize, b:neomake_mymaker_serialize + Save g:neomake_myft_mymaker_serialize, b:neomake_myft_mymaker_serialize + + AssertEqual s:GetSetting(), 'default' + + let g:neomake_serialize = 7 + AssertEqual s:GetSetting(), 7 + " maker-only should return default. + AssertEqual neomake#utils#GetSetting('serialize', s:maker, 'default', + \ 'myft', bufnr('%'), 1), 'default' + let g:neomake_serialize = 0 + AssertEqual s:GetSetting(), 0 + let g:neomake_serialize = 99 + AssertEqual s:GetSetting(), 99 + + let b:neomake_serialize = 6 + AssertEqual s:GetSetting(), 6 + let b:neomake_serialize = 0 + AssertEqual s:GetSetting(), 0 + let b:neomake_serialize = 98 + AssertEqual s:GetSetting(), 98 + + let s:maker.serialize = 5 + AssertEqual s:GetSetting(), 5 + let s:maker.serialize = 0 + AssertEqual s:GetSetting(), 0 + let s:maker.serialize = 97 + AssertEqual s:GetSetting(), 97 + + " Falls back correctly to old-style setting with new-style from maker. + let g:neomake = {} + AssertEqual s:GetSetting(), 97 + unlet g:neomake + + let g:neomake_mymaker_serialize = 4 + AssertEqual s:GetSetting(), 4 + let g:neomake_mymaker_serialize = 0 + AssertEqual s:GetSetting(), 0 + let g:neomake_mymaker_serialize = 96 + AssertEqual s:GetSetting(), 96 + + let b:neomake_mymaker_serialize = 3 + AssertEqual s:GetSetting(), 3 + let b:neomake_mymaker_serialize = 0 + AssertEqual s:GetSetting(), 0 + let b:neomake_mymaker_serialize = 95 + AssertEqual s:GetSetting(), 95 + + let g:neomake_myft_mymaker_serialize = 2 + AssertEqual s:GetSetting(), 2 + let g:neomake_myft_mymaker_serialize = 0 + AssertEqual s:GetSetting(), 0 + let g:neomake_myft_mymaker_serialize = 94 + AssertEqual s:GetSetting(), 94 + + let b:neomake_myft_mymaker_serialize = 1 + AssertEqual s:GetSetting(), 1 + let b:neomake_myft_mymaker_serialize = 0 + AssertEqual s:GetSetting(), 0 + unlet b:neomake_myft_mymaker_serialize + let b:neomake_myft_mymaker_serialize = [1] + AssertEqual s:GetSetting(), [1] + + " Uses b:neomake_serialize + let s:maker = {'name': ''} + AssertEqual s:GetSetting(), 98 + let s:maker = {} + AssertEqual s:GetSetting(), 98 + bwipe + +Execute (neomake#utils#GetSetting handles maker-only settings): + new + set filetype=myft + AssertEqual 'default', neomake#utils#GetSetting('exe', {}, 'default', 'myft', bufnr('%')) + let b:neomake_exe = 'buffer_exe' + AssertEqual 'buffer_exe', neomake#utils#GetSetting('exe', {}, 'default', 'myft', bufnr('%')) + AssertEqual 'default', neomake#utils#GetSetting('exe', {}, 'default', 'myft', bufnr('%'), 1) + + let b:neomake_myft_mymaker_maker = {} + AssertEqual neomake#GetMaker('mymaker', 'myft').exe, 'mymaker' + bwipe + +Execute (neomake#utils#GetSetting handles maker-only settings (dict-config)): + new + set filetype=myft + AssertEqual 'default', neomake#utils#GetSetting('exe', {}, 'default', 'myft', bufnr('%')) + let b:neomake = {'exe': 'buffer_exe'} + AssertEqual 'buffer_exe', neomake#utils#GetSetting('exe', {}, 'default', 'myft', bufnr('%')) + AssertEqual 'default', neomake#utils#GetSetting('exe', {}, 'default', 'myft', bufnr('%'), 1) + + call neomake#config#set('b:ft.myft.mymaker.maker', {}) + AssertEqual neomake#GetMaker('mymaker', 'myft').exe, 'mymaker' + call neomake#config#set('b:ft.myft.mymaker.maker', {'exe': 'foo'}) + AssertEqual neomake#GetMaker('mymaker', 'myft').exe, 'foo' + + let maker = {} + AssertEqual neomake#config#get('mymaker.exe', 'default', {'ft': 'myft', 'bufnr': bufnr('%')}), 'default' + let maker = {'exe': 'maker_exe'} + AssertEqual neomake#config#get('mymaker.exe', 'default', {'ft': 'myft', 'bufnr': bufnr('%'), 'maker': maker}), 'default' + let maker = {'name': 'mymaker', 'exe': 'maker_exe'} + AssertEqual neomake#config#get('mymaker.exe', 'default', {'ft': 'myft', 'bufnr': bufnr('%'), 'maker': maker}), 'maker_exe' + bwipe + +Execute (neomake#utils#GetSetting uses old-style g: with bufnr ''): + Save g:neomake_mysetting + let g:neomake_mysetting = 1 + AssertEqual neomake#utils#GetSetting('mysetting', {}, 'default', 'myft', ''), 1 + let g:neomake_myft_mysetting = 2 + AssertEqual neomake#utils#GetSetting('mysetting', {}, 'default', 'myft', ''), 2 + let g:neomake_myft_mymaker_mysetting = 3 + AssertEqual neomake#utils#GetSetting('mysetting', {'name': 'mymaker'}, 'default', 'myft', ''), 3 + +Execute (neomake#utils#GetSetting for multiple fts): + new + function! s:GetSetting(key) + return neomake#utils#GetSetting(a:key, {}, 'default', + \ 'jsx.javascript', bufnr('%')) + endfunction + let b:neomake_jsx_javascript_setting = '1' + AssertEqual s:GetSetting('setting'), '1' + bwipe + +Execute (neomake#utils#GetSetting for multiple fts (new-style)): + new + function! s:GetSetting(key) + return neomake#utils#GetSetting(a:key, {}, 'default', + \ 'jsx.javascript', bufnr('%')) + endfunction + call neomake#config#set_buffer(bufnr('%'), ['ft', 'jsx.javascript', 'setting'], 1) + AssertEqual s:GetSetting('setting'), 1 + call neomake#config#set(['b:ft', 'jsx.javascript', 'setting'], 2) + AssertEqual s:GetSetting('setting'), 2 + let b:neomake = {'ft': {'jsx.javascript': {'setting': 3}}} + AssertEqual s:GetSetting('setting'), 3 + let b:neomake = {'ft': {'jsx': {'setting': 4}}} + AssertEqual s:GetSetting('setting'), 4 + let b:neomake = {'ft': {'javascript': {'setting': 5}}} + AssertEqual s:GetSetting('setting'), 5 + let b:neomake = {'ft': {'javascript.jsx': {'setting': 6}}} + AssertEqual s:GetSetting('setting'), 'default' + bwipe + +Execute (neomake#utils#GetSetting accepts lists): + Save g:maker + let g:maker = {'name': 'mymaker'} + function! s:GetSetting() + return neomake#utils#GetSetting('args', g:maker, 'default', + \ 'myft', bufnr('%')) + endfunction + + Save g:neomake_myft_mymaker_args, b:neomake_myft_mymaker_args + let g:neomake_myft_mymaker_args = [ 'global', 'shallow', 'list' ] + AssertEqual s:GetSetting(), [ 'global', 'shallow', 'list' ] + let b:neomake_myft_mymaker_args = [ 'buffer', 'shallow', 'list' ] + AssertEqual s:GetSetting(), [ 'buffer', 'shallow', 'list' ] + + Save g:maker + Restore + let g:maker = {'name': 'mymaker'} + Save b:neomake_myft_mymaker_args + let b:neomake_myft_mymaker_args = 'string' + AssertEqual s:GetSetting(), 'string' + +Execute (neomake#utils#GetSetting without name): + Save g:maker + let g:maker = {} + function! s:GetSetting(key) + return neomake#utils#GetSetting(a:key, g:maker, [], + \ 'myft', bufnr('%')) + endfunction + AssertEqual s:GetSetting('args'), [] + + Save g:neomake_setting, g:neomake_myft_setting + AssertEqual s:GetSetting('setting'), [] + let g:neomake_setting = 42 + AssertEqual s:GetSetting('setting'), 42 + let g:neomake_myft_setting = {'custom': 1} + AssertEqual s:GetSetting('setting'), {'custom': 1} + +Execute (neomake#utils#GetSetting with new-style config): + new + set ft=neomake_tests + + let b:neomake_neomake_tests_foo = 'bar' + let maker = {'name': 'mymaker', 'foo': 'from-maker'} + AssertEqual neomake#utils#GetSetting( + \ 'foo', maker, -1, 'neomake_tests', bufnr('%')), 'from-maker' + + let b:neomake_neomake_tests_mymaker_foo = 'bar' + AssertEqual neomake#utils#GetSetting( + \ 'foo', maker, -1, 'neomake_tests', bufnr('%')), 'bar' + + " New-style global setting overrides old-style buffer setting! + call neomake#config#set('ft.neomake_tests.foo', 'new_bar') + AssertEqual neomake#utils#GetSetting( + \ 'foo', maker, -1, 'neomake_tests', bufnr('%')), 'new_bar' + AssertNeomakeMessage "Using setting foo='new_bar' from 'global' (prefix: ['ft', 'neomake_tests'])." + + call neomake#config#set('ft.neomake_tests.foo', function('tr')) + AssertEqual neomake#utils#GetSetting( + \ 'foo', maker, -1, 'neomake_tests', bufnr('%')), function('tr') + AssertNeomakeMessage "Using setting foo=function('tr') from 'global' (prefix: ['ft', 'neomake_tests'])." + bwipe + +Execute (neomake#utils#GetSetting does not create a partial for dict funcs): + " Ref: https://github.com/neovim/neovim/issues/7432#issuecomment-338513967 + let maker = {} + function maker.func() + endfunction + + let l:Func = neomake#utils#GetSetting('func', maker, '', '', '', 1) + AssertEqual type(Func), type(function('tr')) + AssertEqual Func, get(maker, 'func') + + let l:Func = neomake#utils#GetSetting('func', maker, '', '', '', 0) + AssertEqual type(Func), type(function('tr')) + AssertEqual Func, get(maker, 'func') + +Execute (neomake#utils#GetSetting (old-style) can ignore buffer): + new + let bufnr = bufnr('%') + noautocmd set filetype=neomake_tests + let b:neomake_foo = 42 + let b:neomake_neomake_tests_foo = 43 + + AssertEqual neomake#utils#GetSetting('foo', {}, 'default', '', bufnr), 42 + AssertEqual neomake#utils#GetSetting('foo', {}, 'default', &ft, bufnr), 43 + + " 0 is the alternate buffer for the current window. + new + AssertEqual neomake#utils#GetSetting('foo', {}, 'default', '', 0), 42 + AssertEqual neomake#utils#GetSetting('foo', {}, 'default', 'neomake_tests', 0), 43 + + " Empty string ignores the buffer. + AssertEqual neomake#utils#GetSetting('foo', {}, 'default', '', ''), 'default' + AssertEqual neomake#utils#GetSetting('foo', {}, 'default', 'neomake_tests', ''), 'default' + bwipe + bwipe + +Execute (neomake#utils#GetSetting prefers g: over maker): + let maker = {'name': 'mymaker', 'uses_stdin': 1} + new + let bufnr = bufnr('%') + + let g:neomake_dockerfile_mymaker_uses_stdin = 0 + + " Old-style. + AssertEqual neomake#utils#GetSetting('uses_stdin', maker, -1, 'dockerfile', bufnr), 0 + + " With existing new-style. + let g:neomake = {} + AssertEqual neomake#utils#GetSetting('uses_stdin', maker, -1, 'dockerfile', bufnr), 0 + + " Handles maker_only=1, i.e. does not use setting without maker prefix. + call neomake#config#set('ft.dockerfile.uses_stdin', 'ignored') + AssertEqual neomake#utils#GetSetting('uses_stdin', maker, -1, 'dockerfile', bufnr, 1), 1 + + " Prefers new-style global setting. + call neomake#config#set('ft.dockerfile.mymaker.uses_stdin', 3) + AssertEqual neomake#utils#GetSetting('uses_stdin', maker, -1, 'dockerfile', bufnr), 3 + bwipe + +Execute(neomake#utils#redir): + command! NeomakeTestCommand echo 1 | echo 2 + command! NeomakeTestErrorCommand echoerr 'error' + AssertEqual neomake#utils#redir('echon 1'), "1" + AssertEqual neomake#utils#redir('echo 1'), "\n1" + AssertEqual neomake#utils#redir('NeomakeTestCommand'), "\n1\n2" + AssertThrows call neomake#utils#redir('NeomakeTestErrorCommand') + if exists('g:vader_exception') + " https://github.com/junegunn/vader.vim/issues/86 + AssertEqual g:vader_exception, 'Vim(echoerr):error' + endif + AssertEqual neomake#utils#redir(['NeomakeTestCommand', 'echon 3']), "\n1\n23" + AssertThrows neomake#utils#redir(['NeomakeTestCommand', 'echoerr 3']) + +Execute(neomake#utils#redir: recursive use without execute()): + if exists('*execute') && has('nvim-0.2.0') + AssertEqual neomake#utils#redir('echon neomake#utils#redir("echon 1")'), '1' + else + AssertThrows call neomake#utils#redir('echon neomake#utils#redir("echon 1")') + AssertEqual g:vader_exception, 'Neomake: neomake#utils#redir: called with outer :redir (error: Vim(redir):E121: Undefined variable: neomake_redir).' + + try + redir => outer_output + AssertThrows call neomake#utils#redir('echon neomake#utils#redir("echon 1")') + AssertEqual g:vader_exception, 'Neomake: neomake#utils#redir: called with outer :redir (error: Vim(redir):E121: Undefined variable: outer_output).' + finally + redir END + endtry + endif + +Execute (neomake#utils#ExpandArgs): + Save $HOME + let $HOME='/home/sweet' + + new + file file1.ext + let isk = &iskeyword + let args = [ + \ '%', + \ '%:h', + \ '%:p:t:r', + \ '%:rt', + \ '--foo=%:h', + \ '%s', + \ '%z', + \ '\%', + \ '%%', + \ '%%NEOMAKE_FILE%%', + \ '%:r.o', + \ '%:r%', + \ '%:r% %', + \ '%%%%', + \ '%%%', + \ '^%$', + \ 'C:\\%\\', + \ 'C:\\%:r\\', + \ '~', + \ '\~', + \ 't/~=+.view.vim', + \ '~/foo', + \ '~/', + \ '~foo', + \ '%:.', + \ '%:,', + \ '%<', + \ ] + let expected_args = [ + \ 'file1.ext', + \ '.', + \ 'file1', + \ 'file1t', + \ '--foo=.', + \ '%s', + \ '%z', + \ '\%', + \ '%', + \ '%NEOMAKE_FILE%', + \ 'file1.o', + \ 'file1file1.ext', + \ 'file1file1.ext file1.ext', + \ '%%', + \ '%file1.ext', + \ '^file1.ext$', + \ 'C:\\file1.ext\\', + \ 'C:\\file1\\', + \ '/home/sweet', + \ '\~', + \ 't/~=+.view.vim', + \ '/home/sweet/foo', + \ '/home/sweet/', + \ '~foo', + \ 'file1.ext', + \ 'file1.ext:,', + \ 'file1', + \ ] + + let jobinfo = {'bufnr': bufnr('%')} + AssertEqual expected_args, neomake#utils#ExpandArgs(args, jobinfo) + AssertEqual isk, &iskeyword + bwipe + +Execute (neomake#utils#ExpandArgs: :S): + if !has('patch-7.4.191') + NeomakeTestsSkip 'Only with 7.4.191+' + else + new + file file1.ext + let jobinfo = {'bufnr': bufnr('%')} + AssertEqual neomake#utils#ExpandArgs(['%:S'], jobinfo), ["'file1.ext'"] + bwipe + endif + +Execute (neomake#utils#ExpandArgs: %t for temporary file): + new + let jobinfo = {'bufnr': bufnr('%')} + AssertEqual neomake#utils#ExpandArgs(['%t'], jobinfo), [''] + + file fname.ext + AssertEqual neomake#utils#ExpandArgs(['%t'], jobinfo), [fnamemodify('fname.ext', ':p')] + + let jobinfo.tempfile = '/some/temp.file' + AssertEqual neomake#utils#ExpandArgs(['%t'], jobinfo), ['/some/temp.file'] + " Does not get fnamemodified. + AssertEqual neomake#utils#ExpandArgs(['%t:h'], jobinfo), ['/some/temp.file:h'] + bwipe + +Execute (neomake#utils#ExpandArgs: from another buffer): + new + file file1.ext + let jobinfo = {'bufnr': bufnr('%')} + new + AssertEqual neomake#utils#ExpandArgs(['%'], jobinfo), ['file1.ext'] + AssertEqual neomake#utils#ExpandArgs(['%:e'], jobinfo), ['ext'] + AssertEqual neomake#utils#ExpandArgs(['foo: %:e'], jobinfo), ['foo: ext'] + bwipe + bwipe + +Execute (neomake#utils#diff_dict): + AssertEqual neomake#utils#diff_dict({}, {}), {} + AssertEqual neomake#utils#diff_dict({'a': 1}, {'a': 2}), + \ {'changed': {'a': [1, 2]}} + AssertEqual neomake#utils#diff_dict({'a': 1}, {'b': 2}), + \ {'removed': {'a': 1}, 'added': {'b': 2}} + AssertEqual neomake#utils#diff_dict({'a': 1}, {'a': 1, 'b': 2}), + \ {'added': {'b': 2}} + + AssertEqual neomake#utils#diff_dict({'a': '1'}, {'a': 1}), + \ {'changed': {'a': ['1', 1]}} + AssertEqual neomake#utils#diff_dict({'a': []}, {'a': {}}), + \ {'changed': {'a': [[], {}]}} + +Execute (neomake#utils#truncate_width): + AssertEqual neomake#utils#truncate_width('', 0), '' + AssertEqual neomake#utils#truncate_width('', -1), '' + + AssertEqual neomake#utils#truncate_width('123', 0), '' + AssertEqual neomake#utils#truncate_width('123', 1), '…' + AssertEqual neomake#utils#truncate_width('123', 1, ''), '1' + AssertEqual neomake#utils#truncate_width('123', 2), '1…' + AssertEqual neomake#utils#truncate_width('123', 3), '123' + AssertEqual neomake#utils#truncate_width('123', 4), '123' + + AssertEqual neomake#utils#truncate_width('长长的。', 0), '' + AssertEqual neomake#utils#truncate_width('长长的。', 1), '…' + AssertEqual neomake#utils#truncate_width('长长的。', 2), '…' + AssertEqual neomake#utils#truncate_width('长长的。', 3), '长…' + AssertEqual neomake#utils#truncate_width('长长的。', 4), '长…' + AssertEqual neomake#utils#truncate_width('长长的。', 10), '长长的。' + + AssertEqual neomake#utils#truncate_width('abc。', 4), 'abc…' + AssertEqual neomake#utils#truncate_width('abc。', 5), 'abc。' + AssertEqual neomake#utils#truncate_width('abc。xyz', 6), 'abc。…' + AssertEqual neomake#utils#truncate_width('abc。xyz', 7), 'abc。x…' + + " Undefined, currently acts as width=0. + AssertEqual neomake#utils#truncate_width('abc', -1), '' + + " Longer ellipsis. + AssertEqual neomake#utils#truncate_width('abc', 0, '...'), '' + AssertEqual neomake#utils#truncate_width('abc', 1, '...'), '' + AssertEqual neomake#utils#truncate_width('abc', 2, '...'), '' + AssertEqual neomake#utils#truncate_width('abc', 3, '...'), 'abc' + AssertEqual neomake#utils#truncate_width('abcde', 4, '...'), 'a...' + +Execute (neomake#utils#sort_by_col): + function! s:sort(l) + call sort(a:l, function('neomake#utils#sort_by_col')) + return a:l + endfunction + + let a = {'col': 1} + let b = {'col': 5} + AssertEqual s:sort([a, b]), [a, b] + norm i1234 + AssertEqual getpos('.')[2], 4, 'position is correct' + AssertEqual s:sort([a, b]), [a, b] + norm a5 + AssertEqual getpos('.')[2], 5, 'position is correct' + AssertEqual s:sort([a, b]), [b, a] + +Execute (neomake#utils#MakerFromCommand splits shell/shellcmdflag): + Save &shell, &shellcmdflag + + let jobinfo = NeomakeTestsFakeJobinfo() + let jobinfo.file_mode = 0 + let jobinfo.bufnr = 0 + + let &shell = '/bin/bash -o pipefail' + let &shellcmdflag = '-c' + let maker = neomake#utils#MakerFromCommand('echo 1') + if neomake#has_async_support() + let expected_argv = ['/bin/bash', '-o', 'pipefail', '-c', 'echo 1'] + else + let expected_argv = "/bin/bash -o pipefail -c 'echo 1'" + endif + AssertEqual maker._get_argv(jobinfo), expected_argv + + let &shell = '/bin/bash' + let &shellcmdflag = '-o pipefail -c' + let maker = neomake#utils#MakerFromCommand('echo 2') + if neomake#has_async_support() + let expected_argv = ['/bin/bash', '-o', 'pipefail', '-c', 'echo 2'] + else + let expected_argv = "/bin/bash -o pipefail -c 'echo 2'" + endif + AssertEqual maker._get_argv(jobinfo), expected_argv + +Execute (neomake#utils#MakerFromCommand copies args): + new + exe 'file file_with_escaped_\%:p' + let maker = neomake#utils#MakerFromCommand('echo "%" 1') + let maker.tempfile_name = 'tempfile' + let jobinfo = NeomakeTestsFakeJobinfo() + let bound_maker = neomake#GetMaker(maker) + let argv = bound_maker._get_argv(jobinfo) + let shell_argv = split(&shell) + split(&shellcmdflag) + if type(argv) == type([]) + AssertEqual argv, shell_argv + ['echo "file_with_escaped_%:p" 1 tempfile'] + else + AssertEqual argv, join(shell_argv)." 'echo \"file_with_escaped_%:p\" 1 tempfile'" + endif + let again_argv = bound_maker._get_argv(jobinfo) + AssertEqual argv, again_argv + bwipe + +Execute (neomake#utils#MakerFromCommand appends args for file_mode (string)): + let maker = neomake#utils#MakerFromCommand('printf "%s\n" "%" 1') + + new + edit tests/fixtures/a\ filename\ with\ spaces + + let jobinfo = NeomakeTestsFakeJobinfo() + let shell_argv = split(&shell) + split(&shellcmdflag) + AssertEqual maker, { + \ '__command_is_string': 1, + \ '_get_argv': get(maker, '_get_argv'), + \ '_get_fname_for_args': get(maker, '_get_fname_for_args'), + \ 'args': shell_argv[1:] + ['printf "%s\n" "%" 1'], + \ 'exe': shell_argv[0], + \ 'remove_invalid_entries': 0} + + let fname = bufname('%') + let jobinfo.maker = maker + let bound_maker = neomake#GetMaker(maker) + AssertEqual bound_maker.args, shell_argv[1:] + ['printf "%s\n" "%" 1'] + AssertEqual bound_maker.exe, shell_argv[0] + AssertEqual bound_maker.remove_invalid_entries, 0 + + call bound_maker._bind_args() + AssertEqual bound_maker.args, shell_argv[1:] + ['printf "%s\n" "%" 1'] + + let argv = bound_maker._get_argv(jobinfo) + if type(argv) == type([]) + AssertEqual argv, shell_argv + ['printf "%s\n" "'.fname.'" 1 ''tests/fixtures/a filename with spaces'''] + else + AssertEqual argv, join(shell_argv).' ''printf "%s\n" "tests/fixtures/a filename with spaces" 1 ''\''''tests/fixtures/a filename with spaces''\''''''' + endif + " self.args is not changed. + AssertEqual bound_maker.args, shell_argv[1:] + ['printf "%s\n" "%" 1'] + + CallNeomake 1, [maker] + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ 'tests/fixtures/a filename with spaces', + \ '1', + \ 'tests/fixtures/a filename with spaces'] + bwipe + +Execute (neomake#utils#MakerFromCommand appends args for file_mode (list)): + let maker = neomake#utils#MakerFromCommand(['echo', '%', '1']) + let jobinfo = {'file_mode': 0, 'bufnr': bufnr('%'), 'ft': ''} + + AssertEqual maker, { + \ '__command_is_string': 0, + \ '_get_argv': get(maker, '_get_argv'), + \ '_get_fname_for_args': get(maker, '_get_fname_for_args'), + \ 'args': ['%', '1'], + \ 'exe': 'echo', + \ 'remove_invalid_entries': 0} + + new + edit tests/fixtures/a\ filename\ with\ spaces + let fname = bufname('%') + let jobinfo = NeomakeTestsFakeJobinfo() + let jobinfo.maker = maker + let bound_maker = neomake#GetMaker(maker) + AssertEqual bound_maker.args, ['%', '1'] + AssertEqual bound_maker.exe, 'echo' + AssertEqual bound_maker.remove_invalid_entries, 0 + + let argv = bound_maker._get_argv(jobinfo) + if type(argv) == type([]) + AssertEqual argv, ['echo', fname, '1', fname] + else + AssertEqual argv, printf("echo '%s' 1 '%s'", fname, 'tests/fixtures/a filename with spaces') + endif + AssertEqual bound_maker.args, ['%', '1'] + + CallNeomake 0, [maker] + AssertEqual getqflist()[0].text, 'tests/fixtures/a filename with spaces 1' + bwipe + +Execute (neomake#utils#MakerFromCommand calls _get_fname_for_buffer once): + let maker = neomake#utils#MakerFromCommand(['echo', '%', '1']) + let maker.tempfile_enabled = 1 + let maker.append_file = 1 + let maker.uses_filename = 1 + new + file bufname + setlocal modified + CallNeomake 1, [maker] + AssertNeomakeMessage '\v^Using tempfile for modified buffer: "(.*)".$' + let tempfile_name = g:neomake_test_matchlist[1] + AssertEqual len(filter(copy(g:neomake_test_messages), "v:val[1] =~ '^Using tempfile '")), 1 + AssertEqual map(getloclist(0), 'v:val.text'), [ + \ printf('bufname 1 %s', fnamemodify(tempfile_name, ':.'))] + bwipe! + +Execute (neomake#utils#Stringify): + AssertEqual neomake#utils#Stringify(1), 1 + AssertEqual neomake#utils#Stringify('2'), '2' + AssertEqual neomake#utils#Stringify([1, [2, 3]]), '[1, [2, 3]]' + AssertEqual neomake#utils#Stringify([1, function('tr')]), "[1, function('tr')]" + + let obj = {'k': 'v'} + function! obj.f(args) abort dict + endfunction + + let fnr_base = substitute(string(obj.f), '\v.*''(\d+)''.*', '\1', '') + AssertEqual neomake#utils#Stringify(obj), "{f: function('".fnr_base."'), k: v}" + + let base = {'base': 1} + function! base.f2(arg) abort dict + return a:arg + endfunction + + let string_displays_partial = has('patch-7.4.1608') + + let obj = {} + let obj.f2 = base.f2 + AssertEqual obj.f2('called1'), 'called1' + if string_displays_partial + AssertEqual neomake#utils#Stringify(obj), "{f2: function('".(fnr_base + 1)."', {…})}" + else + AssertEqual neomake#utils#Stringify(obj), "{f2: function('".(fnr_base + 1)."')}" + endif + + AssertEqual base.f2('called2'), 'called2' + AssertEqual neomake#utils#Stringify(base), "{f2: function('".(fnr_base + 1)."'), base: 1}" + + let obj = copy(base) + AssertEqual obj.f2, base.f2 + let obj.base = 0 + AssertEqual neomake#utils#Stringify(obj), "{f2: function('".(fnr_base + 1)."'), base: 0}" + if string_displays_partial + " Uses string() for 7.4.1689. + AssertNotEqual string(obj.f2), string(base.f2) + else + AssertEqual obj.f2, base.f2 + endif + + let obj.f2 = base.f2 + if string_displays_partial + AssertEqual neomake#utils#Stringify(obj.f2), "function('".(fnr_base + 1)."', ".string(obj).")" + else + AssertEqual neomake#utils#Stringify(obj.f2), "function('".(fnr_base + 1)."')" + endif + + let obj = extend(copy(base), {}) + AssertEqual obj.f2('called2'), 'called2' + if string_displays_partial + AssertEqual neomake#utils#Stringify(obj.f2), "function('".(fnr_base + 1)."', ".string(obj).")" + else + AssertEqual neomake#utils#Stringify(obj.f2), "function('".(fnr_base + 1)."')" + endif + AssertEqual neomake#utils#Stringify(obj), "{f2: function('".(fnr_base + 1)."'), base: 1}" + +Execute (neomake#utils#MakerFromCommand uses tempfile): + let maker = neomake#utils#MakerFromCommand('echo') + + new + edit tests/fixtures/a\ filename\ with\ spaces + set modified + let b:neomake_tempfile_enabled = 1 + let jobinfo = NeomakeTestsFakeJobinfo() + + let bound_maker = neomake#GetMaker(maker) + let make_info = values(neomake#GetStatus().make_info)[0] + " For make_info.entries_list to be available. + let make_info.entries_list = neomake#list#ListForMake(make_info) + Assert !has_key(make_info, 'tempfiles') + let shell_argv = split(&shell) + split(&shellcmdflag) + AssertEqual bound_maker.args, shell_argv[1:] + ['echo'] + AssertEqual bound_maker.exe, shell_argv[0] + AssertEqual bound_maker.remove_invalid_entries, 0 + + call bound_maker._get_argv(jobinfo) + let temp_file = fnamemodify(make_info.tempfiles[0], ':.') + AssertNotEqual temp_file, fnameescape(temp_file) + + doautocmd neomake VimLeave + Assert empty(glob(temp_file)), 'Temporary file was removed.' + AssertNeomakeMessage printf('Removing temporary file: "%s".', make_info.tempfiles[0]) + bwipe! + +Execute (neomake#utils#get_config_fts): + function! s:F(ft) abort + return neomake#utils#get_config_fts(a:ft) + endfunction + AssertEqual s:F('foo'), ['foo'] + AssertEqual s:F('foo.bar'), ['foo_bar', 'foo', 'bar'] + AssertEqual s:F('bar.foo'), ['bar_foo', 'bar', 'foo'] + AssertEqual s:F('jsx.javascript'), ['jsx_javascript', 'jsx', 'javascript'] + AssertEqual s:F('javascript.jsx'), ['javascript_jsx', 'javascript', 'jsx'] + AssertEqual s:F('jsx'), ['jsx', 'javascript'] + +Execute (neomake#utils#fnamemodify handles fugitive buffer): + NeomakeTestsLoadPlugin 'vim-fugitive' + new + edit autoload/neomake/debug.vim + let bufname = bufname('%') + let bufname_abs = fnamemodify(bufname, ':p') + + Gedit + AssertNotEqual bufname, bufname('%') + Assert bufname('%') =~# '^fugitive://' + + AssertEqual neomake#utils#fnamemodify(bufnr('%'), ''), bufname + AssertEqual neomake#utils#fnamemodify(bufnr('%'), ':p'), bufname_abs + AssertEqual neomake#utils#fnamemodify(bufnr('%'), ':p:h'), fnamemodify(bufname_abs, ':h') + + " ExpandArgs handles fugitive buffers also. + let jobinfo = {'bufnr': bufnr('%')} + AssertEqual neomake#utils#ExpandArgs(['%'], jobinfo), [bufname] + AssertEqual neomake#utils#ExpandArgs(['%:e'], jobinfo), ['vim'] + " NOTE: uses absolute path, although bufname is relative. + AssertEqual neomake#utils#ExpandArgs(['%<'], jobinfo), [fnamemodify(bufname, ':p:r')] + + exe 'lcd '.fnamemodify(tempname(), ':h') + AssertEqual neomake#utils#fnamemodify(bufnr('%'), ''), bufname_abs + AssertEqual neomake#utils#fnamemodify(bufnr('%'), ':p'), bufname_abs + AssertEqual neomake#utils#fnamemodify(bufnr('%'), ':p:h'), fnamemodify(bufname_abs, ':h') + + bwipe + bwipe autoload/neomake/debug.vim + if exists('*VimFtpluginUndo') + delfunction VimFtpluginUndo + endif + +Execute (neomake#utils#fnamemodify handles empty bufname): + new + AssertEqual bufname('%'), '' + AssertEqual neomake#utils#fnamemodify(bufnr('%'), ''), '' + AssertEqual neomake#utils#fnamemodify(bufnr('%'), ':p'), '' + bwipe + +Execute (neomake#utils#FindGlobFile): + let tempdir = tempname() + let slash = neomake#utils#Slash() + let subdir = tempdir . slash . 'sub' + call mkdir(subdir, 'p', 0700) + + let tempfile = tempdir.slash.'temp-file' + call writefile([], tempfile) + let file_in_tempdir = tempdir.slash.'common-file' + call writefile([], file_in_tempdir) + let subfile = subdir.slash.'sub-file' + call writefile([], subfile) + let file_in_subdir = subdir.slash.'common-file' + call writefile([], file_in_subdir) + let anotherfile_in_subdir = subdir.slash.'common-file-2' + call writefile([], anotherfile_in_subdir) + + new + exe 'lcd' subdir + AssertEqual neomake#utils#FindGlobFile('doesnotexist'), '' + AssertEqual neomake#utils#FindGlobFile('sub-file'), subfile + AssertEqual neomake#utils#FindGlobFile('sub-file', tempdir), '' + AssertEqual neomake#utils#FindGlobFile('common-file'), file_in_subdir + AssertEqual neomake#utils#FindGlobFile('common-file', tempdir), file_in_tempdir + + exe 'lcd' tempdir + AssertEqual neomake#utils#FindGlobFile('sub-file'), '' + AssertEqual neomake#utils#FindGlobFile('sub-file', subdir), subfile + AssertEqual neomake#utils#FindGlobFile('sub-file', tempdir), '' + AssertEqual neomake#utils#FindGlobFile('sub-file', tempname()), '' + AssertEqual neomake#utils#FindGlobFile('common-file'), file_in_tempdir + AssertEqual neomake#utils#FindGlobFile('common-file'), file_in_tempdir + AssertEqual neomake#utils#FindGlobFile('common-file', subdir), file_in_subdir + + " Only the first found file gets returned. + AssertEqual neomake#utils#FindGlobFile('common-file{,-2}', subdir), file_in_subdir + AssertEqual neomake#utils#FindGlobFile('common-file{-2,}', subdir), anotherfile_in_subdir + bwipe + +Execute (neomake#utils#shellescape): + AssertEqual neomake#utils#shellescape('foo'), 'foo' + AssertEqual neomake#utils#shellescape('foo-bar'), 'foo-bar' + AssertEqual neomake#utils#shellescape('foo_bar'), 'foo_bar' + AssertEqual neomake#utils#shellescape('foo bar'), "'foo bar'" + AssertEqual neomake#utils#shellescape('foo bar "baz"'), "'foo bar \"baz\"'" + AssertEqual neomake#utils#shellescape('--foo=bar'), '--foo=bar' + + Save &shell + let &shell = 'cmd.exe' + AssertEqual neomake#utils#shellescape('foo'), 'foo' + AssertEqual neomake#utils#shellescape('foo-bar'), 'foo-bar' + AssertEqual neomake#utils#shellescape('foo_bar'), 'foo_bar' + AssertEqual neomake#utils#shellescape('foo bar'), '"foo bar"' + AssertEqual neomake#utils#shellescape('foo bar "baz"'), '"foo bar ""baz"""' + + AssertEqual neomake#utils#shellescape('"foo"'), '"""foo"""' + AssertEqual neomake#utils#shellescape('"foo bar"'), '"""foo bar"""' + AssertEqual neomake#utils#shellescape('-c "foo bar"'), '"-c ""foo bar"""' + +Execute (neomake#utils#fix_self_ref): + AssertEqual neomake#utils#fix_self_ref(''), '' + + let obj = {'foo': 1, 'bar': {}} + AssertEqual neomake#utils#fix_self_ref(obj), { + \ 'foo': 1, + \ 'bar': {}} + let fixed = neomake#utils#fix_self_ref(obj) + Assert fixed is obj, 'does not copy unnecessarily' + + let obj.bar.self_ref = obj + let exception = '' + try + let str_obj = string(obj) + catch /^Vim(let):E724:/ + let exception = v:exception + endtry + if has('nvim') + AssertEqual exception, 'Vim(let):E724: unable to correctly dump variable with self-referencing container' + elseif has('patch-7.4.1644') + AssertEqual str_obj, "{'foo': 1, 'bar': {'self_ref': {...}}}" + else + AssertEqual exception, 'Vim(let):E724: variable nested too deep for displaying' + endif + let fixed = neomake#utils#fix_self_ref(obj) + call string(fixed) + AssertEqual fixed, { + \ 'foo': 1, + \ 'bar': {'self_ref': ''}} + + Assert obj.bar.self_ref is obj, 'self_ref is obj' + + let obj.baz = {} + let obj.baz.self_ref_obj = obj + let obj.baz.self_ref_baz = obj.baz + let fixed = neomake#utils#fix_self_ref(obj) + AssertEqual fixed, { + \ 'foo': 1, + \ 'bar': {'self_ref': ''}, + \ 'baz': { + \ 'self_ref_obj': '', + \ 'self_ref_baz': { + \ 'self_ref_obj': '', + \ 'self_ref_baz': '' + \ } + \ }} + +Execute (neomake#utils#fix_self_ref with obj.func = obj.func): + let string_displays_partial = has('patch-7.4.1608') + let maker = {} + function maker.args() + endfunction + let str_func = string(get(maker, 'args')) + let maker.args = maker.args + let repr = neomake#utils#fix_self_ref(maker) + AssertEqual keys(repr), ['args'] + + if string_displays_partial + if has('nvim') + AssertEqual string(repr), "{'args': ''}" + AssertEqual neomake#utils#fix_self_ref(maker.args), '' + AssertEqual neomake#utils#fix_self_ref(get(maker, 'args')), '' + else + let str_number = matchstr(str_func, '\d\+') + AssertEqual string(repr), printf( + \ "{'args': function('%d', {...})}", + \ str_number) + AssertEqual neomake#utils#fix_self_ref(maker.args), maker.args + AssertEqual neomake#utils#fix_self_ref(get(maker, 'args')), maker.args + endif + else + AssertEqual string(repr), printf("{'args': %s}", str_func) + AssertEqual neomake#utils#fix_self_ref(maker.args), maker.args + endif + + +Execute (neomake#utils#fix_self_ref: handles lists): + let maker = {} + function maker.args() + endfunction + let maker.args = maker.args + let repr = neomake#utils#fix_self_ref([maker]) + AssertEqual keys(repr[0]), ['args'] + call string(repr) + +Execute (neomake#utils#fix_self_ref: uses get(obj, k)): + let make_info = {} + let entries_list = {} + let entries_list.make_info = make_info + let make_info.entries_list = entries_list + AssertEqual neomake#utils#fix_self_ref(make_info), { + \ 'entries_list': {'make_info': ''}} + + " This used to trigger "unrepresentable object" in Neovim. + " (https://github.com/neovim/neovim/issues/7432) + function entries_list.func() abort dict + endfunction + AssertEqual string(neomake#utils#fix_self_ref(make_info)), + \ printf("{'entries_list': {'func': %s, 'make_info': ''}}", + \ string(get(entries_list, 'func'))) + +Execute (neomake#utils#Stringify: uses neomake#utils#fix_self_ref): + let maker = {} + function maker.args() + endfunction + let maker.args = maker.args + let repr = neomake#utils#Stringify(maker) + Assert repr =~# '\V{args: \.\*}' + +Execute (neomake#utils#write_tempfile): + Save &endofline, &binary + let vim_temp = tempname() + let neomake_temp = tempname() + + if !exists('+fixeol') + NeomakeTestsSkip 'Skipping +fixeol variants' + let variants = [ + \ 'endofline binary', + \ 'endofline nobinary', + \ 'noendofline binary', + \ 'noendofline nobinary', + \ ] + else + Save &fixeol + let variants = [ + \ 'fixeol endofline binary', + \ 'fixeol endofline nobinary', + \ 'fixeol noendofline binary', + \ 'fixeol noendofline nobinary', + \ 'nofixeol endofline binary', + \ 'nofixeol endofline nobinary', + \ 'nofixeol noendofline binary', + \ 'nofixeol noendofline nobinary', + \ ] + endif + + for variant in variants + new + let bufnr = bufnr('%') + exe 'set' variant + + exe 'w!' vim_temp + new + call neomake#utils#write_tempfile(bufnr, neomake_temp) + AssertEqual readfile(vim_temp, 'b'), readfile(neomake_temp, 'b') + + b# + normal! ifoo + exe 'w!' vim_temp + b# + call neomake#utils#write_tempfile(bufnr, neomake_temp) + AssertEqual readfile(vim_temp, 'b'), readfile(neomake_temp, 'b') + bwipe! + bwipe + endfor + +Execute (neomake#utils#highlight_is_defined): + AssertEqual neomake#utils#highlight_is_defined('Error'), 1 + AssertEqual neomake#utils#highlight_is_defined('NeomakeCustomHilight'), 0 + hi clear NeomakeCustomHilight + AssertEqual neomake#utils#highlight_is_defined('NeomakeCustomHilight'), 0 + hi link NeomakeCustomHilight Error + AssertEqual neomake#utils#highlight_is_defined('NeomakeCustomHilight'), 1 + hi link NeomakeCustomHilight NONE + AssertEqual neomake#utils#highlight_is_defined('NeomakeCustomHilight'), 0 + +Execute (NeomakeTestsGetVimMessages): + call NeomakeTestsSetVimMessagesMarker() + AssertEqual NeomakeTestsGetVimMessages(), [] + AssertEqual NeomakeTestsGetVimMessages(), [] + echom 1 + AssertEqual NeomakeTestsGetVimMessages(), ['1'] + echom 2 + echom 3 + AssertEqual NeomakeTestsGetVimMessages(), ['2', '3'] + +Execute (neomake#utils#get_buf_line_count): + new + let bufnr = bufnr('%') + AssertEqual neomake#utils#get_buf_line_count(bufnr), 1 + + norm! 7o + AssertEqual line('$'), 8 + AssertEqual neomake#utils#get_buf_line_count(bufnr), 8 + + new + AssertEqual neomake#utils#get_buf_line_count(bufnr), 8 + + let non_existing_buffer = bufnr+100 + Assert !bufexists(non_existing_buffer) + AssertEqual neomake#utils#get_buf_line_count(non_existing_buffer), 0 + bwipe + bwipe! + +Execute (neomake#utils#get_buf_line_count: unloaded buffer): + new + + " Create an unlisted buffer. + call setloclist(0, [{'filename': 'unlisted_buffer'}]) + let unlisted_bufnr = bufnr('^unlisted_buffer') + Assert !buflisted(unlisted_bufnr) + + AssertEqual neomake#utils#get_buf_line_count(unlisted_bufnr), 0 + exe 'b '.unlisted_bufnr + AssertEqual neomake#utils#get_buf_line_count(unlisted_bufnr), 1 + bp + bwipe + exe unlisted_bufnr.'bwipe' + +Execute (neomake#utils#temp_cd): + let cwd = getcwd() + try + AssertEqual neomake#utils#temp_cd('.'), ['', ''] + AssertEqual neomake#utils#temp_cd(cwd), ['', ''] + + " If cur_wd gets passed in the caller is responsible if cd'ing should not get done. + AssertEqual neomake#utils#temp_cd(cwd, cwd), ['', 'cd '.fnameescape(cwd)] + + let tempdir = tempname() + AssertEqual neomake#utils#temp_cd(cwd, tempdir), ['', 'cd '.fnameescape(tempdir)] + let [cd_error, cd_back_cmd] = neomake#utils#temp_cd(tempdir, cwd) + Assert !empty(cd_error) + AssertEqual cd_back_cmd, '' + + call mkdir(tempdir) + AssertEqual neomake#utils#temp_cd(cwd, tempdir), ['', 'cd '.fnameescape(tempdir)] + AssertEqual neomake#utils#temp_cd(tempdir, cwd), ['', 'cd '.fnameescape(cwd)] + finally + exe 'cd '.fnameescape(cwd) + endtry + +Execute (neomake#utils#buf_get_lines): + new + let b = bufnr('%') + AssertEqual neomake#utils#buf_get_lines(b, 1, 1), [] + AssertEqual neomake#utils#buf_get_lines(b, 1, 2), [''] + + call setline(1, '1') + AssertEqual getline(1, '$'), ['1'] + AssertEqual neomake#utils#buf_get_lines(b, 1, 2), ['1'] + + " end > lines + let threw = 0 + try + call neomake#utils#buf_get_lines(b, 1, 3) + catch + let threw = 1 + if has('nvim') + Assert v:exception =~# '\Vneomake#utils#buf_get_lines: \.\*Index out of bounds', v:exception + else + AssertEqual v:exception, 'neomake#utils#buf_get_lines: end is higher than number of lines' + endif + endtry + AssertEqual threw, 1 + + " start < 1 + let threw = 0 + try + call neomake#utils#buf_get_lines(b, 0, 1) + catch + let threw = 1 + AssertEqual v:exception, 'neomake#utils#buf_get_lines: start is lower than 1' + endtry + AssertEqual threw, 1 + + call setline(2, '2') + AssertEqual neomake#utils#buf_get_lines(b, 1, 2), ['1'] + AssertEqual neomake#utils#buf_get_lines(b, 1, 3), ['1', '2'] + + AssertEqual getline(1, '$'), ['1', '2'] + bwipe! + +Execute (neomake#utils#buf_set_lines): + new + let b = bufnr('%') + AssertEqual neomake#utils#buf_set_lines(b, 1, 1, ['1']), '' + AssertEqual getline(1, '$'), ['1', ''] + + AssertEqual neomake#utils#buf_set_lines(b, 1, 3, ['1', '2']), '' + AssertEqual getline(1, '$'), ['1', '2'] + + " end > lines + let error = neomake#utils#buf_set_lines(b, 1, 4, []) + if has('nvim') + Assert error =~# 'neomake#utils#buf_set_lines: .*Index out of bounds', error + else + AssertEqual error, 'neomake#utils#buf_set_lines: end is higher than number of lines' + endif + + " start < 1 + let error = neomake#utils#buf_set_lines(b, 0, 1, []) + AssertEqual error, 'neomake#utils#buf_set_lines: start is lower than 1' + + AssertEqual neomake#utils#buf_set_lines(b, 2, 3, ['2', '3']), '' + AssertEqual getline(1, '$'), ['1', '2', '3'] + + AssertEqual neomake#utils#buf_set_lines(b, 2, 4, []), '' + AssertEqual getline(1, '$'), ['1'] + bwipe! + +Execute (Different buffer with buf_get_lines/buf_set_lines): + " Neovim can handle different buffers. + new + let b = bufnr('%') + new + if exists('*nvim_buf_get_lines') + AssertEqual neomake#utils#buf_set_lines(b, 1, 1, ['1', '2']), '' + AssertEqual neomake#utils#buf_get_lines(b, 1, 3), ['1', '2'] + else + let threw = 0 + try + call neomake#utils#buf_get_lines(b, 1, 3) + catch + let threw = 1 + AssertEqual v:exception, 'Neomake: neomake#utils#buf_get_lines: used for non-current buffer' + endtry + Assert threw + + AssertEqual neomake#utils#buf_set_lines(b, 1, 1, ['1', '2']), 'neomake#utils#buf_set_lines: used for non-current buffer' + endif + bwipe! + bwipe! + +Execute (neomake#utils#shorten_list_for_log): + AssertEqual neomake#utils#shorten_list_for_log([], 1), [] + AssertEqual neomake#utils#shorten_list_for_log([1, 2, 3], 1), [1, '... (3 total)'] diff --git a/bundle/neomake/tests/utils_projectroot.vader b/bundle/neomake/tests/utils_projectroot.vader new file mode 100644 index 000000000..715968a51 --- /dev/null +++ b/bundle/neomake/tests/utils_projectroot.vader @@ -0,0 +1,48 @@ +Execute (neomake#utils#get_project_root): + new + let bufnr = bufnr('%') + AssertEqual neomake#utils#get_project_root(bufnr), fnamemodify(g:vader_file, ':h:h') + + " Gets cached. + AssertEqual b:neomake.project_root, fnamemodify(g:vader_file, ':h:h') + + let slash = neomake#utils#Slash() + let tmpbase = tempname() + let tmpdir = tmpbase . slash . 'python-project' + call mkdir(tmpdir, 'p') + + setfiletype python + Assert !exists('b:neomake.project_root'), 'cache cleared on FileType' + exe 'lcd '.tmpdir + + let project_root = neomake#utils#get_project_root(bufnr) + if project_root ==# fnamemodify(tmpbase, ':h:h') + call vader#log('NOTE: got project root already for tmpbase: '.project_root) + else + AssertEqual project_root, '' + endif + + call writefile([], tmpdir . slash . 'setup.cfg') + unlet b:neomake.project_root + AssertEqual neomake#utils#get_project_root(bufnr), tmpdir + + let tmpdir_sub = tmpdir . slash . 'sub' + call mkdir(tmpdir_sub) + call writefile([], tmpdir_sub . slash . 'setup.cfg') + exe 'lcd '.tmpdir_sub + unlet b:neomake.project_root + AssertEqual neomake#utils#get_project_root(bufnr), tmpdir_sub + + setfiletype c + AssertEqual neomake#utils#get_project_root(bufnr), '' + call writefile([], tmpdir. slash . 'CMakeLists.txt') + unlet b:neomake.project_root + AssertEqual neomake#utils#get_project_root(bufnr), tmpdir + + setfiletype unknown + AssertEqual neomake#utils#get_project_root(bufnr), '' + call writefile([], tmpdir. slash . 'Makefile') + AssertEqual neomake#utils#get_project_root(bufnr), '' + unlet b:neomake.project_root + AssertEqual neomake#utils#get_project_root(bufnr), tmpdir + bwipe diff --git a/bundle/neomake/tests/verbosity.vader b/bundle/neomake/tests/verbosity.vader new file mode 100644 index 000000000..3e6b20c56 --- /dev/null +++ b/bundle/neomake/tests/verbosity.vader @@ -0,0 +1,83 @@ +Include: include/setup.vader + +Execute (neomake#log uses &verbose): + Save g:neomake_verbose, &verbose + unlet! g:neomake_verbose + set verbose=0 + + unlet g:neomake_test_log_all_messages + + call neomake#log#warning('msg.') + AssertEqual g:neomake_test_messages, [[1, 'msg.', {}]] + + let g:neomake_test_messages = [] + 1verb call neomake#log#warning('msg.') + AssertEqual g:neomake_test_messages, [[1, 'msg.', {}]] + + let g:neomake_test_messages = [] + 1verb call neomake#log#info('msg.') + AssertEqual g:neomake_test_messages, [[2, 'msg.', {}]] + + let g:neomake_test_messages = [] + 2verb call neomake#log#info('msg.') + AssertEqual g:neomake_test_messages, [[2, 'msg.', {}]] + + let g:neomake_test_messages = [] + let g:neomake_verbose = 3 + call neomake#log#warning('msg.') + AssertEqual g:neomake_test_messages, [[1, 'msg.', {}]] + + let g:neomake_test_messages = [] + let g:neomake_verbose = 1 + 0verb call neomake#log#warning('msg.') + AssertEqual g:neomake_test_messages, [[1, 'msg.', {}]] + + let g:neomake_verbose = 0 + NeomakeTestsResetMessages + 0verb call neomake#log#warning('msg.') + AssertEqual g:neomake_test_messages, [] + + 1verb call neomake#log#warning('msg.') + AssertNeomakeMessage 'msg.', 1 + + 3verb call neomake#log#warning('msg.') + AssertNeomakeMessage 'msg.', 1 + +Execute (neomake#Make uses &verbose): + Save g:neomake_verbose, &verbose + unlet! g:neomake_verbose + set verbose=0 + + let maker = { + \ 'append_file': 0, + \ 'exe': 'echo', + \ 'args': ['1'], + \ } + let bufnr = bufnr('%') + + unlet g:neomake_test_log_all_messages + + " The default for g:neomake_verbose is 1, and ':2verb' displays level 3." + 2verb call neomake#Make(1, [maker]) + let make_id = neomake#GetStatus().last_make_id + NeomakeTestsWaitForFinishedJobs + + let log_context = {'make_id': make_id, 'bufnr': bufnr} + AssertNeomakeMessage 'Adding &verbose (2) to verbosity level: 3.', 3, log_context + AssertNeomakeMessage 'Running makers: unnamed_maker.', 3, log_context + + NeomakeTestsResetMessages + 1verb let jobinfo = neomake#Make({'enabled_makers': [maker]})[0] + let make_id = jobinfo.make_id + NeomakeTestsWaitForFinishedJobs + if neomake#has_async_support() + AssertNeomakeMessage "Starting async job: echo 1.", 2, {'id': jobinfo.id, 'make_id': make_id, 'bufnr': bufnr} + else + AssertNeomakeMessage "Starting [string]: echo 1.", 2, {'id': jobinfo.id, 'make_id': make_id, 'bufnr': bufnr} + endif + + let g:neomake_verbose = 3 + 0verb call neomake#Make(1, [maker]) + let make_id = neomake#GetStatus().last_make_id + NeomakeTestsWaitForFinishedJobs + AssertNeomakeMessage 'Running makers: unnamed_maker.', 3, {'make_id': make_id, 'bufnr': bufnr} diff --git a/bundle/neomake/tests/vim/vimrc b/bundle/neomake/tests/vim/vimrc new file mode 100644 index 000000000..b6e553692 --- /dev/null +++ b/bundle/neomake/tests/vim/vimrc @@ -0,0 +1,107 @@ +" Based on https://github.com/tweekmonster/braceless.vim/blob/master/test/vim/vimrc +" TODO: provide this by default in the Docker image already?! e.g. /vimrc?! + +set noloadplugins + +" Indicator for tests being run. +let g:neomake_test_messages = [] + +" Shorter timeouts during tests. +let g:neomake_action_queue_timeouts = {1: 10, 2: 20, 3: 30} + +" Remove some overhead by default, tested explicitly. +let g:neomake_echo_current_error = 0 + +let s:slash = has('win32') ? '\' : '/' + +if exists('$NEOMAKE_TESTS_DEP_PLUGINS_DIR') + let s:dep_plugins_base = $NEOMAKE_TESTS_DEP_PLUGINS_DIR +else + let s:dep_plugins_base = join( + \ [expand(':p:h'), '..', '..', 'build', 'vim', 'plugins'], + \ s:slash) +endif + +if exists('$TESTS_VADER_DIR') + let s:vader_dir = expand($TESTS_VADER_DIR) +else + let s:vader_dir = s:dep_plugins_base . s:slash . 'vader' +endif + +let &runtimepath .= ','.s:vader_dir +exe 'source' join([s:vader_dir, 'plugin', 'vader.vim'], s:slash) + +function! s:load_plugin_on_demand(name) abort + Save &runtimepath + + " Restore/unset "loaded" var, to not skip loading on second invocation. + let var_name = substitute(a:name, '^vim-', '', '') + exe printf('Save g:loaded_%s', var_name) + + let dir = s:dep_plugins_base.'/'.a:name + let &runtimepath .= ','.dir + + let funcs_before = map(split(neomake#utils#redir('function /\C^[A-Z]'), '\n'), + \ "substitute(v:val, '\\v^function (.*)\\(.*$', '\\1', '')") + + exe 'source '.join([dir, 'plugin', '*.vim'], s:slash) + + let funcs_after = map(split(neomake#utils#redir('function /\C^[A-Z]'), '\n'), + \ "substitute(v:val, '\\v^function (.*)\\(.*$', '\\1', '')") + + " Add new functions defined in the plugin to g:neomake_test_funcs_before, + " e.g. FugitiveDetect. + for f in funcs_after + if index(funcs_before, f) == -1 + call add(g:neomake_test_funcs_before, f) + endif + endfor +endfunction +command! -nargs=1 NeomakeTestsLoadPlugin call s:load_plugin_on_demand() + +let s:plugin_dir = expand(':p:h:h:h') +let &runtimepath .= ','.s:plugin_dir + +exe 'source' join([s:plugin_dir, 'plugin', 'neomake.vim'], s:slash) + +filetype plugin indent on + +augroup ssshhhhhh + autocmd VimEnter * set visualbell t_vb= + autocmd GUIEnter * set visualbell t_vb= +augroup END + +set noswapfile +syntax on +set number +set background=dark +set colorcolumn=80 +set showcmd +set lazyredraw +set tabstop=4 +set softtabstop=4 +set shiftwidth=4 +set expandtab +set backspace=2 +set nofoldenable +set foldmethod=syntax +set foldlevelstart=10 +set foldnestmax=10 +set ttimeoutlen=0 +set cmdheight=5 +set textwidth=79 +set hidden +set splitbelow " Easier for window numbers (incrementing). +set complete=. " Just simple completion from the current buffer. + +let mapleader=',' + +" No '-- More --' prompt, which would hang Travis. +set nomore + +if expand('$NEOMAKE_TEST_NO_COLORSCHEME') !=# '1' + colorscheme default +endif + +" Avoid system call and warning. +let g:neomake_clippy_rustup_has_nightly = 0 diff --git a/bundle/neomake/tests/vim_and_neovim_behavior.vader b/bundle/neomake/tests/vim_and_neovim_behavior.vader new file mode 100644 index 000000000..d0326f304 --- /dev/null +++ b/bundle/neomake/tests/vim_and_neovim_behavior.vader @@ -0,0 +1,72 @@ +" Tests for generic behavior in Vim/Neovim. +Include: include/setup.vader + +Execute (Test Vim's b:changedtick behavior): + " https://github.com/vim/vim/issues/2764 + new + let before = b:changedtick + exe 'w' tempname() + + if has('patch-8.1.1498') || has('nvim-0.4') + let inc_for_unchanged = 0 + else + let inc_for_unchanged = 1 + endif + + AssertEqual before + inc_for_unchanged, b:changedtick + + let before = b:changedtick + w + AssertEqual before + inc_for_unchanged, b:changedtick + + let before = b:changedtick + update + AssertEqual before, b:changedtick + + setlocal modified + let before = b:changedtick + update + AssertEqual before + 1, b:changedtick + + let before = b:changedtick + normal! ochanged + AssertEqual before + 2, b:changedtick + update + AssertEqual before + 3, b:changedtick + bwipe + + + " Via BufWriteCmd / autocommands. + augroup neomake_tests + autocmd BufWritePost + augroup END + function! s:BufWriteCmd() abort + exe "doautocmd BufWritePre expand('')" + setlocal nomodified + exe "doautocmd BufWritePost expand('')" + endfunction + new + augroup neomake_tests + au BufWriteCmd * call s:BufWriteCmd() + augroup END + let before = b:changedtick + exe 'w' tempname() + AssertEqual before, b:changedtick + + w + AssertEqual before, b:changedtick + + update + AssertEqual before, b:changedtick + + setlocal modified + let before = b:changedtick + update + AssertEqual before, b:changedtick + + let before = b:changedtick + normal! ochanged + AssertEqual before + 2, b:changedtick + update + AssertEqual before + 2, b:changedtick + bwipe diff --git a/bundle/neopairs.vim/autoload/neopairs.vim b/bundle/neopairs.vim/autoload/neopairs.vim new file mode 100644 index 000000000..8cc66e609 --- /dev/null +++ b/bundle/neopairs.vim/autoload/neopairs.vim @@ -0,0 +1,94 @@ +"============================================================================= +" FILE: neopairs.vim +" AUTHOR: Shougo Matsushita +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +" }}} +"============================================================================= + +" Variables initialization "{{{ +let g:neopairs#enable = + \ get(g:, 'neopairs#enable', 1) +let g:neopairs#pairs = + \ get(g:, 'neopairs#pairs', {}) +let g:neopairs#_pairs = + \ get(g:, 'neopairs#_pairs', + \ { '[': ']', '<': '>', '(': ')', '{': '}', '"': '"' }) +"}}} + +function! neopairs#_complete_done() abort "{{{ + let pairs = extend(copy(g:neopairs#_pairs), g:neopairs#pairs) + + if !g:neopairs#enable + \ || !exists('v:completed_item') + \ || empty(v:completed_item) + return + endif + + let item = v:completed_item + let word = item.word + if word == '' + return + endif + + let abbr = (item.abbr != '') ? item.abbr : item.word + if len(item.menu) > 5 + " Combine menu. + let abbr .= ' ' . item.menu + endif + if item.info != '' + let abbr = split(item.info, '\n')[0] + endif + + let insert = map(filter(keys(pairs), + \ 'strridx(word, v:val) == (len(word) - len(v:val))'), + \ 'pairs[v:val]') + if empty(insert) || (insert[0] =~ '^[()]$' && abbr !~ '(.*)') + return + endif + + " Auto close pairs + let input = s:get_input('CompleteDone') + call setline('.', input . insert[0] . getline('.')[len(input):]) +endfunction"}}} + +function! s:get_input(event) abort "{{{ + let input = ((a:event ==# 'InsertEnter' || mode() ==# 'i') ? + \ (col('.')-1) : col('.')) >= len(getline('.')) ? + \ getline('.') : + \ matchstr(getline('.'), + \ '^.*\%' . (mode() ==# 'i' ? col('.') : col('.') - 1) + \ . 'c' . (mode() ==# 'i' ? '' : '.')) + + if input =~ '^.\{-}\ze\S\+$' + let complete_str = matchstr(input, '\S\+$') + let input = matchstr(input, '^.\{-}\ze\S\+$') + else + let complete_str = '' + endif + + if a:event ==# 'InsertCharPre' + let complete_str .= v:char + endif + + return input . complete_str +endfunction"}}} + +" vim: foldmethod=marker diff --git a/bundle/neopairs.vim/doc/neopairs.txt b/bundle/neopairs.vim/doc/neopairs.txt new file mode 100644 index 000000000..cbd56d204 --- /dev/null +++ b/bundle/neopairs.vim/doc/neopairs.txt @@ -0,0 +1,57 @@ +*neopairs.txt* Auto insert pairs when complete done + +Version: 0.1 +Author: Shougo +License: MIT license {{{ + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +}}} + +CONTENTS *neopairs-contents* + +Install |neopairs-install| +Interface |neopairs-interface| + Variables |neopairs-variables| +FAQ |neopairs-faq| + +============================================================================== +INSTALL *neopairs-install* + +Note: |neopairs| requires Vim 7.4.774 or neovim (|v:completed_item| feature). + +============================================================================== +INTERFACE *neopairs-interface* + +------------------------------------------------------------------------------ +VARIABLES *neopairs-variables* + + *g:neopairs#enable* +g:neopairs#enable + If it is enabled, close the parenthesis automatically. + + *g:neopairs#pairs* +g:neopairs#pairs + Pairs user definition. + + Default value: g:neopairs#_pairs + +============================================================================== +FAQ *neopairs-faq* + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: diff --git a/bundle/neopairs.vim/plugin/neopairs.vim b/bundle/neopairs.vim/plugin/neopairs.vim new file mode 100644 index 000000000..ab0c4e58a --- /dev/null +++ b/bundle/neopairs.vim/plugin/neopairs.vim @@ -0,0 +1,36 @@ +"============================================================================= +" FILE: neopairs.vim +" AUTHOR: Shougo Matsushita +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +" }}} +"============================================================================= + +if exists('g:loaded_neopairs') + finish +endif +let g:loaded_neopairs = 1 + +augroup neopairs + autocmd! + autocmd CompleteDone * call neopairs#_complete_done() +augroup END + +" vim: foldmethod=marker diff --git a/bundle/neosnippet-snippets/LICENSE b/bundle/neosnippet-snippets/LICENSE new file mode 100644 index 000000000..154ae13df --- /dev/null +++ b/bundle/neosnippet-snippets/LICENSE @@ -0,0 +1,20 @@ +License: MIT license + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bundle/neosnippet-snippets/README.mkd b/bundle/neosnippet-snippets/README.mkd new file mode 100644 index 000000000..1c329a53d --- /dev/null +++ b/bundle/neosnippet-snippets/README.mkd @@ -0,0 +1,8 @@ +Neosnippet-snippets +=================== + +The standard snippets repository for +[neosnippet](https://github.com/Shougo/neosnippet.vim). + +You can fork or send pull request. + diff --git a/bundle/neosnippet-snippets/neosnippets/Gemfile.snip b/bundle/neosnippet-snippets/neosnippets/Gemfile.snip new file mode 100644 index 000000000..b27d1b175 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/Gemfile.snip @@ -0,0 +1,7 @@ +snippet source-rubygems +options head + source :rubygems + +snippet gem +options head + gem '${1}', '${2} >= 1.0' diff --git a/bundle/neosnippet-snippets/neosnippets/_.snip b/bundle/neosnippet-snippets/neosnippets/_.snip new file mode 100644 index 000000000..619f0e065 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/_.snip @@ -0,0 +1,54 @@ +# Global snippets + +snippet date_english +options word + `strftime("%d %b %Y")`${0} + +snippet datetime_iso8601 +alias df +options word + `strftime("%Y-%m-%dT%H:%M:%S")`${0} + +snippet date_iso8601 +alias dd +options word + `strftime("%Y-%m-%d")`${0} + +snippet time_colon +alias dt +options word + `strftime("%H:%M:%S")`${0} + +snippet lastmod +abbr Last modified time +alias lmod + Last Modified: `strftime("%Y-%m-%dT%H:%M:%S")`${0} + +snippet filename +alias fname +options word + `bufname('%') ==#'[Command Line]' ? expand('#') : expand('%')`${0} + +snippet path +options word + `substitute(bufname('%') ==#'[Command Line]' ? expand('#:p') : expand('%:p'), '//\+', '/', 'g')`${0} + +snippet rpath +options word + `substitute(bufname('%') ==#'[Command Line]' ? expand('#:h') : expand('%:h'), '\(//*\|/*$\)', '/', 'g')`${0} + +snippet basename +alias bname +options word + `bufname('%') ==#'[Command Line]' ? expand('#:t:r:r:r') : expand('%:t:r:r:r')`${0} + +snippet filename_upper_camel +alias fnameuc +options word + `substitute(bufname('%') ==#'[Command Line]' ? expand('#:t:r:r:r') : expand('%:t:r:r:r'), '\%(^\(.\)\|_\(.\)\)', '\u\1\u\2', 'g')`${0} + +snippet filename_lower_camel +alias fnamelc +options word + `substitute(bufname('%') ==#'[Command Line]' ? expand('#:t:r:r:r') : expand('%:t:r:r:r'), '\%(_\(.\)\)', '\u\1', 'g')`${0} + diff --git a/bundle/neosnippet-snippets/neosnippets/actionscript.snip b/bundle/neosnippet-snippets/neosnippets/actionscript.snip new file mode 100644 index 000000000..409ea7a26 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/actionscript.snip @@ -0,0 +1,265 @@ +snippet ec + #endinitclip + + +snippet inc + #include "${1}" + + +snippet br + break; + + +snippet ca + call(${1:#:frame}); + + +snippet case +abbr ce + case ${1:#:expression} : + ${1:TARGET} + + +snippet catch +abbr ch + catch ($1) { + $2 + } + +snippet class + class ${1:#:ClassName} { + var _${2}; + function ${1}(${2}){ + _${2} = ${2};${0} + } + } + +snippet co + continue; + + +snippet dt + default : + ${1:TARGET} + + +snippet de + delete ${1}; + + +snippet do + do { + ${1:TARGET} + } while (${2:#:condition}); + + +snippet dm + duplicateMovieClip(${1:#:target}, ${2:#:newName}, ${3:#:depth}); + + +snippet ei + else if (${1}) { + ${2:TARGET} + } + + +snippet fori +abbr fi + for (var ${1} in ${2}){ + ${3:TARGET} + }; + + +snippet for +abbr fr + for (var ${1} = 0; $1 < ${2}.length; $1++) { + ${0:TARGET} + }; + + +snippet fs + fscommand(${1:#:command}, ${2:#:paramaters}); + + +snippet fn + function ${1}(${2}):${3}{ + ${0:TARGET} + }; + +snippet gu + getURL(${1}); + + +snippet gp + gotoAndPlay(${1}); + + +snippet gs + gotoAndStop(${1}); + +snippet if + if (${1}) { + ${0:TARGET} + } + +snippet il + ifFrameLoaded (${1}) { + ${0:TARGET} + } + +snippet ip + import ${1}; + + +snippet it + interface ${1}{ + ${0:TARGET} + } + + +snippet lm + loadMovie(${1:url}, ${2:target}, ${3:method}); + + +snippet ln + loadMovieNum(${1:url}, ${2:level}, ${3:method}); + + +snippet lv + loadVariables(${1:url}, ${2:target}, ${3:method}); + + +snippet vn + loadVariables(${1:url}, ${2:level}, ${3:method}); + + +snippet mc + MovieClip + + +snippet nf + nextFrame(); + + +snippet ns + nextScene(); + + +snippet on + on (${1}) { + ${2} + }; + + +snippet oc + onClipEvent (${1}) { + ${0:TARGET} + }; + +snippet pl + play(); + + +snippet pf + pravFrame(); + + +snippet ps + prevScene(); + + +snippet pr + print(${1:#:target}, ${2:#:type}); + + +snippet bn + printAsBitmapNum(${1:#:level}, ${2:#:type}); + + +snippet pn + printNum(${1:#:level}, ${2:#:type}); + + +snippet rm + removeMovieClip(${1:#:target}); + + +snippet rt + return ${1}; + + +snippet sp + setProperty(${1:#:target}, ${2:#:property}, ${3:#:value}); + + +snippet sv + set(${1:#:name}, ${2:#:value}); + + +snippet dr + startDrag(${1:#:target}, ${2:#:lockcenter}, ${3:#:l}, ${4:#:t}, ${5:#:r}, ${6:#:b} ); + + +snippet st + stop(); + + +snippet ss + stopAllSounds(); + + +snippet sd + stopDrag(); + + +snippet sw + switch ( ${1:#:condition} ) { + ${0:TARGET} + } + + +snippet tt + tellTarget( ${1:#:target} ) { + ${0:TARGET} + } + +snippet th + throw ${1}; + + +snippet tq + toggleHighQuality(); + + +snippet tr + trace(${1:"$0"}); + + +snippet ty + try { + ${0:TARGET} + }; + +snippet um + unloadMovie(${1:#:target}); + + +snippet un + unloadMovieNum(${1:#:level}); + + +snippet vr + var ${1}:${2}; + + +snippet wh + while (${1:#:condition}) { + ${0:TARGET} + }; + + +snippet wt + with (${1:#:target}); + ${0:TARGET} + }; + diff --git a/bundle/neosnippet-snippets/neosnippets/ada.snip b/bundle/neosnippet-snippets/neosnippets/ada.snip new file mode 100644 index 000000000..b4b431cb1 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/ada.snip @@ -0,0 +1,304 @@ +snippet with +abbr with ...;... +options head + with ${1};${2} + +snippet package +abbr package {NAME} is {...} end +options head + package ${1} is + ${0} + end $1; + + +snippet package_body +abbr package body {NAME} is {...} end +options head + package body ${1} is + ${0} + end $1; + +snippet entry +abbr entry {...} when +options head + entry ${1}(${2}) when ${3} is + begin + ${0} + end $1; + +snippet task +options head + task ${1} is + entry ${0} + end $1; + +snippet task_body +abbr task body +options head + task body ${1} is + ${2} + begin + ${0} + end $1; + +snippet accept +options head + accept ${1}(${2}) do + ${0} + end $1; + +snippet protected_type +abbr protected type +options head + protected type ${1}(${2}) is + ${0} + end $1; + +snippet protected_body +abbr protected body +options head + protected body ${1} is + ${2} + begin + ${0} + end $1; + +snippet generic +abbr generic type +options head + generic + type ${1} is ${2};${0} + +snippet type +options head + type ${1} is ${2};${0} + +snippet type_default +abbr type with default value +options head + type ${1} is ${2} + with Default_Value => ${3};${0} + +snippet subtype +options head + subtype ${1} is ${2};${0} + +snippet declare +abbr declare block +options head + declare + ${1} + begin + ${0} + end; + +snippet declare_named +abbr declare named block +options head + ${1}: + declare + ${2} + begin + ${0} + end $1; + +snippet ife +abbr if expression +options head + if ${1} then ${2} else ${0} + +snippet case_expression +abbr case expression +options head + case ${1} is + when ${2} => ${3},${0} + +snippet for_all +abbr for all +options head + for all ${1} ${2:in} ${3} => ${0} + +snippet for_some +abbr for some +options head + for some ${1} ${2:in} ${3} => ${0} + +snippet if +options head + if ${1} then + ${0} + end if; + +snippet ifelse +abbr if ... else +options head + if ${1} then + ${2} + else + ${0} + end if; + +snippet else +options head + else + ${0} + +snippet elseif +alias ei +options head + elsif ${1} then + ${0} + +snippet while +alias w +options head + while ${1} loop + ${0} + end loop; + +snippet named_while +abbr named while +options head + ${1}: + while ${2} loop + ${0} + end loop $1; + +snippet for +options head + for ${1:I} in ${2} loop + ${0} + end loop; + +snippet for_each +abbr for each +options head + for ${1} of ${2} loop + ${0} + end loop; + +snippet named_for +abbr named for +options head + ${1}: + for ${2:I} in ${3} loop + ${0} + end loop $1; + +snippet named_for_each +abbr named for each +options head + ${1}: + for ${2} of ${3} loop + ${0} + end loop $1; + +snippet procedure +options head + procedure ${1}(${2}) is + ${3} + begin + ${0} + end $1; + +snippet procedure_declare +abbr procedure declaration +options head + procedure ${1};${0} + +snippet function +options head + function ${1}(${2}) return ${3} is + ${4} + begin + ${0} + end $1; + +snippet function_expr +abbr expression function +options head + function ${1} return ${2} is + (${3});${0} + +snippet function_declare +abbr function declaration +options head + function ${1} return ${2};${0} + +snippet return +abbr extended return +options head + return ${1} do + ${0} + end return; + +snippet record +options head + record + ${0} + end record; + +snippet case +options head + case ${1} is + when ${2} => ${3};${0} + end case; + +snippet when +options head + when ${1} => ${2};${0} + +snippet when_others +abbr when others +options head + when others => ${1};${0} + +snippet loop +options head + loop + ${0} + end loop; + +snippet named_loop +abbr named loop +options head + ${1}: + loop + ${0} + end loop $1; + +snippet exit_when +abbr exit when +options head + exit when ${1}; + ${0} + +snippet put +abbr Ada.Text_IO.Put +options head + Ada.Text_IO.Put(${1}); + ${0} + +snippet put_line +abbr Ada.Text_IO.Put_Line +options head + Ada.Text_IO.Put_Line(${1}); + ${0} + +snippet get +abbr Ada.Text_IO.Get +options head + Ada.Text_IO.Get(${1}); + ${0} + +snippet get_line +abbr Ada.Text_IO.Get_Line +options head + Ada.Text_IO.Get_Line(${1}); + ${0} + +snippet newline +abbr Ada.Text_IO.New_Line +options head + Ada.Text_IO.New_Line(${1:1}); + ${0} diff --git a/bundle/neosnippet-snippets/neosnippets/apache.snip b/bundle/neosnippet-snippets/neosnippets/apache.snip new file mode 100644 index 000000000..9df3595f2 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/apache.snip @@ -0,0 +1,50 @@ +snippet allow + AllowOverride ${1:#:AuthConfig} ${2:#:FileInfo} ${3:#:Indexes} ${4:#:Limit} ${5:#:Options} + + +snippet opt + Options ${1:#:All} ${2:#:ExecCGI} ${3:#:FollowSymLinks} ${4:#:Includes} ${5:#:IncludesNOEXEC} ${6:#:Indexes} ${7:#:MultiViews} ${8:#:SymLinksIfOwnerMatch} + + +snippet vhost + + ServerAdmin webmaster@${1} + DocumentRoot /www/vhosts/${1} + ServerName ${1} + ErrorLog logs/${1}-error_log + CustomLog logs/${1}-access_log common + + +snippet dir + + ${0} + + +snippet ifmodule + + ${2} + + +snippet if + + ${2} + + +snippet RemoteIPHeader + RemoteIPHeader X-Forwarded-For + +snippet location + + ${2:config} + + +snippet locationmatch + + ${2:config} + + +snippet directoryindex + DirectoryIndex index.php index.html + +snippet require + Require all granted diff --git a/bundle/neosnippet-snippets/neosnippets/applescript.snip b/bundle/neosnippet-snippets/neosnippets/applescript.snip new file mode 100644 index 000000000..2830040d3 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/applescript.snip @@ -0,0 +1,185 @@ +snippet script + script ${1:#:new_object} + on run + ${2:TARGET} + end run + end script + + +snippet on + on ${1:#:functionName}(${2:#:arguments}) + ${3:TARGET} + end ${1} + + +snippet tell + tell ${1:#:app} + ${0:TARGET} + end tell + +snippet terms + using terms from ${1:#:app} + ${0:TARGET} + end using terms from + + +snippet if + if ${1:true} then + ${0:TARGET} + end if + + +snippet rept +abbr rep + repeat ${1} times} + ${0:TARGET} + end repeat + + +snippet repwh +abbr rep + repeat while ${1:#:condition} + ${0:TARGET} + end repeat + + +snippet repwi +abbr rep + repeat with ${1} in ${2} + ${0:TARGET} + end repeat + + +snippet try + try + ${0:TARGET} + on error + -- error handling + end try + +snippet timeout + with timeout ${1:#:number} seconds + ${0:TARGET} + end timeout + +snippet con + considering ${1:#:case} + ${0:TARGET} + end considering + + +snippet ign + ignoring ${1:#:application responses} + ${0:TARGET} + end ignoring + +snippet shell + ${1:#:set shell_stdout to }do shell script ${3:"${2:#script}"} + without altering line endings + ${0} + +snippet delim + set oldDelims to AppleScript's text item delimiters + set AppleScript's text item delimiters to {"${1:,}"} + ${0:#:TARGET} + set AppleScript's text item delimiters to oldDelims + + +snippet parent + prop parent : app "${1}" + + +snippet alert + display alert "${1:#:alert text}" + ${2:#:message} "${3:#:message text}" + ${4:#:as warning} + +snippet dialog_OK +abbr dialog + display dialog "${1:#:text}" + ${2:#:with icon} ${3:1} + buttons {"${4:OK}"} default button 1 + + +snippet dialog_OK/Cancel +abbr dialog + display dialog "${1:#:text}" + ${2:#:with icon} + buttons {"${3:Cancel}", "${4:OK}"} + default button "${4}" + set button_pressed to button returned of result + if button_pressed is "${4}" then + ${5:#:TARGET} + else + -- action for cancel button goes here + end if + +snippet dialog_OK/Cancel/Other +abbr dialog + display dialog "${1:#:text}" + ${2:#:with icon} + buttons {"${3:Cancel}", "${4:Other Choice}", "${5:OK}"} + default button "${5}" + set button_pressed to button returned of result + if button_pressed is "${5}" then + ${6:TARGET} + else if button_pressed is "${3}" then + -- action for cancel button goes here + else + -- action for other button goes here + end if + +snippet dialog_TextFierld +abbr dialog + set the_result to display dialog "${1:#:text}" + default answer "${2:#:type here}" + ${3:#:with icon} + buttons {"${4:Cancel}", "${5:OK}"} + default button "${5}" + set button_pressed to button returned of the_result + set text_typed to text returned of the_result + if button_pressed is "${5}" then + ${6:#:TARGET} + else + -- action for cancel button goes here + end if + +snippet choose_Applications +abbr choose + ${1:#:set the_application to }choose application with prompt "${2:#:Choose an application:}"${3:#:with multiple selections allowed} + +snippet choose_Files +abbr choose + ${1:#:set the_file to }choose file with prompt "${2:#:Pick a file:}" + ${3:#:default location path to home folder} + ${4:#:with invisibles} + ${5:#:with multiple selections allowed} + ${6:#:with showing package contents} + + +snippet choose_Folders +abbr choose + ${1:#:set the_folder to }choose folder with prompt "${2:#:Pick a folder:}" + ${3:#:default location path to home folder} + ${4:#:with invisibles} + ${5:#:with multiple selections allowed} + ${6:#:with showing package contents} + ${0} + +snippet choose_NewFile +abbr choose + ${1:#:set the_filename to }choose file name with prompt "${2:#:Name this file:}" + default name "${3:untitled}" default location ${4:#:path to home folder} + +snippet choose_URL +abbr choose + ${1:#:set the_url to }choose URL showing ${2:Web} servers with editable URL + +snippet choose_Color +abbr choose + ${1:#:set the_color to }choose color default color ${2:{65536, 65536, 65536\}} + +snippet choose_ItemFromList +abbr choose + set the_choice to choose from list ${1}"\}} + diff --git a/bundle/neosnippet-snippets/neosnippets/asm.snip b/bundle/neosnippet-snippets/neosnippets/asm.snip new file mode 100644 index 000000000..449365471 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/asm.snip @@ -0,0 +1,12 @@ +snippet doxy +abbr ;; @brief ... +options head + ;; + ;; @brief ${1:function description} + ;; + ;; @details ${2:detailed description} + ;; + ;; @param ${3:param} + ;; + ;; @return ${4:return} + ;; diff --git a/bundle/neosnippet-snippets/neosnippets/beancount.snip b/bundle/neosnippet-snippets/neosnippets/beancount.snip new file mode 100644 index 000000000..78538392c --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/beancount.snip @@ -0,0 +1,32 @@ +snippet open +abbr open account +options head + ${1:YYYY}-${2:MM}-${3:DD} open ${4:Account} ${8:#:Commodity} + +snippet close +abbr close account +options head + ${1:YYYY}-${2:MM}-${3:DD} close ${4:#:Account} + +snippet commodity +alias currency +abbr declare commodity +options head + ${1:YYYY}-${2:MM}-${3:DD} commodity ${4:Commodity} + +snippet transaction +abbr transaction +options head + ${1:YYYY}-${2:MM}-${3:DD} * "${5:Payee}" "${6:Narration}" + ${9:Account} ${10:Amount} ${11:Commodity} + ${14:Account} ${15:#:Amount} ${16:#:Commodity} + +snippet balance +abbr balance +options head + ${1:YYYY}-${2:MM}-${3:DD} balance ${4:Account} ${5:Amount} ${6:#:Commodity} + +snippet pad +abbr pad +options head + ${1:YYYY}-${2:MM}-${3:DD} pad ${4:BalanceAccount} ${5:PadAccount} diff --git a/bundle/neosnippet-snippets/neosnippets/bib.snip b/bundle/neosnippet-snippets/neosnippets/bib.snip new file mode 100644 index 000000000..74ed8387b --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/bib.snip @@ -0,0 +1,232 @@ +snippet article +alias @article + @article{${1:LABEL}, + author = {${2}}, + title = {${3}}, + journal = {${4}}, + year = {${5}}, + memo = {volume, number, pages, month, note} + } + +snippet book +alias @book + @book{${1:LABEL}, + author/editor = {${2}}, + title = {${3}}, + publisher = {${4}}, + year = {${5}}, + memo = {volume, series, address, edition, month, note}, + } + +snippet booklet +alias @booklet + @booklet{${1:LABEL}, + title = {${2}}, + memo = {author, howpublished, address, month, year, note}, + } + +snippet inbook +alias @inbook + @inbook{${1:LABEL}, + author/editor = {${2}}, + title = {${3}}, + chapter/pages = {${4}}, + publisher = {${5}}, + year = {${6}}, + memo = {volume, series, address, edition, month, note}, + } + +snippet incollection +alias @incollection + @incollection{${1:LABEL}, + author = {${2}}, + title = {${3}}, + booktitle = {${4}}, + year = {${5}}, + memo = {editor, pages, organization, publisher, address, month, note}, + } + +snippet inproceedings +alias @inproceedings @conference conference + @inproceedings{${1:LABEL}, + author = {${2}}, + title = {${3}}, + booktitle = {${4}}, + year = {${5}}, + memo = {editor, volume, number, series, pages, address, month, + organization, publisher, note} + } + +snippet manual +alias @manual + @manual{${1:LABEL}, + title = {${2}}, + memo = {author, organization, address, edition, month, year, note}, + } + +snippet mastersthesis +alias @mastersthesis + @mastersthesis{${1:LABEL}, + author = {${2}}, + title = {${3}}, + school = {${4}}, + year = {${5}}, + memo = {address, month, note}, + } + +snippet misc +alias @misc + @misc{${1:LABEL}, + memo = {author, title, howpublished, month, year, note}, + } + +snippet online +alias @online + @online{${1:LABEL}, + author = {${2}}, + title = {${3}}, + url = {${4}}, + note = {year/date}, + } + +snippet phdthesis +alias @phdthesis + @phdthesis{${1:LABEL}, + author = {${2}}, + title = {${3}}, + school = {${4}}, + year = {${5}}, + memo = {address, month, note}, + } + +snippet proceedings +alias @proceedings + @proceedings{${1:LABEL}, + title = {${2}}, + year = {${3}}, + memo = {editor, publisher, organization, address, month, note}, + } + +snippet techreport +alias @techreport + @techreport{${1:LABEL}, + author = {${2}}, + title = {${3}}, + institution = {${4}}, + year = {${5}}, + memo = {type, number, address, month, note}, + } + +snippet unpublished +alias @unpublished + @unpublished{${1:LABEL}, + author = {${2}}, + title = {${3}}, + note = {${4}}, + memo = {month, year}, + } + + +snippet address + address = {${1}}, + ${0} + +snippet annote + annote = {${1}}, + ${0} + +snippet author + author = {${1}}, + ${0} + +snippet booktitle + booktitle = {${1}}, + ${0} + +snippet crossref + crossref = {${1}}, + ${0} + +snippet chapter + chapter = {${1}}, + ${0} + +snippet edition + edition = {${1}}, + ${0} + +snippet editor + editor = {${1}}, + ${0} + +snippet eprint + eprint = {${1}}, + ${0} + +snippet howpublished + howpublished = {${1}}, + ${0} + +snippet institution + institution = {${1}}, + ${0} + +snippet journal + journal = {${1}}, + ${0} + +snippet key + key = {${1}}, + ${0} + +snippet month + month = {${1}}, + ${0} + +snippet note + note = {${1}}, + ${0} + +snippet number + number = {${1}}, + ${0} + +snippet organization + organization = {${1}}, + ${0} + +snippet pages + pages = {${1}}, + ${0} + +snippet publisher + publisher = {${1}}, + ${0} + +snippet school + school = {${1}}, + ${0} + +snippet series + series = {${1}}, + ${0} + +snippet title + title = {${1}}, + ${0} + +snippet type + type = {${1}}, + ${0} + +snippet url + url = {${1}}, + ${0} + +snippet volume + volume = {${1}}, + ${0} + +snippet year + year = {${1}}, + ${0} diff --git a/bundle/neosnippet-snippets/neosnippets/blade.snip b/bundle/neosnippet-snippets/neosnippets/blade.snip new file mode 100644 index 000000000..0b2cc946e --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/blade.snip @@ -0,0 +1,120 @@ +snippet yl +abbr @yield + @yield('${1}') + +snippet ext +abbr @extends + @extends('${1}') + +snippet sec +abbr @section + @section('${1}', '${2}') + +snippet section +abbr @section ... @endsection + @section('${1:section name}') + ${2} + @endsection + + +snippet section-parent +abbr @section @parent ... @endsection + @section('${1:section name}') + @parent + + ${2} + @endsection + +snippet compo +abbr @component ... @endcomponent + @component('${1}') + ${2} + @endcomponent + +snippet slot +abbr @slot ... @endslot + @slot('${1}') + ${2} + @endslot + +snippet if +abbr if ... endif + @if(${1:condition}) + ${2} + @endif + +snippet ifelse +abbr if elseif else endif + @if (${1:condition}) + ${2} + @elseif (${3:condition}) + ${4} + @else + ${5} + @endif + +snippet unless +abbr @unless ... @endunless + @unless (${1:condition}) + ${2} + @endunless + +snippet isset +abbr @isset ... @endisset + @isset(${1}) + ${2} + @endisset + +snippet empty +abbr @empty ... @endempty + @empty(${1}) + ${2} + @endempty + +snippet for +abbr @for ... @endfor + @for ($i = 0; $i < ${1}; $i++) + ${2} + @endfor + +snippet foreach +abbr @foreach ... @endforeach + @foreach (${1} as ${2}) + ${3} + @endforeach + +snippet forelse +abbr @forelse ... @empty ... @endforeach + @forelse (${1} as ${2}) + ${3} + @empty + ${4} + @endforelse + +snippet while +abbr @while ... @endwhile + @while (${1}) + ${2} + @endwhile + +snippet comment +abbr {{-- comments --}} + {{-- ${1} --}} + +snippet php +abbr @php ... @endphp + @php + ${1} + @endphp + +snippet include +abbr @include + @include('${1}') + + + + + + + + diff --git a/bundle/neosnippet-snippets/neosnippets/c.snip b/bundle/neosnippet-snippets/neosnippets/c.snip new file mode 100644 index 000000000..21adbe6f2 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/c.snip @@ -0,0 +1,309 @@ +# Control structures {{{ +snippet if +options head +abbr if () {} + if (${1:#:condition}) { + ${0:TARGET} + } + +# No head option in else/elseif so it can be expanded after "}" +snippet else +abbr else {} + else { + ${0:TARGET} + } + +snippet elseif +abbr else () {} + else if (${1:#:condition}) { + ${0:TARGET} + } + +snippet ifelse +options head +abbr if () {} else {} + if (${1:#:condition}) { + ${2:TARGET} + } else { + ${3} + } + +snippet for +options head +abbr for () {} + for (${1:int} ${2:i} = ${3:0}; $2 < ${4}; $2++) { + ${0:#:TARGET} + } + +# Counter based for's (don't ask for the type or count start) +snippet fori +options head +abbr for (int x;...; x++) {} + for (int ${1:i} = 0; $1 < ${2}; $1++) { + ${0:#:TARGET} + } + +# For reverse counter +snippet forri +options head +abbr for (int x; ...; x--) {} + for (int ${1:i} = ${2}; $1 >= 0; $1--) { + ${0:#:TARGET} + } + +snippet while +options head +abbr while () {} + while (${1:#:condition}) { + ${0:TARGET} + } + +snippet do_while +options head +alias do + do { + ${0:TARGET:code} + } while (${1:#:condition}); + +snippet switch +options head +abbr switch () {} + switch (${1:#:var}) { + case ${2:#:val}: + ${0:TARGET} + break; + } + +snippet case +options head +abbr case: break; + case ${1}: + ${0} + break; + +# Ternary conditional operator +snippet conditional + (${1:#:condition}) ? ${2:#:a} : ${3:#:b} + +# }}} + +# Definition bodies {{{ +snippet function +options head +alias func +abbr func() {} + ${1:void} ${2:#:func_name}(${3:void}) { + ${0:TARGET} + } + +snippet struct +options head +abbr struct {} + struct ${1:#:name} { + ${0:TARGET:data} + }; + +# Typedef struct +snippet struct_typedef +options head + typedef struct ${1:#:name} { + ${0:TARGET:data} + }; + +snippet enum +options head +abbr enum {} + enum ${1:#:name} { + ${0:TARGET} + }; + +# hard-tab is necessary; C indent doesn't support this. +snippet main +options head + int main(int argc, char const* argv[]) + { + ${0:TARGET} + return 0; + } + +snippet helloworld +options head + #include + int main(int argc, char const* argv[]) + { + puts("hello, world!"); + return 0; + } + +# }}} + +# Preprocessing directives {{{ +# #include <...> +snippet inc +options head +alias #inc, #include + #include <${1:stdio}.h> + +# #include "..." +snippet inc2 +options head +alias #inc2, #include2 + #include "${1}.h" + +snippet #if +options head + #if ${1} + ${0} + #endif + +snippet ifdef +options head +alias #ifdef +abbr #ifdef ... #endif + #ifdef ${1:#:SYMBOL} + ${0} + #endif + +snippet ifndef +options head +alias #ifndef +abbr #ifndef ... #define ... #endif + #ifndef $1 + #define ${1:#:SYMBOL} + #endif${0} + +# This snippet used the placeholder instead of a trailing space +snippet def +options head +alias #def, #define + #define ${1} + +# Include-Guard +snippet once +options head +alias include-guard +abbr #ifndef ... #define ... #endif + #ifndef ${1:#:SYMBOL} + #define $1 + + ${0:TARGET} + #endif /* end of include guard */ + +# }}} + +# Built-in function calls {{{ +snippet printf +abbr printf("...\n", ...); + printf("${1}\n"${2}); + +snippet scanf +abbr scanf("...", ...); + scanf("${1}", ${2}); + +snippet fprintf +abbr fprintf(..., "...\n", ...); + fprintf(${1:stderr}, "${2}\n"${3}); + +snippet fopen +abbr fopen("...", "..."); + fopen("${1:PATH}", "${2:MODE}"); + ${0:TARGET} + fclose(${3:FD}); + +snippet fgets +abbr fgets(row, length, file); + fgets(${0:ROW}, ${1:LENGTH}, ${2:stdin}); + +snippet fscanf +abbr fscanf(file, "...", ...); + fscanf(${1:stdin}, "${2}", ${3}); + +snippet fwrite +abbr fwrite(......, file) + fwrite(${1:ARRAY}, sizeof(${2:TYPE}), ${3:N_MEMBERS}, ${4:FILE}) + +snippet fread +abbr fread(......, file) + fread(${1:ARRAY}, sizeof(${2:TYPE}), ${3:N_MEMBERS}, ${4:FILE}) + +snippet memcpy +abbr memcpy(dest, src, nbytes) + memcpy(${1:DEST}, ${2:SRC}, ${3:NBYTES}) + +snippet malloc +abbr malloc(size) + ($2 *)malloc(${1:N_MEMBERS} * sizeof(${2:TYPE})); + ${0} + free(${3:MEM}); + +snippet calloc +abbr calloc(n, size) + ($2 *)calloc(${1:N_MEMBERS}, sizeof(${2:TYPE})); + ${0} + free(${3:MEM}); + +snippet realloc +abbr realloc(old, size) + ($3 *)realloc(${1:OLD}, ${2:N_MEMBERS} * sizeof(${3:TYPE})); + ${0} + +snippet seed_rand + srand(time(NULL)); +# }}} + +# Built-in operators and alias {{{ +snippet typedef + typedef ${1:#:base_type} ${2:#:custom_type}; + +snippet sizeof +alias size + sizeof(${0:TARGET}) + +snippet sizeof_array +alias array_size + (sizeof(${1:#:array}) / sizeof(*($1))) + +snippet _Static_assert +alias _static_assert +options head + _Static_assert(${1:#:condition}, ${2:#:message}); + +snippet static_assert +options head + static_assert(${1:#:condition}, ${2:#:message}); + +snippet _Generic +alias generic, select + _Generic(${1:#:expression}, ${2:#:association-list}) + +snippet va_list +options head +abbr va_start(va_list, last_arg); ... ; va_end() + va_list ${1:ap}; + va_start($1, ${2:LAST_ARG}); + ${0} + va_end($1); +# }}} + +# Comments {{{ +snippet comment +alias /* + /* ${1:#:comment} */ + ${0} + +snippet doxy +abbr /** @brief ... +options head + /** + * @brief ${1:function description} + * + * @details ${2:detailed description} + * + * @param ${3:param} + * + * @return ${4:return type} + */ + +# }}} + +# vim: fdm=marker diff --git a/bundle/neosnippet-snippets/neosnippets/clojure.snip b/bundle/neosnippet-snippets/neosnippets/clojure.snip new file mode 100644 index 000000000..cce5a2e0a --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/clojure.snip @@ -0,0 +1,97 @@ +snippet defn-doc +abbr defn function "..." [...] ... +options head + (defn ${1:name} + "${2:doc}" + [${3}] + ${0}) + +snippet try +abbr (try ... (catch ... + (try + ${1} + (catch ${2:Exception} e ${3:nil})) + +snippet ref-set +abbr (dosync (ref-set ... +options head + (dosync + (ref-set ${1:ref} ${2:value})) + +# http://tnoda-clojure.tumblr.com/post/24969285880/clojure-scripting +snippet shebang +options head + #^:shebang '[ + exec java -cp \`locate clojure- | grep -P "clojure-[\\d\\.]+\\.jar$" | tail -1\` clojure.main "\$0" + ] + + +snippet warn +options head + (binding [*out* *err*] + (println ${0:TARGET})) + +snippet defrecord +options head + (defrecord ${1:record} [${2:constructor-args}] + ${3:protocol} (${3:method} [${5}] ${6})) + +snippet deftype +options head + (defrecord ${1:type} [${2:constructor-args}] + ${3:protocol} (${3:method} [${5}] ${6})) + +snippet require-core-match +options head + (ns ${1:example} + (:require [clojure.core.match :as m])) + ; vim: set lispwords+=m/match : + +snippet deftest +options head + (deftest ${1:a}-test + (testing "${2:hello}" + ${0:TARGET:(is (= 0 1))})) + +snippet use-strint-in-ns +options head + (:require [clojure.core.strint :refer (<<)]) + +snippet dir-glob +options head + [org.clojars.hozumi/clj-glob "0.1.2"] + (:require [org.satta.glob :as g]) + (g/glob "${0:TARGET}") + +snippet sleep + (Thread/sleep ${1}) + +snippet defproejct +options head + (defproject ${1:aaa} "0.1-SNAPSHOT" + :description "FIXME: write description" + :url "https://github.com/${2}" + :license {:name "GNU GPL v3+" + :url "http://www.gnu.org/licenses/gpl-3.0.en.html"} + :dependencies [[org.clojure/clojure "1.7.0"]] + :main ^:skip-aot ${3:aaa.core} + :target-path "target/%s" + :min-lein-version "2.3.0") + +snippet ns +options head + (ns ${1:`substitute(substitute(substitute(expand('%:p:r'), '.*/\(src\|test\)/', '', ''), '/', '.', 'g'), '_', '-', 'g')`} + (:require `expand('%:r') =~ '_test$' ? '[clojure.test :refer :all]' : ''`${2:})) + +snippet bench + (let [bench-before (System/currentTimeMillis)] + ${1:TARGET} + (prn 'Took (- (System/currentTimeMillis) bench-before) 'msec)) + +snippet private +options word + @#' + +snippet java-methods +options head + (:members (clojure.reflect/refrect ${1})) diff --git a/bundle/neosnippet-snippets/neosnippets/cmake.snip b/bundle/neosnippet-snippets/neosnippets/cmake.snip new file mode 100644 index 000000000..b0ec95194 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/cmake.snip @@ -0,0 +1,92 @@ +snippet new_project +options head + project(${1:project_name}) + + set(${2:PROJECT}_VERSION_MAJOR 0) + set($2_VERSION_MINOR 0) + set($2_VERSION_TEENY 1) + set(PACKAGE_VERSION "${$2_VERSION_MAJOR}.${$2_VERSION_MINOR}.${$2_VERSION_TEENY}") + + cmake_minimum_required(VERSION ${3:2.8}) + + ${0} + +snippet if +abbr if() endif() +options head + if(${1:#:condition}) + ${0} + endif() + +snippet if_else +abbr if() else() endif() +options head + if(${1:#:condition}) + ${2} + else() + ${3} + endif() + +snippet foreach +abbr foreach() endforeach() +options head + foreach(${1:item} ${2:items}) + ${3} + endforeach($1) + +snippet macro +abbr macro() endmacro() +options head + macro(${1:name} ${2:args}) + ${3} + endmacro($1) + +snippet function +abbr function() endfunction() +options head + function(${1:name} ${2:args}) + ${3} + endfunction($1) + +snippet message +abbr message("...") +options head + message("${1}") + +snippet status_message +abbr message(STATUS "...") +options head + message(STATUS "${1}") + +snippet warning_message +abbr message(WARNING "...") +options head + message(WARNING "${1}") + +snippet author_warning_message +abbr message(AUTHOR_WARNING "...") +options head + message(AUTHOR_WARNING "${1}") + +snippet send_error_message +abbr message(SEND_ERROR "...") +options head + message(SEND_ERROR "${1}") + +snippet fatal_error_message +abbr message(FATAL_ERROR "...") +options head + message(FATAL_ERROR "${1}") + +snippet while +abbr while() endwhile() +options head + while(${1:#:condition}) + ${2} + endwhile() + +snippet file_GLOBE_RECURSE +abbr file(GLOB_RECURSE ...) +options head + file(GLOB_RECURSE ${1:#:var} ${2:#:glob_paths}) + diff --git a/bundle/neosnippet-snippets/neosnippets/coffee.snip b/bundle/neosnippet-snippets/neosnippets/coffee.snip new file mode 100644 index 000000000..55db9e1f1 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/coffee.snip @@ -0,0 +1,72 @@ +snippet req + ${1:#:object} = require('$1') + +snippet log + console.log ${0} + +snippet unl + ${1:#:action} unless ${2:#:condition} + +snippet try + try + ${1:TARGET} + catch ${2:#:error} + ${3} + +snippet if + if ${1:#:condition} + ${0:TARGET} + +snippet elif + else if ${1:#:condition} + ${0:TARGET} + +snippet ifte + if ${1:#:condition} then ${2:#:value} else ${3:#:other} + +snippet ife + if ${1:#:condition} + ${2:TARGET} + else + ${3:#:body...} + +snippet swi + switch ${1:#:object} + when ${2:#:value} + ${0:TARGET} + +snippet ^j + \`${1:javascript}\` + +snippet forr + for ${1:#:name} in [${2:#:start}..${3:#:finish}]${4: by ${5:#:step\}} + ${0:TARGET} + +snippet forrex + for ${1:#:name} in [${2:#:start}...${3:#:finish}]${4: by ${5:#:step\}} + ${0:TARGET} + +snippet foro + for ${1:#:key}, ${2:#:value} of ${3:#:object} + ${0:TARGET} + +snippet fora + for ${1:#:name} in ${2:#:array} + ${0:TARGET} + +snippet fun + ${1:#:name} = (${2:#:args}) -> + ${0:TARGET} + +snippet bfun + (${1:#:args}) => + ${0:TARGET} + +snippet cla +abbr cla +options head + class ${1:#:ClassName}${2: extends ${3:#:Ancestor\}} + + constructor: (${4:#:args}) -> + ${5:TARGET} + diff --git a/bundle/neosnippet-snippets/neosnippets/cpp.snip b/bundle/neosnippet-snippets/neosnippets/cpp.snip new file mode 100644 index 000000000..9518c472d --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/cpp.snip @@ -0,0 +1,106 @@ +include c.snip + +# #include <...> +snippet inc +options head +alias #inc, #include + #include <${1:iostream}>${0} +# #include "..." +snippet inc2 +options head +alias #inc2, #include2 + #include "${1}"${0} + +snippet template +abbr template + template ${0} + +snippet class +options head +abbr class {} + class ${1:#:name} { + ${2} + public: + $1(${3}); + }; + $1::$1($3) { + ${0:TARGET} + } + +snippet class-without-constructor +options head +abbr class {} + class ${1:#:name} { + ${2} + }; + +snippet try +options head +abbr try catch + try { + ${1:#:TARGET} + } catch (${2:...}) { + ${3} + } + +# range based for ( C++11 feature ) +snippet for_CPP11 +options head +abbr for (:) {} + for (${1:auto&& }${2:var} : ${3:container}) { + ${0:TARGET} + } + +# lambda expression ( C++11 feature ) +snippet lambda +abbr [](){} + [${1}](${2})${3}{ ${4:TARGET} }${0:;} + +# scoped enumeration ( C++11 feature ) +snippet enum_scoped +options head +abbr enum struct {}; + enum struct ${1:#:name} { ${2:#:TARGET} }; + +# static assert ( C++11 feature ) +snippet static_assert +abbr static_assert(,"") + static_assert( ${1}, "${2}" );${0} + +delete namespace +options head +snippet namespace +abbr namespace {} + namespace ${1:#:name} { + ${0:TARGET} + } // namespace $1 + +snippet static_cast +abbr static_cast<>() + static_cast<${1}>(${2})${0} + +snippet reinterpret_cast +abbr reinterpret_cast<>() + reinterpret_cast<${1}>(${2})${0} + +snippet const_cast +abbr const_cast<>() + const_cast<${1}>(${2})${0} + +snippet dynamic_cast +abbr dynamic_cast<>() + dynamic_cast<${1}>(${2})${0} + +snippet helloworld +abbr #include int main... + #include + + int main(int argc, char const* argv[]) + { + std::cout << "hello, world!" << std::endl; + return 0; + } + +snippet p +options head + std::cout << ${0:TARGET} << std::endl; diff --git a/bundle/neosnippet-snippets/neosnippets/cs.snip b/bundle/neosnippet-snippets/neosnippets/cs.snip new file mode 100644 index 000000000..76580ce64 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/cs.snip @@ -0,0 +1,483 @@ +# Structure +snippet namespace +alias name +abbr namespace {} +options head + namespace ${1:#:Name} { + ${0:TARGET} + } + +snippet class +abbr class {} + class ${1:#:Name} ${2::} ${3:Parent}${4:,} ${5:Interface} { + ${0:TARGET} + } + +snippet struct +abbr struct {} + struct ${1:#:Name} ${2::} ${3:Interface} { + ${0:TARGET} + } + +snippet interface +abbr interface {} + interface ${1:#:IName} ${2::} ${3:Parent} { + ${0:TARGET} + } + +snippet method + ${1:void} ${2:#:Method}(${3:#:arguments}) { + ${0:TARGET} + } + +snippet enum +abbr enum {} + enum ${1:#:Name} { + ${0:TARGET} + } + + +# Declare +snippet delegate + delegate ${1:void} ${2:#:Delegate}(${3:#:arguments});${0} + +snippet property +alias prop + ${1:int} ${2:#:Name} { get${3:;} ${4:#:private }set${5:;} }${0} + +snippet get +abbr get {} + get {${1:TARGET}}${0} + +snippet set +abbr set {} + set {${1:TARGET}}${0} + + +# PreProcess Syntax +snippet define +alias def +options head + #define ${0:#:SYMBOL} + +snippet undef +alias und +options head + #undef ${0:#:SYMBOL} + +snippet ifdef +options head + #if ${1:SYMBOL} + ${0:TARGET} + #endif + +snippet warning +alias warn +options head + #warning ${0:#:message} + +snippet error +alias err +options head + #error ${0:#:message} + +snippet line +options head + #line ${0:#:number} + +snippet region +alias reg +options head + #region ${1:#:name} + ${0:TARGET} + #endregion + +snippet pragma_warning +alias pragma pragma_warn +options head + #pragma warning ${2:disable} ${3:#:errno} + + +# Syntax +snippet if +abbr if () {} + if (${1:#:condition}) { + ${0:TARGET} + } + +snippet elseif +alias elif +abbr else if () {} + else if (${1:#:condition}) { + ${0:TARGET} + } + +snippet ifelse +alias ifel +abbr if () {} else {} + if (${1:#:condition}) { + ${2:TARGET} + } else { + ${3:TARGET} + } + +snippet while +abbr while () {} + while (${1:#:condition}) { + ${0:TARGET} + } + +snippet do_while +alias dowhile +abbr do {} while() {} + do { + ${0:TARGET} + } while (${1:#:condition}); + +snippet for +abbr for () {} + for (${1:#:var}; ${2:#:condition}; ${3:#:effect}) { + ${0:TARGET} + } + +snippet foreach +alias fore +abbr foreach () {} + foreach (${1:#:var} in ${2:#:iter}) { + ${0:TARGET} + } + +snippet switch +abbr switch () {} + switch (${1:#:var}) { + case ${2:#:val}: + ${0:TARGET} + break; + } + +snippet case +options head + case ${1:#:val}: + ${0:TARGET} + break; + +snippet break +options head + break; + +snippet goto +options head + goto case ${1:#:Val};${0} + +snippet default +options head + default: + ${0:TARGET} + break; + +snippet try_without_catch_nor_finally +alias try_n +options head + try { + ${0:TARGET} + } + +snippet try_catch +alias try +abbr try {} catch () {} +options head + try { + ${0:TARGET} + } catch (${1:Exception} ${2:e}) { + ${3:Console.WriteLine(e.Message);} + } + +snippet try_catch_n +alias try_cn +abbr try {} catch {} +options head + try { + ${0:TARGET} + } catch { + ${1} + } + +snippet try_catch_finally +alias try_cf +abbr try {} catch () {} finally {} +options head + try { + ${0:TARGET} + } catch (${1:Exception} ${2:e}) { + ${3:Console.WriteLine(e.Message);} + } finally { + ${4} + } + +snippet try_finally +alias try_f +abbr try {} finally {} +options head + try { + ${0:TARGET} + } finally { + ${1} + } + +snippet try_catch_n_finally +alias try_cnf +abbr try {} catch {} finally {} +options head + try { + ${0:TARGET} + } catch { + ${1} + } finally { + ${2} + } + +snippet catch +abbr catch () {} + catch (${1:Exception} ${2:e}) { + ${0:Console.WriteLine(e.Message);} + } + +snippet catch_n +abbr catch {} + catch { + ${0} + } + +snippet finally +alias fin +abbr finally {} + finally { + ${0:TARGET} + } + +snippet throw +options head + throw ${0:#:exception} + +snippet lock +abbr lock () {} +options head + lock (${1:#:resource}) { + ${0:TARGET} + } + +snippet using_resource +alias using resource +abbr using () {} +options head + using (${1:#:resource}) { + ${0:TARGET} + } + +snippet checked +abbr checked () {} +options head + checked (${1:#:var}) { + ${0:TARGET} + } + +snippet unchecked +abbr unchecked () {} +options head + unchecked (${1:#:var}) { + ${0:TARGET} + } + +snippet unsafe +abbr unsafe {} +options head + unsafe { + ${0:TARGET} + } + +snippet fixed +abbr fixed () {} +options head + fixed (${1:#:type}* ${2:#:var} = ${3:#:adress}) { + ${0:TARGET} + } + +snippet using_import +alias import +options head + using ${1:#:path};${0} + +snippet using_typedef +alias typedef +options head + using ${1:Name} = ${2:Type};${0} + + +# Import Path +snippet s.l + System.Linq + +snippet s.c.g + System.Collections.Generic + +snippet s.t + System.Text + +snippet s.i + System.IO + +snippet s.d + System.Diagnostics + +snippet s.r.c + System.Runtie.CompilerServices + +snippet s.w.f + System.Windows.Forms + + +# Attribute +snippet serializable +alias serial +options head + [SerializableAttribute] + +snippet conditional +alias cond +options head + [Conditional("${1:#:SYMBOL}")]${0} + +snippet obsolete +alias obs dep deprecated +options head + [Obsolete("${1:#:description}")]${0} + +snippet asm_internals_visible_to +alias internals asmInternalsVisibleTo friend_attr +options head + [assembly: InternalsVisibleTo("${1:#:FriendName}")]${0} + + +#XML Document +snippet c +abbr + ${1:#:text} + +snippet code +abbr + ${0:#:content} + +snippet example +abbr + ${0:#:description} + +snippet exception +abbr + ${2:#:description} + +snippet include +abbr + + +snippet param +abbr + ${0:#:description} + +snippet paramref +abbr + + +snippet returns +abbr + ${0:#:description} + +snippet remarks +abbr + ${0:#:description} + +snippet see +abbr + + +snippet seealso +abbr + } + +snippet summary +abbr

+ ${0:#:description} + +snippet typeparam +abbr + ${0:#:description} + +snippet typeparamref +abbr + + +snippet value +abbr + ${0:#:description} + + +# Other +snippet main +options head + public static void Main(string[] args) { + ${0} + } + +snippet writeline +alias println p +options head + Console.WriteLine(${1:#:message});${0} + +snippet write +alias print +options head + Console.Write(${1:#:message});${0} + +snippet helloworld +options head + public class ${1:Hello} { + public static void Main(string[] args) { + System.Console.WriteLine("Hello, world!"); + } + } + + +# NUnit +snippet testclass +alias tc +options head + [TestFixture] + public class ${1}Test { + ${0:TARGET} + } + +snippet testsetup +alias tsu +options head + [SetUp] + public void SetUp() { + ${0:TARGET} + } + +snippet testteardown +alias ttd +options head + [TearDown] + public void TearDown() { + ${0:TARGET} + } + +snippet test +options head + [Test] + public void ${1:#:Name}Test() { + ${0:TARGET} + } + +snippet category +options head + [Category("${0:#:category}")] diff --git a/bundle/neosnippet-snippets/neosnippets/css.snip b/bundle/neosnippet-snippets/neosnippets/css.snip new file mode 100644 index 000000000..56d621176 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/css.snip @@ -0,0 +1,272 @@ +snippet background +alias bg + background: ${1};${2} + +snippet backattachment +alias ba + background-attachment: ${1};${2} + +snippet backcolor +alias bc + background-color: ${1};${2} + +snippet backimage +alias bi + background-image: ${1};${2} + +snippet backposition +alias bp + background-position: ${1};${2} + +snippet backrepeat +alias br + background-repeat: ${1};${2} + +snippet border +alias b + border: ${1};${2} + +snippet border-style +alias bs + border-style: ${1};${2} + +snippet border-color +alias bc + border-color: ${1};${2} + +snippet border-width +alias bw + border-width: ${1};${2} + +snippet border-bottom-width +alias bbw + border-bottom-width: ${1};${2} + +snippet border-top-width +alias btw + border-top-width: ${1};${2} + +snippet border-left-width +alias blw + border-left-width: ${1};${2} +snippet border-right-width +alias brw + border-right-width: ${1};${2} + + +snippet border-bottom-style +alias bbs + border-bottom-style: ${1};${2} + +snippet border-top-style +alias bts + border-top-style: ${1};${2} + +snippet border-left-style +alias bls + border-left-style: ${1};${2} +snippet border-right-style +alias brs + border-right-style: ${1};${2} + + +snippet border-bottom-color +alias bbc + border-bottom-color: ${1};${2} + +snippet border-top-color +alias btc + border-top-color: ${1};${2} + +snippet border-left-color +alias blc + border-left-color: ${1};${2} +snippet border-right-color +alias brc + border-right-color: ${1};${2} + +snippet outline +alias ol + outline: ${1};${2} + +snippet outline-color +alias oc + outline-color: ${1};${2} + +snippet outline-style +alias os + outline-style: ${1};${2} + +snippet outline-width +alias ow + outline-width: ${1};${2} + +snippet color +alias c + color: ${1};${2} + +snippet direction +alias d + direction: ${1};${2} + +snippet letter-spacing +alias ls + letter-spacing: ${1};${2} + +snippet line-height +alias lh + line-height: ${1};${2} + +snippet text-align +alias ta + text-align: ${1};${2} + +snippet text-decoration +alias td + text-decoration: ${1};${2} + +snippet text-indent +alias ti + text-indent: ${1};${2} + +snippet text-transform +alias tt + text-transform: ${1};${2} + +snippet unicode-bidi +alias ub + unicode-bidi: ${1};${2} + +snippet white-space +alias ws + white-space: ${1};${2} + +snippet word-spacing +alias ws + word-spacing: ${1};${2} + +snippet font +alias f + font: ${1};${2} + +snippet font-family +alias ff + font-family: ${1:"Times New Roman",Georgia,Serif};${2} + +snippet font-size +alias fs + font-size: ${1};${2} + +snippet font-style +alias fs + font-style: ${1};${2} + +snippet font-weight +alias fw + font-weight: ${1};${2} + +snippet margin +alias m + margin: ${1};${2} + +snippet margin-bottom +alias mb + margin-bottom: ${1};${2} + +snippet margin-top +alias mt + margin-top: ${1};${2} + +snippet margin-left +alias ml + margin-left: ${1};${2} + +snippet margin-right +alias mr + margin-right: ${1};${2} + +snippet padding +alias p + padding: ${1};${2} + +snippet padding-bottom +alias pb + padding-bottom: ${1};${2} + +snippet padding-top +alias pt + padding-top: ${1};${2} + +snippet padding-left +alias pl + padding-left: ${1};${2} + +snippet padding-right +alias pr + padding-right: ${1};${2} + +snippet list-style +alias ls + list-style: ${1};${2} + +snippet list-style-image +alias lsi + list-style-image: ${1};${2} + +snippet list-style-position +alias lsp + list-style-position: ${1};${2} + +snippet list-style-type +alias lst + list-style-type: ${1};${2} + +snippet content +alias c + content: ${1};${2} + +snippet height +alias h + height: ${1};${2} + +snippet max-height +alias mah + max-height: ${1};${2} + +snippet max-width +alias maw + max-width: ${1};${2} + +snippet min-height +alias mih + min-height: ${1};${2} + +snippet min-width +alias miw + min-width: ${1};${2} + +snippet width +alias w + width: ${1};${2} + +# For media query +snippet media +abbr @media ... +options head + @media ${1:condition} { + ${0:TARGET} + } + +snippet media-min-width +abbr @media all and (min-width) {...} +options head + @media ${1:all} and (min-width: ${2:SIZE}) { + ${0:TARGET} + } + +snippet media-max-width +abbr @media all and (max-width) {...} +options head + @media ${1:all} and (max-width: ${2:SIZE}) { + ${0:TARGET} + } diff --git a/bundle/neosnippet-snippets/neosnippets/cuda.snip b/bundle/neosnippet-snippets/neosnippets/cuda.snip new file mode 100644 index 000000000..425ca67f1 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/cuda.snip @@ -0,0 +1 @@ +extends cpp diff --git a/bundle/neosnippet-snippets/neosnippets/d.snip b/bundle/neosnippet-snippets/neosnippets/d.snip new file mode 100644 index 000000000..b173a4e67 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/d.snip @@ -0,0 +1,40 @@ +include c.snip + +# Delete snippet depended on C. +delete struct +delete struct_typedef +delete enum +delete main +delete inc +delete inc2 +delete Inc +delete Def +delete def +delete once +delete printf +delete fprintf + +snippet foreach +abbr foreach() {} + foreach (${1:#:var}; ${2:#:list}) { + ${3:TARGET} + } + +snippet class +abbr class {} + class ${1:#:name} { + ${2:TARGET} + } + +snippet struct +abbr struct {} + struct ${1:#:name} { + ${2:TARGET} + } + +snippet enum +abbr enum {} + enum ${1:#:name} { + ${2:TARGET} + } + diff --git a/bundle/neosnippet-snippets/neosnippets/elixir.snip b/bundle/neosnippet-snippets/neosnippets/elixir.snip new file mode 100644 index 000000000..b8f17f6a8 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/elixir.snip @@ -0,0 +1,119 @@ +snippet do +abbr do...end +options head + do + ${1:TARGET} + end + +snippet if +abbr if .. do .. end +options head + if ${1:true} do + ${2:TARGET} + end + +snippet ife +abbr if .. do .. else .. end +options head + if ${1:true} do + ${2:ok} + else + ${3:ok} + end + +snippet case +abbr case .. end +options head + case ${1} do + ${2} -> ${3} + end + +snippet def +abbr def .. do .. end +options head + def ${1:name} do + ${2:TARGET} + end + +snippet defm +abbr def module +options head + defmodule ${1:module_name} do + ${2:TARGET} + end + +snippet defp +abbr defp .. end +options head + defp ${1:name} do + ${2:TARGET} + end + +snippet doc +abbr @doc """...""" +options head + @doc """${0:TARGET}""" + +snippet mdoc +abbr @moduledoc """...""" +options head + @moduledoc """${0:TARGET}""" + +snippet fn +abbr fn(..) -> .. end +options head + fn(${1:args}) -> ${2:TARGET} end + +snippet rec +abbr receive .. do .. end +options head + receive do + ${1} -> ${2} + end + +snippet test +abbr test .. do .. end +options head + test "${1:test_name}" do + ${2:TARGET} + end + +snippet try +abbr try .. rescue .. end +options head + try do + ${1:TARGET} + rescue + ${2} -> ${3} + +snippet with +abbr with .. do .. end +options head + with ${1} + do + ${2:TARGET} + end + +snippet describe +abbr describe .. do .. end +options head + describe "${1:describe_name}" do + ${2:TARGET} + end + +snippet puts + IO.puts(${1}) + +snippet p +abbr IO.inspect() + IO.inspect(${1}) + +snippet main +options head + defmodule Main do + def main do + ${1:TARGET} + end + end + + Main.main diff --git a/bundle/neosnippet-snippets/neosnippets/elm.snip b/bundle/neosnippet-snippets/neosnippets/elm.snip new file mode 100644 index 000000000..e92573a2e --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/elm.snip @@ -0,0 +1,114 @@ +snippet module +options head + module ${1:`substitute(substitute(expand('%:r'), '[/\\]','.','g'),'^\%(\l*\.\)\?','','')} exposing (${2:...}) + ${0} + + +snippet import +options head +abbr import +alias imp + import ${1:String} + ${0} + + +snippet importAs +options head +abbr import ... as ... +alias impa + import ${1} as ${2} + ${0} + + +snippet importExposing +options head +abbr import ... exposing (..) +alias impe + import ${1:Html} exposing (${2:..}) + ${0} + + +snippet importAsExposing +options head +abbr import ... as ... exposing (..) +alias impae + import ${1:Html} as ${2} exposing (${2:..}) + ${0} + + +snippet main +abbr main : Program +alias prog +options head + main : Program Never ${2:Model} ${3:Msg} + main = + ${4:Html.}program + { init: ${6:( model, Cmd.none )} + , update: ${7:update} + , subscriptions: ${8:subscriptions} + ${9:, view: ${10:view\}} + } + + ${0} + + +snippet programWithFlags +abbr main : Program +alias progf mainf +options head + main : Program ${1:Flags} ${2:Model} ${3:Msg} + main = + ${4:Html.}programWithFlags + { init: ${6:initWithFlags} + , update: ${7:update} + , subscriptions: ${8:subscriptions} + ${9:, view: ${10:view\}} + } + + ${0} + + +snippet basicProgram +abbr main : Program +alias progb mainb +options head + main : Program Never ${2:Model} ${3:Msg} + main = + ${4:Html.}beginnerProgram + { init: ${6:init} + , update: ${7:update} + , subscriptions: ${8:subscriptions} + ${9:, view: ${10:view\}} + } + + ${0} + + +snippet case +abbr case ... of + case ${1:#:expression} of + ${2:#:value} -> + ${3:TARGET} + + +snippet if +abbr if ... then ... else ... + if ${1:#:condition} then + ${2} + else + ${3} + + +snippet let +abbr let ... in ... +options head + let + ${1} = + ${2} + in + ${0} + + +snippet lambda +abbr λ + \\${1:x} -> ${0} diff --git a/bundle/neosnippet-snippets/neosnippets/erlang.snip b/bundle/neosnippet-snippets/neosnippets/erlang.snip new file mode 100644 index 000000000..6ddb20597 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/erlang.snip @@ -0,0 +1,32 @@ +snippet helloworld +options head + + + main(_) -> io:format("Hello, world!\n"). + +snippet -module +options head + -module(${0:module}). + +snippet -export +options head + -export([${0:f/1}]). + +snippet ioformat +options word + io:format("${1:~w~n}"${2:, []}) + +snippet main +options head + main(_) -> ${0}. + +snippet case +abbr case +options head + case ${0:TARGET} of + ${1} + end + +snippet bs +abbr <<"...">> + <<"${0:TARGET}">> diff --git a/bundle/neosnippet-snippets/neosnippets/eruby.snip b/bundle/neosnippet-snippets/neosnippets/eruby.snip new file mode 100644 index 000000000..db5f845d1 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/eruby.snip @@ -0,0 +1,25 @@ +snippet ruby_print +abbr <%= %> +options word + <%= ${1:TARGET} %>${2} + +snippet ruby_code +abbr <% %> +options word + <% ${1:TARGET} %>${2} + +snippet ruby_print_nonl +abbr <%= -%> +options word + <%= ${1:TARGET} -%>${2} + +snippet ruby_code_nonl +abbr <% -%> +options word + <% ${1:TARGET} -%>${2} + +snippet comment +abbr <%# %> +options word + <%# ${1:TARGET} %>${2} + diff --git a/bundle/neosnippet-snippets/neosnippets/fortran.snip b/bundle/neosnippet-snippets/neosnippets/fortran.snip new file mode 100644 index 000000000..ce884897a --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/fortran.snip @@ -0,0 +1,188 @@ +# inspired/derived from +# https://github.com/hellolife/Vim/blob/b4b84f5e0685bdccf58474d5311c094e7eab5eb4/vimfiles/autoload/neosnippet/snippets/fortran.snip + +snippet pr +abbr program +options head + program ${1:main} + ${2} + end program $1 + +snippet sua +abbr subroutine +options head + subroutine ${1:`expand('%:r')`}(${2}) + use ${3:comvar} + implicit none + ${4} + end subroutine $1 + +snippet su +abbr subroutine +options head + subroutine ${1:`expand('%:r')`} + use ${2:comvar} + implicit none + ${3} + end subroutine $1 + +snippet mo +abbr module +options head + module ${1:`expand('%:r')`} + implicit none + save + ${2} + end module $1 + +snippet fu +abbr function +options head + function ${1:}(${2}) + ${3} + end function $1 + +snippet inp +abbr integer parameter +options head + integer, parameter :: + +snippet in +abbr integer +options head + integer :: + +snippet ini +abbr integer intent(in) +options head + integer, intent(in) :: + +snippet ino +abbr integer intent(out) +options head + integer, intent(out) :: + +snippet rep +abbr real parameter +options head + real, parameter :: + +snippet re +abbr real +options head + real :: + +snippet rei +abbr real intent(in) +options head + real, intent(in) :: + +snippet reo +abbr real intent(out) +options head + real, intent(out) :: + +snippet ind +abbr integer dimension +options head + integer, dimension(${1::})${2:#:, allocatable} :: ${3} + +snippet indi +abbr integer dimension intent(in) +options head + integer, dimension(${1}), intent(in) :: ${2} + +snippet indo +abbr integer dimension intent(out) +options head + integer, dimension(${1}), intent(out) :: ${2} + +snippet red +abbr real dimension +options head + real, dimension(${1::})${2:#:, allocatable} :: ${3} + +snippet redi +abbr real dimension intent(in) +options head + real, dimension(${1}), intent(in) :: ${2} + +snippet redo +abbr real dimension intent(out) +options head + real, dimension(${1}), intent(out) :: ${2} + +snippet ch +abbr character +options head + character(${1}) :: ${2} + +snippet chd +abbr character dimension +options head + character(${1}), dimension(${2}) :: ${3} + +snippet lo +abbr logical +options head + logical :: ${1:fileExsit} + +snippet if +abbr if +options head + if (${1}) ${2} + +snippet ift +abbr if then +options head + if (${1}) then + ${2} + end if + +snippet read +abbr read +options head + read(${1:*},${2:*}) ${3} + +snippet wr +abbr write +options head + write(${1:*},${2:*}) ${3} + +snippet op +abbr open +options head + open(${1:11},file=${2},status=${3:#:old}${4:#:,position='append'}) + ${5} + close($1) + +snippet se +abbr select case +options head + select case (${1}) + ${2} + end select + +snippet case +abbr case +options head + case(${1}) + ${2} + +snippet do +abbr do +options head + do ${1} + end do + +snippet ty +abbr type +options head + type ${1:} + ${2} + end type $1 + +snippet tyd +abbr type dimension +options head + type(${1}), dimension(${2::}), allcatable :: ${3} diff --git a/bundle/neosnippet-snippets/neosnippets/fsharp.snip b/bundle/neosnippet-snippets/neosnippets/fsharp.snip new file mode 100644 index 000000000..399415e7d --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/fsharp.snip @@ -0,0 +1,58 @@ +snippet If +abbr if..then..else +options head + if ${1:TARGET} + then ${2} + else ${0} + +snippet if +abbr if..then..else - oneline +options head + if ${1:TARGET} then ${2} else ${0} + +snippet match +abbr match + match ${1:TARGET} with + | ${2} -> ${0} + +snippet fun +abbr (fun x -> ..) +options head + (fun ${1:x} -> ${2:x}) + +snippet arl +abbr array literal [| |] + [| ${0:TARGET} |] + +snippet att +abbr attribute [<..>] +options head + [<${0:TARGET}>] + +snippet #if +abbr #if .. #endif +options head + #if ${1} + ${2:TARGET} + #endif + +snippet #ife +abbr #if .. else .. #endif +options head + #if ${1} + ${2} + else + #{3} + #endif + +snippet sourced +abbr __SOURCE_DIRECTORY__ + __SOURCE_DIRECTORY__ + +snippet line +abbr __LINE__ + __LINE__ + +snippet sourcef +abbr __FILE__ + __SOURCE_FILE__ diff --git a/bundle/neosnippet-snippets/neosnippets/gnuplot.snip b/bundle/neosnippet-snippets/neosnippets/gnuplot.snip new file mode 100644 index 000000000..c26fd7d82 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/gnuplot.snip @@ -0,0 +1,149 @@ +snippet range +abbr set x/y range. +options head + set ${1:#:axis}range [${2:*}:${3:*}] + +snippet xrange +abbr set xrange [X1:X2] +options head + set xrange [${1:*}:${2:*}] + +snippet yrange +abbr set yrange [Y1:Y2] +options head + set yrange [${1:*}:${2:*}] + +snippet title +abbr set title '...' +options head + set title ${1:#:title} + +snippet labelaxis +abbr set title '...' +options head + set ${1:#:axis}label ${2:#:label} + +snippet tics +abbr set x/y tics start, incr, end +options head + set ${1:#:axis}tics ${2:#:start}, ${3:#:incr}, ${4:#:end} + +snippet xtics +abbr set xtics start, incr, end +options head + set xtics ${1:#:start}, ${2:#:incr}, ${3:#:end} + +snippet ytics +abbr set ytics start, incr, end +options head + set ytics ${1:#:start}, ${2:#:incr}, ${3:#:end} + +snippet datasep +abbr set datafile separator 'separator' +options head + set datafile separator '${1:#:separator}' + +snippet term +abbr set terminal +options head + set terminal ${1:#:terminal} + +snippet out +abbr set output 'filename' +options head + set output '${1:#:filename}' + +snippet key +abbr set key +options head + set key + +snippet key! +abbr unset key +options head + unset key + +snippet grid +abbr set grid +options head + set grid + +snippet grid! +abbr unset grid +options head + unset grid + +snippet border +abbr set border +options head + set border + +snippet print +abbr print +options head + print(${1:#:string}} + +snippet sprintf +abbr sprintf +options head + sprintf('${1:#:format}', ${2:#:vars}) + +snippet multiplot +abbr set multiplot ... unset multiplot +options head + set multiplot + ${1:#:plot code} + unset multiplot + +snippet if +abbr if (...) {...} +options head + if (${1:#:condition}) { + ${2:#:commands} + } + +snippet else +abbr else {...} +options head + else { + ${1:#:commands} + } + +snippet ifelse +abbr if (...) {...} else {...} +options head + if (${1:#:condition}) { + ${2:#:commands} + } else { + ${3:#:commands} + } + +snippet while +abbr while (...) {...} +options head + while (${1:#:expression}) { + ${2:#:commands} + } + +snippet do +abbr do for {...} +options head + do for ${1:#:iter} { + ${2:#:commands} + } + +snippet fors +abbr for [string in "A B C..."] +options head + for [${1:str} in '${2:#:string list}'] + +snippet fori +abbr for [intvar = start, end, incr] +options head + for [${1:i} = ${2:#:start}, ${3:#:end}, ${4:1} + +snippet logscale +abbr set logscale +options head + set logscale ${1:#:axis} + diff --git a/bundle/neosnippet-snippets/neosnippets/go.snip b/bundle/neosnippet-snippets/neosnippets/go.snip new file mode 100644 index 000000000..634d2e273 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/go.snip @@ -0,0 +1,146 @@ +source go.vim + +snippet helloworld +abbr package main\nimport fmt... +options head + package main + + import ( + "fmt" + ) + + func main() { + fmt.Printf("Hello, world\n") + } + +snippet func +abbr func ...() { ... } +alias fn +options head + func ${1:fname}(${2}) ${3:int }{ + ${0:TARGET:return } + } + +snippet import +alias im +options head + import ( + "${1:fmt}" + ) + ${0:TARGET} + +snippet package +alias pk +options head + package ${1:main} + ${0:TARGET} + +snippet printf +alias pf +options head + fmt.Printf("${1}\n"${2:}) + +snippet println +alias pl +options head + fmt.Println(${0:TARGET}) + +snippet struct +alias ts +options head + type ${1} struct { + ${0:TARGET} + } + +snippet interface +alias ti +options head + type ${1} interface { + ${0:TARGET} + } + +snippet for +options head + for ${1} { + ${0:TARGET} + } + +snippet range +abbr for range +options head + for ${1:v} := range ${2:#:iterator} { + ${0:TARGET} + } + +snippet if +options head + if ${1:#:condition} { + ${0:TARGET} + } + +snippet iferr +alias ife +options head + if err != nil { + return `g:NeosnippetSnippets_Goiferr()` + } + ${2} + +snippet switch +abbr switch {} +options head + switch ${1:#:v} { + case ${2:#:condition}: + ${0:TARGET} + } + +snippet select +abbr select {} +options head + select { + case ${1:#:condition}: + ${0:TARGET} + } + +snippet case +options head + case ${1:#:condition}: + ${2:TARGET} + +snippet funcTest +abbr func Test... (t *testing.T) { ... } +options head + func Test${1} (${2:t *testing.T}) { + for i := 0; i < ${3:t.N}; i++ { + ${4} + } + } + +snippet funcbench +abbr func Benchmark... (b *testing.B) { ... } +options head + func Benchmark${1} (${2:b *testing.B}) { + for i := 0; i < ${3:b.N}; i++ { + ${4} + } + } + +snippet testtable +abbr var test = {...}{...} for {t.Run(){...}} +options head + var tests = []struct { + name string + expected string + given string + }{ + {"${2}", "${3}", "${4}",}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T){ + actual := ${1:Function}(tt.given) + if actual != tt.expected { + t.Errorf("given(%s): expected %s, actual %s", tt.given, tt.expected, actual) + } + }) + } diff --git a/bundle/neosnippet-snippets/neosnippets/go.vim b/bundle/neosnippet-snippets/neosnippets/go.vim new file mode 100644 index 000000000..8c44e99c6 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/go.vim @@ -0,0 +1,49 @@ +" From http://pocke.hatenablog.com/entry/2015/12/20/133445 +function! g:NeosnippetSnippets_Goiferr() abort + let re_func = '\vfunc' + let re_type = '%(%([.A-Za-z0-9*]|\[|\]|%(%(struct)|%(interface)\{\}))+)' + let re_rcvr = '%(\s*\(\w+\s+' . re_type . '\))?' + let re_name = '%(\s*\w+)?' + let re_arg = '\(%(\w+%(\s+%(\.\.\.)?' . re_type . ')?\s*,?\s*)*\)' + + let re_ret_v = '%(\w+)' + let re_ret = '%(\s*\(?(\s*\*?[a-zA-Z0-9_. ,]+)\)?\s*)?' + let re_ret_body = '%(' . re_ret_v . '|%(' . re_ret_v . '\s*' . re_type . ')|' . re_type . '\s*,?\s*)*' + let re_ret = '%(\s*\(?\s*(' . re_ret_body . ')\)?\s*)?' + let re = re_func . re_rcvr . re_name . re_arg . re_ret . '\{' + + let lnum = line('.') + let ret = "" + while lnum > 0 + let lnum -= 1 + + let ma = matchlist(getline(lnum), re) + if empty(ma) + continue + endif + let ret = ma[1] + break + endwhile + + if ret =~ '\v^\s*$' + return '${1}' + endif + + let rets = [] + for t in split(ret, ',') + if t =~# '\v^\s*error\s*$' + let v = 'err' + elseif t =~# '\v^\s*string\s*$' + let v = '"${1\}"' + elseif t =~# '\v^\s*int\d*\s*$' + let v = '0' + elseif t =~# '\v^\s*bool\s*$' + let v = 'false' + else + let v = 'nil' + endif + call add(rets, v) + endfor + + return '${1:' . join(rets, ", ") . '${0\}}' +endfunction diff --git a/bundle/neosnippet-snippets/neosnippets/groovy.snip b/bundle/neosnippet-snippets/neosnippets/groovy.snip new file mode 100644 index 000000000..b74137984 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/groovy.snip @@ -0,0 +1,29 @@ +snippet helloworld +options head + package ${1:com.github.ujihisa} + + class ${2:TARGET} { + public static void main(String[] args) { + println("Hello world!") + } + } + +snippet gradle +options head + apply plugin: 'groovy' + apply plugin: 'maven' + + repositories { + mavenCentral() + ${2:mavenLocal()} + } + + dependencies { + compile 'org.codehaus.groovy:groovy-all:2.1.1' + //testCompile group: 'junit', name: 'junit', version: '4.+' + } + + jar { + from configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } + } + manifest.mainAttributes("Main-Class": "${1:com.github.`$USER`.}") diff --git a/bundle/neosnippet-snippets/neosnippets/haskell.snip b/bundle/neosnippet-snippets/neosnippets/haskell.snip new file mode 100644 index 000000000..6cbd4ff9d --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/haskell.snip @@ -0,0 +1,37 @@ +snippet import +abbr import qualified ... as ... + import qualified ${1} as ${2} + +snippet importOnly +abbr import ... (...) + import ${1} (${2}) + +snippet language +abbr {-# LANGUAGE ... #-} + {-# LANGUAGE ${1} #-} + +# hard-tab is necessary +snippet case +abbr case ... of + case ${1} of + ${2} -> ${0} + +snippet main +abbr main = do + main = do + ${0} + +snippet class +options head + class ${1:Class} ${2:a} where + ${3:function} :: ${4:Type} + +snippet instance +options head + instance ${1:Class} ${2:Type} where + ${3:function} ${4:self} = ${0:TARGET} + +snippet lambda +abbr λ + \ ${1:x} -> ${0} + diff --git a/bundle/neosnippet-snippets/neosnippets/html.snip b/bundle/neosnippet-snippets/neosnippets/html.snip new file mode 100644 index 000000000..945d4cd38 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/html.snip @@ -0,0 +1,341 @@ +snippet doctypetransitional + + +snippet doctypeframeset + + +snippet doctypestrict + + +snippet html5 + + + + + + ${4} + + + ${5} + + + +snippet head + + + ${2} + + ${4} + ${5} + +snippet metaauthor + ${2} +snippet keywords + ${2} +snippet metaothers + ${2} +snippet metagenerator + ${2} +snippet metadescription + ${2} +snippet metaviewport + +snippet metatheme + + +snippet scriptcharset + ${3} +snippet script + ${2} +snippet scriptsrc +abbr js + ${3} + +snippet body + + ${1:TARGET} + + +snippet h +options word + ${2}${3} + +snippet p +options word +

${1}

${2} + +snippet br +options word +
+ +snippet hr +options word +
+ +snippet comment +options word + ${2} + +snippet b +options word + ${1:TARGET}${2} +snippet small +options word + ${1:TARGET}${2} +snippet strong +options word + ${1:TARGET}${2} +snippet sub +options word + ${1:TARGET}${2} +snippet sup +options word + ${1:TARGET}${2} +snippet ins +options word + ${1:TARGET}${2} +snippet del +options word + ${1:TARGET}${2} +snippet em +options word + ${1:TARGET}${2} +snippet bdo +options word + ${2:TARGET}${3} +snippet pre +
+    ${1:TARGET}
+    
${2} +snippet blockquote +
+ ${1} +
+ ${2} + +snippet link +abbr link stylesheet css + ${4} +snippet manifest + ${2} + +snippet alignl + text-align="left" +snippet alignr + text-align="right" +snippet alignc + text-align="center" + +snippet bgcolor + bgcolor="${1}"${2} + +snippet ahref +options word + ${2:TARGET}${3} +snippet ahref_blank +options word + ${2:TARGET}${3} +snippet ahref_parent +options word + ${2:TARGET}${3} +snippet ahref_top +options word + ${2:TARGET}${3} +snippet aname +options word + ${2:TARGET}${3} + +snippet framesetcols + + ${2:TARGET} + ${3} +snippet framesetrows + ${3} + +snippet iframe +options word + ${2} +snippet table + + ${2:TARGET} +
${3} + +snippet th +options word + ${1:TARGET}${2} + +snippet ulsquare +options word +
    ${1:TARGET}
${2} +snippet ulcircle +options word +
    ${1:TARGET}
${2} +snippet uldisc +options word +
    ${1:TARGET}
${2} + +snippet ol +options word +
    ${1:TARGET}
${2} +snippet olA +options word +
    ${1:TARGET}
${2} +snippet ola +options word +
    ${1:TARGET}
${2} +snippet olI +options word +
    ${1:TARGET}
${2} +snippet oli +options word +
    ${1:TARGET}
${2} + +snippet li +options word +
  • ${1:TARGET}
  • ${2} + +snippet dl +options word +
    ${1:TARGET}
    ${2} +snippet dt +options word +
    ${1:TARGET}
    ${2} +snippet dd +options word +
    ${1:TARGET}
    ${2} + +snippet form +
    + ${1:TARGET} +
    ${2} + +snippet inputtext +options word + ${2} +snippet inputpassword +options word + ${2} +snippet inputradio +options word + ${2} +snippet inputcheckbox +options word + ${2} + +snippet textarea + + ${4} + +snippet button +options word + ${2} + +snippet buttonsubmit +options word + ${2} + +snippet select +options word + ${2} + +snippet optgroup + + ${2:TARGET} + ${3} +snippet option +options word + ${3} + +snippet label +options word + ${3} + +snippet labelfor +options word + ${3} + +snippet fieldset +options word +
    ${1:TARGET}
    ${2} + +snippet legend +options word + ${1:TARGET}${2} + +snippet id +options word + id="${1}"${2} + +snippet class +options word + class="${1}"${2} + +snippet pclass +options word +

    ${2:TARGET}

    ${3} + +snippet pid +options word +

    ${2:TARGET}

    ${3} + +snippet divid +options word +
    ${2:TARGET}
    ${3} + +snippet divclass +options word +
    ${2:TARGET}
    ${3} + +snippet img +options word + ${2}${3} + +snippet div +options word +
    ${3:TARGET}
    ${4} + +snippet header +options word +
    + ${1} +
    + +snippet nav +options word + + +snippet main +options word +
    + ${1} +
    + +snippet footer +options word +
    + ${1} +
    + +snippet details + + ${1} + ${3} + diff --git a/bundle/neosnippet-snippets/neosnippets/java.snip b/bundle/neosnippet-snippets/neosnippets/java.snip new file mode 100644 index 000000000..f312beee3 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/java.snip @@ -0,0 +1,266 @@ +snippet class + class ${1} ${2:#:extends_or_implements}{ + ${0:TARGET} + } + +snippet interface + interface ${1} ${2:#:extends}{ + ${0:TARGET} + } + +snippet method + ${1:void} ${2:#:method}(${3}) ${4:throws} { + ${0:TARGET} + } + +snippet enum +abbr enum {} + enum ${1:#:name} { + ${0:TARGET} + } + +snippet set + public void set${1:Name}(${2:String} ${3:name}) { + this.$3 = $3; + }${0:TARGET} + +snippet get + public ${1:String} get${2:Name}() { + return $2; + }${0:TARGET} + +snippet setget + public void set${1:Name}(${2:String} ${3:name}) { + this.$3 = $3; + } + public $2 get$1() { + return $1; + }${0:TARGET} + +snippet var + ${1:#:type} ${2:#:var}${3}; + +snippet const + static public final ${1:#:type} ${2:#:var} = ${3};${4} + +snippet const_string + static public final String ${1:var} = "${2}";${4} + +snippet final + public final ${1:#:type} ${2:#:var} = ${3}; + +snippet assert + assert ${1:#:test} : ${2:#:Failure message};${3} + +snippet if + if (${1}) { + ${2:TARGET} + } + +snippet else + else { + ${1:TARGET} + } + +snippet elif +alias elseif + else if (${1}) { + ${2:TARGET} + } + +snippet while + while (${1}) { + ${2:TARGET} + } + +snippet for + for (${1}; ${2}; ${3}) { + ${4:TARGET} + } + +snippet foreach +alias fore + for (${1} : ${2}) { + ${3:TARGET} + } + +snippet switch + switch (${1}) { + ${2:TARGET} + } + +snippet case + case ${1}: + ${2:TARGET} + ${0} + +snippet br + break; + +snippet default +alias de + default: + ${0} + +snippet try + try { + ${0:TARGET} + } catch (${1:Exception} ${2:e}) { + ${3:e.printStackTrace();} + } + +snippet try_resources + try (${1:#:Resources}) { + ${0:TARGET} + } catch (${2:Exception} ${3:e}) { + ${4:e.printStackTrace();} + } + +snippet try_finally + try { + ${0:TARGET} + } catch (${1:Exception} ${2:e}) { + ${3:e.printStackTrace();} + } finally { + ${4} + } + +snippet catch + catch (${1:Exception} ${2:e}) { + ${0:e.printStackTrace();} + } + +snippet finally + finally { + ${0:TARGET} + } + +snippet th +options word + throw ${0} + +snippet sy +options word + synchronized + +snippet testclass +alias tc +options head + public class ${1} extends ${2:TestCase} { + ${0:TARGET} + } + +snippet test +options head + public void test${1:#:Name}() throws Exception { + ${0:TARGET} + } + +snippet import +alias imt + import ${1}; + ${0} + +snippet j.u + java.util. + +snippet j.i + java.io. + +snippet j.b + java.beans. + +snippet j.n + java.net + +snippet j.m + java.math. + +snippet main + class `expand('%:p:t:r')` { + public static void main(String args[]) { + ${0:#:body} + } + } + + +snippet println +options word + System.out.println(${1}); + +snippet print +options word + System.out.print(${1}); + +snippet format +options word + System.out.format(${1}); + +#javadoc +snippet comment + /** + * ${0:TARGET} + */ + +snippet author + @author ${0:$TM_FULLNAME} + +snippet {code + {@code ${0} + +snippet deprecated + @deprecated ${0:#:description} + +snippet {docRoot + {@docRoot + +snippet {inheritDoc + {@inheritDoc + +snippet {link + {@link ${1:#:target} ${0:#:label} + +snippet {linkplain + {@linkplain ${1:#:target} ${0:#:label} + +snippet {literal + {@literal ${0} + +snippet param + @param ${1:#:var} ${0:#:description} + +snippet return + @return ${0:#:description} + +snippet see + @see ${0:#:reference} + +snippet serial + @serial ${0:#:description} + +snippet sd + @serialField ${0:#:description} + +snippet sf + @serialField ${1:#:name} ${2:#:type} ${0:#:description} + +snippet since + @since ${0:#:version} + +snippet throws + @throws ${1:#:class} ${0:#:description} + +snippet {value + {@value ${0} + +snippet version +alias ver + @version ${0:#:version} + +snippet helloworld +options head + public class ${1:Hello} { + static public void main(String args[]) { + System.out.println("Hello, world!"); + } + } diff --git a/bundle/neosnippet-snippets/neosnippets/javascript.snip b/bundle/neosnippet-snippets/neosnippets/javascript.snip new file mode 100644 index 000000000..6c0f6a096 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/javascript.snip @@ -0,0 +1,211 @@ +snippet :f +options head + ${1:#:method_name}: function(${2:#:attribute}) { + ${0:TARGET} + } + +snippet function +abbr func +options word + function ${1:#:function_name}(${2:#:argument}) { + ${0:TARGET} + } + +snippet function2 +abbr func2 +options head + function ${1:function_name}(${2:argument}) { + ${0:TARGET} + } + +snippet proto +options head + ${1:#:class_name}.prototype.${2:#:method_name} = function(${3:#:first_argument}) { + ${0:TARGET} + }; + + +snippet f +options word + function(${1}) { ${0:TARGET} }; + +snippet if +options head + if (${1:true}) { + ${0:TARGET} + } + +snippet if-else +abbr ife +options head + if (${1:#:condition}) { + ${2:TARGET} + } else { + ${3} + } + +snippet for +options head + for (let ${1:i} = 0; $1 < ${2:#:Things}.length; ++$1) { + ${0:TARGET} + } + +snippet forin +options head + for (let ${1:i} in ${2:#:Things}) { + ${0:TARGET} + } + +snippet forof +options head + for (let ${1:i} of ${2:#:Things}) { + ${0:TARGET} + } + +snippet while +options head + while (${1:true}) { + ${0:TARGET} + } + +snippet switch +options head + switch (${1:#:let}) { + case ${2:#:val}: + ${0:TARGET} + break; + } + +snippet try +options head + try { + ${1:TARGET} + } catch (${2:e}) { + ${3} + } + +snippet try_finally +options head + try { + ${1:TARGET} + } catch (${2:e}) { + ${3} + } finally { + ${4} + } + + +snippet key-value +abbr :, +options word + ${1:#:value_name}: ${0:#:value}, + +#snippet key +#options word +# ${1:#:key}: "${2:#:value}"}${3:, } + +snippet setTimeout-function +options head + setTimeout(function() { ${0} }, ${1:10}); + +snippet debugger +alias db +options head + debugger; + +snippet console-log +alias cl +options head + console.log(${0:TARGET}); + +snippet console-trace +alias ct +options head + console.trace(); + +snippet console-error +alias ce +options head + console.error(${0:TARGET}); + +snippet console-warn +alias cw +options head + console.warn(${0:TARGET}); + +snippet console-info +alias ci +options head + console.info(${0:TARGET}); + +snippet iife +options head + (function(${1}) { + 'use strict'; + ${0:TARGET} + })(${2}); + +snippet js +options head + JSON.stringify(${1:TARGET}, null, 2); + +snippet jsc +options head + console.log(JSON.stringify(${1:TARGET}, null, 2)); + +snippet class +abbr class {...} +options head + class ${1:#:NAME} { + constructor(${2:#:ARGS}) { + ${0:TARGET} + } + } + +snippet class-extends +abbr class extends {...} +options head + class ${1:#:NAME} extends ${2:#:SuperClass} { + constructor(${3:#:ARGS}) { + ${0:TARGET} + } + } + +snippet static +options head + static ${1:#:NAME}(${2:#:ARGS}) { + ${0:TARGET} + } + +snippet set +options head + set ${1:#:NAME}(${2:#:ARGS}) { + ${0:TARGET} + } + +snippet get +options head + get ${1:#:NAME}() { + ${0:TARGET} + } + +snippet import +abbr import { member, ... } from "module-name"; +options head + import { ${1:MEMBERS} } from "${0:TARGET}"; + +snippet import-default +abbr import defaultMember from "module-name"; +options head + import ${1:defaultMember} from "${0:TARGET}"; + +snippet import-all +abbr import * as NAME from "..."; +options head + import * as ${1:NAME} from "${0:TARGET}"; + +snippet import-default-member +abbr import defaultMember, { member, ... } from "module-name"; +options head + import ${1:defaultMember}, { ${2:MEMBERS} } from "${0:TARGET}"; + diff --git a/bundle/neosnippet-snippets/neosnippets/julia.snip b/bundle/neosnippet-snippets/neosnippets/julia.snip new file mode 100644 index 000000000..af25b7e68 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/julia.snip @@ -0,0 +1,79 @@ +snippet function +abbr function ... end +options head + function ${1}(${2}) + ${0} + end + +snippet macro +abbr macro ... end +options head + macro ${1}(${2}) + ${0} + end + +snippet struct +abbr struct ... end +options head + struct ${1} + ${0} + end + +snippet module +abbr module ... end +options head + module ${1} + ${0} + end#module + +snippet let +abbr let ... end +options head + let ${1} + ${0} + end + +snippet quote +abbr quote ... end +options head + quote + ${0} + end + + +snippet begin +abbr begin ... end +options head + begin + ${0} + end + +snippet for +abbr for ... end +options head + for ${1} + ${0} + end + +snippet if +abbr if ... end +options head + if ${1} + ${0} + end + +snippet try +abbr try ... end +options head + try + ${1} + ${2:catch} + ${0} + end + +snippet while +abbr while ... end +options head + while ${1:true} + ${0} + end diff --git a/bundle/neosnippet-snippets/neosnippets/kp19pp.snip b/bundle/neosnippet-snippets/neosnippets/kp19pp.snip new file mode 100644 index 000000000..e091dfd2f --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/kp19pp.snip @@ -0,0 +1,21 @@ +snippet token_desc +options head + token{ + ${0:TARGET} + } + +snippet left +options head + { + ${0:TARGET} + } + +snippet grammar +options head + grammar{ + E<${1}> + : [${2}] ${3} + ; + } + +# vim: noexpandtab : diff --git a/bundle/neosnippet-snippets/neosnippets/liquid.snip b/bundle/neosnippet-snippets/neosnippets/liquid.snip new file mode 100644 index 000000000..e0e4c900e --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/liquid.snip @@ -0,0 +1,128 @@ +snippet comment +options word + {% comment %}${1:#:comment}{% endcomment %} + +snippet raw +options word + {% raw %}${1:#:TARGET}{% endraw %} + +snippet if +abbr if endif +options word + {% if ${1:#:condition} %} + ${0:TARGET} + {% endif %} + +snippet elseif + {% elseif ${1:#:condition} %} + ${0:TARGET} + +snippet ifelse +abbr if else endif + {% if ${1:#:condition} %} + ${2:TARGET} + {% else %} + ${3} + {% endif %} + +snippet unless +abbr unless endunless +options word + {% unless ${1:#:TARGET} %} + ${0:TARGET} + {% endunless %} + +snippet case +abbr case when endcase + {% case ${1:#:condition} %} + {% when ${2:#:TARGET} %} + ${3} + {% endcase%} + +snippet else + {% else %} + ${1:TARGET} + +snippet when + {% when ${1:#:TARGET} %} + ${0} + +snippet cycle +options word + {% cycle ${1:#:TARGET} %} + +snippet for +abbr for in endfor +options word + {% for ${1:#:var} in ${2:#:list} %} + ${0:TARGET} + {% endfor%} + +snippet tablerow +abbr tablerow in endtablerow +options word + {% tablerow ${1:#:var} in ${2:#:list} %} + ${0:TARGET} + {% endtablerow %} + +snippet assign +options word + {% assign ${1:#:var} = ${2:#:value} %} + +snippet capture +options word + {% capture ${1:#:var} %}${2:#:TARGET}{% endcapture %} + +snippet include +options word + {% include ${1:#:TARGET} %} + +snippet output +abbr {{ }} +alias {{ +options word + {{ ${1:#:TARGET} }} + +snippet filter +abbr {{ | }} +alias {{ +options word + {{ ${1:#:TARGET} | ${2:#:filter} }} + + +# Jekyll enhancements + +snippet highlight +alias hl +options word + {% highlight ${1:#:TARGET} %} + ${2:code} + {% endhighlight %} + +snippet highlight_line +abbr Line number +alias hl_l +options word + {% highlight ${1:#:TARGET} linenos %} + ${2:code} + {% endhighlight %} + +snippet post_url +options word + {% post_url ${1:#:TARGET} %} + +snippet gist +options word + {% gist `getreg('+')=='' ? '<\`0\`>' : getreg('+')` %} + +snippet front-matter +abbr layout title category +alias --- +options head + --- + layout: ${1} + title: ${2} + category: ${3} + --- + ${0} + diff --git a/bundle/neosnippet-snippets/neosnippets/lua.snip b/bundle/neosnippet-snippets/neosnippets/lua.snip new file mode 100644 index 000000000..e8fc02b3e --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/lua.snip @@ -0,0 +1,93 @@ +# lua's indent plugin doesn't work well partly with markers. Use hard-tab for some of this snippet. +snippet func +abbr function name(args)...end +options word + function ${1:#:function_name}(${2:#:argument}) + ${0:TARGET} + end + +snippet if +options head + if ${1:#:condition} then + ${0:TARGET} + end + +snippet for +options head + for ${2:i} = 0, ${1:#:Things} do + ${0:TARGET} + end + +snippet forin +options head + for ${2:k}, ${3:v} in ${1:ipairs(xs)} do + ${0:TARGET} + end + +snippet print_table +options head +abbr for k, v in ipairs(table) do + for k, v in ipairs(${1:table}) do + print(k, v) + end + +snippet print +alias p +options head + print(${0:TARGET}) + +snippet comment +options head + [[${0:TARGET}]] + +# For busted snippets +# http://olivinelabs.com/busted/ +snippet describe +options head +abbr describe(message, func) + describe(${1:#:message}, function() + ${0:TARGET} + end) + +snippet it +options head +abbr it(message, func) + it(${1:#:message}, function() + ${0:TARGET} + end) + +snippet before_each +options head +abbr before_each(func) + before_each(function() + ${0:TARGET} + end) + +snippet after_each +options head +abbr after_each(func) + after_each(function() + ${0:TARGET} + end) + +snippet setup +options head +abbr setup(func) + setup(function() + ${0:TARGET} + end) + +snippet tear_down +options head +abbr tear_down(func) + tear_down(function() + ${0:TARGET} + end) + +snippet finally +options head +abbr finally(func) + finally(function() + ${0:TARGET} + end) + diff --git a/bundle/neosnippet-snippets/neosnippets/make.snip b/bundle/neosnippet-snippets/neosnippets/make.snip new file mode 100644 index 000000000..0e7830f2c --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/make.snip @@ -0,0 +1,8 @@ +snippet CFLAGS +options head + CFLAGS=-Wall -g ${0: -llua -lzeromq} + +snippet clean: +options head + clean: + rm -f ${0} diff --git a/bundle/neosnippet-snippets/neosnippets/markdown.snip b/bundle/neosnippet-snippets/neosnippets/markdown.snip new file mode 100644 index 000000000..dd7bd9923 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/markdown.snip @@ -0,0 +1,81 @@ +snippet link +abbr [link][] +options word + [${1:#:link_id}][]${2} + +snippet linkid +abbr [link][id] +options word + [${1:#:link}][${2:id}]${3} + +snippet linkurl +abbr [link](url) +options word + [${1:#:link}](https://${2:#:url})${3} + +snippet linkemail +abbr [link](email) +options word + [${1:#:link}](mailto:${2:#:email})${3} + +snippet linkurltitle +abbr [link](url "title") +options word + [${1:#:link}](${2:#:url} "${3:#:title}")${4} + +snippet idurl +abbr [id]: url "title" +options word + [${1:#:id}]: https://${2:#:url} "${3:#:title}" + +snippet idemail +abbr [id]: email "title" +options word + [${1:#:id}]: mailto:${2:#:url} "${3:#:title}" + +snippet altid +abbr ![alt][id] +options word + ![${1:#:alt}][${2:#:id}]${3} + +snippet alturl +abbr ![alt](url) +options word + ![${1:#:alt}](${2:#:url})${3} + +snippet alturltitle +abbr ![alt](url "title") +options word + ![${1:#:alt}](${2:#:url} "${3:#:title}")${4} + +snippet emphasis1 +abbr *emphasis* +options word + *${1}*${2} + +snippet emphasis2 +abbr _emphasis_ +options word + _${1}_${2} + +snippet strong1 +abbr **strong** +options word + **${1}**${2} + +snippet strong2 +abbr __strong__ +options word + __${1}__${2} + +snippet code +abbr `code` +options word + \`${1}\`${2} + +snippet codeblock +abbr code block +options head + \`\`\`${1:#:language} + ${2:#:code } + \`\`\` diff --git a/bundle/neosnippet-snippets/neosnippets/mediawiki.snip b/bundle/neosnippet-snippets/neosnippets/mediawiki.snip new file mode 100644 index 000000000..a9cd2f718 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/mediawiki.snip @@ -0,0 +1,70 @@ +snippet == + == ${1} == + + ${2} + +snippet === + === ${1} === + + ${2} + +snippet ==== + ==== ${1} ==== + + ${2} + +snippet ===== + ===== ${1} ===== + + ${2} + +snippet ====== + ====== ${1} ====== + + ${2} + +snippet [[ + [[${1}]] ${2} +snippet '' + ''${1}'' +snippet ''' + '''${1}''' +snippet ''''' + '''''${1}''''' +snippet sy + + ${2} + +snippet pre +
    +        ${1}
    +        
    +snippet html + + ${1} + +snippet nowiki + ${1} +snippet tt + ${1} +snippet blockquote +
    ${1}
    +snippet ft + +snippet {| + {|class="wikitable" + |+ ${1} + ! ${2} + ! ${3} + |- + | ${4} + | ${5} + |- + | ${6} + | ${7} + |- + | + | + |} diff --git a/bundle/neosnippet-snippets/neosnippets/mkd.snip b/bundle/neosnippet-snippets/neosnippets/mkd.snip new file mode 100644 index 000000000..023f4c8c0 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/mkd.snip @@ -0,0 +1 @@ +include markdown.snip diff --git a/bundle/neosnippet-snippets/neosnippets/moon.snip b/bundle/neosnippet-snippets/neosnippets/moon.snip new file mode 100644 index 000000000..b7ce2cdfd --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/moon.snip @@ -0,0 +1,24 @@ +snippet helloworld +options head + print 'Hello world!' + +snippet map +options word + [${0:TARGET} for ${1:x} in ${2:xs}] + +snippet p +options head + moon.p ${0} + +snippet defn + ${1:f} = (${2:args}) -> + ${0:TARGET} + +snippet defm +options head + ${1:f}: (${2:args}) => + ${0:TARGET} + +snippet require +options head + ${1:moon} = require '$1' diff --git a/bundle/neosnippet-snippets/neosnippets/neosnippet.snip b/bundle/neosnippet-snippets/neosnippets/neosnippet.snip new file mode 100644 index 000000000..0f83c7b7c --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/neosnippet.snip @@ -0,0 +1,161 @@ +snippet snippet +abbr snippet abbr options +alias snip +options head + snippet ${1:#:trigger} + abbr ${2:#:abbr} + options head + ${3:#:TARGET} + +snippet include +abbr include *.snip +alias inc +options head + include ${0:filetype}.snip + +snippet $ +abbr ${..} +options word + ${${0:0}} + +snippet 0 +abbr ${0} +options word + \${0}${0} + +snippet 1 +abbr ${1} +options word + \${1}${0} + +snippet 2 +abbr ${2} +options word + \${2}${0} + +snippet 3 +abbr ${3} +options word + \${3}${0} + +snippet 4 +abbr ${4} +options word + \${4}${0} + +snippet 5 +abbr ${5} +options word + \${5}${0} + +snippet $: +abbr ${X:default} +options word + ${${1:0}:${0:default}} + +snippet 0: +abbr ${0:default} +options word + \${0:${0:default}} + +snippet 1: +abbr ${1:default} +options word + \${1:${0:default}} + +snippet 2: +abbr ${2:default} +options word + \${2:${0:default}} + +snippet 3: +abbr ${3:default} +options word + \${3:${0:default}} + +snippet 4: +abbr ${4:default} +options word + \${4:${0:default}} + +snippet 5: +abbr ${5:default} +options word + \${5:${0:default}} + +snippet $# +abbr ${X#optional} +options word + ${${1:0}#${0:optional}} + +snippet 0# +abbr ${0:#optional} +options word + \${0:#${0:optional}} + +snippet 1# +abbr ${1:#optional} +options word + \${1:#${0:optional}} + +snippet 2# +abbr ${2:#optional} +options word + \${2:#${0:optional}} + +snippet 3# +abbr ${3:#optional} +options word + \${3:#${0:optional}} + +snippet 4# +abbr ${4:#optional} +options word + \${4:#${0:optional}} + +snippet 5# +abbr ${5:#optional} +options word + \${5:#${0:optional}} + +snippet TARGET +abbr ${*:TARGET} +alias T +options word + ${${0:0}:TARGET} + +snippet 0T +abbr ${0:TARGET} +alias 0t +options word + \${0:TARGET}${0} + +snippet 1T +abbr ${1:TARGET} +alias 1t +options word + \${1:TARGET}${0} + +snippet 2T +abbr ${2:TARGET} +alias 2t +options word + \${2:TARGET}${0} + +snippet 3T +abbr ${3:TARGET} +alias 3t +options word + \${3:TARGET}${0} + +snippet 4T +abbr ${4:TARGET} +alias 4t +options word + \${4:TARGET}${0} + +snippet 5T +abbr ${5:TARGET} +alias 5t +options word + \${5:TARGET}${0} diff --git a/bundle/neosnippet-snippets/neosnippets/nim.snip b/bundle/neosnippet-snippets/neosnippets/nim.snip new file mode 100644 index 000000000..b16485f67 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/nim.snip @@ -0,0 +1,107 @@ +# 2 space +snippet proc +options head + proc ${1:#:name}(${2}) = + ${0:pass} + +snippet procd +options head + proc ${1:#:name}(${2}): + discard """${3:#:function documentation}""" + ${0:pass} + +snippet proct +options head + proc ${1:#:name}(${2}):${3:#:type} = + ${0:pass} + +snippet procg +options head + proc ${1:#:name}(${2}) = + ${0:pass} + +snippet procgt +options head + proc ${1:#:name}(${2}):${3:#:type} = + ${0:pass} + +snippet template +options head + template ${1:#:name}(${2}):${3:type} = + ${0:pass} + +snippet macro +options head + macro ${1:#:name}(${2}):${3:type} = + ${0:pass} + +snippet elif +abbr elif ...: ... +options head + elif ${1:#:condition}: + ${0:pass} + +snippet else +abbr else: ... +options head + else: + ${0:pass} + +snippet for +abbr for ... in ...: ... +options head + for ${1:#:value} in ${2:#:list}: + ${0:pass} + +snippet if +abbr if ...: ... +options head + if ${1:#:condition}: + ${0:pass} + +snippet when +abbr when ...: ... +options head + when ${1:#:condition}: + ${0:pass} + +snippet ifmain +abbr if isMainModule: ... +alias main +options head + if isMainModule: + ${0:pass} + +snippet tryexcept +abbr try: ... except ...: ... +options head + try: + ${1:pass} + except ${2:#:ExceptionClass}: + ${3:pass} + +snippet tryfinally +abbr try: ... finally: ... +options head + try: + ${1:pass} + finally: + ${2:pass} + +snippet trydefer +options head + try: ${1:pass} + defer: ${2:pass} + +snippet while +options head + while ${1:#:condition}: + ${0:pass} + +snippet echo +options word + echo(${0:#:TARGET}) + +snippet fmt +options word + fmt"${0:#:TARGET}" diff --git a/bundle/neosnippet-snippets/neosnippets/objc.snip b/bundle/neosnippet-snippets/neosnippets/objc.snip new file mode 100644 index 000000000..2aba88cd4 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/objc.snip @@ -0,0 +1,333 @@ +snippet sel + @selector(${1:#:method}:) + + +snippet imp + #import <${1:Cocoa/Cocoa.h}> + + +snippet Imp + #import "${1}}" + + +snippet log +abbr NSLog(...) + NSLog(@"${1}") + + +snippet cl +abbr Class + @interface ${1} : ${2:NSObject} + { + } + @end + + @implementation ${1} + - (id)init + { + if((self = [super init])) + {${0} + } + return self; + } + @end + +snippet cli +abbr ClassInterface + @interface ${1} : ${2:NSObject} + {${3} + } + ${0} + @end + +snippet clm +abbr ClassImplementation + @implementation ${1:object} + - (id)init + { + if((self = [super init])) + {${0} + } + return self; + } + @end + +snippet cat +abbr Category + @interface ${1:NSObject} (${2:Category}) + @end + + @implementation ${1} (${2}) + ${0} + @end + +snippet cati +abbr CategoryInterface + @interface ${1:NSObject)} (${2:Category)}) + ${0} + @end + +snippet array + NSMutableArray *${1:#:array} = [NSMutableArray array]; + + +snippet dict + NSMutableDictionary *${1:#:dict} = [NSMutableDictionary dictionary]; + + +snippet bez + NSBezierPath *${1:#:path} = [NSBezierPath bezierPath]; + +snippet m +abbr Method + - (${1:#:id})${2:#:method}${3:(#:id)}${4:#:anArgument} + { + ${0} + return nil; + } + +snippet M +abbr Method + - (${1:#:id})${2:#:method}${3:(#:id)}${4:#:anArgument}; + + +snippet cm +abbr ClassMethod + + (${1:#:id})${2:#:method}${3:(#:id)}${4:#:anArgument} + { + ${0} + return nil; + } + + +snippet icm +abbr InterfaceClassMethod + + (${1:#:id})${0:#:method}; + + +snippet sm +abbr SubMethod + - (${1:#:id})${2:#:method}${3:(#:id)}${4:#:anArgument} + { + ${1} res = [super ${2:#:method}] + return res; + } + + +snippet mi +abbr MethodInitialize + + (void)initialize + { + [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys: + ${0}@"value", @"key", + nil]]; + } + +snippet obj + - (${1:#:id})${2:#:thing} + { + return ${2}; + } + + - (void)set${2}:(${1})aValue + { + ${0}${1}old${2} = ${2}; + ${2} = [aValue retain]; + [old${2} release]; + } + + +snippet iobj + - (${1:#:id})${2:#:thing}; + - (void)set${2}:(${1})aValue; + +snippet str + - (NSString${$1: *)})${1:#:thing} + { + return ${2}; + } + + - (void)set${1}:(NSString${2: *})${3} + { + ${3} = [${3} copy]; + [${2} release]; + ${2} = ${3}; + } + +snippet istr + - (NSString${1: *)}${1:#:thing}; + - (void)set${1}:(NSString${2: *})${2}; + +snippet cd +abbr CoreData + - (${1:#:id})${2:#:attribute} + { + [self willAccessValueForKey:@"$2"]; + $1 value = [self primitiveValueForKey:@"$2"]; + [self didAccessValueForKey:@"$2"]; + return value; + } + + - (void)set$2:($1)aValue + { + [self willChangeValueForKey:@"$2"]; + [self setPrimitiveValue:aValue forKey:@"$2"]; + [self didChangeValueForKey:@"$2"]; + } + +snippet karray +abbr KVCArry + - (void)addObjectTo${1:#:Things}:(${2:#:id})anObject + { + [${3}} addObject:anObject]; + } + + - (void)insertObject:($2)anObject in$1AtIndex:(unsigned int)i + { + [${3} insertObject:anObject atIndex:i]; + } + + - (${2})objectIn${1}AtIndex:(unsigned int)i + { + return [${3} objectAtIndex:i]; + } + + - (unsigned int)indexOfObjectIn${1}:(${2})anObject + { + return [${3} indexOfObject:anObject]; + } + + - (void)removeObjectFrom${1}AtIndex:(unsigned int)i + { + [${3} removeObjectAtIndex:i]; + } + + - (unsigned int)countOf${1} + { + return [${3} count]; + } + + - (NSArray${4: *}${1} + { + return ${3} + } + + - (void)set${1}:(NSArray${4: *})new${1} + { + [${3} setArray:new${1}]; + } + + +snippet iarray +abbr InterfaceAccessorsForKVCArray + - (void)addObjectTo${1:#:Things}:(${2:#:id})anObject; + - (void)insertObject:(${2})anObject in${1}AtIndex:(unsigned int)i; + - (${2})objectIn${1}AtIndex:(unsigned int)i; + - (unsigned int)indexOfObjectIn${1}:(${2})anObject; + - (void)removeObjectFrom${1}AtIndex:(unsigned int)i; + - (unsigned int)countOf${1}; + - (NSArray${3: *})${1}; + - (void)set${1}:(NSArray${3: *})new${1}; + + +snippet acc +abbr PrimitiveType + - (${1:unsigned int})${2:#:thing} + { + return ${3}; + } + + - (void)set${2}:(${1:unsigned int})new${2} + { + ${3} = new${2}; + } + + +snippet iacc +abbr Interface:AccessorsForPrimitiveType + - (${1:unsigned int})${2:thing}; + - (void)set${2}:($1)new${2}; + +snippet rdef +abbr ReadDefaultsValue + [[NSUserDefaults standardUserDefaults] objectForKey:${1:key}]; + + +snippet wdef +abbr WriteDefaultsValue + [[NSUserDefaults standardUserDefaults] setObject:${1:object} forKey:${2:key}]; + + +snippet ibo +abbr IBOutlet + IBOutlet ${1}${2: *}${3}; + + +snippet syn + @synthesize ${1:#:property}; + + +snippet bind + bind:@"${2:#:binding}" toObject:${3:observableController} withKeyPath:@"${4:keyPath}" options:${5:nil} + + +snippet reg + [[NSNotificationCenter defaultCenter] addObserver:${1:self} selector:@selector(${3}) name:${2:NSWindowDidBecomeMainNotification} object:${4:nil}]; + + +snippet focus + [self lockFocus]; + ${0} + [self unlockFocus]; + +snippet forarray + unsigned int ${1:object}Count = [${2:array} count]; + + for(unsigned int index = 0; index < ${1}Count; index += 1) + { + ${3:id} ${1} = [${2} objectAtIndex:index]; + ${0} + } + +snippet alert + int choice = NSRunAlertPanel(@"${1:Something important!}", @"${2:Something important just happend, and now I need to ask you, do you want to continue?}", @"${3:Continue}", @"${4:Cancel}", nil); + if(choice == NSAlertDefaultReturn) // "${3:Continue}" + { + ${0}; + } + else if(choice == NSAlertAlternateReturn) // "${4:Cancel}" + { + + } + +snippet res + ${1} Send ${2} to ${1}, if ${1} supports it}${3} + if ([${1:self} respondsToSelector:@selector(${2:someSelector:})]) + { + [${1} ${3}]; + } + +snippet del + if([${1:[self delegate]} respondsToSelector:@selector(${2:selfDidSomething:})]) + [${1} ${3}]; + + +snippet format + [NSString stringWithFormat:@"${1}", ${2}]${0} + + +snippet save + [NSGraphicsContext saveGraphicsState]; + ${0} + [NSGraphicsContext restoreGraphicsState]; + + +snippet thread + [NSThread detachNewThreadSelector:@selector(${1:#:method}:) toTarget:${2:#:aTarget} withObject:${3:#:anArgument}] + + +snippet pool + NSAutoreleasePool${TM_C_POINTER: *}pool = [NSAutoreleasePool new]; + ${0} + [pool drain]; + diff --git a/bundle/neosnippet-snippets/neosnippets/ocaml.snip b/bundle/neosnippet-snippets/neosnippets/ocaml.snip new file mode 100644 index 000000000..0cd75b925 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/ocaml.snip @@ -0,0 +1,117 @@ +snippet mot +abbr module signature +options head + module type ${1} = sig + ${2:TARGET} + end + +snippet mod +abbr module struct +options head + module ${1} = struct + ${2:TARGET} + end + +snippet mos +abbr module signature +options head + module ${1} : sig + ${2:TARGET} + end + +snippet cc +abbr comment + (* ${0:TARGET} *) + +snippet Cc +abbr multi line comment + (* + ${0:TARGET} + *) + +snippet oo +abbr ocamldoc comment (** .. *) + (** ${0:TARGET} *) + +snippet if +abbr if..then..else + if ${1:TARGET} + then ${2} + else ${3} + +snippet let +abbr let..in + let ${1:TARGET} in ${0} + +snippet letr +abbr let rec .. in +options head + let rec ${1:TARGET} + in ${0} + +snippet match +abbr match + match ${1:TARGET} with + | ${2} -> ${0} + +snippet obj +abbr object + object + ${0:TARGET} + end + +snippet try +abbr try..with + try ${1:TARGET} + with ${0} + +snippet lopen +abbr let open .. in +options head + let open ${1} in + ${2:TARGET} + +snippet for +abbr for i=x..y do; ... done +options head + for ${1:i} = ${2:0} to ${3:10} do + ${0:TARGET} + done + +snippet while +abbr while ... do; ... done +options head + while ${1:true} do + ${2:TARGET} + done + +snippet fun +abbr (fun x -> ...) + (fun ${1:x} -> ${2:TARGET}) + +snippet arl +abbr array literal [| |] + [| ${0:TARGET} |] + +snippet fail +abbr failwith "..." + failwith "${0:TARGET}" + +snippet beg +abbr begin ... end + begin ${0:TARGET} end + +snippet exn +abbr exception +options head + exception ${0:TARGET} of ${1:string} + +snippet lit +abbr string literals {xxx| ... |xxx} +options head + {${0:}|${1:TARGET}|$0} + +snippet @@ +abbr [@@deriving ...] +options head + [@@deriving ${0:TARGET}] diff --git a/bundle/neosnippet-snippets/neosnippets/perl.snip b/bundle/neosnippet-snippets/neosnippets/perl.snip new file mode 100644 index 000000000..84034198d --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/perl.snip @@ -0,0 +1,77 @@ +snippet perl + #!/opt/local/bin/perl + + use strict; + use warnings; + ${1} + +snippet sub + sub ${1:#:function_name} { + ${2:TARGET} + } + +snippet if + if (${1:#:condition}) { + ${2:TARGET} + } + +snippet ife + if (${1:#:condition}) { + ${2:TARGET} + } else { + ${3:#:else...} + } + +snippet ifee + if (${1:#:condition}) { + ${2:TARGET} + } elsif (${3}) { + ${4:#:elsif...} + } else { + ${5:#:else...} + } + +snippet xif + ${1:#:expression} if ${2:#:condition}; + +snippet while +abbr wh + while (${1:#:condition}) { + ${2:TARGET} + } + +snippet xwhile +abbr xwh + ${1:#:expression} while ${2:#:condition}; + +snippet for + for (my $${1:#:var} = 0; $$1 < ${2:#:expression}; $$1++) { + ${3:TARGET} + } + +snippet fore + for ${1} (${2:#:expression}){ + ${3:TARGET} + } + +snippet xfor + ${1:#:expression} for @${2:#:array}; + +snippet unless +abbr un + unless (${1:condition}) { + ${2:TARGET} + } + +snippet xunless +abbr xun + ${1:#:expression} unless ${2:#:condition}; + +snippet eval + eval { + ${1:TARGET} + }; + if ($@) { + ${2:#:handle failure...} + } + diff --git a/bundle/neosnippet-snippets/neosnippets/php.snip b/bundle/neosnippet-snippets/neosnippets/php.snip new file mode 100644 index 000000000..2cb47a5c5 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/php.snip @@ -0,0 +1,332 @@ +snippet function +abbr public function () {} + ${1:public }function ${2:#:FunctionName}(${3}) + { + ${4:TARGET} + } + +snippet function_literal +options word +abbr function () {} + function (${1})${2: use } { + ${3:TARGET} + } + +snippet php + ${0} + +snippet echoh + ${0} + +snippet pforeach + }): ?> + ${0:TARGET} + + +snippet pifelse + + ${2:TARGET} + + ${0} + + +snippet pif + + ${0:TARGET} + + +snippet pelse + + +snippet pthis + ${0} ?> + +snippet pethis + ${0} ?> + +snippet doc_class_var + /** + * ${3:#:undocumented class variable} + * + * @var ${4:#:string} + **/ + ${1:#:var} $${2};${0} + +snippet doc_constant + /** + * ${3:#:undocumented constant} + **/ + define(${1} ${2});${0} + +snippet doc_interface_function + /** + * ${4:#:undocumented function} + * + * @return ${5:void} + * @author ${6} + **/ + ${1}function ${2}(${3});${0} + +snippet doc_function + /** + * ${4:#:undocumented function} + * + * @return ${5:void} + * @author ${6} + **/ + ${1}function ${2}(${3}) + { + ${0:TARGET} + } + + +snippet doch + /** + * ${1} + * + * @author ${2} + * @version ${3} + * @copyright ${4} + * @package ${5:default} + **/ + + /** + * Define DocBlock + **/ + +snippet doci + /** + * ${2:#:undocumented class} + * + * @package ${3:default} + * @author ${4} + **/ + interface ${1} + { + ${0:TARGET} + } // END interface $1 + +snippet doc + /** + * ${0} + */ + +snippet class_with_constructor + /** + * ${1} + */ + class ${2:#:ClassName}${3:#:extends} + { + $5 + function ${4:__construct}(${5:#:argument}) + { + ${0:# code...} + } + } + +snippet class +options head + class ${2:#:ClassName} { + ${0:TARGET} + } + +snippet def + ${1}defined('${2}')${0} + + +snippet dowhile +options head + do { + ${0:TARGET} + } while (${1:#:condition}); + +snippet if? +options head + $${1:#:retVal} = (${2:#:condition}) ? ${3:#:a} : ${4:#:b}; + +snippet ifelse +options head + if (${1:#:condition}) { + ${2:TARGET} + } else { + ${3:#:code...} + } + ${0} + +snippet if +options head + if (${1:#:condition}) { + ${0:TARGET} + } + +snippet var_dump +options head + var_dump(${0:TARGET}); + +snippet p +options head + print_r(${1}); + +snippet echo +options head + echo "${1:#:string}"; + +snippet println +options head + printf("${1:#:string}\n"${2:, }); + +snippet else + else { + ${0:TARGET} + } + +snippet elseif + elseif (${1:#:condition}) { + ${0:TARGET} + } + +snippet for +options head + for ($${1:i}=${2:0}; $$1 < ${3}; $$1++) { + ${0:TARGET} + } + +snippet foreach-hashmap + foreach ($${1:#:variable} as $${2:#:key}${3: =>} $${4:#:value}) { + ${0:TARGET} + } + +snippet foreach-list +alias foreach +options head + foreach ($${1:#:variable} as $${2:#:x}) { + ${0:TARGET} + } + +snippet construct +options head + function __construct(${1}) + { + ${0:TARGET} + } + +snippet here + <<<${1:HTML} + ${2:TARGET:#:content here} + $1; + +snippet inc +options head + include '${1:#:file}';${0} + +snippet inco +options head + include_once '${1:#:file}';${0} + +snippet array + $${1:#:arrayName} = array('${2}' => ${3} ${0}); + +snippet req +options head + require '${1:#:file}';${0} + +snippet reqo +options head + require_once '${1:#:file}';${0} + +snippet ret +options head + return${1};${0} + +snippet retf +options head + return false; + +snippet rett +options head + return true; + +snippet case +options head + case '${1:#:variable}': + ${0:#:code...} + break; + +snippet switch +abbr sw +options head + switch (${1:#:variable}) { + case '${2:#:value}': + ${3:#:code...} + break; + ${0} + default: + ${4:#:code...} + break; + } + +snippet try +options head + try { + ${1:TARGET} + } catch (${2:#:Exception} $e) { + ${3:#:code} + } + +snippet tryf +options head + try { + ${1:TARGET} + } catch (${2:#:Exception} $e) { + ${3:#:code} + } finally { + ${4:#:code} + } + +snippet throw +options head + throw new ${1}Exception(${2:"${3:#:Error Processing Request}"}${4:}); + ${0} + +snippet while +abbr wh +options head + while (${1}) { + ${0:TARGET} + } + +snippet gloabals + \$GLOBALS['${1:#:variable}']${2: = }${3:#:something}${4:;}${0} + +snippet cookie + \$_COOKIE['${1:#:variable}'] + +snippet env + \$_ENV['${1:#:variable}'] + +snippet files + \$_FILES['${1:#:variable}'] + +snippet get + \$_GET['${1:#:variable}'] + +snippet post + \$_POST['${1:#:variable}'] + +snippet request + \$_REQUEST['${1:#:variable}'] + +snippet server + \$_SERVER['${1:#:variable}'] + +snippet session + \$_SESSION['${1:#:variable}'] + +snippet var_export +alias inspect + var_export(${1}, true) diff --git a/bundle/neosnippet-snippets/neosnippets/prolog.snip b/bundle/neosnippet-snippets/neosnippets/prolog.snip new file mode 100644 index 000000000..81a2d25d4 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/prolog.snip @@ -0,0 +1,28 @@ +snippet main +options head + :- initialization main. + + main :- + current_prolog_flag(argv, Args), + writeln(Args), + halt. + +snippet module +options head + :- module(${1:name}, [${0:export}]). + +snippet begintest +options head + :- begin_tests(${1:name}). + ${0} + :- end_tests($1). + +snippet runtest +options head + :- run_tests. + :- halt. + +snippet test +options head + test(${1:case}, [true(${2:var} = ${3:value})]) :- + ${0:goal}. diff --git a/bundle/neosnippet-snippets/neosnippets/python.snip b/bundle/neosnippet-snippets/neosnippets/python.snip new file mode 100644 index 000000000..3c5cac0a4 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/python.snip @@ -0,0 +1,157 @@ +snippet #! +abbr #!/usr/bin/env python3 +alias shebang +options head + #!/usr/bin/env python3 + ${0} + +snippet class +abbr class Class(...): ... +options head + class ${1:#:name}(${2:object}): + + def __init__(self, ${3}): + ${0:pass} + +snippet classd +abbr class Class(...): "..." +options head + class ${1:#:name}(${2:object}): + """${3:#:class documentation}""" + + def __init__(self, ${4}): + """${5:#:__init__ documentation}""" + ${0:pass} + +snippet def +abbr def function(...): ... +options head + def ${1:#:name}(${2}): + ${0:pass} + +snippet defd +abbr def function(...): """...""" +options head + def ${1:#:name}(${2}): + """${3:#:function documentation}""" + ${0:pass} + +snippet defm +abbr def method(self, ...): ... +options head + def ${1:#:name}(self, ${2}): + ${0:pass} + +snippet defmd +abbr def method(self, ...): "..." +options head + def ${1:#:name}(self, ${2}): + """${3:#:method documentation}""" + ${0:pass} + +snippet elif +abbr elif ...: ... +options head + elif ${1:#:condition}: + ${0:pass} + +snippet else +abbr else: ... +options head + else: + ${0:pass} + +snippet with_open +alias fileidiom +options head + with open(${1:#:file}, '${2:r}') as ${3:f}: + ${0:pass} + +snippet for +abbr for ... in ...: ... +options head + for ${1:#:value} in ${2:#:list}: + ${0:pass} + +snippet if +abbr if ...: ... +options head + if ${1:#:condition}: + ${0:pass} + +snippet ifmain +abbr if __name__ == '__main__': ... +alias main +options head + if __name__ == '__main__': + ${0:pass} + +snippet tryexcept +abbr try: ... except ...: ... +options head + try: + ${1:pass} + except ${2:#:ExceptionClass}: + ${3:pass} + +snippet tryfinally +abbr try: ... finally: ... +options head + try: + ${1:pass} + finally: + ${2:pass} + +snippet while +abbr while ...: ... +options head + while ${1:#:condition}: + ${0:pass} + +snippet with +abbr with {func}({file}) as : +options head + with ${1:open}(${2:#:filename, mode}) as ${3:f}: + ${0:pass} + +snippet filter +abbr [x for x in {list} if {condition}] + [$1 for ${1:x} in ${2:#:list} if ${3:#:condition}] + +snippet print +options word + print(${0:#:TARGET}) + +snippet coding +abbr # -*- coding ... + # -*- coding: utf-8 -*- + +snippet getattr +abbr getattr(..., ...) +options word + getattr(${1:#:obj}, ${2:#:attr}) + +snippet setattr +abbr setattr(..., ...) + setattr(${1:#:obj}, ${2:#:attr}, ${3:#:value}) + +snippet hasattr +abbr hasattr(..., ...) +options word + hasattr(${1:#:obj}, ${2:#:attr}) + +snippet pdb +abbr import pdb.. + import pdb; pdb.set_trace() + +snippet ipdb +abbr import ipdb.. + import ipdb; ipdb.set_trace() + +snippet pudb +abbr import pudb.. + import pudb; pudb.set_trace() + +snippet ipy +abbr import ipython.. + from IPython import embed; embed() diff --git a/bundle/neosnippet-snippets/neosnippets/rails.snip b/bundle/neosnippet-snippets/neosnippets/rails.snip new file mode 100644 index 000000000..1e5004947 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/rails.snip @@ -0,0 +1,164 @@ +snippet rr +abbr render + render + +snippet ra +abbr render :action + render action: + +snippet rc +abbr render :controller + render controller: + +snippet rf +abbr render :file + render file: + +snippet ri +abbr render :inline + render inline: + +snippet rj +abbr render :json + render json: + +snippet rl +abbr render :layout + render layout: + +snippet rp +abbr render :partial + render partial: + +snippet rt +abbr render :text + render text: + +snippet rx +abbr render :xml + render xml: + +snippet dotiw +abbr distance_of_time_in_words + distance_of_time_in_words + +snippet taiw +abbr time_ago_in_words + time_ago_in_words + +snippet re +abbr redirect_to + redirect_to + +snippet rea +abbr redirect_to :action + redirect_to action: + +snippet rec +abbr redirect_to :controller + redirect_to controller: + +snippet rst +abbr respond_to + respond_to + +snippet bt +abbr belongs_to + belongs_to + +snippet ho +abbr has_one + has_one + +snippet hm +abbr has_many + has_many + +snippet habtm +abbr has_and_belongs_to_many + has_and_belongs_to_many + +snippet co +abbr composed_of + composed_of + +snippet va +abbr validates_associated + validates_associated + +snippet vb +abbr validates_acceptance_of + validates_acceptance_of + +snippet vc +abbr validates_confirmation_of + validates_confirmation_of + +snippet ve +abbr validates_exclusion_of + validates_exclusion_of + +snippet vf +abbr validates_format_of + validates_format_of + +snippet vi +abbr validates_inclusion_of + validates_inclusion_of + +snippet vl +abbr validates_length_of + validates_length_of + +snippet vn +abbr validates_numericality_of + validates_numericality_of + +snippet vp +abbr validates_presence_of + validates_presence_of + +snippet vu +abbr validates_uniqueness_of + validates_uniqueness_of + +snippet logd +abbr logger.debug + logger.debug + +snippet logi +abbr logger.info + logger.info + +snippet logw +abbr logger.warn + logger.warn + +snippet loge +abbr logger.error + logger.error + +snippet logf +abbr logger.fatal + logger.fatal + +snippet action +abbr action: + action: + +snippet co_ +abbr co________: + co________: + +snippet id +abbr id: + id: + +snippet object +abbr object: + object: + +snippet partial +abbr partial: + partial: + diff --git a/bundle/neosnippet-snippets/neosnippets/rst.snip b/bundle/neosnippet-snippets/neosnippets/rst.snip new file mode 100644 index 000000000..c981681d0 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/rst.snip @@ -0,0 +1,244 @@ +snippet quickstart +options head + =========================== + ${1:#:content_name} + =========================== + + .. contents:: contents_name + + title1 + ==================================== + + subtitle1 + ----------------------------------- + + subtitle2 + ----------------------------------- + + subtitle3 + ----------------------------------- + + title2 + ==================================== + + subtitle1 + ----------------------------------- + + subtitle2 + ----------------------------------- + + subtitle3 + ----------------------------------- + + title3 + ==================================== + + subtitle1 + ----------------------------------- + + subtitle2 + ----------------------------------- + + subtitle3 + ----------------------------------- + + +snippet contnents +options head + .. contents:: ${1:#:contents_name} + +snippet title +options head + ${1:#:title} + ==================================== + +snippet subtitle +options head + ${1:#:subtitle} + ----------------------------------- + +snippet code_block +abbr code +options head + .. code-block:: ${1:#:filetype} + + ${2:#:content} + +snippet link_raw +abbr link_as_raw +options head + \`${1:#:link}\`_ + +snippet link_label +abbr link_and_label +options head + \`${1:#:title} <${2:#:link}>\`_ + +snippet table_grid +abbr grid_table +options head + +------------------+------------+-----------------------+------------+ + |${1:#:cel} | | | | + +==================+============+=======================+============+ + | | | | | + +------------------+------------+-----------------------+------------+ + | | | | | + +------------------+------------+-----------------------+------------+ + +snippet table_simple +abbr simple_table +options head + :${1:#:text}: + : : + : : + : : + +snippet list +options head + - + - + - + - + +snippet nested_list +options head + + - ${1:#:text} + - + - + - + +snippet caption +options head + [#] + +snippet image +options head + .. image:: ${1:#:path} + +snippet strong +options head + **${1:#:text}** + + +snippet toctree +abbr directive_toctree +options head + .. toctree:: + :maxdepth: ${1:2} + + ${2:#:FILES} + + +snippet link_doc +abbr link_to_doc +options head + :doc:\`${1:#:PageName}\` ${0:#:CURSOR} + + +snippet syntax +abbr syntax +options indent + .. code-block:: ${1:python} + + ${1:#:TERGET} + + +snippet label +abbr label +options head + .. _${1:#:NAME}: + ${2:#:CURSOR} + + +snippet ref +abbr role_ref + :ref:\`${1:#:NAME}\` + ${2:#:CURSOR} + + +snippet content +abbr directive_content +options head + .. contents:: + :depth: ${1:2} + ${2::local:} + + +snippet guilabel +abbr role_guilabel + :guilabel:\`${1:#:NAME}\` ${0:#:CURSOR} + + +snippet menuselection +abbr role_menuselection + :menuselection:\`${1:#:NAME} --> ${2:#:NAME}\` ${0:#:CURSOR} + + +snippet table +abbr directive_table +options head + .. table:: ${1:#:TITLE} + ${0:#:CURSOR} + +snippet csvtable +abbr directive_csvtable +options head + .. csv-table:: ${1:#:TITLE} + :header: "${2:#:Header1}", "${3:#:Header2}"${4:#:Headers} + + "${5:#:Column1}", "${6:#:Column2}"${0:#:CURSOR} + + +snippet directive +abbr directive + .. ${1:#:NAME}:: ${0:#:CURSOR} + + +snippet note +abbr note + .. note:: ${0:#:CURSOR} + + +snippet tip +abbr tip + .. tip:: ${0:#:CURSOR} + + +snippet warning +abbr warning + .. warning:: ${0:#:CURSOR} + + +snippet attention +abbr attention + .. attention:: ${0:#:CURSOR} + +snippet caution +abbr caution + .. caution:: ${0:#:CURSOR} + + +snippet danger +abbr danger + .. danger:: ${0:#:CURSOR} + + +snippet error +abbr error + .. error:: ${0:#:CURSOR} + + +snippet hint +abbr hint + .. hint:: ${0:#:CURSOR} + + +snippet important +abbr important + .. important:: ${0:#:CURSOR} + + +snippet seealso +abbr seealso + .. seealso:: ${0:#:CURSOR} diff --git a/bundle/neosnippet-snippets/neosnippets/ruby.snip b/bundle/neosnippet-snippets/neosnippets/ruby.snip new file mode 100644 index 000000000..d77c6d4d1 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/ruby.snip @@ -0,0 +1,178 @@ +snippet #! +abbr #!/usr/bin/env ruby +alias shebang +options head + #!/usr/bin/env ruby + ${0} + +snippet if +abbr if ... end + if ${1:#:condition} + ${0:TARGET} + end + +snippet unless +abbr unless ... end + unless ${1:#:condition} + ${0:TARGET} + end + +snippet def +abbr def ... end + def ${1:#:method_name} + ${0:TARGET} + end + +snippet defrescue +alias defr +abbr def ... rescue ... end + def ${1:#:method_name} + ${2:TARGET} + rescue ${3:#:StandardError} => ${4:error} + ${0} + end + +snippet do +abbr do ... end + do + ${0:TARGET} + end + +snippet dovar +abbr do |var| ... end + do |${1:#:var}| + ${0:TARGET} + end + +snippet block +abbr { ... } + { + ${0:TARGET} + } + +snippet blockvar +abbr {|var| ... } + {|${1:#:var}| + ${0:TARGET} + } + +snippet fileopen +alias open +abbr File.open(filename) do ... end + File.open(${1:#:filename}, '${2:#:mode}') do |${3:io}| + ${0:TARGET} + end + +snippet edn +abbr => end? + end + +snippet urlencode + # coding: utf-8 + require 'erb' + puts ERB::Util.url_encode '${1}' + +snippet encoding +alias enc + # coding: utf-8 + ${0} + +snippet each +options word + each do |${1:#:variable}| + ${0} + end + +snippet each_byte +options word + each_byte {|${1:#:variable}| ${0} } + +snippet each_char +options word + each_char {|${1:#:variable}| ${0} } + +snippet each_index +options word + each_index {|${1:#:variable}| ${0} } + +snippet each_key +options word + each_key {|${1:#:variable}| ${0} } + +snippet each_line +options word + each_line {|${1:#:variable}| ${0} } + +snippet each_with_index +options word + each_with_index {|${1:#:variable}| ${0} } + +snippet each_pair +options word + each_pair {|${1:#:key}, ${2:value}| ${0} } + +snippet each_pair_do +options word + each_pair do |${1:key}, ${2:value}| + ${0} + end + +snippet map +options word + map {|${1:#:variable}| ${0} } + +snippet sort +options word + sort {|${1:x}, ${2:y}| ${0} } + +snippet sort_by +options word + sort_by {|${1:#:variable}| ${0} } + +snippet lambda +options word + -> (${1:#:args}) { ${0} } + +snippet lambda-keyword +options word + lambda {|${1:#:args}| ${0} } + +snippet main +options head + if __FILE__ == \$0 + ${0:TARGET} + end + +# This idiom is only for legacy ruby such as 1.9.3 +snippet filedir-legacy-compatibility +alias __dir__ +abbr File.dirname(...) + File.dirname(File.expand_path(__FILE__)) + +snippet glob +options head + Dir.glob(${1:'**/*'}) do |fname| + ${0:TARGET} + end + +snippet case +abbr case ... when ... else ... end +options head + case ${1} + when ${2} + ${3} + else + ${0} + end + +snippet class + class ${1:`substitute(expand('%:t:r:r:r'), '\v%(^(.)|_(.))', '\u\1\u\2', 'g')`} + ${0} + end + +snippet module + module ${1:`substitute(expand('%:t:r:r:r'), '\v%(^(.)|_(.))', '\u\1\u\2', 'g')`} + ${0} + end + +# vim:set et ts=2 sts=2 sw=2 tw=0: diff --git a/bundle/neosnippet-snippets/neosnippets/rust.snip b/bundle/neosnippet-snippets/neosnippets/rust.snip new file mode 100644 index 000000000..d9e129051 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/rust.snip @@ -0,0 +1,173 @@ +# functions + +snippet fn +abbr fn () {} +options head + fn ${1:#:func_name}(${2:#:args}) { + ${0:TARGET} + } + +snippet fn- +abbr fn () {} +options head + fn ${1:#:func_name}(${2:#:args}) -> ${3:#:()} { + ${0:TARGET} + } + +snippet pubfn +abbr pubfn () {} +options head + pub fn ${1:#:func_name}(${2:#:args}) -> ${3:#:()} { + ${0:TARGET} + } + +snippet test +options head + #[test] + fn ${1:#:test_function_name}() { + ${0:TARGET} + } + +snippet pubnew +abbr pub fn new() {} +options head + pub fn new(${1}) -> ${2:#:Name} { + ${0:TARGET} + } + +snippet impl +options head + impl ${1} { + ${0:TARGET} + } + +snippet implfor +options head + impl ${1} for ${2} { + ${0:TARGET} + } + +snippet trait +options head + trait ${1} { + ${0:TARGET} + } + +# macros + +snippet macro + ${1:#:macro_name}!(${2})${3} + +snippet bfl +abbr bitflags! + bitflags! { + ${0:TARGET} + } + +snippet pln +abbr println! + println!(${1:"\{\}"}, ${0:TARGET}); + +snippet fm +abbr format! + format!("${1:\{\}}", ${0:TARGET}); + +# attributes + +snippet ec +abbr extern crate +options head + extern crate ${0:TARGET}; + +snippet ecl +abbr extern crate log +options head + #![feature(phase)] + #[phase(plugin, link)] extern crate log; + +snippet crate +options head + #![crate_name=${1:#:crate_name}] + +snippet derive +options head + #[derive(${1:TARGET})]${2} + +# statements + +snippet mod +options head + mod ${1:#:mod_name} { + ${0:TARGET} + } + +snippet let + let ${1:TARGET} = ${2};${3} + +snippet if +abbr if {} + if ${1:#:condition} { + ${0:TARGET} + } + +snippet else + else { + ${0:TARGET} + } + +snippet elseif + } else if (${1:#:condition}) { + ${0:TARGET} + } + +snippet ifelse +abbr if () {} else {} + if ${1:#:condition} { + ${2:TARGET} + } else { + ${3} + } + +snippet forin +abbr forin {} + for ${1} in ${2} { + ${0:TARGET} + } + +snippet match + match ${1:TARGET} { + ${2:#:pattern} => ${3:#expr},${4} + } + +snippet mcase +alias case + ${1:TARGET} => ${2:#expr},${3} + +# data + +snippet struct +options head + struct ${1} { + ${0:TARGET} + } + +snippet pubstruct +abbr pub struct +options head + pub struct ${1} { + ${0:TARGET} + } + +snippet enum +options head + enum ${1} { + ${0:TARGET} + } + +snippet opt +abbr Option + Option<${1:()}>${2} + +snippet res +abbr Result + Result<${1:#:~str}, ${2:#:()}>${3} diff --git a/bundle/neosnippet-snippets/neosnippets/scala.snip b/bundle/neosnippet-snippets/neosnippets/scala.snip new file mode 100644 index 000000000..f960ab5b4 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/scala.snip @@ -0,0 +1,103 @@ +snippet match +abbr match {\n case .. => .. + match { + case ${1} => ${0} + } + +snippet case +abbr case .. => .. + case ${1} => ${0} + +snippet try +abbr try {} catch { case ... } +options head + try { + ${1:TARGET} + } catch { + case e${2:: Exception} => ${0} + } + +snippet for + for { + ${1} + } yield ${2} + +snippet if + if (${1}) { + ${2} + }${3: else} + +snippet p +abbr println() + println(${1}) + +snippet pn +abbr println('name, name) + println('${1:#:name}, $1) + +snippet pf +abbr p in for + _ = println(${1}) + +snippet main +abbr def main(args: Array[String]) { +options head + object ${1:`expand('%:t:r') ==# '' ? 'HelloWorld' : expand('%:t:r')`} { + def main(args: Array[String]) { + ${0:TARGET} + } + } + +snippet hello +abbr object HelloWorld { def main(...) } +options head + object ${1:`expand('%:t:r') ==# '' ? 'HelloWorld' : expand('%:t:r')`} { + def main(args: Array[String]) { + println("Hello, world!") + } + } + +snippet object +options head + object ${1:X} { + ${0:TARGET} + } + +snippet class +options head + class ${1:X()} { + ${0:TARGET} + } + +snippet should-scalatest +options word + should "${1}" in { + ${0:TARGET} + } + +snippet akka-actor +options head + import akka.actor.{ActorSystem, Actor, ActorLogging, Props} + + object ${1:X} { + def props(${2}) = Props(new X($2)) + } + + class $1($2) extends Actor with ActorLogging { + def receive = { + case e => + ${0:TARGET:println(e)} + } + } + +snippet package +options head + package `substitute(substitute(expand('%:h'), '.*\&2 + +snippet abort +options head + echo "${0:TARGET}" 1>&2 + exit 1 + +# vim: set noexpandtab : diff --git a/bundle/neosnippet-snippets/neosnippets/sql.snip b/bundle/neosnippet-snippets/neosnippets/sql.snip new file mode 100644 index 000000000..3708a8399 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/sql.snip @@ -0,0 +1,63 @@ +snippet CREATE_TABLE +abbr CREATE TABLE { ... } +options head + CREATE TABLE ${1:cities} ( + ${0:name varchar(80), country_name text} + ); + +snippet CREATE_INDEX +abbr CREATE INDEX ... ON ... ( ... ) +options head + CREATE INDEX ${1:_name} ON ${2:cities} (${3:name}); + +snippet DROP_TABLE +abbr DROP TABLE IF EXISTS ... + DROP TABLE IF EXISTS ${1:table}; + +snippet ALTER_TABLE +abbr ALTER TABLE ... MODIFY ... + ALTER TABLE ${1:table} + MODIFY ${2:column} ${3:new_column_desc}; + +snippet TRUNCATE_TABLE +abbr TRUNCATE TABLE ... + TRUNCATE TABLE ${1:table}; + +snippet INSERT_DATA +abbr INSERT INTO ... VALUES ( ... ) +options head + INSERT INTO ${1:cities} + VALUES (${0:'Vancouver', 'Canada'}); + +snippet UPDATE_DATA +abbr UPDATE ... SET ... WHERE ... + UPDATE ${1:table} + SET ${2:column} = ${3:value} + WHERE ${4:condition}; + +snippet SELECT_DATA +abbr SELECT * from ... ORDER BY ... LIMIT ... +options head + SELECT ${1:*} + FROM ${2:cities} ${3:WHERE area = 'Asia'} + ${4: ORDER BY distance} + ${5: LIMIT 30}; + +snippet SELECT_JOIN_DATA +abbr SELECT * FROM T1 JOIN T2 ... ON + SELECT ${1:*} + FROM ${2:table1} ${3:T1} + JOIN ${4:table2} ${5:T2} + ON T1.${6:column1} = T2.${7:column2} + +snippet DELETE_DATA +abbr DELETE FROM ... WHERE ... + DELETE FROM ${1:table} + WHERE ${2:condition}; + +snippet TRANSACTION +alias BEGIN TRANSACTION +options head + BEGIN TRANSACTION; + ${0:TARGET} + COMMIT; diff --git a/bundle/neosnippet-snippets/neosnippets/sshconfig.snip b/bundle/neosnippet-snippets/neosnippets/sshconfig.snip new file mode 100644 index 000000000..d2aafcca6 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/sshconfig.snip @@ -0,0 +1,6 @@ +snippet Host +options head + Host ${1:name} + HostName $1.${2:domain} + Port ${3} + ${4:User } diff --git a/bundle/neosnippet-snippets/neosnippets/swift.snip b/bundle/neosnippet-snippets/neosnippets/swift.snip new file mode 100644 index 000000000..d66396aa9 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/swift.snip @@ -0,0 +1,163 @@ +snippet struct +options word + struct ${1:name} { + ${0:TARGET} + } + +snippet class +options word + class ${1:name} { + ${0:TARGET} + } + +snippet enum +options word + enum ${1:name} { + ${0:TARGET} + } + +snippet case +options head + case ${1:pattern}${0} + +snippet protocol +options word + protocol ${1:name} { + ${0:TARGET} + } + +snippet var +options word + var ${1:name}: ${2:Int}${0} + +snippet let +options word + let ${1:name}: ${2:Int}${0} + +snippet extension + extension ${1:Int} { + ${0:TARGET} + } + +snippet func +abbr func name(...) -> Type { ... } +options word + func ${1:name}(${2:#:arguments}) -> ${3:Int}${0} + +snippet void +abbr func name(...) { ... } +options word + func ${1:name}(${2:#:arguments})${0} + +snippet for +options head + for var ${1:i = 0}; ${2:i < j}; ${3:i++} { + ${0:TARGET} + } + +snippet iter +options head + for ${1:item} in ${2:collection} { + ${0:TARGET} + } + +snippet while +options head + while ${1:false} { + ${0:TARGET} + } + +snippet repeat +options head + repeat { + ${0:TARGET} + } while ${1:false} + +snippet if +options word + if ${1:false} { + ${0:TARGET} + }${9} + +snippet elif +options word + else if ${1:false} { + ${0:TARGET} + }${9} + +snippet else +options word + else { + ${0:TARGET} + }${9} + +snippet optional +abbr if let/case ... { ... } +options head + if ${1:let} ${2:name} = ${3:expression} else { + ${0:TARGET} + }${9} + +snippet guard +abbr guard let ... else { ... } +options head + guard let ${1} = ${2} else { + ${0:TARGET} + } + ${9} + +snippet switch +options head + switch ${1:expression} { + ${0:TARGET} + } + +snippet do +options head + do { + ${0:TARGET} + }${9} + +snippet catch +options word + catch${1:#:pattern} { + ${0:TARGET} + }${9} + +snippet defer +options head + defer { + ${0:TARGET} + } + +snippet import + import ${1:module} + ${0} + +snippet subscript +options word + subscript(${1:index: Int}) -> ${2:Int} { + ${0:TARGET} + } + ${9} + +snippet init +options word + init${1:#:?}(${2:#:arguments}) { + ${0:TARGET} + } + ${9} + +snippet deinit +options head + deinit { + ${0:TARGET} + } + +snippet closure +options word +abbr { (...) -> Type in ... } + { ${1:#capture}(${2:#:arguments}) -> ${3:Void} in + ${0:TARGET} + } + ${9} diff --git a/bundle/neosnippet-snippets/neosnippets/systemverilog.snip b/bundle/neosnippet-snippets/neosnippets/systemverilog.snip new file mode 100644 index 000000000..7acb1b380 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/systemverilog.snip @@ -0,0 +1,55 @@ +include verilog.snip + +snippet alc +abbr always_comb + always_comb begin + ${1:TARGET} + end + +snippet alf +abbr always_ff @() + always @(posedge ${1:clk} iff !${2:rst} or posedge $2) begin + if (${2}) begin + ${3:TARGET} + end else begin + end + end + +snippet all +abbr always_latch + always_latch begin + if (${1:enable}) begin + ${2:TARGET} + end + end + +snippet rw +abbr logic [] _r, _w; + logic${1:#: nbit} ${2:reg}_r, $2_w;${3:TARGET} + +snippet struct + typedef struct packed { + ${2:TARGET} + } ${1:name} ; + +snippet enum + typedef enum {${2:TARGET}} ${1:name}; + +snippet for + for (int ${1:i} = ${2}; $1 < ${3}; ${4:do what}) begin + ${5:TARGET} + end + +snippet case_parallel + unique case (${1}) begin + ${2:'b0}: begin + ${3} + end + end + +snippet case_full + priority case (${1}) begin + ${2:'b0}: begin + ${3} + end + end diff --git a/bundle/neosnippet-snippets/neosnippets/tex.snip b/bundle/neosnippet-snippets/neosnippets/tex.snip new file mode 100644 index 000000000..20501c8f9 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/tex.snip @@ -0,0 +1,576 @@ +snippet \documentclass +alias documentclass + \documentclass[${1}]{${2:article}}${0} + +snippet mathexpression +alias $ +abbr $ expression $ + $${1:#:expression}$${2} + +snippet mathenva +alias $$ +abbr $$ expression $$ + $$${1:#:expression}$$${2} + +snippet mathenvb +alias \[ +abbr \[ expression \] + \[${1:#:expression}\]${2} + +# ========== ENVIRONMENT ========== + +snippet begin +alias \begin + \begin{${1:#:type}} + ${2:TARGET} + \end{$1} + +snippet list +alias \begin{list} \list + \begin{list} + ${1:TARGET} + \end{list} + +snippet quotation +alias \begin{quotation} \quotation + \begin{quotation} + ${1:TARGET} + \end{quotation} + +snippet description +alias \begin{description} \description desc + \begin{description} + \item[${1}] ${0} + \end{description} + +snippet itd +alias item[ \item[ + \item[${1}] ${0} + +snippet it +alias item \item + \item ${0} + +snippet sloppypar +alias \begin{sloppypar} \sloppypar + \begin{sloppypar} + ${1:TARGET} + \end{sloppypar} + +snippet enumerate +alias \begin{enumerate} \enumerate enum + \begin{enumerate} + \item ${1:TARGET} + \end{enumerate} + +snippet theindex +alias \begin{theindex} \theindex + \begin{theindex} + ${1:TARGET} + \end{theindex} + +snippet itemize +alias \begin{itemize} \itemize + \begin{itemize} + \item ${1:TARGET} + \end{itemize} + +snippet titlepage +alias \begin{titlepage} \titlepage + \begin{titlepage} + ${1:TARGET} + \end{titlepage} + +snippet verbatim +alias \begin{verbatim} verb \verbatim + \begin{verbatim} + ${1:TARGET} + \end{verbatim} + +snippet verbatimtab +alias \begin{verbatimtab} \verbatimtab + \begin{verbatimtab}[${1:8}] + ${2:TARGET} + \end{verbatim} + +snippet trivlist +alias \begin{trivlist} \trivlist + \begin{trivlist} + ${1:TARGET} + \end{trivlist} + +snippet verse +alias \begin{verse} \verse + \begin{verse} + ${1:TARGET} + \end{verse} + +snippet table +alias \begin{table} \table + \begin{table}[${1}] + \centering + \caption{${2}} + \label{${3}} + \begin{tabular}{${4}} + ${5} + \end{tabular} + \end{table} + +snippet thebibliography +alias \begin{thebibliography} \thebibliography + \begin{thebibliography} + ${1:TARGET} + \end{thebibliography} + +snippet tabbing +alias \begin{tabbing} \tabbing + \begin{tabbing} + ${1:TARGET} + \end{tabbing} + +snippet note +alias \begin{note} \note + \begin{note} + ${1:TARGET} + \end{note} + +snippet tabular +alias \begin{tabular} \tabular + \begin{tabular}{${1}} + ${2:TARGET} + \end{tabular} + +snippet overlay +alias \begin{overlay} \overlay + \begin{overlay} + ${1:TARGET} + \end{overlay} + +snippet array +alias \begin{array} \array + \begin{array}{${1}} + ${2:TARGET} + \end{array} + +snippet cases +alias \begin{cases} \cases + \begin{cases}{${1}} + ${2:TARGET} + \end{cases} + +snippet slide +alias \begin{slide} \slide + \begin{slide} + ${1:TARGET} + \end{slide} + +snippet displaymath +alias \begin{displaymath} \displaymath + \begin{displaymath} + ${1:TARGET} + \end{displaymath} + +snippet abstract +alias \begin{abstract} \abstract + \begin{abstract} + ${1:TARGET} + \end{abstract} + +snippet align +alias \begin{align} \align + \begin{align} + ${1:TARGET} + \end{align} + +snippet align* +alias \begin{align*} \align* + \begin{align*} + ${1:TARGET} + \end{align*} + +snippet aligned +alias \begin{aligned} \aligned + \begin{aligned} + ${1:TARGET} + \end{aligned} + +snippet eqnarray +alias \begin{eqnarray} \eqnarray + \begin{eqnarray} + ${1:TARGET} + \end{eqnarray} + +snippet eqnarray* +alias \begin{eqnarray*} \eqnarray* + \begin{eqnarray*} + ${1:TARGET} + \end{eqnarray*} + +snippet equation +alias \begin{equation} \equation + \begin{equation} + ${1:TARGET} + \end{equation} + +snippet equation* +alias \begin{equation*} \equation* + \begin{equation*} + ${1:TARGET} + \end{equation*} + +snippet center +alias \begin{center} \center + \begin{center} + ${1:TARGET} + \end{center} + +snippet document +alias \begin{document} \document + \begin{document} + ${1:TARGET} + \end{document} + +snippet figure +alias \begin{figure} \figure + \begin{figure}[${1}] + \centering + \includegraphics[${2:width=${3\}}]{${4}} + \caption{${5}} + \label{${6}} + \end{figure} + +snippet filecontents +alias \begin{filecontents} \filecontents + \begin{filecontents} + ${1:TARGET} + \end{filecontents} + +snippet lrbox +alias \begin{lrbox} \lrbox + \begin{lrbox} + ${1:TARGET} + \end{lrbox} + +snippet flushleft +alias \begin{flushleft} \flushleft + \begin{flushleft} + ${1:TARGET} + \end{flushleft} + +snippet flushright +alias \begin{flushright} \flushright + \begin{flushright} + ${1:TARGET} + \end{flushright} + +snippet minipage +alias \begin{minipage} \minipage + \begin{minipage} + ${1:TARGET} + \end{minipage} + +snippet picture +alias \begin{picture} \picture + \begin{picture} + ${1:TARGET} + \end{picture} + +snippet math +alias \begin{math} \math + \begin{math} + ${1:TARGET} + \end{math} + +snippet quote +alias \begin{quote} \quote + \begin{quote} + ${1:TARGET} + \end{quote} + +snippet matrix +alias \begin{matrix} \matrix + \begin{matrix} + ${1:TARGET} + \end{matrix} + +snippet bmatrix +alias \begin{bmatrix} \bmatrix + \begin{bmatrix} + ${1:TARGET} + \end{bmatrix} + +snippet pmatrix +alias \pegin{bmatrix} \pmatrix + \begin{pmatrix} + ${1:TARGET} + \end{pmatrix} + +snippet vmatrix +alias \begin{vmatrix} \vmatrix + \begin{vmatrix} + ${1:TARGET} + \end{vmatrix} + +snippet Bmatrix +alias \begin{Bmatrix} \Bmatrix + \begin{Bmatrix} + ${1:TARGET} + \end{Bmatrix} + +snippet Vmatrix +alias \begin{Vmatrix} \Vmatrix + \begin{Vmatrix} + ${1:TARGET} + \end{Vmatrix} + +# ========== SECTION ========== + +snippet \part +alias part \part{ + \part{${1}} + ${0:TARGET} + +snippet \chapter +alias chapter \chapter{ + \chapter{${1}} + ${0:TARGET} + +snippet \section +alias section \section{ + \section{${1}} + ${0:TARGET} + +snippet \subsection +alias subsection \subsection{ + \subsection{${1}} + ${0:TARGET} + +snippet \subsubsection +alias subsubsection \subsubsection{ + \subsubsection{${1}} + ${0:TARGET} + +snippet \paragraph +alias paragraph \paragraph{ + \paragraph{${1}} + ${0:TARGET} + +snippet \subparagraph +alias subparagraph \subparagraph{ + \subparagraph{${1}} + ${0:TARGET} + +# ========== MATH ========== + +snippet \frac +alias frac \frac{ + \frac{${1}}{${2}}${0} + +snippet \left +alias left +abbr \left \right + \left${1:(} ${3:#:body} \right${2:)}${0} + +# ========== FONT ========== + +snippet bfseries +alias \begin{bfseries} \bfseries + \begin{bfseries} + ${1:TARGET} + \end{bfseries} + +snippet mdseries +alias \begin{mdseries} \mdseries + \begin{mdseries} + ${1:TARGET} + \end{mdseries} + +snippet ttfamily +alias \begin{ttfamily} \ttfamily + \begin{ttfamily} + ${1:TARGET} + \end{ttfamily} + +snippet sffamily +alias \begin{sffamily} \sffamily + \begin{sffamily} + ${1:TARGET} + \end{sffamily} + +snippet rmfamily +alias \begin{rmfamily} \rmfamily + \begin{rmfamily} + ${1:TARGET} + \end{rmfamily} + +snippet upshape +alias \begin{upshape} \upshape + \begin{upshape} + ${1:TARGET} + \end{upshape} + +snippet slshape +alias \begin{slshape} \slshape + \begin{slshape} + ${1:TARGET} + \end{slshape} + +snippet scshape +alias \begin{scshape} \scshape + \begin{scshape} + ${1:TARGET} + \end{scshape} + +snippet itshape +alias \begin{itshape} \itshape + \begin{itshape} + ${1:TARGET} + \end{itshape} + +snippet \textbf +alias textbf \textbf{ + \textbf{${1:TARGET}}${0} + +snippet \textmd +alias textmd \textmd{ + \textmd{${1:TARGET}}${0} + +snippet \texttt +alias texttt \texttt{ + \texttt{${1:TARGET}}${0} + +snippet \textsf +alias textsf \textsf{ + \textsf{${1:TARGET}}${0} + +snippet \textrm +alias textrm \textrm{ + \textrm{${1:TARGET}}${0} + +snippet \textup +alias textup \textup{ + \textup{${1:TARGET}}${0} + +snippet \textsl +alias textsl \textsl{ + \textsl{${1:TARGET}}${0} + +snippet \textsc +alias textsc \textsc{ + \textsc{${1:TARGET}}${0} + +snippet \textit +alias textit \textit{ + \textit{${1:TARGET}}${0} + +# ==== BEAMER ==== +snippet frame +alias \begin{frame} \frame + \begin{frame}{${1:#:frametitle}} + ${2:TARGET} + \end{frame} + +snippet block +alias \begin{block} + \begin{block}{${1:#:title}} + ${2:TARGET} + \end{block} + +snippet exampleblock +alias \begin{exampleblock} + \begin{exampleblock}{${1:#:title}} + ${2:TARGET} + \end{exampleblock} + +snippet alertblock +alias \begin{alertblock} + \begin{alertblock}{${1:#:title}} + ${2:TARGET} + \end{alertblock} + +snippet columns +alias \begin{columns} \columns + \begin{columns} + \begin{column}{${1:#:width}${2:\\\textwidth}} + ${0:#:body} + \end{column} + \end{columns} + +snippet column +alias \begin{column} \column + \begin{column}{${1:#:width}${2:\\\textwidth}} + ${0:#:body} + \end{column} + +# ========== TikZ ========== +snippet tikzpicture +alias \begin{tikzpicture} + \begin{tikzpicture}[${1}] + ${2:TARGET} + \end{tikzpicture} + +snippet path +alias \path + \path[${1}] ${2};${0} + +snippet draw +alias \draw + \draw[${1}] ${2};${0} + +snippet fill +alias \fill + \fill[${1}] ${2};${0} + +snippet filldraw +alias \filldraw + \filldraw[${1}] ${2};${0} + +snippet shade +alias \shade + \shade[${1}] ${2};${0} + +snippet coordinate +alias \coordinate + \coordinate[${1}](${2:name}) ${3};${0} + +snippet node +alias \node + \node[${1}](${2:name}) ${3};${0} + +# ========== BibLaTeX ========== +snippet addbibresource +alias \addbibresource + \addbibresource{${1:resource}}${0} + +snippet cite +alias \cite + \cite{${1}}${0} + +snippet nocite +alias \nocite + \nocite{${1}}${0} + +snippet supercite +alias \supercite + \supercite{${1}}${0} + +snippet autocite +alias \autocite + \autocite{${1}}${0} + +snippet fullcite +alias \fullcite + \fullcite{${1}}${0} + +# ========== OTHERS ========== +snippet usepackage +alias \usepackage + \usepackage${1:[${2\}]}{${3}} + +snippet ref +alias \ref + \ref{${1}}${0} + +snippet label +alias \label + \label{${1}}${0} diff --git a/bundle/neosnippet-snippets/neosnippets/toml.snip b/bundle/neosnippet-snippets/neosnippets/toml.snip new file mode 100644 index 000000000..d1042dffc --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/toml.snip @@ -0,0 +1,6 @@ +snippet plugins +abbr [[plugins]] + [[plugins]] + repo = '`getreg('+')=='' ? '<\`0\`>' : getreg('+')`' + ${0} + diff --git a/bundle/neosnippet-snippets/neosnippets/twig.snip b/bundle/neosnippet-snippets/neosnippets/twig.snip new file mode 100644 index 000000000..c4241fe4e --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/twig.snip @@ -0,0 +1,159 @@ +snippet autoescape +abbr {% autoescape ... %} ... {% endautoescape %} +options head + {% autoescape ${1:#:strategy} %} + ${0:TARGET} + {% autoescape %} + +snippet block +abbr {% block ... %} ... {% endblock %} +alias bl +options head + {% block ${1:#:name} %} + ${0:TARGET} + {% endblock %} + +snippet dump +abbr
     {{ dump(...) }} 
    +options head +
    + 		{{ dump(${0:TARGET}) }}
    +    
    + +snippet embed +abbr {% embed ... %} ... {% endembed %} +options head + {% embed '${1:template}' %} + {% block ${2} %} + ${0:TARGET} + {% endblock %} + {% endembed %} + +snippet extends +abbr {% extends ... %} +alias ext +options head + {% extends '${1:#:template}' %} + +snippet filter +abbr {% filter ... %} ... {% endfilter %} +options head + {% filter ${1} %} + ${0:TARGET} + {% endfilter %} + +snippet flush +abbr {% flush %} +options head + {% flush %} + +snippet for +abbr {% for ... in ... %} ... {% endfor %} +options head + {% for ${1:#:value} in ${2:#:list} %} + ${0:TARGET} + {% endfor %} + +snippet from +abbr {% from '...' import ... %} +options head + {% from '${1:#:module}' import ${2:#:macro} %} + +snippet if +abbr {% if ... %} ... {% endif %} +options head + {% if ${1} %} + ${0:TARGET} + {% endif %} + +snippet elseif +abbr {% elseif ... %} ... +alias elif +options head + {% elseif ${1} %} + ${0:TARGET} + +snippet else +abbr {% else %} ... +options head + {% else %} + ${0:TARGET} + +snippet import +abbr {% import '...' as ... %} +options head + {% import '${1:#:module}' as ${2:#:namespace} %} + +snippet include +abbr {% include '...' %} +options head + {% include '${1:#:template}' %} + +snippet includewith +abbr {% include '...' %} +options head + {% include '${1:#:template}' with {${2:#:'key'}: ${2:#:'value'}} %} + +snippet macro +abbr {% macro ...(...) %} ... {% endmacro %} +options head + {% macro ${1:#:name}(${2:#:args}) %} + ${0:TARGET} + {% endmacro %} + +snippet sandbox +abbr {% sandbox %} ... {% endsandbox %} +options head + {% sandbox %} + ${0:TARGET} + {% endsandbox %} + +snippet set +abbr {% set ... = ... %} +options head + {% set ${1:#:var} = ${2:#:value} %} + +snippet setblock +abbr {% set ... %} ... {% endset %} +options head + {% set ${1:#:var} %} + ${0:TARGET} + {% endset %} + +snippet spaceless +abbr {% spaceless %} ... {% endspaceless %} +options head + {% spaceless %} + ${0:TARGET} + {% endspaceless %} + +snippet use +abbr {% use '...' %} +options head + {% use '${1:#:template}' %} + +snippet verbatim +abbr {% verbatim %} ... {% endverbatim %} +options head + {% verbatim %} + ${0:TARGET} + {% endverbatim %} + +snippet comment +abbr {# ... #} +alias # +options head + {# ${1:comment} #} + +snippet tag +abbr {% ... %} +alias % +options head + {% ${1:#:tag} %} + +snippet tagblock +abbr {% ... %} ... {% end... %} +options head + {% ${1:#:tag} ${2:#:name} %} + ${0:TARGET} + {% end$1 %} diff --git a/bundle/neosnippet-snippets/neosnippets/typescript.snip b/bundle/neosnippet-snippets/neosnippets/typescript.snip new file mode 100644 index 000000000..d138bd649 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/typescript.snip @@ -0,0 +1,79 @@ +include javascript.snip + +snippet var-with-type +abbr var NAME: TYPE = expr; +options head + var ${1:#:NAME}: ${2:#:TYPE} = ${0:#:TARGET}; + +snippet class +abbr class NAME {...} +options word + class ${1:#:NAME} { + constructor(${2:#:Args}) { + ${3:#:TARGET} + } + + ${0:#:TARGET} + } + +snippet method +options head + ${1:#:NAME}(${2:#:Args}): ${3:#:TYPE} { + ${0:#:TARGET} + } + +snippet accessor +options head + get ${1:#:NAME}(): ${2:#:TYPE} { + ${3:#:TARGET} + } + + set $1(${4:value}: $2) { + ${0:#:TARGET} + } + +snippet static +abbr static f(){} +options head + static ${1:#:NAME}(${2:#:Args}) { + ${0:#:TARGET} + } + +snippet interface +abbr interface NAME {...} +options word + interface ${1:#:NAME} { + ${0:#:TARGET} + } + +snippet enum +abbr enum NAME {...} +options head + enum ${1:#:NAME} { + ${0:#:TARGET} + } + +snippet module +abbr module NAME {...} +options head + module ${1:#:NAME} { + ${0:#:TARGET} + } + +snippet namespace +abbr namespace NAME {...} +options head + namespace ${1:#:NAME} { + ${0:#:TARGET} + } + +snippet reference +abbr /// +options head + /// + +snippet function-arrow +alias arrow-function +abbr () => {} +options word + (${1:#:Args}) => { ${0:#:TARGET} } diff --git a/bundle/neosnippet-snippets/neosnippets/typescriptreact.snip b/bundle/neosnippet-snippets/neosnippets/typescriptreact.snip new file mode 100644 index 000000000..f7472b80c --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/typescriptreact.snip @@ -0,0 +1 @@ +include typescript.snip diff --git a/bundle/neosnippet-snippets/neosnippets/verilog.snip b/bundle/neosnippet-snippets/neosnippets/verilog.snip new file mode 100644 index 000000000..b83aba6c3 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/verilog.snip @@ -0,0 +1,158 @@ +snippet al +abbr always @() + always @(${1:*})${2:TARGET} + +snippet alclk +abbr always @(posedge clk) + always @(posedge clk${1})${2:TARGET} + +snippet beginend +alias be +abbr begin ... end + begin + ${1:TARGET} + end + +snippet module +alias mod +abbr module () ... endmodule + module ${1:`expand("%:r")`}( + ${2:TARGET} + ); + endmodule + +snippet rw +abbr reg [] _r, _w; + reg${1:#: nbit} ${2:reg}_r, $2_w;${3:TARGET} + +snippet I +abbr input [] i_, + input${1:#: nbit} i_${2:name}, + +snippet O +abbr output [] o_, + output${1:#: nbit} o_${2:name}, + +snippet IO +abbr inout [] io_, + inout${1:#: nbit} io_${2:name}, + +snippet regmemory +alias regm +abbr reg [] name [] + reg [${1}:${2:0}] ${3:name} [${4:0}:${5}];${6:TARGET} + +snippet regseq +abbr _r <= _w; + ${1:reg}_r <= $1_w;${2:TARGET} + +snippet regkeep +abbr _w = _r + ${1:reg}_w = $1_r;${2:TARGET} + +snippet assign +alias as +abbr assign ... = ... + assign ${1:#:name} = ${2:#:val};${3:TARGET} + +snippet parameter +alias pa +abbr parameter ... = ... + parameter ${1:#:name} = ${2:#:val};${3:TARGET} + +snippet localparam +alias lpa +abbr localparam ... = ... + localparam ${1:#:name} = ${2:#:val};${3:TARGET} + +snippet if +abbr if() + if (${1:#:condition})${0:TARGET} + +snippet else +alias el +abbr else + else${0:TARGET} + +snippet elseif +abbr else if () + else if (${1:#:condition})${0:TARGET} + +snippet initial +alias init +abbr initial begin ... end + initial begin + ${0:TARGET} + end + +snippet for +abbr for () begin ... end + for (${1:i} = ${2}; $1 < ${3}; ${4:$1 = $1 + 1})${0:TARGET} + +snippet while +abbr while () begin ... end + while (${1:#:condition})${0:TARGET} + +snippet case +abbr case () ... endcase + case (${1}) + ${2:'b0}: begin + ${3} + end + default : begin + ${4} + end + endcase + +snippet function +alias func +abbr function ... endfunction + function${1:# nbit} ${1:func_name}; + ${2:portlist}; + begin + ${0:TARGET}; + end + endfunction + +snippet inc +alias `inc, `include +abbr `include "..." + \`include "${1}"${0} + +snippet def +alias `def, `define +abbr `define ... ... + \`define ${1} ${2} + +snippet default_nettype +alias dn, defn + \`default_nettype ${1:none}${0} + +snippet timescale +alias ts, `time, `timescale +abbr `timescale 1ns/100ps + \`timescale ${1:1ns}/${2:100ps}${0} + +snippet ternary +alias ter +abbr () ? a : b + (${1:#:condition}) ? ${2:#:a} : ${3:#:b} + +snippet dumpfile +alias df +abbr $dumpfile("....vcd"); + $dumpfile("${1:`expand("%:r")`}.vcd");${0} + +snippet dumpvars +alias dv +abbr $dumpvars(0, ...); + $dumpvars(${1:0}, ${2:`expand("%:r")`});${0} + +snippet display +abbr $display("...", ...); + $display("${1}", ${2}); + +snippet strobe +abbr $strobe("...", ...); + $strobe("${1}", ${2}); + diff --git a/bundle/neosnippet-snippets/neosnippets/vim.snip b/bundle/neosnippet-snippets/neosnippets/vim.snip new file mode 100644 index 000000000..2c1d10684 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/vim.snip @@ -0,0 +1,224 @@ +snippet if +abbr if endif +options head + if ${1:#:condition} + ${0:TARGET} + endif + +snippet elseif +options head + elseif ${1:#:condition} + ${0:TARGET} + +snippet ifelse +abbr if else endif +options head + if ${1:#:condition} + ${2:TARGET} + else + ${3} + endif + +snippet for +abbr for in endfor +options head + for ${1:#:var} in ${2:#:list} + ${0:TARGET} + endfor + +snippet while +abbr while endwhile +options head + while ${1:#:condition} + ${0:TARGET} + endwhile + +snippet function +abbr func endfunc +alias func +options head + function! ${1:#:func_name}(${2}) abort + ${0:TARGET} + endfunction + +snippet try +abbr try endtry +options head + try + ${1:TARGET} + catch /${2:#:pattern}/ + ${3} + endtry + +snippet tryfinally +abbr try ... finally ... endtry +alias tryf +options head + try + ${1:TARGET} + finally + ${2} + endtry + +snippet catch +abbr catch /pattern/ +options head + catch ${1:/${2:#:pattern: empty, E484, Vim(cmdname):{errmsg\\}\}/} + +snippet echomsg +alias log +options head + echomsg string(${1:TARGET}) + +snippet command +abbr command call function +options head + command! ${1:#:command_name} call ${2:#:func_name} + +snippet customlist +abbr customlist complete function +options head + function! ${1:#:func_name}(arglead, cmdline, cursorpos) abort + return filter(${2:#:list}, 'stridx(v:val, a:arglead) == 0') + endfunction + +snippet augroup +abbr augroup with autocmds +options head + augroup ${1:#:augroup_name} + autocmd! + autocmd ${2:#:event} + augroup END + +snippet redir +abbr redir => var +options head + redir => ${1:#:var} + ${2::TARGET} + redir END + +snippet NeoBundle +alias neobundle +abbr NeoBundle '' + NeoBundle '`getreg('+')=='' ? '<\`0\`>' : getreg('+')`'${0} + +snippet NeoBundleLazy +alias neobundlelazy +abbr NeoBundleLazy '' + NeoBundleLazy '`getreg('+')=='' ? '<\`0\`>' : getreg('+')`', { + \ ${0} + \ } + +snippet bundle_hooks +abbr neobundle hooks + let s:hooks = neobundle#get_hooks('${1}') + function! s:hooks.on_source(bundle) abort + ${0} + endfunction + unlet s:hooks + +snippet autoload +abbr autoload func endfunc +alias afunction afunc +options head + function! `substitute(matchstr(neosnippet#util#expand('%:p:r'), '/autoload/\zs.*$'), '/', '#', 'g')`#${1:#:func_name}(${2:#:args}) abort + ${0} + endfunction + +snippet g:loaded +abbr if exists('g:loaded_{plugin-name}') +alias loaded +options head + if exists('g:loaded_${1}') + finish + endif + + ${0} + + let g:loaded_$1 = 1 + +snippet modeline +abbr " vim: {modeline} + " vim: ${0:foldmethod=marker} + +snippet undo_ftplugin +abbr if !exists('b:undo_ftplugin') +alias b:undo_ftplugin + if !exists('b:undo_ftplugin') + let b:undo_ftplugin = '' + endif + + ${1} + + let b:undo_ftplugin .= ' + \ | setlocal ${2:#:option_name1< option_name2<...} + \' + +snippet python +alias py +options head +abbr python < ${1} || (v:version == $1 && has('patch${2}')) + +snippet version_new +abbr vim-version-check-new + has('patch-${1}') + diff --git a/bundle/neosnippet-snippets/neosnippets/vim/vital.snip b/bundle/neosnippet-snippets/neosnippets/vim/vital.snip new file mode 100644 index 000000000..33e20b9bc --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/vim/vital.snip @@ -0,0 +1,35 @@ +snippet vital_new_without_let +abbr vital#...#new() + vital#${1:#:plugin_name}#new() + +snippet vital_new +abbr let s:V = vital#...#new() +options head + let ${1:s:V} = vital#${2:#:plugin_name}#new() + +snippet vital_import_without_let +abbr s:V.import('...') + ${1:s:V}.import('${2:#:module_name}') + +snippet vital_import +abbr let s:M = s:V.import('...') +options head + let ${1:s:M} = ${2:s:V}.import('${3:#:module_name}') + +snippet vital_load_without_call +abbr s:V.load('...') + ${1:s:V}.load('${2:#:module_name}') + +snippet vital_load +abbr call s:V.load('...') +options head + call ${1:s:V}.load('${2:#:module_name}') + +# FAQ +# Q. Why does this snip file has verbose prefix "vital_" for everything? +# A. Because it's vital.vim specific but this snip is available in any vim +# filetype buffers. +# +# Q. Why didn't provide X/X_with_Y instead of X_without_Y/X? +# A. To show what is encouraged. Programmers usually assume that they should +# always use shorter name of functions, so this snip followed the convention. diff --git a/bundle/neosnippet-snippets/neosnippets/vimshell.snip b/bundle/neosnippet-snippets/neosnippets/vimshell.snip new file mode 100644 index 000000000..6a93c921e --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/vimshell.snip @@ -0,0 +1,4 @@ +snippet sl +abbr => ls? + ls + diff --git a/bundle/neosnippet-snippets/neosnippets/vimspec.snip b/bundle/neosnippet-snippets/neosnippets/vimspec.snip new file mode 100644 index 000000000..b6fb19221 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/vimspec.snip @@ -0,0 +1,13 @@ +include vim.snip + +snippet suite +options head + function! s:suite.${1}() + ${2:TARGET} + call s:assert.equal(${3:expected}, ${4:actual}) + endfunction + +snippet themis#log (This is an undocumented function) +abbr p +options head + call themis#log(${TARGET}) diff --git a/bundle/neosnippet-snippets/neosnippets/vimwiki.snip b/bundle/neosnippet-snippets/neosnippets/vimwiki.snip new file mode 100644 index 000000000..a42d8ad2c --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/vimwiki.snip @@ -0,0 +1,59 @@ + +snippet bold +abbr *text* +options head + *${1}*${2} + +snippet scratch +abbr ~~scratch~~ +options head + ~~${1}~~${2} + +snippet italic +abbr _italic_ +options head + _${1}_${2} + +snippet sub +abbr ,,sub,, +options head + ,,${1},,${2} + +snippet upper +abbr ^upper^ +options head + ^${1}^${2} + +snippet image_local +abbr {{}} +options head + {{local:${1:image_path}}}${2} + +snippet image +abbr {{}} +options head + {{http://${1:image_url}}}${2} + +snippet table +abbr table template +options head + |${1:title}|${2:title}| + |---|---| + |${3:value}|${4:value}${5:TARGET}| + +snippet definintion +abbr definition +options head + term:: ${1:definintion} + +snippet tag +abbr :tag1:tag2: +options head + :${1:tag}:${3} + +snippet code +abbr {{{}}} +options head + {{{ + ${0:TARGET} + }}} diff --git a/bundle/neosnippet-snippets/neosnippets/vue.snip b/bundle/neosnippet-snippets/neosnippets/vue.snip new file mode 100644 index 000000000..9666c9161 --- /dev/null +++ b/bundle/neosnippet-snippets/neosnippets/vue.snip @@ -0,0 +1,132 @@ +snippet scaffold +options head +abbr Scaffold