1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 06:50:05 +08:00
SpaceVim/bundle/vim-slumlord/autoload/slumlord.vim

273 lines
7.7 KiB
VimL
Vendored

" PlantUML Live Preview for ascii/unicode art
" @Author: Martin Grenfell <martin.grenfell@gmail.com>
" @Date: 2018-12-07 13:00:22
" @Last Modified by: Tsuyoshi CHO <Tsuyoshi.CHO@Gmail.com>
" @Last Modified time: 2018-12-08 00:02:38
" @License: WTFPL
" PlantUML preview plugin core
" Intro {{{1
if exists("g:autoloaded_slumlord")
finish
endif
let g:autoloaded_slumlord = 1
let s:save_cpo = &cpo
set cpo&vim
" variable {{{1
let g:slumlord_plantuml_jar_path = get(g:, 'slumlord_plantuml_jar_path', expand("<sfile>:p:h") . "/../plantuml.jar")
let g:slumlord_plantuml_include_path = get(g:, 'slumlord_plantuml_include_path', expand("~/.config/plantuml/include/"))
let g:slumlord_asciiart_utf = get(g:, 'slumlord_asciiart_utf', 1)
" function {{{1
function! slumlord#updatePreview(args) abort
if !s:shouldInsertPreview()
return
end
let charset = 'UTF-8'
let type = 'utxt'
let ext = 'utxt'
if !g:slumlord_asciiart_utf
let type = 'txt'
let ext = 'atxt'
endif
let tmpfname = tempname()
call s:mungeDiagramInTmpFile(tmpfname)
let b:slumlord_preview_fname = fnamemodify(tmpfname, ':r') . '.' . ext
let cmd = "java -Dapple.awt.UIElement=true -Dplantuml.include.path=\"". g:slumlord_plantuml_include_path ."\" -splash: -jar ". g:slumlord_plantuml_jar_path ." -charset ". charset ." -t" . type ." ". tmpfname
let write = has_key(a:args, 'write') && a:args["write"] == 1
if exists("*jobstart")
call jobstart(cmd, { "on_exit": function("s:asyncHandlerAdapter"), "write": write, "bufnr": bufnr("") })
elseif exists("*job_start")
call job_start(cmd, { "exit_cb": {job,st->call('s:asyncHandlerAdapter',[job,st,0],{"bufnr": bufnr(""),"write": write})}, "out_io": "buffer", "out_buf": bufnr("") })
else
call system(cmd)
if v:shell_error == 0
call s:updater.update(a:args)
endif
endif
endfunction
function! s:shouldInsertPreview() abort
"check for 'no-preview flag
if search('^\s*''no-preview', 'wn') > 0
return
endif
"check for state diagram
if search('^\s*\[\*\]', 'wn') > 0
return
endif
"check for use cases
if search('^\s*\%((.*)\|:.*:\)', 'wn') > 0
return
endif
"check for class diagrams
if search('^\s*class\>', 'wn') > 0
return
endif
"check for activity diagrams
if search('^\s*:.*;', 'wn') > 0
return
endif
return 1
endfunction
function! s:asyncHandlerAdapter(job_id, data, event) abort dict
if a:data != 0
return 0
endif
if bufnr("") != self.bufnr
return 0
endif
call s:updater.update(self)
endfunction
function! s:readWithoutStoringAsAltFile(fname) abort
let oldcpoptions = &cpoptions
set cpoptions-=a
exec 'read' a:fname
let &cpoptions = oldcpoptions
endfunction
function! s:mungeDiagramInTmpFile(fname) abort
call writefile(getline(1, '$'), a:fname)
call s:convertNonAsciiSupportedSyntax(a:fname)
endfunction
function! s:convertNonAsciiSupportedSyntax(fname) abort
exec 'sp' a:fname
/@startuml/,/@enduml/s/^\s*\(boundary\|database\|entity\|control\)/participant/e
/@startuml/,/@enduml/s/^\s*\(end \)\?\zsref\>/note/e
/@startuml/,/@enduml/s/^\s*ref\>/note/e
/@startuml/,/@enduml/s/|||/||4||/e
/@startuml/,/@enduml/s/\.\.\.\([^.]*\)\.\.\./==\1==/e
write
bwipe!
endfunction
function! s:removeLeadingWhitespace(...) abort
let opts = a:0 ? a:1 : {}
let diagramEnd = get(opts, 'diagramEnd', line('$'))
let smallestLead = 100
for i in range(1, diagramEnd-1)
let lead = match(getline(i), '\S')
if lead >= 0 && lead < smallestLead
let smallestLead = lead
endif
endfor
exec '1,' . diagramEnd . 's/^ \{'.smallestLead.'}//e'
endfunction
function! s:addTitle() abort
let lnum = search('^title ', 'n')
if !lnum
return
endif
let title = substitute(getline(lnum), '^title \(.*\)', '\1', '')
call append(0, "")
call append(0, repeat("^", strdisplaywidth(title)+6))
call append(0, " " . title)
endfunction
" InPlaceUpdater object {{{1
let s:InPlaceUpdater = {}
let s:InPlaceUpdater.divider = "@startuml"
function! s:InPlaceUpdater.update(args) abort
let startLine = line(".")
let lastLine = line("$")
let startCol = col(".")
call self.__deletePreviousDiagram()
call self.__insertDiagram(b:slumlord_preview_fname)
call s:addTitle()
call cursor(line("$") - (lastLine - startLine), startCol)
if a:args['write']
noautocmd write
endif
endfunction
function! s:InPlaceUpdater.__deletePreviousDiagram() abort
if self.__dividerLnum() > 1
exec '0,' . (self.__dividerLnum() - 1) . 'delete _'
endif
endfunction
function! s:InPlaceUpdater.__insertDiagram(fname) abort
call append(0, "")
call append(0, "")
0
call s:readWithoutStoringAsAltFile(a:fname)
"fix trailing whitespace
exec '1,' . self.__dividerLnum() . 's/\s\+$//e'
call s:removeLeadingWhitespace()
endfunction
function! s:InPlaceUpdater.__dividerLnum() abort
return search(self.divider, 'wn')
endfunction
" WinUpdater object {{{1
let s:WinUpdater = {}
function! s:WinUpdater.update(args) abort
let fname = b:slumlord_preview_fname
call self.__moveToWin()
%d
call append(0, "")
call append(0, "")
0
call s:readWithoutStoringAsAltFile(fname)
"fix trailing whitespace
%s/\s\+$//e
call s:removeLeadingWhitespace()
call s:addTitle()
wincmd p
endfunction
function s:WinUpdater.__moveToWin() abort
if exists("b:slumlord_bnum") && bufexists(b:slumlord_bnum)
if bufwinnr(b:slumlord_bnum) != -1
exec bufwinnr(b:slumlord_bnum) . "wincmd w"
else
exec b:slumlord_bnum . "sb"
endif
else
let prev_bnum = bufnr("")
new
setlocal buftype=nofile
setlocal bufhidden=wipe
setlocal noswapfile
setlocal textwidth=0 " avoid automatic line break
call setbufvar(prev_bnum, "slumlord_bnum", bufnr(""))
call self.__setupWinOpts()
endif
endfunction
function s:WinUpdater.__setupWinOpts() abort
setl nowrap
setl buftype=nofile
syn match plantumlPreviewBoxParts #[┌┐└┘┬─│┴<>╚═╪╝╔═╤╪╗║╧╟╠╣]#
syn match plantumlPreviewCtrlFlow #\(LOOP\|ALT\|OPT\)[^│]*│\s*[a-zA-Z0-9?! ]*#
syn match plantumlPreviewCtrlFlow #║ \[[^]]*\]#hs=s+3,he=e-1
syn match plantumlPreviewEntity #│\w*│#hs=s+1,he=e-1
syn match plantumlPreviewTitleUnderline #\^\+#
syn match plantumlPreviewNoteText #║[^┌┐└┘┬─│┴<>╚═╪╝╔═╤╪╗║╧╟╠╣]*[░ ]║#hs=s+1,he=e-2
syn match plantumlPreviewDividerText #╣[^┌┐└┘┬─│┴<>╚═╪╝╔═╤╪╗║╧╟╣]*╠#hs=s+1,he=e-1
syn match plantumlPreviewMethodCall #\(\(│\|^\)\s*\)\@<=[a-zA-Z_]*([[:alnum:],_ ]*)#
syn match plantumlPreviewMethodCallParen #[()]# containedin=plantumlPreviewMethodCall contained
hi def link plantumlPreviewBoxParts normal
hi def link plantumlPreviewCtrlFlow Keyword
hi def link plantumlPreviewLoopName Statement
hi def link plantumlPreviewEntity Statement
hi def link plantumlPreviewTitleUnderline Statement
hi def link plantumlPreviewNoteText Constant
hi def link plantumlPreviewDividerText Constant
hi def link plantumlPreviewMethodCall plantumlText
hi def link plantumlPreviewMethodCallParen plantumlColonLine
endfunction
" other shit {{{1
if exists("g:slumlord_separate_win") && g:slumlord_separate_win
let s:updater = s:WinUpdater
else
let s:updater = s:InPlaceUpdater
endif
" Outro {{{1
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set fdm=marker: