mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-23 07:00:04 +08:00
feat(plantuml): add java_command
option
close https://github.com/SpaceVim/SpaceVim/issues/4586
This commit is contained in:
parent
dfb8b10556
commit
6975374b3b
@ -6,11 +6,46 @@
|
||||
" License: GPLv3
|
||||
"=============================================================================
|
||||
|
||||
""
|
||||
" @section lang#plantuml, layers-lang-plantuml
|
||||
" @parentsection layers
|
||||
" This layer is for plantuml development, disabled by default, to enable this
|
||||
" layer, add following snippet to your SpaceVim configuration file.
|
||||
" >
|
||||
" [[layers]]
|
||||
" name = 'lang#plantuml'
|
||||
" <
|
||||
"
|
||||
" @subsection layer options
|
||||
"
|
||||
" 1. `java_command`: Set the path of java command, by default, it is `java`
|
||||
" >
|
||||
" [[layers]]
|
||||
" name = 'lang#plantuml'
|
||||
" java_command = 'path/to/java'
|
||||
" <
|
||||
" 2. `plantuml_jar_path`: Set the path of `pluatuml.jar`.
|
||||
" >
|
||||
" [[layers]]
|
||||
" name = 'lang#plantuml'
|
||||
" plantuml_jar_path = 'path/to/plantuml.jar'
|
||||
" <
|
||||
"
|
||||
" @subsection Key bindings
|
||||
" >
|
||||
" Mode Key Function
|
||||
" ---------------------------------------------
|
||||
" normal SPC l p preview uml file
|
||||
" normal SPC l c stop preview
|
||||
" normal SPC l s save uml file
|
||||
" <
|
||||
"
|
||||
|
||||
function! SpaceVim#layers#lang#plantuml#plugins() abort
|
||||
let plugins = []
|
||||
call add(plugins, ['aklt/plantuml-syntax', {'on_ft' : 'plantuml'}])
|
||||
call add(plugins, ['wsdjeg/vim-slumlord', {'on_ft' : 'plantuml'}])
|
||||
call add(plugins, ['weirongxu/plantuml-previewer.vim', {'depends': 'open-browser.vim'}])
|
||||
call add(plugins, [g:_spacevim_root_dir . 'bundle/plantuml-previewer.vim', {'merged':0}])
|
||||
return plugins
|
||||
endfunction
|
||||
|
||||
@ -28,6 +63,7 @@ let s:plantuml_jar_path = ''
|
||||
function! SpaceVim#layers#lang#plantuml#set_variable(var) abort
|
||||
|
||||
let s:plantuml_jar_path = get(a:var, 'plantuml_jar_path', s:plantuml_jar_path)
|
||||
let g:plantuml_java_command = get(a:var, 'java_command', 'java')
|
||||
|
||||
endfunction
|
||||
|
||||
|
6
bundle/plantuml-previewer.vim/.gitignore
vendored
Normal file
6
bundle/plantuml-previewer.vim/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/viewer/tmp.svg
|
||||
/viewer/tmp.png
|
||||
/viewer/tmp.js
|
||||
/viewer/tmp.puml
|
||||
/viewer/node_modules
|
||||
/tmp
|
21
bundle/plantuml-previewer.vim/LICENSE
Normal file
21
bundle/plantuml-previewer.vim/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Weirong Xu <weirongxu.raidou@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
71
bundle/plantuml-previewer.vim/README.md
Normal file
71
bundle/plantuml-previewer.vim/README.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Plantuml Previewer Vim
|
||||
Vim/NeoVim plugin for preview [PlantUML](http://plantuml.com/)
|
||||
|
||||
![image](https://user-images.githubusercontent.com/1709861/40650003-dcd75a76-6364-11e8-8cb1-40d710a0cc0a.png)
|
||||
|
||||
## Dependencies
|
||||
* Java
|
||||
* Graphviz (https://www.graphviz.org/download/)
|
||||
* brew install graphviz
|
||||
* apt-get install graphviz
|
||||
* [open-browser.vim](https://github.com/tyru/open-browser.vim)
|
||||
* [aklt/plantuml-syntax](https://github.com/aklt/plantuml-syntax) (vim syntax file for plantuml)
|
||||
|
||||
## Usage
|
||||
1. Start editing plantuml file in Vim
|
||||
2. Run `:PlantumlOpen` to open previewer webpage in browser
|
||||
3. Saving plantuml file in Vim, then previewer webpage will refresh
|
||||
|
||||
### Commands
|
||||
|
||||
#### PlantumlOpen
|
||||
Open previewer webpage in browser, and watch current buffer
|
||||
|
||||
#### PlantumlStart
|
||||
Like `PlantumlOpen`, but won't open in browser
|
||||
|
||||
#### PlantumlStop
|
||||
Stop watch buffer
|
||||
|
||||
#### PlantumlSave [filepath] [format]
|
||||
Export uml diagram to file path
|
||||
Available formats
|
||||
> png, svg, eps, pdf, vdx, xmi,
|
||||
> scxml, html, txt, utxt, latex
|
||||
|
||||
Example:
|
||||
```
|
||||
:e diagram.puml
|
||||
|
||||
:PlantumlSave
|
||||
:PlantumlSave diagram.png
|
||||
:PlantumlSave diagram.svg
|
||||
```
|
||||
|
||||
### Variables
|
||||
#### `g:plantuml_previewer#plantuml_jar_path`
|
||||
Custom plantuml.jar file path
|
||||
|
||||
If plant uml was installed by homebrew, you can add the following code to your `.vimrc` to use the version installed by homebrew:
|
||||
|
||||
```vim
|
||||
au FileType plantuml let g:plantuml_previewer#plantuml_jar_path = get(
|
||||
\ matchlist(system('cat `which plantuml` | grep plantuml.jar'), '\v.*\s[''"]?(\S+plantuml\.jar).*'),
|
||||
\ 1,
|
||||
\ 0
|
||||
\)
|
||||
```
|
||||
|
||||
#### `g:plantuml_previewer#save_format`
|
||||
`:PlantumlSave` default format
|
||||
Default: 'png'
|
||||
|
||||
#### `g:plantuml_previewer#viewer_path`
|
||||
Custom plantuml viewer path
|
||||
The plugin will copy viewer to here if the directory does not exist
|
||||
And `tmp.puml` and `tmp.svg` will output to here
|
||||
|
||||
|
||||
## Related
|
||||
* [vim-slumlord](https://github.com/scrooloose/vim-slumlord)
|
||||
* [previm](https://github.com/kannokanno/previm)
|
210
bundle/plantuml-previewer.vim/autoload/plantuml_previewer.vim
Normal file
210
bundle/plantuml-previewer.vim/autoload/plantuml_previewer.vim
Normal file
@ -0,0 +1,210 @@
|
||||
let s:Process = vital#plantuml_previewer#new().import('System.Process')
|
||||
let s:Job = vital#plantuml_previewer#new().import('System.Job')
|
||||
let s:is_win = has('win32') || has('win64') || has('win95')
|
||||
|
||||
let s:base_path = fnameescape(expand("<sfile>:p:h")) . '/..'
|
||||
|
||||
let s:default_jar_path = s:base_path . '/lib/plantuml.jar'
|
||||
|
||||
let s:tmp_path = s:base_path . '/tmp'
|
||||
|
||||
let s:save_as_script_path = s:base_path . '/script/save-as' . (s:is_win ? '.cmd' : '.sh')
|
||||
|
||||
let s:update_viewer_script_path = s:base_path . '/script/update-viewer' . (s:is_win ? '.cmd' : '.sh')
|
||||
|
||||
let s:watched_bufnr = 0
|
||||
|
||||
let s:started = v:false
|
||||
|
||||
let s:java = get(g:, 'plantuml_java_command', 'java')
|
||||
|
||||
function! plantuml_previewer#start() "{{{
|
||||
if !executable(s:java)
|
||||
echoerr 'require java command'
|
||||
return v:false
|
||||
endif
|
||||
let viewer_path = s:viewer_path()
|
||||
if !isdirectory(viewer_path) && !filereadable(viewer_path)
|
||||
call plantuml_previewer#copy_viewer_directory()
|
||||
endif
|
||||
call delete(s:viewer_tmp_puml_path())
|
||||
call delete(s:viewer_tmp_svg_path())
|
||||
let s:watched_bufnr = bufnr('%')
|
||||
call plantuml_previewer#refresh(s:watched_bufnr)
|
||||
augroup plantuml_previewer
|
||||
autocmd!
|
||||
autocmd BufWritePost *.pu,*.uml,*.plantuml,*.puml,*.iuml call plantuml_previewer#refresh(s:watched_bufnr)
|
||||
augroup END
|
||||
return v:true
|
||||
endfunction "}}}
|
||||
|
||||
function! plantuml_previewer#open() "{{{
|
||||
if !exists('*OpenBrowser')
|
||||
echoerr 'require open-browser.vim'
|
||||
return v:false
|
||||
endif
|
||||
let start_result = plantuml_previewer#start()
|
||||
if !start_result
|
||||
return v:false
|
||||
endif
|
||||
call OpenBrowser(s:viewer_html_path())
|
||||
let s:started = v:true
|
||||
return v:true
|
||||
endfunction "}}}
|
||||
|
||||
function! plantuml_previewer#stop() "{{{
|
||||
augroup plantuml_previewer
|
||||
autocmd!
|
||||
augroup END
|
||||
let s:started = v:false
|
||||
endfunction "}}}
|
||||
|
||||
function! plantuml_previewer#toggle() abort
|
||||
if s:started
|
||||
call plantuml_previewer#stop()
|
||||
echo 'plantuml-previewer stopped'
|
||||
else
|
||||
let open_result = plantuml_previewer#open()
|
||||
if open_result
|
||||
echo 'plantuml-previewer opened'
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:is_zero(val) "{{{
|
||||
return type(a:val) == type(0) && a:val == 0
|
||||
endfunction "}}}
|
||||
|
||||
function! plantuml_previewer#copy_viewer_directory() "{{{
|
||||
let viewer_path = s:viewer_path()
|
||||
let default_viewer_path = plantuml_previewer#default_viewer_path()
|
||||
if viewer_path != default_viewer_path
|
||||
if s:is_win
|
||||
call system('xcopy ' . default_viewer_path . ' ' . g:plantuml_previewer#viewer_path . ' /O /X /E /H /K')
|
||||
else
|
||||
call system('cp -r ' . default_viewer_path . ' ' . g:plantuml_previewer#viewer_path)
|
||||
endif
|
||||
echom 'copy ' . default_viewer_path . ' -> ' . viewer_path
|
||||
endif
|
||||
endfunction "}}}
|
||||
|
||||
function! plantuml_previewer#default_viewer_path() "{{{
|
||||
return s:base_path . '/viewer'
|
||||
endfunction "}}}
|
||||
|
||||
function! s:viewer_path() "{{{
|
||||
let path = get(g:, 'plantuml_previewer#viewer_path', 0)
|
||||
return s:is_zero(path) ? plantuml_previewer#default_viewer_path() : fnameescape(path)
|
||||
endfunction "}}}
|
||||
|
||||
function! s:viewer_tmp_puml_path() "{{{
|
||||
return s:viewer_path() . '/tmp.puml'
|
||||
endfunction "}}}
|
||||
|
||||
function! s:viewer_tmp_svg_path() "{{{
|
||||
return s:viewer_path() . '/tmp.svg'
|
||||
endfunction "}}}
|
||||
|
||||
function! s:viewer_tmp_js_path() "{{{
|
||||
return s:viewer_path() . '/tmp.js'
|
||||
endfunction "}}}
|
||||
|
||||
function! s:viewer_html_path() "{{{
|
||||
return s:viewer_path() . '/index.html'
|
||||
endfunction "}}}
|
||||
|
||||
function! s:jar_path() "{{{
|
||||
let path = get(g:, 'plantuml_previewer#plantuml_jar_path', 0)
|
||||
return s:is_zero(path) ? s:default_jar_path : path
|
||||
endfunction "}}}
|
||||
|
||||
function! s:save_format() "{{{
|
||||
return get(g:, 'plantuml_previewer#save_format', 'png')
|
||||
endfunction "}}}
|
||||
|
||||
function! s:ext_to_fmt(ext) "{{{
|
||||
return a:ext == 'tex' ? 'latex' : a:ext
|
||||
endfunction "}}}
|
||||
|
||||
function! s:fmt_to_ext(fmt) "{{{
|
||||
return a:fmt == 'latex' ? 'tex' : a:fmt
|
||||
endfunction "}}}
|
||||
|
||||
function! s:run_in_background(cmd) "{{{
|
||||
if s:Job.is_available()
|
||||
call s:Job.start(a:cmd)
|
||||
else
|
||||
try
|
||||
call s:Process.execute(a:cmd, {
|
||||
\ 'background': 1,
|
||||
\})
|
||||
catch
|
||||
call s:Process.execute(a:cmd)
|
||||
endtry
|
||||
endif
|
||||
endfunction "}}}
|
||||
|
||||
function! s:normalize_path(path) "{{{
|
||||
return simplify(expand(a:path, 1))
|
||||
endfunction "}}}
|
||||
|
||||
function! plantuml_previewer#refresh(bufnr) "{{{
|
||||
let puml_src_path = fnamemodify(bufname(a:bufnr), ':p')
|
||||
let puml_filename = fnamemodify(puml_src_path, ':t:r')
|
||||
let image_type = 'svg'
|
||||
let image_ext = s:fmt_to_ext(image_type)
|
||||
let output_dir_path = s:tmp_path
|
||||
let output_path = output_dir_path . '/' . puml_filename . '.' . image_ext
|
||||
let finial_path = s:viewer_path() . '/tmp.' . image_ext
|
||||
let cmd = [
|
||||
\ s:update_viewer_script_path,
|
||||
\ s:java,
|
||||
\ s:jar_path(),
|
||||
\ puml_src_path,
|
||||
\ s:normalize_path(output_dir_path),
|
||||
\ s:normalize_path(output_path),
|
||||
\ s:normalize_path(finial_path),
|
||||
\ image_type,
|
||||
\ localtime(),
|
||||
\ s:normalize_path(s:viewer_tmp_js_path()),
|
||||
\ ]
|
||||
call s:run_in_background(cmd)
|
||||
endfunction "}}}
|
||||
|
||||
function! plantuml_previewer#save_as(...) "{{{
|
||||
if !executable('java')
|
||||
echoerr 'require java command'
|
||||
return
|
||||
endif
|
||||
|
||||
let save_path = get(a:000, 0, 0)
|
||||
let image_type = get(a:000, 1, 0)
|
||||
if s:is_zero(save_path)
|
||||
let source_name = expand('%:t:r')
|
||||
let save_path = printf("%s.%s", source_name, s:fmt_to_ext(s:save_format()))
|
||||
else
|
||||
let save_path = fnamemodify(save_path, ':p')
|
||||
endif
|
||||
if s:is_zero(image_type)
|
||||
let ext = fnamemodify(save_path, ':e')
|
||||
let image_type = ext == '' ? s:save_format() : s:ext_to_fmt(ext)
|
||||
endif
|
||||
|
||||
let puml_src_path = expand('%:p')
|
||||
let puml_filename = fnamemodify(puml_src_path, ':t:r')
|
||||
let image_ext = s:fmt_to_ext(image_type)
|
||||
let output_dir_path = s:tmp_path
|
||||
let output_path = output_dir_path . '/' . puml_filename . '.' . image_ext
|
||||
call mkdir(fnamemodify(save_path, ':p:h'), 'p')
|
||||
let cmd = [
|
||||
\ s:save_as_script_path,
|
||||
\ s:java,
|
||||
\ s:jar_path(),
|
||||
\ puml_src_path,
|
||||
\ s:normalize_path(output_dir_path),
|
||||
\ s:normalize_path(output_path),
|
||||
\ s:normalize_path(save_path),
|
||||
\ image_type,
|
||||
\ ]
|
||||
call s:run_in_background(cmd)
|
||||
endfunction "}}}
|
@ -0,0 +1,9 @@
|
||||
let s:_plugin_name = expand('<sfile>:t:r')
|
||||
|
||||
function! vital#{s:_plugin_name}#new() abort
|
||||
return vital#{s:_plugin_name[1:]}#new()
|
||||
endfunction
|
||||
|
||||
function! vital#{s:_plugin_name}#function(funcname) abort
|
||||
silent! return function(a:funcname)
|
||||
endfunction
|
@ -0,0 +1,151 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#Data#Dict#import() abort', printf("return map({'_vital_depends': '', 'clear': '', 'max_by': '', 'foldl': '', 'pick': '', 'from_list': '', 'swap': '', 'omit': '', 'min_by': '', 'foldr': '', 'make_index': '', 'make': '', '_vital_loaded': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
" Utilities for dictionary.
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:t = a:V.import('Vim.Type').types
|
||||
endfunction
|
||||
|
||||
function! s:_vital_depends() abort
|
||||
return ['Vim.Type']
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:_ensure_key(key) abort
|
||||
let t = type(a:key)
|
||||
if t != s:t.string && t != s:t.number
|
||||
throw 'vital: Data.Dict: Invalid key: ' . string(a:key)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:from_list(list) abort
|
||||
let dict = {}
|
||||
let i = 0
|
||||
let len = len(a:list)
|
||||
while i < len
|
||||
if type(a:list[i]) == s:t.list
|
||||
let key_value = a:list[i]
|
||||
if len(key_value) != 2
|
||||
throw 'vital: Data.Dict: Invalid key-value pair index at ' . i
|
||||
endif
|
||||
call s:_ensure_key(key_value[0])
|
||||
let dict[key_value[0]] = key_value[1]
|
||||
let i += 1
|
||||
else
|
||||
if len <= i + 1
|
||||
throw 'vital: Data.Dict: Invalid key-value pair index at ' . i
|
||||
endif
|
||||
call s:_ensure_key(a:list[i])
|
||||
let dict[a:list[i]] = a:list[i + 1]
|
||||
let i += 2
|
||||
endif
|
||||
endwhile
|
||||
return dict
|
||||
endfunction
|
||||
|
||||
" Makes a dict from keys and values
|
||||
function! s:make(keys, values, ...) abort
|
||||
let dict = {}
|
||||
let fill = a:0 ? a:1 : 0
|
||||
for i in range(len(a:keys))
|
||||
let key = type(a:keys[i]) == s:t.string ? a:keys[i] : string(a:keys[i])
|
||||
if key ==# ''
|
||||
throw "vital: Data.Dict: Can't use an empty string for key."
|
||||
endif
|
||||
let dict[key] = get(a:values, i, fill)
|
||||
endfor
|
||||
return dict
|
||||
endfunction
|
||||
|
||||
" Swaps keys and values
|
||||
function! s:swap(dict) abort
|
||||
return s:make(values(a:dict), keys(a:dict))
|
||||
endfunction
|
||||
|
||||
" Makes a index dict from a list
|
||||
function! s:make_index(list, ...) abort
|
||||
let value = a:0 ? a:1 : 1
|
||||
return s:make(a:list, [], value)
|
||||
endfunction
|
||||
|
||||
function! s:pick(dict, keys) abort
|
||||
let new_dict = {}
|
||||
for key in a:keys
|
||||
if has_key(a:dict, key)
|
||||
let new_dict[key] = a:dict[key]
|
||||
endif
|
||||
endfor
|
||||
return new_dict
|
||||
endfunction
|
||||
|
||||
function! s:omit(dict, keys) abort
|
||||
let new_dict = copy(a:dict)
|
||||
for key in a:keys
|
||||
if has_key(a:dict, key)
|
||||
call remove(new_dict, key)
|
||||
endif
|
||||
endfor
|
||||
return new_dict
|
||||
endfunction
|
||||
|
||||
function! s:clear(dict) abort
|
||||
for key in keys(a:dict)
|
||||
call remove(a:dict, key)
|
||||
endfor
|
||||
return a:dict
|
||||
endfunction
|
||||
|
||||
function! s:_max_by(dict, expr) abort
|
||||
let dict = s:swap(map(copy(a:dict), a:expr))
|
||||
let key = dict[max(keys(dict))]
|
||||
return [key, a:dict[key]]
|
||||
endfunction
|
||||
|
||||
function! s:max_by(dict, expr) abort
|
||||
if empty(a:dict)
|
||||
throw 'vital: Data.Dict: Empty dictionary'
|
||||
endif
|
||||
return s:_max_by(a:dict, a:expr)
|
||||
endfunction
|
||||
|
||||
function! s:min_by(dict, expr) abort
|
||||
if empty(a:dict)
|
||||
throw 'vital: Data.Dict: Empty dictionary'
|
||||
endif
|
||||
return s:_max_by(a:dict, '-(' . a:expr . ')')
|
||||
endfunction
|
||||
|
||||
function! s:_foldl(f, init, xs) abort
|
||||
let memo = a:init
|
||||
for [k, v] in a:xs
|
||||
let expr = substitute(a:f, 'v:key', string(k), 'g')
|
||||
let expr = substitute(expr, 'v:val', string(v), 'g')
|
||||
let expr = substitute(expr, 'v:memo', string(memo), 'g')
|
||||
unlet memo
|
||||
let memo = eval(expr)
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
function! s:foldl(f, init, dict) abort
|
||||
return s:_foldl(a:f, a:init, items(a:dict))
|
||||
endfunction
|
||||
|
||||
function! s:foldr(f, init, dict) abort
|
||||
return s:_foldl(a:f, a:init, reverse(items(a:dict)))
|
||||
endfunction
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim:set et ts=2 sts=2 sw=2 tw=0:
|
@ -0,0 +1,464 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#Data#List#import() abort', printf("return map({'combinations': '', 'and': '', 'sort_by': '', 'foldr1': '', 'sort': '', 'flatten': '', 'has_index': '', 'find_indices': '', 'any': '', 'unshift': '', 'span': '', 'pop': '', 'binary_search': '', 'uniq_by': '', 'or': '', 'all': '', 'zip': '', 'find_last_index': '', 'find': '', 'partition': '', 'shift': '', 'permutations': '', 'break': '', 'max_by': '', 'foldl': '', 'foldr': '', 'find_index': '', 'drop_while': '', 'group_by': '', 'take_while': '', 'conj': '', 'push': '', 'char_range': '', 'cons': '', 'foldl1': '', 'intersect': '', 'concat': '', 'map_accum': '', 'clear': '', 'has_common_items': '', 'product': '', 'zip_fill': '', 'uniq': '', 'has': '', 'min_by': '', 'with_index': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
" Utilities for list.
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
function! s:pop(list) abort
|
||||
return remove(a:list, -1)
|
||||
endfunction
|
||||
|
||||
function! s:push(list, val) abort
|
||||
call add(a:list, a:val)
|
||||
return a:list
|
||||
endfunction
|
||||
|
||||
function! s:shift(list) abort
|
||||
return remove(a:list, 0)
|
||||
endfunction
|
||||
|
||||
function! s:unshift(list, val) abort
|
||||
return insert(a:list, a:val)
|
||||
endfunction
|
||||
|
||||
function! s:cons(x, xs) abort
|
||||
return [a:x] + a:xs
|
||||
endfunction
|
||||
|
||||
function! s:conj(xs, x) abort
|
||||
return a:xs + [a:x]
|
||||
endfunction
|
||||
|
||||
" Removes duplicates from a list.
|
||||
function! s:uniq(list) abort
|
||||
return s:uniq_by(a:list, 'v:val')
|
||||
endfunction
|
||||
|
||||
" Removes duplicates from a list.
|
||||
function! s:uniq_by(list, f) abort
|
||||
let list = map(copy(a:list), printf('[v:val, %s]', a:f))
|
||||
let i = 0
|
||||
let seen = {}
|
||||
while i < len(list)
|
||||
let key = string(list[i][1])
|
||||
if has_key(seen, key)
|
||||
call remove(list, i)
|
||||
else
|
||||
let seen[key] = 1
|
||||
let i += 1
|
||||
endif
|
||||
endwhile
|
||||
return map(list, 'v:val[0]')
|
||||
endfunction
|
||||
|
||||
function! s:clear(list) abort
|
||||
if !empty(a:list)
|
||||
unlet! a:list[0 : len(a:list) - 1]
|
||||
endif
|
||||
return a:list
|
||||
endfunction
|
||||
|
||||
" Concatenates a list of lists.
|
||||
" XXX: Should we verify the input?
|
||||
function! s:concat(list) abort
|
||||
let memo = []
|
||||
for Value in a:list
|
||||
let memo += Value
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
" Take each elements from lists to a new list.
|
||||
function! s:flatten(list, ...) abort
|
||||
let limit = a:0 > 0 ? a:1 : -1
|
||||
let memo = []
|
||||
if limit == 0
|
||||
return a:list
|
||||
endif
|
||||
let limit -= 1
|
||||
for Value in a:list
|
||||
let memo +=
|
||||
\ type(Value) == type([]) ?
|
||||
\ s:flatten(Value, limit) :
|
||||
\ [Value]
|
||||
unlet! Value
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
" Sorts a list with expression to compare each two values.
|
||||
" a:a and a:b can be used in {expr}.
|
||||
function! s:sort(list, expr) abort
|
||||
if type(a:expr) == type(function('function'))
|
||||
return sort(a:list, a:expr)
|
||||
endif
|
||||
let s:expr = a:expr
|
||||
return sort(a:list, 's:_compare')
|
||||
endfunction
|
||||
|
||||
function! s:_compare(a, b) abort
|
||||
return eval(s:expr)
|
||||
endfunction
|
||||
|
||||
" Sorts a list using a set of keys generated by mapping the values in the list
|
||||
" through the given expr.
|
||||
" v:val is used in {expr}
|
||||
function! s:sort_by(list, expr) abort
|
||||
let pairs = map(a:list, printf('[v:val, %s]', a:expr))
|
||||
return map(s:sort(pairs,
|
||||
\ 'a:a[1] ==# a:b[1] ? 0 : a:a[1] ># a:b[1] ? 1 : -1'), 'v:val[0]')
|
||||
endfunction
|
||||
|
||||
" Returns a maximum value in {list} through given {expr}.
|
||||
" Returns 0 if {list} is empty.
|
||||
" v:val is used in {expr}
|
||||
function! s:max_by(list, expr) abort
|
||||
if empty(a:list)
|
||||
return 0
|
||||
endif
|
||||
let list = map(copy(a:list), a:expr)
|
||||
return a:list[index(list, max(list))]
|
||||
endfunction
|
||||
|
||||
" Returns a minimum value in {list} through given {expr}.
|
||||
" Returns 0 if {list} is empty.
|
||||
" v:val is used in {expr}
|
||||
" FIXME: -0x80000000 == 0x80000000
|
||||
function! s:min_by(list, expr) abort
|
||||
return s:max_by(a:list, '-(' . a:expr . ')')
|
||||
endfunction
|
||||
|
||||
" Returns List of character sequence between [a:from, a:to]
|
||||
" e.g.: s:char_range('a', 'c') returns ['a', 'b', 'c']
|
||||
function! s:char_range(from, to) abort
|
||||
return map(
|
||||
\ range(char2nr(a:from), char2nr(a:to)),
|
||||
\ 'nr2char(v:val)'
|
||||
\)
|
||||
endfunction
|
||||
|
||||
" Returns true if a:list has a:value.
|
||||
" Returns false otherwise.
|
||||
function! s:has(list, value) abort
|
||||
return index(a:list, a:value) isnot -1
|
||||
endfunction
|
||||
|
||||
" Returns true if a:list[a:index] exists.
|
||||
" Returns false otherwise.
|
||||
" NOTE: Returns false when a:index is negative number.
|
||||
function! s:has_index(list, index) abort
|
||||
" Return true when negative index?
|
||||
" let index = a:index >= 0 ? a:index : len(a:list) + a:index
|
||||
return 0 <= a:index && a:index < len(a:list)
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.span
|
||||
function! s:span(f, xs) abort
|
||||
let border = len(a:xs)
|
||||
for i in range(len(a:xs))
|
||||
if !eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
|
||||
let border = i
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
return border == 0 ? [[], copy(a:xs)] : [a:xs[: border - 1], a:xs[border :]]
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.break
|
||||
function! s:break(f, xs) abort
|
||||
return s:span(printf('!(%s)', a:f), a:xs)
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.takeWhile
|
||||
function! s:take_while(f, xs) abort
|
||||
return s:span(a:f, a:xs)[0]
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.dropWhile
|
||||
function! s:drop_while(f, xs) abort
|
||||
return s:span(a:f, a:xs)[1]
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.partition
|
||||
function! s:partition(f, xs) abort
|
||||
return [filter(copy(a:xs), a:f), filter(copy(a:xs), '!(' . a:f . ')')]
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.all
|
||||
function! s:all(f, xs) abort
|
||||
return !s:any(printf('!(%s)', a:f), a:xs)
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.any
|
||||
function! s:any(f, xs) abort
|
||||
return !empty(filter(map(copy(a:xs), a:f), 'v:val'))
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.and
|
||||
function! s:and(xs) abort
|
||||
return s:all('v:val', a:xs)
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.or
|
||||
function! s:or(xs) abort
|
||||
return s:any('v:val', a:xs)
|
||||
endfunction
|
||||
|
||||
function! s:map_accum(expr, xs, init) abort
|
||||
let memo = []
|
||||
let init = a:init
|
||||
for x in a:xs
|
||||
let expr = substitute(a:expr, 'v:memo', init, 'g')
|
||||
let expr = substitute(expr, 'v:val', x, 'g')
|
||||
let [tmp, init] = eval(expr)
|
||||
call add(memo, tmp)
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.foldl
|
||||
function! s:foldl(f, init, xs) abort
|
||||
let memo = a:init
|
||||
for x in a:xs
|
||||
let expr = substitute(a:f, 'v:val', string(x), 'g')
|
||||
let expr = substitute(expr, 'v:memo', string(memo), 'g')
|
||||
unlet memo
|
||||
let memo = eval(expr)
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.foldl1
|
||||
function! s:foldl1(f, xs) abort
|
||||
if len(a:xs) == 0
|
||||
throw 'vital: Data.List: foldl1'
|
||||
endif
|
||||
return s:foldl(a:f, a:xs[0], a:xs[1:])
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.foldr
|
||||
function! s:foldr(f, init, xs) abort
|
||||
return s:foldl(a:f, a:init, reverse(copy(a:xs)))
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.fold11
|
||||
function! s:foldr1(f, xs) abort
|
||||
if len(a:xs) == 0
|
||||
throw 'vital: Data.List: foldr1'
|
||||
endif
|
||||
return s:foldr(a:f, a:xs[-1], a:xs[0:-2])
|
||||
endfunction
|
||||
|
||||
" similar to python's zip()
|
||||
function! s:zip(...) abort
|
||||
return map(range(min(map(copy(a:000), 'len(v:val)'))), "map(copy(a:000), 'v:val['.v:val.']')")
|
||||
endfunction
|
||||
|
||||
" similar to zip(), but goes until the longer one.
|
||||
function! s:zip_fill(xs, ys, filler) abort
|
||||
if empty(a:xs) && empty(a:ys)
|
||||
return []
|
||||
elseif empty(a:ys)
|
||||
return s:cons([a:xs[0], a:filler], s:zip_fill(a:xs[1 :], [], a:filler))
|
||||
elseif empty(a:xs)
|
||||
return s:cons([a:filler, a:ys[0]], s:zip_fill([], a:ys[1 :], a:filler))
|
||||
else
|
||||
return s:cons([a:xs[0], a:ys[0]], s:zip_fill(a:xs[1 :], a:ys[1: ], a:filler))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Inspired by Ruby's with_index method.
|
||||
function! s:with_index(list, ...) abort
|
||||
let base = a:0 > 0 ? a:1 : 0
|
||||
return map(copy(a:list), '[v:val, v:key + base]')
|
||||
endfunction
|
||||
|
||||
" similar to Ruby's detect or Haskell's find.
|
||||
function! s:find(list, default, f) abort
|
||||
let l:Call = type(a:f) is type(function('function'))
|
||||
\ ? function('call')
|
||||
\ : function('s:_call_string_expr')
|
||||
|
||||
for x in a:list
|
||||
if l:Call(a:f, [x])
|
||||
return x
|
||||
endif
|
||||
endfor
|
||||
return a:default
|
||||
endfunction
|
||||
|
||||
function! s:_call_string_expr(expr, args) abort
|
||||
return map([a:args[0]], a:expr)[0]
|
||||
endfunction
|
||||
|
||||
" Returns the index of the first element which satisfies the given expr.
|
||||
function! s:find_index(xs, f, ...) abort
|
||||
let len = len(a:xs)
|
||||
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0
|
||||
let default = a:0 > 1 ? a:2 : -1
|
||||
if start >=# len || start < 0
|
||||
return default
|
||||
endif
|
||||
for i in range(start, len - 1)
|
||||
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
|
||||
return i
|
||||
endif
|
||||
endfor
|
||||
return default
|
||||
endfunction
|
||||
|
||||
" Returns the index of the last element which satisfies the given expr.
|
||||
function! s:find_last_index(xs, f, ...) abort
|
||||
let len = len(a:xs)
|
||||
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : len - 1
|
||||
let default = a:0 > 1 ? a:2 : -1
|
||||
if start >=# len || start < 0
|
||||
return default
|
||||
endif
|
||||
for i in range(start, 0, -1)
|
||||
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
|
||||
return i
|
||||
endif
|
||||
endfor
|
||||
return default
|
||||
endfunction
|
||||
|
||||
" Similar to find_index but returns the list of indices satisfying the given expr.
|
||||
function! s:find_indices(xs, f, ...) abort
|
||||
let len = len(a:xs)
|
||||
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0
|
||||
let result = []
|
||||
if start >=# len || start < 0
|
||||
return result
|
||||
endif
|
||||
for i in range(start, len - 1)
|
||||
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
|
||||
call add(result, i)
|
||||
endif
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
" Return non-zero if a:list1 and a:list2 have any common item(s).
|
||||
" Return zero otherwise.
|
||||
function! s:has_common_items(list1, list2) abort
|
||||
return !empty(filter(copy(a:list1), 'index(a:list2, v:val) isnot -1'))
|
||||
endfunction
|
||||
|
||||
function! s:intersect(list1, list2) abort
|
||||
let items = []
|
||||
" for funcref
|
||||
for X in a:list1
|
||||
if index(a:list2, X) != -1 && index(items, X) == -1
|
||||
let items += [X]
|
||||
endif
|
||||
endfor
|
||||
return items
|
||||
endfunction
|
||||
|
||||
" similar to Ruby's group_by.
|
||||
function! s:group_by(xs, f) abort
|
||||
let result = {}
|
||||
let list = map(copy(a:xs), printf('[v:val, %s]', a:f))
|
||||
for x in list
|
||||
let Val = x[0]
|
||||
let key = type(x[1]) !=# type('') ? string(x[1]) : x[1]
|
||||
if has_key(result, key)
|
||||
call add(result[key], Val)
|
||||
else
|
||||
let result[key] = [Val]
|
||||
endif
|
||||
unlet Val
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
function! s:_default_compare(a, b) abort
|
||||
return a:a <# a:b ? -1 : a:a ># a:b ? 1 : 0
|
||||
endfunction
|
||||
|
||||
function! s:binary_search(list, value, ...) abort
|
||||
let Predicate = a:0 >= 1 ? a:1 : 's:_default_compare'
|
||||
let dic = a:0 >= 2 ? a:2 : {}
|
||||
let start = 0
|
||||
let end = len(a:list) - 1
|
||||
|
||||
while 1
|
||||
if start > end
|
||||
return -1
|
||||
endif
|
||||
|
||||
let middle = (start + end) / 2
|
||||
|
||||
let compared = call(Predicate, [a:value, a:list[middle]], dic)
|
||||
|
||||
if compared < 0
|
||||
let end = middle - 1
|
||||
elseif compared > 0
|
||||
let start = middle + 1
|
||||
else
|
||||
return middle
|
||||
endif
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
function! s:product(lists) abort
|
||||
let result = [[]]
|
||||
for pool in a:lists
|
||||
let tmp = []
|
||||
for x in result
|
||||
let tmp += map(copy(pool), 'x + [v:val]')
|
||||
endfor
|
||||
let result = tmp
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
function! s:permutations(list, ...) abort
|
||||
if a:0 > 1
|
||||
throw 'vital: Data.List: too many arguments'
|
||||
endif
|
||||
let r = a:0 == 1 ? a:1 : len(a:list)
|
||||
if r > len(a:list)
|
||||
return []
|
||||
elseif r < 0
|
||||
throw 'vital: Data.List: {r} must be non-negative integer'
|
||||
endif
|
||||
let n = len(a:list)
|
||||
let result = []
|
||||
for indices in s:product(map(range(r), 'range(n)'))
|
||||
if len(s:uniq(indices)) == r
|
||||
call add(result, map(indices, 'a:list[v:val]'))
|
||||
endif
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
function! s:combinations(list, r) abort
|
||||
if a:r > len(a:list)
|
||||
return []
|
||||
elseif a:r < 0
|
||||
throw 'vital: Data.List: {r} must be non-negative integer'
|
||||
endif
|
||||
let n = len(a:list)
|
||||
let result = []
|
||||
for indices in s:permutations(range(n), a:r)
|
||||
if s:sort(copy(indices), 'a:a - a:b') == indices
|
||||
call add(result, map(indices, 'a:list[v:val]'))
|
||||
endif
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim:set et ts=2 sts=2 sw=2 tw=0:
|
@ -0,0 +1,628 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#Data#String#import() abort', printf("return map({'starts_with': '', 'split3': '', 'replace_first': '', 'chop': '', 'unescape': '', 'split_posix_text': '', 'replace': '', 'scan': '', 'strwidthpart': '', 'common_head': '', 'reverse': '', 'escape_pattern': '', 'trim_end': '', '_vital_depends': '', 'wrap': '', 'join_posix_lines': '', 'contains_multibyte': '', 'truncate_skipping': '', 'split_leftright': '', 'ends_with': '', 'nsplit': '', 'strwidthpart_reverse': '', 'unescape_pattern': '', 'levenshtein_distance': '', 'trim_start': '', 'justify_equal_spacing': '', 'nr2hex': '', 'iconv': '', 'pad_left': '', 'nr2enc_char': '', 'lines': '', 'repair_posix_text': '', 'nr2byte': '', 'trim': '', 'diffidx': '', 'truncate': '', 'split_by_displaywidth': '', '_vital_created': '', 'padding_by_displaywidth': '', 'hash': '', 'chomp': '', 'pad_between_letters': '', 'dstring': '', 'pad_both_sides': '', 'substitute_last': '', 'pad_right': '', 'remove_ansi_sequences': '', '_vital_loaded': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
" Utilities for string.
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:V = a:V
|
||||
let s:L = s:V.import('Data.List')
|
||||
endfunction
|
||||
|
||||
function! s:_vital_depends() abort
|
||||
return ['Data.List']
|
||||
endfunction
|
||||
|
||||
function! s:_vital_created(module) abort
|
||||
" Expose script-local funcref
|
||||
if exists('s:strchars')
|
||||
let a:module.strchars = s:strchars
|
||||
endif
|
||||
if exists('s:wcswidth')
|
||||
let a:module.wcswidth = s:wcswidth
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Substitute a:from => a:to by string.
|
||||
" To substitute by pattern, use substitute() instead.
|
||||
function! s:replace(str, from, to) abort
|
||||
return s:_replace(a:str, a:from, a:to, 'g')
|
||||
endfunction
|
||||
|
||||
" Substitute a:from => a:to only once.
|
||||
" cf. s:replace()
|
||||
function! s:replace_first(str, from, to) abort
|
||||
return s:_replace(a:str, a:from, a:to, '')
|
||||
endfunction
|
||||
|
||||
" implement of replace() and replace_first()
|
||||
function! s:_replace(str, from, to, flags) abort
|
||||
return substitute(a:str, '\V'.escape(a:from, '\'), escape(a:to, '\'), a:flags)
|
||||
endfunction
|
||||
|
||||
function! s:scan(str, pattern) abort
|
||||
let list = []
|
||||
call substitute(a:str, a:pattern, '\=add(list, submatch(0)) == [] ? "" : ""', 'g')
|
||||
return list
|
||||
endfunction
|
||||
|
||||
function! s:reverse(str) abort
|
||||
return join(reverse(split(a:str, '.\zs')), '')
|
||||
endfunction
|
||||
|
||||
function! s:starts_with(str, prefix) abort
|
||||
return stridx(a:str, a:prefix) == 0
|
||||
endfunction
|
||||
|
||||
function! s:ends_with(str, suffix) abort
|
||||
let idx = strridx(a:str, a:suffix)
|
||||
return 0 <= idx && idx + len(a:suffix) == len(a:str)
|
||||
endfunction
|
||||
|
||||
function! s:common_head(strs) abort
|
||||
if empty(a:strs)
|
||||
return ''
|
||||
endif
|
||||
let len = len(a:strs)
|
||||
if len == 1
|
||||
return a:strs[0]
|
||||
endif
|
||||
let strs = len == 2 ? a:strs : sort(copy(a:strs))
|
||||
let pat = substitute(strs[0], '.', '\="[" . escape(submatch(0), "^\\") . "]"', 'g')
|
||||
return pat ==# '' ? '' : matchstr(strs[-1], '\C^\%[' . pat . ']')
|
||||
endfunction
|
||||
|
||||
" Split to two elements of List. ([left, right])
|
||||
" e.g.: s:split3('neocomplcache', 'compl') returns ['neo', 'compl', 'cache']
|
||||
function! s:split_leftright(expr, pattern) abort
|
||||
let [left, _, right] = s:split3(a:expr, a:pattern)
|
||||
return [left, right]
|
||||
endfunction
|
||||
|
||||
function! s:split3(expr, pattern) abort
|
||||
let ERROR = ['', '', '']
|
||||
if a:expr ==# '' || a:pattern ==# ''
|
||||
return ERROR
|
||||
endif
|
||||
let begin = match(a:expr, a:pattern)
|
||||
if begin is -1
|
||||
return ERROR
|
||||
endif
|
||||
let end = matchend(a:expr, a:pattern)
|
||||
let left = begin <=# 0 ? '' : a:expr[: begin - 1]
|
||||
let right = a:expr[end :]
|
||||
return [left, a:expr[begin : end-1], right]
|
||||
endfunction
|
||||
|
||||
" Slices into strings determines the number of substrings.
|
||||
" e.g.: s:nsplit("neo compl cache", 2, '\s') returns ['neo', 'compl cache']
|
||||
function! s:nsplit(expr, n, ...) abort
|
||||
let pattern = get(a:000, 0, '\s')
|
||||
let keepempty = get(a:000, 1, 1)
|
||||
let ret = []
|
||||
let expr = a:expr
|
||||
if a:n <= 1
|
||||
return [expr]
|
||||
endif
|
||||
while 1
|
||||
let pos = match(expr, pattern)
|
||||
if pos == -1
|
||||
if expr !~ pattern || keepempty
|
||||
call add(ret, expr)
|
||||
endif
|
||||
break
|
||||
elseif pos >= 0
|
||||
let left = pos > 0 ? expr[:pos-1] : ''
|
||||
if pos > 0 || keepempty
|
||||
call add(ret, left)
|
||||
endif
|
||||
let ml = len(matchstr(expr, pattern))
|
||||
if pos == 0 && ml == 0
|
||||
let pos = 1
|
||||
endif
|
||||
let expr = expr[pos+ml :]
|
||||
endif
|
||||
if len(expr) == 0
|
||||
break
|
||||
endif
|
||||
if len(ret) == a:n - 1
|
||||
call add(ret, expr)
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
return ret
|
||||
endfunction
|
||||
|
||||
" Returns the number of character in a:str.
|
||||
" NOTE: This returns proper value
|
||||
" even if a:str contains multibyte character(s).
|
||||
" s:strchars(str) {{{
|
||||
if exists('*strchars')
|
||||
let s:strchars = function('strchars')
|
||||
else
|
||||
function! s:strchars(str) abort
|
||||
return strlen(substitute(copy(a:str), '.', 'x', 'g'))
|
||||
endfunction
|
||||
endif "}}}
|
||||
|
||||
" Returns the bool of contains any multibyte character in s:str
|
||||
function! s:contains_multibyte(str) abort "{{{
|
||||
return strlen(a:str) != s:strchars(a:str)
|
||||
endfunction "}}}
|
||||
|
||||
" Remove last character from a:str.
|
||||
" NOTE: This returns proper value
|
||||
" even if a:str contains multibyte character(s).
|
||||
function! s:chop(str) abort "{{{
|
||||
return substitute(a:str, '.$', '', '')
|
||||
endfunction "}}}
|
||||
|
||||
" Remove last \r,\n,\r\n from a:str.
|
||||
function! s:chomp(str) abort "{{{
|
||||
return substitute(a:str, '\%(\r\n\|[\r\n]\)$', '', '')
|
||||
endfunction "}}}
|
||||
|
||||
" wrap() and its internal functions
|
||||
" * _split_by_wcswidth_once()
|
||||
" * _split_by_wcswidth()
|
||||
" * _concat()
|
||||
" * wrap()
|
||||
"
|
||||
" NOTE _concat() is just a copy of Data.List.concat().
|
||||
" FIXME don't repeat yourself
|
||||
function! s:_split_by_wcswidth_once(body, x) abort
|
||||
let fst = s:strwidthpart(a:body, a:x)
|
||||
let snd = s:strwidthpart_reverse(a:body, s:wcswidth(a:body) - s:wcswidth(fst))
|
||||
return [fst, snd]
|
||||
endfunction
|
||||
|
||||
function! s:_split_by_wcswidth(body, x) abort
|
||||
let memo = []
|
||||
let body = a:body
|
||||
while s:wcswidth(body) > a:x
|
||||
let [tmp, body] = s:_split_by_wcswidth_once(body, a:x)
|
||||
call add(memo, tmp)
|
||||
endwhile
|
||||
call add(memo, body)
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
function! s:trim(str) abort
|
||||
return substitute(a:str,'\%#=1^[[:space:]]\+\|[[:space:]]\+$', '', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:trim_start(str) abort
|
||||
return substitute(a:str,'\%#=1^[[:space:]]\+', '', '')
|
||||
endfunction
|
||||
|
||||
function! s:trim_end(str) abort
|
||||
let i = match(a:str, '\%#=2[[:space:]]*$')
|
||||
return i is# 0 ? '' : a:str[: i-1]
|
||||
endfunction
|
||||
|
||||
function! s:wrap(str,...) abort
|
||||
let _columns = a:0 > 0 ? a:1 : &columns
|
||||
return s:L.concat(
|
||||
\ map(split(a:str, '\r\n\|[\r\n]'), 's:_split_by_wcswidth(v:val, _columns - 1)'))
|
||||
endfunction
|
||||
|
||||
function! s:nr2byte(nr) abort
|
||||
if a:nr < 0x80
|
||||
return nr2char(a:nr)
|
||||
elseif a:nr < 0x800
|
||||
return nr2char(a:nr/64+192).nr2char(a:nr%64+128)
|
||||
else
|
||||
return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:nr2enc_char(charcode) abort
|
||||
if &encoding ==# 'utf-8'
|
||||
return nr2char(a:charcode)
|
||||
endif
|
||||
let char = s:nr2byte(a:charcode)
|
||||
if strlen(char) > 1
|
||||
let char = strtrans(iconv(char, 'utf-8', &encoding))
|
||||
endif
|
||||
return char
|
||||
endfunction
|
||||
|
||||
function! s:nr2hex(nr) abort
|
||||
let n = a:nr
|
||||
let r = ''
|
||||
while n
|
||||
let r = '0123456789ABCDEF'[n % 16] . r
|
||||
let n = n / 16
|
||||
endwhile
|
||||
return r
|
||||
endfunction
|
||||
|
||||
" If a ==# b, returns -1.
|
||||
" If a !=# b, returns first index of different character.
|
||||
function! s:diffidx(a, b) abort
|
||||
return a:a ==# a:b ? -1 : strlen(s:common_head([a:a, a:b]))
|
||||
endfunction
|
||||
|
||||
function! s:substitute_last(expr, pat, sub) abort
|
||||
return substitute(a:expr, printf('.*\zs%s', a:pat), a:sub, '')
|
||||
endfunction
|
||||
|
||||
function! s:dstring(expr) abort
|
||||
let x = substitute(string(a:expr), "^'\\|'$", '', 'g')
|
||||
let x = substitute(x, "''", "'", 'g')
|
||||
return printf('"%s"', escape(x, '"'))
|
||||
endfunction
|
||||
|
||||
function! s:lines(str) abort
|
||||
return split(a:str, '\r\?\n')
|
||||
endfunction
|
||||
|
||||
function! s:_pad_with_char(str, left, right, char) abort
|
||||
return repeat(a:char, a:left). a:str. repeat(a:char, a:right)
|
||||
endfunction
|
||||
|
||||
function! s:pad_left(str, width, ...) abort
|
||||
let char = get(a:, 1, ' ')
|
||||
if strdisplaywidth(char) != 1
|
||||
throw "vital: Data.String: Can't use non-half-width characters for padding."
|
||||
endif
|
||||
let left = max([0, a:width - strdisplaywidth(a:str)])
|
||||
return s:_pad_with_char(a:str, left, 0, char)
|
||||
endfunction
|
||||
|
||||
function! s:pad_right(str, width, ...) abort
|
||||
let char = get(a:, 1, ' ')
|
||||
if strdisplaywidth(char) != 1
|
||||
throw "vital: Data.String: Can't use non-half-width characters for padding."
|
||||
endif
|
||||
let right = max([0, a:width - strdisplaywidth(a:str)])
|
||||
return s:_pad_with_char(a:str, 0, right, char)
|
||||
endfunction
|
||||
|
||||
function! s:pad_both_sides(str, width, ...) abort
|
||||
let char = get(a:, 1, ' ')
|
||||
if strdisplaywidth(char) != 1
|
||||
throw "vital: Data.String: Can't use non-half-width characters for padding."
|
||||
endif
|
||||
let space = max([0, a:width - strdisplaywidth(a:str)])
|
||||
let left = space / 2
|
||||
let right = space - left
|
||||
return s:_pad_with_char(a:str, left, right, char)
|
||||
endfunction
|
||||
|
||||
function! s:pad_between_letters(str, width, ...) abort
|
||||
let char = get(a:, 1, ' ')
|
||||
if strdisplaywidth(char) != 1
|
||||
throw "vital: Data.String: Can't use non-half-width characters for padding."
|
||||
endif
|
||||
let letters = split(a:str, '\zs')
|
||||
let each_width = a:width / len(letters)
|
||||
let str = join(map(letters, 's:pad_both_sides(v:val, each_width, char)'), '')
|
||||
if a:width - strdisplaywidth(str) > 0
|
||||
return char. s:pad_both_sides(str, a:width - 1, char)
|
||||
endif
|
||||
return str
|
||||
endfunction
|
||||
|
||||
function! s:justify_equal_spacing(str, width, ...) abort
|
||||
let char = get(a:, 1, ' ')
|
||||
if strdisplaywidth(char) != 1
|
||||
throw "vital: Data.String: Can't use non-half-width characters for padding."
|
||||
endif
|
||||
let letters = split(a:str, '\zs')
|
||||
let first_letter = letters[0]
|
||||
" {width w/o the first letter} / {length w/o the first letter}
|
||||
let each_width = (a:width - strdisplaywidth(first_letter)) / (len(letters) - 1)
|
||||
let remainder = (a:width - strdisplaywidth(first_letter)) % (len(letters) - 1)
|
||||
return first_letter. join(s:L.concat([
|
||||
\ map(letters[1:remainder], 's:pad_left(v:val, each_width + 1, char)'),
|
||||
\ map(letters[remainder + 1:], 's:pad_left(v:val, each_width, char)')
|
||||
\ ]), '')
|
||||
endfunction
|
||||
|
||||
function! s:levenshtein_distance(str1, str2) abort
|
||||
let letters1 = split(a:str1, '\zs')
|
||||
let letters2 = split(a:str2, '\zs')
|
||||
let length1 = len(letters1)
|
||||
let length2 = len(letters2)
|
||||
let distances = map(range(1, length1 + 1), 'map(range(1, length2 + 1), ''0'')')
|
||||
|
||||
for i1 in range(0, length1)
|
||||
let distances[i1][0] = i1
|
||||
endfor
|
||||
for i2 in range(0, length2)
|
||||
let distances[0][i2] = i2
|
||||
endfor
|
||||
|
||||
for i1 in range(1, length1)
|
||||
for i2 in range(1, length2)
|
||||
let cost = (letters1[i1 - 1] ==# letters2[i2 - 1]) ? 0 : 1
|
||||
|
||||
let distances[i1][i2] = min([
|
||||
\ distances[i1 - 1][i2 ] + 1,
|
||||
\ distances[i1 ][i2 - 1] + 1,
|
||||
\ distances[i1 - 1][i2 - 1] + cost,
|
||||
\])
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return distances[length1][length2]
|
||||
endfunction
|
||||
|
||||
function! s:padding_by_displaywidth(expr, width, float) abort
|
||||
let padding_char = ' '
|
||||
let n = a:width - strdisplaywidth(a:expr)
|
||||
if n <= 0
|
||||
let n = 0
|
||||
endif
|
||||
if a:float < 0
|
||||
return a:expr . repeat(padding_char, n)
|
||||
elseif 0 < a:float
|
||||
return repeat(padding_char, n) . a:expr
|
||||
else
|
||||
if n % 2 is 0
|
||||
return repeat(padding_char, n / 2) . a:expr . repeat(padding_char, n / 2)
|
||||
else
|
||||
return repeat(padding_char, (n - 1) / 2) . a:expr . repeat(padding_char, (n - 1) / 2) . padding_char
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:split_by_displaywidth(expr, width, float, is_wrap) abort
|
||||
if a:width is 0
|
||||
return ['']
|
||||
endif
|
||||
|
||||
let lines = []
|
||||
|
||||
let cs = split(a:expr, '\zs')
|
||||
let cs_index = 0
|
||||
|
||||
let text = ''
|
||||
while cs_index < len(cs)
|
||||
if cs[cs_index] is# "\n"
|
||||
let text = s:padding_by_displaywidth(text, a:width, a:float)
|
||||
let lines += [text]
|
||||
let text = ''
|
||||
else
|
||||
let w = strdisplaywidth(text . cs[cs_index])
|
||||
|
||||
if w < a:width
|
||||
let text .= cs[cs_index]
|
||||
elseif a:width < w
|
||||
let text = s:padding_by_displaywidth(text, a:width, a:float)
|
||||
else
|
||||
let text .= cs[cs_index]
|
||||
endif
|
||||
|
||||
if a:width <= w
|
||||
let lines += [text]
|
||||
let text = ''
|
||||
if a:is_wrap
|
||||
if a:width < w
|
||||
if a:width < strdisplaywidth(cs[cs_index])
|
||||
while get(cs, cs_index, "\n") isnot# "\n"
|
||||
let cs_index += 1
|
||||
endwhile
|
||||
continue
|
||||
else
|
||||
let text = cs[cs_index]
|
||||
endif
|
||||
endif
|
||||
else
|
||||
while get(cs, cs_index, "\n") isnot# "\n"
|
||||
let cs_index += 1
|
||||
endwhile
|
||||
continue
|
||||
endif
|
||||
endif
|
||||
|
||||
endif
|
||||
let cs_index += 1
|
||||
endwhile
|
||||
|
||||
if !empty(text)
|
||||
let lines += [ s:padding_by_displaywidth(text, a:width, a:float) ]
|
||||
endif
|
||||
|
||||
return lines
|
||||
endfunction
|
||||
|
||||
function! s:hash(str) abort
|
||||
if exists('*sha256')
|
||||
return sha256(a:str)
|
||||
else
|
||||
" This gives up sha256ing but just adds up char with index.
|
||||
let sum = 0
|
||||
for i in range(len(a:str))
|
||||
let sum += char2nr(a:str[i]) * (i + 1)
|
||||
endfor
|
||||
|
||||
return printf('%x', sum)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:truncate(str, width) abort
|
||||
" Original function is from mattn.
|
||||
" http://github.com/mattn/googlereader-vim/tree/master
|
||||
|
||||
if a:str =~# '^[\x00-\x7f]*$'
|
||||
return len(a:str) < a:width
|
||||
\ ? printf('%-' . a:width . 's', a:str)
|
||||
\ : strpart(a:str, 0, a:width)
|
||||
endif
|
||||
|
||||
let ret = a:str
|
||||
let width = s:wcswidth(a:str)
|
||||
if width > a:width
|
||||
let ret = s:strwidthpart(ret, a:width)
|
||||
let width = s:wcswidth(ret)
|
||||
endif
|
||||
|
||||
if width < a:width
|
||||
let ret .= repeat(' ', a:width - width)
|
||||
endif
|
||||
|
||||
return ret
|
||||
endfunction
|
||||
|
||||
function! s:truncate_skipping(str, max, footer_width, separator) abort
|
||||
let width = s:wcswidth(a:str)
|
||||
if width <= a:max
|
||||
let ret = a:str
|
||||
else
|
||||
let header_width = a:max - s:wcswidth(a:separator) - a:footer_width
|
||||
let ret = s:strwidthpart(a:str, header_width) . a:separator
|
||||
\ . s:strwidthpart_reverse(a:str, a:footer_width)
|
||||
endif
|
||||
return s:truncate(ret, a:max)
|
||||
endfunction
|
||||
|
||||
function! s:strwidthpart(str, width) abort
|
||||
let str = tr(a:str, "\t", ' ')
|
||||
let vcol = a:width + 2
|
||||
return matchstr(str, '.*\%<' . (vcol < 0 ? 0 : vcol) . 'v')
|
||||
endfunction
|
||||
|
||||
function! s:strwidthpart_reverse(str, width) abort
|
||||
let str = tr(a:str, "\t", ' ')
|
||||
let vcol = s:wcswidth(str) - a:width
|
||||
return matchstr(str, '\%>' . (vcol < 0 ? 0 : vcol) . 'v.*')
|
||||
endfunction
|
||||
|
||||
if v:version >= 703
|
||||
" Use builtin function.
|
||||
let s:wcswidth = function('strwidth')
|
||||
else
|
||||
function! s:wcswidth(str) abort
|
||||
if a:str =~# '^[\x00-\x7f]*$'
|
||||
return strlen(a:str)
|
||||
endif
|
||||
let mx_first = '^\(.\)'
|
||||
let str = a:str
|
||||
let width = 0
|
||||
while 1
|
||||
let ucs = char2nr(substitute(str, mx_first, '\1', ''))
|
||||
if ucs == 0
|
||||
break
|
||||
endif
|
||||
let width += s:_wcwidth(ucs)
|
||||
let str = substitute(str, mx_first, '', '')
|
||||
endwhile
|
||||
return width
|
||||
endfunction
|
||||
|
||||
" UTF-8 only.
|
||||
function! s:_wcwidth(ucs) abort
|
||||
let ucs = a:ucs
|
||||
if (ucs >= 0x1100
|
||||
\ && (ucs <= 0x115f
|
||||
\ || ucs == 0x2329
|
||||
\ || ucs == 0x232a
|
||||
\ || (ucs >= 0x2e80 && ucs <= 0xa4cf
|
||||
\ && ucs != 0x303f)
|
||||
\ || (ucs >= 0xac00 && ucs <= 0xd7a3)
|
||||
\ || (ucs >= 0xf900 && ucs <= 0xfaff)
|
||||
\ || (ucs >= 0xfe30 && ucs <= 0xfe6f)
|
||||
\ || (ucs >= 0xff00 && ucs <= 0xff60)
|
||||
\ || (ucs >= 0xffe0 && ucs <= 0xffe6)
|
||||
\ || (ucs >= 0x20000 && ucs <= 0x2fffd)
|
||||
\ || (ucs >= 0x30000 && ucs <= 0x3fffd)
|
||||
\ ))
|
||||
return 2
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! s:remove_ansi_sequences(text) abort
|
||||
return substitute(a:text, '\e\[\%(\%(\d\+;\)*\d\+\)\?[mK]', '', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:escape_pattern(str) abort
|
||||
" escape characters for no-magic
|
||||
return escape(a:str, '^$~.*[]\')
|
||||
endfunction
|
||||
|
||||
function! s:unescape_pattern(str) abort
|
||||
" unescape characters for no-magic
|
||||
return s:unescape(a:str, '^$~.*[]\')
|
||||
endfunction
|
||||
|
||||
function! s:unescape(str, chars) abort
|
||||
let chars = map(split(a:chars, '\zs'), 'escape(v:val, ''^$~.*[]\'')')
|
||||
return substitute(a:str, '\\\(' . join(chars, '\|') . '\)', '\1', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:iconv(expr, from, to) abort
|
||||
if a:from ==# '' || a:to ==# '' || a:from ==? a:to
|
||||
return a:expr
|
||||
endif
|
||||
let result = iconv(a:expr, a:from, a:to)
|
||||
return empty(result) ? a:expr : result
|
||||
endfunction
|
||||
|
||||
" NOTE:
|
||||
" A definition of a TEXT file is "A file that contains characters organized
|
||||
" into one or more lines."
|
||||
" A definition of a LINE is "A sequence of zero or more non- <newline>s
|
||||
" plus a terminating <newline>"
|
||||
" That's why {stdin} always ends with <newline> ideally. However, there are
|
||||
" some programs which does not follow the POSIX rule and a Vim's way to join
|
||||
" List into TEXT; join({text}, "\n"); does not add <newline> to the end of
|
||||
" the last line.
|
||||
" That's why add a trailing <newline> if it does not exist.
|
||||
" REF:
|
||||
" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_392
|
||||
" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_205
|
||||
" :help split()
|
||||
" NOTE:
|
||||
" it does nothing if the text is a correct POSIX text
|
||||
function! s:repair_posix_text(text, ...) abort
|
||||
let newline = get(a:000, 0, "\n")
|
||||
return a:text =~# '\n$' ? a:text : a:text . newline
|
||||
endfunction
|
||||
|
||||
" NOTE:
|
||||
" A definition of a TEXT file is "A file that contains characters organized
|
||||
" into one or more lines."
|
||||
" A definition of a LINE is "A sequence of zero or more non- <newline>s
|
||||
" plus a terminating <newline>"
|
||||
" REF:
|
||||
" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_392
|
||||
" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_205
|
||||
function! s:join_posix_lines(lines, ...) abort
|
||||
let newline = get(a:000, 0, "\n")
|
||||
return join(a:lines, newline) . newline
|
||||
endfunction
|
||||
|
||||
" NOTE:
|
||||
" A definition of a TEXT file is "A file that contains characters organized
|
||||
" into one or more lines."
|
||||
" A definition of a LINE is "A sequence of zero or more non- <newline>s
|
||||
" plus a terminating <newline>"
|
||||
" TEXT into List; split({text}, '\r\?\n', 1); add an extra empty line at the
|
||||
" end of List because the end of TEXT ends with <newline> and keepempty=1 is
|
||||
" specified. (btw. keepempty=0 cannot be used because it will remove
|
||||
" emptylines in the head and the tail).
|
||||
" That's why removing a trailing <newline> before proceeding to 'split' is required
|
||||
" REF:
|
||||
" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_392
|
||||
" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_205
|
||||
function! s:split_posix_text(text, ...) abort
|
||||
let newline = get(a:000, 0, '\r\?\n')
|
||||
let text = substitute(a:text, newline . '$', '', '')
|
||||
return split(text, newline, 1)
|
||||
endfunction
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
" vim:set et ts=2 sts=2 sw=2 tw=0:
|
@ -0,0 +1,424 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#Prelude#import() abort', printf("return map({'escape_pattern': '', 'is_funcref': '', 'path2directory': '', 'wcswidth': '', 'is_string': '', 'input_helper': '', 'is_number': '', 'is_cygwin': '', 'path2project_directory': '', 'strwidthpart_reverse': '', 'input_safe': '', 'is_list': '', 'truncate_skipping': '', 'glob': '', 'truncate': '', 'is_dict': '', 'set_default': '', 'is_numeric': '', 'getchar_safe': '', 'substitute_path_separator': '', 'is_mac': '', 'strwidthpart': '', 'getchar': '', 'is_unix': '', 'is_windows': '', 'globpath': '', 'escape_file_searching': '', 'is_float': '', 'smart_execute_command': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
if v:version > 703 ||
|
||||
\ (v:version == 703 && has('patch465'))
|
||||
function! s:glob(expr) abort
|
||||
return glob(a:expr, 1, 1)
|
||||
endfunction
|
||||
else
|
||||
function! s:glob(expr) abort
|
||||
return split(glob(a:expr, 1), '\n')
|
||||
endfunction
|
||||
endif
|
||||
|
||||
if v:version > 704 ||
|
||||
\ (v:version == 704 && has('patch279'))
|
||||
function! s:globpath(path, expr) abort
|
||||
return globpath(a:path, a:expr, 1, 1)
|
||||
endfunction
|
||||
else
|
||||
function! s:globpath(path, expr) abort
|
||||
return split(globpath(a:path, a:expr, 1), '\n')
|
||||
endfunction
|
||||
endif
|
||||
|
||||
" Wrapper functions for type().
|
||||
" NOTE: __TYPE_FLOAT = -1 when -float.
|
||||
" this doesn't match to anything.
|
||||
if has('patch-7.4.2071')
|
||||
let [
|
||||
\ s:__TYPE_NUMBER,
|
||||
\ s:__TYPE_STRING,
|
||||
\ s:__TYPE_FUNCREF,
|
||||
\ s:__TYPE_LIST,
|
||||
\ s:__TYPE_DICT,
|
||||
\ s:__TYPE_FLOAT] = [
|
||||
\ v:t_number,
|
||||
\ v:t_string,
|
||||
\ v:t_func,
|
||||
\ v:t_list,
|
||||
\ v:t_dict,
|
||||
\ v:t_float]
|
||||
else
|
||||
let [
|
||||
\ s:__TYPE_NUMBER,
|
||||
\ s:__TYPE_STRING,
|
||||
\ s:__TYPE_FUNCREF,
|
||||
\ s:__TYPE_LIST,
|
||||
\ s:__TYPE_DICT,
|
||||
\ s:__TYPE_FLOAT] = [
|
||||
\ type(3),
|
||||
\ type(''),
|
||||
\ type(function('tr')),
|
||||
\ type([]),
|
||||
\ type({}),
|
||||
\ has('float') ? type(str2float('0')) : -1]
|
||||
endif
|
||||
|
||||
" Number or Float
|
||||
function! s:is_numeric(Value) abort
|
||||
let _ = type(a:Value)
|
||||
return _ ==# s:__TYPE_NUMBER
|
||||
\ || _ ==# s:__TYPE_FLOAT
|
||||
endfunction
|
||||
|
||||
" Number
|
||||
function! s:is_number(Value) abort
|
||||
return type(a:Value) ==# s:__TYPE_NUMBER
|
||||
endfunction
|
||||
|
||||
" String
|
||||
function! s:is_string(Value) abort
|
||||
return type(a:Value) ==# s:__TYPE_STRING
|
||||
endfunction
|
||||
|
||||
" Funcref
|
||||
function! s:is_funcref(Value) abort
|
||||
return type(a:Value) ==# s:__TYPE_FUNCREF
|
||||
endfunction
|
||||
|
||||
" List
|
||||
function! s:is_list(Value) abort
|
||||
return type(a:Value) ==# s:__TYPE_LIST
|
||||
endfunction
|
||||
|
||||
" Dictionary
|
||||
function! s:is_dict(Value) abort
|
||||
return type(a:Value) ==# s:__TYPE_DICT
|
||||
endfunction
|
||||
|
||||
" Float
|
||||
function! s:is_float(Value) abort
|
||||
return type(a:Value) ==# s:__TYPE_FLOAT
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:truncate_skipping(str, max, footer_width, separator) abort
|
||||
call s:_warn_deprecated('truncate_skipping', 'Data.String.truncate_skipping')
|
||||
|
||||
let width = s:wcswidth(a:str)
|
||||
if width <= a:max
|
||||
let ret = a:str
|
||||
else
|
||||
let header_width = a:max - s:wcswidth(a:separator) - a:footer_width
|
||||
let ret = s:strwidthpart(a:str, header_width) . a:separator
|
||||
\ . s:strwidthpart_reverse(a:str, a:footer_width)
|
||||
endif
|
||||
|
||||
return s:truncate(ret, a:max)
|
||||
endfunction
|
||||
|
||||
function! s:truncate(str, width) abort
|
||||
" Original function is from mattn.
|
||||
" http://github.com/mattn/googlereader-vim/tree/master
|
||||
|
||||
call s:_warn_deprecated('truncate', 'Data.String.truncate')
|
||||
|
||||
if a:str =~# '^[\x00-\x7f]*$'
|
||||
return len(a:str) < a:width ?
|
||||
\ printf('%-'.a:width.'s', a:str) : strpart(a:str, 0, a:width)
|
||||
endif
|
||||
|
||||
let ret = a:str
|
||||
let width = s:wcswidth(a:str)
|
||||
if width > a:width
|
||||
let ret = s:strwidthpart(ret, a:width)
|
||||
let width = s:wcswidth(ret)
|
||||
endif
|
||||
|
||||
if width < a:width
|
||||
let ret .= repeat(' ', a:width - width)
|
||||
endif
|
||||
|
||||
return ret
|
||||
endfunction
|
||||
|
||||
function! s:strwidthpart(str, width) abort
|
||||
call s:_warn_deprecated('strwidthpart', 'Data.String.strwidthpart')
|
||||
|
||||
if a:width <= 0
|
||||
return ''
|
||||
endif
|
||||
let ret = a:str
|
||||
let width = s:wcswidth(a:str)
|
||||
while width > a:width
|
||||
let char = matchstr(ret, '.$')
|
||||
let ret = ret[: -1 - len(char)]
|
||||
let width -= s:wcswidth(char)
|
||||
endwhile
|
||||
|
||||
return ret
|
||||
endfunction
|
||||
function! s:strwidthpart_reverse(str, width) abort
|
||||
call s:_warn_deprecated('strwidthpart_reverse', 'Data.String.strwidthpart_reverse')
|
||||
|
||||
if a:width <= 0
|
||||
return ''
|
||||
endif
|
||||
let ret = a:str
|
||||
let width = s:wcswidth(a:str)
|
||||
while width > a:width
|
||||
let char = matchstr(ret, '^.')
|
||||
let ret = ret[len(char) :]
|
||||
let width -= s:wcswidth(char)
|
||||
endwhile
|
||||
|
||||
return ret
|
||||
endfunction
|
||||
|
||||
if v:version >= 703
|
||||
" Use builtin function.
|
||||
function! s:wcswidth(str) abort
|
||||
call s:_warn_deprecated('wcswidth', 'Data.String.wcswidth')
|
||||
return strwidth(a:str)
|
||||
endfunction
|
||||
else
|
||||
function! s:wcswidth(str) abort
|
||||
call s:_warn_deprecated('wcswidth', 'Data.String.wcswidth')
|
||||
|
||||
if a:str =~# '^[\x00-\x7f]*$'
|
||||
return strlen(a:str)
|
||||
end
|
||||
|
||||
let mx_first = '^\(.\)'
|
||||
let str = a:str
|
||||
let width = 0
|
||||
while 1
|
||||
let ucs = char2nr(substitute(str, mx_first, '\1', ''))
|
||||
if ucs == 0
|
||||
break
|
||||
endif
|
||||
let width += s:_wcwidth(ucs)
|
||||
let str = substitute(str, mx_first, '', '')
|
||||
endwhile
|
||||
return width
|
||||
endfunction
|
||||
|
||||
" UTF-8 only.
|
||||
function! s:_wcwidth(ucs) abort
|
||||
let ucs = a:ucs
|
||||
if (ucs >= 0x1100
|
||||
\ && (ucs <= 0x115f
|
||||
\ || ucs == 0x2329
|
||||
\ || ucs == 0x232a
|
||||
\ || (ucs >= 0x2e80 && ucs <= 0xa4cf
|
||||
\ && ucs != 0x303f)
|
||||
\ || (ucs >= 0xac00 && ucs <= 0xd7a3)
|
||||
\ || (ucs >= 0xf900 && ucs <= 0xfaff)
|
||||
\ || (ucs >= 0xfe30 && ucs <= 0xfe6f)
|
||||
\ || (ucs >= 0xff00 && ucs <= 0xff60)
|
||||
\ || (ucs >= 0xffe0 && ucs <= 0xffe6)
|
||||
\ || (ucs >= 0x20000 && ucs <= 0x2fffd)
|
||||
\ || (ucs >= 0x30000 && ucs <= 0x3fffd)
|
||||
\ ))
|
||||
return 2
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
endif
|
||||
|
||||
let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95')
|
||||
let s:is_cygwin = has('win32unix')
|
||||
let s:is_mac = !s:is_windows && !s:is_cygwin
|
||||
\ && (has('mac') || has('macunix') || has('gui_macvim') ||
|
||||
\ (!isdirectory('/proc') && executable('sw_vers')))
|
||||
let s:is_unix = has('unix')
|
||||
|
||||
function! s:is_windows() abort
|
||||
return s:is_windows
|
||||
endfunction
|
||||
|
||||
function! s:is_cygwin() abort
|
||||
return s:is_cygwin
|
||||
endfunction
|
||||
|
||||
function! s:is_mac() abort
|
||||
return s:is_mac
|
||||
endfunction
|
||||
|
||||
function! s:is_unix() abort
|
||||
return s:is_unix
|
||||
endfunction
|
||||
|
||||
function! s:_warn_deprecated(name, alternative) abort
|
||||
try
|
||||
echohl Error
|
||||
echomsg 'Prelude.' . a:name . ' is deprecated! Please use ' . a:alternative . ' instead.'
|
||||
finally
|
||||
echohl None
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:smart_execute_command(action, word) abort
|
||||
execute a:action . ' ' . (a:word ==# '' ? '' : '`=a:word`')
|
||||
endfunction
|
||||
|
||||
function! s:escape_file_searching(buffer_name) abort
|
||||
return escape(a:buffer_name, '*[]?{}, ')
|
||||
endfunction
|
||||
|
||||
function! s:escape_pattern(str) abort
|
||||
call s:_warn_deprecated(
|
||||
\ 'escape_pattern',
|
||||
\ 'Data.String.escape_pattern',
|
||||
\)
|
||||
return escape(a:str, '~"\.^$[]*')
|
||||
endfunction
|
||||
|
||||
function! s:getchar(...) abort
|
||||
let c = call('getchar', a:000)
|
||||
return type(c) == type(0) ? nr2char(c) : c
|
||||
endfunction
|
||||
|
||||
function! s:getchar_safe(...) abort
|
||||
let c = s:input_helper('getchar', a:000)
|
||||
return type(c) == type('') ? c : nr2char(c)
|
||||
endfunction
|
||||
|
||||
function! s:input_safe(...) abort
|
||||
return s:input_helper('input', a:000)
|
||||
endfunction
|
||||
|
||||
function! s:input_helper(funcname, args) abort
|
||||
let success = 0
|
||||
if inputsave() !=# success
|
||||
throw 'vital: Prelude: inputsave() failed'
|
||||
endif
|
||||
try
|
||||
return call(a:funcname, a:args)
|
||||
finally
|
||||
if inputrestore() !=# success
|
||||
throw 'vital: Prelude: inputrestore() failed'
|
||||
endif
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:set_default(var, val) abort
|
||||
if !exists(a:var) || type({a:var}) != type(a:val)
|
||||
let {a:var} = a:val
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:substitute_path_separator(path) abort
|
||||
return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path
|
||||
endfunction
|
||||
|
||||
function! s:path2directory(path) abort
|
||||
return s:substitute_path_separator(isdirectory(a:path) ? a:path : fnamemodify(a:path, ':p:h'))
|
||||
endfunction
|
||||
|
||||
function! s:_path2project_directory_git(path) abort
|
||||
let parent = a:path
|
||||
|
||||
while 1
|
||||
let path = parent . '/.git'
|
||||
if isdirectory(path) || filereadable(path)
|
||||
return parent
|
||||
endif
|
||||
let next = fnamemodify(parent, ':h')
|
||||
if next == parent
|
||||
return ''
|
||||
endif
|
||||
let parent = next
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
function! s:_path2project_directory_svn(path) abort
|
||||
let search_directory = a:path
|
||||
let directory = ''
|
||||
|
||||
let find_directory = s:escape_file_searching(search_directory)
|
||||
let d = finddir('.svn', find_directory . ';')
|
||||
if d ==# ''
|
||||
return ''
|
||||
endif
|
||||
|
||||
let directory = fnamemodify(d, ':p:h:h')
|
||||
|
||||
" Search parent directories.
|
||||
let parent_directory = s:path2directory(
|
||||
\ fnamemodify(directory, ':h'))
|
||||
|
||||
if parent_directory !=# ''
|
||||
let d = finddir('.svn', parent_directory . ';')
|
||||
if d !=# ''
|
||||
let directory = s:_path2project_directory_svn(parent_directory)
|
||||
endif
|
||||
endif
|
||||
return directory
|
||||
endfunction
|
||||
|
||||
function! s:_path2project_directory_others(vcs, path) abort
|
||||
let vcs = a:vcs
|
||||
let search_directory = a:path
|
||||
|
||||
let find_directory = s:escape_file_searching(search_directory)
|
||||
let d = finddir(vcs, find_directory . ';')
|
||||
if d ==# ''
|
||||
return ''
|
||||
endif
|
||||
return fnamemodify(d, ':p:h:h')
|
||||
endfunction
|
||||
|
||||
function! s:path2project_directory(path, ...) abort
|
||||
let is_allow_empty = get(a:000, 0, 0)
|
||||
let search_directory = s:path2directory(a:path)
|
||||
let directory = ''
|
||||
|
||||
" Search VCS directory.
|
||||
for vcs in ['.git', '.bzr', '.hg', '.svn']
|
||||
if vcs ==# '.git'
|
||||
let directory = s:_path2project_directory_git(search_directory)
|
||||
elseif vcs ==# '.svn'
|
||||
let directory = s:_path2project_directory_svn(search_directory)
|
||||
else
|
||||
let directory = s:_path2project_directory_others(vcs, search_directory)
|
||||
endif
|
||||
if directory !=# ''
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Search project file.
|
||||
if directory ==# ''
|
||||
for d in ['build.xml', 'prj.el', '.project', 'pom.xml', 'package.json',
|
||||
\ 'Makefile', 'configure', 'Rakefile', 'NAnt.build',
|
||||
\ 'P4CONFIG', 'tags', 'gtags']
|
||||
let d = findfile(d, s:escape_file_searching(search_directory) . ';')
|
||||
if d !=# ''
|
||||
let directory = fnamemodify(d, ':p:h')
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
if directory ==# ''
|
||||
" Search /src/ directory.
|
||||
let base = s:substitute_path_separator(search_directory)
|
||||
if base =~# '/src/'
|
||||
let directory = base[: strridx(base, '/src/') + 3]
|
||||
endif
|
||||
endif
|
||||
|
||||
if directory ==# '' && !is_allow_empty
|
||||
" Use original path.
|
||||
let directory = search_directory
|
||||
endif
|
||||
|
||||
return s:substitute_path_separator(directory)
|
||||
endfunction
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim:set et ts=2 sts=2 sw=2 tw=0:
|
@ -0,0 +1,61 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#System#Job#import() abort', printf("return map({'_vital_depends': '', '_vital_healthcheck': '', 'is_available': '', 'start': '', '_vital_loaded': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:t_string = type('')
|
||||
let s:t_list = type([])
|
||||
|
||||
function! s:_vital_loaded(V) abort
|
||||
if has('nvim')
|
||||
let s:Job = a:V.import('System.Job.Neovim')
|
||||
else
|
||||
let s:Job = a:V.import('System.Job.Vim')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:_vital_depends() abort
|
||||
return [
|
||||
\ 'System.Job.Vim',
|
||||
\ 'System.Job.Neovim',
|
||||
\]
|
||||
endfunction
|
||||
|
||||
function! s:_vital_healthcheck() abort
|
||||
if has('patch-8.0.0027') || has('nvim-0.2.0')
|
||||
return
|
||||
endif
|
||||
return 'This module requires Vim 8.0.0027 or Neovim 0.2.0'
|
||||
endfunction
|
||||
|
||||
|
||||
" Note:
|
||||
" Vim does not raise E902 on Unix system even the prog is not found so use a
|
||||
" custom exception instead to make the method compatible.
|
||||
" Note:
|
||||
" Vim/Neovim treat String a bit differently so prohibit String as well
|
||||
function! s:_validate_args(args) abort
|
||||
if type(a:args) != s:t_list
|
||||
throw 'vital: System.Job: Argument requires to be a List instance.'
|
||||
endif
|
||||
if len(a:args) == 0
|
||||
throw 'vital: System.Job: Argument vector must have at least one item.'
|
||||
endif
|
||||
let prog = a:args[0]
|
||||
if !executable(prog)
|
||||
throw printf('vital: System.Job: "%s" is not an executable', prog)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:is_available() abort
|
||||
return s:Job.is_available()
|
||||
endfunction
|
||||
|
||||
function! s:start(args, ...) abort
|
||||
call s:_validate_args(a:args)
|
||||
return s:Job.start(a:args, a:0 ? a:1 : {})
|
||||
endfunction
|
@ -0,0 +1,119 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#System#Job#Neovim#import() abort', printf("return map({'is_available': '', 'start': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
" http://vim-jp.org/blog/2016/03/23/take-care-of-patch-1577.html
|
||||
function! s:is_available() abort
|
||||
return has('nvim') && has('nvim-0.2.0')
|
||||
endfunction
|
||||
|
||||
function! s:start(args, options) abort
|
||||
let job = extend(copy(s:job), a:options)
|
||||
let job_options = {}
|
||||
if has_key(job, 'on_stdout')
|
||||
let job_options.on_stdout = function('s:_on_stdout', [job])
|
||||
endif
|
||||
if has_key(job, 'on_stderr')
|
||||
let job_options.on_stderr = function('s:_on_stderr', [job])
|
||||
endif
|
||||
if has_key(job, 'on_exit')
|
||||
let job_options.on_exit = function('s:_on_exit', [job])
|
||||
else
|
||||
let job_options.on_exit = function('s:_on_exit_raw', [job])
|
||||
endif
|
||||
let job.__job = jobstart(a:args, job_options)
|
||||
let job.__exitval = v:null
|
||||
let job.args = a:args
|
||||
return job
|
||||
endfunction
|
||||
|
||||
function! s:_on_stdout(job, job_id, data, event) abort
|
||||
call a:job.on_stdout(a:data)
|
||||
endfunction
|
||||
|
||||
function! s:_on_stderr(job, job_id, data, event) abort
|
||||
call a:job.on_stderr(a:data)
|
||||
endfunction
|
||||
|
||||
function! s:_on_exit(job, job_id, exitval, event) abort
|
||||
let a:job.__exitval = a:exitval
|
||||
call a:job.on_exit(a:exitval)
|
||||
endfunction
|
||||
|
||||
function! s:_on_exit_raw(job, job_id, exitval, event) abort
|
||||
let a:job.__exitval = a:exitval
|
||||
endfunction
|
||||
|
||||
" Instance -------------------------------------------------------------------
|
||||
function! s:_job_id() abort dict
|
||||
return self.__job
|
||||
endfunction
|
||||
|
||||
function! s:_job_status() abort dict
|
||||
try
|
||||
call jobpid(self.__job)
|
||||
return 'run'
|
||||
catch /^Vim\%((\a\+)\)\=:E900/
|
||||
return 'dead'
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
if exists('*chansend') " Neovim 0.2.3
|
||||
function! s:_job_send(data) abort dict
|
||||
return chansend(self.__job, a:data)
|
||||
endfunction
|
||||
else
|
||||
function! s:_job_send(data) abort dict
|
||||
return jobsend(self.__job, a:data)
|
||||
endfunction
|
||||
endif
|
||||
|
||||
if exists('*chanclose') " Neovim 0.2.3
|
||||
function! s:_job_close() abort dict
|
||||
call chanclose(self.__job, 'stdin')
|
||||
endfunction
|
||||
else
|
||||
function! s:_job_close() abort dict
|
||||
call jobclose(self.__job, 'stdin')
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! s:_job_stop() abort dict
|
||||
try
|
||||
call jobstop(self.__job)
|
||||
catch /^Vim\%((\a\+)\)\=:E900/
|
||||
" NOTE:
|
||||
" Vim does not raise exception even the job has already closed so fail
|
||||
" silently for 'E900: Invalid job id' exception
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:_job_wait(...) abort dict
|
||||
let timeout = a:0 ? a:1 : v:null
|
||||
let exitval = timeout is# v:null
|
||||
\ ? jobwait([self.__job])[0]
|
||||
\ : jobwait([self.__job], timeout)[0]
|
||||
if exitval != -3
|
||||
return exitval
|
||||
endif
|
||||
" Wait until 'on_exit' callback is called
|
||||
while self.__exitval is# v:null
|
||||
sleep 1m
|
||||
endwhile
|
||||
return self.__exitval
|
||||
endfunction
|
||||
|
||||
" To make debug easier, use funcref instead.
|
||||
let s:job = {
|
||||
\ 'id': function('s:_job_id'),
|
||||
\ 'status': function('s:_job_status'),
|
||||
\ 'send': function('s:_job_send'),
|
||||
\ 'close': function('s:_job_close'),
|
||||
\ 'stop': function('s:_job_stop'),
|
||||
\ 'wait': function('s:_job_wait'),
|
||||
\}
|
@ -0,0 +1,143 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#System#Job#Vim#import() abort', printf("return map({'is_available': '', 'start': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
" https://github.com/neovim/neovim/blob/f629f83/src/nvim/event/process.c#L24-L26
|
||||
let s:KILL_TIMEOUT_MS = 2000
|
||||
|
||||
function! s:is_available() abort
|
||||
return !has('nvim') && has('patch-8.0.0027')
|
||||
endfunction
|
||||
|
||||
function! s:start(args, options) abort
|
||||
let job = extend(copy(s:job), a:options)
|
||||
let job_options = {
|
||||
\ 'mode': 'raw',
|
||||
\ 'timeout': 0,
|
||||
\}
|
||||
if has_key(job, 'on_stdout')
|
||||
let job_options.out_cb = function('s:_out_cb', [job])
|
||||
else
|
||||
let job_options.out_io = 'null'
|
||||
endif
|
||||
if has_key(job, 'on_stderr')
|
||||
let job_options.err_cb = function('s:_err_cb', [job])
|
||||
else
|
||||
let job_options.err_io = 'null'
|
||||
endif
|
||||
if has_key(job, 'on_stdout') || has_key(job, 'on_stderr')
|
||||
let job_options.close_cb = function('s:_close_cb', [job])
|
||||
endif
|
||||
if has_key(job, 'on_exit')
|
||||
let job_options.exit_cb = function('s:_exit_cb', [job])
|
||||
endif
|
||||
let job.__job = job_start(a:args, job_options)
|
||||
let job.__closed = v:false
|
||||
let job.args = a:args
|
||||
return job
|
||||
endfunction
|
||||
|
||||
function! s:_out_cb(job, channel, msg) abort
|
||||
call a:job.on_stdout(split(a:msg, "\n", 1))
|
||||
endfunction
|
||||
|
||||
function! s:_err_cb(job, channel, msg) abort
|
||||
call a:job.on_stderr(split(a:msg, "\n", 1))
|
||||
endfunction
|
||||
|
||||
function! s:_close_cb(job, channel) abort
|
||||
let a:job.__closed = v:true
|
||||
if has_key(a:job, 'on_stdout')
|
||||
let options = {'part': 'out'}
|
||||
while ch_status(a:channel, options) ==# 'buffered'
|
||||
call s:_out_cb(a:job, a:channel, ch_readraw(a:channel, options))
|
||||
endwhile
|
||||
endif
|
||||
if has_key(a:job, 'on_stderr')
|
||||
let options = {'part': 'err'}
|
||||
while ch_status(a:channel, options) ==# 'buffered'
|
||||
call s:_err_cb(a:job, a:channel, ch_readraw(a:channel, options))
|
||||
endwhile
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:_exit_cb(job, channel, exitval) abort
|
||||
" Make sure on_stdout/on_stderr are called prior to on_exit.
|
||||
" This check requires 'close_cb' so perform only when on_stdout/on_stderr
|
||||
" is defined in a job instance.
|
||||
if has_key(a:job, 'on_stdout') || has_key(a:job, 'on_stderr')
|
||||
while !a:job.__closed
|
||||
sleep 1m
|
||||
endwhile
|
||||
endif
|
||||
call a:job.on_exit(a:exitval)
|
||||
endfunction
|
||||
|
||||
|
||||
" Instance -------------------------------------------------------------------
|
||||
function! s:_job_id() abort dict
|
||||
return job_info(self.__job).process
|
||||
endfunction
|
||||
|
||||
" NOTE:
|
||||
" On Unix a non-existing command results in "dead" instead
|
||||
" So returns "dead" instead of "fail" even in non Unix.
|
||||
function! s:_job_status() abort dict
|
||||
let status = job_status(self.__job)
|
||||
return status ==# 'fail' ? 'dead' : status
|
||||
endfunction
|
||||
|
||||
" NOTE:
|
||||
" A Null character (\0) is used as a terminator of a string in Vim.
|
||||
" Neovim can send \0 by using \n splitted list but in Vim.
|
||||
" So replace all \n in \n splitted list to ''
|
||||
function! s:_job_send(data) abort dict
|
||||
let data = type(a:data) == v:t_list
|
||||
\ ? join(map(a:data, 'substitute(v:val, "\n", '''', ''g'')'), "\n")
|
||||
\ : a:data
|
||||
return ch_sendraw(self.__job, data)
|
||||
endfunction
|
||||
|
||||
function! s:_job_close() abort dict
|
||||
call ch_close_in(self.__job)
|
||||
endfunction
|
||||
|
||||
function! s:_job_stop() abort dict
|
||||
call job_stop(self.__job)
|
||||
call timer_start(s:KILL_TIMEOUT_MS, { -> job_stop(self.__job, 'kill') })
|
||||
endfunction
|
||||
|
||||
function! s:_job_wait(...) abort dict
|
||||
let timeout = a:0 ? a:1 : v:null
|
||||
let timeout = timeout is# v:null ? v:null : timeout / 1000.0
|
||||
let start_time = reltime()
|
||||
let job = self.__job
|
||||
try
|
||||
while timeout is# v:null || timeout > reltimefloat(reltime(start_time))
|
||||
let status = job_status(job)
|
||||
if status !=# 'run'
|
||||
return status ==# 'dead' ? job_info(job).exitval : -3
|
||||
endif
|
||||
sleep 1m
|
||||
endwhile
|
||||
catch /^Vim:Interrupt$/
|
||||
call self.stop()
|
||||
return -2
|
||||
endtry
|
||||
return -1
|
||||
endfunction
|
||||
|
||||
" To make debug easier, use funcref instead.
|
||||
let s:job = {
|
||||
\ 'id': function('s:_job_id'),
|
||||
\ 'status': function('s:_job_status'),
|
||||
\ 'send': function('s:_job_send'),
|
||||
\ 'close': function('s:_job_close'),
|
||||
\ 'stop': function('s:_job_stop'),
|
||||
\ 'wait': function('s:_job_wait'),
|
||||
\}
|
@ -0,0 +1,96 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#System#Process#import() abort', printf("return map({'_vital_depends': '', 'execute': '', 'register': '', '_vital_loaded': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:save_cpoptions = &cpoptions
|
||||
set cpoptions&vim
|
||||
|
||||
let s:registry = {}
|
||||
let s:priority = []
|
||||
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:V = a:V
|
||||
let s:Prelude = a:V.import('Prelude')
|
||||
let s:String = a:V.import('Data.String')
|
||||
call s:register('System.Process.Vimproc')
|
||||
call s:register('System.Process.System')
|
||||
endfunction
|
||||
|
||||
function! s:_vital_depends() abort
|
||||
return [
|
||||
\ 'Prelude',
|
||||
\ 'Data.String',
|
||||
\ 'System.Process.System',
|
||||
\ 'System.Process.Vimproc',
|
||||
\]
|
||||
endfunction
|
||||
|
||||
function! s:_throw(msg) abort
|
||||
throw printf('vital: System.Process: %s', a:msg)
|
||||
endfunction
|
||||
|
||||
function! s:register(name) abort
|
||||
let client = s:V.import(a:name)
|
||||
if client.is_available()
|
||||
let s:registry[a:name] = client
|
||||
call add(s:priority, a:name)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:_execute(args, options) abort
|
||||
for name_or_client in a:options.clients
|
||||
let client = s:Prelude.is_string(name_or_client)
|
||||
\ ? s:registry[name_or_client]
|
||||
\ : name_or_client
|
||||
if !client.is_supported(a:options)
|
||||
continue
|
||||
endif
|
||||
return client.execute(a:args, a:options)
|
||||
endfor
|
||||
call s:_throw(printf(
|
||||
\ 'None of client support options : %s',
|
||||
\ string(a:options),
|
||||
\))
|
||||
endfunction
|
||||
|
||||
" execute({args}[, {options}])
|
||||
function! s:execute(args, ...) abort
|
||||
let options = extend({
|
||||
\ 'clients': s:priority,
|
||||
\ 'input': 0,
|
||||
\ 'timeout': 0,
|
||||
\ 'background': 0,
|
||||
\ 'encode_input': 1,
|
||||
\ 'encode_output': 1,
|
||||
\ 'split_output': 1,
|
||||
\ 'debug': &verbose,
|
||||
\}, get(a:000, 0, {}))
|
||||
if s:Prelude.is_string(options.input) && !empty(options.encode_input)
|
||||
let encoding = s:Prelude.is_string(options.encode_input)
|
||||
\ ? options.encode_input
|
||||
\ : &encoding
|
||||
let options.input = s:String.iconv(options.input, encoding, 'char')
|
||||
endif
|
||||
let result = s:_execute(a:args, options)
|
||||
if s:Prelude.is_string(result.output) && !empty(options.encode_output)
|
||||
let encoding = s:Prelude.is_string(options.encode_output)
|
||||
\ ? options.encode_output
|
||||
\ : &encoding
|
||||
let result.output = s:String.iconv(result.output, 'char', encoding)
|
||||
endif
|
||||
if options.split_output
|
||||
let result.content = s:String.split_posix_text(result.output)
|
||||
endif
|
||||
let result.success = result.status == 0
|
||||
let result.args = a:args
|
||||
let result.options = options
|
||||
return result
|
||||
endfunction
|
||||
|
||||
let &cpoptions = s:save_cpoptions
|
||||
unlet s:save_cpoptions
|
@ -0,0 +1,128 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#System#Process#System#import() abort', printf("return map({'_vital_depends': '', 'shellescape': '', 'execute': '', 'is_supported': '', 'is_available': '', '_vital_loaded': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:save_cpoptions = &cpoptions
|
||||
set cpoptions&vim
|
||||
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:Prelude = a:V.import('Prelude')
|
||||
let s:String = a:V.import('Data.String')
|
||||
let s:Guard = a:V.import('Vim.Guard')
|
||||
endfunction
|
||||
|
||||
function! s:_vital_depends() abort
|
||||
return [
|
||||
\ 'Prelude',
|
||||
\ 'Data.String',
|
||||
\ 'Vim.Guard',
|
||||
\]
|
||||
endfunction
|
||||
|
||||
function! s:is_available() abort
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:is_supported(options) abort
|
||||
if get(a:options, 'timeout')
|
||||
return 0
|
||||
elseif get(a:options, 'background') && s:Prelude.is_windows()
|
||||
return 0
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:shellescape(string) abort
|
||||
if s:Prelude.is_windows()
|
||||
" NOTE:
|
||||
" In windows, a string which does not contain space SHOULD NOT be escaped
|
||||
return a:string =~# '\s' ? shellescape(a:string) : a:string
|
||||
else
|
||||
return shellescape(a:string)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:execute(args, options) abort
|
||||
" NOTE:
|
||||
" execute() is a command for executing program WITHOUT using shell.
|
||||
" so mimic that behaviour with shell
|
||||
let guard = s:Guard.store(filter([
|
||||
\ '&shell',
|
||||
\ '&shellcmdflag',
|
||||
\ '&shellquote',
|
||||
\ '&shellredir',
|
||||
\ '&shelltemp',
|
||||
\ (exists('+shelltype') ? '&shelltype' : ''),
|
||||
\ (exists('+shellxescape') ? '&shellxescape' : ''),
|
||||
\ (exists('+shellxquote') ? '&shellxquote' : ''),
|
||||
\ (exists('+shellslash') ? '&shellslash' : ''),
|
||||
\], '!empty(v:val)')
|
||||
\)
|
||||
try
|
||||
" Reset shell related options
|
||||
if s:Prelude.is_windows()
|
||||
set shell&
|
||||
if exists('+shellslash')
|
||||
set shellslash&
|
||||
endif
|
||||
else
|
||||
set shell=sh
|
||||
endif
|
||||
set shellcmdflag& shellquote& shellredir& shelltemp&
|
||||
if exists('+shelltype')
|
||||
set shelltype&
|
||||
endif
|
||||
if exists('+shellxescape')
|
||||
set shellxescape&
|
||||
endif
|
||||
if exists('+shellxquote')
|
||||
set shellxquote&
|
||||
endif
|
||||
let cmdline = join(map(
|
||||
\ copy(a:args),
|
||||
\ 's:shellescape(v:val)',
|
||||
\))
|
||||
if a:options.background && !s:Prelude.is_windows()
|
||||
let cmdline = cmdline . ' &'
|
||||
endif
|
||||
if a:options.debug > 0
|
||||
echomsg printf(
|
||||
\ 'vital: System.Process.System: %s',
|
||||
\ cmdline
|
||||
\)
|
||||
endif
|
||||
if v:version < 704 || (v:version == 704 && !has('patch122'))
|
||||
" {cmdline} of system() before Vim 7.4.122 is not converted so convert
|
||||
" it manually from &encoding to 'char'
|
||||
let cmdline = s:String.iconv(cmdline, &encoding, 'char')
|
||||
endif
|
||||
let args = [cmdline] + (s:Prelude.is_string(a:options.input) ? [a:options.input] : [])
|
||||
let output = call('system', args)
|
||||
if s:Prelude.is_windows()
|
||||
" A builtin system() add a trailing space in Windows.
|
||||
" It is probably an issue of pipe in Windows so remove it.
|
||||
let output = substitute(output, '\s\n$', '\n', '')
|
||||
endif
|
||||
" NOTE:
|
||||
" Vim 7.4 always return exit_status:0 for background process so mimic
|
||||
let status = a:options.background ? 0 : v:shell_error
|
||||
" NOTE:
|
||||
" status, output are COMMON information
|
||||
" cmdline is an EXTRA information
|
||||
return {
|
||||
\ 'status': status,
|
||||
\ 'output': output,
|
||||
\ 'cmdline': cmdline,
|
||||
\}
|
||||
finally
|
||||
call guard.restore()
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
let &cpoptions = s:save_cpoptions
|
||||
unlet s:save_cpoptions
|
@ -0,0 +1,82 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#System#Process#Vimproc#import() abort', printf("return map({'_vital_depends': '', 'execute': '', 'is_supported': '', 'is_available': '', '_vital_loaded': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:save_cpoptions = &cpoptions
|
||||
set cpoptions&vim
|
||||
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:Prelude = a:V.import('Prelude')
|
||||
endfunction
|
||||
|
||||
function! s:_vital_depends() abort
|
||||
return [
|
||||
\ 'Prelude',
|
||||
\]
|
||||
endfunction
|
||||
|
||||
function! s:is_available() abort
|
||||
if exists('s:vimproc_available')
|
||||
return s:vimproc_available
|
||||
endif
|
||||
try
|
||||
call vimproc#version()
|
||||
let s:vimproc_available = 1
|
||||
catch
|
||||
let s:vimproc_available = 0
|
||||
endtry
|
||||
return s:vimproc_available
|
||||
endfunction
|
||||
|
||||
function! s:is_supported(options) abort
|
||||
if get(a:options, 'background') && (
|
||||
\ s:Prelude.is_string(get(a:options, 'input')) ||
|
||||
\ get(a:options, 'timeout')
|
||||
\)
|
||||
return 0
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:execute(args, options) abort
|
||||
let cmdline = join(map(
|
||||
\ copy(a:args),
|
||||
\ 'vimproc#shellescape(v:val)',
|
||||
\))
|
||||
if a:options.debug > 0
|
||||
echomsg printf(
|
||||
\ 'vital: System.Process.Vimproc: %s',
|
||||
\ cmdline
|
||||
\)
|
||||
endif
|
||||
if a:options.background
|
||||
let output = vimproc#system_bg(cmdline)
|
||||
" NOTE:
|
||||
" background process via Builtin always return exit_code:0 so mimic
|
||||
let status = 0
|
||||
else
|
||||
let output = vimproc#system(
|
||||
\ cmdline,
|
||||
\ s:Prelude.is_string(a:options.input) ? a:options.input : '',
|
||||
\ a:options.timeout,
|
||||
\)
|
||||
let status = vimproc#get_last_status()
|
||||
endif
|
||||
" NOTE:
|
||||
" status, output are COMMON information
|
||||
" errormsg, cmdline are EXTRA information
|
||||
return {
|
||||
\ 'status': status,
|
||||
\ 'output': output,
|
||||
\ 'errormsg': vimproc#get_last_errmsg(),
|
||||
\ 'cmdline': cmdline,
|
||||
\}
|
||||
endfunction
|
||||
|
||||
let &cpoptions = s:save_cpoptions
|
||||
unlet s:save_cpoptions
|
@ -0,0 +1,234 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#Vim#Guard#import() abort', printf("return map({'_vital_depends': '', '_vital_created': '', 'store': '', '_vital_loaded': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" Use a Funcref as a special term _UNDEFINED
|
||||
function! s:_undefined() abort
|
||||
return 'undefined'
|
||||
endfunction
|
||||
let s:_UNDEFINED = function('s:_undefined')
|
||||
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:V = a:V
|
||||
let s:Prelude = s:V.import('Prelude')
|
||||
let s:List = s:V.import('Data.List')
|
||||
let s:Dict = s:V.import('Data.Dict')
|
||||
endfunction
|
||||
function! s:_vital_depends() abort
|
||||
return ['Prelude', 'Data.List', 'Data.Dict']
|
||||
endfunction
|
||||
function! s:_vital_created(module) abort
|
||||
" define constant variables
|
||||
if !exists('s:const')
|
||||
let s:const = {}
|
||||
let s:const.is_local_variable_supported =
|
||||
\ v:version > 703 || (v:version == 703 && has('patch560'))
|
||||
" NOTE:
|
||||
" The third argument is available from 7.4.242 but it had bug and that
|
||||
" bug was fixed from 7.4.513
|
||||
let s:const.is_third_argument_of_getreg_supported = has('patch-7.4.513')
|
||||
lockvar s:const
|
||||
endif
|
||||
call extend(a:module, s:const)
|
||||
endfunction
|
||||
function! s:_throw(msg) abort
|
||||
throw printf('vital: Vim.Guard: %s', a:msg)
|
||||
endfunction
|
||||
|
||||
let s:option = {}
|
||||
function! s:_new_option(name) abort
|
||||
if a:name !~# '^&'
|
||||
call s:_throw(printf(
|
||||
\'An option name "%s" requires to be started from "&"', a:name
|
||||
\))
|
||||
elseif !exists(a:name)
|
||||
call s:_throw(printf(
|
||||
\'An option name "%s" does not exist', a:name
|
||||
\))
|
||||
endif
|
||||
let option = copy(s:option)
|
||||
let option.name = a:name
|
||||
let option.value = eval(a:name)
|
||||
return option
|
||||
endfunction
|
||||
function! s:option.restore() abort
|
||||
execute printf('let %s = %s', self.name, string(self.value))
|
||||
endfunction
|
||||
|
||||
let s:register = {}
|
||||
function! s:_new_register(name) abort
|
||||
if len(a:name) != 2
|
||||
call s:_throw(printf(
|
||||
\'A register name "%s" requires to be "@" + a single character', a:name
|
||||
\))
|
||||
elseif a:name !~# '^@'
|
||||
call s:_throw(printf(
|
||||
\'A register name "%s" requires to be started from "@"', a:name
|
||||
\))
|
||||
elseif a:name =~# '^@[:.%]$'
|
||||
call s:_throw(printf(
|
||||
\'A register name "%s" is read only', a:name
|
||||
\))
|
||||
elseif a:name !~# '^@[@0-9a-zA-Z#=*+~_/-]$'
|
||||
call s:_throw(printf(
|
||||
\'A register name "%s" does not exist. See ":help let-register"', a:name
|
||||
\))
|
||||
endif
|
||||
let name = a:name ==# '@@' ? '' : a:name[1]
|
||||
let register = copy(s:register)
|
||||
let register.name = name
|
||||
if s:const.is_third_argument_of_getreg_supported
|
||||
let register.value = getreg(name, 1, 1)
|
||||
else
|
||||
let register.value = getreg(name, 1)
|
||||
endif
|
||||
let register.type = getregtype(name)
|
||||
return register
|
||||
endfunction
|
||||
function! s:register.restore() abort
|
||||
" https://github.com/vim/vim/commit/5a50c2255c447838d08d3b4895a3be3a41cd8eda
|
||||
if has('patch-7.4.243') || self.name !=# '='
|
||||
call setreg(self.name, self.value, self.type)
|
||||
else
|
||||
let @= = self.value
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:environment = {}
|
||||
function! s:_new_environment(name) abort
|
||||
if a:name !~# '^\$'
|
||||
call s:_throw(printf(
|
||||
\'An environment variable name "%s" requires to be started from "$"', a:name
|
||||
\))
|
||||
elseif !exists(a:name)
|
||||
call s:_throw(printf(
|
||||
\'An environment variable name "%s" does not exist. While Vim cannot unlet environment variable, it requires to exist', a:name
|
||||
\))
|
||||
endif
|
||||
let environment = copy(s:environment)
|
||||
let environment.name = a:name
|
||||
let environment.value = eval(a:name)
|
||||
return environment
|
||||
endfunction
|
||||
function! s:environment.restore() abort
|
||||
execute printf('let %s = %s', self.name, string(self.value))
|
||||
endfunction
|
||||
|
||||
let s:variable = {}
|
||||
function! s:_new_variable(name, ...) abort
|
||||
if a:0 == 0
|
||||
let m = matchlist(a:name, '^\([bwtg]:\)\(.*\)$')
|
||||
if empty(m)
|
||||
call s:_throw(printf(
|
||||
\ join([
|
||||
\ 'An variable name "%s" requires to start from b:, w:, t:, or g:',
|
||||
\ 'while no {namespace} is specified',
|
||||
\ ]),
|
||||
\ a:name,
|
||||
\))
|
||||
endif
|
||||
let [prefix, name] = m[1 : 2]
|
||||
let namespace = eval(prefix)
|
||||
else
|
||||
let name = a:name
|
||||
let namespace = a:1
|
||||
endif
|
||||
let variable = copy(s:variable)
|
||||
let variable.name = name
|
||||
let variable.value = get(namespace, name, s:_UNDEFINED)
|
||||
let variable.value =
|
||||
\ type(variable.value) == type({}) || type(variable.value) == type([])
|
||||
\ ? deepcopy(variable.value)
|
||||
\ : variable.value
|
||||
let variable._namespace = namespace
|
||||
return variable
|
||||
endfunction
|
||||
function! s:variable.restore() abort
|
||||
" unlet the variable to prevent variable type mis-match in case
|
||||
silent! unlet! self._namespace[self.name]
|
||||
if type(self.value) == type(s:_UNDEFINED) && self.value == s:_UNDEFINED
|
||||
" do nothing, leave the variable as undefined
|
||||
else
|
||||
let self._namespace[self.name] = self.value
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:instance = {}
|
||||
function! s:_new_instance(instance, ...) abort
|
||||
let shallow = get(a:000, 0, 0)
|
||||
if !s:Prelude.is_list(a:instance) && !s:Prelude.is_dict(a:instance)
|
||||
call s:_throw(printf(
|
||||
\'An instance "%s" requires to be List or Dictionary', string(a:instance)
|
||||
\))
|
||||
endif
|
||||
let instance = copy(s:instance)
|
||||
let instance.instance = a:instance
|
||||
let instance.values = shallow ? copy(a:instance) : deepcopy(a:instance)
|
||||
return instance
|
||||
endfunction
|
||||
function! s:instance.restore() abort
|
||||
if s:Prelude.is_list(self.instance)
|
||||
call s:List.clear(self.instance)
|
||||
else
|
||||
call s:Dict.clear(self.instance)
|
||||
endif
|
||||
call extend(self.instance, self.values)
|
||||
endfunction
|
||||
|
||||
let s:guard = {}
|
||||
function! s:store(targets) abort
|
||||
let resources = []
|
||||
for meta in a:targets
|
||||
if s:Prelude.is_list(meta)
|
||||
if len(meta) == 1
|
||||
call add(resources, s:_new_instance(meta[0]))
|
||||
elseif len(meta) == 2
|
||||
if s:Prelude.is_string(meta[0])
|
||||
call add(resources, call('s:_new_variable', meta))
|
||||
else
|
||||
call add(resources, call('s:_new_instance', meta))
|
||||
endif
|
||||
else
|
||||
call s:_throw('List assignment requires one or two elements')
|
||||
endif
|
||||
elseif type(meta) == type('')
|
||||
if meta =~# '^[bwtgls]:'
|
||||
" Note:
|
||||
" To improve an error message, handle l:XXX or s:XXX as well
|
||||
call add(resources, s:_new_variable(meta))
|
||||
elseif meta =~# '^&'
|
||||
call add(resources, s:_new_option(meta))
|
||||
elseif meta =~# '^@'
|
||||
call add(resources, s:_new_register(meta))
|
||||
elseif meta =~# '^\$'
|
||||
call add(resources, s:_new_environment(meta))
|
||||
else
|
||||
call s:_throw(printf(
|
||||
\ 'Unknown value "%s" was specified',
|
||||
\ meta
|
||||
\))
|
||||
endif
|
||||
endif
|
||||
unlet meta
|
||||
endfor
|
||||
let guard = copy(s:guard)
|
||||
let guard._resources = resources
|
||||
return guard
|
||||
endfunction
|
||||
function! s:guard.restore() abort
|
||||
for resource in self._resources
|
||||
call resource.restore()
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet! s:save_cpo
|
||||
" vim:set et ts=2 sts=2 sw=2 tw=0 fdm=marker:
|
@ -0,0 +1,92 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_plantuml_previewer#Vim#Type#import() abort', printf("return map({'is_comparable': '', '_vital_created': '', 'is_predicate': '', 'is_numeric': '', 'is_special': ''}, \"vital#_plantuml_previewer#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:types = {
|
||||
\ 'number': 0,
|
||||
\ 'string': 1,
|
||||
\ 'func': 2,
|
||||
\ 'list': 3,
|
||||
\ 'dict': 4,
|
||||
\ 'float': 5,
|
||||
\ 'bool': 6,
|
||||
\ 'none': 7,
|
||||
\ 'job': 8,
|
||||
\ 'channel': 9,
|
||||
\ }
|
||||
lockvar 1 s:types
|
||||
|
||||
let s:type_names = {
|
||||
\ '0': 'number',
|
||||
\ '1': 'string',
|
||||
\ '2': 'func',
|
||||
\ '3': 'list',
|
||||
\ '4': 'dict',
|
||||
\ '5': 'float',
|
||||
\ '6': 'bool',
|
||||
\ '7': 'none',
|
||||
\ '8': 'job',
|
||||
\ '9': 'channel',
|
||||
\ }
|
||||
lockvar 1 s:type_names
|
||||
|
||||
function! s:_vital_created(module) abort
|
||||
let a:module.types = s:types
|
||||
let a:module.type_names = s:type_names
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:is_numeric(value) abort
|
||||
let t = type(a:value)
|
||||
return t == s:types.number || t == s:types.float
|
||||
endfunction
|
||||
|
||||
function! s:is_special(value) abort
|
||||
let t = type(a:value)
|
||||
return t == s:types.bool || t == s:types.none
|
||||
endfunction
|
||||
|
||||
function! s:is_predicate(value) abort
|
||||
let t = type(a:value)
|
||||
return t == s:types.number || t == s:types.string ||
|
||||
\ t == s:types.bool || t == s:types.none
|
||||
endfunction
|
||||
|
||||
function! s:is_comparable(value1, value2) abort
|
||||
if !exists('s:is_comparable_cache')
|
||||
let s:is_comparable_cache = s:_make_is_comparable_cache()
|
||||
endif
|
||||
return s:is_comparable_cache[type(a:value1)][type(a:value2)]
|
||||
endfunction
|
||||
|
||||
function! s:_make_is_comparable_cache() abort
|
||||
let vals = [
|
||||
\ 0, '', function('type'), [], {}, 0.0,
|
||||
\ get(v:, 'false'),
|
||||
\ get(v:, 'null'),
|
||||
\ exists('*test_null_job') ? test_null_job() : 0,
|
||||
\ exists('*test_null_channel') ? test_null_channel() : 0,
|
||||
\ ]
|
||||
|
||||
let result = []
|
||||
for l:V1 in vals
|
||||
let result_V1 = []
|
||||
let result += [result_V1]
|
||||
for l:V2 in vals
|
||||
try
|
||||
let _ = V1 == V2
|
||||
let result_V1 += [1]
|
||||
catch
|
||||
let result_V1 += [0]
|
||||
endtry
|
||||
unlet V2
|
||||
endfor
|
||||
unlet V1
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
@ -0,0 +1,328 @@
|
||||
let s:plugin_name = expand('<sfile>:t:r')
|
||||
let s:vital_base_dir = expand('<sfile>:h')
|
||||
let s:project_root = expand('<sfile>:h:h:h')
|
||||
let s:is_vital_vim = s:plugin_name is# 'vital'
|
||||
|
||||
let s:loaded = {}
|
||||
let s:cache_sid = {}
|
||||
|
||||
" function() wrapper
|
||||
if v:version > 703 || v:version == 703 && has('patch1170')
|
||||
function! s:_function(fstr) abort
|
||||
return function(a:fstr)
|
||||
endfunction
|
||||
else
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
let s:_s = '<SNR>' . s:_SID() . '_'
|
||||
function! s:_function(fstr) abort
|
||||
return function(substitute(a:fstr, 's:', s:_s, 'g'))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! vital#{s:plugin_name}#new() abort
|
||||
return s:new(s:plugin_name)
|
||||
endfunction
|
||||
|
||||
function! vital#{s:plugin_name}#import(...) abort
|
||||
if !exists('s:V')
|
||||
let s:V = s:new(s:plugin_name)
|
||||
endif
|
||||
return call(s:V.import, a:000, s:V)
|
||||
endfunction
|
||||
|
||||
let s:Vital = {}
|
||||
|
||||
function! s:new(plugin_name) abort
|
||||
let base = deepcopy(s:Vital)
|
||||
let base._plugin_name = a:plugin_name
|
||||
return base
|
||||
endfunction
|
||||
|
||||
function! s:vital_files() abort
|
||||
if !exists('s:vital_files')
|
||||
let s:vital_files = map(
|
||||
\ s:is_vital_vim ? s:_global_vital_files() : s:_self_vital_files(),
|
||||
\ 'fnamemodify(v:val, ":p:gs?[\\\\/]?/?")')
|
||||
endif
|
||||
return copy(s:vital_files)
|
||||
endfunction
|
||||
let s:Vital.vital_files = s:_function('s:vital_files')
|
||||
|
||||
function! s:import(name, ...) abort dict
|
||||
let target = {}
|
||||
let functions = []
|
||||
for a in a:000
|
||||
if type(a) == type({})
|
||||
let target = a
|
||||
elseif type(a) == type([])
|
||||
let functions = a
|
||||
endif
|
||||
unlet a
|
||||
endfor
|
||||
let module = self._import(a:name)
|
||||
if empty(functions)
|
||||
call extend(target, module, 'keep')
|
||||
else
|
||||
for f in functions
|
||||
if has_key(module, f) && !has_key(target, f)
|
||||
let target[f] = module[f]
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
return target
|
||||
endfunction
|
||||
let s:Vital.import = s:_function('s:import')
|
||||
|
||||
function! s:load(...) abort dict
|
||||
for arg in a:000
|
||||
let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg]
|
||||
let target = split(join(as, ''), '\W\+')
|
||||
let dict = self
|
||||
let dict_type = type({})
|
||||
while !empty(target)
|
||||
let ns = remove(target, 0)
|
||||
if !has_key(dict, ns)
|
||||
let dict[ns] = {}
|
||||
endif
|
||||
if type(dict[ns]) == dict_type
|
||||
let dict = dict[ns]
|
||||
else
|
||||
unlet dict
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
if exists('dict')
|
||||
call extend(dict, self._import(name))
|
||||
endif
|
||||
unlet arg
|
||||
endfor
|
||||
return self
|
||||
endfunction
|
||||
let s:Vital.load = s:_function('s:load')
|
||||
|
||||
function! s:unload() abort dict
|
||||
let s:loaded = {}
|
||||
let s:cache_sid = {}
|
||||
unlet! s:vital_files
|
||||
endfunction
|
||||
let s:Vital.unload = s:_function('s:unload')
|
||||
|
||||
function! s:exists(name) abort dict
|
||||
if a:name !~# '\v^\u\w*%(\.\u\w*)*$'
|
||||
throw 'vital: Invalid module name: ' . a:name
|
||||
endif
|
||||
return s:_module_path(a:name) isnot# ''
|
||||
endfunction
|
||||
let s:Vital.exists = s:_function('s:exists')
|
||||
|
||||
function! s:search(pattern) abort dict
|
||||
let paths = s:_extract_files(a:pattern, self.vital_files())
|
||||
let modules = sort(map(paths, 's:_file2module(v:val)'))
|
||||
return s:_uniq(modules)
|
||||
endfunction
|
||||
let s:Vital.search = s:_function('s:search')
|
||||
|
||||
function! s:plugin_name() abort dict
|
||||
return self._plugin_name
|
||||
endfunction
|
||||
let s:Vital.plugin_name = s:_function('s:plugin_name')
|
||||
|
||||
function! s:_self_vital_files() abort
|
||||
let builtin = printf('%s/__%s__/', s:vital_base_dir, s:plugin_name)
|
||||
let installed = printf('%s/_%s/', s:vital_base_dir, s:plugin_name)
|
||||
let base = builtin . ',' . installed
|
||||
return split(globpath(base, '**/*.vim', 1), "\n")
|
||||
endfunction
|
||||
|
||||
function! s:_global_vital_files() abort
|
||||
let pattern = 'autoload/vital/__*__/**/*.vim'
|
||||
return split(globpath(&runtimepath, pattern, 1), "\n")
|
||||
endfunction
|
||||
|
||||
function! s:_extract_files(pattern, files) abort
|
||||
let tr = {'.': '/', '*': '[^/]*', '**': '.*'}
|
||||
let target = substitute(a:pattern, '\.\|\*\*\?', '\=tr[submatch(0)]', 'g')
|
||||
let regexp = printf('autoload/vital/[^/]\+/%s.vim$', target)
|
||||
return filter(a:files, 'v:val =~# regexp')
|
||||
endfunction
|
||||
|
||||
function! s:_file2module(file) abort
|
||||
let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?')
|
||||
let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$')
|
||||
return join(split(tail, '[\\/]\+'), '.')
|
||||
endfunction
|
||||
|
||||
" @param {string} name e.g. Data.List
|
||||
function! s:_import(name) abort dict
|
||||
if has_key(s:loaded, a:name)
|
||||
return copy(s:loaded[a:name])
|
||||
endif
|
||||
let module = self._get_module(a:name)
|
||||
if has_key(module, '_vital_created')
|
||||
call module._vital_created(module)
|
||||
endif
|
||||
let export_module = filter(copy(module), 'v:key =~# "^\\a"')
|
||||
" Cache module before calling module.vital_loaded() to avoid cyclic
|
||||
" dependences but remove the cache if module._vital_loaded() fails.
|
||||
" let s:loaded[a:name] = export_module
|
||||
let s:loaded[a:name] = export_module
|
||||
if has_key(module, '_vital_loaded')
|
||||
try
|
||||
call module._vital_loaded(vital#{s:plugin_name}#new())
|
||||
catch
|
||||
unlet s:loaded[a:name]
|
||||
throw 'vital: fail to call ._vital_loaded(): ' . v:exception
|
||||
endtry
|
||||
endif
|
||||
return copy(s:loaded[a:name])
|
||||
endfunction
|
||||
let s:Vital._import = s:_function('s:_import')
|
||||
|
||||
" s:_get_module() returns module object wihch has all script local functions.
|
||||
function! s:_get_module(name) abort dict
|
||||
let funcname = s:_import_func_name(self.plugin_name(), a:name)
|
||||
try
|
||||
return call(funcname, [])
|
||||
catch /^Vim\%((\a\+)\)\?:E117/
|
||||
return s:_get_builtin_module(a:name)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:_get_builtin_module(name) abort
|
||||
return s:sid2sfuncs(s:_module_sid(a:name))
|
||||
endfunction
|
||||
|
||||
if s:is_vital_vim
|
||||
" For vital.vim, we can use s:_get_builtin_module directly
|
||||
let s:Vital._get_module = s:_function('s:_get_builtin_module')
|
||||
else
|
||||
let s:Vital._get_module = s:_function('s:_get_module')
|
||||
endif
|
||||
|
||||
function! s:_import_func_name(plugin_name, module_name) abort
|
||||
return printf('vital#_%s#%s#import', a:plugin_name, s:_dot_to_sharp(a:module_name))
|
||||
endfunction
|
||||
|
||||
function! s:_module_sid(name) abort
|
||||
let path = s:_module_path(a:name)
|
||||
if !filereadable(path)
|
||||
throw 'vital: module not found: ' . a:name
|
||||
endif
|
||||
let vital_dir = s:is_vital_vim ? '__\w\+__' : printf('_\{1,2}%s\%%(__\)\?', s:plugin_name)
|
||||
let base = join([vital_dir, ''], '[/\\]\+')
|
||||
let p = base . substitute('' . a:name, '\.', '[/\\\\]\\+', 'g')
|
||||
let sid = s:_sid(path, p)
|
||||
if !sid
|
||||
call s:_source(path)
|
||||
let sid = s:_sid(path, p)
|
||||
if !sid
|
||||
throw printf('vital: cannot get <SID> from path: %s', path)
|
||||
endif
|
||||
endif
|
||||
return sid
|
||||
endfunction
|
||||
|
||||
function! s:_module_path(name) abort
|
||||
return get(s:_extract_files(a:name, s:vital_files()), 0, '')
|
||||
endfunction
|
||||
|
||||
function! s:_module_sid_base_dir() abort
|
||||
return s:is_vital_vim ? &rtp : s:project_root
|
||||
endfunction
|
||||
|
||||
function! s:_dot_to_sharp(name) abort
|
||||
return substitute(a:name, '\.', '#', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:_source(path) abort
|
||||
execute 'source' fnameescape(a:path)
|
||||
endfunction
|
||||
|
||||
" @vimlint(EVL102, 1, l:_)
|
||||
" @vimlint(EVL102, 1, l:__)
|
||||
function! s:_sid(path, filter_pattern) abort
|
||||
let unified_path = s:_unify_path(a:path)
|
||||
if has_key(s:cache_sid, unified_path)
|
||||
return s:cache_sid[unified_path]
|
||||
endif
|
||||
for line in filter(split(s:_execute(':scriptnames'), "\n"), 'v:val =~# a:filter_pattern')
|
||||
let [_, sid, path; __] = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$')
|
||||
if s:_unify_path(path) is# unified_path
|
||||
let s:cache_sid[unified_path] = sid
|
||||
return s:cache_sid[unified_path]
|
||||
endif
|
||||
endfor
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" We want to use a execute() builtin function instead of s:_execute(),
|
||||
" however there is a bug in execute().
|
||||
" execute() returns empty string when it is called in
|
||||
" completion function of user defined ex command.
|
||||
" https://github.com/vim-jp/issues/issues/1129
|
||||
function! s:_execute(cmd) abort
|
||||
let [save_verbose, save_verbosefile] = [&verbose, &verbosefile]
|
||||
set verbose=0 verbosefile=
|
||||
redir => res
|
||||
silent! execute a:cmd
|
||||
redir END
|
||||
let [&verbose, &verbosefile] = [save_verbose, save_verbosefile]
|
||||
return res
|
||||
endfunction
|
||||
|
||||
if filereadable(expand('<sfile>:r') . '.VIM') " is case-insensitive or not
|
||||
let s:_unify_path_cache = {}
|
||||
" resolve() is slow, so we cache results.
|
||||
" Note: On windows, vim can't expand path names from 8.3 formats.
|
||||
" So if getting full path via <sfile> and $HOME was set as 8.3 format,
|
||||
" vital load duplicated scripts. Below's :~ avoid this issue.
|
||||
function! s:_unify_path(path) abort
|
||||
if has_key(s:_unify_path_cache, a:path)
|
||||
return s:_unify_path_cache[a:path]
|
||||
endif
|
||||
let value = tolower(fnamemodify(resolve(fnamemodify(
|
||||
\ a:path, ':p')), ':~:gs?[\\/]?/?'))
|
||||
let s:_unify_path_cache[a:path] = value
|
||||
return value
|
||||
endfunction
|
||||
else
|
||||
function! s:_unify_path(path) abort
|
||||
return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?'))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
" copied and modified from Vim.ScriptLocal
|
||||
let s:SNR = join(map(range(len("\<SNR>")), '"[\\x" . printf("%0x", char2nr("\<SNR>"[v:val])) . "]"'), '')
|
||||
function! s:sid2sfuncs(sid) abort
|
||||
let fs = split(s:_execute(printf(':function /^%s%s_', s:SNR, a:sid)), "\n")
|
||||
let r = {}
|
||||
let pattern = printf('\m^function\s<SNR>%d_\zs\w\{-}\ze(', a:sid)
|
||||
for fname in map(fs, 'matchstr(v:val, pattern)')
|
||||
let r[fname] = function(s:_sfuncname(a:sid, fname))
|
||||
endfor
|
||||
return r
|
||||
endfunction
|
||||
|
||||
"" Return funcname of script local functions with SID
|
||||
function! s:_sfuncname(sid, funcname) abort
|
||||
return printf('<SNR>%s_%s', a:sid, a:funcname)
|
||||
endfunction
|
||||
|
||||
if exists('*uniq')
|
||||
function! s:_uniq(list) abort
|
||||
return uniq(a:list)
|
||||
endfunction
|
||||
else
|
||||
function! s:_uniq(list) abort
|
||||
let i = len(a:list) - 1
|
||||
while 0 < i
|
||||
if a:list[i] ==# a:list[i - 1]
|
||||
call remove(a:list, i)
|
||||
endif
|
||||
let i -= 1
|
||||
endwhile
|
||||
return a:list
|
||||
endfunction
|
||||
endif
|
@ -0,0 +1,5 @@
|
||||
plantuml_previewer
|
||||
a8773a35b8b122b59c956a23d1e686d595bca3b4
|
||||
|
||||
System.Job
|
||||
System.Process
|
20
bundle/plantuml-previewer.vim/demo.puml
Normal file
20
bundle/plantuml-previewer.vim/demo.puml
Normal file
@ -0,0 +1,20 @@
|
||||
@startuml
|
||||
scale 600 width
|
||||
|
||||
[*] -> State1
|
||||
State1 --> State2 : Succeeded
|
||||
State1 --> [*] : Aborted
|
||||
State2 --> State3 : Succeeded
|
||||
State2 --> [*] : Aborted
|
||||
state State3 {
|
||||
state "Accumulate Enough Data\nLong State Name" as long1
|
||||
long1 : Just a test
|
||||
[*] --> long1
|
||||
long1 --> long1 : New Data
|
||||
long1 --> ProcessData : Enough Data
|
||||
}
|
||||
State3 --> State3 : Failed
|
||||
State3 --> [*] : Succeeded / Save Result
|
||||
State3 --> [*] : Aborted
|
||||
|
||||
@enduml
|
107
bundle/plantuml-previewer.vim/doc/plantuml-previewer.txt
Normal file
107
bundle/plantuml-previewer.vim/doc/plantuml-previewer.txt
Normal file
@ -0,0 +1,107 @@
|
||||
*plantuml-previewer.txt* plugin for preview PlantUML
|
||||
|
||||
Version: 1.5.1
|
||||
Author: Weirong Xu <weirongxu.raidou@gmail.com>
|
||||
License: MIT License
|
||||
|
||||
==============================================================================
|
||||
CONTENTS *plantuml-previewer-contents*
|
||||
|
||||
Introduction |plantuml-previewer-introduction|
|
||||
Install |plantuml-previewer-install|
|
||||
Usage |plantuml-previewer-usage|
|
||||
Interface |plantuml-previewer-interface|
|
||||
Commands |plantuml-previewer-interface-commands|
|
||||
Variables |plantuml-previewer-interface-variables|
|
||||
|
||||
==============================================================================
|
||||
INTRODUCTION *plantuml-previewer-introduction*
|
||||
|
||||
plantuml-previewer is a plugin to preview PlantUML
|
||||
|
||||
==============================================================================
|
||||
INSTALL *plantuml-previewer-install*
|
||||
|
||||
Dependencies
|
||||
- Java
|
||||
- Graphviz : https://www.graphviz.org/download/
|
||||
- Mac >
|
||||
brew install graphviz
|
||||
<
|
||||
- Ubuntu >
|
||||
apt-get install graphviz
|
||||
<
|
||||
- Other
|
||||
https://www.graphviz.org/download/
|
||||
- open-browser.vim https://github.com/tyru/open-browser.vim
|
||||
- aklt/plantuml-syntax https://github.com/aklt/plantuml-syntax (vim syntax file for plantuml)
|
||||
|
||||
==============================================================================
|
||||
USAGE *plantuml-previewer-usage*
|
||||
|
||||
1. Start editing plantuml file in Vim
|
||||
2. Run |:PlantumlOpen| to open previewer webpage in browser
|
||||
3. Saving plantuml file in Vim, then previewer webpage will refresh
|
||||
|
||||
==============================================================================
|
||||
INTERFACE *plantuml-previewer-interface*
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
COMMANDS *plantuml-previewer-interface-commands*
|
||||
|
||||
*:PlantumlOpen*
|
||||
:PlantumlOpen
|
||||
Open previewer webpage in browser, and watch current buffer
|
||||
|
||||
*:PlantumlStart*
|
||||
:PlantumlStart
|
||||
Like |PlantumlOpen|, but won't open in browser
|
||||
|
||||
*:PlantumlStop*
|
||||
:PlantumlStop
|
||||
Stop watch buffers
|
||||
|
||||
*:PlantumlToggle*
|
||||
:PlantumlToggle
|
||||
|PlantumlOpen| or |PlantumlStop|
|
||||
|
||||
*:PlantumlSave*
|
||||
:PlantumlSave [{filepath}] [{format}]
|
||||
Export uml diagram
|
||||
If {filepath} is missing, the {filepath} using the same file path as
|
||||
plant uml, and default extension guessed by |g:plantuml_previewer#save_format|
|
||||
If {format} is missing, the {format} will be guessed by {filepath}
|
||||
extension.
|
||||
|
||||
Available formats: >
|
||||
png, svg, eps, pdf, vdx, xmi,
|
||||
scxml, html, txt, utxt, latex
|
||||
<
|
||||
Example: >
|
||||
:e diagram.puml
|
||||
|
||||
:PlantumlSave
|
||||
:PlantumlSave diagram.png
|
||||
:PlantumlSave diagram.svg
|
||||
<
|
||||
-----------------------------------------------------------------------------
|
||||
VARIABLES *plantuml-previewer-interface-variables*
|
||||
|
||||
*g:plantuml_previewer#plantuml_jar_path*
|
||||
g:plantuml_previewer#plantuml_jar_path
|
||||
plantuml.jar path
|
||||
Default: "lib/plantuml.jar"
|
||||
|
||||
*g:plantuml_previewer#save_format*
|
||||
g:plantuml_previewer#save_format
|
||||
|:PlantumlSave| default format
|
||||
Default: "png"
|
||||
|
||||
*g:plantuml_previewer#viewer_path*
|
||||
g:plantuml_previewer#viewer_path
|
||||
Custom plantuml viewer path
|
||||
The plugin will copy viewer to here if the directory does not exist
|
||||
And `tmp.puml` and `tmp.svg` will output to here
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:ft=help:norl:
|
BIN
bundle/plantuml-previewer.vim/lib/plantuml.jar
Normal file
BIN
bundle/plantuml-previewer.vim/lib/plantuml.jar
Normal file
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
command! PlantumlToggle call plantuml_previewer#toggle()
|
||||
command! PlantumlOpen call plantuml_previewer#open()
|
||||
command! PlantumlStart call plantuml_previewer#start()
|
||||
command! PlantumlStop call plantuml_previewer#stop()
|
||||
command! -nargs=* -complete=file PlantumlSave call plantuml_previewer#save_as(<f-args>)
|
11
bundle/plantuml-previewer.vim/script/save-as.cmd
Normal file
11
bundle/plantuml-previewer.vim/script/save-as.cmd
Normal file
@ -0,0 +1,11 @@
|
||||
set java_path=%1
|
||||
set jar_path=%2
|
||||
|
||||
set puml_src_path=%3
|
||||
set output_dir_path=%4
|
||||
set output_path=%5
|
||||
set save_path=%6
|
||||
set image_type=%7
|
||||
|
||||
"%java_path%" -Dapple.awt.UIElement=true -jar "%jar_path%" "%puml_src_path%" -t%image_type% -o "%output_dir_path%"
|
||||
copy "%output_path%" "%save_path%"
|
12
bundle/plantuml-previewer.vim/script/save-as.sh
Normal file
12
bundle/plantuml-previewer.vim/script/save-as.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
java_path=$1
|
||||
jar_path=$2
|
||||
|
||||
puml_src_path=$3
|
||||
output_dir_path=$4
|
||||
output_path=$5
|
||||
save_path=$6
|
||||
image_type=$7
|
||||
|
||||
"$java_path" -Dapple.awt.UIElement=true -jar "$jar_path" "$puml_src_path" -t$image_type -o "$output_dir_path"
|
||||
cp "$output_path" "$save_path"
|
15
bundle/plantuml-previewer.vim/script/update-viewer.cmd
Normal file
15
bundle/plantuml-previewer.vim/script/update-viewer.cmd
Normal file
@ -0,0 +1,15 @@
|
||||
set java_path=%1
|
||||
set jar_path=%2
|
||||
|
||||
set puml_src_path=%3
|
||||
set output_dir_path=%4
|
||||
set output_path=%5
|
||||
set finial_path=%6
|
||||
set image_type=%7
|
||||
|
||||
set timestamp=%8
|
||||
set update_js_path=%9
|
||||
|
||||
"%java_path%" -Dapple.awt.UIElement=true -jar "%jar_path%" "%puml_src_path%" -t%image_type% -o "%output_dir_path%"
|
||||
echo F | xcopy /S /Q /F /Y "%output_path%" "%finial_path%"
|
||||
echo window.updateDiagramURL('%timestamp%') > "%update_js_path%"
|
17
bundle/plantuml-previewer.vim/script/update-viewer.sh
Normal file
17
bundle/plantuml-previewer.vim/script/update-viewer.sh
Normal file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
java_path=$1
|
||||
jar_path=$2
|
||||
|
||||
puml_src_path=$3
|
||||
output_dir_path=$4
|
||||
output_path=$5
|
||||
finial_path=$6
|
||||
image_type=$7
|
||||
|
||||
timestamp=$8
|
||||
update_js_path=$9
|
||||
|
||||
"$java_path" -Dapple.awt.UIElement=true -jar "$jar_path" "$puml_src_path" -t$image_type -o "$output_dir_path"
|
||||
cp "$output_path" "$finial_path"
|
||||
echo "window.updateDiagramURL('$timestamp')" > "$update_js_path"
|
1
bundle/plantuml-previewer.vim/viewer/dist/c027ca96553d780c4370107827292565.svg
vendored
Normal file
1
bundle/plantuml-previewer.vim/viewer/dist/c027ca96553d780c4370107827292565.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 595.28 841.89"><defs><style>.cls-1{fill:none;stroke:#231815;stroke-miterlimit:10;stroke-width:60px;}.cls-2{fill:#231815;}</style></defs><title>未标题-2</title><circle class="cls-1" cx="237.42" cy="329.29" r="169.09" transform="translate(-163.31 264.32) rotate(-45)"/><rect class="cls-2" x="428.28" y="406.9" width="60" height="286.5" rx="30" ry="30" transform="translate(-254.79 485.18) rotate(-45)"/><path class="cls-2" d="M300.41,299.29h-33v-33a30,30,0,0,0-60,0v33h-33a30,30,0,0,0-30,30h0a30,30,0,0,0,30,30h33v33a30,30,0,1,0,60,0v-33h33a30,30,0,0,0,30-30h0A30,30,0,0,0,300.41,299.29Z"/></svg>
|
After Width: | Height: | Size: 685 B |
1
bundle/plantuml-previewer.vim/viewer/dist/c38c5e8361a61039ba107d5798346ce6.svg
vendored
Normal file
1
bundle/plantuml-previewer.vim/viewer/dist/c38c5e8361a61039ba107d5798346ce6.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 595.28 841.89"><defs><style>.cls-1{fill:#231815;}.cls-2{fill:none;stroke:#231815;stroke-miterlimit:10;stroke-width:60px;}</style></defs><title>未标题-2</title><rect class="cls-1" x="143.94" y="299.29" width="185.99" height="60" rx="30" ry="30"/><circle class="cls-2" cx="236.93" cy="329.29" r="169.09" transform="translate(-163.45 263.98) rotate(-45)"/><rect class="cls-1" x="427.79" y="406.9" width="60" height="286.5" rx="30" ry="30" transform="translate(-254.93 484.84) rotate(-45)"/></svg>
|
After Width: | Height: | Size: 584 B |
1
bundle/plantuml-previewer.vim/viewer/dist/ce21159a71b4ecaf63de7f048eef373b.svg
vendored
Normal file
1
bundle/plantuml-previewer.vim/viewer/dist/ce21159a71b4ecaf63de7f048eef373b.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 595.28 841.89"><defs><style>.cls-1{fill:#231815;}</style></defs><title>未标题-2</title><path class="cls-1" d="M477.38,403.76L328.27,245a44,44,0,0,0-64-.22l-151.36,159a41,41,0,0,0-10.75,27.67V605.09a41,41,0,0,0,41,41H214a24.4,24.4,0,0,0,24.4-24.4V542h113.4v79.68a24.4,24.4,0,0,0,24.4,24.4h70.9a41,41,0,0,0,41-41V431.44A41,41,0,0,0,477.38,403.76Z"/><path class="cls-1" d="M509.59,397.39L323.83,196.74a40,40,0,0,0-58.63-.08L83.09,392.29a40,40,0,0,1-56.53,2h0a40,40,0,0,1-2-56.53L265.36,79.07a40,40,0,0,1,58.63.08L568.3,343a40,40,0,0,1-2.18,56.53h0A40,40,0,0,1,509.59,397.39Z"/></svg>
|
After Width: | Height: | Size: 671 B |
1
bundle/plantuml-previewer.vim/viewer/dist/index.html
vendored
Normal file
1
bundle/plantuml-previewer.vim/viewer/dist/index.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><html><head><meta http-equiv="Content-type" content="text/html; charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Plantuml Previewer</title><link href="./main.3f72aac9.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="app"></div><script type="text/javascript" src="./vendors~main.16025f89.js"></script><script type="text/javascript" src="./main.e8e44d5b.js"></script></body></html>
|
2
bundle/plantuml-previewer.vim/viewer/dist/main.3f72aac9.css
vendored
Normal file
2
bundle/plantuml-previewer.vim/viewer/dist/main.3f72aac9.css
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.body[data-v-2d92bcce]{width:100%;height:100%;position:relative}.tools[data-v-2d92bcce]{position:absolute;right:10px;top:10px;display:flex;flex-direction:column;z-index:1000}.tools a[data-v-2d92bcce]{cursor:pointer;display:block;width:30px;height:30px}.tools a img[data-v-2d92bcce]{width:30px;height:30px}.wrapper[data-v-2d92bcce]{flex:1;width:100%;height:100%;position:relative;top:0;left:0;overflow:hidden;background:#ccc}.box[data-v-2d92bcce]{position:absolute;cursor:move}.box img[data-v-2d92bcce]{width:100%;height:100%}
|
||||
body,html{margin:0;width:100%;height:100%}
|
1
bundle/plantuml-previewer.vim/viewer/dist/main.e8e44d5b.js
vendored
Normal file
1
bundle/plantuml-previewer.vim/viewer/dist/main.e8e44d5b.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
!function(t){function e(e){for(var n,a,s=e[0],l=e[1],h=e[2],d=0,u=[];d<s.length;d++)a=s[d],r[a]&&u.push(r[a][0]),r[a]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(t[n]=l[n]);for(c&&c(e);u.length;)u.shift()();return o.push.apply(o,h||[]),i()}function i(){for(var t,e=0;e<o.length;e++){for(var i=o[e],n=!0,s=1;s<i.length;s++){var l=i[s];0!==r[l]&&(n=!1)}n&&(o.splice(e--,1),t=a(a.s=i[0]))}return t}var n={},r={1:0},o=[];function a(e){if(n[e])return n[e].exports;var i=n[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,a),i.l=!0,i.exports}a.m=t,a.c=n,a.d=function(t,e,i){a.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:i})},a.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},a.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return a.d(e,"a",e),e},a.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},a.p="./";var s=window.webpackJsonp=window.webpackJsonp||[],l=s.push.bind(s);s.push=e,s=s.slice();for(var h=0;h<s.length;h++)e(s[h]);var c=l;o.push([20,0]),i()}([,,,,,function(t,e,i){"use strict";i.r(e);var n=i(4),r=i(3),o=i(2),a=i.n(o),s=new Image,l={data:function(){return{img:{realWidth:null,realHeight:null,width:null,height:null,whRate:null},relativeCenter:{left:null,top:null},lastTimestamp:null,needReset:!0,diagramUrl:"../tmp.svg",url:null}},methods:{boxReset:function(){var t=this.$refs.wrapper;t.clientWidth/t.clientHeight>this.img.whRate?this.boxResize({height:t.clientHeight}):this.boxResize({width:t.clientWidth}),this.boxCenter()},boxResize:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=t.width,i=void 0===e?null:e,n=t.height,r=void 0===n?null:n;this.$refs.box;i?(this.img.width=i,this.img.height=i/this.img.whRate):r&&(this.img.height=r,this.img.width=r*this.img.whRate)},boxCenter:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=t.top,i=void 0===e?0:e,n=t.left,r=void 0===n?0:n,o=this.$refs.wrapper,a=this.$refs.box;this.relativeCenter.left=r,this.relativeCenter.top=i,r=o.clientWidth/2-r*this.img.width-this.img.width/2,i=o.clientHeight/2-i*this.img.height-this.img.height/2,a.style.left=r+"px",a.style.top=i+"px"},bindEvent:function(){var t=this,e=this.$refs.wrapper,i=this.$refs.box;new a.a(i).on("dragEnd",function(n){var r=i.style,o=r.top,a=r.left;o=parseFloat(o),a=parseFloat(a),t.relativeCenter.left=(e.clientWidth/2-(a+t.img.width/2))/t.img.width,t.relativeCenter.top=(e.clientHeight/2-(o+t.img.height/2))/t.img.height}),Object(r.addWheelListener)(e,function(e){e.preventDefault(),t.zoom(e.deltaY)}),s.addEventListener("error",function(e){console.error(e),t.needReset=!0}),s.addEventListener("load",function(){t.url=s.src,t.img.realWidth=s.width,t.img.realHeight=s.height;var e=s.width/s.height;t.img.whRate!==e&&(t.img.height=t.img.width/e,t.img.whRate=e),t.needReset&&(t.needReset=!1,t.boxReset())})},zoom:function(t){var e=this.img.width-t*this.img.width/1e3;if(e>100){var i=this.relativeCenter,n=i.top,r=i.left;this.boxResize({width:e}),this.boxCenter({top:n,left:r})}},reloadImage:function(){s.src=this.diagramUrl+"?t="+Date.now()},reloadUpdateJs:function(){var t=document.getElementsByTagName("head")[0],e=document.createElement("script"),i=function(){setTimeout(function(){t.removeChild(e)},200)};e.type="text/javascript",e.addEventListener("error",i),e.addEventListener("load",i),e.src="../tmp.js?t="+Date.now(),t.appendChild(e)}},mounted:function(){var t=this;this.bindEvent(),this.reloadImage(),window.updateDiagramURL=function(e){e!==t.lastTimestamp&&(t.lastTimestamp=e,t.reloadImage())},setInterval(function(){t.reloadUpdateJs()},1e3)}},h=i(1);var c=function(t){i(16)},d=Object(h.a)(l,function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"body"},[n("div",{staticClass:"tools"},[n("a",{attrs:{title:"Double click"},on:{click:t.boxReset}},[n("img",{attrs:{src:i(10)}})]),t._v(" "),n("a",{attrs:{title:"Mouse wheel"},on:{click:function(e){t.zoom(-100)}}},[n("img",{attrs:{src:i(9)}})]),t._v(" "),n("a",{attrs:{title:"Mouse wheel"},on:{click:function(e){t.zoom(100)}}},[n("img",{attrs:{src:i(8)}})])]),t._v(" "),n("div",{ref:"wrapper",staticClass:"wrapper",on:{dblclick:t.boxReset}},[n("div",{ref:"box",staticClass:"box",style:{width:t.img.width+"px",height:t.img.height+"px"},attrs:{"data-center":"left: "+t.relativeCenter.left+", top: "+t.relativeCenter.top}},[n("img",{directives:[{name:"show",rawName:"v-show",value:t.url,expression:"url"}],attrs:{src:t.url},on:{load:function(){return t.$emit("loadedImage")}}})])])])},[],!1,c,"data-v-2d92bcce",null).exports;i(7);new n.a({el:"#app",render:function(t){return t(d)}})},,function(t,e,i){},function(t,e,i){t.exports=i.p+"c38c5e8361a61039ba107d5798346ce6.svg"},function(t,e,i){t.exports=i.p+"c027ca96553d780c4370107827292565.svg"},function(t,e,i){t.exports=i.p+"ce21159a71b4ecaf63de7f048eef373b.svg"},,,,,,function(t,e,i){},,,,function(t,e,i){t.exports=i(5)}]);
|
1
bundle/plantuml-previewer.vim/viewer/dist/vendors~main.16025f89.js
vendored
Normal file
1
bundle/plantuml-previewer.vim/viewer/dist/vendors~main.16025f89.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
bundle/plantuml-previewer.vim/viewer/index.ejs
Normal file
15
bundle/plantuml-previewer.vim/viewer/index.ejs
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>Plantuml Previewer</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
10
bundle/plantuml-previewer.vim/viewer/index.html
Normal file
10
bundle/plantuml-previewer.vim/viewer/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Plantuml Previewer</title>
|
||||
<meta http-equiv="refresh" content="0; url=./dist/index.html" />
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
12528
bundle/plantuml-previewer.vim/viewer/package-lock.json
generated
Normal file
12528
bundle/plantuml-previewer.vim/viewer/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
bundle/plantuml-previewer.vim/viewer/package.json
Normal file
23
bundle/plantuml-previewer.vim/viewer/package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "plantuml-previewer",
|
||||
"version": "1.0.0",
|
||||
"description": "Plantuml Previewer",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"draggabilly": "^2.2.0",
|
||||
"vue": "^2.5.16",
|
||||
"wheel": "0.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"file-loader": "^1.1.11",
|
||||
"node-sass": "^4.13.1",
|
||||
"poi": "^10.1.9",
|
||||
"sass-loader": "^7.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "poi --port 3233 src/index.js",
|
||||
"build": "poi build src/index.js -d dist"
|
||||
},
|
||||
"author": "Weirong Xu <weirongxu.raidou@gmail.com>",
|
||||
"license": "MIT"
|
||||
}
|
11
bundle/plantuml-previewer.vim/viewer/poi.config.js
Normal file
11
bundle/plantuml-previewer.vim/viewer/poi.config.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
(poi) => {
|
||||
const isBuild = poi.command === 'build'
|
||||
if (isBuild) {
|
||||
poi.options.sourceMap = false
|
||||
poi.options.publicPath = './'
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
1
bundle/plantuml-previewer.vim/viewer/src/icons/home.svg
Normal file
1
bundle/plantuml-previewer.vim/viewer/src/icons/home.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 595.28 841.89"><defs><style>.cls-1{fill:#231815;}</style></defs><title>未标题-2</title><path class="cls-1" d="M477.38,403.76L328.27,245a44,44,0,0,0-64-.22l-151.36,159a41,41,0,0,0-10.75,27.67V605.09a41,41,0,0,0,41,41H214a24.4,24.4,0,0,0,24.4-24.4V542h113.4v79.68a24.4,24.4,0,0,0,24.4,24.4h70.9a41,41,0,0,0,41-41V431.44A41,41,0,0,0,477.38,403.76Z"/><path class="cls-1" d="M509.59,397.39L323.83,196.74a40,40,0,0,0-58.63-.08L83.09,392.29a40,40,0,0,1-56.53,2h0a40,40,0,0,1-2-56.53L265.36,79.07a40,40,0,0,1,58.63.08L568.3,343a40,40,0,0,1-2.18,56.53h0A40,40,0,0,1,509.59,397.39Z"/></svg>
|
After Width: | Height: | Size: 671 B |
@ -0,0 +1 @@
|
||||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 595.28 841.89"><defs><style>.cls-1{fill:none;stroke:#231815;stroke-miterlimit:10;stroke-width:60px;}.cls-2{fill:#231815;}</style></defs><title>未标题-2</title><circle class="cls-1" cx="237.42" cy="329.29" r="169.09" transform="translate(-163.31 264.32) rotate(-45)"/><rect class="cls-2" x="428.28" y="406.9" width="60" height="286.5" rx="30" ry="30" transform="translate(-254.79 485.18) rotate(-45)"/><path class="cls-2" d="M300.41,299.29h-33v-33a30,30,0,0,0-60,0v33h-33a30,30,0,0,0-30,30h0a30,30,0,0,0,30,30h33v33a30,30,0,1,0,60,0v-33h33a30,30,0,0,0,30-30h0A30,30,0,0,0,300.41,299.29Z"/></svg>
|
After Width: | Height: | Size: 685 B |
@ -0,0 +1 @@
|
||||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 595.28 841.89"><defs><style>.cls-1{fill:#231815;}.cls-2{fill:none;stroke:#231815;stroke-miterlimit:10;stroke-width:60px;}</style></defs><title>未标题-2</title><rect class="cls-1" x="143.94" y="299.29" width="185.99" height="60" rx="30" ry="30"/><circle class="cls-2" cx="236.93" cy="329.29" r="169.09" transform="translate(-163.45 263.98) rotate(-45)"/><rect class="cls-1" x="427.79" y="406.9" width="60" height="286.5" rx="30" ry="30" transform="translate(-254.93 484.84) rotate(-45)"/></svg>
|
After Width: | Height: | Size: 584 B |
8
bundle/plantuml-previewer.vim/viewer/src/index.js
Normal file
8
bundle/plantuml-previewer.vim/viewer/src/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
import Vue from 'vue'
|
||||
import Preview from './preview.vue'
|
||||
import './index.scss'
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
render: h => h(Preview)
|
||||
})
|
5
bundle/plantuml-previewer.vim/viewer/src/index.scss
Normal file
5
bundle/plantuml-previewer.vim/viewer/src/index.scss
Normal file
@ -0,0 +1,5 @@
|
||||
html, body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
201
bundle/plantuml-previewer.vim/viewer/src/preview.vue
Normal file
201
bundle/plantuml-previewer.vim/viewer/src/preview.vue
Normal file
@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div class="body">
|
||||
<div class="tools">
|
||||
<a title="Double click" @click="boxReset"><img src="./icons/home.svg"></a>
|
||||
<a title="Mouse wheel" @click="zoom(-100)"><img src="./icons/zoom-in.svg"></a>
|
||||
<a title="Mouse wheel" @click="zoom(100)"><img src="./icons/zoom-out.svg"></a>
|
||||
</div>
|
||||
<div class="wrapper" ref="wrapper" @dblclick="boxReset">
|
||||
<div
|
||||
class="box"
|
||||
:style="{width: img.width + 'px', height: img.height + 'px'}"
|
||||
:data-center="`left: ${relativeCenter.left}, top: ${relativeCenter.top}`"
|
||||
ref="box">
|
||||
<img
|
||||
v-show="url"
|
||||
:src="url"
|
||||
@load="() => $emit('loadedImage')">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.tools {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1000;
|
||||
a {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.wrapper {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
background: #ccc;
|
||||
}
|
||||
.box {
|
||||
position: absolute;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
cursor: move;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {addWheelListener, removeWheelListener} from 'wheel'
|
||||
import Dragger from 'draggabilly'
|
||||
|
||||
const updateJsPath = '../tmp.js'
|
||||
const diagramUrl = '../tmp.svg'
|
||||
const $tmpImage = new Image()
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
img: {
|
||||
realWidth: null,
|
||||
realHeight: null,
|
||||
width: null,
|
||||
height: null,
|
||||
whRate: null,
|
||||
},
|
||||
relativeCenter: {
|
||||
left: null,
|
||||
top: null,
|
||||
},
|
||||
lastTimestamp: null,
|
||||
needReset: true,
|
||||
diagramUrl,
|
||||
url: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
boxReset() {
|
||||
const $wrapper = this.$refs.wrapper
|
||||
if ($wrapper.clientWidth / $wrapper.clientHeight > this.img.whRate) {
|
||||
this.boxResize({height: $wrapper.clientHeight})
|
||||
} else {
|
||||
this.boxResize({width: $wrapper.clientWidth})
|
||||
}
|
||||
this.boxCenter()
|
||||
},
|
||||
boxResize({width = null, height = null} = {}) {
|
||||
const $box = this.$refs.box
|
||||
if (width) {
|
||||
this.img.width = width
|
||||
this.img.height = width / this.img.whRate
|
||||
} else if (height) {
|
||||
this.img.height = height
|
||||
this.img.width = height * this.img.whRate
|
||||
}
|
||||
},
|
||||
boxCenter({top = 0, left = 0} = {}) {
|
||||
const $wrapper = this.$refs.wrapper
|
||||
const $box = this.$refs.box
|
||||
this.relativeCenter.left = left
|
||||
this.relativeCenter.top = top
|
||||
left = $wrapper.clientWidth/2 - (left * this.img.width) - this.img.width/2
|
||||
top = $wrapper.clientHeight/2 - (top * this.img.height) - this.img.height/2
|
||||
$box.style.left = left + 'px'
|
||||
$box.style.top = top + 'px'
|
||||
},
|
||||
bindEvent() {
|
||||
const $wrapper = this.$refs.wrapper
|
||||
const $box = this.$refs.box
|
||||
const dragger = new Dragger($box)
|
||||
dragger.on('dragEnd', event => {
|
||||
let {top, left} = $box.style
|
||||
top = parseFloat(top)
|
||||
left = parseFloat(left)
|
||||
|
||||
this.relativeCenter.left = ($wrapper.clientWidth/2 - (left + this.img.width/2)) / this.img.width
|
||||
this.relativeCenter.top = ($wrapper.clientHeight/2 - (top + this.img.height/2)) / this.img.height
|
||||
})
|
||||
addWheelListener($wrapper, e => {
|
||||
e.preventDefault()
|
||||
this.zoom(e.deltaY)
|
||||
})
|
||||
|
||||
$tmpImage.addEventListener('error', (error) => {
|
||||
console.error(error)
|
||||
this.needReset = true
|
||||
})
|
||||
$tmpImage.addEventListener('load', () => {
|
||||
this.url = $tmpImage.src
|
||||
this.img.realWidth = $tmpImage.width
|
||||
this.img.realHeight = $tmpImage.height
|
||||
const whRate = $tmpImage.width / $tmpImage.height
|
||||
if (this.img.whRate !== whRate) {
|
||||
this.img.height = this.img.width / whRate
|
||||
this.img.whRate = whRate
|
||||
}
|
||||
if (this.needReset) {
|
||||
this.needReset = false
|
||||
this.boxReset()
|
||||
}
|
||||
})
|
||||
},
|
||||
zoom(delta) {
|
||||
const width = this.img.width - delta * this.img.width / 1000
|
||||
if (width > 100) {
|
||||
const {top, left} = this.relativeCenter
|
||||
this.boxResize({width})
|
||||
this.boxCenter({top, left})
|
||||
}
|
||||
},
|
||||
reloadImage() {
|
||||
$tmpImage.src = this.diagramUrl + '?t=' + Date.now()
|
||||
},
|
||||
reloadUpdateJs() {
|
||||
const head = document.getElementsByTagName('head')[0]
|
||||
const script = document.createElement('script')
|
||||
const removeScript = () => {
|
||||
setTimeout(() => {
|
||||
head.removeChild(script)
|
||||
}, 200)
|
||||
}
|
||||
script.type = 'text/javascript'
|
||||
script.addEventListener('error', removeScript)
|
||||
script.addEventListener('load', removeScript)
|
||||
script.src = updateJsPath + '?t=' + Date.now()
|
||||
head.appendChild(script)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.bindEvent()
|
||||
this.reloadImage()
|
||||
window.updateDiagramURL = (timestamp) => {
|
||||
if (timestamp !== this.lastTimestamp) {
|
||||
this.lastTimestamp = timestamp
|
||||
this.reloadImage()
|
||||
}
|
||||
}
|
||||
setInterval(() => {
|
||||
this.reloadUpdateJs()
|
||||
}, 1000)
|
||||
},
|
||||
}
|
||||
</script>
|
131
doc/SpaceVim.txt
131
doc/SpaceVim.txt
@ -164,52 +164,53 @@ CONTENTS *SpaceVim-contents*
|
||||
77. lang#pascal............................|SpaceVim-layers-lang-pascal|
|
||||
78. lang#perl................................|SpaceVim-layers-lang-perl|
|
||||
79. lang#php..................................|SpaceVim-layers-lang-php|
|
||||
80. lang#pony................................|SpaceVim-layers-lang-pony|
|
||||
81. lang#processing....................|SpaceVim-layers-lang-processing|
|
||||
82. lang#prolog............................|SpaceVim-layers-lang-prolog|
|
||||
83. lang#puppet............................|SpaceVim-layers-lang-puppet|
|
||||
84. lang#purescript....................|SpaceVim-layers-lang-purescript|
|
||||
85. lang#python............................|SpaceVim-layers-lang-python|
|
||||
86. lang#racket............................|SpaceVim-layers-lang-racket|
|
||||
87. lang#racket...............................|SpaceVim-layers-lang-red|
|
||||
88. lang#reason............................|SpaceVim-layers-lang-reason|
|
||||
89. lang#ring...................................|SpaceVim-layers-lang-r|
|
||||
90. lang#ring................................|SpaceVim-layers-lang-ring|
|
||||
91. lang#ruby................................|SpaceVim-layers-lang-ruby|
|
||||
92. lang#rust................................|SpaceVim-layers-lang-rust|
|
||||
93. lang#scala..............................|SpaceVim-layers-lang-scala|
|
||||
94. lang#scheme............................|SpaceVim-layers-lang-scheme|
|
||||
95. lang#sh....................................|SpaceVim-layers-lang-sh|
|
||||
96. lang#smalltalk......................|SpaceVim-layers-lang-smalltalk|
|
||||
97. lang#sml..................................|SpaceVim-layers-lang-sml|
|
||||
98. lang#swig...............................|SpaceVim-layers-lang-swift|
|
||||
99. lang#swig................................|SpaceVim-layers-lang-swig|
|
||||
100. lang#tcl.................................|SpaceVim-layers-lang-tcl|
|
||||
101. lang#toml...............................|SpaceVim-layers-lang-toml|
|
||||
102. lang#typescript...................|SpaceVim-layers-lang-typescript|
|
||||
103. lang#v.....................................|SpaceVim-layers-lang-v|
|
||||
104. lang#vala...............................|SpaceVim-layers-lang-vala|
|
||||
105. lang#vbnet.............................|SpaceVim-layers-lang-vbnet|
|
||||
106. lang#vim.................................|SpaceVim-layers-lang-vim|
|
||||
107. lang#vue.................................|SpaceVim-layers-lang-vue|
|
||||
108. lang#wolfram.........................|SpaceVim-layers-lang-wolfram|
|
||||
109. lang#xml.................................|SpaceVim-layers-lang-xml|
|
||||
110. lang#xquery...........................|SpaceVim-layers-lang-xquery|
|
||||
111. lang#zig.................................|SpaceVim-layers-lang-zig|
|
||||
112. language server protocol......................|SpaceVim-layers-lsp|
|
||||
113. leaderf...................................|SpaceVim-layers-leaderf|
|
||||
114. mail.........................................|SpaceVim-layers-mail|
|
||||
115. operator.................................|SpaceVim-layers-operator|
|
||||
116. shell.......................................|SpaceVim-layers-shell|
|
||||
117. ssh...........................................|SpaceVim-layers-ssh|
|
||||
118. test.........................................|SpaceVim-layers-test|
|
||||
119. tmux.........................................|SpaceVim-layers-tmux|
|
||||
120. tools#dash.............................|SpaceVim-layers-tools-dash|
|
||||
121. tools#mpv...............................|SpaceVim-layers-tools-mpv|
|
||||
122. tools#zeal.............................|SpaceVim-layers-tools-zeal|
|
||||
123. treesitter.............................|SpaceVim-layers-treesitter|
|
||||
124. ui.............................................|SpaceVim-layers-ui|
|
||||
125. unite.......................................|SpaceVim-layers-unite|
|
||||
80. lang#plantuml........................|SpaceVim-layers-lang-plantuml|
|
||||
81. lang#pony................................|SpaceVim-layers-lang-pony|
|
||||
82. lang#processing....................|SpaceVim-layers-lang-processing|
|
||||
83. lang#prolog............................|SpaceVim-layers-lang-prolog|
|
||||
84. lang#puppet............................|SpaceVim-layers-lang-puppet|
|
||||
85. lang#purescript....................|SpaceVim-layers-lang-purescript|
|
||||
86. lang#python............................|SpaceVim-layers-lang-python|
|
||||
87. lang#racket............................|SpaceVim-layers-lang-racket|
|
||||
88. lang#racket...............................|SpaceVim-layers-lang-red|
|
||||
89. lang#reason............................|SpaceVim-layers-lang-reason|
|
||||
90. lang#ring...................................|SpaceVim-layers-lang-r|
|
||||
91. lang#ring................................|SpaceVim-layers-lang-ring|
|
||||
92. lang#ruby................................|SpaceVim-layers-lang-ruby|
|
||||
93. lang#rust................................|SpaceVim-layers-lang-rust|
|
||||
94. lang#scala..............................|SpaceVim-layers-lang-scala|
|
||||
95. lang#scheme............................|SpaceVim-layers-lang-scheme|
|
||||
96. lang#sh....................................|SpaceVim-layers-lang-sh|
|
||||
97. lang#smalltalk......................|SpaceVim-layers-lang-smalltalk|
|
||||
98. lang#sml..................................|SpaceVim-layers-lang-sml|
|
||||
99. lang#swig...............................|SpaceVim-layers-lang-swift|
|
||||
100. lang#swig...............................|SpaceVim-layers-lang-swig|
|
||||
101. lang#tcl.................................|SpaceVim-layers-lang-tcl|
|
||||
102. lang#toml...............................|SpaceVim-layers-lang-toml|
|
||||
103. lang#typescript...................|SpaceVim-layers-lang-typescript|
|
||||
104. lang#v.....................................|SpaceVim-layers-lang-v|
|
||||
105. lang#vala...............................|SpaceVim-layers-lang-vala|
|
||||
106. lang#vbnet.............................|SpaceVim-layers-lang-vbnet|
|
||||
107. lang#vim.................................|SpaceVim-layers-lang-vim|
|
||||
108. lang#vue.................................|SpaceVim-layers-lang-vue|
|
||||
109. lang#wolfram.........................|SpaceVim-layers-lang-wolfram|
|
||||
110. lang#xml.................................|SpaceVim-layers-lang-xml|
|
||||
111. lang#xquery...........................|SpaceVim-layers-lang-xquery|
|
||||
112. lang#zig.................................|SpaceVim-layers-lang-zig|
|
||||
113. language server protocol......................|SpaceVim-layers-lsp|
|
||||
114. leaderf...................................|SpaceVim-layers-leaderf|
|
||||
115. mail.........................................|SpaceVim-layers-mail|
|
||||
116. operator.................................|SpaceVim-layers-operator|
|
||||
117. shell.......................................|SpaceVim-layers-shell|
|
||||
118. ssh...........................................|SpaceVim-layers-ssh|
|
||||
119. test.........................................|SpaceVim-layers-test|
|
||||
120. tmux.........................................|SpaceVim-layers-tmux|
|
||||
121. tools#dash.............................|SpaceVim-layers-tools-dash|
|
||||
122. tools#mpv...............................|SpaceVim-layers-tools-mpv|
|
||||
123. tools#zeal.............................|SpaceVim-layers-tools-zeal|
|
||||
124. treesitter.............................|SpaceVim-layers-treesitter|
|
||||
125. ui.............................................|SpaceVim-layers-ui|
|
||||
126. unite.......................................|SpaceVim-layers-unite|
|
||||
7. Usage....................................................|SpaceVim-usage|
|
||||
1. buffers-and-files..................|SpaceVim-usage-buffers-and-files|
|
||||
2. command-line-mode..................|SpaceVim-usage-command-line-mode|
|
||||
@ -3711,6 +3712,44 @@ This layer also provides REPL support for php, the key bindings are:
|
||||
<
|
||||
|
||||
|
||||
==============================================================================
|
||||
LANG#PLANTUML *SpaceVim-layers-lang-plantuml*
|
||||
|
||||
This layer is for plantuml development, disabled by default, to enable this
|
||||
layer, add following snippet to your SpaceVim configuration file.
|
||||
>
|
||||
[[layers]]
|
||||
name = 'lang#plantuml'
|
||||
<
|
||||
|
||||
LAYER OPTIONS
|
||||
|
||||
1. `java_command`: Set the path of java command, by default, it is `java`
|
||||
|
||||
>
|
||||
[[layers]]
|
||||
name = 'lang#plantuml'
|
||||
java_command = 'path/to/java'
|
||||
<
|
||||
2. `plantuml_jar_path`: Set the path of `pluatuml.jar`.
|
||||
|
||||
>
|
||||
[[layers]]
|
||||
name = 'lang#plantuml'
|
||||
plantuml_jar_path = 'path/to/plantuml.jar'
|
||||
<
|
||||
|
||||
KEY BINDINGS
|
||||
|
||||
>
|
||||
Mode Key Function
|
||||
---------------------------------------------
|
||||
normal SPC l p preview uml file
|
||||
normal SPC l c stop preview
|
||||
normal SPC l s save uml file
|
||||
<
|
||||
|
||||
|
||||
==============================================================================
|
||||
LANG#PONY *SpaceVim-layers-lang-pony*
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user