Typographic transforms (---, quote pairs, ~) no longer touch verbatim text: @c/@code/@source_listing content and ^'...'^ spans show exactly the characters written. "^" before any punctuation character quotes it in every target (the apostrophe excepted: ^' opens a literal span), with the new :resolve option on @@@target declaring per-target renderings. The ^UUUU^ code-point form accepts 4-6 hex digits, the full Unicode range. The html output and transform spellings are polyglot (XML-valid), in preparation for an EPUB target. New suites: transform_test, character_test (engine), typography_test (SKS). (from dev 07ce5ea86a0a)
196 lines
8.4 KiB
VimL
196 lines
8.4 KiB
VimL
" vim_feature_test.vim — comprehensive checks of the Klammertext Vim plugin,
|
|
" beyond the fixture runs in editor_test.sh (which cover the Reindent and
|
|
" Align commands' output bytes). Run headlessly:
|
|
"
|
|
" KT_FIX=<fixture dir> KT_OUT=<result file> \
|
|
" vim -N -n -u NONE -i NONE -es --not-a-term \
|
|
" --cmd 'set rtp^=<doc/edit/vim>' -c 'source vim_feature_test.vim'
|
|
"
|
|
" What is checked:
|
|
" * ftdetect: .kt maps to the klammertext filetype, overriding the stock
|
|
" runtime's .kt -> kotlin mapping
|
|
" * syntax: token classes at known positions (three @-tiers open/close,
|
|
" removal line/block/file with markers, verbatim @code interior,
|
|
" ^-escapes, abbreviated @name-arg)
|
|
" * commands: KlammertextJumpToMatch (open->close, close->open,
|
|
" multibyte columns), KlammertextCheck (location list)
|
|
" * with +python3: 'indentexpr' drives the = operator (gg=G equals the
|
|
" expected fixture), and the CursorMoved match highlighter sets
|
|
" KlammertextMatch / KlammertextMismatch matches
|
|
"
|
|
" Writes PASS/FAIL lines to $KT_OUT; exits nonzero if anything failed.
|
|
|
|
let s:results = []
|
|
function! s:Check(name, ok, ...) abort
|
|
let detail = (a:ok || !a:0) ? '' : ' -- ' . string(a:1)
|
|
call add(s:results, (a:ok ? 'PASS ' : 'FAIL ') . a:name . detail)
|
|
endfunction
|
|
|
|
function! s:Syn(l, c) abort
|
|
return synIDattr(synID(a:l, a:c, 1), 'name')
|
|
endfunction
|
|
|
|
filetype plugin on
|
|
if has('syntax')
|
|
syntax enable
|
|
endif
|
|
|
|
" --- ftdetect: .kt is klammertext (the Kotlin override) --------------------
|
|
execute 'edit! ' . fnameescape($KT_FIX . '/indent_list.kt')
|
|
call s:Check('ftdetect .kt -> klammertext (overrides kotlin)',
|
|
\ &filetype ==# 'klammertext', &filetype)
|
|
|
|
" --- syntax token classes ---------------------------------------------------
|
|
if has('syntax')
|
|
enew!
|
|
call setline(1, [
|
|
\ '@i abc @ x',
|
|
\ '@@def : x @@',
|
|
\ '@@@target x @@@',
|
|
\ '# removed line',
|
|
\ '#[ rem ]# after',
|
|
\ '^@ escaped',
|
|
\ '@code x @ y code@',
|
|
\ 'name@ x',
|
|
\ '@name-arg x',
|
|
\ '## tail',
|
|
\ 'still removed'])
|
|
set filetype=klammertext
|
|
call s:Check('syntax loaded', b:current_syntax ==# 'klammertext')
|
|
call s:Check('app open @i', s:Syn(1, 1) ==# 'klammertextAppOpen', s:Syn(1, 1))
|
|
call s:Check('app bare close', s:Syn(1, 8) ==# 'klammertextAppClose', s:Syn(1, 8))
|
|
call s:Check('plain text', s:Syn(1, 10) ==# '', s:Syn(1, 10))
|
|
call s:Check('def open @@def', s:Syn(2, 1) ==# 'klammertextDefOpen', s:Syn(2, 1))
|
|
call s:Check('def bare close', s:Syn(2, 11) ==# 'klammertextDefClose', s:Syn(2, 11))
|
|
call s:Check('sys open @@@target', s:Syn(3, 1) ==# 'klammertextSysOpen', s:Syn(3, 1))
|
|
call s:Check('sys bare close', s:Syn(3, 13) ==# 'klammertextSysClose', s:Syn(3, 13))
|
|
call s:Check('line marker #', s:Syn(4, 1) ==# 'klammertextMarkerLine', s:Syn(4, 1))
|
|
call s:Check('line removed text', s:Syn(4, 5) ==# 'klammertextRemovedLine', s:Syn(4, 5))
|
|
call s:Check('block marker #[', s:Syn(5, 1) ==# 'klammertextMarker', s:Syn(5, 1))
|
|
call s:Check('block removed text', s:Syn(5, 5) ==# 'klammertextRemovedBlock', s:Syn(5, 5))
|
|
call s:Check('block marker ]#', s:Syn(5, 8) ==# 'klammertextMarker', s:Syn(5, 8))
|
|
call s:Check('text after block', s:Syn(5, 12) ==# '', s:Syn(5, 12))
|
|
call s:Check('escape ^@ consumed', s:Syn(6, 1) ==# 'klammertextEscape'
|
|
\ && s:Syn(6, 2) ==# 'klammertextEscape', s:Syn(6, 2))
|
|
call s:Check('verbatim open', s:Syn(7, 1) ==# 'klammertextAppOpen', s:Syn(7, 1))
|
|
call s:Check('verbatim interior @', s:Syn(7, 9) ==# 'klammertextVerbatim', s:Syn(7, 9))
|
|
call s:Check('verbatim close', s:Syn(7, 17) ==# 'klammertextAppClose', s:Syn(7, 17))
|
|
call s:Check('named close name@', s:Syn(8, 1) ==# 'klammertextAppClose'
|
|
\ && s:Syn(8, 5) ==# 'klammertextAppClose', s:Syn(8, 1))
|
|
call s:Check('abbreviated @name-', s:Syn(9, 1) ==# 'klammertextAppOpen'
|
|
\ && s:Syn(9, 6) ==# '' && s:Syn(9, 7) ==# '', s:Syn(9, 6))
|
|
call s:Check('file marker ##', s:Syn(10, 1) ==# 'klammertextMarker', s:Syn(10, 1))
|
|
call s:Check('## removes to EOF', s:Syn(11, 3) ==# 'klammertextRemovedFile', s:Syn(11, 3))
|
|
|
|
" @c is the single-letter literal klammer (inline @code, 2026-08-16). A
|
|
" fresh buffer: the ## in the buffer above removes to EOF. The traps a
|
|
" single-letter name adds: a word ending in c ("basic@") must not close the
|
|
" region, and "@caption" must not open one.
|
|
enew!
|
|
call setline(1, [
|
|
\ '@c y @ basic@ z c@ tail',
|
|
\ '@caption arg @'])
|
|
set filetype=klammertext
|
|
call s:Check('c verbatim open @c', s:Syn(1, 1) ==# 'klammertextAppOpen', s:Syn(1, 1))
|
|
call s:Check('c interior @ verbatim', s:Syn(1, 6) ==# 'klammertextVerbatim', s:Syn(1, 6))
|
|
call s:Check('basic@ does not close @c', s:Syn(1, 13) ==# 'klammertextVerbatim', s:Syn(1, 13))
|
|
call s:Check('real close c@', s:Syn(1, 17) ==# 'klammertextAppClose', s:Syn(1, 17))
|
|
call s:Check('text after c@ plain', s:Syn(1, 20) ==# '', s:Syn(1, 20))
|
|
call s:Check('@caption opens @caption, not @c', s:Syn(2, 1) ==# 'klammertextAppOpen', s:Syn(2, 1))
|
|
else
|
|
call add(s:results, 'SKIP syntax checks (this Vim lacks +syntax)')
|
|
endif
|
|
|
|
" --- jump-to-match (the CLI shell-out path) ---------------------------------
|
|
enew!
|
|
call setline(1, ['@i abc @ x'])
|
|
set filetype=klammertext
|
|
call cursor(1, 1)
|
|
KlammertextJumpToMatch
|
|
call s:Check('jump open -> close', col('.') == 8, col('.'))
|
|
KlammertextJumpToMatch
|
|
call s:Check('jump close -> open', col('.') == 1, col('.'))
|
|
|
|
" multibyte: 2-byte umlauts before the delimiters
|
|
enew!
|
|
call setline(1, ['üü @i x @'])
|
|
set filetype=klammertext
|
|
call cursor(1, 6) " byte col 6 = the @ of @i (2 x 2-byte ü)
|
|
KlammertextJumpToMatch
|
|
call s:Check('jump with multibyte line',
|
|
\ (exists('*charcol') ? charcol('.') : col('.'))
|
|
\ == (exists('*charcol') ? 9 : 11),
|
|
\ [col('.'), getline('.')])
|
|
|
|
" --- KlammertextCheck: diagnostics into the location list -------------------
|
|
enew!
|
|
call setline(1, ['@i abc', '@ol x ul@'])
|
|
set filetype=klammertext
|
|
KlammertextCheck
|
|
let s:ll = getloclist(0)
|
|
call s:Check('check fills the location list', len(s:ll) == 2, s:ll)
|
|
call s:Check('check positions', len(s:ll) == 2
|
|
\ && s:ll[0].lnum == 1 && s:ll[0].col == 1
|
|
\ && s:ll[1].lnum == 2 && s:ll[1].col == 7, s:ll)
|
|
call s:Check('check messages', len(s:ll) == 2
|
|
\ && s:ll[0].text =~# 'never closed' && s:ll[1].text =~# 'ul@', s:ll)
|
|
lclose
|
|
|
|
enew!
|
|
call setline(1, ['@i balanced @'])
|
|
set filetype=klammertext
|
|
KlammertextCheck
|
|
call s:Check('check clean buffer -> empty list', len(getloclist(0)) == 0)
|
|
|
|
" --- +python3: indentexpr (= operator) and live match highlighting ---------
|
|
if has('python3')
|
|
for s:fix in ['indent_list', 'indent_document', 'indent_named_close']
|
|
execute 'edit! ' . fnameescape($KT_FIX . '/' . s:fix . '.kt')
|
|
call s:Check(s:fix . ': indentexpr is set',
|
|
\ &indentexpr ==# 'klammertext#IndentExpr()', &indentexpr)
|
|
normal! gg=G
|
|
call s:Check(s:fix . ': gg=G equals expected fixture',
|
|
\ getline(1, '$') ==# readfile($KT_FIX . '/' . s:fix . '_expected.kt'))
|
|
edit!
|
|
endfor
|
|
|
|
" live match highlighting via the CursorMoved autocmd
|
|
enew!
|
|
call setline(1, ['@i abc @ x'])
|
|
set filetype=klammertext
|
|
call cursor(1, 1)
|
|
doautocmd CursorMoved
|
|
let s:m = filter(getmatches(), 'v:val.group =~# "^Klammertext"')
|
|
call s:Check('highlight: matched pair boxed',
|
|
\ len(s:m) == 1 && s:m[0].group ==# 'KlammertextMatch'
|
|
\ && len(filter(keys(s:m[0]), 'v:val =~# "^pos"')) == 2, s:m)
|
|
call cursor(1, 5) " not on a delimiter
|
|
doautocmd CursorMoved
|
|
call s:Check('highlight: cleared off-delimiter',
|
|
\ empty(filter(getmatches(), 'v:val.group =~# "^Klammertext"')))
|
|
|
|
enew!
|
|
call setline(1, ['@ol x ul@'])
|
|
set filetype=klammertext
|
|
call cursor(1, 1)
|
|
doautocmd CursorMoved
|
|
let s:m = filter(getmatches(), 'v:val.group =~# "^Klammertext"')
|
|
call s:Check('highlight: mismatch in red group',
|
|
\ len(s:m) == 1 && s:m[0].group ==# 'KlammertextMismatch', s:m)
|
|
|
|
" default mappings exist (buffer-local, LocalLeader)
|
|
call s:Check('mappings defined',
|
|
\ !empty(maparg('<LocalLeader>j', 'n'))
|
|
\ && !empty(maparg('<LocalLeader>i', 'n'))
|
|
\ && !empty(maparg('<LocalLeader>a', 'n')))
|
|
else
|
|
call add(s:results, 'SKIP +python3 checks (this Vim lacks python3)')
|
|
endif
|
|
|
|
" --- write results and exit -------------------------------------------------
|
|
call writefile(s:results, $KT_OUT)
|
|
if len(filter(copy(s:results), 'v:val =~# "^FAIL"')) > 0
|
|
cquit!
|
|
endif
|
|
qa!
|