1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 07:00:04 +08:00

Add bundle dir (#3542)

This commit is contained in:
Wang Shidong 2020-06-13 14:06:35 +08:00 committed by GitHub
parent 06c7cc740a
commit aebee1b28b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1822 changed files with 248506 additions and 86 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ doc/tags-cn
wiki/.git
*.class
.floo
*.pyc
.flooignore
*.netrwhist
*-rplugin~

View File

@ -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
```

View File

@ -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

View File

@ -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'}],

View File

@ -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

View File

@ -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

View File

@ -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' : '<Plug>(wildfire-'}],
\ ['easymotion/vim-easymotion'],
\ ['haya14busa/vim-easyoperator-line'],
\ ['editorconfig/editorconfig-vim', { 'merged' : 0, 'if' : has('python') || has('python3')}],
\ ['osyo-manga/vim-jplus', { 'on_map' : '<Plug>(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' : '<Plug>(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' : '<Plug>(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

View File

@ -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

View File

@ -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

View File

@ -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)
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
function! SpaceVim#plugins#begin(path) abort
let g:unite_source_menu_menus.AddedPlugins =

View File

@ -417,6 +417,7 @@ endfunction
function! s:pull(repo) abort
let s:pct += 1
let s:ui_buf[a:repo.name] = s:pct
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,{
@ -440,6 +441,9 @@ function! s:pull(repo) abort
\ })
endif
else
call s:msg_on_local(a:repo.name)
endif
endfunction
function! s:get_uri(repo) abort
@ -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

11
bundle/README.md Normal file
View File

@ -0,0 +1,11 @@
## Forked repos
### checkers layer
- neomake
- vim-snippets
- neco-syntax
- context_filetype.vim
- neoinclude.vim
- neosnippet-snippets
- neopairs.vim

View File

@ -0,0 +1,8 @@
coverage:
status:
project:
default:
target: 0%
patch:
default:
target: 0%

View File

@ -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

4
bundle/clever-f.vim/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/doc/tags
/test/profile.txt
/test/htmlcov
/test/.coverage_covimerage

View File

@ -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 `<Plug>(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
`<CR>` is easy to type but usually it isn't input as the target character of search. So by default,
when you input `<CR>` as `{char}`, the previous input is used instead of `<CR>`. For example, when
you previously input `fa` and then input `f<CR>`, `a` will be used as input instead of `<CR>`.
You can specify characters to use previous input by setting `g:clever_f_repeat_last_char_inputs`.
Adding `<Tab>` 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 ; <Plug>(clever-f-repeat-forward)
map , <Plug>(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/

View File

@ -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', ["\<CR>"])
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("\<Esc>")
return "\<Esc>"
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 ==# "\<C-v>" ||
\ mode ==# 'ce' || mode ==? 's' || mode ==# "\<C-s>"
augroup plugin-clever-f-finalizer
autocmd CursorMoved <buffer> call s:maybe_finalize()
autocmd InsertEnter <buffer> 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 \<Left>
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] ==# "\<C-v>"
let cmd = s:move_cmd_for_visualmode(pmap, prev_char_num)
else
let inclusive = mode ==# 'no' && pmap =~# '\l'
let cmd = printf("%s:\<C-u>call clever_f#find(%s, %s)\<CR>",
\ 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

View File

@ -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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,274 @@
*clever-f.txt* Make |f|, |F|, |t| and |T| cleverer.
Author : rhysd <lin90162@yahoo.co.jp>
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 |<Plug>(clever-f-f)|, |<Plug>(clever-f-F)|,
|<Plug>(clever-f-t)| and |<Plug>(clever-f-T)| as default mappings.
<Plug>(clever-f-f) *<Plug>(clever-f-f)*
<Plug>(clever-f-F) *<Plug>(clever-f-F)*
<Plug>(clever-f-t) *<Plug>(clever-f-t)*
<Plug>(clever-f-T) *<Plug>(clever-f-T)*
<Plug>(clever-f-reset) *<Plug>(clever-f-reset)*
<Plug>(clever-f-repeat-forward) *<Plug>(clever-f-repeat-forward)*
<Plug>(clever-f-repeat-back) *<Plug>(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 ["\<CR>"]. It means that previous input is used when
you input <CR>. For example, when you previously input "fa" and then
input "f<CR>", "a" will be used instead of "<CR>".
If you want to add <Tab> to the element, please write below in your vimrc.
>
let g:clever_f_repeat_last_char_inputs = ["\<CR>", "\<Tab>"]
<
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*
|<Plug>(clever-f-t)|, |<Plug>(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:

View File

@ -0,0 +1,28 @@
if exists('g:loaded_clever_f') && g:loaded_clever_f
finish
endif
noremap <silent><expr><Plug>(clever-f-f) clever_f#find_with('f')
noremap <silent><expr><Plug>(clever-f-F) clever_f#find_with('F')
noremap <silent><expr><Plug>(clever-f-t) clever_f#find_with('t')
noremap <silent><expr><Plug>(clever-f-T) clever_f#find_with('T')
noremap <silent><expr><Plug>(clever-f-reset) clever_f#reset()
noremap <silent><expr><Plug>(clever-f-repeat-forward) clever_f#repeat(0)
noremap <silent><expr><Plug>(clever-f-repeat-back) clever_f#repeat(1)
if ! exists('g:clever_f_not_overwrites_standard_mappings')
nmap f <Plug>(clever-f-f)
xmap f <Plug>(clever-f-f)
omap f <Plug>(clever-f-f)
nmap F <Plug>(clever-f-F)
xmap F <Plug>(clever-f-F)
omap F <Plug>(clever-f-F)
nmap t <Plug>(clever-f-t)
xmap t <Plug>(clever-f-t)
omap t <Plug>(clever-f-t)
nmap T <Plug>(clever-f-T)
xmap T <Plug>(clever-f-T)
omap T <Plug>(clever-f-T)
endif
let g:loaded_clever_f = 1

View File

@ -0,0 +1,3 @@
[run]
plugins = covimerage
data_file = .coverage_covimerage

View File

@ -0,0 +1,15 @@
let g:repo_root = fnamemodify(expand('<sfile>'), ':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))

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
License: MIT license
AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
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.

View File

@ -0,0 +1,679 @@
"=============================================================================
" FILE: context_filetype.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" 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':
\ '<script\%( [^>]*\)\? type="text/javascript"\%( [^>]*\)\?>',
\ 'end': '</script>', 'filetype': 'javascript',
\ },
\ {
\ 'start':
\ '<script\%( [^>]*\)\? type="text/coffeescript"\%( [^>]*\)\?>',
\ 'end': '</script>', 'filetype': 'coffee',
\ },
\ {
\ 'start':
\ '<script\%( [^>]*\)\?>',
\ 'end': '</script>', 'filetype': 'javascript',
\ },
\ {
\ 'start':
\ '<style\%( [^>]*\)\?>',
\ 'end': '</style>', 'filetype': 'css',
\ },
\ {
\ 'start':
\ '<[^>]\+ style=\([''"]\)',
\ 'end': '\1', 'filetype': 'css',
\ },
\ ],
\ 'vue': [
\ {
\ 'start':
\ '<template\%( [^>]*\)\? \%(lang="\%(\(\h\w*\)\)"\)\%( [^>]*\)\?>',
\ 'end': '</template>', 'filetype': '\1',
\ },
\ {
\ 'start':
\ '<template\%( [^>]*\)\?>',
\ 'end': '</template>', 'filetype': 'html',
\ },
\ {
\ 'start':
\ '<script\%( [^>]*\)\? \%(ts\|lang="\%(ts\|typescript\)"\)\%( [^>]*\)\?>',
\ 'end': '</script>', 'filetype': 'typescript',
\ },
\ {
\ 'start':
\ '<script\%( [^>]*\)\? \%(lang="\%(\(\h\w*\)\)"\)\%( [^>]*\)\?>',
\ 'end': '</script>', 'filetype': '\1',
\ },
\ {
\ 'start':
\ '<script\%( [^>]*\)\?>',
\ 'end': '</script>', 'filetype': 'javascript',
\ },
\ {
\ 'start':
\ '<style\%( [^>]*\)\? \%(lang="\%(\(\h\w*\)\)"\)\%( [^>]*\)\?>',
\ 'end': '</style>', 'filetype': '\1',
\ },
\ {
\ 'start':
\ '<style\%( [^>]*\)\?>',
\ 'end': '</style>', 'filetype': 'css',
\ },
\ {
\ 'start':
\ '<\(\h\w*\)>',
\ 'end': '</\1>', 'filetype': 'vue-\1',
\ },
\ {
\ 'start':
\ '<\(\h\w*\) \%(lang="\%(\(\h\w*\)\)"\)\%( [^>]*\)\?>',
\ 'end': '</\1>', 'filetype': '\2',
\ },
\ ],
\ 'int-nyaos': [
\ {
\ 'start': '\<lua_e\s\+\(["'']\)',
\ 'end': '\1\@<!\1\1\@!', 'filetype': 'lua',
\ },
\ ],
\ 'lua': [
\ {
\ 'start': 'vim.command\s*(\([''"]\)',
\ 'end': '\\\@<!\1', 'filetype': 'vim',
\ },
\ {
\ 'start': 'vim.eval\s*(\([''"]\)',
\ 'end': '\\\@<!\1', 'filetype': 'vim',
\ },
\ ],
\ 'nyaos': [
\ {
\ 'start': '\<lua_e\s\+\(["'']\)',
\ 'end': '\1\@<!\1\1\@!', 'filetype': 'lua',
\ },
\ ],
\ 'perl6': [
\ {
\ 'start': 'Q:PIR\s*{',
\ 'end': '}', 'filetype': 'pir',
\ },
\ ],
\ 'python': [
\ {
\ 'start': 'vim.command\s*(\([''"]\)',
\ 'end': '\\\@<!\1', 'filetype': 'vim',
\ },
\ {
\ 'start': 'vim.eval\s*(\([''"]\)',
\ 'end': '\\\@<!\1', 'filetype': 'vim',
\ },
\ {
\ 'start': 'vim.call\s*(\([''"]\)',
\ 'end': '\\\@<!\1', 'filetype': 'vim',
\ },
\ ],
\ 'vim': [
\ {
\ 'start': '^\s*pe\%[rl\] <<\s*\(\h\w*\)',
\ 'end': '^\1', 'filetype': 'perl',
\ },
\ {
\ 'start': '^\s*py\%[thon\]3\? <<\s*\(\h\w*\)',
\ 'end': '^\1', 'filetype': 'python',
\ },
\ {
\ 'start': '^\s*rub\%[y\] <<\s*\(\h\w*\)',
\ 'end': '^\1', 'filetype': 'ruby',
\ },
\ {
\ 'start': '^\s*lua <<\s*\(\h\w*\)',
\ 'end': '^\1', 'filetype': 'lua',
\ },
\ {
\ 'start': '^\s*lua ',
\ 'end': '\n\|\s\+|', 'filetype': 'lua',
\ },
\ ],
\ 'vimperator': [
\ {
\ 'start': '^\s*\%(javascript\|js\)\s\+<<\s*\(\h\w*\)',
\ 'end': '^\1', 'filetype': 'javascript',
\ }
\ ],
\ 'vimshell': [
\ {
\ 'start': 'vexe \([''"]\)',
\ 'end': '\\\@<!\1', 'filetype': 'vim',
\ },
\ {
\ 'start': ' :\w*',
\ 'end': '\n', 'filetype': 'vim',
\ },
\ {
\ 'start': ' vexe\s\+',
\ 'end': '\n', 'filetype': 'vim',
\ },
\ ],
\ 'xhtml': [
\ {
\ 'start':
\ '<script\%( [^>]*\)\? type="text/javascript"\%( [^>]*\)\?>',
\ 'end': '</script>', 'filetype': 'javascript',
\ },
\ {
\ 'start':
\ '<script\%( [^>]*\)\? type="text/coffeescript"\%( [^>]*\)\?>',
\ 'end': '</script>', 'filetype': 'coffee',
\ },
\ {
\ 'start': '<style\%( [^>]*\)\? type="text/css"\%( [^>]*\)\?>',
\ 'end': '</style>', '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': '\<hook_\%('.
\ 'add\|source\|post_source\|post_update'.
\ '\)\s*=\s*\('."'''".'\|"""\)',
\ 'end': '\1', 'filetype': 'vim',
\ },
\ ],
\ 'go': [
\ {
\ 'start': '^\s*\%(//\s*\)\?#\s*include\s\+',
\ 'end': '$', 'filetype': 'c',
\ },
\ ],
\ 'asciidoc': [
\ {
\ 'start' : '^\[source\%(%[^,]*\)\?,\(\h\w*\)\(,.*\)\?\]\s*\n----\s*\n',
\ 'end' : '^----\s*$', 'filetype' : '\1',
\ },
\ {
\ 'start' : '^\[source\%(%[^,]*\)\?,\(\h\w*\)\(,.*\)\?\]\s*\n',
\ 'end' : '^$', 'filetype' : '\1',
\ },
\ ],
\ 'review': [
\ {
\ 'start': '^//list\[[^]]\+\]\[[^]]\+\]\[\([^]]\+\)\]{',
\ 'end': '^//}', 'filetype' : '\1',
\ },
\ ],
\ 'javascript': [
\ {
\ 'synname_pattern': '^jsx',
\ 'filetype' : 'jsx',
\ },
\ {
\ 'start': '^\s*{/\*',
\ 'end': '\*/}', 'filetype' : 'jsx',
\ },
\ ],
\ 'typescript': [
\ {
\ 'synname_pattern': '^jsx',
\ 'filetype' : 'tsx',
\ },
\ {
\ 'start': '^\s*{/\*',
\ 'end': '\*/}', 'filetype' : 'tsx',
\ },
\ ],
\}
" s:default_same_filetypes {{{
let s:default_same_filetypes = {
\ 'cpp': 'c',
\ 'erb': 'ruby,html,xhtml',
\ 'html': 'xhtml',
\ 'xml': 'xhtml',
\ 'xhtml': 'html,xml',
\ 'htmldjango': 'html',
\ 'css': 'scss',
\ 'scss': 'css',
\ 'stylus': 'css',
\ 'less': 'css',
\ 'tex': 'bib,plaintex',
\ 'plaintex': 'bib,tex',
\ 'lingr-say': 'lingr-messages,lingr-members',
\ 'J6uil_say': 'J6uil',
\ 'vimconsole': 'vim',
\
\ 'int-irb': 'ruby',
\ 'int-ghci': 'haskell',
\ 'int-hugs': 'haskell',
\ 'int-python': 'python',
\ 'int-python3': 'python',
\ 'int-ipython': 'python',
\ 'int-ipython3': 'python',
\ 'int-gosh': 'scheme',
\ 'int-clisp': 'lisp',
\ 'int-erl': 'erlang',
\ 'int-zsh': 'zsh',
\ 'int-bash': 'bash',
\ 'int-sh': 'sh',
\ 'int-cmdproxy': 'dosbatch',
\ 'int-powershell': 'powershell',
\ 'int-perlsh': 'perl',
\ 'int-perl6': 'perl6',
\ 'int-ocaml': 'ocaml',
\ 'int-clj': 'clojure',
\ 'int-lein': 'clojure',
\ 'int-sml': 'sml',
\ 'int-smlsharp': 'sml',
\ 'int-js': 'javascript',
\ 'int-kjs': 'javascript',
\ 'int-rhino': 'javascript',
\ 'int-coffee': 'coffee',
\ 'int-gdb': 'gdb',
\ 'int-scala': 'scala',
\ 'int-nyaos': 'nyaos',
\ 'int-php': 'php',
\}
function! s:get_same_filetypes(filetype) abort
let same_filetypes = extend(copy(s:default_same_filetypes),
\ g:context_filetype#same_filetypes)
return split(get(same_filetypes, a:filetype,
\ get(same_filetypes, '_', '')), ',')
endfunction
function! s:stopline_forward() abort
let stopline_forward = line('.') + g:context_filetype#search_offset
return (stopline_forward > 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

View File

@ -0,0 +1,232 @@
*context_filetype.txt* Vim script の context filetype ライブラリ
Version: 1.0
Author : Shougo <Shougo.Matsu at gmail.com>
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:

View File

@ -0,0 +1,140 @@
*context_filetype.txt* Context filetype library for Vim script
Version: 1.0
Author : Shougo <Shougo.Matsu at gmail.com>
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:

View File

@ -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('<cword>')
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"))

View File

@ -0,0 +1,57 @@
<script type="text/javascript">`javascript`
`javascript`
`javascript`
</script>
<script>`javascript`
`javascript`
`javascript`
</script>
<script charset="utf-8">`javascript`
`javascript`
`javascript`
</script>
<script type="text/template">`html`
`html`
`html`
</script>
<script type="text/coffeescript">`coffee`
`coffee`
`coffee`
</script>
<style type="text/css">`css`
`css`
`css`
</style>

View File

@ -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
<script type="text/javascript">`javascript`
`javascript`
`javascript`
`javascript`</script>
```
```cpp
`cpp`
```
```text
`text`本日は晴天なり`text`
```
`markdown`

View File

@ -0,0 +1,13 @@
`nyaos`
lua_e "
`lua`
" `nyaos`
lua_e "`lua`" `nyaos`
lua_e "
print(""`lua`"")
" `nyaos`

View File

@ -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`

21
bundle/defx-git/LICENSE Normal file
View File

@ -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.

109
bundle/defx-git/README.md Normal file
View File

@ -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:
* `<Plug>(defx-git-next)` - Goes to the next file that has a git status
* `<Plug>(defx-git-prev)` - Goes to the previous file that has a git status
* `<Plug>(defx-git-stage)` - Stages the file/directory under cursor
* `<Plug>(defx-git-reset)` - Unstages the file/directory under cursor
* `<Plug>(defx-git-discard)` - Discards all changes to file/directory under cursor
If these are not manually mapped by the user, defaults are:
```viml
nnoremap <buffer><silent> [c <Plug>(defx-git-prev)
nnoremap <buffer><silent> ]c <Plug>(defx-git-next)
nnoremap <buffer><silent> ]a <Plug>(defx-git-stage)
nnoremap <buffer><silent> ]r <Plug>(defx-git-reset)
nnoremap <buffer><silent> ]d <Plug>(defx-git-discard)
```

View File

@ -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 <buffer><silent><Plug>(defx-git-next) :<C-u>call <sid>search(1)<CR>
nnoremap <buffer><silent><Plug>(defx-git-prev) :<C-u>call <sid>search(-1)<CR>
nnoremap <buffer><silent><Plug>(defx-git-stage) :<C-u>call <sid>git_cmd('stage')<CR>
nnoremap <buffer><silent><Plug>(defx-git-reset) :<C-u>call <sid>git_cmd('reset')<CR>
nnoremap <buffer><silent><Plug>(defx-git-discard) :<C-u>call <sid>git_cmd('discard')<CR>
if !hasmapto('<Plug>(defx-git-prev)') && maparg('[c', 'n') ==? ''
silent! nmap <buffer><unique><silent> [c <Plug>(defx-git-prev)
endif
if !hasmapto('<Plug>(defx-git-next)') && maparg(']c', 'n') ==? ''
silent! nmap <buffer><unique><silent> ]c <Plug>(defx-git-next)
endif
if !hasmapto('<Plug>(defx-git-stage)') && maparg(']a', 'n') ==? ''
silent! nmap <buffer><unique><silent> ]a <Plug>(defx-git-stage)
endif
if !hasmapto('<Plug>(defx-git-reset)') && maparg(']r', 'n') ==? ''
silent! nmap <buffer><unique><silent> ]r <Plug>(defx-git-reset)
endif
if !hasmapto('<Plug>(defx-git-discard)') && maparg(']d', 'n') ==? ''
silent! nmap <buffer><unique><silent> ]d <Plug>(defx-git-discard)
endif

View File

@ -0,0 +1,225 @@
# ============================================================================
# FILE: git.py
# AUTHOR: Kristijan Husak <husakkristijan at gmail.com>
# 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')

21
bundle/defx-icons/LICENSE Normal file
View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,137 @@
# ============================================================================
# FILE: icons.py
# AUTHOR: Kristijan Husak <husakkristijan at gmail.com>
# 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

View File

@ -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

6
bundle/defx.nvim/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*.py[cod]
doc/tags
vim-themis
.cache
.mypy_cache/
.pytest_cache/

View File

@ -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

21
bundle/defx.nvim/LICENSE Normal file
View File

@ -0,0 +1,21 @@
License: MIT license
AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
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.

31
bundle/defx.nvim/Makefile Normal file
View File

@ -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

117
bundle/defx.nvim/README.md Normal file
View File

@ -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)

View File

@ -0,0 +1,83 @@
"=============================================================================
" FILE: defx.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" 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(":\<C-u>call defx#call_action(%s, %s)\<CR>",
\ 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(":\<C-u>call defx#call_async_action(%s, %s)\<CR>",
\ 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

View File

@ -0,0 +1,62 @@
"=============================================================================
" FILE: custom.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" 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

View File

@ -0,0 +1,211 @@
"=============================================================================
" FILE: exrename.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" EDITOR: Alisue <lambdalisue at hashnote.net>
" 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 <buffer><silent> q :<C-u>call <SID>exit(bufnr('%'))<CR>
augroup defx-exrename
autocmd! * <buffer>
autocmd BufHidden <buffer> call s:exit(expand('<abuf>'))
autocmd BufWriteCmd <buffer> call s:do_rename()
autocmd CursorMoved,CursorMovedI <buffer> 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

View File

@ -0,0 +1,143 @@
"=============================================================================
" FILE: init.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" 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

View File

@ -0,0 +1,325 @@
"=============================================================================
" FILE: util.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" 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 =~# '\\\@<!`.*\\\@<!`') ?
\ s:eval_cmdline(a:cmdline) : a:cmdline
for s in split(cmdline, s:re_unquoted_match('\%(\\\@<!\s\)\+'))
let arg = substitute(s, '\\\( \)', '\1', 'g')
let arg_key = substitute(arg, '=\zs.*$', '', '')
let name = substitute(tr(arg_key, '-', '_'), '=$', '', '')[1:]
if name =~# '^no_'
let name = name[3:]
let value = v:false
else
let value = (arg_key =~# '=$') ?
\ s:remove_quote_pairs(arg[len(arg_key) :]) : v:true
endif
if index(keys(defx#init#_user_options()), name) >= 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, '\\\@<!`.\{-}\\\@<!`')
while eval_pos >= 0
if eval_pos - prev_match > 0
let cmdline .= a:cmdline[prev_match : eval_pos - 1]
endif
let prev_match = matchend(a:cmdline,
\ '\\\@<!`.\{-}\\\@<!`', eval_pos)
let cmdline .= escape(eval(a:cmdline[eval_pos+1 : prev_match - 2]), '\ ')
let eval_pos = match(a:cmdline, '\\\@<!`.\{-}\\\@<!`', prev_match)
endwhile
if prev_match >= 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

View File

@ -0,0 +1,25 @@
"=============================================================================
" FILE: defx.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" 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

View File

@ -0,0 +1,824 @@
*defx.txt* Dark powered file explorer for neovim/Vim8.
Version: 1.0
Author: Shougo <Shougo.Matsu at gmail.com>
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 <silent><buffer><expr> <CR>
\ 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 <silent><buffer><expr> 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('<sfile>'),
\ '<SNR>\d\+_\zeSID_PREFIX$')
endfunction
let g:sid = s:SID_PREFIX()
nnoremap <silent><buffer><expr> 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 <silent><buffer><expr> <CR>
\ defx#do_action('multi', ['drop', 'quit'])
nnoremap <silent><buffer><expr> 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 <silent><buffer><expr> <CR>
\ defx#do_action('open')
nnoremap <silent><buffer><expr> c
\ defx#do_action('copy')
nnoremap <silent><buffer><expr> m
\ defx#do_action('move')
nnoremap <silent><buffer><expr> p
\ defx#do_action('paste')
nnoremap <silent><buffer><expr> l
\ defx#do_action('open')
nnoremap <silent><buffer><expr> E
\ defx#do_action('open', 'vsplit')
nnoremap <silent><buffer><expr> P
\ defx#do_action('open', 'pedit')
nnoremap <silent><buffer><expr> o
\ defx#do_action('open_tree', 'toggle')
nnoremap <silent><buffer><expr> K
\ defx#do_action('new_directory')
nnoremap <silent><buffer><expr> N
\ defx#do_action('new_file')
nnoremap <silent><buffer><expr> M
\ defx#do_action('new_multiple_files')
nnoremap <silent><buffer><expr> C
\ defx#do_action('toggle_columns',
\ 'mark:indent:icon:filename:type:size:time')
nnoremap <silent><buffer><expr> S
\ defx#do_action('toggle_sort', 'time')
nnoremap <silent><buffer><expr> d
\ defx#do_action('remove')
nnoremap <silent><buffer><expr> r
\ defx#do_action('rename')
nnoremap <silent><buffer><expr> !
\ defx#do_action('execute_command')
nnoremap <silent><buffer><expr> x
\ defx#do_action('execute_system')
nnoremap <silent><buffer><expr> yy
\ defx#do_action('yank_path')
nnoremap <silent><buffer><expr> .
\ defx#do_action('toggle_ignored_files')
nnoremap <silent><buffer><expr> ;
\ defx#do_action('repeat')
nnoremap <silent><buffer><expr> h
\ defx#do_action('cd', ['..'])
nnoremap <silent><buffer><expr> ~
\ defx#do_action('cd')
nnoremap <silent><buffer><expr> q
\ defx#do_action('quit')
nnoremap <silent><buffer><expr> <Space>
\ defx#do_action('toggle_select') . 'j'
nnoremap <silent><buffer><expr> *
\ defx#do_action('toggle_select_all')
nnoremap <silent><buffer><expr> j
\ line('.') == line('$') ? 'gg' : 'j'
nnoremap <silent><buffer><expr> k
\ line('.') == 1 ? 'G' : 'k'
nnoremap <silent><buffer><expr> <C-l>
\ defx#do_action('redraw')
nnoremap <silent><buffer><expr> <C-g>
\ defx#do_action('print')
nnoremap <silent><buffer><expr> 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 <silent><buffer><expr> <CR> 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 <silent><buffer><expr> > defx#do_action('resize',
\ defx#get_context().winwidth + 10)
nnoremap <silent><buffer><expr> < defx#do_action('resize',
\ defx#get_context().winwidth - 10)
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 <silent><buffer><expr> <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:

View File

@ -0,0 +1,14 @@
"=============================================================================
" FILE: defx.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" 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', <q-args>)

View File

@ -0,0 +1,82 @@
# ============================================================================
# FILE: __init__.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -0,0 +1,74 @@
# ============================================================================
# FILE: __init__.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,56 @@
# ============================================================================
# FILE: column.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -0,0 +1,332 @@
# ============================================================================
# FILE: kind.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -0,0 +1,40 @@
# ============================================================================
# FILE: source.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -0,0 +1,22 @@
# ============================================================================
# FILE: clipboard.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,134 @@
# ============================================================================
# FILE: filename.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -0,0 +1,68 @@
# ============================================================================
# FILE: icon.py
# AUTHOR: GuoPan Zhao <zgpio@qq.com>
# Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,31 @@
# ============================================================================
# FILE: indent.py
# AUTHOR: GuoPan Zhao <zgpio@qq.com>
# Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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]))

View File

@ -0,0 +1,61 @@
# ============================================================================
# FILE: mark.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,47 @@
# ============================================================================
# FILE: size.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,26 @@
# ============================================================================
# FILE: space.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,46 @@
# ============================================================================
# FILE: time.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,74 @@
# ============================================================================
# FILE: type.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,42 @@
# ============================================================================
# FILE: context.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,127 @@
# ============================================================================
# FILE: defx.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -0,0 +1,481 @@
# ============================================================================
# FILE: file.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -0,0 +1,74 @@
# ============================================================================
# FILE: rplugin.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -0,0 +1,13 @@
# ============================================================================
# FILE: session.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# License: MIT license
# ============================================================================
import typing
class Session(typing.NamedTuple):
name: str = ''
path: str = ''
opened_candidates: typing.List[str] = []

View File

@ -0,0 +1,75 @@
# ============================================================================
# FILE: sort.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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,
}

View File

@ -0,0 +1,61 @@
# ============================================================================
# FILE: file.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,90 @@
# ============================================================================
# FILE: util.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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

View File

@ -0,0 +1,678 @@
# ============================================================================
# FILE: view.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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 * <buffer>')
self._vim.command('autocmd defx '
'CursorHold,FocusGained <buffer> '
'call defx#call_async_action("check_redraw")')
self._vim.command('autocmd defx FileType <buffer> '
'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', '%'))

View File

@ -0,0 +1,36 @@
# ============================================================================
# FILE: defx/drive.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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()]

View File

@ -0,0 +1,35 @@
# ============================================================================
# FILE: defx/history.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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]

View File

@ -0,0 +1,58 @@
# ============================================================================
# FILE: defx/session.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# 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)

View File

@ -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

View File

@ -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')))

View File

@ -0,0 +1,5 @@
pynvim
pytest
flake8
mypy
vim-vint

View File

@ -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)

View File

@ -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)

4
bundle/dein.vim/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
doc/tags
.cache
*.py[cod]
vim-themis/

View File

@ -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

21
bundle/dein.vim/LICENSE Normal file
View File

@ -0,0 +1,21 @@
License: MIT license
AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
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.

24
bundle/dein.vim/Makefile Normal file
View File

@ -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

138
bundle/dein.vim/README.md Normal file
View File

@ -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.
<!-- vim-markdown-toc GFM -->
- [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)
<!-- vim-markdown-toc -->
## 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. |

View File

@ -0,0 +1,204 @@
"=============================================================================
" FILE: dein.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" 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('<afile>'))
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('<afile>'))
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

Some files were not shown because too many files have changed in this diff Show More