├── .github └── workflows │ ├── neovim.yml │ ├── reviewdog.yml │ └── vim.yml ├── .gitignore ├── .vintrc.yaml ├── LICENSE ├── README.md ├── autoload └── vital │ └── __vital__ │ ├── App │ ├── Action.vim │ ├── Args.vim │ ├── Emitter.vim │ ├── Flag.vim │ ├── Revelator.vim │ ├── Spinner.vim │ ├── WindowLocator.vim │ └── WindowSelector.vim │ ├── Async │ ├── CancellationToken.vim │ ├── CancellationTokenSource.vim │ ├── File.vim │ ├── Lambda.vim │ ├── Observable.vim │ ├── Observable │ │ └── Process.vim │ ├── Process.vim │ └── Promise │ │ ├── Deferred.vim │ │ └── Process.vim │ ├── Config.vim │ ├── Data │ └── List │ │ └── Chunker.vim │ ├── Lambda.vim │ ├── Path.vim │ ├── Path │ └── Filepath.vim │ ├── Prompt.vim │ ├── System │ ├── Job.vim │ ├── Job │ │ ├── Neovim.vim │ │ └── Vim.vim │ └── Sandbox.vim │ └── Vim │ ├── Buffer │ ├── ANSI.vim │ ├── Group.vim │ ├── Opener.vim │ └── Writer.vim │ ├── Console.vim │ ├── Highlight.vim │ ├── Window.vim │ └── Window │ ├── Cursor.vim │ ├── Locator.vim │ └── Selector.vim ├── doc └── Vital │ ├── App │ ├── Action.txt │ ├── Args.txt │ ├── Emitter.txt │ ├── Flag.txt │ ├── Revelator.txt │ ├── Spinner.txt │ ├── WindowLocator.txt │ └── WindowSelector.txt │ ├── Async │ ├── CancellationToken.txt │ ├── CancellationTokenSource.txt │ ├── File.txt │ ├── Lambda.txt │ ├── Observable.txt │ ├── Observable │ │ └── Process.txt │ └── Promise │ │ ├── Deferred.txt │ │ └── Process.txt │ ├── Config.txt │ ├── Data │ └── List │ │ └── Chunker.txt │ ├── Lambda.txt │ ├── Path.txt │ ├── Path │ └── Filepath.txt │ ├── Prompt.txt │ ├── System │ ├── Job.txt │ └── Sandbox.txt │ └── Vim │ ├── Buffer │ ├── ANSI.txt │ ├── Group.txt │ ├── Opener.txt │ └── Writer.txt │ ├── Console.txt │ ├── Highlight.txt │ └── Window.txt └── test ├── .gitignore ├── .themisrc ├── App ├── Action.vimspec ├── Args.vimspec ├── Emitter.vimspec ├── Flag.vimspec ├── Revelator.vimspec └── Spinner.vimspec ├── Async ├── CancellationToken.vimspec ├── CancellationTokenSource.vimspec ├── File.vimspec ├── Lambda.vimspec ├── Observable.vimspec ├── Observable │ └── Process.vimspec └── Promise │ ├── Deferred.vimspec │ └── Process.vimspec ├── Config.vimspec ├── Data └── List │ └── Chunker.vimspec ├── Lambda.vimspec ├── Path.vimspec ├── Path └── Filepath.vimspec ├── System ├── Job.vimspec └── Sandbox.vimspec ├── Vim ├── Buffer │ ├── ANSI.vimspec │ ├── Group.vimspec │ ├── Opener.vimspec │ └── Writer.vimspec ├── Console.vimspec ├── Highlight.vimspec ├── Window.vimspec └── Window │ └── Cursor.vimspec └── _testdata ├── System └── Job │ ├── cwd.py │ ├── echo.py │ ├── env.py │ ├── exit.py │ ├── never.py │ └── reply.py └── Vim └── Buffer └── Writer ├── cp1250-encoding.txt ├── cp932-encoding.txt ├── euc-jp-encoding.txt ├── sjis-encoding.txt └── utf-8-encoding.txt /.github/workflows/neovim.yml: -------------------------------------------------------------------------------- 1 | name: neovim 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | strategy: 14 | matrix: 15 | os: 16 | - macos-11 17 | - windows-2022 18 | - ubuntu-20.04 19 | version: 20 | - head 21 | - stable 22 | - v0.4.3 23 | runs-on: ${{ matrix.os }} 24 | steps: 25 | - uses: actions/checkout@v2 26 | - name: Install Neovim 27 | uses: thinca/action-setup-vim@v1 28 | id: vim 29 | with: 30 | vim_type: Neovim 31 | vim_version: ${{ matrix.version }} 32 | - name: Download test runner 33 | uses: actions/checkout@v2 34 | with: 35 | repository: thinca/vim-themis 36 | path: vim-themis 37 | - name: Prepare environment 38 | run: | 39 | git config --global user.name "github-action" 40 | git config --global user.email "github-action@example.com" 41 | - name: Run tests 42 | env: 43 | CI: 1 44 | THEMIS_VIM: ${{ steps.vim.outputs.executable }} 45 | # XXX: 46 | # Overwrite %TMP% to point a correct temp directory. 47 | # Note that %TMP% only affects value of 'tempname()' in Windows. 48 | # https://github.community/t5/GitHub-Actions/TEMP-is-broken-on-Windows/m-p/30432#M427 49 | TMP: 'C:\Users\runneradmin\AppData\Local\Temp' 50 | run: | 51 | ./vim-themis/bin/themis --reporter spec 52 | -------------------------------------------------------------------------------- /.github/workflows/reviewdog.yml: -------------------------------------------------------------------------------- 1 | name: reviewdog 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | vimlint: 13 | name: runner / vint 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: vint 18 | uses: reviewdog/action-vint@v1 19 | with: 20 | github_token: ${{ secrets.github_token }} 21 | level: error 22 | reporter: github-pr-review 23 | -------------------------------------------------------------------------------- /.github/workflows/vim.yml: -------------------------------------------------------------------------------- 1 | name: vim 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | strategy: 14 | matrix: 15 | os: 16 | - macos-11 17 | - windows-2022 18 | # NOTE: 19 | # Use 'ubuntu-18.04' for now because using 'ubuntu-20.04' cause the following error 20 | # 21 | # ERROR: helper/deps: Failed fetching deps: git clone --quiet --depth 1 'https://github.com/vim-jp/vital.vim' 'test/.deps/vital.vim' 22 | # /usr/lib/git-core/git-remote-https: /tmp/.mount_vim6vy1Wm/usr/lib/x86_64-linux-gnu/libcrypt.so.1: version `XCRYPT_2.0' not found (required by /lib/x86_64-linux-gnu/libkrb5.so.26) 23 | # /usr/lib/git-core/git-remote-https: /tmp/.mount_vim6vy1Wm/usr/lib/x86_64-linux-gnu/libcrypt.so.1: version `XCRYPT_2.0' not found (required by /lib/x86_64-linux-gnu/libroken.so.18) 24 | # Error: Process completed with exit code 1. 25 | # 26 | # Somehow, this doesn't occured for Neovim. 27 | - ubuntu-18.04 28 | version: 29 | - head 30 | - v8.2.0235 31 | - v8.1.2424 32 | runs-on: ${{ matrix.os }} 33 | steps: 34 | - uses: actions/checkout@v2 35 | - name: Install Vim 36 | uses: thinca/action-setup-vim@v1 37 | id: vim 38 | with: 39 | vim_type: Vim 40 | vim_version: ${{ matrix.version }} 41 | - name: Download test runner 42 | uses: actions/checkout@v2 43 | with: 44 | repository: thinca/vim-themis 45 | path: vim-themis 46 | - name: Prepare environment 47 | run: | 48 | git config --global user.name "github-action" 49 | git config --global user.email "github-action@example.com" 50 | - name: Run tests 51 | env: 52 | CI: 1 53 | THEMIS_VIM: ${{ steps.vim.outputs.executable }} 54 | # XXX: 55 | # Overwrite %TMP% to point a correct temp directory. 56 | # Note that %TMP% only affects value of 'tempname()' in Windows. 57 | # https://github.community/t5/GitHub-Actions/TEMP-is-broken-on-Windows/m-p/30432#M427 58 | TMP: 'C:\Users\runneradmin\AppData\Local\Temp' 59 | run: | 60 | ./vim-themis/bin/themis --reporter spec 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | doc/tags 2 | -------------------------------------------------------------------------------- /.vintrc.yaml: -------------------------------------------------------------------------------- 1 | policies: 2 | ProhibitUnnecessaryDoubleQuote: 3 | enabled: false 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) since 2016 Alisue, hashnote.net 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/App/Args.vim: -------------------------------------------------------------------------------- 1 | function! s:_index(args, pattern) abort 2 | for index in range(len(a:args)) 3 | if a:args[index] =~# a:pattern 4 | return index 5 | endif 6 | endfor 7 | return -1 8 | endfunction 9 | 10 | function! s:get(args, name, default) abort 11 | let pattern = printf('^-%s\%(=.*\)\?$', a:name) 12 | let index = s:_index(a:args, pattern) 13 | if index is# -1 14 | return a:default 15 | else 16 | let value = a:args[index] 17 | return value =~# '^-[^=]\+=' 18 | \ ? matchstr(value, '=\zs.*$') 19 | \ : v:true 20 | endif 21 | endfunction 22 | 23 | function! s:pop(args, name, default) abort 24 | let pattern = printf('^-%s\%(=.*\)\?$', a:name) 25 | let index = s:_index(a:args, pattern) 26 | if index is# -1 27 | return a:default 28 | else 29 | let value = remove(a:args, index) 30 | return value =~# '^-[^=]\+=' 31 | \ ? matchstr(value, '=\zs.*$') 32 | \ : v:true 33 | endif 34 | endfunction 35 | 36 | function! s:set(args, name, value) abort 37 | let pattern = printf('^-%s\%(=.*\)\?$', a:name) 38 | let index = s:_index(a:args, pattern) 39 | let value = a:value is# v:true 40 | \ ? printf('-%s', a:name) 41 | \ : printf('-%s=%s', a:name, a:value) 42 | if index is# -1 43 | call add(a:args, value) 44 | elseif a:value is# v:false 45 | call remove(a:args, index) 46 | else 47 | let a:args[index] = value 48 | endif 49 | endfunction 50 | 51 | function! s:throw_if_dirty(args, ...) abort 52 | let prefix = a:0 ? a:1 : '' 53 | for arg in a:args 54 | if arg =~# '^-' 55 | throw printf('%sunknown option %s has specified', prefix, arg) 56 | endif 57 | endfor 58 | endfunction 59 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/App/Emitter.vim: -------------------------------------------------------------------------------- 1 | let s:listeners = {} 2 | let s:middlewares = [] 3 | 4 | function! s:subscribe(name, listener, ...) abort 5 | let dict = get(a:000, 0, v:null) 6 | let s:listeners[a:name] = get(s:listeners, a:name, []) 7 | call add(s:listeners[a:name], [a:listener, dict]) 8 | endfunction 9 | 10 | function! s:unsubscribe(...) abort 11 | if a:0 == 0 12 | let s:listeners = {} 13 | elseif a:0 == 1 14 | let s:listeners[a:1] = [] 15 | else 16 | let dict = a:0 == 3 ? a:3 : v:null 17 | let s:listeners[a:1] = get(s:listeners, a:1, []) 18 | let index = index(s:listeners[a:1], [a:2, dict]) 19 | if index != -1 20 | call remove(s:listeners[a:1], index) 21 | endif 22 | endif 23 | endfunction 24 | 25 | function! s:add_middleware(middleware) abort 26 | call add(s:middlewares, a:middleware) 27 | endfunction 28 | 29 | function! s:remove_middleware(...) abort 30 | if a:0 == 0 31 | let s:middlewares = [] 32 | else 33 | let index = index(s:middlewares, a:1) 34 | if index != -1 35 | call remove(s:middlewares, index) 36 | endif 37 | endif 38 | endfunction 39 | 40 | function! s:emit(name, ...) abort 41 | let attrs = copy(a:000) 42 | let listeners = copy(get(s:listeners, a:name, [])) 43 | let middlewares = map(s:middlewares, 'extend(copy(s:middleware), v:val)') 44 | for middleware in middlewares 45 | call call(middleware.on_emit_pre, [a:name, listeners, attrs], middleware) 46 | endfor 47 | for [l:Listener, dict] in listeners 48 | if empty(dict) 49 | call call(Listener, attrs) 50 | else 51 | call call(Listener, attrs, dict) 52 | endif 53 | endfor 54 | for middleware in middlewares 55 | call call(middleware.on_emit_post, [a:name, listeners, attrs], middleware) 56 | endfor 57 | endfunction 58 | 59 | 60 | " Middleware skeleton -------------------------------------------------------- 61 | let s:middleware = {} 62 | 63 | function! s:middleware.on_emit_pre(name, listeners, attrs) abort 64 | " Users can override this method 65 | endfunction 66 | 67 | function! s:middleware.on_emit_post(name, listeners, attrs) abort 68 | " Users can override this method 69 | endfunction 70 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/App/Flag.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_created(module) abort 2 | " build pattern for parsing arguments 3 | let single_quote = '''\zs[^'']\+\ze''' 4 | let double_quote = '"\zs[^"]\+\ze"' 5 | let bare_strings = '\%(\\\s\|[^ ''"]\)\+' 6 | let s:PARSE_PATTERN = printf( 7 | \ '\%%(%s\)*\zs\%%(\s\+\|$\)\ze', 8 | \ join([single_quote, double_quote, bare_strings], '\|') 9 | \) 10 | let s:NORM_PATTERN = '^\%("\zs.*\ze"\|''\zs.*\ze''\|.*\)$' 11 | endfunction 12 | 13 | function! s:split(cmdline) abort 14 | return map( 15 | \ split(a:cmdline, s:PARSE_PATTERN), 16 | \ 's:_norm(v:val)', 17 | \) 18 | endfunction 19 | 20 | function! s:parse(args) abort 21 | let options = {} 22 | let remains = [] 23 | for index in range(len(a:args)) 24 | let term = a:args[index] 25 | if term ==# '--' 26 | let remains += a:args[index+1:] 27 | return [options, remains] 28 | elseif term =~# '^-\S\+=' 29 | let name = matchstr(term, '^-\zs\S\+\ze=') 30 | let options[name] = matchstr(term, '^-\S\+=\zs.*') 31 | elseif term =~# '^-\S\+' 32 | let name = matchstr(term, '^-\zs\S\+') 33 | let options[name] = v:true 34 | else 35 | call add(remains, term) 36 | endif 37 | endfor 38 | return [options, remains] 39 | endfunction 40 | 41 | function! s:flag(args, name) abort 42 | let pattern = printf('^-%s$', a:name) 43 | return match(a:args, pattern) isnot# -1 44 | endfunction 45 | 46 | function! s:value(args, name, ...) abort 47 | let pattern = printf('^-%s=\zs.*$', a:name) 48 | let index = match(a:args, pattern) 49 | if index is# -1 50 | return a:0 ? a:1 : v:null 51 | endif 52 | return matchstr(a:args[index], pattern) 53 | endfunction 54 | 55 | 56 | " Private 57 | function! s:_norm(term) abort 58 | let m = matchlist(a:term, '^\(-\w\|--\S\+=\)\(.\+\)') 59 | if empty(m) 60 | return matchstr(a:term, s:NORM_PATTERN) 61 | endif 62 | return m[1] . matchstr(m[2], s:NORM_PATTERN) 63 | endfunction 64 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/App/Revelator.vim: -------------------------------------------------------------------------------- 1 | let s:t_number = type(0) 2 | let s:receivers = [] 3 | 4 | 5 | function! s:_vital_loaded(V) abort 6 | let s:Console = a:V.import('Vim.Console') 7 | endfunction 8 | 9 | function! s:_vital_depends() abort 10 | return ['Vim.Console'] 11 | endfunction 12 | 13 | function! s:_vital_created(module) abort 14 | call a:module.register(s:get_default_receiver()) 15 | endfunction 16 | 17 | function! s:message(category, msg) abort 18 | return printf( 19 | \ 'vital: App.Revelator: %s: %s', 20 | \ a:category, 21 | \ a:msg, 22 | \) 23 | endfunction 24 | 25 | function! s:info(msg) abort 26 | let v:statusmsg = a:msg 27 | return s:message('INFO', a:msg) 28 | endfunction 29 | 30 | function! s:warning(msg) abort 31 | let v:warningmsg = a:msg 32 | return s:message('WARNING', a:msg) 33 | endfunction 34 | 35 | function! s:error(msg) abort 36 | let v:errmsg = a:msg 37 | return s:message('ERROR', a:msg) 38 | endfunction 39 | 40 | function! s:critical(msg) abort 41 | let v:errmsg = a:msg 42 | return s:message('CRITICAL', a:msg) 43 | endfunction 44 | 45 | function! s:call(func, arglist, ...) abort 46 | let receivers_saved = copy(s:receivers) 47 | let dict = a:0 ? a:1 : 0 48 | try 49 | return type(dict) == s:t_number 50 | \ ? call(a:func, a:arglist) 51 | \ : call(a:func, a:arglist, dict) 52 | catch /^vital: App\.Revelator: / 53 | call s:_receive(v:exception, v:throwpoint) 54 | finally 55 | let s:receivers = receivers_saved 56 | endtry 57 | endfunction 58 | 59 | function! s:register(receiver) abort 60 | call add(s:receivers, a:receiver) 61 | endfunction 62 | 63 | function! s:unregister(receiver) abort 64 | let index = index(s:receivers, a:receiver) 65 | if index != -1 66 | call remove(s:receivers, index) 67 | endif 68 | endfunction 69 | 70 | function! s:get_default_receiver() abort 71 | return function('s:_default_receiver') 72 | endfunction 73 | 74 | 75 | function! s:_receive(exception, throwpoint) abort 76 | let m = matchlist(a:exception, '^vital: App\.Revelator: \(.\{-}\): \(.*\)$') 77 | if len(m) 78 | let category = m[1] 79 | let message = m[2] 80 | let revelation = { 81 | \ 'category': m[1], 82 | \ 'message': m[2], 83 | \ 'exception': a:exception, 84 | \ 'throwpoint': a:throwpoint, 85 | \} 86 | for l:Receiver in reverse(copy(s:receivers)) 87 | if call(Receiver, [revelation]) 88 | return 89 | endif 90 | endfor 91 | endif 92 | throw a:exception . "\n" . a:throwpoint 93 | endfunction 94 | 95 | function! s:_default_receiver(revelation) abort 96 | if a:revelation.category ==# 'INFO' 97 | redraw 98 | call s:Console.info(a:revelation.message) 99 | call s:Console.debug(a:revelation.throwpoint) 100 | return 1 101 | elseif a:revelation.category ==# 'WARNING' 102 | redraw 103 | call s:Console.warn(a:revelation.message) 104 | call s:Console.debug(a:revelation.throwpoint) 105 | return 1 106 | elseif a:revelation.category ==# 'ERROR' 107 | redraw 108 | call s:Console.error(a:revelation.message) 109 | call s:Console.debug(a:revelation.throwpoint) 110 | return 1 111 | elseif a:revelation.category ==# 'CRITICAL' 112 | redraw 113 | call s:Console.error(a:revelation.message) 114 | call s:Console.error(a:revelation.throwpoint) 115 | return 1 116 | endif 117 | endfunction 118 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/App/WindowLocator.vim: -------------------------------------------------------------------------------- 1 | let s:threshold = 0 2 | let s:conditions = [ 3 | \ { wi -> !wi.loclist }, 4 | \ { wi -> !wi.quickfix }, 5 | \ { wi -> !getwinvar(wi.winid, '&winfixwidth', 0) }, 6 | \ { wi -> !getwinvar(wi.winid, '&winfixheight', 0) }, 7 | \ { wi -> !getbufvar(wi.bufnr, '&previewwindow', 0) }, 8 | \] 9 | 10 | " Add condition to make sure that the window is not floating 11 | if exists('*nvim_win_get_config') 12 | call add(s:conditions, { wi -> nvim_win_get_config(wi.winid).relative ==# '' }) 13 | endif 14 | 15 | function! s:score(winnr) abort 16 | let winid = win_getid(a:winnr) 17 | let wininfo = getwininfo(winid) 18 | if empty(wininfo) 19 | return 0 20 | endif 21 | let wi = wininfo[0] 22 | let score = 1 23 | for Condition in s:conditions 24 | let score += Condition(wi) 25 | endfor 26 | return score 27 | endfunction 28 | 29 | function! s:list() abort 30 | let nwinnr = winnr('$') 31 | if nwinnr == 1 32 | return 1 33 | endif 34 | let threshold = s:get_threshold() 35 | while threshold > 0 36 | let ws = filter( 37 | \ range(1, winnr('$')), 38 | \ { -> s:score(v:val) >= threshold } 39 | \) 40 | if !empty(ws) 41 | break 42 | endif 43 | let threshold -= 1 44 | endwhile 45 | return ws 46 | endfunction 47 | 48 | function! s:find(origin) abort 49 | let nwinnr = winnr('$') 50 | if nwinnr == 1 51 | return 1 52 | endif 53 | let origin = a:origin == 0 ? winnr() : a:origin 54 | let former = range(origin, winnr('$')) 55 | let latter = reverse(range(1, origin - 1)) 56 | let threshold = s:get_threshold() 57 | while threshold > 0 58 | for winnr in (former + latter) 59 | if s:score(winnr) >= threshold 60 | return winnr 61 | endif 62 | endfor 63 | let threshold -= 1 64 | endwhile 65 | return 0 66 | endfunction 67 | 68 | function! s:focus(origin) abort 69 | let winnr = s:find(a:origin) 70 | if winnr == 0 || winnr == winnr() 71 | return 1 72 | endif 73 | call win_gotoid(win_getid(winnr)) 74 | endfunction 75 | 76 | function! s:get_conditions() abort 77 | return copy(s:conditions) 78 | endfunction 79 | 80 | function! s:set_conditions(conditions) abort 81 | let s:conditions = copy(a:conditions) 82 | endfunction 83 | 84 | function! s:get_threshold() abort 85 | return s:threshold is# 0 ? len(s:conditions) + 1 : s:threshold 86 | endfunction 87 | 88 | function! s:set_threshold(threshold) abort 89 | let s:threshold = a:threshold 90 | endfunction 91 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Async/CancellationToken.vim: -------------------------------------------------------------------------------- 1 | let s:STATE_OPEN = 0 2 | let s:STATE_CLOSED = 1 3 | let s:STATE_REQUESTED = 2 4 | 5 | let s:CANCELLED_ERROR = 'vital: Async.CancellationToken: CancelledError' 6 | 7 | function! s:_vital_created(module) abort 8 | " State 9 | call extend(a:module, { 10 | \ 'STATE_OPEN': s:STATE_OPEN, 11 | \ 'STATE_CLOSED': s:STATE_CLOSED, 12 | \ 'STATE_REQUESTED': s:STATE_REQUESTED, 13 | \}) 14 | " A token which will never be canceled 15 | let a:module.none = s:new({ 16 | \ '_state': s:STATE_CLOSED, 17 | \ '_registrations': [], 18 | \}) 19 | " A token that is already canceled 20 | let a:module.canceled = s:new({ 21 | \ '_state': s:STATE_REQUESTED, 22 | \ '_registrations': [], 23 | \}) 24 | let a:module.CancelledError = s:CANCELLED_ERROR 25 | lockvar 3 a:module 26 | endfunction 27 | 28 | function! s:new(source) abort 29 | let token = { 30 | \ '_source': a:source, 31 | \ 'cancellation_requested': funcref('s:_cancellation_requested'), 32 | \ 'can_be_canceled': funcref('s:_can_be_canceled'), 33 | \ 'throw_if_cancellation_requested': funcref('s:_throw_if_cancellation_requested'), 34 | \ 'register': funcref('s:_register'), 35 | \} 36 | lockvar 1 token 37 | return token 38 | endfunction 39 | 40 | function! s:_cancellation_requested() abort dict 41 | return self._source._state is# s:STATE_REQUESTED 42 | endfunction 43 | 44 | function! s:_can_be_canceled() abort dict 45 | return self._source._state isnot# s:STATE_CLOSED 46 | endfunction 47 | 48 | function! s:_throw_if_cancellation_requested() abort dict 49 | if self.cancellation_requested() 50 | throw s:CANCELLED_ERROR 51 | endif 52 | endfunction 53 | 54 | function! s:_register(callback) abort dict 55 | if self._source._state is# s:STATE_REQUESTED 56 | call a:callback() 57 | return { 'unregister': { -> 0 } } 58 | elseif self._source._state is# s:STATE_CLOSED 59 | return { 'unregister': { -> 0 } } 60 | endif 61 | 62 | let registration = { 63 | \ '_source': self._source, 64 | \ '_target': a:callback, 65 | \ 'unregister': funcref('s:_unregister'), 66 | \} 67 | call add(self._source._registrations, registration) 68 | return registration 69 | endfunction 70 | 71 | function! s:_unregister() abort dict 72 | if self._source is# v:null 73 | return 74 | endif 75 | let index = index(self._source._registrations, self) 76 | if index isnot# -1 77 | call remove(self._source._registrations, index) 78 | endif 79 | let self._source = v:null 80 | let self._target = v:null 81 | endfunction 82 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Async/CancellationTokenSource.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_depends() abort 2 | return ['Async.CancellationToken'] 3 | endfunction 4 | 5 | function! s:_vital_loaded(V) abort 6 | let s:CancellationToken = a:V.import('Async.CancellationToken') 7 | endfunction 8 | 9 | function! s:new(...) abort 10 | let source = { 11 | \ '_state': s:CancellationToken.STATE_OPEN, 12 | \ '_registrations': [], 13 | \ '_linking_registrations': [], 14 | \ 'cancel': funcref('s:_cancel'), 15 | \ 'close': funcref('s:_close'), 16 | \} 17 | " Link to given tokens 18 | for token in (a:0 ? a:1 : []) 19 | if token.cancellation_requested() 20 | let source._state = token._source._state 21 | call s:_unlink(source) 22 | break 23 | elseif token.can_be_canceled() 24 | call add( 25 | \ source._linking_registrations, 26 | \ token.register({ -> source.cancel() }), 27 | \) 28 | endif 29 | endfor 30 | " Assign token 31 | let source.token = s:CancellationToken.new(source) 32 | lockvar 1 source 33 | return source 34 | endfunction 35 | 36 | function! s:_cancel() abort dict 37 | if self._state isnot# s:CancellationToken.STATE_OPEN 38 | return 39 | endif 40 | 41 | let self._state = s:CancellationToken.STATE_REQUESTED 42 | call s:_unlink(self) 43 | 44 | let registrations = filter( 45 | \ self._registrations, 46 | \ { _, v -> v._target isnot# v:null } 47 | \) 48 | let self._registrations = [] 49 | for registration in registrations 50 | try 51 | call registration._target() 52 | catch 53 | let exception = v:exception 54 | call timer_start(0, { -> s:_throw(exception) }) 55 | endtry 56 | endfor 57 | endfunction 58 | 59 | function! s:_close() abort dict 60 | if self._state isnot# s:CancellationToken.STATE_OPEN 61 | return 62 | endif 63 | 64 | let self._state = s:CancellationToken.STATE_CLOSED 65 | call s:_unlink(self) 66 | let self._registrations = [] 67 | endfunction 68 | 69 | function! s:_unlink(source) abort 70 | let linking_registrations = a:source._linking_registrations 71 | let a:source._linking_registrations = [] 72 | call map(linking_registrations, { _, v -> v.unregister() }) 73 | endfunction 74 | 75 | function! s:_throw(exception) abort 76 | throw substitute(a:exception, '^Vim(.*):', '', '') 77 | endfunction 78 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Async/Lambda.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_created(module) abort 2 | let a:module.chunk_size = 1000 3 | endfunction 4 | 5 | function! s:_vital_loaded(V) abort 6 | let s:Later = a:V.import('Async.Later') 7 | let s:Lambda = a:V.import('Lambda') 8 | let s:Promise = a:V.import('Async.Promise') 9 | let s:Chunker = a:V.import('Data.List.Chunker') 10 | endfunction 11 | 12 | function! s:_vital_depends() abort 13 | return ['Async.Later', 'Async.Promise', 'Data.List.Chunker', 'Lambda'] 14 | endfunction 15 | 16 | function! s:map(list, fn) abort dict 17 | let t = self.chunk_size 18 | let c = s:Chunker.new(t, a:list) 19 | return s:Promise.new({ resolve -> s:_map(c, a:fn, [], 0, resolve)}) 20 | endfunction 21 | 22 | function! s:filter(list, fn) abort dict 23 | let t = self.chunk_size 24 | let c = s:Chunker.new(t, a:list) 25 | return s:Promise.new({ resolve -> s:_filter(c, a:fn, [], 0, resolve)}) 26 | endfunction 27 | 28 | function! s:reduce(list, fn, init) abort dict 29 | let t = self.chunk_size 30 | let c = s:Chunker.new(t, a:list) 31 | return s:Promise.new({ resolve -> s:_reduce(c, a:fn, a:init, 0, resolve)}) 32 | endfunction 33 | 34 | function! s:map_f(fn) abort dict 35 | return { list -> self.map(list, a:fn) } 36 | endfunction 37 | 38 | function! s:filter_f(fn) abort dict 39 | return { list -> self.filter(list, a:fn) } 40 | endfunction 41 | 42 | function! s:reduce_f(fn, init) abort dict 43 | return { list -> self.reduce(list, a:fn, a:init) } 44 | endfunction 45 | 46 | function! s:_map(chunker, fn, result, offset, resolve) abort 47 | let chunk = a:chunker.next() 48 | let chunk_size = len(chunk) 49 | if chunk_size is# 0 50 | call a:resolve(a:result) 51 | return 52 | endif 53 | call extend(a:result, map(chunk, { k, v -> a:fn(v, a:offset + k) })) 54 | call s:Later.call({ -> 55 | \ s:_map(a:chunker, a:fn, a:result, a:offset + chunk_size, a:resolve) 56 | \}) 57 | endfunction 58 | 59 | function! s:_filter(chunker, fn, result, offset, resolve) abort 60 | let chunk = a:chunker.next() 61 | let chunk_size = len(chunk) 62 | if chunk_size is# 0 63 | call a:resolve(a:result) 64 | return 65 | endif 66 | call extend(a:result, filter(chunk, { k, v -> a:fn(v, a:offset + k) })) 67 | call s:Later.call({ -> 68 | \ s:_filter(a:chunker, a:fn, a:result, a:offset + chunk_size, a:resolve) 69 | \}) 70 | endfunction 71 | 72 | function! s:_reduce(chunker, fn, result, offset, resolve) abort 73 | let chunk = a:chunker.next() 74 | let chunk_size = len(chunk) 75 | if chunk_size is# 0 76 | call a:resolve(a:result) 77 | return 78 | endif 79 | let result = s:Lambda.reduce( 80 | \ chunk, 81 | \ { a, v, k -> a:fn(a, v, a:offset + k) }, 82 | \ a:result, 83 | \) 84 | call s:Later.call({ -> 85 | \ s:_reduce(a:chunker, a:fn, result, a:offset + chunk_size, a:resolve) 86 | \}) 87 | endfunction 88 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Async/Process.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_created(module) abort 2 | let a:module.operators = { 3 | \ 'focus': { -> call(s:Process.operators.focus, a:000, s:Process.operators) }, 4 | \ 'squash': { -> call(s:Process.operators.squash, a:000, s:Process.operators) }, 5 | \ 'stretch': { -> call(s:Process.operators.stretch, a:000, s:Process.operators) }, 6 | \ 'pile': { -> call(s:Process.operators.pile, a:000, s:Process.operators) }, 7 | \ 'line': { -> call(s:Process.operators.line, a:000, s:Process.operators) }, 8 | \} 9 | echohl Error 10 | echo 'vital: Async.Process is deprecated. Use Async.Observable.Process instead.' 11 | echohl None 12 | endfunction 13 | 14 | function! s:_vital_loaded(V) abort 15 | let s:Process = a:V.import('Async.Observable.Process') 16 | endfunction 17 | 18 | function! s:_vital_depends() abort 19 | return ['Async.Observable.Process'] 20 | endfunction 21 | 22 | function! s:new(...) abort 23 | return call(s:Process.new, a:000, s:Process) 24 | endfunction 25 | 26 | function! s:start(...) abort 27 | return call(s:Process.start, a:000, s:Process) 28 | endfunction 29 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Async/Promise/Deferred.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_loaded(V) abort 2 | let s:Promise = a:V.import('Async.Promise') 3 | endfunction 4 | 5 | function! s:_vital_depends() abort 6 | return ['Async.Promise'] 7 | endfunction 8 | 9 | function! s:new() abort 10 | let ns = {'resolve': v:null, 'reject': v:null} 11 | let promise = s:Promise.new( 12 | \ { rv, rt -> extend(ns, {'resolve': rv, 'reject': rt}) } 13 | \) 14 | while ns.resolve is# v:null 15 | sleep 1m 16 | endwhile 17 | let promise.resolve = ns.resolve 18 | let promise.reject = ns.reject 19 | return promise 20 | endfunction 21 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Async/Promise/Process.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_loaded(V) abort 2 | let s:Job = a:V.import('System.Job') 3 | let s:Promise = a:V.import('Async.Promise') 4 | let s:CancellationToken = a:V.import('Async.CancellationToken') 5 | endfunction 6 | 7 | function! s:_vital_depends() abort 8 | return ['System.Job', 'Async.Promise', 'Async.CancellationToken'] 9 | endfunction 10 | 11 | function! s:start(args, ...) abort 12 | let options = extend({ 13 | \ 'cwd': '.', 14 | \ 'raw': 0, 15 | \ 'stdin': s:Promise.reject(), 16 | \ 'token': s:CancellationToken.none, 17 | \ 'reject_on_failure': v:false, 18 | \}, a:0 ? a:1 : {}, 19 | \) 20 | let p = s:Promise.new(funcref('s:_executor', [a:args, options])) 21 | if options.reject_on_failure 22 | let p = p.then(funcref('s:_reject_on_failure')) 23 | endif 24 | return p 25 | endfunction 26 | 27 | function! s:is_available() abort 28 | if !has('patch-8.0.0107') && !has('nvim-0.2.0') 29 | return 0 30 | endif 31 | return s:Promise.is_available() && s:Job.is_available() 32 | endfunction 33 | 34 | function! s:_reject_on_failure(result) abort 35 | if a:result.exitval 36 | return s:Promise.reject(a:result) 37 | endif 38 | return a:result 39 | endfunction 40 | 41 | function! s:_executor(args, options, resolve, reject) abort 42 | call a:options.token.throw_if_cancellation_requested() 43 | 44 | let ns = { 45 | \ 'args': a:args, 46 | \ 'stdout': [''], 47 | \ 'stderr': [''], 48 | \ 'resolve': a:resolve, 49 | \ 'reject': a:reject, 50 | \ 'token': a:options.token, 51 | \} 52 | let reg = ns.token.register(funcref('s:_on_cancel', [ns])) 53 | let ns.job = s:Job.start(a:args, { 54 | \ 'cwd': a:options.cwd, 55 | \ 'on_stdout': a:options.raw 56 | \ ? funcref('s:_on_receive_raw', [ns.stdout]) 57 | \ : funcref('s:_on_receive', [ns.stdout]), 58 | \ 'on_stderr': a:options.raw 59 | \ ? funcref('s:_on_receive_raw', [ns.stderr]) 60 | \ : funcref('s:_on_receive', [ns.stderr]), 61 | \ 'on_exit': funcref('s:_on_exit', [reg, ns]), 62 | \}) 63 | call a:options.stdin 64 | \.then({ v -> ns.job.send(v) }) 65 | \.then({ -> ns.job.close() }) 66 | if has_key(a:options, 'abort') 67 | echohl WarningMsg 68 | echomsg 'vital: Async.Promise.Process: The "abort" has deprecated. Use "token" instead.' 69 | echohl None 70 | call a:options.abort 71 | \.then({ -> ns.job.stop() }) 72 | endif 73 | endfunction 74 | 75 | function! s:_on_receive(buffer, data) abort 76 | call map(a:data, 'v:val[-1:] ==# "\r" ? v:val[:-2] : v:val') 77 | let a:buffer[-1] .= a:data[0] 78 | call extend(a:buffer, a:data[1:]) 79 | endfunction 80 | 81 | function! s:_on_receive_raw(buffer, data) abort 82 | let a:buffer[-1] .= a:data[0] 83 | call extend(a:buffer, a:data[1:]) 84 | endfunction 85 | 86 | function! s:_on_exit(reg, ns, data) abort 87 | call a:reg.unregister() 88 | call a:ns.resolve({ 89 | \ 'args': a:ns.args, 90 | \ 'stdout': a:ns.stdout, 91 | \ 'stderr': a:ns.stderr, 92 | \ 'exitval': a:data, 93 | \}) 94 | endfunction 95 | 96 | function! s:_on_cancel(ns, ...) abort 97 | call a:ns.job.stop() 98 | call a:ns.reject(s:CancellationToken.CancelledError) 99 | endfunction 100 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Config.vim: -------------------------------------------------------------------------------- 1 | let s:plugin_name = expand(':p:h:t') 2 | let s:plugin_name = s:plugin_name =~# '^__.\+__$' 3 | \ ? s:plugin_name[2:-3] 4 | \ : s:plugin_name =~# '^_.\+$' 5 | \ ? s:plugin_name[1:] 6 | \ : s:plugin_name 7 | 8 | function! s:define(prefix, default) abort 9 | let prefix = a:prefix =~# '^g:' ? a:prefix : 'g:' . a:prefix 10 | for [key, Value] in items(a:default) 11 | let name = prefix . '#' . key 12 | if !exists(name) 13 | execute 'let ' . name . ' = ' . string(Value) 14 | endif 15 | unlet Value 16 | endfor 17 | endfunction 18 | 19 | function! s:config(scriptfile, default) abort 20 | let prefix = s:translate(a:scriptfile) 21 | call s:define(prefix, a:default) 22 | endfunction 23 | 24 | function! s:translate(scriptfile) abort 25 | let path = fnamemodify(a:scriptfile, ':gs?\\?/?') 26 | let name = matchstr(path, printf( 27 | \ 'autoload/\zs\%%(%s\.vim\|%s/.*\)$', 28 | \ s:plugin_name, 29 | \ s:plugin_name, 30 | \)) 31 | let name = substitute(name, '\.vim$', '', '') 32 | let name = substitute(name, '/', '#', 'g') 33 | let name = substitute(name, '\%(^#\|#$\)', '', 'g') 34 | return 'g:' . name 35 | endfunction 36 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Data/List/Chunker.vim: -------------------------------------------------------------------------------- 1 | function! s:new(size, candidates) abort 2 | return { 3 | \ '__cursor': 0, 4 | \ 'next': function('s:_chunker_next', [a:size, a:candidates]), 5 | \} 6 | endfunction 7 | 8 | function! s:_chunker_next(size, candidates) abort dict 9 | let prev_cursor = self.__cursor 10 | let self.__cursor = self.__cursor + a:size 11 | return a:candidates[ prev_cursor : (self.__cursor - 1) ] 12 | endfunction 13 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Lambda.vim: -------------------------------------------------------------------------------- 1 | function! s:void(...) abort 2 | endfunction 3 | 4 | function! s:pass(value, ...) abort 5 | return a:value 6 | endfunction 7 | 8 | function! s:let(object, key, value) abort 9 | let a:object[a:key] = a:value 10 | endfunction 11 | 12 | function! s:unlet(object, key, ...) abort 13 | let force = a:0 ? a:1 : 0 14 | if (a:0 ? a:1 : 0) is# 1 15 | silent! unlet! a:object[a:key] 16 | else 17 | unlet a:object[a:key] 18 | endif 19 | endfunction 20 | 21 | function! s:throw(message) abort 22 | throw a:message 23 | endfunction 24 | 25 | function! s:echo(message) abort 26 | echo a:message 27 | endfunction 28 | 29 | function! s:echomsg(message) abort 30 | echomsg a:message 31 | endfunction 32 | 33 | function! s:if(condition, true, ...) abort 34 | if a:condition 35 | return a:true() 36 | elseif a:0 37 | return a:1() 38 | endif 39 | endfunction 40 | 41 | function! s:map(list, fn) abort 42 | return map(copy(a:list), { k, v -> a:fn(v, k) }) 43 | endfunction 44 | 45 | function! s:filter(list, fn) abort 46 | return filter(copy(a:list), { k, v -> a:fn(v, k) }) 47 | endfunction 48 | 49 | function! s:reduce(list, fn, ...) abort 50 | let accumulator = a:0 ? a:1 : a:list[0] 51 | let offset = a:0 ? 0 : 1 52 | for index in range(len(a:list) - offset) 53 | let accumulator = a:fn( 54 | \ accumulator, 55 | \ a:list[offset + index], 56 | \ offset + index, 57 | \) 58 | endfor 59 | return accumulator 60 | endfunction 61 | 62 | function! s:map_f(fn) abort 63 | return { list -> s:map(list, a:fn) } 64 | endfunction 65 | 66 | function! s:filter_f(fn) abort 67 | return { list -> s:filter(list, a:fn) } 68 | endfunction 69 | 70 | function! s:reduce_f(fn, ...) abort 71 | let args = a:000 72 | return { list -> call('s:reduce', [list, a:fn] + args) } 73 | endfunction 74 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Path.vim: -------------------------------------------------------------------------------- 1 | function! s:simplify(path) abort 2 | let terms = s:_split(a:path) 3 | let path = join(s:_simplify(terms), '/') 4 | let prefix = a:path[:0] ==# '/' && path[:2] !=# '../' ? '/' : '' 5 | return prefix . path 6 | endfunction 7 | 8 | function! s:commonpath(paths) abort 9 | if !empty(filter(copy(a:paths), 'v:val[:0] !=# ''/''')) 10 | throw printf('Path: path in {paths} must be an absolute path: %s', a:paths) 11 | endif 12 | let path = s:_commonpath(map( 13 | \ copy(a:paths), 14 | \ 's:_split(v:val)' 15 | \)) 16 | return '/' . join(path, '/') 17 | endfunction 18 | 19 | function! s:absolute(path, base) abort 20 | if a:base[:0] !=# '/' 21 | throw printf('Path: {base} ("%s") must be an absolute path', a:base) 22 | elseif a:path[:0] ==# '/' 23 | return a:path 24 | endif 25 | let path = s:_split(a:path) 26 | let base = s:_split(a:base) 27 | let abspath = join(s:_simplify(base + path), '/') 28 | if abspath[:2] ==# '../' 29 | throw printf('Path: {path} (%s) beyonds {base} (%s)', a:path, a:base) 30 | endif 31 | return '/' . abspath 32 | endfunction 33 | 34 | function! s:relative(path, base) abort 35 | if a:base[:0] !=# '/' 36 | throw printf('Path: {base} ("%s") must be an absolute path', a:base) 37 | elseif a:path[:0] !=# '/' 38 | return a:path 39 | endif 40 | let path = s:_split(a:path) 41 | let base = s:_split(a:base) 42 | return join(s:_relative(path, base), '/') 43 | endfunction 44 | 45 | function! s:basename(path) abort 46 | if empty(a:path) || a:path ==# '/' 47 | return a:path 48 | endif 49 | let terms = s:_split(a:path) 50 | return terms[-1] 51 | endfunction 52 | 53 | function! s:dirname(path) abort 54 | if empty(a:path) || a:path ==# '/' 55 | return a:path 56 | endif 57 | let terms = s:_split(a:path)[:-2] 58 | let path = join(s:_simplify(terms), '/') 59 | let prefix = a:path[:0] ==# '/' && path[:2] !=# '../' ? '/' : '' 60 | return prefix . path 61 | endfunction 62 | 63 | function! s:_split(path) abort 64 | return filter(split(a:path, '/'), '!empty(v:val)') 65 | endfunction 66 | 67 | function! s:_simplify(path) abort 68 | let result = [] 69 | for term in a:path 70 | if term ==# '..' 71 | if empty(result) || result[-1] ==# '..' 72 | call insert(result, '..', 0) 73 | else 74 | call remove(result, -1) 75 | endif 76 | elseif term ==# '.' || empty(term) 77 | continue 78 | else 79 | call add(result, term) 80 | endif 81 | endfor 82 | return result 83 | endfunction 84 | 85 | function! s:_commonpath(paths) abort 86 | let paths = map(copy(a:paths), { -> s:_simplify(v:val) }) 87 | let common = [] 88 | for index in range(min(map(copy(paths), { -> len(v:val) }))) 89 | let term = paths[0][index] 90 | if empty(filter(paths[1:], { -> v:val[index] !=? term })) 91 | call add(common, term) 92 | endif 93 | endfor 94 | return common 95 | endfunction 96 | 97 | function! s:_relative(path, base) abort 98 | let path = s:_simplify(a:path) 99 | let base = s:_simplify(a:base) 100 | for index in range(min([len(path), len(base)])) 101 | if path[0] !=? base[0] 102 | break 103 | endif 104 | call remove(path, 0) 105 | call remove(base, 0) 106 | endfor 107 | let prefix = repeat(['..'], len(base)) 108 | return prefix + path 109 | endfunction 110 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Path/Filepath.vim: -------------------------------------------------------------------------------- 1 | let s:is_windows = has('win32') 2 | 3 | function! s:get_is_windows() abort 4 | return s:is_windows 5 | endfunction 6 | 7 | function! s:set_is_windows(is_windows) abort 8 | let s:is_windows = a:is_windows 9 | endfunction 10 | 11 | function! s:to_slash(path) abort 12 | return s:is_windows 13 | \ ? s:_to_slash_windows(a:path) 14 | \ : s:_to_slash_unix(a:path) 15 | endfunction 16 | 17 | function! s:from_slash(path) abort 18 | return s:is_windows 19 | \ ? s:_from_slash_windows(a:path) 20 | \ : s:_to_slash_unix(a:path) 21 | endfunction 22 | 23 | function! s:is_root(path) abort 24 | return s:is_windows 25 | \ ? a:path ==# '' 26 | \ : a:path ==# '/' 27 | endfunction 28 | 29 | function! s:is_drive_root(path) abort 30 | return s:is_windows 31 | \ ? a:path =~# '^\w:\\$' 32 | \ : a:path ==# '/' 33 | endfunction 34 | 35 | function! s:is_absolute(path) abort 36 | return s:is_windows 37 | \ ? s:_is_absolute_windows(a:path) 38 | \ : s:_is_absolute_unix(a:path) 39 | endfunction 40 | 41 | function! s:join(paths) abort 42 | let paths = map( 43 | \ copy(a:paths), 44 | \ 's:to_slash(v:val)', 45 | \) 46 | return s:from_slash(join(paths, '/')) 47 | endfunction 48 | 49 | function! s:_to_slash_windows(path) abort 50 | let prefix = s:_is_absolute_windows(a:path) ? '/' : '' 51 | let terms = filter(split(a:path, '\\'), '!empty(v:val)') 52 | return prefix . join(terms, '/') 53 | endfunction 54 | 55 | function! s:_to_slash_unix(path) abort 56 | if empty(a:path) 57 | return '/' 58 | endif 59 | let prefix = s:_is_absolute_unix(a:path) ? '/' : '' 60 | let terms = filter(split(a:path, '/'), '!empty(v:val)') 61 | return prefix . join(terms, '/') 62 | endfunction 63 | 64 | function! s:_from_slash_windows(path) abort 65 | let terms = filter(split(a:path, '/'), '!empty(v:val)') 66 | let path = join(terms, '\') 67 | return path[:2] =~# '^\w:$' ? path . '\' : path 68 | endfunction 69 | 70 | function! s:_is_absolute_windows(path) abort 71 | return a:path ==# '' || a:path[:2] =~# '^\w:\\$' 72 | endfunction 73 | 74 | function! s:_is_absolute_unix(path) abort 75 | return a:path ==# '' || a:path[:0] ==# '/' 76 | endfunction 77 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Prompt.vim: -------------------------------------------------------------------------------- 1 | let s:ESCAPE_MARKER = sha256(expand('')) 2 | 3 | function! s:input(prompt, ...) abort 4 | let text = a:0 > 0 ? a:1 : '' 5 | let comp = a:0 > 1 6 | \ ? type(a:2) is# v:t_func ? 'customlist,' . get(a:2, 'name') : a:2 7 | \ : v:null 8 | let default = a:0 > 2 ? a:3 : v:null 9 | let args = comp is# v:null ? [text] : [text, comp] 10 | try 11 | execute printf( 12 | \ 'silent cnoremap %s', 13 | \ s:ESCAPE_MARKER, 14 | \) 15 | let result = call('input', [a:prompt] + args) 16 | return result ==# s:ESCAPE_MARKER ? default : result 17 | finally 18 | silent cunmap 19 | endtry 20 | endfunction 21 | 22 | function! s:ask(...) abort 23 | call inputsave() 24 | try 25 | echohl Question 26 | return call('s:input', a:000) 27 | finally 28 | echohl None 29 | call inputrestore() 30 | redraw | echo 31 | endtry 32 | endfunction 33 | 34 | function! s:confirm(prompt, ...) abort 35 | let default = a:0 ? (a:1 ? 'yes' : 'no') : v:null 36 | call inputsave() 37 | echohl Question 38 | try 39 | let r = '' 40 | while r !~? '^\%(y\%[es]\|n\%[o]\)$' 41 | let r = s:input(a:prompt, '', funcref('s:_confirm_complete')) 42 | if r is# v:null 43 | return v:null 44 | endif 45 | let r = r ==# '' ? default : r 46 | endwhile 47 | return r =~? 'y\%[es]' 48 | finally 49 | echohl None 50 | call inputrestore() 51 | redraw | echo 52 | endtry 53 | endfunction 54 | 55 | function! s:select(prompt, ...) abort 56 | let max = a:0 > 0 ? a:1 : 1 57 | let min = a:0 > 1 ? a:2 : 1 58 | let pat = a:0 > 2 ? a:3 : '\d' 59 | let buffer = '' 60 | call inputsave() 61 | echohl Question 62 | try 63 | while len(buffer) < max 64 | redraw | echo 65 | echo a:prompt . buffer 66 | let c = nr2char(getchar()) 67 | if c ==# "\" && len(buffer) >= min 68 | return buffer 69 | elseif c ==# "\" 70 | return v:null 71 | elseif c =~# pat 72 | let buffer .= c 73 | endif 74 | endwhile 75 | return buffer 76 | finally 77 | echohl None 78 | call inputrestore() 79 | endtry 80 | endfunction 81 | 82 | function! s:_confirm_complete(arglead, cmdline, cursorpos) abort 83 | return filter(['yes', 'no'], { -> v:val =~? '^' . a:arglead }) 84 | endfunction 85 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/System/Job.vim: -------------------------------------------------------------------------------- 1 | let s:t_string = type('') 2 | let s:t_list = type([]) 3 | 4 | function! s:_vital_loaded(V) abort 5 | if has('nvim') 6 | let s:Job = a:V.import('System.Job.Neovim') 7 | else 8 | let s:Job = a:V.import('System.Job.Vim') 9 | endif 10 | endfunction 11 | 12 | function! s:_vital_depends() abort 13 | return [ 14 | \ 'System.Job.Vim', 15 | \ 'System.Job.Neovim', 16 | \] 17 | endfunction 18 | 19 | " Note: 20 | " Vim does not raise E902 on Unix system even the prog is not found so use a 21 | " custom exception instead to make the method compatible. 22 | " Note: 23 | " Vim/Neovim treat String a bit differently so prohibit String as well 24 | function! s:_validate_args(args) abort 25 | if type(a:args) != s:t_list 26 | throw 'vital: System.Job: Argument requires to be a List instance.' 27 | endif 28 | if len(a:args) == 0 29 | throw 'vital: System.Job: Argument vector must have at least one item.' 30 | endif 31 | let prog = a:args[0] 32 | if !executable(prog) 33 | throw printf('vital: System.Job: "%s" is not an executable', prog) 34 | endif 35 | endfunction 36 | 37 | function! s:is_available() abort 38 | return s:Job.is_available() 39 | endfunction 40 | 41 | function! s:start(args, ...) abort 42 | call s:_validate_args(a:args) 43 | return s:Job.start(a:args, a:0 ? a:1 : {}) 44 | endfunction 45 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/System/Job/Neovim.vim: -------------------------------------------------------------------------------- 1 | " http://vim-jp.org/blog/2016/03/23/take-care-of-patch-1577.html 2 | function! s:is_available() abort 3 | return has('nvim') && has('nvim-0.2.0') 4 | endfunction 5 | 6 | function! s:start(args, options) abort 7 | let job = extend(copy(s:job), a:options) 8 | let job_options = {} 9 | if has_key(a:options, 'cwd') 10 | let job_options.cwd = a:options.cwd 11 | endif 12 | if has_key(a:options, 'env') 13 | let job_options.env = a:options.env 14 | endif 15 | if has_key(job, 'on_stdout') 16 | let job_options.on_stdout = funcref('s:_on_stdout', [job]) 17 | endif 18 | if has_key(job, 'on_stderr') 19 | let job_options.on_stderr = funcref('s:_on_stderr', [job]) 20 | endif 21 | if has_key(job, 'on_exit') 22 | let job_options.on_exit = funcref('s:_on_exit', [job]) 23 | else 24 | let job_options.on_exit = funcref('s:_on_exit_raw', [job]) 25 | endif 26 | let job.__job = jobstart(a:args, job_options) 27 | let job.__pid = s:_jobpid_safe(job.__job) 28 | let job.__exitval = v:null 29 | let job.args = a:args 30 | return job 31 | endfunction 32 | 33 | if has('nvim-0.3.0') 34 | " Neovim 0.3.0 and over seems to invoke on_stdout/on_stderr with an empty 35 | " string data when the stdout/stderr channel has closed. 36 | " It is different behavior from Vim and Neovim prior to 0.3.0 so remove an 37 | " empty string list to keep compatibility. 38 | function! s:_on_stdout(job, job_id, data, event) abort 39 | if a:data == [''] 40 | return 41 | endif 42 | call a:job.on_stdout(a:data) 43 | endfunction 44 | 45 | function! s:_on_stderr(job, job_id, data, event) abort 46 | if a:data == [''] 47 | return 48 | endif 49 | call a:job.on_stderr(a:data) 50 | endfunction 51 | else 52 | function! s:_on_stdout(job, job_id, data, event) abort 53 | call a:job.on_stdout(a:data) 54 | endfunction 55 | 56 | function! s:_on_stderr(job, job_id, data, event) abort 57 | call a:job.on_stderr(a:data) 58 | endfunction 59 | endif 60 | 61 | function! s:_on_exit(job, job_id, exitval, event) abort 62 | let a:job.__exitval = a:exitval 63 | call a:job.on_exit(a:exitval) 64 | endfunction 65 | 66 | function! s:_on_exit_raw(job, job_id, exitval, event) abort 67 | let a:job.__exitval = a:exitval 68 | endfunction 69 | 70 | function! s:_jobpid_safe(job) abort 71 | try 72 | return jobpid(a:job) 73 | catch /^Vim\%((\a\+)\)\=:E900/ 74 | " NOTE: 75 | " Vim does not raise exception even the job has already closed so fail 76 | " silently for 'E900: Invalid job id' exception 77 | return 0 78 | endtry 79 | endfunction 80 | 81 | " Instance ------------------------------------------------------------------- 82 | function! s:_job_id() abort dict 83 | if &verbose 84 | echohl WarningMsg 85 | echo 'vital: System.Job: job.id() is deprecated. Use job.pid() instead.' 86 | echohl None 87 | endif 88 | return self.pid() 89 | endfunction 90 | 91 | function! s:_job_pid() abort dict 92 | return self.__pid 93 | endfunction 94 | 95 | function! s:_job_status() abort dict 96 | try 97 | sleep 1m 98 | call jobpid(self.__job) 99 | return 'run' 100 | catch /^Vim\%((\a\+)\)\=:E900/ 101 | return 'dead' 102 | endtry 103 | endfunction 104 | 105 | if exists('*chansend') " Neovim 0.2.3 106 | function! s:_job_send(data) abort dict 107 | return chansend(self.__job, a:data) 108 | endfunction 109 | else 110 | function! s:_job_send(data) abort dict 111 | return jobsend(self.__job, a:data) 112 | endfunction 113 | endif 114 | 115 | if exists('*chanclose') " Neovim 0.2.3 116 | function! s:_job_close() abort dict 117 | call chanclose(self.__job, 'stdin') 118 | endfunction 119 | else 120 | function! s:_job_close() abort dict 121 | call jobclose(self.__job, 'stdin') 122 | endfunction 123 | endif 124 | 125 | function! s:_job_stop() abort dict 126 | try 127 | call jobstop(self.__job) 128 | catch /^Vim\%((\a\+)\)\=:E900/ 129 | " NOTE: 130 | " Vim does not raise exception even the job has already closed so fail 131 | " silently for 'E900: Invalid job id' exception 132 | endtry 133 | endfunction 134 | 135 | function! s:_job_wait(...) abort dict 136 | let timeout = a:0 ? a:1 : v:null 137 | let exitval = timeout is# v:null 138 | \ ? jobwait([self.__job])[0] 139 | \ : jobwait([self.__job], timeout)[0] 140 | if exitval != -3 141 | return exitval 142 | endif 143 | " Wait until 'on_exit' callback is called 144 | while self.__exitval is# v:null 145 | sleep 1m 146 | endwhile 147 | return self.__exitval 148 | endfunction 149 | 150 | " To make debug easier, use funcref instead. 151 | let s:job = { 152 | \ 'id': funcref('s:_job_id'), 153 | \ 'pid': funcref('s:_job_pid'), 154 | \ 'status': funcref('s:_job_status'), 155 | \ 'send': funcref('s:_job_send'), 156 | \ 'close': funcref('s:_job_close'), 157 | \ 'stop': funcref('s:_job_stop'), 158 | \ 'wait': funcref('s:_job_wait'), 159 | \} 160 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/System/Job/Vim.vim: -------------------------------------------------------------------------------- 1 | " https://github.com/neovim/neovim/blob/f629f83/src/nvim/event/process.c#L24-L26 2 | let s:KILL_TIMEOUT_MS = 2000 3 | 4 | function! s:is_available() abort 5 | return !has('nvim') && has('patch-8.0.0027') 6 | endfunction 7 | 8 | function! s:start(args, options) abort 9 | let job = extend(copy(s:job), a:options) 10 | let job_options = { 11 | \ 'mode': 'raw', 12 | \ 'timeout': 0, 13 | \} 14 | if has('patch-8.1.889') 15 | let job_options['noblock'] = 1 16 | endif 17 | if has_key(job, 'on_stdout') 18 | let job_options.out_cb = funcref('s:_out_cb', [job]) 19 | else 20 | let job_options.out_io = 'null' 21 | endif 22 | if has_key(job, 'on_stderr') 23 | let job_options.err_cb = funcref('s:_err_cb', [job]) 24 | else 25 | let job_options.err_io = 'null' 26 | endif 27 | if has_key(job, 'on_exit') 28 | let job_options.exit_cb = funcref('s:_exit_cb', [job]) 29 | endif 30 | if has_key(job, 'cwd') && has('patch-8.0.0902') 31 | let job_options.cwd = job.cwd 32 | endif 33 | if has_key(job, 'env') && has('patch-8.0.0902') 34 | let job_options.env = job.env 35 | endif 36 | let job.__job = job_start(a:args, job_options) 37 | let job.args = a:args 38 | return job 39 | endfunction 40 | 41 | function! s:_out_cb(job, channel, msg) abort 42 | call a:job.on_stdout(split(a:msg, "\n", 1)) 43 | endfunction 44 | 45 | function! s:_err_cb(job, channel, msg) abort 46 | call a:job.on_stderr(split(a:msg, "\n", 1)) 47 | endfunction 48 | 49 | function! s:_exit_cb(job, channel, exitval) abort 50 | " Make sure on_stdout/on_stderr are called prior to on_exit. 51 | if has_key(a:job, 'on_stdout') 52 | let options = {'part': 'out'} 53 | while ch_status(a:channel, options) ==# 'open' 54 | sleep 1m 55 | endwhile 56 | while ch_status(a:channel, options) ==# 'buffered' 57 | call s:_out_cb(a:job, a:channel, ch_readraw(a:channel, options)) 58 | endwhile 59 | endif 60 | if has_key(a:job, 'on_stderr') 61 | let options = {'part': 'err'} 62 | while ch_status(a:channel, options) ==# 'open' 63 | sleep 1m 64 | endwhile 65 | while ch_status(a:channel, options) ==# 'buffered' 66 | call s:_err_cb(a:job, a:channel, ch_readraw(a:channel, options)) 67 | endwhile 68 | endif 69 | call a:job.on_exit(a:exitval) 70 | endfunction 71 | 72 | 73 | " Instance ------------------------------------------------------------------- 74 | function! s:_job_id() abort dict 75 | if &verbose 76 | echohl WarningMsg 77 | echo 'vital: System.Job: job.id() is deprecated. Use job.pid() instead.' 78 | echohl None 79 | endif 80 | return self.pid() 81 | endfunction 82 | 83 | function! s:_job_pid() abort dict 84 | return job_info(self.__job).process 85 | endfunction 86 | 87 | " NOTE: 88 | " On Unix a non-existing command results in "dead" instead 89 | " So returns "dead" instead of "fail" even in non Unix. 90 | function! s:_job_status() abort dict 91 | let status = job_status(self.__job) 92 | return status ==# 'fail' ? 'dead' : status 93 | endfunction 94 | 95 | " NOTE: 96 | " A Null character (\0) is used as a terminator of a string in Vim. 97 | " Neovim can send \0 by using \n splitted list but in Vim. 98 | " So replace all \n in \n splitted list to '' 99 | function! s:_job_send(data) abort dict 100 | let data = type(a:data) == v:t_list 101 | \ ? join(map(a:data, 'substitute(v:val, "\n", '''', ''g'')'), "\n") 102 | \ : a:data 103 | return ch_sendraw(self.__job, data) 104 | endfunction 105 | 106 | function! s:_job_close() abort dict 107 | call ch_close_in(self.__job) 108 | endfunction 109 | 110 | function! s:_job_stop() abort dict 111 | call job_stop(self.__job) 112 | call timer_start(s:KILL_TIMEOUT_MS, { -> job_stop(self.__job, 'kill') }) 113 | endfunction 114 | 115 | function! s:_job_wait(...) abort dict 116 | let timeout = a:0 ? a:1 : v:null 117 | let timeout = timeout is# v:null ? v:null : timeout / 1000.0 118 | let start_time = reltime() 119 | let job = self.__job 120 | try 121 | while timeout is# v:null || timeout > reltimefloat(reltime(start_time)) 122 | let status = job_status(job) 123 | if status !=# 'run' 124 | return status ==# 'dead' ? job_info(job).exitval : -3 125 | endif 126 | sleep 1m 127 | endwhile 128 | catch /^Vim:Interrupt$/ 129 | call self.stop() 130 | return -2 131 | endtry 132 | return -1 133 | endfunction 134 | 135 | " To make debug easier, use funcref instead. 136 | let s:job = { 137 | \ 'id': funcref('s:_job_id'), 138 | \ 'pid': funcref('s:_job_pid'), 139 | \ 'status': funcref('s:_job_status'), 140 | \ 'send': funcref('s:_job_send'), 141 | \ 'close': funcref('s:_job_close'), 142 | \ 'stop': funcref('s:_job_stop'), 143 | \ 'wait': funcref('s:_job_wait'), 144 | \} 145 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/System/Sandbox.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_depends() abort 2 | return [ 3 | \ 'System.File', 4 | \ 'System.Filepath' 5 | \] 6 | endfunction 7 | 8 | function! s:_vital_loaded(V) abort 9 | let s:File = a:V.import('System.File') 10 | let s:Path = a:V.import('System.Filepath') 11 | endfunction 12 | 13 | function! s:new(...) abort 14 | let l:Factory = a:0 ? a:1 : function('tempname') 15 | let sandbox = { 16 | \ '__home': fnamemodify(resolve(Factory()), ':p'), 17 | \ '__origin': fnamemodify(resolve(getcwd()), ':p'), 18 | \ 'origin': funcref('s:_sandbox_origin'), 19 | \ 'path': funcref('s:_sandbox_path'), 20 | \ 'visit': funcref('s:_sandbox_visit'), 21 | \ 'return': funcref('s:_sandbox_return'), 22 | \ 'dispose': funcref('s:_sandbox_dispose'), 23 | \} 24 | call s:File.mkdir_nothrow(sandbox.__home, 'r', 0700) 25 | call sandbox.return() 26 | lockvar 2 sandbox 27 | return sandbox 28 | endfunction 29 | 30 | function! s:_sandbox_origin() abort dict 31 | return self.__origin 32 | endfunction 33 | 34 | function! s:_sandbox_path(...) abort dict 35 | let path = a:0 ? a:1 : '' 36 | if s:Path.is_absolute(path) 37 | throw printf('vital: System.Sandbox: path requires to be a relative path: %s', path) 38 | endif 39 | return resolve(s:Path.join(self.__home, s:Path.realpath(path))) 40 | endfunction 41 | 42 | function! s:_sandbox_visit(path) abort dict 43 | let path = self.path(a:path) 44 | if !isdirectory(path) 45 | call s:File.mkdir_nothrow(path, 'r', 0700) 46 | endif 47 | execute 'cd' fnameescape(path) 48 | endfunction 49 | 50 | function! s:_sandbox_return() abort dict 51 | execute 'cd' fnameescape(self.__home) 52 | endfunction 53 | 54 | function! s:_sandbox_dispose() abort dict 55 | execute 'cd' fnameescape(self.__origin) 56 | call s:File.rmdir(self.__home, 'r') 57 | endfunction 58 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Buffer/ANSI.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_created(module) abort 2 | let s:COLORS = { 3 | \ '\%(30\|0;30\|30;0\)': 'AnsiColor0', 4 | \ '\%(31\|0;31\|31;0\)': 'AnsiColor1', 5 | \ '\%(32\|0;32\|32;0\)': 'AnsiColor2', 6 | \ '\%(33\|0;33\|33;0\)': 'AnsiColor3', 7 | \ '\%(34\|0;34\|34;0\)': 'AnsiColor4', 8 | \ '\%(35\|0;35\|35;0\)': 'AnsiColor5', 9 | \ '\%(36\|0;36\|36;0\)': 'AnsiColor6', 10 | \ '\%(37\|0;37\|37;0\)': 'AnsiColor7', 11 | \ '\%(1;30\|30;1\)': 'AnsiColor8', 12 | \ '\%(1;31\|31;1\)': 'AnsiColor9', 13 | \ '\%(1;32\|32;1\)': 'AnsiColor10', 14 | \ '\%(1;33\|33;1\)': 'AnsiColor11', 15 | \ '\%(1;34\|34;1\)': 'AnsiColor12', 16 | \ '\%(1;35\|35;1\)': 'AnsiColor13', 17 | \ '\%(1;36\|36;1\)': 'AnsiColor14', 18 | \ '\%(1;37\|37;1\)': 'AnsiColor15', 19 | \} 20 | call s:_define_highlight() 21 | endfunction 22 | 23 | function! s:_define_highlight() abort 24 | " Ref: https://github.com/w0ng/vim-hybrid 25 | highlight default AnsiColor0 ctermfg=0 guifg=#282A2E 26 | highlight default AnsiColor1 ctermfg=1 guifg=#A54242 27 | highlight default AnsiColor2 ctermfg=2 guifg=#8C9440 28 | highlight default AnsiColor3 ctermfg=3 guifg=#DE935F 29 | highlight default AnsiColor4 ctermfg=4 guifg=#5F819D 30 | highlight default AnsiColor5 ctermfg=5 guifg=#85678F 31 | highlight default AnsiColor6 ctermfg=6 guifg=#5E8D87 32 | highlight default AnsiColor7 ctermfg=7 guifg=#707880 33 | highlight default AnsiColor8 ctermfg=8 guifg=#373B41 34 | highlight default AnsiColor9 ctermfg=9 guifg=#CC6666 35 | highlight default AnsiColor10 ctermfg=10 guifg=#B5BD68 36 | highlight default AnsiColor11 ctermfg=11 guifg=#F0C674 37 | highlight default AnsiColor12 ctermfg=12 guifg=#81A2BE 38 | highlight default AnsiColor13 ctermfg=13 guifg=#B294BB 39 | highlight default AnsiColor14 ctermfg=14 guifg=#8ABEB7 40 | highlight default AnsiColor15 ctermfg=15 guifg=#C5C8C6 41 | augroup vital_vim_buffer_ansi 42 | autocmd! * 43 | autocmd ColorScheme * call s:_define_highlight() 44 | augroup END 45 | endfunction 46 | 47 | function! s:define_syntax(...) abort 48 | let prefix = get(a:000, 0, '') 49 | execute printf( 50 | \ 'syntax match %sAnsiSuppress conceal /\e\[[0-9A-Z;]*m/', 51 | \ prefix 52 | \) 53 | for [code, name] in items(s:COLORS) 54 | execute printf( 55 | \ 'syn region %s%s contains=%s keepend start=/\e\[%sm/ end=/\e\[[0-9A-Z;]*m/', 56 | \ prefix, name, 'AnsiSuppress', code 57 | \) 58 | execute printf( 59 | \ 'syntax cluster %sAnsiColors add=%s%s', 60 | \ prefix, prefix, name 61 | \) 62 | endfor 63 | setlocal conceallevel=3 concealcursor=nvic 64 | endfunction 65 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Buffer/Group.vim: -------------------------------------------------------------------------------- 1 | let s:groups = {} 2 | 3 | function! s:new(...) abort 4 | let options = extend({ 5 | \ 'on_close_fail': v:null, 6 | \}, get(a:000, 0, {}) 7 | \) 8 | let hash = sha256(reltimestr(reltime())) 9 | let s:groups[hash] = { 10 | \ 'add': function('s:_group_add'), 11 | \ 'close': function('s:_group_close'), 12 | \} 13 | let s:groups[hash].__hash = hash 14 | let s:groups[hash].__tabnr = v:null 15 | let s:groups[hash].__members = [] 16 | let s:groups[hash].__on_close_fail = options.on_close_fail 17 | return s:groups[hash] 18 | endfunction 19 | 20 | function! s:_group_add(...) abort dict 21 | let options = extend({ 22 | \ 'keep': 0, 23 | \ 'expr': '%', 24 | \}, get(a:000, 0, {}) 25 | \) 26 | let bufnr = bufnr(options.expr) 27 | let winid = bufwinid(options.expr) 28 | let tabnr = tabpagenr() 29 | if self.__tabnr is# v:null 30 | let self.__tabnr = tabnr 31 | elseif tabnr != self.__tabnr 32 | throw printf( 33 | \ 'vital: Vim.Buffer.Group: %s', 34 | \ 'A buffer on a different tabpage cannot be added.' 35 | \) 36 | endif 37 | call add(self.__members, { 38 | \ 'bufnr': bufnr, 39 | \ 'winid': winid, 40 | \ 'options': options, 41 | \}) 42 | execute printf('augroup vital_vim_buffer_group_%s', self.__hash) 43 | execute printf('autocmd! * ', bufnr) 44 | execute printf('autocmd WinLeave call s:_on_WinLeave(''%s'')', bufnr, self.__hash) 45 | execute 'augroup END' 46 | endfunction 47 | 48 | function! s:_group_close() abort dict 49 | for member in self.__members 50 | if member.options.keep 51 | continue 52 | endif 53 | let winnr = win_id2win(member.winid) 54 | if winnr == 0 || getbufvar(member.bufnr, '&modified') || bufwinid(member.bufnr) != member.winid 55 | continue 56 | endif 57 | try 58 | execute printf('%dclose', winnr) 59 | catch /^Vim\%((\a\+)\)\=:E444/ 60 | " E444: Cannot close last window may thrown but ignore that 61 | " Vim.Buffer.Group should NOT close the last window so ignore 62 | " this exception silently. 63 | if self.__on_close_fail isnot# v:null 64 | call call(self.__on_close_fail, [winnr, member], self) 65 | endif 66 | endtry 67 | endfor 68 | endfunction 69 | 70 | 71 | function! s:_on_WinLeave(hash) abort 72 | execute 'augroup vital_vim_buffer_group_temporal_' . a:hash 73 | execute 'autocmd! *' 74 | execute printf( 75 | \ 'autocmd WinEnter * nested call s:_on_WinEnter(''%s'', %d)', 76 | \ a:hash, winnr('$'), 77 | \) 78 | execute 'augroup END' 79 | endfunction 80 | 81 | function! s:_on_WinEnter(hash, nwin) abort 82 | execute 'augroup vital_vim_buffer_group_temporal_' . a:hash 83 | execute 'autocmd! *' 84 | execute 'augroup END' 85 | if winnr('$') < a:nwin 86 | call s:groups[a:hash].close() 87 | endif 88 | endfunction 89 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Buffer/Opener.vim: -------------------------------------------------------------------------------- 1 | let s:t_string = type('') 2 | 3 | function! s:_vital_depends() abort 4 | return ['Vim.Buffer', 'Vim.BufferManager'] 5 | endfunction 6 | 7 | function! s:_vital_loaded(V) abort 8 | let s:Buffer = a:V.import('Vim.Buffer') 9 | let s:BufferManager = a:V.import('Vim.BufferManager') 10 | endfunction 11 | 12 | 13 | " Public --------------------------------------------------------------------- 14 | function! s:open(buffer, ...) abort 15 | let config = extend({ 16 | \ 'mods': '', 17 | \ 'cmdarg': '', 18 | \ 'opener': 'edit', 19 | \ 'group': '', 20 | \ 'range': 'tabpage', 21 | \ 'force': 1, 22 | \}, get(a:000, 0, {}) 23 | \) 24 | " validate and normalize {opener} 25 | if type(config.opener) != s:t_string 26 | throw 'vital: Vim.Buffer.Opener: {opener} must be String' 27 | endif 28 | let opener = empty(config.opener) ? 'edit' : config.opener 29 | while opener[0] ==# '=' 30 | let opener = eval(opener[1:]) 31 | endwhile 32 | 33 | let preview = s:is_preview_opener(opener) 34 | let bufloaded = bufloaded(a:buffer) 35 | let bufexists = bufexists(a:buffer) 36 | 37 | try 38 | if empty(config.group) || preview 39 | call s:Buffer.open(a:buffer, { 40 | \ 'mods': config.mods, 41 | \ 'cmdarg': config.cmdarg, 42 | \ 'opener': opener, 43 | \}) 44 | else 45 | let manager = s:_get_buffer_manager(config.group) 46 | call manager.open(a:buffer, { 47 | \ 'mods': config.mods, 48 | \ 'cmdarg': config.cmdarg, 49 | \ 'opener': opener, 50 | \ 'range': config.range, 51 | \}) 52 | endif 53 | catch /^Vim\%((\a\+)\)\=:E325/ 54 | " Silence 'E325: ATTENTION' 55 | endtry 56 | 57 | let context = { 58 | \ 'preview': preview, 59 | \ 'bufloaded': bufloaded, 60 | \ 'bufexists': bufexists, 61 | \} 62 | if config.force && preview 63 | let context.focusto = bufnr('%') 64 | silent wincmd P 65 | endif 66 | let context.bufnr = bufnr('%') 67 | let context.bufname = bufname('%') 68 | return extend(context, s:context) 69 | endfunction 70 | 71 | function! s:is_preview_opener(opener) abort 72 | if a:opener =~# '\' 73 | return 1 74 | elseif a:opener =~# '\' 75 | return 1 76 | elseif a:opener =~# '\' 77 | return 1 78 | endif 79 | return 0 80 | endfunction 81 | 82 | 83 | 84 | " Context -------------------------------------------------------------------- 85 | let s:context = {} 86 | function! s:context.end() abort 87 | let focusto = get(self, 'focusto', -1) 88 | if focusto == -1 || focusto == bufnr('%') 89 | return 90 | endif 91 | silent unlet self.focusto 92 | silent execute 'keepjumps' bufwinnr(focusto) 'wincmd w' 93 | endfunction 94 | 95 | 96 | " Private -------------------------------------------------------------------- 97 | function! s:_get_buffer_manager(group) abort 98 | let group = substitute(a:group, '-', '_', 'g') 99 | if exists('s:_bm_' . group) 100 | return s:_bm_{group} 101 | endif 102 | let s:_bm_{group} = s:BufferManager.new() 103 | return s:_bm_{group} 104 | endfunction 105 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Console.vim: -------------------------------------------------------------------------------- 1 | let s:t_string = type('') 2 | 3 | function! s:_vital_created(module) abort 4 | let a:module.prefix = '' 5 | let a:module.escape_marker = 6 | \ '=======================================' . 7 | \ 'Vital.Vim.Console.ESCAPE.' . localtime() . 8 | \ '=======================================' 9 | endfunction 10 | 11 | function! s:echo(msg, ...) abort dict 12 | let hl = get(a:000, 0, 'None') 13 | let msg = s:_ensure_string(a:msg) 14 | let msg = s:_assign_prefix(a:msg, self.prefix) 15 | execute 'echohl' hl 16 | echo msg 17 | echohl None 18 | endfunction 19 | 20 | function! s:echon(msg, ...) abort dict 21 | let hl = get(a:000, 0, 'None') 22 | let msg = s:_ensure_string(a:msg) 23 | execute 'echohl' hl 24 | echon msg 25 | echohl None 26 | endfunction 27 | 28 | function! s:echomsg(msg, ...) abort dict 29 | let hl = get(a:000, 0, 'None') 30 | let msg = s:_ensure_string(a:msg) 31 | let msg = s:_assign_prefix(a:msg, self.prefix) 32 | execute 'echohl' hl 33 | for line in split(msg, '\r\?\n') 34 | echomsg line 35 | endfor 36 | echohl None 37 | endfunction 38 | 39 | function! s:input(hl, msg, ...) abort dict 40 | let msg = s:_ensure_string(a:msg) 41 | let msg = s:_assign_prefix(a:msg, self.prefix) 42 | let text = get(a:000, 0, '') 43 | if a:0 > 1 44 | let args = [ 45 | \ type(a:2) == s:t_string 46 | \ ? a:2 47 | \ : 'customlist,' . get(a:2, 'name') 48 | \] 49 | else 50 | let args = [] 51 | endif 52 | execute 'echohl' a:hl 53 | call inputsave() 54 | try 55 | return call('s:_input', [msg, text] + args, self) 56 | finally 57 | redraw | echo '' 58 | echohl None 59 | call inputrestore() 60 | endtry 61 | endfunction 62 | 63 | function! s:inputlist(hl, textlist) abort dict 64 | let textlist = map(copy(a:textlist), 's:_ensure_string(v:val)') 65 | execute 'echohl' a:hl 66 | call inputsave() 67 | try 68 | return inputlist(textlist) 69 | finally 70 | redraw | echo '' 71 | echohl None 72 | call inputrestore() 73 | endtry 74 | endfunction 75 | 76 | function! s:debug(msg) abort dict 77 | if !&verbose 78 | return 79 | endif 80 | call self.echomsg(a:msg, 'Comment') 81 | endfunction 82 | 83 | function! s:info(msg) abort dict 84 | let v:statusmsg = s:_ensure_string(a:msg) 85 | call self.echomsg(a:msg, 'Title') 86 | endfunction 87 | 88 | function! s:warn(msg) abort dict 89 | let v:warningmsg = s:_ensure_string(a:msg) 90 | call self.echomsg(a:msg, 'WarningMsg') 91 | endfunction 92 | 93 | function! s:error(msg) abort dict 94 | let v:errmsg = s:_ensure_string(a:msg) 95 | call self.echomsg(a:msg, 'ErrorMsg') 96 | endfunction 97 | 98 | function! s:ask(...) abort dict 99 | let result = call('s:input', ['Question'] + a:000, self) 100 | redraw 101 | return result 102 | endfunction 103 | 104 | function! s:select(msg, candidates, ...) abort dict 105 | let canceled = get(a:000, 0, '') 106 | let candidates = map( 107 | \ copy(a:candidates), 108 | \ 'v:key+1 . ''. '' . s:_ensure_string(v:val)' 109 | \) 110 | let result = self.inputlist('Question', [a:msg] + candidates) 111 | redraw 112 | return result <= 0 || result > len(a:candidates) ? canceled : a:candidates[result-1] 113 | endfunction 114 | 115 | function! s:confirm(msg, ...) abort dict 116 | call inputsave() 117 | echohl Question 118 | try 119 | let default = get(a:000, 0, '') 120 | if default !~? '^\%(y\%[es]\|n\%[o]\|\)$' 121 | throw 'vital: Vim.Console: An invalid default value has specified.' 122 | endif 123 | let choices = default =~? 'y\%[es]' 124 | \ ? 'Y[es]/n[o]' 125 | \ : default =~? 'n\%[o]' 126 | \ ? 'y[es]/N[o]' 127 | \ : 'y[es]/n[o]' 128 | let result = 'invalid' 129 | let prompt = printf('%s (%s): ', a:msg, choices) 130 | let completion = 'customlist,' . get(function('s:_confirm_complete'), 'name') 131 | while result !~? '^\%(y\%[es]\|n\%[o]\)$' 132 | let result = call('s:_input', [prompt, '', completion], self) 133 | if type(result) != s:t_string 134 | redraw | echo '' 135 | call self.echo('Canceled.', 'WarningMsg') 136 | return 0 137 | endif 138 | let result = empty(result) ? default : result 139 | endwhile 140 | redraw | echo '' 141 | return result =~? 'y\%[es]' 142 | finally 143 | echohl None 144 | call inputrestore() 145 | endtry 146 | endfunction 147 | 148 | function! s:_input(...) abort dict 149 | try 150 | execute printf( 151 | \ 'silent cnoremap %s', 152 | \ self.escape_marker, 153 | \) 154 | let result = call('input', a:000) 155 | return result ==# self.escape_marker ? 0 : result 156 | finally 157 | silent cunmap 158 | endtry 159 | endfunction 160 | 161 | function! s:_confirm_complete(arglead, cmdline, cursorpos) abort 162 | return filter(['yes', 'no'], 'v:val =~# ''^'' . a:arglead') 163 | endfunction 164 | 165 | function! s:_ensure_string(x) abort 166 | return type(a:x) == s:t_string ? a:x : string(a:x) 167 | endfunction 168 | 169 | function! s:_assign_prefix(msg, prefix) abort 170 | return join(map(split(a:msg, '\r\?\n'), 'a:prefix . v:val'), "\n") 171 | endfunction 172 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Highlight.vim: -------------------------------------------------------------------------------- 1 | function! s:get(...) abort 2 | let name = a:0 ? a:1 : '' 3 | let records = split(s:_highlight(name), '\r\?\n') 4 | let highlights = map(records, 's:_parse_record(v:val)') 5 | let highlights = filter(highlights, '!empty(v:val)') 6 | return a:0 ? highlights[0] : highlights 7 | endfunction 8 | 9 | function! s:set(highlight, ...) abort 10 | let options = extend({ 11 | \ 'force': 0, 12 | \ 'default': 0, 13 | \}, get(a:000, 0, {}) 14 | \) 15 | let name = a:highlight.name 16 | let force = options.force ? '!' : '' 17 | let default = options.default ? 'default' : '' 18 | if get(a:highlight.attrs, 'clear') 19 | execute 'highlight' 'clear' name 20 | elseif !empty(get(a:highlight.attrs, 'link')) 21 | execute 'highlight' . force default 'link' name a:highlight.attrs.link 22 | else 23 | let attrs = map(items(a:highlight.attrs), 'v:val[0] . ''='' . v:val[1]') 24 | execute 'highlight' default name join(attrs) 25 | endif 26 | endfunction 27 | 28 | 29 | function! s:_parse_record(record) abort 30 | let m = matchlist(a:record, '^\(\S\+\)\s\+xxx\s\(.*\)$') 31 | if empty(m) 32 | return {} 33 | endif 34 | let name = m[1] 35 | let attrs = s:_parse_attrs(m[2]) 36 | return {'name': name, 'attrs': attrs} 37 | endfunction 38 | 39 | function! s:_parse_attrs(attrs) abort 40 | if a:attrs ==# 'cleared' 41 | return { 'cleared': 1 } 42 | elseif a:attrs =~# '^links to' 43 | return { 'link': matchstr(a:attrs, 'links to \zs.*') } 44 | endif 45 | let attrs = {} 46 | for term in split(a:attrs, ' ') 47 | let m = split(term, '=') 48 | if len(m) < 2 49 | continue 50 | endif 51 | let attrs[m[0]] = join(m[1:], '=') 52 | endfor 53 | return attrs 54 | endfunction 55 | 56 | function! s:_highlight(name) abort 57 | return execute(printf('highlight %s', a:name)) 58 | endfunction 59 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Window.vim: -------------------------------------------------------------------------------- 1 | let s:t_string = type('') 2 | let s:DEFAULT_OPTIONS = { 3 | \ 'range': 'tabpage', 4 | \} 5 | 6 | function! s:focus_window(expr, ...) abort 7 | let options = extend(copy(s:DEFAULT_OPTIONS), a:0 ? a:1 : {}) 8 | let winid = s:_find_nearest_window_winid(a:expr, options.range) 9 | if winid == 0 10 | return v:null 11 | endif 12 | let guard = copy(s:guard) 13 | let guard.winid = win_getid() 14 | if winid != guard.winid 15 | call win_gotoid(winid) 16 | endif 17 | return guard 18 | endfunction 19 | 20 | function! s:focus_buffer(expr, ...) abort 21 | let options = extend(copy(s:DEFAULT_OPTIONS), a:0 ? a:1 : {}) 22 | let winid = s:_find_nearest_buffer_winid(a:expr, options.range) 23 | if winid == 0 24 | return v:null 25 | endif 26 | let guard = copy(s:guard) 27 | let guard.winid = win_getid() 28 | if winid != guard.winid 29 | call win_gotoid(winid) 30 | endif 31 | return guard 32 | endfunction 33 | 34 | 35 | " Guard ---------------------------------------------------------------------- 36 | let s:guard = {} 37 | 38 | function! s:guard.restore() abort 39 | let winid = self.winid 40 | if winid != win_getid() 41 | call win_gotoid(winid) 42 | endif 43 | endfunction 44 | 45 | 46 | " Private -------------------------------------------------------------------- 47 | function! s:_find_nearest_window_winid(expr, range) abort 48 | let ntabpages = tabpagenr('$') 49 | if a:range ==# 'tabpage' || ntabpages == 1 50 | return win_getid(type(a:expr) == s:t_string ? winnr(a:expr) : a:expr) 51 | endif 52 | let l:Distance = function('s:_distance', [tabpagenr()]) 53 | for tabpagenr in sort(range(1, ntabpages), Distance) 54 | let winnr = type(a:expr) == s:t_string 55 | \ ? tabpagewinnr(tabpagenr, a:expr) 56 | \ : a:expr 57 | if winnr > 0 && winnr <= tabpagewinnr(tabpagenr, '$') 58 | return win_getid(winnr, tabpagenr) 59 | endif 60 | endfor 61 | return 0 62 | endfunction 63 | 64 | function! s:_find_nearest_buffer_winid(expr, range) abort 65 | let bufnr = type(a:expr) == s:t_string ? bufnr(a:expr) : a:expr 66 | let ntabpages = tabpagenr('$') 67 | if a:range ==# 'tabpage' || ntabpages == 1 68 | return win_getid(bufwinnr(bufnr)) 69 | endif 70 | let l:Distance = function('s:_distance', [tabpagenr()]) 71 | for tabpagenr in sort(range(1, ntabpages), Distance) 72 | let s:base = tabpagewinnr(tabpagenr) 73 | let buflist = tabpagebuflist(tabpagenr) 74 | for winnr in sort(range(1, len(buflist)), Distance) 75 | if buflist[winnr - 1] == bufnr 76 | return win_getid(winnr, tabpagenr) 77 | endif 78 | endfor 79 | endfor 80 | return 0 81 | endfunction 82 | 83 | function! s:_distance(base, a, b) abort 84 | return abs(a:a - a:base) - abs(a:b - a:base) 85 | endfunction 86 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Window/Cursor.vim: -------------------------------------------------------------------------------- 1 | if !exists('*nvim_win_get_cursor') 2 | function! s:get_cursor(winid) abort 3 | if win_getid() is# a:winid 4 | let cursor = getpos('.') 5 | return [cursor[1], cursor[2] - 1] 6 | else 7 | let winid_saved = win_getid() 8 | try 9 | noautocmd call win_gotoid(a:winid) 10 | return s:get_cursor(a:winid) 11 | finally 12 | noautocmd call win_gotoid(winid_saved) 13 | endtry 14 | endif 15 | endfunction 16 | else 17 | function! s:get_cursor(winid) abort 18 | return nvim_win_get_cursor(a:winid) 19 | endfunction 20 | endif 21 | 22 | if !exists('*nvim_win_set_cursor') 23 | function! s:set_cursor(winid, pos) abort 24 | if win_getid() is# a:winid 25 | let cursor = [0, a:pos[0], a:pos[1] + 1, 0] 26 | call setpos('.', cursor) 27 | else 28 | let winid_saved = win_getid() 29 | try 30 | noautocmd call win_gotoid(a:winid) 31 | call s:set_cursor(a:winid, a:pos) 32 | finally 33 | noautocmd call win_gotoid(winid_saved) 34 | endtry 35 | endif 36 | endfunction 37 | else 38 | function! s:set_cursor(winid, pos) abort 39 | try 40 | call nvim_win_set_cursor(a:winid, a:pos) 41 | catch /Cursor position outside buffer/ 42 | " Do nothing 43 | endtry 44 | endfunction 45 | endif 46 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Window/Locator.vim: -------------------------------------------------------------------------------- 1 | let s:UNIQUE = sha256(expand(':p')) 2 | 3 | let s:winwidth_threshold = &columns / 4 4 | let s:winheight_threshold = &lines / 3 5 | 6 | function! s:get_thresholds() abort 7 | return { 8 | \ 'winwidth': s:winwidth_threshold, 9 | \ 'winheight': s:winheight_threshold, 10 | \} 11 | endfunction 12 | 13 | function! s:set_thresholds(thresholds) abort 14 | let s:winwidth_threshold = get(a:thresholds, 'winwidth', s:winwidth_threshold) 15 | let s:winheight_threshold = get(a:thresholds, 'winheight', s:winheight_threshold) 16 | endfunction 17 | 18 | function! s:find(origin) abort 19 | let nwinnr = winnr('$') 20 | if nwinnr == 1 21 | return 1 22 | endif 23 | let origin = a:origin == 0 ? winnr() : a:origin 24 | let former = range(origin, winnr('$')) 25 | let latter = reverse(range(1, origin - 1)) 26 | for winnr in (former + latter) 27 | if s:is_suitable(winnr) 28 | return winnr 29 | endif 30 | endfor 31 | return 0 32 | endfunction 33 | 34 | function! s:focus(origin) abort 35 | let winnr = s:find(a:origin) 36 | if winnr == 0 || winnr == winnr() 37 | return 1 38 | endif 39 | call win_gotoid(win_getid(winnr)) 40 | endfunction 41 | 42 | function! s:attach() abort 43 | execute printf('augroup vital_window_locator_local_internal_%s', s:UNIQUE) 44 | execute 'autocmd! * ' 45 | execute 'autocmd WinLeave call s:_on_WinLeave()' 46 | execute 'augroup END' 47 | endfunction 48 | 49 | function! s:detach() abort 50 | execute printf('augroup vital_window_locator_local_internal_%s', s:UNIQUE) 51 | autocmd! * 52 | execute 'augroup END' 53 | endfunction 54 | 55 | function! s:is_suitable(winnr) abort 56 | if getbufvar(winbufnr(a:winnr), '&previewwindow') 57 | \ || winwidth(a:winnr) < s:winwidth_threshold 58 | \ || winheight(a:winnr) < s:winheight_threshold 59 | return 0 60 | endif 61 | return 1 62 | endfunction 63 | 64 | function! s:_on_WinLeave() abort 65 | let s:info = { 66 | \ 'nwin': winnr('$'), 67 | \ 'previous': win_getid(winnr('#')) 68 | \} 69 | endfunction 70 | 71 | function! s:_on_WinEnter() abort 72 | if exists('s:info') && winnr('$') < s:info.nwin 73 | call s:focus(win_id2win(s:info.previous) || winnr()) 74 | endif 75 | silent! unlet! s:info 76 | endfunction 77 | 78 | execute printf('augroup vital_window_locator_internal_%s', s:UNIQUE) 79 | execute 'autocmd! *' 80 | execute 'autocmd WinEnter * nested call s:_on_WinEnter()' 81 | execute 'augroup END' 82 | -------------------------------------------------------------------------------- /autoload/vital/__vital__/Vim/Window/Selector.vim: -------------------------------------------------------------------------------- 1 | function! s:_vital_depends() abort 2 | return ['Prompt'] 3 | endfunction 4 | 5 | function! s:_vital_loaded(V) abort 6 | let s:Prompt = a:V.import('Prompt') 7 | endfunction 8 | 9 | function! s:select(winnrs, ...) abort 10 | let options = extend({ 11 | \ 'auto_select': 0, 12 | \}, a:0 ? a:1 : {}) 13 | if options.auto_select && len(a:winnrs) <= 1 14 | call win_gotoid(len(a:winnrs) ? win_getid(a:winnrs[0]) : win_getid()) 15 | return 0 16 | endif 17 | let length = len(a:winnrs) 18 | let store = {} 19 | for winnr in a:winnrs 20 | let store[winnr] = getwinvar(winnr, '&statusline') 21 | endfor 22 | try 23 | call map(keys(store), { k, v -> setwinvar(v, '&statusline', s:_statusline(v, k + 1)) }) 24 | redrawstatus 25 | let n = s:Prompt.select( 26 | \ printf('choose number [1-%d]: ', length), 27 | \ len(length . ''), 28 | \) 29 | redraw | echo 30 | if n is# v:null 31 | return 1 32 | endif 33 | call win_gotoid(win_getid(a:winnrs[n - 1])) 34 | finally 35 | call map(keys(store), { _, v -> setwinvar(v, '&statusline', store[v]) }) 36 | redrawstatus 37 | endtry 38 | endfunction 39 | 40 | function! s:_statusline(winnr, n) abort 41 | let width = winwidth(a:winnr) - len(a:winnr . '') - 6 42 | let leading = repeat(' ', width / 2) 43 | return printf( 44 | \ '%%#NonText#%s%%#DiffText# %d %%#NonText#', 45 | \ leading, a:n, 46 | \) 47 | endfunction 48 | -------------------------------------------------------------------------------- /doc/Vital/App/Action.txt: -------------------------------------------------------------------------------- 1 | *Vital/App/Action.txt* Action 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.App.Action-content* 8 | 9 | INTRODUCTION |Vital.App.Action-introduction| 10 | USAGE |Vital.App.Action-usage| 11 | INTERFACE |Vital.App.Action-interface| 12 | FUNCTION |Vital.App.Action-function| 13 | MAPPING |Vital.App.Action-mapping| 14 | 15 | 16 | ============================================================================= 17 | INTRODUCTION *Vital.App.Action-introduction* 18 | 19 | *Vital.App.Action* is a |Vital| module used to add "action" feature to execute 20 | special buffer mappings. 21 | 22 | ============================================================================= 23 | USAGE *Vital.App.Action-usage* 24 | 25 | Call |Vital.App.Action.init()| on a buffer where you'd like to enable the 26 | action feature. 27 | It defines buffer local mappings listed in |Vital.App.Action-mapping|. 28 | 29 | After that, define custom mappings like "({prefix}-action-{name})" where 30 | {prefix} is a plugin name which is retrieved from the script path of the vital 31 | module and {name} is an unique name of the feature. 32 | 33 | For example, the following define a new action "echo-hello" of "example". 34 | > 35 | " Assume that the plugin name is 'example' and the vital module is 36 | " installed in ".../autoload/vital/_example/App/Action.vim" 37 | nnoremap 38 | \ (example-action-echo-hello) 39 | \ echo "Hello" 40 | < 41 | See |Vital.App.Action.set_prefix()| if the guessed plugin name is wrong. 42 | 43 | ============================================================================= 44 | INTERFACE *Vital.App.Action-interface* 45 | 46 | ----------------------------------------------------------------------------- 47 | FUNCTION *Vital.App.Action-function* 48 | 49 | *Vital.App.Action.get_prefix()* 50 | .get_prefix() 51 | Return a current {prefix} |String|. 52 | 53 | *Vital.App.Action.set_prefix()* 54 | .set_prefix({new_prefix}) 55 | Set a current {prefix} to the {new_prefix}. 56 | 57 | *Vital.App.Action.get_hiddens()* 58 | .get_hiddens() 59 | Return a |List| of action names which should be hidden. 60 | 61 | *Vital.App.Action.set_hiddens()* 62 | .set_hiddens({names}) 63 | Set a |List| of action names ({names}) which should be hidden. 64 | 65 | *Vital.App.Action.get_ignores()* 66 | .get_ignores() 67 | Return a |List| of action names which should not be listed. 68 | 69 | *Vital.App.Action.set_ignores()* 70 | .set_ignores({names}) 71 | Set a |List| of action names ({names}) which should not be listed. 72 | 73 | *Vital.App.Action.init()* 74 | .init() 75 | Initialize the current buffer to prepare actions. 76 | 77 | *Vital.App.Action.call()* 78 | .call({name}[, {options}]) 79 | Call an action {name} on the current buffer. 80 | The following attributes are available in {options} 81 | 82 | "capture" 1 to enable capture mode which write output messages 83 | into a new empty buffer instead 84 | "verbose" 1 to execute action with 'verbose' (1) mode. 85 | 86 | *Vital.App.Action.list()* 87 | .list([{conceal}]) 88 | Return a |List| of available actions. Each item of the list is tuple 89 | like [{lhs}, {name}, {rhs}] where {lhs} is an actual mapping, {name} 90 | is an action name, and {rhs} is a mapping like: 91 | > 92 | assert_equal(s:Action.list(), [ 93 | \ ['a', 'choice', '(example-action-choice)'], 94 | \ ['.', 'repeat', '(example-action-repeat)'], 95 | \ ['?', 'help', '(example-action-help)'], 96 | \ ['', 'help:all', '(example-action-help:all)'], 97 | \]) 98 | < 99 | When {conceal} is truthy value, it remove items which contains ":" in 100 | it's name and no actual mapping (like "help:all" in above example.) 101 | 102 | ----------------------------------------------------------------------------- 103 | MAPPING *Vital.App.Action-mapping* 104 | 105 | *({prefix}-action-choice)* 106 | ({prefix}-action-choice) 107 | Open a prompt to select action to execute. 108 | 109 | *({prefix}-action-repeat)* 110 | ({prefix}-action-repeat) 111 | Repeat previous executed action through the prompt. 112 | 113 | *({prefix}-action-help)* 114 | ({prefix}-action-help) 115 | Show action help. 116 | 117 | *({prefix}-action-help:all)* 118 | ({prefix}-action-help:all) 119 | Show all action help. 120 | 121 | ============================================================================= 122 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 123 | -------------------------------------------------------------------------------- /doc/Vital/App/Args.txt: -------------------------------------------------------------------------------- 1 | *Vital/App/Args.txt* Minimal command argument manager 2 | 3 | Author: Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.App.Args-contents* 8 | 9 | Introduction |Vital.App.Args-introduction| 10 | Usage |Vital.App.Args-usage| 11 | Functions |Vital.App.Args-functions| 12 | 13 | 14 | ============================================================================= 15 | INTRODUCTION *Vital.App.Args-introduction* 16 | 17 | |Vital.App.Args| is minimal command argument manager which supports only the 18 | following two forms. 19 | 20 | -flag |Boolean| 21 | -flag=value |String| 22 | 23 | 24 | ============================================================================= 25 | USAGE *Vital.App.Args-usage* 26 | 27 | Use |Vital.App.Args.get()| to get an option (a value starts from "-") like: 28 | > 29 | " Replace {your-plugin-name} to your plugin name 30 | let Args = vital#{your-plugin-name}#import('App.Args') 31 | 32 | " Use in realworld 33 | let args = ['hello', '-foo', '-bar=bar'] 34 | 35 | echo Args.get(args, 'foo', v:false) 36 | " -> v:true 37 | echo args 38 | " -> ['hello', '-foo', '-bar=bar'] 39 | 40 | echo Args.get(args, 'bar', '') 41 | " -> 'bar' 42 | echo args 43 | " -> ['hello', '-foo', '-bar=bar'] 44 | < 45 | Or use |Vital.App.Args.pop()| to remove the option from the {args} like: 46 | > 47 | echo Args.pop(args, 'foo', v:false) 48 | " -> v:true 49 | echo args 50 | " -> ['hello', '-bar=bar'] 51 | 52 | echo Args.pop(args, 'bar', '') 53 | " -> 'bar' 54 | echo args 55 | " -> ['hello'] 56 | < 57 | Or set new options to the {args} by |Vital.App.Args.set()| like: 58 | > 59 | call Args.set(args, 'foo2', v:true) 60 | echo args 61 | " -> ['hello', '-foo2'] 62 | 63 | call Args.set(args, 'bar2', 'bar2') 64 | echo args 65 | " -> ['hello', '-foo2', '-bar2=bar2] 66 | < 67 | Or update existing options of {args} like: 68 | > 69 | call Args.set(args, 'foo2', v:false) 70 | echo args 71 | " -> ['hello', '-bar2=bar2] 72 | 73 | call Args.set(args, 'bar2', 'barbar') 74 | echo args 75 | " -> ['hello', '-bar2=barbar] 76 | < 77 | After all, use |Vital.App.Args.throw_if_dirty()| to check all known options 78 | are popped properly like: 79 | > 80 | " Below throws an exception while {args} still has '-bar2=barbar' 81 | call Args.throw_if_dirty(args) 82 | 83 | " Below does NOT throw exceptions while {args} become clean 84 | call Args.pop(args, 'bar2', '') 85 | call Args.throw_if_dirty(args) 86 | < 87 | 88 | ============================================================================= 89 | FUNCTIONS *Vital.App.Args-functions* 90 | 91 | *Vital.App.Args.get()* 92 | .get({args}, {name}, {default}) 93 | Get a {name} option ("-{name}" or "-{name}=XXXXX") from {args} and 94 | return the value. If the {name} option is not exists in {args}, it 95 | returns {default}. 96 | 97 | *Vital.App.Args.pop()* 98 | .pop({args}, {name}, {default}) 99 | Remove a {name} option ("-{name}" or "-{name}=XXXXX") from {args} and 100 | return the value. If the {name} option is not exists in {args}, it 101 | returns {default}. 102 | 103 | *Vital.App.Args.set()* 104 | .set({args}, {name}, {value}) 105 | Set a {name} option ("-{name}" or "-{name}={value}") to {args}. 106 | It add a new {name} option if the {name} option does not exist in the 107 | {args}. Otherwise it update/remove the {name} option. 108 | 109 | *Vital.App.Args.throw_if_dirty()* 110 | .throw_if_dirty({args}, [{prefix}]) 111 | Throw an exception when {args} contains any option (a value starts 112 | from "-"). If {prefix} is specified, the {prefix} is prefixed to the 113 | error message. 114 | 115 | 116 | ============================================================================= 117 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 118 | -------------------------------------------------------------------------------- /doc/Vital/App/Emitter.txt: -------------------------------------------------------------------------------- 1 | *Vital/App/Emitter.txt* An emitter library 2 | 3 | Author : Alisue 4 | 5 | DEPRECATED 6 | 7 | 8 | ============================================================================= 9 | CONTENTS *Vital.App.Emitter-content* 10 | 11 | INTRODUCTION |Vital.App.Emitter-introduction| 12 | INTERFACE |Vital.App.Emitter-interface| 13 | FUNCTION |Vital.App.Emitter-function| 14 | 15 | 16 | ============================================================================= 17 | INTRODUCTION *Vital.App.Emitter-introduction* 18 | 19 | *Vital.App.Emitter* is a |Vital| module used for emit an event. 20 | 21 | 22 | ============================================================================= 23 | INTERFACE *Vital.App.Emitter-interface* 24 | 25 | ----------------------------------------------------------------------------- 26 | FUNCTION *Vital.App.Emitter-function* 27 | 28 | *Vital.App.Emitter.subscribe()* 29 | .subscribe({name}, {listener}[, {instance}]) 30 | Subscribe a {name} event by a {listener}. 31 | If {instance} is specified, the {listener} is called as a dictionary 32 | function of the {instance}. 33 | 34 | *Vital.App.Emitter.unsubscribe()* 35 | .unsubscribe([{name}, [{listener}[, {instance}]]]) 36 | Unsubscribe a {name} event of {listener}. 37 | If {listener} is not specified, it unsubscribe all listeners of the 38 | {name} event. 39 | If {name} is not specified, it unsubscribe all listeners of all 40 | events. 41 | 42 | *Vital.App.Emitter.add_middleware()* 43 | .add_middleware({middleware}) 44 | Add {middleware} to the middleware list. 45 | See |Vital.App.Emitter-middleware| for the detail. 46 | 47 | *Vital.App.Emitter.remove_middleware()* 48 | .remove_middleware([{middleware}]) 49 | Remove {middleware} from the middleware list. 50 | If no {middleware} has specified, it remove all middlewares. 51 | See |Vital.App.Emitter-middleware| for the detail. 52 | 53 | *Vital.App.Emitter.emit()* 54 | .emit({name} [, {attr}...]) 55 | Call registered listeners of {name} with {attr}s. 56 | 57 | ----------------------------------------------------------------------------- 58 | MIDDLEWARE *Vital.App.Emitter-middleware* 59 | 60 | 61 | *Vital.App.Emitter-middleware.on_emit_pre()* 62 | .on_emit_pre({name}, {listeners}, {attrs}) 63 | Called before the event has been sent to all listeners. 64 | If {listeners} and/or {attrs} are modified in this method, the 65 | modified version will be used for further procession. 66 | Note that {listeners} and {attrs} are one-time variable for the emit 67 | process which call this middleware. So that modification performed on 68 | these variable won't affect to other process. 69 | 70 | *Vital.App.Emitter-middleware.on_emit_post()* 71 | .on_emit_post({name}, {listeners}, {attrs}) 72 | Called after the event had been sent to all listeners. 73 | 74 | 75 | ============================================================================= 76 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 77 | -------------------------------------------------------------------------------- /doc/Vital/App/Flag.txt: -------------------------------------------------------------------------------- 1 | *Vital/App/Flag.txt* Simple command argument manager. 2 | 3 | Author: Alisue 4 | 5 | DEPRECATED 6 | 7 | 8 | ============================================================================= 9 | CONTENTS *Vital.App.Flag-contents* 10 | 11 | Introduction |Vital.App.Flag-introduction| 12 | Usage |Vital.App.Flag-usage| 13 | Functions |Vital.App.Flag-functions| 14 | 15 | 16 | ============================================================================= 17 | INTRODUCTION *Vital.App.Flag-introduction* 18 | 19 | |Vital.App.Flag| is simple command argument manager which supports only the 20 | following two forms. 21 | 22 | -flag Boolean 23 | -flag=value String value 24 | 25 | Not like |Vital.OptionParser| or Vital.ArgumentParser, this module limits form 26 | styles to make internal code simple and stable. 27 | 28 | See also: 29 | https://github.com/lambdalisue/vital-ArgumentParser 30 | 31 | 32 | ============================================================================= 33 | USAGE *Vital.App.Flag-usage* 34 | 35 | Use |Vital.App.Flag.split()| to split cmdline string like: 36 | > 37 | let s:Flag = vital#vital#import('App.Flag') 38 | let args = s:Flag.split('command -foo -bar -hoge=hoge file1 file2') 39 | echo args 40 | " -> ['command', '-foo', '-bar', '-hoge=hoge', 'file1', 'file2'] 41 | < 42 | Then use |Vital.App.Flag.flag()| and |Vital.App.Flag.value()| to read flags 43 | like: 44 | > 45 | echo s:Flag.flag(args, 'foo') 46 | " -> 1 47 | call s:Flag.flag(args, 'foo-missing') 48 | " -> 0 49 | call s:Flag.value(args, 'hoge') 50 | " -> "hoge" 51 | call s:Flag.value(args, 'hoge-missing') 52 | " -> v:null 53 | < 54 | Or use |Vital.App.Flag.parse()| to parse all flags like: 55 | > 56 | let [options, remains] = s:Flag.parse(args) 57 | echo options 58 | " -> { 59 | " 'foo': 1, 60 | " 'bar': 1, 61 | " 'hoge': 'hoge', 62 | "} 63 | " echo remains 64 | " -> ['command', 'file1', 'file2'] 65 | < 66 | 67 | 68 | ============================================================================= 69 | FUNCTIONS *Vital.App.Flag-functions* 70 | 71 | *Vital.App.Flag.split()* 72 | .split({cmdline}) 73 | Split {cmdline} and return string list. 74 | It respects escaped space and single/double quoted string. 75 | > 76 | echo Flag.split('foo') 77 | " -> ['foo'] 78 | echo Flag.split('foo bar') 79 | " -> ['foo', 'bar'] 80 | echo Flag.split('"foo foo" "bar bar"') 81 | " -> ['foo foo', 'bar bar'] 82 | echo Flag.split('foo "bar bar" hoge') 83 | " -> ['foo', 'bar bar', 'hoge'] 84 | echo Flag.split('--foo="foo" -b"bar"') 85 | " -> ['--foo=foo', '-bbar'] 86 | echo Flag.split('foo\ bar\ hoge') 87 | " -> ['foo\ bar\ hoge'] 88 | < 89 | *Vital.App.Flag.flag()* 90 | .flag({args}, {name}) 91 | Return TRUE if {name} option (-{name}) exists in {args}. 92 | > 93 | echo Flag.flag(['-foo'], 'foo') 94 | " -> 1 95 | echo Flag.flag(['-foo-bar'], 'foo') 96 | " -> 0 97 | < 98 | *Vital.App.Flag.value()* 99 | .value({args}, {name}[, {default}]) 100 | Return {value} of {name} option (-{name}={value}) exists in {args}. 101 | It returns {default} or |v:null| if no {name} option exists. 102 | > 103 | echo Flag.value(['-foo=FOO'], 'foo') 104 | " -> 'FOO' 105 | echo Flag.value(['-foo-bar=FOO'], 'foo') 106 | " -> v:null 107 | echo Flag.value(['-foo-bar=FOO'], 'foo', 'DEFAULT') 108 | " -> 'DEFAULT' 109 | < 110 | *Vital.App.Flag.parse()* 111 | .parse({args}) 112 | Parse {args} and return [{options}, {remains}]. 113 | All flags found in {args} exists in {options} object and all non flag 114 | values (positional arguments) exists in {remains} list. 115 | 116 | 117 | ============================================================================= 118 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 119 | -------------------------------------------------------------------------------- /doc/Vital/App/Revelator.txt: -------------------------------------------------------------------------------- 1 | *Vital/App/Revelator.txt* Framework for an exception revelator pattern 2 | 3 | Author : Alisue 4 | 5 | DEPRECATED 6 | 7 | 8 | ============================================================================= 9 | CONTENTS *Vital.App.Revelator-contents* 10 | 11 | USAGE |Vital.App.Revelator-usage| 12 | FUNCTIONS |Vital.App.Revelator-functions| 13 | 14 | 15 | ============================================================================= 16 | USAGE *Vital.App.Revelator-usage* 17 | 18 | Throw exceptions through the helper function and call a target function with 19 | |Vital.App.Revelator.call()| like: 20 | > 21 | let s:Revelator = vital#vital#import('Revelator') 22 | 23 | function! s:foobar(x) abort 24 | if x == 0 25 | throw s:Revelator.info('foo') 26 | elseif x == 1 27 | throw s:Revelator.warning('foo') 28 | elseif x == 2 29 | throw s:Revelator.error('foo') 30 | elseif x == 3 31 | throw s:Revelator.critical'foo') 32 | endif 33 | echomsg "This line should not be called." 34 | endfunction 35 | 36 | call s:Revelator.call(function('s:foobar'), [0]) 37 | " foo 38 | 39 | call s:Revelator.call(function('s:foobar'), [1]) 40 | " foo (With WarningMsg highlight) 41 | 42 | call s:Revelator.call(function('s:foobar'), [2]) 43 | " foo (With ErrorMsg highlight) 44 | 45 | call s:Revelator.call(function('s:foobar'), [3]) 46 | " foo (With ErrorMsg highlight and throwpoint 47 | < 48 | 49 | ============================================================================= 50 | FUNCTIONS *Vital.App.Revelator-functions* 51 | 52 | *Vital.App.Revelator.message()* 53 | message({category}, {msg}) 54 | Return a {category} revelation message of {msg}. 55 | Use this method to create custom revelations. 56 | 57 | *Vital.App.Revelator.status()* 58 | info{msg}) 59 | Return a INFO revelation message of {msg}. 60 | 61 | *Vital.App.Revelator.warning()* 62 | warning({msg}) 63 | Return a WARNING revelation message of {msg}. 64 | 65 | *Vital.App.Revelator.error()* 66 | error({msg}) 67 | Return an ERROR revelation message of {msg}. 68 | 69 | *Vital.App.Revelator.critical()* 70 | critical({msg}) 71 | Return a CRITICAL revelation message of {msg}. 72 | 73 | *Vital.App.Revelator.call()* 74 | call({func}, {argslist}[, {dict}]) 75 | Call {func} with {argslist} like a builtin |call()| function but it 76 | catch exceptions which follow the revelation message format. 77 | Then it use registered receivers to handle the revelation message 78 | until one of the receivers returns truthy value. 79 | 80 | Note that receivers registered in {func} will be removed after the 81 | function call so that temporary receiver can be registered in the 82 | target {func}. 83 | 84 | If {dict} is specified, the {func} is called as a dictionary 85 | function with the {dict}. 86 | 87 | *Vital.App.Revelator.register()* 88 | register({receiver}) 89 | Register a new revelation {receiver}. 90 | The {receiver} function must accept a {revelation} instance and may 91 | return 1 to skip rest of the receivers. 92 | 93 | The {revelation} instance has 94 | 95 | "category" Category string (e.g. INFO) 96 | "message" Message string 97 | "exception" Exception (|v:exception|) 98 | "throwpoint" Throwpoint (|v:throwpoint|) 99 | > 100 | function! s:my_receiver(revelation) abort 101 | if a:revelation.category ==# 'Error' 102 | call writefile( 103 | \ split(a:revelation.message, '\r\?\n'), 104 | \ 'error.log', 105 | \) 106 | " Comment out the following if you would like to skip rest of 107 | " the receivers 108 | " return 1 109 | endif 110 | endfunction 111 | 112 | call s:Revelator.register(function('s:my_receiver')) 113 | < 114 | *Vital.App.Revelator.unregister()* 115 | unregister({receiver}) 116 | Unregister an revelation {receiver}. 117 | 118 | *Vital.App.Revelator.get_default_receiver()* 119 | get_default_receiver() 120 | Return a default revelation receive. 121 | This default receiver can handle the following revelations. 122 | 123 | "INFO" Echo normally 124 | "WARNING" Echo with |WarningMsg| 125 | "ERROR" Echo with |ErrorMsg| 126 | "CRITICAL" Echo with |ErrorMsg| with throwpoint. 127 | 128 | 129 | ============================================================================= 130 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 131 | -------------------------------------------------------------------------------- /doc/Vital/App/Spinner.txt: -------------------------------------------------------------------------------- 1 | *App.Spinner.txt* Collections of text spinners 2 | 3 | Author : Alisue 4 | 5 | DEPRECATED 6 | 7 | ============================================================================= 8 | CONTENTS *App.Spinner-contents* 9 | 10 | Usage |App.Spinner-usage| 11 | Functions |App.Spinner-functions| 12 | Credits |App.Spinner-credits| 13 | 14 | 15 | ============================================================================= 16 | USAGE *App.Spinner-usage* 17 | 18 | Create a spinner instance and call next() method like: 19 | > 20 | let s:Spinner = vital#vital#import('App.Spinner') 21 | let spinner = s:Spinner.new(s:Spinner.line) 22 | echo spinner.next() 23 | " -> '-' 24 | echo spinner.next() 25 | " -> '\\' 26 | echo spinner.next() 27 | " -> '|' 28 | echo spinner.next() 29 | " -> '/' 30 | echo spinner.next() 31 | " -> '-' 32 | < 33 | This module provides 60+ spinners thanks to sindresorhus/cli-spinners. 34 | This module supports spinners defined in cli-spinners 1.3.1. 35 | 36 | See also: 37 | http://jsfiddle.net/sindresorhus/2eLtsbey/embedded/result/ 38 | 39 | 40 | ============================================================================= 41 | FUNCTIONS *App.Spinner-functions* 42 | 43 | *App.Spinner.new()* 44 | .new({frames}) 45 | Return a spinner instance of a given {frame}. 46 | 47 | The spinner instance has the following methods 48 | 49 | "next()" 50 | Returns a next frame. 51 | "reset()" 52 | Reset an internal index. 53 | 54 | 55 | ============================================================================= 56 | CREDITS *App.Spinner-credits* 57 | 58 | All spinner frames are licensed by Sindre Sorhus. 59 | https://github.com/sindresorhus/cli-spinners 60 | 61 | MIT License~ 62 | 63 | Copyright (c) Sindre Sorhus (sindresorhus.com) 64 | 65 | Permission is hereby granted, free of charge, to any person obtaining a copy 66 | of this software and associated documentation files (the "Software"), to 67 | deal in the Software without restriction, including without limitation the 68 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 69 | sell copies of the Software, and to permit persons to whom the Software is 70 | furnished to do so, subject to the following conditions: 71 | 72 | The above copyright notice and this permission notice shall be included in 73 | all copies or substantial portions of the Software. 74 | 75 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 76 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 77 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 78 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 79 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 80 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 81 | DEALINGS IN THE SOFTWARE. 82 | 83 | 84 | ============================================================================= 85 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 86 | -------------------------------------------------------------------------------- /doc/Vital/App/WindowLocator.txt: -------------------------------------------------------------------------------- 1 | *Vital/App/WindowLocator.txt* Utility to manage suitable window 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.App.WindowLocator-content* 8 | 9 | INTRODUCTION |Vital.App.WindowLocator-introduction| 10 | INTERFACE |Vital.App.WindowLocator-interface| 11 | FUNCTION |Vital.App.WindowLocator-function| 12 | 13 | 14 | ============================================================================= 15 | INTRODUCTION *Vital.App.WindowLocator-introduction* 16 | 17 | *Vital.App.WindowLocator* is a |Vital| module to manage suitable windows. 18 | 19 | 20 | ============================================================================= 21 | INTERFACE *Vital.App.WindowLocator-interface* 22 | 23 | ----------------------------------------------------------------------------- 24 | FUNCTION *Vital.App.WindowLocator-function* 25 | 26 | *Vital.App.WindowLocator.score()* 27 | .score({winnr}) 28 | Return a score of the window {winnr}. It returns higher score if the 29 | window pass given conditions. 30 | 31 | *Vital.App.WindowLocator.list()* 32 | .list() 33 | Return a |List| of suitable window |winnr|. 34 | 35 | *Vital.App.WindowLocator.find()* 36 | .find({origin}) 37 | Find a nearest suitable window from {origin} (|winnr|). 38 | It returns 0 if no suitable window is found. 39 | 40 | *Vital.App.WindowLocator.focus()* 41 | .focus({origin}) 42 | Focus a nearest suitable window from {origin} (|winnr|). 43 | 44 | *Vital.App.WindowLocator.get_conditions()* 45 | get_conditions() 46 | Return a current conditions (A |List| of |Function|). 47 | Default: 48 | 49 | *Vital.App.WindowLocator.set_conditions()* 50 | set_conditions({conditions}) 51 | Set a current conditions to {conditions}. The {conditions} is a |List| 52 | of |Function| and each function get window information returned by 53 | |getwininfo()|. For example: 54 | > 55 | call s:WindowLocator.set_conditions([ 56 | \ { wi -> !wi.loclist }, 57 | \ { wi -> !wi.quickfix }, 58 | \ { wi -> !getwinvar(wi.winid, '&winfixwidth', 0) }, 59 | \ { wi -> !getwinvar(wi.winid, '&winfixheight', 0) }, 60 | \ { wi -> !getbufvar(wi.bufnr, '&previewwindow', 0) }, 61 | \]) 62 | < 63 | *Vital.App.WindowLocator.get_threshold()* 64 | get_threshold() 65 | Return a current threshold. 66 | 67 | *Vital.App.WindowLocator.set_threshold()* 68 | set_threshold({threshold}) 69 | Set a current threshold to {threshold}. 70 | Set 0 to reset and guess threshold from current conditions. 71 | 72 | 73 | ============================================================================= 74 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 75 | -------------------------------------------------------------------------------- /doc/Vital/App/WindowSelector.txt: -------------------------------------------------------------------------------- 1 | *Vital/App/WindowSelector.txt* Interface to visually select window 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.App.WindowSelector-content* 8 | 9 | INTRODUCTION |Vital.App.WindowSelector-introduction| 10 | USAGE |Vital.App.WindowSelector-usage| 11 | INTERFACE |Vital.App.WindowSelector-interface| 12 | FUNCTION |Vital.App.WindowSelector-function| 13 | 14 | 15 | ============================================================================= 16 | INTRODUCTION *Vital.App.WindowSelector-introduction* 17 | 18 | *Vital.App.WindowSelector* is a |Vital| module used to add an interface to 19 | select window visually. 20 | 21 | 22 | ============================================================================= 23 | USAGE *Vital.App.WindowSelector-usage* 24 | 25 | Call |Vital.App.WindowSelector.select()| with a |List| of window numbers like: 26 | > 27 | let cancelled = s:WindowSelector.select(range(1, winnr('$'))) 28 | < 29 | Then the focus has moved to the selected window or {cancelled} is 1 if user 30 | has cancelled. 31 | 32 | 33 | ============================================================================= 34 | INTERFACE *Vital.App.WindowSelector-interface* 35 | 36 | ----------------------------------------------------------------------------- 37 | FUNCTION *Vital.App.WindowSelector-function* 38 | 39 | *Vital.App.WindowSelector.select()* 40 | .select({ws}[, {options}]) 41 | Open an interface to select window from a window number |List| {ws}. 42 | It moves the focus to the selected window or return 1 when user 43 | cancelled. 44 | The following attributes are available in {options}. 45 | 46 | "auto_select" 1 to automatically select window if there is 1 47 | or 0 window exists. 48 | "select_chars" A |List| of |String| used as an window 49 | indicator. 50 | "use_popup" Use popup/float window to select window. 51 | "popup_borderchars" A |List| of |String| used as an border chars of 52 | popup/float window. 53 | The default border chars: 54 | "['╭', '─', '╮', '│', '╯', '─', '╰', '│']" 55 | NOTE: The order of border chars in a popup 56 | window is originally different from a float 57 | window. 58 | Please use the float window border chars 59 | definition, as it is automatically converted 60 | internally to the popup window border chars 61 | definition. 62 | "statusline_hl" A |String| highlight name used for statusline. 63 | "indicator_hl" A |String| highlight name used for indicator. 64 | 65 | 66 | ============================================================================= 67 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 68 | -------------------------------------------------------------------------------- /doc/Vital/Async/CancellationTokenSource.txt: -------------------------------------------------------------------------------- 1 | *Vital/Async/CancellationTokenSource.txt* Cancellation controller 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.Async.CancellationTokenSource-content* 8 | 9 | INTRODUCTION |Vital.Async.CancellationTokenSource-introduction| 10 | USAGE |Vital.Async.CancellationTokenSource-usage| 11 | INTERFACE |Vital.Async.CancellationTokenSource-interface| 12 | FUNCTION |Vital.Async.CancellationTokenSource-function| 13 | INSTANCE |Vital.Async.CancellationTokenSource-instance| 14 | 15 | 16 | ============================================================================= 17 | INTRODUCTION *Vital.Async.CancellationTokenSource-introduction* 18 | 19 | *Vital.Async.CancellationTokenSource* emit a cancellation signal to notify 20 | |Vital.Async.CancellationToken| to achieve cancellation in general. 21 | 22 | This is CancellationTokenSource implementation of a cancellation proposal in 23 | TC39. 24 | 25 | TC39 Cancellation API~ 26 | https://github.com/tc39/proposal-cancellation 27 | 28 | 29 | ============================================================================= 30 | USAGE *Vital.Async.CancellationTokenSource-usage* 31 | 32 | The code below shows how to use an asynchronous cancelable function shown in 33 | |Vital.Async.CancellationToken-usage|. 34 | Note that the source is canceled after 1000 ms so that if HTTP requests takes 35 | longer than 1000ms, an internal process (curl) will be killed by cancellation. 36 | > 37 | let s:CancellationTokenSource = 38 | \ vital#vital#import('Async.CancellationTokenSource') 39 | 40 | function! s:test() abort 41 | let source = s:CancellationTokenSource.new() 42 | 43 | call s:request('https://httpbin.org/get', source.token) 44 | \.then({ r -> execute('echomsg "OK: " . string(r)', '') }) 45 | \.catch({ r -> execute('echomsg "Fail: " . string(r)', '') }) 46 | 47 | call timer_start(1000, { -> source.cancel() }) 48 | endfunction 49 | call s:test() 50 | < 51 | See |Vital.Async.CancellationToken-usage| to create asynchronous cancelable 52 | functions. 53 | 54 | 55 | ============================================================================= 56 | INTERFACE *Vital.Async.CancellationTokenSource-interface* 57 | 58 | ----------------------------------------------------------------------------- 59 | FUNCTION *Vital.Async.CancellationTokenSource-function* 60 | 61 | *Vital.Async.CancellationTokenSource.new()* 62 | .new([{linked-tokens}]) 63 | Create a new source. When {linked-tokens} is given, the source is 64 | linked to the given tokens and be canceled when one of a token is 65 | canceled. 66 | 67 | See also: 68 | |Vital.Async.CancellationToken.new()| 69 | 70 | 71 | ----------------------------------------------------------------------------- 72 | INSTANCE *Vital.Async.CancellationTokenSource-instance* 73 | 74 | *Vital.Async.CancellationTokenSource-ins.cancel()* 75 | .cancel() 76 | Requests cancellation. All cancellation callbacks in all linked 77 | tokens will be called. 78 | When any exceptions are occurred in cancellation callback, the 79 | exception will be raised after this function call. 80 | 81 | *Vital.Async.CancellationTokenSource-ins.close()* 82 | .close() 83 | Close the source. No cancellation can be requests through the closed 84 | source. If the source is linked to any existing tokens, the links 85 | are unregistered. 86 | 87 | 88 | ============================================================================= 89 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 90 | -------------------------------------------------------------------------------- /doc/Vital/Async/File.txt: -------------------------------------------------------------------------------- 1 | *vital/Async/File.txt* asynchronous filesystem utilities library. 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================== 7 | CONTENTS *Vital.Async.File-contents* 8 | 9 | INTRODUCTION |Vital.Async.File-introduction| 10 | INTERFACE |Vital.Async.File-interface| 11 | Functions |Vital.Async.File-functions| 12 | 13 | ============================================================================== 14 | INTRODUCTION *Vital.Async.File-introduction* 15 | 16 | *Vital.Async.File* is an asynchronous filesystem utilities library. 17 | It is asynchronous version of |Vital.System.File| with some additional 18 | functions. 19 | 20 | ============================================================================== 21 | INTERFACE *Vital.Async.File-interface* 22 | 23 | ------------------------------------------------------------------------------ 24 | FUNCTIONS *Vital.Async.File-functions* 25 | 26 | is_open_supported() *Vital.Async.File.is_open_supported()* 27 | Returns TRUE if "open()" is supported in a current platform. 28 | 29 | is_move_supported() *Vital.Async.File.is_move_supported()* 30 | Returns TRUE if "move()" is supported in a current platform. 31 | 32 | is_copy_supported() *Vital.Async.File.is_copy_supported()* 33 | Returns TRUE if "copy()" is supported in a current platform. 34 | 35 | is_copy_dir_supported() *Vital.Async.File.is_copy_dir_supported()* 36 | Returns TRUE if "copy_dir()" is supported in a current platform. 37 | 38 | is_trash_supported() *Vital.Async.File.is_trash_supported()* 39 | Returns TRUE if "trash()" is supported in a current platform. 40 | 41 | open({expr}[, {options}]) *Vital.Async.File.open()* 42 | Returns a promise to opens an {expr} by a system command. 43 | > 44 | call s:F.open("/tmp/file") 45 | \.then({ -> execute('echo "opened"', '') }) 46 | < 47 | The {options} is passed to |Vital.Async.Promise.Process.start()|. 48 | So to cancel the operation, assign |Vital.Async.CancellationToken| 49 | to {options.token}. 50 | 51 | move({src}, {dst}[, {options}]) *Vital.Async.File.move()* 52 | Return a promise to move a {src} to {dst}. 53 | > 54 | call s:F.move("/tmp/old", "/tmp/new") 55 | \.then({ -> execute('echo "moved"', '') }) 56 | < 57 | The {options} is passed to |Vital.Async.Promise.Process.start()|. 58 | So to cancel the operation, assign |Vital.Async.CancellationToken| 59 | to {options.token}. 60 | 61 | copy({src}, {dst}[, {options}]) *Vital.Async.File.copy()* 62 | Return a promise to copy a {src} file to {dst}. 63 | Use |Vital.Async.File.copy_dir()| to copy a directory. 64 | > 65 | call s:F.copy("/tmp/file.old", "/tmp/file.new") 66 | \.then({ -> execute('echo "copied"', '') }) 67 | < 68 | The {options} is passed to |Vital.Async.Promise.Process.start()|. 69 | So to cancel the operation, assign |Vital.Async.CancellationToken| 70 | to {options.token}. 71 | 72 | copy_dir({src}, {dst}[, {options}]) *Vital.Async.File.copy_dir()* 73 | Return a promise to copy a {src} directory to {dst}. 74 | Use |Vital.Async.File.copy()| to copy a file. 75 | > 76 | call s:F.copy_dir("/tmp/old", "/tmp/new") 77 | \.then({ -> execute('echo "copied"', '') }) 78 | < 79 | The {options} is passed to |Vital.Async.Promise.Process.start()|. 80 | So to cancel the operation, assign |Vital.Async.CancellationToken| 81 | to {options.token}. 82 | 83 | trash({path}[, {options}]) *Vital.Async.File.trash()* 84 | Return a promise to move {path} into a system trash. 85 | > 86 | call s:F.trash("/tmp/file") 87 | \.then({ -> execute('echo "trashed"', '') }) 88 | < 89 | The {options} is passed to |Vital.Async.Promise.Process.start()|. 90 | So to cancel the operation, assign |Vital.Async.CancellationToken| 91 | to {options.token}. 92 | 93 | ============================================================================== 94 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 95 | -------------------------------------------------------------------------------- /doc/Vital/Async/Lambda.txt: -------------------------------------------------------------------------------- 1 | *Vital/Async/Lambda.txt* Async function collection for lambda function 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================== 7 | CONTENTS *Vital.Async.Lambda-contents* 8 | 9 | FUNCTION |Vital.Async.Lambda-function| 10 | 11 | 12 | ============================================================================= 13 | FUNCTION *Vital.Async.Lambda-function* 14 | 15 | *Vital.Async.Lambda.map()* 16 | map({list}, {fn}) 17 | It returns a promise which is resolved to a copies of {fn} applied 18 | {list}. 19 | Note that the order of argument for {fn} is inverted compared to the 20 | |map()| function to keep the order among map, filter, and reduce. 21 | > 22 | let list = [5, 4, 3, 2, 1] 23 | call s:Lambda.map(list, { v -> v + 1 }) 24 | \.then({ v -> execute("echo v", "") }) 25 | " -> [6, 5, 4, 3, 2] 26 | < 27 | *Vital.Async.Lambda.filter()* 28 | filter({list}, {fn}) 29 | It returns a promise which is resolved to a copies of {list} filtered 30 | by {fn}. 31 | Note that the order of argument for {fn} is inverted compared to the 32 | |filter()| function to keep the order among map, filter, and reduce. 33 | > 34 | let list = [5, 4, 3, 2, 1] 35 | echo s:Lambda.filter(list, { v -> v % 2 is# 0 }) 36 | \.then({ v -> execute("echo v", "") }) 37 | " -> [4, 2] 38 | < 39 | *Vital.Async.Lambda.reduce()* 40 | reduce({list}, {fn}, {init}) 41 | It returns a promise which is resolved to an accumulated value of 42 | {list} accumulated by {fn}. 43 | > 44 | let list = [5, 4, 3, 2, 1] 45 | echo s:Lambda.reduce(list, { a, v -> a + v }) 46 | \.then({ v -> execute("echo v", "") }) 47 | " -> 15 48 | < 49 | *Vital.Async.Lambda.map_f()* 50 | map_f({fn}) 51 | It returns a function to map a first argument with given {fn}. 52 | 53 | *Vital.Async.Lambda.filter_f()* 54 | filter_f({fn}) 55 | It returns a function to filter a first argument with given {fn}. 56 | 57 | *Vital.Async.Lambda.reduce_f()* 58 | reduce_f({fn}[, {init}]) 59 | It returns a function to reduce a first argument with given {fn} and. 60 | {init}. 61 | 62 | ============================================================================== 63 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 64 | -------------------------------------------------------------------------------- /doc/Vital/Async/Promise/Deferred.txt: -------------------------------------------------------------------------------- 1 | *Vital/Async/Promise/Deferred.txt* Deferred style promise 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.Async.Promise.Deferred-content* 8 | 9 | INTRODUCTION |Vital.Async.Promise.Deferred-introduction| 10 | USAGE |Vital.Async.Promise.Deferred-usage| 11 | INTERFACE |Vital.Async.Promise.Deferred-interface| 12 | FUNCTION |Vital.Async.Promise.Deferred-function| 13 | 14 | 15 | ============================================================================= 16 | INTRODUCTION *Vital.Async.Promise.Deferred-introduction* 17 | 18 | *Vital.Async.Promise.Deferred* is an deferred style promise implementation. 19 | The deferred style promise become obsolete in JavaScript but it still has 20 | some advantage for writing unit tests which relies on promise feature while 21 | the deferred style promise can resolve/reject from outside of the scope. 22 | 23 | https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred 24 | 25 | 26 | ============================================================================= 27 | USAGE *Vital.Async.Promise.Deferred-usage* 28 | 29 | The code belows create a deferred style promise and resolve synchronously. 30 | It is not possible to write this kind of code with a native promise. 31 | > 32 | let s:Promise = vital#vital#import('Async.Promise') 33 | let s:Deferred = vital#vital#import('Async.Promise.Deferred') 34 | 35 | " Create a deferred promise 36 | let d = s:Deferred.new() 37 | 38 | " A deferred promise is a superset of a native promise 39 | echo s:Promise.is_promise(d) 40 | " -> 1 41 | 42 | " A status of the deferred promise can be changed outside of the 43 | " scope. 44 | call d.resolve('Hello') 45 | 46 | < 47 | 48 | ============================================================================= 49 | INTERFACE *Vital.Async.Promise.Deferred-interface* 50 | 51 | ----------------------------------------------------------------------------- 52 | FUNCTION *Vital.Async.Promise.Deferred-function* 53 | 54 | *Vital.Async.Promise.Deferred.new()* 55 | .new({source}) 56 | Create a new deferred style promise. 57 | The instance extends a native promise with the following methods. 58 | 59 | resolve([{value}]) Resolve the promise 60 | reject([{reason}]) Reject the promise 61 | 62 | ============================================================================= 63 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 64 | -------------------------------------------------------------------------------- /doc/Vital/Async/Promise/Process.txt: -------------------------------------------------------------------------------- 1 | *Vital.Async.Promise.Process.txt* System.Job wrapper with Promise 2 | 3 | Author: Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.Async.Promise.Process-contents* 8 | 9 | Introduction |Vital.Async.Promise.Process-introduction| 10 | Usage |Vital.Async.Promise.Process-usage| 11 | Functions |Vital.Async.Promise.Process-functions| 12 | 13 | 14 | ============================================================================= 15 | INTRODUCTION *Vital.Async.Promise.Process-introduction* 16 | 17 | *Vital.Async.Promise.Process* is a module to provide a way to execute an 18 | external program with a |Vital.Async.Promise| interface. 19 | 20 | It internally uses |Vital.System.Job| to execute a program so it works both 21 | on Vim and Neovim. 22 | 23 | Note that if intermediate data is necessary, see 24 | |Vital.Async.Observable.Process| instead. 25 | 26 | 27 | ============================================================================= 28 | USAGE *Vital.Async.Promise.Process-usage* 29 | 30 | Start an external program with |Vital.Async.Promise.Process.start()| function 31 | by appling command arguments like: 32 | > 33 | call Process.start(['echo', 'Hello']) 34 | \.then({ v -> execute('echo v', '') }) 35 | "{ 36 | " 'args': ['echo', 'Hello'], 37 | " 'stdout': ['Hello', ''], 38 | " 'stderr': [''], 39 | " 'exitval': 0, 40 | "} 41 | < 42 | 43 | ============================================================================= 44 | FUNCTIONS *Vital.Async.Promise.Process-functions* 45 | 46 | .start({args}[, {options}]) *Vital.Async.Promise.Process.start()* 47 | Execute a command {args} and return a Promise instance which will 48 | be resolved when the process is terminated. Note that even the process 49 | has terminated with non 0 exit-status, the promise is resolved rather 50 | than rejected unless "reject_on_failure" option has specified. The 51 | promise is rejected only when the process could not be started (e.g. 52 | the given executable is not found). 53 | 54 | The following attributes are available in {options}. 55 | 56 | "cwd" Force to execute a process in a given 57 | directory. Otherwise the process is executed 58 | under a current directory. 59 | "raw" TRUE to use raw data instead of \r removed 60 | data. 61 | "stdin" A Promise instance which resolve string or 62 | string list to send messages into the process. 63 | When this promise has resolved, the stdin 64 | channel will be closed. 65 | Note that rejection value is not used. 66 | "token" An instance of |Vital.Async.CancellationToken| 67 | to cancel process execution. 68 | "reject_on_failure" Reject when the process exit with failure exit 69 | status (non 0 exit status.) instead. 70 | "abort" A Promise instance which is used to abort the 71 | process. 72 | Note that rejection value is not used. 73 | WARNING deprecated. 74 | 75 | The promise instance will be resolved with an object which has the 76 | following attributes. 77 | 78 | "args" Given arguments 79 | "stdout" Stdout of the process in newline separated list. 80 | "stderr" Stderr of the process in newline separated list. 81 | "exitval" Exit value of the process 82 | 83 | 84 | is_available() *Vital.Async.Promise.Process.is_available()* 85 | Returns TRUE when requirements for using 86 | |Vital.Async.Promise.Process| are met. 87 | Requirements is that |Vital.Async.Promise| and |Vital.System.Job| 88 | work. 89 | Otherwise, returns FALSE. 90 | > 91 | if Process.is_available() 92 | " Asynchronous operations using Process Promise 93 | else 94 | " Fallback into synchronous operations 95 | endif 96 | < 97 | 98 | ============================================================================= 99 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 100 | -------------------------------------------------------------------------------- /doc/Vital/Config.txt: -------------------------------------------------------------------------------- 1 | *Vital/Config.txt* Define default variables 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================== 7 | CONTENTS *Vital.Config-contents* 8 | 9 | INTRODUCTION |Vital.Config-introduction| 10 | FUNCTION |Vital.Config-function| 11 | 12 | 13 | ============================================================================== 14 | INTRODUCTION *Vital.Config-introduction* 15 | 16 | *Vital.Config* is a plugin to define default variables. 17 | > 18 | let s:Config = vital#vital#import('Config') 19 | 20 | " Define the following only when the variable is missing 21 | " - g:vital#foo#bar#foo = 1 22 | " - g:vital#foo#bar#bar = 'bar' 23 | " Useful to define default variables 24 | call s:Config.define('vital#foo#bar', { 25 | \ 'foo': 1, 26 | \ 'bar': 'bar', 27 | \}) 28 | 29 | " Assign a corresponding variable name from 30 | call s:Config.config(expand(':p'), { 31 | \ 'foo': 1, 32 | \ 'bar': 'bar', 33 | \}) 34 | < 35 | 36 | Latest version: 37 | https://github.com/lambdalisue/vital-Config 38 | 39 | 40 | ============================================================================= 41 | FUNCTION *Vital.Config-function* 42 | 43 | *Vital.Config.define()* 44 | define({prefix}, {default}) 45 | Define missing values in a {default} dictionary as global variables. 46 | When "g:" is missing from the {prefix}, it is automatically 47 | prepended. 48 | 49 | *Vital.Config.config()* 50 | config({scriptfile}, {default}) 51 | An alternative of |Vital.Config.define()|. 52 | Developers can use with ||expand()| to automatically use a 53 | autoloadable variable name if they use exactly same name for the 54 | path to the vital's plugin name. 55 | 56 | For example, "g:gina#foo#bar" is used as a {prefix} if this module 57 | is located as "autoload/vital/__gina__/Config.vim" and the script 58 | is located as "autoload/gina/foo/bar.vim". Otherwise it may fail. 59 | 60 | Note that developers can confirm what name is used for a particular 61 | scriptfile path with |Vital.Config.trasnlate()| method. 62 | 63 | *Vital.Config.translate()* 64 | translate({scriptfile}) 65 | Return a corresponding variable name for the {scriptfile}. 66 | It is mainly for debug use. 67 | Note that the variable name of a scriptfile which is not located in 68 | a plugin-name (of vital.vim) directory cannot be translated. 69 | 70 | ============================================================================== 71 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 72 | -------------------------------------------------------------------------------- /doc/Vital/Data/List/Chunker.txt: -------------------------------------------------------------------------------- 1 | *vital-data-list-chunker.txt* Split a large list into several chunks 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.Data.List.Chunker-contents* 8 | 9 | INTRODUCTION |Vital.Data.List.Chunker-introduction| 10 | INTERFACE |Vital.Data.List.Chunker-interface| 11 | 12 | 13 | ============================================================================= 14 | INTRODUCTION *Vital.Data.List.Chunker-introduction* 15 | 16 | *Vital.Data.List.Chunker* is a module to split a large list into small chunks. 17 | For example, the following code split a large list into small chunks to 18 | improve the initial response. 19 | > 20 | let s:Chunker = vital#vital#import('Data.List.Chunker') 21 | 22 | function! Test() abort 23 | let candidates = range(1000) 24 | let chunker = s:Chunker.new(10, candidates) 25 | let chunker.bufnum = bufnr('%') 26 | 27 | if exists('s:timer_id') 28 | call timer_stop(s:timer_id) 29 | endif 30 | let s:timer_id = timer_start( 31 | \ 0, 32 | \ function('s:timer_callback', [chunker]) 33 | \) 34 | endfunction 35 | 36 | function! s:timer_callback(chunker, timer_id) abort 37 | if a:chunker.bufnum != bufnr('%') 38 | " The focus has moved to a differnt bufferso stop iteration. 39 | return 40 | endif 41 | 42 | let candidates = a:chunker.next() 43 | if empty(candidates) 44 | " There is no candidate left. Stop iteration. 45 | return 46 | endif 47 | 48 | call map(candidates, 's:parse_candidate(v:val)') 49 | call append(line('$'), candidates) 50 | let s:timer_id = timer_start( 51 | \ 100, 52 | \ function('s:timer_callback', [a:chunker]) 53 | \) 54 | endfunction 55 | 56 | function! s:parse_candidate(candidate) abort 57 | " Assume that parsing is a really heavy process 58 | sleep 1m 59 | return string(a:candidate) 60 | endfunction 61 | < 62 | Without chunker, it requires approx. 1000 x 1 ms to get the initial 63 | response. Using chunker reduce this initial response to approx. 10 x 1 ms so 64 | users would feel that the response has improved. 65 | Note that the total procession time would become longer with chunker. 66 | 67 | 68 | ============================================================================= 69 | INTERFACE *Vital.Data.List.Chunker-interface* 70 | 71 | *Vital.Data.List.Chunker.new()* 72 | .new({chunk_size}, {candidates}) 73 | Returns a new chunker instance. 74 | 75 | *Vital.Data.List.Chunker-instance.next()* 76 | chunker.next() 77 | Returns a next chunk. It returns an empty list when there are no 78 | candidate left so the following code iterate all chunks. 79 | > 80 | let chunk = chunker.next() 81 | while !empty(chunk) 82 | for candidate in chunk 83 | " Do something more useful! 84 | echo candidate 85 | endfor 86 | let chunk = chunker.next() 87 | endwhile 88 | < 89 | 90 | ============================================================================= 91 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 92 | -------------------------------------------------------------------------------- /doc/Vital/Lambda.txt: -------------------------------------------------------------------------------- 1 | *Vital/Lambda.txt* Function collection for lambda function 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================== 7 | CONTENTS *Vital.Lambda-contents* 8 | 9 | FUNCTION |Vital.Lambda-function| 10 | 11 | 12 | ============================================================================= 13 | FUNCTION *Vital.Lambda-function* 14 | 15 | *Vital.Lambda.void()* 16 | void([{args}...]) 17 | The function itself does nothing. It is used to invoke multiple 18 | expression in a single expression. 19 | > 20 | " Invoke A, B, C in a single lambda function 21 | let l:F = { -> s:Lambda.void(A(), B(), C()) } 22 | echo F() 23 | " -> 0 24 | < 25 | *Vital.Lambda.pass()* 26 | pass({value}[, {args}...]) 27 | It is like |Vital.Lambda.void()| but it always returns {value}. 28 | > 29 | " Invoke A, B, C in a single lambda function 30 | let l:F = { -> s:Lambda.pass(v:null, A(), B(), C()) } 31 | echo F() 32 | " -> v:null 33 | < 34 | *Vital.Lambda.let()* 35 | let({object}, {key}, {value}) 36 | It executes |let| command; assigns {key} as {value} to {object}. 37 | > 38 | let obj = {} 39 | call s:Lambda.let(obj, 'foo', 'bar') 40 | echo obj 41 | " -> { 'foo': 'bar' } 42 | < 43 | *Vital.Lambda.unlet()* 44 | unlet({object}, {key}[, {force}]) 45 | It executes |unlet| command; removes {key} from {object}. 46 | It does not throw exception for missing {key} if {force} is 1. 47 | > 48 | let obj = {'foo': 'bar'} 49 | call s:Lambda.unlet(obj, 'foo') 50 | echo obj 51 | " -> {} 52 | < 53 | *Vital.Lambda.throw()* 54 | throw({message}) 55 | It executes |throw| command; throws {message} exception. 56 | > 57 | call s:Lambda.throw('hello world') 58 | " Error: 'hello world' 59 | < 60 | *Vital.Lambda.echo()* 61 | echo({message}) 62 | It executes |echo| command; echos {message}. 63 | > 64 | call s:Lambda.echo('hello world') 65 | " -> 'hello world' 66 | < 67 | *Vital.Lambda.echomsg()* 68 | echomsg({message}) 69 | It executes |echomsg| command; echos {message}. 70 | > 71 | call s:Lambda.echomsg('hello world') 72 | " -> 'hello world' 73 | < 74 | *Vital.Lambda.if()* 75 | if({condition}, {true}[, {false}]) 76 | It returns an execution result of {true} function if {condition} is 77 | TRUE. Otherwise it returns an execution result of {false} or 0 if 78 | {false} is not specified. 79 | > 80 | echo s:Lambda.if(0 is# 0, { -> 'yes' }) 81 | " -> 'yes' 82 | echo s:Lambda.if(0 is# 1, { -> 'yes' }) 83 | " -> 0 84 | echo s:Lambda.if(0 is# 1, { -> 'yes' }, { -> 'no' }) 85 | " -> 'no' 86 | < 87 | *Vital.Lambda.map()* 88 | map({list}, {fn}) 89 | It returns a copies of {fn} applied {list}. 90 | Note that the order of argument for {fn} is inverted compared to the 91 | |map()| function to keep the order among map, filter, and reduce. 92 | > 93 | let list = [5, 4, 3, 2, 1] 94 | echo s:Lambda.map(list, { v -> v + 1 }) 95 | " -> [6, 5, 4, 3, 2] 96 | echo list 97 | " -> [5, 4, 3, 2, 1] 98 | echo s:Lambda.map(list, { _, k -> k + 1 }) 99 | " -> [1, 2, 3, 4, 5] 100 | < 101 | *Vital.Lambda.filter()* 102 | filter({list}, {fn}) 103 | It returns a copies of {list} filtered by {fn}. 104 | Note that the order of argument for {fn} is inverted compared to the 105 | |filter()| function to keep the order among map, filter, and reduce. 106 | > 107 | let list = [5, 4, 3, 2, 1] 108 | echo s:Lambda.filter(list, { v -> v % 2 is# 0 }) 109 | " -> [4, 2] 110 | echo list 111 | " -> [5, 4, 3, 2, 1] 112 | echo s:Lambda.filter(list, { _, k -> k % 2 is# 0 }) 113 | " -> [5, 3, 1] 114 | < 115 | *Vital.Lambda.reduce()* 116 | reduce({list}, {fn}[, {init}]) 117 | It returns an accumulated value of {list} accumulated by {fn}. 118 | Note that if {init} is missing, the first value of {list} is used 119 | as an initial value instead. 120 | > 121 | let list = [5, 4, 3, 2, 1] 122 | echo s:Lambda.reduce(list, { a, v -> a + v }) 123 | " -> 15 124 | echo list 125 | " -> [5, 4, 3, 2, 1] 126 | 127 | echo s:Lambda.reduce(list, { a, v -> a + v }, 5) 128 | " -> 20 129 | < 130 | *Vital.Lambda.map_f()* 131 | map_f({fn}) 132 | It returns a function to map a first argument with given {fn}. 133 | 134 | *Vital.Lambda.filter_f()* 135 | filter_f({fn}) 136 | It returns a function to filter a first argument with given {fn}. 137 | 138 | *Vital.Lambda.reduce_f()* 139 | reduce_f({fn}[, {init}]) 140 | It returns a function to reduce a first argument with given {fn} and. 141 | {init}. 142 | 143 | ============================================================================== 144 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 145 | -------------------------------------------------------------------------------- /doc/Vital/Path.txt: -------------------------------------------------------------------------------- 1 | *Vital/Path.txt* Utility module for manipulating slash-separated paths 2 | 3 | 4 | ============================================================================== 5 | CONTENTS *Vital.Path-contents* 6 | 7 | INTRODUCTION |Vital.Path-introduction| 8 | FUNCTION |Vital.Path-function| 9 | 10 | 11 | ============================================================================== 12 | INTRODUCTION *Vital.Path-introduction* 13 | 14 | *Vital.Path* is utility module for manipulating slash-separated paths. 15 | This module does not deal with Windows paths so use |Vital.Path.Filepath| to 16 | convert file system paths to slash-separated paths prior to manipulate. 17 | 18 | 19 | ============================================================================= 20 | FUNCTION *Vital.Path-function* 21 | 22 | *Vital.Path.simplify()* 23 | simplify({path}) 24 | Return simplified path (|String|) of the {path}. It will 25 | 1. Remove duplicate slashes 26 | 2. Remove trailing slashes 27 | 3. Remove middle '.' 28 | 4. Remove '..' and corresponding components 29 | > 30 | Path.simplify("/usr//local/./bin/../../bin/") 31 | " -> /usr/bin 32 | < 33 | *Vital.Path.commonpath()* 34 | commonpath({paths}) 35 | Return a common path (|String|) among the {paths}. 36 | > 37 | Path.commonpath([ 38 | \ '/usr/local/bin/vim', 39 | \ '/usr/local/openssh', 40 | \ '/usr/bin/vim', 41 | \]) 42 | " -> '/usr' 43 | 44 | Path.commonpath([ 45 | \ '/usr/local/bin/vim', 46 | \ '/usr/local/openssh', 47 | \ '/vim', 48 | \]) 49 | " -> '/' 50 | < 51 | *Vital.Path.absolute()* 52 | absolute({path}, {base}) 53 | Return an absolute path (|String|) of the {path} from the {base}. 54 | It return the {path} as-is if the {path} is already absolute path. 55 | > 56 | Path.absolute('usr/local', '/home/vim') 57 | " -> '/home/vim/usr/local' 58 | 59 | Path.absolute('/usr/local', '/home/vim') 60 | " -> '/usr/local' 61 | < 62 | *Vital.Path.relative()* 63 | relative({path}, {base}) 64 | Return a relative path (|String|) of the {path} from the {base}. 65 | It return the {path} as-is if the {path} is already relative path. 66 | > 67 | Path.relative('/home/vim/usr/local', '/home/vim') 68 | " -> 'usr/local' 69 | 70 | Path.relative('usr/local', '/home/vim') 71 | " -> 'usr/local' 72 | < 73 | *Vital.Path.basename()* 74 | basename({path}) 75 | Return a last component (|String|) of the {path}. It removes trailing 76 | slashes prior to get the last component. 77 | It returns "/" if the {path} is root and "" if the {path} is empty. 78 | > 79 | Path.basename('/usr/local') 80 | " -> 'local' 81 | 82 | Path.basename('/usr/local//') 83 | " -> 'local' 84 | 85 | Path.basename('/') 86 | " -> '/' 87 | 88 | Path.basename('') 89 | " -> '' 90 | < 91 | *Vital.Path.dirname()* 92 | dirname({path}) 93 | Return a last component removed path (|String|) of the {path}. It 94 | removes trailing slashes prior to remove a last component. 95 | It returns "/" if the {path} is a root and "" if the {path} is empty. 96 | > 97 | Path.dirname('/usr/local') 98 | " -> '/usr' 99 | 100 | Path.dirname('/usr/local//') 101 | " -> '/usr' 102 | 103 | Path.dirname('/') 104 | " -> '/' 105 | 106 | Path.dirname('') 107 | " -> '' 108 | < 109 | 110 | ============================================================================== 111 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 112 | -------------------------------------------------------------------------------- /doc/Vital/Path/Filepath.txt: -------------------------------------------------------------------------------- 1 | *Vital/Path/Filepath.txt* Utility module for manipulating system paths 2 | 3 | 4 | ============================================================================== 5 | CONTENTS *Vital.Path.Filepath-contents* 6 | 7 | INTRODUCTION |Vital.Path.Filepath-introduction| 8 | FUNCTION |Vital.Path.Filepath-function| 9 | 10 | 11 | ============================================================================== 12 | INTRODUCTION *Vital.Path.Filepath-introduction* 13 | 14 | |Vital.Path.Filepath| is a utility module for manipulating file system paths. 15 | Use this module to convert file system paths to slash-separated paths and 16 | manipulate the paths with |Vital.Path|. 17 | 18 | 19 | ============================================================================= 20 | FUNCTION *Vital.Path.Filepath-function* 21 | 22 | *Vital.Path.Filepath.to_slash()* 23 | to_slash({path}) 24 | Return simplified slash (/) path (|String|) from the file system {path}. 25 | > 26 | " On Unix 27 | Filepath.to_slash('/usr/local') 28 | " -> '/usr/local' 29 | 30 | " On Windows 31 | Filepath.to_slash('C:\Windows\System32') 32 | " -> '/C:/Windows/System32' 33 | < 34 | *Vital.Path.Filepath.from_slash()* 35 | from_slash({path}) 36 | Return simplified file system path (|String|) of the slash (/) {path}. 37 | > 38 | " On Unix 39 | Filepath.from_slash('/usr/local') 40 | " -> '/usr/local' 41 | 42 | " On Windows 43 | Filepath.from_slash('/C:/Windows/System32') 44 | " -> 'C:\Windows\System32' 45 | < 46 | *Vital.Path.Filepath.is_root()* 47 | is_root({path}) 48 | Return 1 when the {path} is the file system root path. 49 | > 50 | " On Unix 51 | Filepath.is_root('/') 52 | " -> 1 53 | Filepath.is_root('') 54 | " -> 0 55 | Filepath.is_root('/usr/local') 56 | " -> 0 57 | 58 | " On Windows 59 | Filepath.is_root('') 60 | " -> 1 61 | Filepath.is_root('C:\Windows\System32') 62 | " -> 0 63 | < 64 | *Vital.Path.Filepath.is_drive_root()* 65 | is_drive_root({path}) 66 | Return 1 when the {path} is the file system drive root path. 67 | > 68 | " On Unix 69 | Filepath.is_drive_root('/') 70 | " -> 1 71 | Filepath.is_drive_root('') 72 | " -> 0 73 | Filepath.is_drive_root('/usr/local') 74 | " -> 0 75 | 76 | " On Windows 77 | Filepath.is_drive_root('C:\') 78 | " -> 1 79 | Filepath.is_drive_root('') 80 | " -> 0 81 | Filepath.is_drive_root('C:\Windows\System32') 82 | " -> 0 83 | < 84 | *Vital.Path.Filepath.is_absolute()* 85 | is_absolute({path}) 86 | Return 1 when the {path} is the file system absolute path. 87 | > 88 | " On Unix 89 | Filepath.is_absolute('/usr/local') 90 | " -> 1 91 | Filepath.is_absolute('/') 92 | " -> 1 93 | Filepath.is_absolute('') " To keep behavior consistency to Win 94 | " -> 1 95 | Filepath.is_absolute('usr/local') 96 | " -> 0 97 | 98 | " On Windows 99 | Filepath.is_absolute('C:\Windows\System32') 100 | " -> 1 101 | Filepath.is_absolute('C:\') 102 | " -> 1 103 | Filepath.is_absolute('') 104 | " -> 1 105 | Filepath.is_absolute('Windows\System32') 106 | " -> 0 107 | < 108 | *Vital.Path.Filepath.join()* 109 | join({paths}) 110 | Return file system joined path (|String|) of {paths}. 111 | > 112 | " On Unix 113 | Filepath.join(['/usr/local', 'bin']) 114 | " -> '/usr/local/bin' 115 | 116 | " On Windows 117 | Filepath.join(['C:\Windows\System32', 'Foo']) 118 | " -> 'C:\Windows\System32\Foo' 119 | < 120 | ============================================================================== 121 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 122 | -------------------------------------------------------------------------------- /doc/Vital/Prompt.txt: -------------------------------------------------------------------------------- 1 | *Vital/Prompt.txt* Prompt vital module 2 | 3 | Author : Alisue 4 | DEPRECATED 5 | 6 | 7 | 8 | ============================================================================== 9 | CONTENTS *Vital.Prompt-contents* 10 | 11 | FUNCTION |Vital.Prompt-function| 12 | 13 | 14 | ============================================================================= 15 | FUNCTION *Vital.Prompt-function* 16 | 17 | *Vital.Prompt.input()* 18 | input({prompt}[, {text}[, {comp}[, {default}]]]) 19 | An |input()| which returns the {default} (default: |v:null|) instead 20 | when user cancelled the input by . 21 | Note that the function allows |Funcref| which is used for 'customlist' 22 | to the {comp}. 23 | 24 | *Vital.Prompt.ask()* 25 | ask({prompt}[, {text}[, {comp}[, {default}]]]) 26 | Ask a question ({prompt}) to user and return the result. 27 | 28 | It invokes |inputsave()| and |inputrestore()| automatically to make 29 | the function safe in mapping. 30 | 31 | *Vital.Prompt.confirm()* 32 | confirm({prompt}[, {default}]) 33 | Ask a yes/no question ({prompt}) to user and return 1/0. 34 | 35 | It invokes |inputsave()| and |inputrestore()| automatically to make 36 | the function safe in mapping. 37 | *Vital.Prompt.select()* 38 | select({prompt}[, {max}[, {min}[, {pattern}]]]) 39 | Select an answer from {promt} and return |String|. 40 | 41 | A value has limited to the {pattern} (default: '\d') and the length of 42 | the string has limited by {max} (default: 1) and {min} (default: 1). 43 | 44 | It invokes |inputsave()| and |inputrestore()| automatically to make 45 | the function safe in mapping. 46 | 47 | ============================================================================== 48 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 49 | -------------------------------------------------------------------------------- /doc/Vital/System/Sandbox.txt: -------------------------------------------------------------------------------- 1 | *Vital/System/Sandbox.txt* Create a sandbox directory and move in 2 | 3 | Author : Alisue 4 | 5 | 6 | ============================================================================= 7 | CONTENTS *Vital.System.Sandbox-content* 8 | 9 | INTRODUCTION |Vital.System.Sandbox-introduction| 10 | FUNCTION |Vital.System.Sandbox-function| 11 | INSTANCE |Vital.System.Sandbox-instance| 12 | 13 | 14 | ============================================================================= 15 | INTRODUCTION *Vital.System.Sandbox-introduction* 16 | 17 | *Vital.System.Sandbox* is library to create and move into a temporary 18 | directory. 19 | 20 | 21 | ============================================================================= 22 | FUNCTION *Vital.System.Sandbox-function* 23 | 24 | .new([{factory}]) *Vital.System.Sandbox.new()* 25 | 26 | Create a new sandbox instance, a home directory of the sandbox 27 | instance, and change the current working directory to the home 28 | directory of the sandbox. 29 | 30 | If {factory} function is given, it determines the home directory of 31 | the sandbox via calling the function. Otherwise it uses |tempname()| 32 | function to determine the home directory. 33 | 34 | Note that the home directory of the sandbox instance will be created 35 | with the protection bits as 0700. So if you need to make the home 36 | readable from others, create the home directory by yourself and give 37 | a {factory} function which returns the created home directory. 38 | 39 | 40 | ============================================================================= 41 | INSTANCE *Vital.System.Sandbox-instance* 42 | 43 | .origin() *Vital.System.Sandbox-instance.origin()* 44 | 45 | Return an origin directory path of the sandbox. 46 | The origin directory of the sandbox is a previous current working 47 | directory prior to the creation of the sandbox. 48 | > 49 | echo getcwd() 50 | " /home/foobar 51 | 52 | let s = Sandbox.new() 53 | 54 | echo getcwd() 55 | " /tmp/xxxx/xxxx/xxxx 56 | 57 | echo s.origin() 58 | " /home/foobar 59 | < 60 | 61 | .path([{path}]) *Vital.System.Sandbox-instance.path()* 62 | 63 | Return an absolute path of a given {path} in the home directory of 64 | the sandbox. 65 | It throws an exception when {path} is an absolute path. 66 | 67 | Note that the path is normalized via |resolve()| function. 68 | > 69 | let s = Sandbox.new() 70 | 71 | echo getcwd() 72 | " /tmp/xxxx/xxxx/xxxx 73 | 74 | echo s.path() 75 | " /tmp/xxxx/xxxx/xxxx 76 | 77 | echo s.path('foo') 78 | " /tmp/xxxx/xxxx/xxxx/foo 79 | 80 | echo s.path('bar') 81 | " /tmp/xxxx/xxxx/xxxx/bar 82 | < 83 | 84 | .visit({path}) *Vital.System.Sandbox-instance.visit()* 85 | 86 | Create and change the current directory into a given {path} in the 87 | home directory of the sandbox. 88 | 89 | Note that the {path} directory will be created with the protection 90 | bits as 0700. So if you need to make it readable from others, create 91 | the directory by yourself prior to calling this method. 92 | > 93 | let s = Sandbox.new() 94 | 95 | echo getcwd() 96 | " /tmp/xxxx/xxxx/xxxx 97 | 98 | call s.visit('foo') 99 | echo getcwd() 100 | " /tmp/xxxx/xxxx/xxxx/foo 101 | 102 | call s.visit('bar') 103 | echo getcwd() 104 | " /tmp/xxxx/xxxx/xxxx/bar 105 | < 106 | 107 | .return() *Vital.System.Sandbox-instance.return()* 108 | 109 | Change the current working directory to the home directory of the 110 | sandbox. 111 | > 112 | let s = Sandbox.new() 113 | 114 | echo getcwd() 115 | " /tmp/xxxx/xxxx/xxxx 116 | 117 | call s.visit('foo') 118 | echo getcwd() 119 | " /tmp/xxxx/xxxx/xxxx/foo 120 | 121 | call s.return() 122 | echo getcwd() 123 | " /tmp/xxxx/xxxx/xxxx 124 | < 125 | 126 | .dispose() *Vital.System.Sandbox-instance.dispose()* 127 | 128 | Change the current working directory to the origin directory of the 129 | sandbox and remove any files/directories in the home directory of the 130 | sandbox. 131 | > 132 | echo getcwd() 133 | " /home/foobar 134 | 135 | let s = Sandbox.new() 136 | call s.visit('foo') 137 | call s.visit('bar') 138 | 139 | call s.dispose() 140 | echo getcwd() 141 | " /home/foobar 142 | echo isdirectory(s.path()) 143 | " 0 144 | < 145 | 146 | ============================================================================= 147 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 148 | -------------------------------------------------------------------------------- /doc/Vital/Vim/Buffer/ANSI.txt: -------------------------------------------------------------------------------- 1 | *Vital/Vim/Buffer/ANSI.txt* Highlight ANSI color sequences 2 | 3 | Author : Alisue 4 | DEPRECATED 5 | 6 | 7 | ============================================================================= 8 | CONTENTS *Vital.Vim.Buffer.ANSI-contents* 9 | 10 | USAGE |Vital.Vim.Buffer.ANSI-usage| 11 | FUNCTIONS |Vital.Vim.Buffer.ANSI-functions| 12 | HIGHLIGHTS |Vital.Vim.Buffer.ANSI-highlights| 13 | 14 | 15 | ============================================================================== 16 | USAGE *Vital.Vim.Buffer.ANSI-usage* 17 | > 18 | let s:ANSI = vital#vital#import('Vim.Buffer.ANSI') 19 | 20 | function! s:demo() abort 21 | let content = [ 22 | \ "\e[31mRed\e[m", 23 | \ "\e[32mGreen\e[m", 24 | \ "\e[33mYellow\e[m", 25 | \] 26 | new 27 | call append(0, content) 28 | call s:ANSI.define_syntax() 29 | endfunction 30 | 31 | call s:demo() 32 | < 33 | 34 | ============================================================================== 35 | FUNCTIONS *Vital.Vim.Buffer.ANSI-functions* 36 | 37 | *Vital.Vim.Buffer.ANSI.define_syntax()* 38 | define_syntax([{prefix}]) 39 | Define |syntax| for ANSI color sequences. 40 | Note taht 'conceallevel' and 'concealcursor' options will be 41 | configured automatically. 42 | 43 | It defines the following syntaxes. 44 | 45 | Name Description~ 46 | AnsiSuppress To supress ANSI sequence. 47 | AnsiColor0-15 See |Vital.Vim.Buffer.ANSI-highlights|. 48 | AnsiColors Syntax group of the above 16 colors. 49 | 50 | If {prefix} is specified, it define AnsiColor0-15 and AnsiColors with 51 | the specified {prefix} instead. 52 | 53 | 54 | ============================================================================== 55 | HIGHLIGHTS *Vital.Vim.Buffer.ANSI-highlights* 56 | 57 | This module define the following default highlights. 58 | 59 | Name ANSI sequence~ 60 | AnsiColor0 \e[30m 61 | AnsiColor1 \e[31m 62 | AnsiColor2 \e[32m 63 | AnsiColor3 \e[33m 64 | AnsiColor4 \e[34m 65 | AnsiColor5 \e[35m 66 | AnsiColor6 \e[36m 67 | AnsiColor7 \e[37m 68 | AnsiColor8 \e[1;30m or \e[30;1m 69 | AnsiColor9 \e[1;31m or \e[31;1m 70 | AnsiColor10 \e[1;32m or \e[32;1m 71 | AnsiColor11 \e[1;33m or \e[33;1m 72 | AnsiColor12 \e[1;34m or \e[34;1m 73 | AnsiColor13 \e[1;35m or \e[35;1m 74 | AnsiColor14 \e[1;36m or \e[36;1m 75 | AnsiColor15 \e[1;37m or \e[37;1m 76 | 77 | The color for the default highlights above were taken from 78 | https://github.com/w0ng/vim-hybrid 79 | 80 | 81 | ============================================================================== 82 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 83 | -------------------------------------------------------------------------------- /doc/Vital/Vim/Buffer/Group.txt: -------------------------------------------------------------------------------- 1 | *Vital/Vim/Buffer/Group.txt* A vital module for grouping buffers 2 | 3 | Author : Alisue 4 | DEPRECATED 5 | 6 | 7 | ============================================================================= 8 | CONTENTS *Vital.Vim.Buffer.Group-content* 9 | 10 | INTRODUCTION |Vital.Vim.Buffer.Group-introduction| 11 | USAGE |Vital.Vim.Buffer.Group-usage| 12 | INTERFACE |Vital.Vim.Buffer.Group-interface| 13 | 14 | 15 | ============================================================================= 16 | INTRODUCTION *Vital.Vim.Buffer.Group-introduction* 17 | 18 | *Vital.Vim.Buffer.Group* is a library for grouping buffers. 19 | It is used to close all related buffers at the same time. 20 | 21 | 22 | ============================================================================= 23 | USAGE *Vital.Vim.Buffer.Group-usage* 24 | 25 | Create a group instance and use "add()" method to make associated buffers. 26 | > 27 | let s:Group = vital#{plugin}#import('Vim.Buffer.Group') 28 | let group1 = s:Group.new() 29 | 30 | edit Hello 31 | split foo1 32 | split foo2 33 | split foo3 34 | call group1.add() " foo3 is added 35 | call group1.add({'expr': 'foo2'}) " foo2 is added 36 | call group1.add({'expr': 'foo1', 'keep': 1}) " foo1 is added 37 | 38 | " Behavior 39 | " 1. When Hello is closed, foo1-3 stays. 40 | " 2. When foo1 is closed, all foo2-3 will be closed. 41 | " 3. When foo2 is closed, foo3 will be closed. 42 | " 4. When foo3 is closed, foo2 will be closed. 43 | < 44 | ============================================================================= 45 | INTERFACE *Vital.Vim.Buffer.Group-interface* 46 | 47 | *Vital.Vim.Buffer.Group.new()* 48 | new([{options}]) 49 | Create a new group instance. 50 | The following option is available on {options}. 51 | 52 | "on_close_fail" A |Funcref| which is called when |E444| 53 | exception (Cannot close last window) is 54 | raised for closing related buffers. 55 | 56 | The "on_close_fail" callback is called as a dictionary function 57 | of the group instance with {winnr} and {member} arguments. 58 | The {winnr} is a window number which the target buffer is shown. 59 | The {member} is an instance which has the following attributes 60 | 61 | "bufnr" A buffer number 62 | "winid" A window ID 63 | "options" An {options} used in "add()" method. 64 | 65 | Developers can use "on_close_fail" to quit Vim for example 66 | > 67 | function! s:on_close_fail(winnr, member) abort 68 | quit! 69 | endfunction 70 | 71 | let group = s:Group.new({ 72 | \ 'on_close_fail': function('s:on_close_fail') 73 | \}) 74 | " Add buffers ... 75 | < 76 | ----------------------------------------------------------------------------- 77 | INSTANCE *Vital.Vim.Buffer.Group-instance* 78 | 79 | *Vital.Vim.Buffer.Group-instance.add()* 80 | {group}.add([{options}]) 81 | Add a current/specified buffer to the {group} instance. 82 | The following options are available on {options}. 83 | 84 | "keep" If 1 is specified, the buffer is not closed when 85 | other members has closed. 86 | "expr" An {expr} used in |bufnr()| and |bufwinid()|. 87 | If omit, "%" is used to indicate the current buffer 88 | 89 | Use "keep" to protect a main buffer. For example, assume you have 90 | three related buffers. The one is a main content and other two are 91 | header and sidebar. In this case, you would like to close header and 92 | sidebar when the main content has closed BUT you would like to keep 93 | open the main content when header/sidebar has closed. Then, do like 94 | > 95 | edit main-content 96 | 20split header 97 | wincmd p 98 | 50vsplit sidebar 99 | wincmd p 100 | call group.add({'expr': 'main-content', 'keep': 1}) 101 | call group.add({'expr': 'header'}) 102 | call group.add({'expr': 'sidebar'}) 103 | < 104 | *Vital.Vim.Buffer.Group-instance.close()* 105 | {group}.close() 106 | Close all associated buffers of the {group}. 107 | It is a method which is automatically called when one of an 108 | associated buffer of the {group} has closed. 109 | It use |close| command internally so it silently fails to close the 110 | last window. Use "on_close_fail" callback if you would like to do 111 | something in that case. 112 | 113 | Note that a buffer with "keep" is not closed by this method. 114 | 115 | 116 | ============================================================================= 117 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 118 | -------------------------------------------------------------------------------- /doc/Vital/Vim/Buffer/Opener.txt: -------------------------------------------------------------------------------- 1 | *Vital/Vim/Buffer/Opener.txt* A vital module for opening buffers 2 | 3 | Author : Alisue 4 | DEPRECATED 5 | 6 | 7 | ============================================================================= 8 | CONTENTS *Vital.Vim.Buffer.Opener-content* 9 | 10 | INTRODUCTION |Vital.Vim.Buffer.Opener-introduction| 11 | USAGE |Vital.Vim.Buffer.Opener-usage| 12 | INTERFACE |Vital.Vim.Buffer.Opener-interface| 13 | 14 | 15 | ============================================================================= 16 | INTRODUCTION *Vital.Vim.Buffer.Opener-introduction* 17 | 18 | *Vital.Vim.Buffer.Opener* is a simple library to open a buffer. 19 | Not like |Vital.Vim.Buffer.open()| or |Vital.Vim.BufferManager-Manager.open()|, 20 | it makes sure that the current focus is on a buffer specified even an opener 21 | for preview window (such as |pedit|) has used. 22 | 23 | 24 | ============================================================================= 25 | USAGE *Vital.Vim.Buffer.Opener-usage* 26 | 27 | Following example directly use |append()| function just after opening a 28 | buffer. 29 | > 30 | let s:Opener = vital#vital#import('Vim.Buffer.Opener') 31 | 32 | function! s:open_pseudo_file(opener) abort 33 | let config = { 'opener': a:opener } 34 | let context = s:Opener.open('a pseudo file', config) 35 | 36 | " The focus is on a target buffer even an opener for preview window 37 | " such as 'pedit' has specified so using append() directly is safe. 38 | call append(line('$'), ['This is a pseudo content']) 39 | 40 | " Focus back if necessary 41 | call context.end() 42 | endfunction 43 | 44 | command! -nargs=* OpenPseudoFile call s:open_pseudo_file() 45 | < 46 | Basically when {opener} is an opener for preview window (e.g |pedit|), |append()| 47 | will be pefromed on a wrong buffer because |pedit| does not move the focus to a 48 | opened buffer. 49 | Using |Vital.Vim.Buffer.Opener| solve this issue by focusing a specified 50 | buffer even the buffer is a |previewwindow|. 51 | 52 | 53 | ============================================================================= 54 | INTERFACE *Vital.Vim.Buffer.Opener-interface* 55 | 56 | *Vital.Vim.Buffer.Opener.open()* 57 | open({buffer}[, {config}]) 58 | Open a {buffer} with a mannar specified by {config}. 59 | Note that when there is a swap file, user is requested to choose an 60 | action and |E325|| exception will be cached and ignored. 61 | The following attributes are allowed for {config}: 62 | 63 | "mods" 64 | A command modifiers () such as |vertical|. 65 | 66 | "opener" 67 | An opener string such as "edit" or "split". If an opener for preview 68 | window (e.g. |pedit|) has specified, it removes the "group" config 69 | specified. 70 | The default value is "edit". 71 | 72 | "group" 73 | A window group name. If a group name is specified, it tries to reuse 74 | the same group name window and ignore "opener" if a same group name 75 | window is found. Note that if an opener for preview window (e.g 76 | |pedit|) has specified, the value of "group" is ignored. 77 | The default value is "". 78 | 79 | "range" 80 | A range used to find a same group name window. Available values are 81 | "tabpage" and "all". 82 | The default value is "tabpage". 83 | 84 | "force" 85 | If 1, a specified {buffer} is focused even an opener for preview 86 | window has used. To focus back, call "context.end()" method. 87 | 88 | This function returns a {context} dictionary which has the following 89 | attributes and method: 90 | 91 | "preview" 92 | 1 or 0, if a specified {buffer} is opened as a previewwindow. 93 | 94 | "bufloaded" 95 | A value of |bufloaded| for a {buffer} before open. So that 0 means the 96 | buffer was not loaded and has loaded with this function. 97 | 98 | "bufexists" 99 | A value of |bufexists| for a {buffer} before open. So that 0 means the 100 | buffer did not exist and has created with this function. 101 | 102 | "bufnr" 103 | A buffer number of a {buffer}. It is a correct value even for an 104 | opener for preview window. 105 | 106 | "bufname" 107 | A buffer name of a {buffer}. It is a correct value even for an opener 108 | for preview window. 109 | 110 | "focusto" 111 | May exist. It is a buffer number and indicate that the focus should 112 | be moved into that buffer when "context.end()" is called. 113 | 114 | "end()" 115 | A method which focus back to "focusto" buffer. It does nothing if no 116 | focus back is required. 117 | 118 | *Vital.Vim.Buffer.Opener.is_preview_openr()* 119 | is_preview_opener{opener}) 120 | Return if the {opener} is for preview window. 121 | 122 | 123 | ============================================================================= 124 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 125 | -------------------------------------------------------------------------------- /doc/Vital/Vim/Buffer/Writer.txt: -------------------------------------------------------------------------------- 1 | *Vital/Vim/Buffer/Writer.txt* A vital module for writing buffer contents 2 | 3 | Author : Alisue 4 | DEPRECATED 5 | 6 | 7 | ============================================================================= 8 | CONTENTS *Vital.Vim.Buffer.Writer-content* 9 | 10 | INTRODUCTION |Vital.Vim.Buffer.Writer-introduction| 11 | INTERFACE |Vital.Vim.Buffer.Writer-interface| 12 | 13 | 14 | ============================================================================= 15 | INTRODUCTION *Vital.Vim.Buffer.Writer-introduction* 16 | 17 | *Vital.Vim.Buffer.Writer* is a module to write buffer contents. 18 | It is mainly used for gradually write mass contents to the buffer without 19 | interrupting user's actions. 20 | 21 | 22 | ============================================================================= 23 | INTERFACE *Vital.Vim.Buffer.Writer-interface* 24 | 25 | *Vital.Vim.Buffer.Writer.replace()* 26 | replace({expr}, {start}, {end}, {replacement}) 27 | Replace contents between {start} to {end} of a {expr} buffer with 28 | a given {replacement} (|List|). 29 | 30 | Indexing of {start} and {end} is zero-based and end-exclusive. 31 | Additionally the negative indices are counts from the last, mean that 32 | the -1 indicate the last line. 33 | 34 | For example 35 | > 36 | call Writer.replace('%', 0, 0, ['Hello']) 37 | " Insert 'Hello' line at the top of the buffer 38 | 39 | call Writer.replace('%', -1, -1, ['World']) 40 | " Append 'World' line at the bottom of the buffer 41 | 42 | call Writer.replace('%', -2, -1, ['Darkness']) 43 | " Replace the last 'World' line to 'Darkness' 44 | 45 | call Writer.replace('%', 0, -1, []) 46 | " Remove entire contents 47 | < 48 | Note that it uses |iconv()| function to convert {replacement} from 49 | 'encoding' to 'fileencoding' of the {expr} buffer. However, it uses 50 | {replacement} as-is when 51 | 52 | 1. 'fileencoding' of the {expr} buffer is empty 53 | 2. 'encoding' and 'fileencoding' of the {expr} buffer is equal 54 | 3. |iconv()| completely failed to convert {replacement} 55 | 56 | Note that this method works even the {expr} buffer is 57 | specified as 'nomodifiable' buffer. It temporary off that option and 58 | restore. 59 | 60 | Note that using this method may temporary change a current buffer 61 | in Vim. However it does not affects the followings 62 | 63 | 1. Content of non target buffer 64 | 2. cursor position 65 | 3. |alternate-file| 66 | 4. |jumplist|| 67 | 68 | But it would affects the followings (the behavior has not defined or 69 | tested yet.) 70 | 71 | 1. |undolist|| 72 | 73 | Note that this method does not work and return 1 when 74 | 75 | 1. The {expr} buffer does not exist 76 | 2. Vim is going to close (|VimLeave| has emitted) 77 | 3. |v:dying| is not 0 (Vim is forcedly closing) 78 | 79 | *Vital.Vim.Buffer.Writer.new()* 80 | new([{options}]) 81 | Create a new writer instance. 82 | The following options are available on {options}. 83 | 84 | "bufnr" A target buffer number. 85 | Default is a current buffer number. 86 | 87 | "updatetime" An interval milliseconds between each flush. 88 | Default is |Vital.Vim.Buffer.Writer.updatetime|. 89 | 90 | ----------------------------------------------------------------------------- 91 | INSTANCE *Vital.Vim.Buffer.Writer-instance* 92 | 93 | *Vital.Vim.Buffer.Writer-instance.start()* 94 | {writer}.start() 95 | Start an internal timer of the {writer}. 96 | The internaly timer periodically call "flush()" method of the 97 | {writer} to update the target buffer contents. 98 | 99 | It kill existing writer instances which have an equal target buffer. 100 | 101 | It calls "on_start()" callback of the {writer} if the callback 102 | exists on the instance. 103 | 104 | Note that it does nothing when the {writer} has already started. 105 | 106 | *Vital.Vim.Buffer.Writer-instance.stop()* 107 | {writer}.stop() 108 | Stop an internal timer of the {writer} on next tick so that the 109 | last empty line can be removed (See "write()" for the detail.) 110 | Use "kill()" method to immediately stop the timer. 111 | 112 | *Vital.Vim.Buffer.Writer-instance.kill()* 113 | {writer}.kill() 114 | Stop an internal timer of the {writer} immediately. 115 | 116 | It will be called automatically when "stop()" method has called in 117 | previous tick. 118 | 119 | It calls "on_exit()" callback of the {writer} if the callback 120 | exists on the instance. 121 | 122 | *Vital.Vim.Buffer.Writer-instance.write()* 123 | {writer}.write({content}) 124 | Write {content} to an internal buffer of the {writer}. 125 | 126 | The {content} must follow the POSIX text format, mean that the 127 | complete {content} always ends with an empty line. For example 128 | > 129 | call writer.start() 130 | call writer.write(['Hello', 'World', '']) 131 | call writer.write(['Hello', '']) 132 | call writer.write(['World', '']) 133 | call writer.write(['Hello', 'Wor']) 134 | call writer.write(['ld', '']) 135 | sleep 1m 136 | " > Hello 137 | " > World 138 | " > Hello 139 | " > World 140 | " > Hello 141 | " > World 142 | " > 143 | < 144 | Note that the last empty line will be removed in the final tick when 145 | "stop()" method is used and the writer successfully terminate. 146 | > 147 | " ... continues from above example 148 | call writer.stop() 149 | sleep 1m 150 | " > Hello 151 | " > World 152 | " > Hello 153 | " > World 154 | " > Hello 155 | " > World 156 | < 157 | *Vital.Vim.Buffer.Writer-instance.flush()* 158 | {writer}.flush() 159 | Manually flush an internal buffer to the target buffer. 160 | It is automatically called by an internal timer when the {writer} 161 | has started so usually user do not need to call it manually. 162 | 163 | 164 | ============================================================================= 165 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 166 | -------------------------------------------------------------------------------- /doc/Vital/Vim/Console.txt: -------------------------------------------------------------------------------- 1 | *Vital/Vim/Console.txt* echo/echomsg/input library 2 | 3 | Author : Alisue 4 | DEPRECATED 5 | 6 | 7 | ============================================================================== 8 | CONTENTS *Vital.Vim.Console-contents* 9 | 10 | INTRODUCTIONS |Vital.Vim.Console-introductions| 11 | USAGE |Vital.Vim.Console-usage| 12 | FUNCTIONS |Vital.Vim.Console-functions| 13 | VARIABLES |Vital.Vim.Console-variables| 14 | CHANGELOG |Vital.Vim.Console-changelog| 15 | 16 | 17 | ============================================================================== 18 | INTRODUCTIONS *Vital.Vim.Console-introductions* 19 | 20 | This module provides several utility functions for message such as |echo|. 21 | The basic usage is something like: 22 | 23 | > 24 | let s:Console = vital#vital#import('Vim.Console') 25 | 26 | if s:Console.ask('Do you like Vim?') 27 | call s:Console.info('I knew') 28 | else 29 | call s:Console.error('What did you say?') 30 | endif 31 | < 32 | 33 | ============================================================================== 34 | FUNCTIONS *Vital.Vim.Console-functions* 35 | 36 | *Vital.Vim.Console.echo()* 37 | echo({msg}[, {hl}]) 38 | Execute |:echo| with {hl} (|highlight-groups|). 39 | > 40 | call s:Console.echo('a', 'None') 41 | " a 42 | call s:Console.echo("a\nb\nc", 'None') 43 | " a 44 | " b 45 | " c 46 | let s:Console.prefix = '[prefix] ' 47 | call s:Console.echo('a', 'None') 48 | " [prefix] a 49 | call s:Console.echo("a\nb\nc", 'None') 50 | " [prefix] a 51 | " [prefix] b 52 | " [prefix] c 53 | < 54 | *Vital.Vim.Console.echon()* 55 | echon({msg}[, {hl}]) 56 | Execute |:echon| with {hl} (|highlight-groups|). 57 | Note that |Vital.Vim.Console.prefix| is not used for this method. 58 | 59 | *Vital.Vim.Console.echomsg()* 60 | echomsg({msg}[, {hl}]) 61 | Execute |:echomsg| with {hl} (|highlight-groups|). 62 | 63 | *Vital.Vim.Console.input()* 64 | input({hl}, {msg}[, {text}, {completion}]) 65 | Execute |:input| with {hl} (|highlight-groups|). 66 | |inputsave()| and |inputrestore()| are used internally to guard 67 | typeahead. 68 | Not like a native |input()|, the {completion} can be a |Funcref| 69 | which returns a list. Refer to |:command-completion| for detail. 70 | It returns 0 if users hit to cancel. 71 | 72 | *Vital.Vim.Console.inputlist()* 73 | inputlist({hl}, {textlist}]) 74 | Execute |:inputlist| with {hl} (|highlight-groups|). 75 | |inputsave()| and |inputrestore()| are used internally to guard 76 | typeahead. 77 | 78 | *Vital.Vim.Console.debug()* 79 | debug({msg}) 80 | Echo {msg} by |:echomsg| with |hl-Comment| highlight group only when the 81 | 'verbose' option has set. 82 | 83 | *Vital.Vim.Console.info()* 84 | info({msg}) 85 | Echo {msg} by |:echomsg| with |hl-Title| highlight group. 86 | It assign {msg} to |v:statusmsg| as well. 87 | 88 | *Vital.Vim.Console.warn()* 89 | warn({msg}) 90 | Echo {msg} by |:echomsg| with |hl-WarningMsg| highlight group. 91 | It assign {msg} to |v:warningmsg| as well. 92 | 93 | *Vital.Vim.Console.error()* 94 | error({msg}) 95 | Echo {msg} by |:echomsg| with |hl-ErrorMsg| highlight group. 96 | It assign {msg} to |v:errmsg| as well. 97 | 98 | *Vital.Vim.Console.ask()* 99 | ask({msg}[, {default}, {completion}]) 100 | Ask {msg} to users with |hl-Question| highlight group. 101 | 102 | *Vital.Vim.Console.select()* 103 | select({msg}, {candidates}[, {canceled}]) 104 | Ask users to select one of the {candidates} with |hl-Question| 105 | highlight group. 106 | When user cancel, the value of {canceled} is returned. 107 | When user input an invalid index, the value of {canceled} is 108 | returned. 109 | 110 | *Vital.Vim.Console.confirm()* 111 | confirm({msg}[, {default}]) 112 | Confirm yes/no question to users. 113 | It returns 1 if users answered yes. 114 | The {default} can be 'y\%[es]', 'n\%[o]', or an empty string. 115 | This value is used when user hit without input anything. 116 | It throws an exception when {default} is not one of the listed. 117 | 118 | 119 | ============================================================================== 120 | VARIABLES *Vital.Vim.Console-variables* 121 | 122 | *Vital.Vim.Console.prefix* 123 | prefix 124 | A prefix string used when message. An empty value i assigned in 125 | default. 126 | 127 | *Vital.Vim.Console.escape_marker* 128 | escape_marker 129 | A constant string used to check if users hit in a prompt. 130 | Usually the default value is unique enough so developers do not need 131 | to change the value. 132 | Note that the value is used in |cnoremap| directly without escaping. 133 | 134 | 135 | ============================================================================== 136 | CHANGELOG *Vital.Vim.Console-changelog* 137 | 138 | 1.0.0 2016-08-26 139 | - Initial stable version 140 | 1.1.0 2017-01-05 141 | - Add info() method to document 142 | 2.0.0 2017-01-12 143 | - Change API interface 144 | 3.0.0 2018-01-16 145 | - Change minimum Vim/Neovim version 146 | - Add unittests for methods which requires user input 147 | - Remove obsolute methods/features 148 | 149 | ============================================================================== 150 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 151 | -------------------------------------------------------------------------------- /doc/Vital/Vim/Highlight.txt: -------------------------------------------------------------------------------- 1 | *Vital/Vim/Highlight.txt* Highlight get/set library 2 | 3 | Author : Alisue 4 | DEPRECATED 5 | 6 | 7 | ============================================================================== 8 | CONTENTS *Vital.Vim.Highlight-contents* 9 | 10 | INTRODUCTIONS |Vital.Vim.Highlight-introductions| 11 | FUNCTIONS |Vital.Vim.Highlight-functions| 12 | 13 | 14 | ============================================================================== 15 | INTRODUCTIONS *Vital.Vim.Highlight-introductions* 16 | 17 | This module provides several utility functions for |highlight|. 18 | 19 | ============================================================================== 20 | FUNCTIONS *Vital.Vim.Highlight-functions* 21 | 22 | *Vital.Vim.Highlight.get()* 23 | get([{name}]) 24 | Return a highlight instance or a list of highlight instances. 25 | When {name} is specified, it returns a highlight instance of the 26 | given {name}. Otherwise it returns a list of highlight instance of 27 | all highlights defined. 28 | 29 | The highlight instance has 30 | 31 | "name" The name of the highlight 32 | "attrs" Highlight arguments 33 | 34 | For example 35 | > 36 | let highlight = s:Highlight.get('Title') 37 | echo highlight.name 38 | " 'Title' 39 | echo highlight.attrs.ctermfg 40 | " '0' 41 | echo highlight.attrs.guifg 42 | " '#000000' 43 | < 44 | *Vital.Vim.Highlight.set()* 45 | set({highlight}[, {options}]) 46 | Create or overwrite highlight by {highlight} instance. 47 | The {options} may contains 48 | 49 | "force" Overwrite existing highlight forcedly 50 | "default" Use "default" keyword to define highlight 51 | 52 | For example 53 | > 54 | call Highlight.set({'name': 'Title', 'attrs': { 55 | \ 'cterm': 'reverse', 56 | \ 'ctermfg': '1', 57 | \ 'guifg': '#123123', 58 | \}}) 59 | 60 | call Highlight.set({'name': 'TitleLink', 'attrs': { 61 | \ 'link': 'Title', 62 | \}}) 63 | 64 | call Highlight.set({'name': 'TitleClear', 'attrs': { 65 | \ 'cleared': 1, 66 | \}}) 67 | < 68 | 69 | ============================================================================== 70 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 71 | -------------------------------------------------------------------------------- /doc/Vital/Vim/Window.txt: -------------------------------------------------------------------------------- 1 | *Vital/Vim/Window.txt* A vital module for window related operation 2 | 3 | Author : Alisue 4 | DEPRECATED 5 | 6 | 7 | ============================================================================= 8 | CONTENTS *Vital.Vim.Window-contents* 9 | 10 | FUNCTION |Vital.Vim.Window-function| 11 | 12 | 13 | ============================================================================= 14 | FUNCTION *Vital.Vim.Window-function* 15 | 16 | *Vital.Vim.Window.focus_window()* 17 | focus_window({expr} [, {options}]) 18 | Focus a corresponding window which is specified via {expr}. 19 | The {expr} is a window number or an expression used in |winnr()| 20 | function. 21 | It returns a focus guard instance which is used to restore the 22 | previous focus when a corresponding window is found in a range 23 | specified via {options.range}. Otherwise it returns |v:null|. 24 | 25 | The {options} may have the following 26 | 27 | "range" A range to find a window. The followings are allowed 28 | "tabpage" Find a window from a current tabpage 29 | "all" Find a window from all tabpages 30 | The default value is "tabpage" 31 | > 32 | edit foo1 33 | split foo2 34 | " Focus 'foo1' which is shown in a window 2 35 | let guard = s:Window.focus_window(2) 36 | " Restore the previous focus (focus back to 'foo2') 37 | call guard.restore() 38 | < 39 | *Vital.Vim.Window.focus_buffer()* 40 | focus_buffer({expr} [, {options}]) 41 | Focus a window which opens a corresponding buffer of {expr}. 42 | The {expr} is a buffer number or an expression used in |bufnr()| 43 | function. 44 | It returns a focus guard instance which is used to restore the 45 | previous focus when a corresponding window is found in a range 46 | specified via {options.range}. Otherwise it returns |v:null|. 47 | 48 | The {options} may have the following 49 | 50 | "range" A range to find a buffer The followings are allowed 51 | "tabpage" Find a buffer from a current tabpage 52 | "all" Find a buffer from all tabpages 53 | The default value is "tabpage" 54 | > 55 | edit foo1 56 | split foo2 57 | " Focus 'foo1' 58 | let guard = s:Window.focus_buffer('foo1') 59 | " Restore the previous focus (focus back to 'foo2') 60 | call guard.restore() 61 | < 62 | 63 | ============================================================================= 64 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 65 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | /.deps 2 | -------------------------------------------------------------------------------- /test/.themisrc: -------------------------------------------------------------------------------- 1 | if &encoding ==# 'latin1' 2 | set encoding=utf-8 3 | endif 4 | 5 | " Profile 6 | if $PROFILE !=# '' 7 | execute 'profile start' $PROFILE 8 | profile! file ./autoload/* 9 | endif 10 | 11 | " Force English interface 12 | try 13 | language message C 14 | catch 15 | endtry 16 | set helplang=en 17 | 18 | let s:assert = themis#helper('assert') 19 | call themis#option('recursive', 1) 20 | call themis#option('reporter', 'dot') 21 | call themis#helper('command').with(s:assert) 22 | 23 | let s:deps = themis#helper('deps') 24 | call s:deps.git('vim-jp/vital.vim') 25 | 26 | call themis#log(substitute(execute('version'), '^\%(\r\?\n\)*', '', '')) 27 | call themis#log('-----------------------------------------------------------') 28 | call themis#log('has("lua"): ' . has('lua')) 29 | call themis#log('has("python"): ' . has('python')) 30 | call themis#log('has("python3"): ' . has('python3')) 31 | call themis#log('$LANG: ' . $LANG) 32 | call themis#log('&encoding: ' . &encoding) 33 | call themis#log('&termencoding: ' . &termencoding) 34 | call themis#log('&fileencodings: ' . &fileencodings) 35 | call themis#log('&fileformats: ' . &fileformats) 36 | call themis#log('&shellslash: ' . (exists('&shellslash') ? &shellslash : 'DISABLED')) 37 | call themis#log('&runtimepath:') 38 | for s:runtimepath in split(&runtimepath, ',') 39 | call themis#log(' ' . s:runtimepath) 40 | endfor 41 | call themis#log('-----------------------------------------------------------') 42 | 43 | 44 | function! Approx(actual, expect, ...) abort 45 | return call(s:assert.compare, [a:actual, '>', a:expect * 0.7] + a:000, s:assert) 46 | \ && call(s:assert.compare, [a:actual, '<', a:expect * 1.3] + a:000, s:assert) 47 | endfunction 48 | -------------------------------------------------------------------------------- /test/App/Action.vimspec: -------------------------------------------------------------------------------- 1 | Describe App.Action 2 | Before all 3 | let Action = vital#vital#import('App.Action') 4 | End 5 | 6 | After all 7 | %bwipeout! 8 | End 9 | 10 | Before 11 | %bwipeout! 12 | End 13 | 14 | Describe .init() 15 | It defines mappings for actions 16 | call Action.init() 17 | let rs = map( 18 | \ split(execute('nmap (vital-action'), '\n'), 19 | \ { -> split(v:val)[1] }, 20 | \) 21 | Assert Equals(sort(rs), sort([ 22 | \ '(vital-action-choice)', 23 | \ '(vital-action-repeat)', 24 | \ '(vital-action-help)', 25 | \ '(vital-action-help:all)', 26 | \])) 27 | End 28 | End 29 | 30 | Describe .call() 31 | It invoke a corresponding mapping of a given name 32 | function! s:map_test() abort 33 | let b:called = 1 34 | endfunction 35 | 36 | nnoremap (vital-action-test) :call map_test() 37 | 38 | call Action.init() 39 | call Action.call('test') 40 | Assert Equals(b:called, 1) 41 | End 42 | 43 | It throws exception when no corresponding mapping exists 44 | call Action.init() 45 | Throws /no action test found in the buffer/ Action.call('test') 46 | End 47 | End 48 | End 49 | -------------------------------------------------------------------------------- /test/App/Args.vimspec: -------------------------------------------------------------------------------- 1 | Describe App.Args 2 | Before all 3 | let Args = vital#vital#import('App.Args') 4 | End 5 | 6 | Describe Usage 7 | Before all 8 | let args = ['hello', '-foo', '-bar=bar'] 9 | End 10 | 11 | It follows behavior written in docs (get) 12 | Assert Equals(Args.get(args, 'foo', v:false), v:true) 13 | Assert Equals(args, ['hello', '-foo', '-bar=bar']) 14 | Assert Equals(Args.get(args, 'bar', ''), 'bar') 15 | Assert Equals(args, ['hello', '-foo', '-bar=bar']) 16 | End 17 | 18 | It follows behavior written in docs (pop) 19 | Assert Equals(Args.pop(args, 'foo', v:false), v:true) 20 | Assert Equals(args, ['hello', '-bar=bar']) 21 | Assert Equals(Args.pop(args, 'bar', ''), 'bar') 22 | Assert Equals(args, ['hello']) 23 | End 24 | 25 | It follows behavior written in docs (set) 26 | call Args.set(args, 'foo2', v:true) 27 | Assert Equals(args, ['hello', '-foo2']) 28 | call Args.set(args, 'bar2', 'bar2') 29 | Assert Equals(args, ['hello', '-foo2', '-bar2=bar2']) 30 | 31 | call Args.set(args, 'foo2', v:false) 32 | Assert Equals(args, ['hello', '-bar2=bar2']) 33 | call Args.set(args, 'bar2', 'barbar') 34 | Assert Equals(args, ['hello', '-bar2=barbar']) 35 | End 36 | 37 | It follows behavior written in docs (throw_if_dirty) 38 | Throw /unknown option/ Args.throw_if_dirty(args) 39 | call Args.pop(args, 'bar2', '') 40 | call Args.throw_if_dirty(args) 41 | End 42 | End 43 | End 44 | -------------------------------------------------------------------------------- /test/App/Flag.vimspec: -------------------------------------------------------------------------------- 1 | Describe App.Flag 2 | Before 3 | let Flag = vital#vital#import('App.Flag') 4 | End 5 | 6 | Describe .split() 7 | It splits {cmdline} by a whitespace 8 | Assert Equals(Flag.split('foo'), ['foo']) 9 | Assert Equals(Flag.split('foo bar'), ['foo', 'bar']) 10 | Assert Equals(Flag.split('foo bar hoge'), ['foo', 'bar', 'hoge']) 11 | End 12 | 13 | It does not split {cmdline} by a single quoted whitespace 14 | Assert Equals(Flag.split('''foo bar'''), ['foo bar']) 15 | Assert Equals(Flag.split('-f''foo bar'''), ['-ffoo bar']) 16 | Assert Equals(Flag.split('--foo=''foo bar'''), ['--foo=foo bar']) 17 | End 18 | 19 | It does not split {cmdline} by a double quoted whitespace 20 | Assert Equals(Flag.split('"foo bar"'), ['foo bar']) 21 | Assert Equals(Flag.split('-f"foo bar"'), ['-ffoo bar']) 22 | Assert Equals(Flag.split('--foo="foo bar"'), ['--foo=foo bar']) 23 | End 24 | End 25 | 26 | Describe .parse() 27 | It parses {args} and return [{ns}, {args}] 28 | Assert Equals(Flag.parse(['-foo']), [ 29 | \ { 30 | \ 'foo': v:true, 31 | \ }, 32 | \ [], 33 | \]) 34 | Assert Equals(Flag.parse(['-foo', 'bar']), [ 35 | \ { 36 | \ 'foo': v:true, 37 | \ }, 38 | \ ['bar'], 39 | \]) 40 | Assert Equals(Flag.parse(['-foo', 'bar', '-hoge=HOGE']), [ 41 | \ { 42 | \ 'foo': v:true, 43 | \ 'hoge': 'HOGE', 44 | \ }, 45 | \ ['bar'], 46 | \]) 47 | End 48 | End 49 | 50 | Describe .flag() 51 | It returns flag (0/1) for a given name 52 | let args = [ 53 | \ '-foo', 54 | \ 'bar', 55 | \ '-hoge=HOGE', 56 | \] 57 | Assert True(Flag.flag(args, 'foo')) 58 | Assert False(Flag.flag(args, 'bar')) 59 | Assert False(Flag.flag(args, 'hoge')) 60 | End 61 | End 62 | 63 | Describe .value() 64 | It returns value for a given nam 65 | let args = [ 66 | \ '-foo', 67 | \ 'bar', 68 | \ '-hoge=HOGE', 69 | \] 70 | Assert Equals(Flag.value(args, 'foo'), v:null) 71 | Assert Equals(Flag.value(args, 'bar'), v:null) 72 | Assert Equals(Flag.value(args, 'hoge'), 'HOGE') 73 | End 74 | End 75 | End 76 | -------------------------------------------------------------------------------- /test/App/Revelator.vimspec: -------------------------------------------------------------------------------- 1 | Describe App.Revelator 2 | Before all 3 | let prefix = 'vital: App.Revelator: ' 4 | End 5 | 6 | Before 7 | let Revelator = vital#vital#import('App.Revelator') 8 | End 9 | 10 | Describe .info() 11 | It returns an exception message with INFO category 12 | Assert Equal(Revelator.info('foobar'), prefix . 'INFO: foobar') 13 | End 14 | 15 | It replaces v:statusmsg to the given message 16 | call Revelator.info('foobar') 17 | Assert Equal(v:statusmsg, 'foobar') 18 | End 19 | End 20 | 21 | Describe .warning() 22 | It returns an exception message with WARNING category 23 | Assert Equal(Revelator.warning('foobar'), prefix . 'WARNING: foobar') 24 | End 25 | 26 | It replaces v:warningmsg to the given message 27 | call Revelator.warning('foobar') 28 | Assert Equal(v:warningmsg, 'foobar') 29 | End 30 | End 31 | 32 | Describe .error() 33 | It returns an exception message with ERROR category 34 | Assert Equal(Revelator.error('foobar'), prefix . 'ERROR: foobar') 35 | End 36 | 37 | It replaces v:errmsg to the given message 38 | call Revelator.error('foobar') 39 | Assert Equal(v:errmsg, 'foobar') 40 | End 41 | End 42 | 43 | Describe .critical() 44 | It returns an exception message with CRITICAL category 45 | Assert Equal(Revelator.critical('foobar'), prefix . 'CRITICAL: foobar') 46 | End 47 | 48 | It replaces v:errmsg to the given message 49 | call Revelator.critical('foobar') 50 | Assert Equal(v:errmsg, 'foobar') 51 | End 52 | End 53 | 54 | Describe .call() 55 | It calls {func} with {argslist} 56 | let calls = [] 57 | function! s:test_funcref(calls, ...) abort 58 | call add(a:calls, a:000) 59 | endfunction 60 | 61 | call Revelator.call( 62 | \ function('s:test_funcref', [calls]), 63 | \ ['foo', 'bar'] 64 | \) 65 | Assert Equals(calls, [ 66 | \ ['foo', 'bar'], 67 | \]) 68 | End 69 | 70 | It calls {func} with {argslist} as a dictionary function of {dict} 71 | let dict = { 'calls': [] } 72 | function! dict.test_funcref(...) abort 73 | call add(self.calls, [self] + a:000) 74 | endfunction 75 | 76 | call Revelator.call( 77 | \ dict.test_funcref, 78 | \ ['foo', 'bar'], 79 | \ dict, 80 | \) 81 | Assert Equals(dict.calls, [ 82 | \ [dict, 'foo', 'bar'], 83 | \]) 84 | End 85 | 86 | It echos INFO message when a info() revelation has thrown 87 | let dict = {} 88 | let dict.Revelator = Revelator 89 | function dict.test_funcref(...) abort 90 | throw self.Revelator.info('Revelation:' . string(a:000)) 91 | endfunction 92 | 93 | let output = execute('call Revelator.call(dict.test_funcref, ["foo", "bar"], dict)') 94 | Assert Equal(output, "\nRevelation:['foo', 'bar']") 95 | End 96 | 97 | It echos WARNING message when a warning() revelation has thrown 98 | let dict = {} 99 | let dict.Revelator = Revelator 100 | function dict.test_funcref(...) abort 101 | throw self.Revelator.warning('Revelation:' . string(a:000)) 102 | endfunction 103 | 104 | let output = execute('call Revelator.call(dict.test_funcref, ["foo", "bar"], dict)') 105 | Assert Equal(output, "\nRevelation:['foo', 'bar']") 106 | End 107 | 108 | It echos ERROR message when a error() revelation has thrown 109 | let dict = {} 110 | let dict.Revelator = Revelator 111 | function dict.test_funcref(...) abort 112 | throw self.Revelator.error('Revelation:' . string(a:000)) 113 | endfunction 114 | 115 | let output = execute('call Revelator.call(dict.test_funcref, ["foo", "bar"], dict)') 116 | Assert Equal(output, "\nRevelation:['foo', 'bar']") 117 | End 118 | 119 | It echos CRITICAL message and throwpoint when a critical() revelation has thrown 120 | let dict = {} 121 | let dict.Revelator = Revelator 122 | function dict.test_funcref(...) abort 123 | throw self.Revelator.critical('Revelation:' . string(a:000)) 124 | endfunction 125 | 126 | let output = execute('call Revelator.call(dict.test_funcref, ["foo", "bar"], dict)') 127 | Assert Match(output, "\nRevelation:\\['foo', 'bar']\n.*function ") 128 | End 129 | End 130 | End 131 | 132 | -------------------------------------------------------------------------------- /test/App/Spinner.vimspec: -------------------------------------------------------------------------------- 1 | Describe App.Spinner 2 | Before 3 | let Spinner = vital#vital#import('App.Spinner') 4 | End 5 | 6 | It exposes builtin spinner frames 7 | Assert KeyExists(Spinner, 'dots') 8 | Assert KeyExists(Spinner, 'dots2') 9 | Assert KeyExists(Spinner, 'dots3') 10 | Assert KeyExists(Spinner, 'dots4') 11 | Assert KeyExists(Spinner, 'dots5') 12 | Assert KeyExists(Spinner, 'dots6') 13 | Assert KeyExists(Spinner, 'dots7') 14 | Assert KeyExists(Spinner, 'dots8') 15 | Assert KeyExists(Spinner, 'dots9') 16 | Assert KeyExists(Spinner, 'dots10') 17 | Assert KeyExists(Spinner, 'dots11') 18 | Assert KeyExists(Spinner, 'dots12') 19 | Assert KeyExists(Spinner, 'line') 20 | Assert KeyExists(Spinner, 'line2') 21 | Assert KeyExists(Spinner, 'pipe') 22 | Assert KeyExists(Spinner, 'simpleDots') 23 | Assert KeyExists(Spinner, 'simpleDotsScrolling') 24 | Assert KeyExists(Spinner, 'star') 25 | Assert KeyExists(Spinner, 'star2') 26 | Assert KeyExists(Spinner, 'flip') 27 | Assert KeyExists(Spinner, 'hamburger') 28 | Assert KeyExists(Spinner, 'growVertical') 29 | Assert KeyExists(Spinner, 'growHorizontal') 30 | Assert KeyExists(Spinner, 'balloon') 31 | Assert KeyExists(Spinner, 'balloon2') 32 | Assert KeyExists(Spinner, 'noise') 33 | Assert KeyExists(Spinner, 'bounce') 34 | Assert KeyExists(Spinner, 'boxBounce') 35 | Assert KeyExists(Spinner, 'boxBounce2') 36 | Assert KeyExists(Spinner, 'triangle') 37 | Assert KeyExists(Spinner, 'arc') 38 | Assert KeyExists(Spinner, 'circle') 39 | Assert KeyExists(Spinner, 'squareCorners') 40 | Assert KeyExists(Spinner, 'circleQuarters') 41 | Assert KeyExists(Spinner, 'circleHalves') 42 | Assert KeyExists(Spinner, 'squish') 43 | Assert KeyExists(Spinner, 'toggle') 44 | Assert KeyExists(Spinner, 'toggle2') 45 | Assert KeyExists(Spinner, 'toggle3') 46 | Assert KeyExists(Spinner, 'toggle4') 47 | Assert KeyExists(Spinner, 'toggle5') 48 | Assert KeyExists(Spinner, 'toggle6') 49 | Assert KeyExists(Spinner, 'toggle7') 50 | Assert KeyExists(Spinner, 'toggle8') 51 | Assert KeyExists(Spinner, 'toggle9') 52 | Assert KeyExists(Spinner, 'toggle10') 53 | Assert KeyExists(Spinner, 'toggle11') 54 | Assert KeyExists(Spinner, 'toggle12') 55 | Assert KeyExists(Spinner, 'toggle13') 56 | Assert KeyExists(Spinner, 'arrow') 57 | Assert KeyExists(Spinner, 'arrow2') 58 | Assert KeyExists(Spinner, 'arrow3') 59 | Assert KeyExists(Spinner, 'bouncingBar') 60 | Assert KeyExists(Spinner, 'bouncingBall') 61 | Assert KeyExists(Spinner, 'smiley') 62 | Assert KeyExists(Spinner, 'monkey') 63 | Assert KeyExists(Spinner, 'hearts') 64 | Assert KeyExists(Spinner, 'clock') 65 | Assert KeyExists(Spinner, 'earth') 66 | Assert KeyExists(Spinner, 'moon') 67 | Assert KeyExists(Spinner, 'runner') 68 | Assert KeyExists(Spinner, 'pong') 69 | Assert KeyExists(Spinner, 'shark') 70 | Assert KeyExists(Spinner, 'dqpb') 71 | Assert KeyExists(Spinner, 'weather') 72 | Assert KeyExists(Spinner, 'christmas') 73 | Assert KeyExists(Spinner, 'grenade') 74 | Assert KeyExists(Spinner, 'point') 75 | Assert KeyExists(Spinner, 'layer') 76 | End 77 | 78 | Describe .new() 79 | It returns a spinner instance 80 | let s = Spinner.new(Spinner.dots) 81 | Assert KeyExists(s, 'next') 82 | Assert KeyExists(s, 'reset') 83 | End 84 | 85 | Context a spinner instance 86 | Describe .next() 87 | It returns a next frame 88 | let s = Spinner.new(Spinner.line) 89 | Assert Equals(s.next(), '-') 90 | Assert Equals(s.next(), '\\') 91 | Assert Equals(s.next(), '|') 92 | Assert Equals(s.next(), '/') 93 | Assert Equals(s.next(), '-') 94 | End 95 | End 96 | 97 | Describe .reset() 98 | It resets the internal index of a spinner 99 | let s = Spinner.new(Spinner.line) 100 | Assert Equals(s.next(), '-') 101 | call s.reset() 102 | Assert Equals(s.next(), '-') 103 | End 104 | End 105 | End 106 | End 107 | End 108 | 109 | -------------------------------------------------------------------------------- /test/Async/CancellationTokenSource.vimspec: -------------------------------------------------------------------------------- 1 | Describe Async.CancellationTokenSource 2 | Before 3 | let CancellationTokenSource = vital#vital#import('Async.CancellationTokenSource') 4 | End 5 | 6 | Describe .new([{linked-tokens}]) 7 | It returns a source instance 8 | let source = CancellationTokenSource.new() 9 | Assert KeyExists(source, 'cancel') 10 | Assert KeyExists(source, 'close') 11 | End 12 | End 13 | 14 | Context a source instance 15 | Before 16 | let source1 = CancellationTokenSource.new() 17 | let source2 = CancellationTokenSource.new([source1.token]) 18 | let source3 = CancellationTokenSource.new([source2.token]) 19 | let source4 = CancellationTokenSource.new() 20 | let source5 = CancellationTokenSource.new([source3.token, source4.token]) 21 | End 22 | 23 | Describe .cancel() 24 | It changes the token status to 'cancelled' 25 | let token1 = source1.token 26 | Assert Equals(token1.cancellation_requested(), 0) 27 | call source1.cancel() 28 | Assert Equals(token1.cancellation_requested(), 1) 29 | End 30 | 31 | It changes all linked tokens' status to 'cancelled' 32 | let token1 = source1.token 33 | let token2 = source2.token 34 | let token3 = source3.token 35 | let token4 = source4.token 36 | let token5 = source5.token 37 | Assert Equals(token1.cancellation_requested(), 0) 38 | Assert Equals(token2.cancellation_requested(), 0) 39 | Assert Equals(token3.cancellation_requested(), 0) 40 | Assert Equals(token4.cancellation_requested(), 0) 41 | Assert Equals(token5.cancellation_requested(), 0) 42 | call source1.cancel() 43 | Assert Equals(token1.cancellation_requested(), 1) 44 | Assert Equals(token2.cancellation_requested(), 1) 45 | Assert Equals(token3.cancellation_requested(), 1) 46 | Assert Equals(token4.cancellation_requested(), 0) 47 | Assert Equals(token5.cancellation_requested(), 1) 48 | End 49 | End 50 | 51 | Describe .close() 52 | It changes the token status to 'closed' 53 | let token1 = source1.token 54 | Assert Equals(token1.can_be_canceled(), 1) 55 | call source1.close() 56 | Assert Equals(token1.can_be_canceled(), 0) 57 | End 58 | 59 | It does not touch linked tokens 60 | let token1 = source1.token 61 | let token2 = source2.token 62 | let token3 = source3.token 63 | let token4 = source4.token 64 | let token5 = source5.token 65 | Assert Equals(token1.can_be_canceled(), 1) 66 | Assert Equals(token2.can_be_canceled(), 1) 67 | Assert Equals(token3.can_be_canceled(), 1) 68 | Assert Equals(token4.can_be_canceled(), 1) 69 | Assert Equals(token5.can_be_canceled(), 1) 70 | call source1.close() 71 | Assert Equals(token1.can_be_canceled(), 0) 72 | Assert Equals(token2.can_be_canceled(), 1) 73 | Assert Equals(token3.can_be_canceled(), 1) 74 | Assert Equals(token4.can_be_canceled(), 1) 75 | Assert Equals(token5.can_be_canceled(), 1) 76 | End 77 | End 78 | End 79 | End 80 | 81 | -------------------------------------------------------------------------------- /test/Async/Lambda.vimspec: -------------------------------------------------------------------------------- 1 | Describe Async.Lambda 2 | Before 3 | let Lambda = vital#vital#import('Async.Lambda') 4 | let Promise = vital#vital#import('Async.Promise') 5 | 6 | let Lambda.chunk_size = 2 7 | End 8 | Describe .map() 9 | It returns a {fn} applied copies of {list} 10 | let list = [5, 4, 3, 2, 1] 11 | 12 | " The first argument is value 13 | let [copy, e] = Promise.wait(Lambda.map(list, { v -> v + 1 }), 100) 14 | Assert Equals(e, v:null) 15 | Assert Equals(list, [5, 4, 3, 2, 1]) 16 | Assert Equals(copy, [6, 5, 4, 3, 2]) 17 | 18 | " The second argument is index 19 | let [copy, e] = Promise.wait(Lambda.map(list, { _, k -> k + 1 })) 20 | Assert Equals(e, v:null) 21 | Assert Equals(list, [5, 4, 3, 2, 1]) 22 | Assert Equals(copy, [1, 2, 3, 4, 5]) 23 | End 24 | End 25 | 26 | Describe .filter() 27 | It returns copies of {list} filtered by {fn} 28 | let list = [5, 4, 3, 2, 1] 29 | 30 | " The first argument is value 31 | let [copy, e] = Promise.wait(Lambda.filter(list, { v -> v % 2 is# 0 })) 32 | Assert Equals(e, v:null) 33 | Assert Equals(list, [5, 4, 3, 2, 1]) 34 | Assert Equals(copy, [4, 2]) 35 | 36 | " The second argument is index 37 | let [copy, e] = Promise.wait(Lambda.filter(list, { _, k -> k % 2 is# 0 })) 38 | Assert Equals(e, v:null) 39 | Assert Equals(list, [5, 4, 3, 2, 1]) 40 | Assert Equals(copy, [5, 3, 1]) 41 | End 42 | End 43 | 44 | Describe .reduce() 45 | It returns a reduced value for {fn} applied copies of {list} 46 | let list = [5, 4, 3, 2, 1] 47 | 48 | " The second argument is value 49 | let [value, e] = Promise.wait(Lambda.reduce(list, { a, v -> a + v }, 0), 100) 50 | Assert Equals(e, v:null) 51 | Assert Equals(list, [5, 4, 3, 2, 1]) 52 | Assert Equals(value, 15) 53 | 54 | " The thrid argument is index 55 | let [value, e] = Promise.wait(Lambda.reduce(list, { a, _, k -> a + k }, 0), 100) 56 | Assert Equals(e, v:null) 57 | Assert Equals(list, [5, 4, 3, 2, 1]) 58 | Assert Equals(value, 10) 59 | End 60 | End 61 | 62 | Describe .map_f() 63 | It returns a function which execute map on the list 64 | let list = [5, 4, 3, 2, 1] 65 | 66 | " The first argument is value 67 | let l:F = Lambda.map_f({ v -> v + 1 }) 68 | let [copy, e] = Promise.wait(F(list), 100) 69 | Assert Equals(e, v:null) 70 | Assert Equals(list, [5, 4, 3, 2, 1]) 71 | Assert Equals(copy, [6, 5, 4, 3, 2]) 72 | 73 | " The second argument is index 74 | let l:F = Lambda.map_f({ _, k -> k + 1 }) 75 | let [copy, e] = Promise.wait(F(list), 100) 76 | Assert Equals(e, v:null) 77 | Assert Equals(list, [5, 4, 3, 2, 1]) 78 | Assert Equals(copy, [1, 2, 3, 4, 5]) 79 | End 80 | End 81 | 82 | Describe .filter_f() 83 | It returns a function which execute filter on the list 84 | let list = [5, 4, 3, 2, 1] 85 | 86 | " The first argument is value 87 | let l:F = Lambda.filter_f({ v -> v % 2 is# 0 }) 88 | let [copy, e] = Promise.wait(F(list), 100) 89 | Assert Equals(e, v:null) 90 | Assert Equals(list, [5, 4, 3, 2, 1]) 91 | Assert Equals(copy, [4, 2]) 92 | 93 | " The second argument is index 94 | let l:F = Lambda.filter_f({ _, k -> k % 2 is# 0 }) 95 | let [copy, e] = Promise.wait(F(list), 100) 96 | Assert Equals(e, v:null) 97 | Assert Equals(list, [5, 4, 3, 2, 1]) 98 | Assert Equals(copy, [5, 3, 1]) 99 | End 100 | End 101 | 102 | Describe .reduce() 103 | It returns a function which execute reduce on the list 104 | let list = [5, 4, 3, 2, 1] 105 | 106 | " The second argument is value 107 | let l:F = Lambda.reduce_f({ a, v -> a + v }, 0) 108 | let [value, e] = Promise.wait(F(list), 100) 109 | Assert Equals(e, v:null) 110 | Assert Equals(list, [5, 4, 3, 2, 1]) 111 | Assert Equals(value, 15) 112 | 113 | " The thrid argument is index 114 | let l:F = Lambda.reduce_f({ a, _, k -> a + k }, 0) 115 | let [value, e] = Promise.wait(F(list), 100) 116 | Assert Equals(e, v:null) 117 | Assert Equals(list, [5, 4, 3, 2, 1]) 118 | Assert Equals(value, 10) 119 | End 120 | End 121 | End 122 | -------------------------------------------------------------------------------- /test/Async/Promise/Deferred.vimspec: -------------------------------------------------------------------------------- 1 | Describe Async.Promise.Deferred 2 | Before all 3 | let Promise = vital#vital#import('Async.Promise') 4 | " States of promise 5 | let PENDING = 0 6 | let FULFILLED = 1 7 | let REJECTED = 2 8 | End 9 | 10 | Before 11 | let Deferred = vital#vital#import('Async.Promise.Deferred') 12 | End 13 | 14 | Describe .new() 15 | It returns a deferred instance 16 | let d = Deferred.new() 17 | Assert True(Promise.is_promise(d)) 18 | Assert KeyExists(d, 'resolve') 19 | Assert KeyExists(d, 'reject') 20 | End 21 | 22 | Context instance 23 | Before 24 | let d = Deferred.new() 25 | End 26 | 27 | Describe .resolve() 28 | It resolves the internal promise 29 | Assert Equals(d._state, PENDING) 30 | call d.resolve() 31 | Assert Equals(d._state, FULFILLED) 32 | End 33 | End 34 | 35 | Describe .reject() 36 | It rejects the internal promise 37 | Assert Equals(d._state, PENDING) 38 | call d.reject() 39 | Assert Equals(d._state, REJECTED) 40 | End 41 | End 42 | End 43 | End 44 | End 45 | -------------------------------------------------------------------------------- /test/Config.vimspec: -------------------------------------------------------------------------------- 1 | Describe Config 2 | Before all 3 | let Guard = vital#vital#import('Vim.Guard') 4 | End 5 | 6 | Before 7 | let Config = vital#vital#import('Config') 8 | let guard = Guard.store([ 9 | \ 'g:vital#foo', 10 | \ 'g:vital#bar', 11 | \ 'g:vital#hello#foo', 12 | \ 'g:vital#hello#bar', 13 | \]) 14 | End 15 | 16 | After 17 | if exists('guard') 18 | call guard.restore() 19 | endif 20 | End 21 | 22 | Describe .define({prefix}, {defaults}) 23 | It defines 'g:{prefix}#{key}' variables 24 | let defaults = { 25 | \ 'foo': 'bar', 26 | \ 'bar': 0, 27 | \} 28 | let ret = Config.define('g:vital#hello', defaults) 29 | Assert exists('g:vital#hello#foo') 30 | Assert exists('g:vital#hello#bar') 31 | 32 | Assert Equals(g:vital#hello#foo, defaults.foo) 33 | Assert Equals(g:vital#hello#bar, defaults.bar) 34 | End 35 | 36 | It will not overwrite the existing variables 37 | let defaults = { 38 | \ 'foo': 'bar', 39 | \ 'bar': 0, 40 | \} 41 | let g:vital#foo = 'hello' 42 | let g:vital#bar = 1 43 | let ret = Config.define('g:vital', defaults) 44 | Assert exists('g:vital#foo') 45 | Assert exists('g:vital#bar') 46 | 47 | Assert Equals(g:vital#foo, 'hello') 48 | Assert Equals(g:vital#bar, 1) 49 | End 50 | End 51 | 52 | Describe .translate({scriptfile}) 53 | It translates {scriptfile} into a global variable name 54 | let ret = Config.translate(fnamemodify('autoload/vital.vim', ':p')) 55 | Assert Equals(ret, 'g:vital') 56 | 57 | let ret = Config.translate(fnamemodify('autoload/vital/foo.vim', ':p')) 58 | Assert Equals(ret, 'g:vital#foo') 59 | 60 | let ret = Config.translate(fnamemodify('autoload/vital/foo/bar.vim', ':p')) 61 | Assert Equals(ret, 'g:vital#foo#bar') 62 | End 63 | End 64 | 65 | Describe .config({scriptfile}, {defaults}) 66 | It define 'g:{prefix}#{key}' variables 67 | let defaults = { 68 | \ 'foo': 'bar', 69 | \ 'bar': 0, 70 | \} 71 | let ret = Config.config(fnamemodify('autoload/vital/hello.vim', ':p'), defaults) 72 | Assert exists('g:vital#hello#foo') 73 | Assert exists('g:vital#hello#bar') 74 | 75 | Assert Equals(g:vital#hello#foo, defaults.foo) 76 | Assert Equals(g:vital#hello#bar, defaults.bar) 77 | End 78 | End 79 | End 80 | -------------------------------------------------------------------------------- /test/Data/List/Chunker.vimspec: -------------------------------------------------------------------------------- 1 | Describe Data.List.Chunker 2 | Before 3 | let Chunker = vital#vital#import('Data.List.Chunker') 4 | End 5 | 6 | Describe .new() 7 | It returns a {chunker} instance 8 | let chunk_size = 10 9 | let candidates = range(100) 10 | let chunker = Chunker.new(chunk_size, candidates) 11 | Assert KeyExists(chunker, 'next') 12 | End 13 | 14 | Describe a {chunker} instance 15 | Before 16 | let chunk_size = 10 17 | let candidates = range(55) 18 | let chunker = Chunker.new(chunk_size, candidates) 19 | End 20 | 21 | Describe .next() 22 | It forward {cursor} by {chunk_size} and return a partial {candidates} 23 | Assert Equals(chunker.next(), range(0, 10-1)) 24 | Assert Equals(chunker.next(), range(10, 20-1)) 25 | Assert Equals(chunker.next(), range(20, 30-1)) 26 | Assert Equals(chunker.next(), range(30, 40-1)) 27 | Assert Equals(chunker.next(), range(40, 50-1)) 28 | Assert Equals(chunker.next(), range(50, 55-1)) 29 | Assert Equals(chunker.next(), []) 30 | End 31 | End 32 | End 33 | End 34 | End 35 | -------------------------------------------------------------------------------- /test/System/Sandbox.vimspec: -------------------------------------------------------------------------------- 1 | Describe System.Sandbox 2 | Before all 3 | let Path = vital#vital#import('System.Filepath') 4 | let assert = themis#helper('assert') 5 | let saved_cwd = getcwd() 6 | 7 | function! GetCwd() abort closure 8 | return fnamemodify(resolve(getcwd()), ':p') 9 | endfunction 10 | 11 | function! PathEquals(a, b) abort closure 12 | return assert.equals( 13 | \ Path.remove_last_separator(a:a), 14 | \ Path.remove_last_separator(a:b), 15 | \) 16 | endfunction 17 | End 18 | 19 | After all 20 | execute 'cd' fnameescape(saved_cwd) 21 | End 22 | 23 | Before 24 | let Sandbox = vital#vital#import('System.Sandbox') 25 | End 26 | 27 | Describe .new() 28 | It returns a new Sandbox instance 29 | let sandbox = Sandbox.new() 30 | Assert KeyExists(sandbox, 'path') 31 | Assert KeyExists(sandbox, 'visit') 32 | Assert KeyExists(sandbox, 'return') 33 | Assert KeyExists(sandbox, 'dispose') 34 | Assert IsFunc(sandbox.path) 35 | Assert IsFunc(sandbox.visit) 36 | Assert IsFunc(sandbox.return) 37 | Assert IsFunc(sandbox.dispose) 38 | End 39 | End 40 | 41 | Describe Sandbox instance 42 | Describe .origin() 43 | It returns the origin directory of the sandbox which is a previous current working directory prior to the creation 44 | let saved_cwd = GetCwd() 45 | let sandbox = Sandbox.new() 46 | Assert PathEquals(sandbox.origin(), saved_cwd) 47 | End 48 | End 49 | 50 | Describe .path() 51 | It returns the home directory of the sandbox which exists under a system temp directory 52 | let sandbox = Sandbox.new() 53 | let tempdir = fnamemodify(resolve(tempname()), ':p:h') 54 | Assert True(isdirectory(sandbox.path())) 55 | Assert PathEquals(sandbox.path()[:len(tempdir)], tempdir) 56 | End 57 | End 58 | 59 | Describe .visit() 60 | It creates a subdirectory and change current working directory 61 | let sandbox = Sandbox.new() 62 | call sandbox.visit('hello') 63 | Assert PathEquals(GetCwd(), Path.join(sandbox.path(), 'hello')) 64 | End 65 | 66 | It change current working directory if the subdirectory exists 67 | let sandbox = Sandbox.new() 68 | call sandbox.visit('hello') 69 | Assert PathEquals(GetCwd(), Path.join(sandbox.path(), 'hello')) 70 | call sandbox.visit('world') 71 | Assert PathEquals(GetCwd(), Path.join(sandbox.path(), 'world')) 72 | call sandbox.visit('hello') 73 | Assert PathEquals(GetCwd(), Path.join(sandbox.path(), 'hello')) 74 | End 75 | End 76 | 77 | Describe .return() 78 | It returns to the home directory of the sandbox 79 | let sandbox = Sandbox.new() 80 | call sandbox.visit('hello') 81 | call sandbox.return() 82 | Assert PathEquals(GetCwd(), sandbox.path()) 83 | End 84 | End 85 | 86 | Describe .dispose() 87 | It returns to the original directory and remove the sandbox home directory 88 | let saved_cwd = GetCwd() 89 | let sandbox = Sandbox.new() 90 | call sandbox.visit('hello') 91 | call sandbox.visit('world') 92 | call sandbox.dispose() 93 | Assert PathEquals(GetCwd(), saved_cwd) 94 | Assert True(IsDirRemoved(sandbox.path(), 5000)) 95 | End 96 | End 97 | End 98 | End 99 | 100 | function! IsDirRemoved(path, timeout) abort 101 | let start = reltime() 102 | let timeout = a:timeout / 1000 103 | while reltimefloat(reltime(start)) <= timeout 104 | if !isdirectory(a:path) 105 | return v:true 106 | endif 107 | sleep 10m 108 | endwhile 109 | return v:false 110 | endfunction 111 | -------------------------------------------------------------------------------- /test/Vim/Buffer/ANSI.vimspec: -------------------------------------------------------------------------------- 1 | Describe Vim.Buffer.ANSI 2 | After all 3 | silent %bwipeout! 4 | End 5 | 6 | Before 7 | let ANSI = vital#vital#import('Vim.Buffer.ANSI') 8 | silent %bwipeout! 9 | End 10 | 11 | It defines ColorScheme autocmd to define highlights for ANSI Colors 12 | Assert True(exists('#vital_vim_buffer_ansi')) 13 | End 14 | 15 | Describe .define_syntac([{prefix}]) 16 | It define syntaxes for ANSI color sequence 17 | call ANSI.define_syntax() 18 | Assert False(empty(execute('syntax list AnsiSuppress'))) 19 | Assert False(empty(execute('syntax list AnsiColor0'))) 20 | Assert False(empty(execute('syntax list AnsiColor1'))) 21 | Assert False(empty(execute('syntax list AnsiColor2'))) 22 | Assert False(empty(execute('syntax list AnsiColor3'))) 23 | Assert False(empty(execute('syntax list AnsiColor4'))) 24 | Assert False(empty(execute('syntax list AnsiColor5'))) 25 | Assert False(empty(execute('syntax list AnsiColor6'))) 26 | Assert False(empty(execute('syntax list AnsiColor7'))) 27 | Assert False(empty(execute('syntax list AnsiColor8'))) 28 | Assert False(empty(execute('syntax list AnsiColor9'))) 29 | Assert False(empty(execute('syntax list AnsiColor10'))) 30 | Assert False(empty(execute('syntax list AnsiColor11'))) 31 | Assert False(empty(execute('syntax list AnsiColor12'))) 32 | Assert False(empty(execute('syntax list AnsiColor13'))) 33 | Assert False(empty(execute('syntax list AnsiColor14'))) 34 | Assert False(empty(execute('syntax list AnsiColor15'))) 35 | Assert False(empty(execute('syntax list @AnsiColors'))) 36 | End 37 | 38 | It define syntaxes for ANSI color sequence with {prefix} 39 | call ANSI.define_syntax('Test') 40 | Assert False(empty(execute('syntax list TestAnsiSuppress'))) 41 | Assert False(empty(execute('syntax list TestAnsiColor0'))) 42 | Assert False(empty(execute('syntax list TestAnsiColor1'))) 43 | Assert False(empty(execute('syntax list TestAnsiColor2'))) 44 | Assert False(empty(execute('syntax list TestAnsiColor3'))) 45 | Assert False(empty(execute('syntax list TestAnsiColor4'))) 46 | Assert False(empty(execute('syntax list TestAnsiColor5'))) 47 | Assert False(empty(execute('syntax list TestAnsiColor6'))) 48 | Assert False(empty(execute('syntax list TestAnsiColor7'))) 49 | Assert False(empty(execute('syntax list TestAnsiColor8'))) 50 | Assert False(empty(execute('syntax list TestAnsiColor9'))) 51 | Assert False(empty(execute('syntax list TestAnsiColor10'))) 52 | Assert False(empty(execute('syntax list TestAnsiColor11'))) 53 | Assert False(empty(execute('syntax list TestAnsiColor12'))) 54 | Assert False(empty(execute('syntax list TestAnsiColor13'))) 55 | Assert False(empty(execute('syntax list TestAnsiColor14'))) 56 | Assert False(empty(execute('syntax list TestAnsiColor15'))) 57 | Assert False(empty(execute('syntax list @TestAnsiColors'))) 58 | End 59 | End 60 | End 61 | -------------------------------------------------------------------------------- /test/Vim/Buffer/Group.vimspec: -------------------------------------------------------------------------------- 1 | Describe Vim.Buffer.Group 2 | After all 3 | silent %bwipeout! 4 | End 5 | 6 | Before 7 | let Group = vital#vital#import('Vim.Buffer.Group') 8 | silent %bwipeout! 9 | End 10 | 11 | Describe .new() 12 | It returns a new unique group instance 13 | let group1 = Group.new() 14 | let group2 = Group.new() 15 | Assert NotSame(group1, group2) 16 | End 17 | End 18 | 19 | Describe group instance 20 | Before 21 | let group = Group.new() 22 | End 23 | 24 | Describe the behavior 25 | It close all members except buffers added with {'keep': 1} 26 | new foo1 27 | call group.add() 28 | new foo2 29 | call group.add({'keep': 1}) 30 | new foo3 31 | call group.add() 32 | new foo4 33 | call group.add() 34 | new foo5 35 | call group.add({'keep': 1}) 36 | Assert Equals(winnr('$'), 5 + 1) 37 | close 38 | Assert Equals(winnr('$'), 1 + 1) 39 | End 40 | 41 | It does not close buffers when no member buffer has closed 42 | new foo1 43 | call group.add() 44 | new foo2 45 | call group.add({'keep': 1}) 46 | new foo3 47 | call group.add() 48 | new foo4 49 | call group.add() 50 | new foo5 51 | call group.add({'keep': 1}) 52 | new foo6 53 | Assert Equals(winnr('$'), 6 + 1) 54 | close 55 | Assert Equals(winnr('$'), 5 + 1) 56 | End 57 | 58 | It does not close buffers when tabpage has changed 59 | new foo1 60 | call group.add() 61 | new foo2 62 | call group.add({'keep': 1}) 63 | new foo3 64 | call group.add() 65 | new foo4 66 | call group.add() 67 | new foo5 68 | call group.add({'keep': 1}) 69 | Assert Equals(winnr('$'), 5 + 1) 70 | tabnew 71 | Assert Equals(winnr('$'), 1) 72 | tabprevious 73 | Assert Equals(winnr('$'), 5 + 1) 74 | End 75 | End 76 | End 77 | End 78 | -------------------------------------------------------------------------------- /test/Vim/Window/Cursor.vimspec: -------------------------------------------------------------------------------- 1 | Describe Vim.Window.Cursor 2 | Before 3 | let WindowCursor = vital#vital#import('Vim.Window.Cursor') 4 | call setline(1, [ 5 | \ 'Hello', 6 | \ 'Darkness', 7 | \ 'My', 8 | \ 'Old', 9 | \ 'Friend', 10 | \]) 11 | End 12 | 13 | After 14 | %bwipeout! 15 | End 16 | 17 | Describe .get_cursor() 18 | It returns [x, y] of the cursor on the window 19 | let winid = win_getid() 20 | Assert Equals(WindowCursor.get_cursor(winid), [1, 0]) 21 | 22 | call cursor(2, 1) 23 | Assert Equals(WindowCursor.get_cursor(winid), [2, 0]) 24 | 25 | call cursor(2, 5) 26 | Assert Equals(WindowCursor.get_cursor(winid), [2, 4]) 27 | End 28 | End 29 | End 30 | -------------------------------------------------------------------------------- /test/_testdata/System/Job/cwd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | import time 5 | import argparse 6 | 7 | parser = argparse.ArgumentParser() 8 | parser.add_argument('--delay', 9 | type=int, 10 | default=0) 11 | parser.add_argument('--newline', 12 | choices=['\n', '\r', '\r\n'], 13 | default='\n') 14 | parser.add_argument('--out', 15 | choices=['stdout', 'stderr'], 16 | default='stdout') 17 | args = parser.parse_args() 18 | 19 | fo = sys.stderr if args.out == 'stderr' else sys.stdout 20 | 21 | # Disable universal newline to prevent '\n' -> '\r\n' in Windows 22 | if sys.platform.startswith('win'): 23 | if sys.version_info < (3,): 24 | import msvcrt 25 | msvcrt.setmode(fo.fileno(), os.O_BINARY) 26 | else: 27 | fo = open( 28 | fo.fileno(), 29 | mode=fo.mode, 30 | buffering=1, 31 | encoding=fo.encoding, 32 | errors=fo.errors, 33 | newline='\n', 34 | closefd=False, 35 | ) 36 | 37 | if args.delay: 38 | time.sleep(args.delay / 1000.0) 39 | 40 | fo.write(os.getcwd()) 41 | fo.write(args.newline) 42 | fo.flush() 43 | -------------------------------------------------------------------------------- /test/_testdata/System/Job/echo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | import time 5 | import argparse 6 | 7 | parser = argparse.ArgumentParser() 8 | parser.add_argument('--delay', 9 | type=int, 10 | default=0) 11 | parser.add_argument('--interval', 12 | type=int, 13 | default=100) 14 | parser.add_argument('--newline', 15 | choices=['\n', '\r', '\r\n'], 16 | default='\n') 17 | parser.add_argument('--out', 18 | choices=['stdout', 'stderr'], 19 | default='stdout') 20 | parser.add_argument('--without-trailing-newline', 21 | action='store_true', 22 | default=False) 23 | args = parser.parse_args() 24 | 25 | fo = sys.stderr if args.out == 'stderr' else sys.stdout 26 | 27 | # Disable universal newline to prevent '\n' -> '\r\n' in Windows 28 | if sys.platform.startswith('win'): 29 | if sys.version_info < (3,): 30 | import msvcrt 31 | msvcrt.setmode(fo.fileno(), os.O_BINARY) 32 | else: 33 | fo = open( 34 | fo.fileno(), 35 | mode=fo.mode, 36 | buffering=1, 37 | encoding=fo.encoding, 38 | errors=fo.errors, 39 | newline='\n', 40 | closefd=False, 41 | ) 42 | 43 | if args.delay: 44 | time.sleep(args.delay / 1000.0) 45 | 46 | chunks = [ 47 | 'Hello', 48 | ' World', 49 | args.newline, 50 | 'Hello', 51 | ' World', 52 | '' if args.without_trailing_newline else args.newline, 53 | ] 54 | 55 | for chunk in chunks: 56 | fo.write(chunk) 57 | fo.flush() 58 | if args.interval: 59 | time.sleep(args.interval / 1000.0) 60 | -------------------------------------------------------------------------------- /test/_testdata/System/Job/env.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import argparse 3 | import os 4 | import sys 5 | import time 6 | 7 | parser = argparse.ArgumentParser() 8 | parser.add_argument("name") 9 | parser.add_argument("--delay", type=int, default=0) 10 | parser.add_argument("--interval", type=int, default=100) 11 | parser.add_argument("--newline", choices=["\n", "\r", "\r\n"], default="\n") 12 | parser.add_argument("--out", choices=["stdout", "stderr"], default="stdout") 13 | args = parser.parse_args() 14 | 15 | fo = sys.stderr if args.out == "stderr" else sys.stdout 16 | 17 | # Disable universal newline to prevent '\n' -> '\r\n' in Windows 18 | if sys.platform.startswith("win"): 19 | if sys.version_info < (3,): 20 | import msvcrt 21 | 22 | msvcrt.setmode(fo.fileno(), os.O_BINARY) 23 | else: 24 | fo = open( 25 | fo.fileno(), 26 | mode=fo.mode, 27 | buffering=1, 28 | encoding=fo.encoding, 29 | errors=fo.errors, 30 | newline="\n", 31 | closefd=False, 32 | ) 33 | 34 | fo.write(os.environ[args.name]) 35 | fo.write(args.newline) 36 | fo.flush() 37 | -------------------------------------------------------------------------------- /test/_testdata/System/Job/exit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import time 3 | import sys 4 | import argparse 5 | 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument('--delay', 8 | type=int, 9 | default=0) 10 | parser.add_argument('--exitval', 11 | type=int, 12 | default=0) 13 | args = parser.parse_args() 14 | 15 | if args.delay: 16 | time.sleep(args.delay / 1000.0) 17 | sys.exit(args.exitval) 18 | -------------------------------------------------------------------------------- /test/_testdata/System/Job/never.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import time 3 | 4 | while True: 5 | time.sleep(1) 6 | -------------------------------------------------------------------------------- /test/_testdata/System/Job/reply.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | import time 5 | import argparse 6 | 7 | parser = argparse.ArgumentParser() 8 | parser.add_argument('--delay', 9 | type=int, 10 | default=0) 11 | parser.add_argument('--interval', 12 | type=int, 13 | default=100) 14 | parser.add_argument('--newline', 15 | choices=['\n', '\r', '\r\n'], 16 | default='\n') 17 | parser.add_argument('--out', 18 | choices=['stdout', 'stderr'], 19 | default='stdout') 20 | args = parser.parse_args() 21 | 22 | fo = sys.stderr if args.out == 'stderr' else sys.stdout 23 | 24 | # Disable universal newline to prevent '\n' -> '\r\n' in Windows 25 | if sys.platform.startswith('win'): 26 | if sys.version_info < (3,): 27 | import msvcrt 28 | msvcrt.setmode(fo.fileno(), os.O_BINARY) 29 | else: 30 | fo = open( 31 | fo.fileno(), 32 | mode=fo.mode, 33 | buffering=1, 34 | encoding=fo.encoding, 35 | errors=fo.errors, 36 | newline='\n', 37 | closefd=False, 38 | ) 39 | 40 | if args.delay: 41 | time.sleep(args.delay / 1000.0) 42 | 43 | for m in sys.stdin: 44 | fo.write('received: %s' % m.replace('\0', '')) 45 | fo.flush() 46 | if args.interval: 47 | time.sleep(args.interval / 1000.0) 48 | -------------------------------------------------------------------------------- /test/_testdata/Vim/Buffer/Writer/cp1250-encoding.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdalisue/vital-Whisky/15d41606076842931af0530c5e330c5fc96d4713/test/_testdata/Vim/Buffer/Writer/cp1250-encoding.txt -------------------------------------------------------------------------------- /test/_testdata/Vim/Buffer/Writer/cp932-encoding.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdalisue/vital-Whisky/15d41606076842931af0530c5e330c5fc96d4713/test/_testdata/Vim/Buffer/Writer/cp932-encoding.txt -------------------------------------------------------------------------------- /test/_testdata/Vim/Buffer/Writer/euc-jp-encoding.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdalisue/vital-Whisky/15d41606076842931af0530c5e330c5fc96d4713/test/_testdata/Vim/Buffer/Writer/euc-jp-encoding.txt -------------------------------------------------------------------------------- /test/_testdata/Vim/Buffer/Writer/sjis-encoding.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdalisue/vital-Whisky/15d41606076842931af0530c5e330c5fc96d4713/test/_testdata/Vim/Buffer/Writer/sjis-encoding.txt -------------------------------------------------------------------------------- /test/_testdata/Vim/Buffer/Writer/utf-8-encoding.txt: -------------------------------------------------------------------------------- 1 | Unix EOL 2 | árvíztűrő tükörfúrógép 3 | ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP 4 | --------------------------------------------------------------------------------