refactor(viml): extract shared heading_level/is_table_row/wiki_cfg; fix cap + spaceless
CI / editor tests (push) Successful in 44s
CI / editor tests (push) Successful in 44s
Mirrors the Lua util refactor. Pulls the copy-pasted VimL helpers into
autoload/nuwiki/util.vim and points the per-file s: stubs at it:
- heading_level (commands/folding/textobjects) — commands.vim's copy was
missing the >6 level cap the others had (a 7+ `=` line returned 7). The
unified version caps at 6 AND accepts spaceless headings (==Heading==),
matching the server lexer + the Lua client (so fold fallback, text
objects, and ]] navigation recognize spaceless headings too).
- is_table_row (commands/textobjects) — identical copies.
- wiki_cfg (commands/diary) — these had DRIFTED: commands.vim's included a
`space` (links_space_char) key diary.vim's lacked. Unified to the superset
so callers reading `.space` keep working; diary callers ignore the extra key.
Also refreshes the stale plugin/nuwiki.vim header ("all logic lives in the
Rust language server" → thin client; server is nuwiki-rs, downloaded).
Verified: 18-case heading battery in headless vim + full editor harness 10/10.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -468,15 +468,7 @@ endfunction
|
|||||||
" ===== Heading navigation (pure VimL) =====
|
" ===== Heading navigation (pure VimL) =====
|
||||||
|
|
||||||
function! s:heading_level(line) abort
|
function! s:heading_level(line) abort
|
||||||
let l:lead = matchstr(a:line, '^\s*\zs=\+\ze\s')
|
return nuwiki#util#heading_level(a:line)
|
||||||
if l:lead ==# ''
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let l:trail = matchstr(a:line, '\s\zs=\+\ze\s*$')
|
|
||||||
if len(l:trail) != len(l:lead)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return len(l:lead)
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:current_heading_level() abort
|
function! s:current_heading_level() abort
|
||||||
@@ -593,21 +585,7 @@ endfunction
|
|||||||
" upstream g:vimwiki_list both work — and falls back to the scalar g:nuwiki_*
|
" upstream g:vimwiki_list both work — and falls back to the scalar g:nuwiki_*
|
||||||
" vars (single-wiki shorthand) and finally built-in defaults.
|
" vars (single-wiki shorthand) and finally built-in defaults.
|
||||||
function! s:wiki_cfg(n) abort
|
function! s:wiki_cfg(n) abort
|
||||||
let l:wikis = nuwiki#config#wikis()
|
return nuwiki#util#wiki_cfg(a:n)
|
||||||
let l:w = (a:n >= 0 && a:n < len(l:wikis)) ? l:wikis[a:n] : {}
|
|
||||||
let l:root = expand(get(l:w, 'root',
|
|
||||||
\ get(g:, 'nuwiki_wiki_root', '~/vimwiki')))
|
|
||||||
let l:ext = get(l:w, 'file_extension',
|
|
||||||
\ get(g:, 'nuwiki_file_extension', '.wiki'))
|
|
||||||
if l:ext[0] !=# '.' | let l:ext = '.' . l:ext | endif
|
|
||||||
let l:idx = get(l:w, 'index', 'index')
|
|
||||||
let l:diary_rel = get(l:w, 'diary_rel_path',
|
|
||||||
\ get(g:, 'nuwiki_diary_rel_path', 'diary'))
|
|
||||||
let l:diary_idx = get(l:w, 'diary_index', 'diary')
|
|
||||||
let l:space = get(l:w, 'links_space_char',
|
|
||||||
\ get(g:, 'nuwiki_links_space_char', ' '))
|
|
||||||
return { 'root': l:root, 'ext': l:ext, 'idx': l:idx,
|
|
||||||
\ 'diary_rel': l:diary_rel, 'diary_idx': l:diary_idx, 'space': l:space }
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Build the list of configured wikis as {name, root, ext, idx, diary_rel,
|
" Build the list of configured wikis as {name, root, ext, idx, diary_rel,
|
||||||
@@ -1178,7 +1156,7 @@ endfunction
|
|||||||
" matches `nuwiki-lsp/src/commands.rs::ops::render_aligned_table` (nuwiki-rs repo).
|
" matches `nuwiki-lsp/src/commands.rs::ops::render_aligned_table` (nuwiki-rs repo).
|
||||||
|
|
||||||
function! s:is_table_row(line) abort
|
function! s:is_table_row(line) abort
|
||||||
return a:line =~# '^\s*|.*|\s*$'
|
return nuwiki#util#is_table_row(a:line)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:table_cell_starts(line) abort
|
function! s:table_cell_starts(line) abort
|
||||||
|
|||||||
@@ -106,17 +106,5 @@ endfunction
|
|||||||
" nuwiki#config#wikis() so g:nuwiki_wikis AND an upstream g:vimwiki_list both
|
" nuwiki#config#wikis() so g:nuwiki_wikis AND an upstream g:vimwiki_list both
|
||||||
" work, falling back to the scalar g:nuwiki_* single-wiki shorthand.
|
" work, falling back to the scalar g:nuwiki_* single-wiki shorthand.
|
||||||
function! s:wiki_cfg(n) abort
|
function! s:wiki_cfg(n) abort
|
||||||
let l:wikis = nuwiki#config#wikis()
|
return nuwiki#util#wiki_cfg(a:n)
|
||||||
let l:w = (a:n >= 0 && a:n < len(l:wikis)) ? l:wikis[a:n] : {}
|
|
||||||
let l:root = expand(get(l:w, 'root',
|
|
||||||
\ get(g:, 'nuwiki_wiki_root', '~/vimwiki')))
|
|
||||||
let l:ext = get(l:w, 'file_extension',
|
|
||||||
\ get(g:, 'nuwiki_file_extension', '.wiki'))
|
|
||||||
if l:ext[0] !=# '.' | let l:ext = '.' . l:ext | endif
|
|
||||||
let l:idx = get(l:w, 'index', 'index')
|
|
||||||
let l:diary_rel = get(l:w, 'diary_rel_path',
|
|
||||||
\ get(g:, 'nuwiki_diary_rel_path', 'diary'))
|
|
||||||
let l:diary_idx = get(l:w, 'diary_index', 'diary')
|
|
||||||
return { 'root': l:root, 'ext': l:ext, 'idx': l:idx,
|
|
||||||
\ 'diary_rel': l:diary_rel, 'diary_idx': l:diary_idx }
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|||||||
@@ -13,15 +13,7 @@
|
|||||||
" end of buffer).
|
" end of buffer).
|
||||||
|
|
||||||
function! s:heading_level(line) abort
|
function! s:heading_level(line) abort
|
||||||
let l:lead = matchstr(a:line, '^\s*\zs=\+\ze\s')
|
return nuwiki#util#heading_level(a:line)
|
||||||
if empty(l:lead) | return 0 | endif
|
|
||||||
let l:lvl = strlen(l:lead)
|
|
||||||
if l:lvl > 6 | return 0 | endif
|
|
||||||
let l:trail = matchstr(a:line, '\s\zs=\+\ze\s*$')
|
|
||||||
if empty(l:trail) || strlen(l:trail) != l:lvl
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return l:lvl
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! nuwiki#folding#expr() abort
|
function! nuwiki#folding#expr() abort
|
||||||
|
|||||||
@@ -24,15 +24,7 @@
|
|||||||
" ===== Heading helpers =====
|
" ===== Heading helpers =====
|
||||||
|
|
||||||
function! s:heading_level(line) abort
|
function! s:heading_level(line) abort
|
||||||
let l:lead = matchstr(a:line, '^\s*\zs=\+\ze\s')
|
return nuwiki#util#heading_level(a:line)
|
||||||
if empty(l:lead) | return 0 | endif
|
|
||||||
let l:lvl = strlen(l:lead)
|
|
||||||
if l:lvl > 6 | return 0 | endif
|
|
||||||
let l:trail = matchstr(a:line, '\s\zs=\+\ze\s*$')
|
|
||||||
if empty(l:trail) || strlen(l:trail) != l:lvl
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return l:lvl
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Returns `[start, end]` line numbers, or `[]` if no heading found.
|
" Returns `[start, end]` line numbers, or `[]` if no heading found.
|
||||||
@@ -130,7 +122,7 @@ endfunction
|
|||||||
" ===== Table cell / column =====
|
" ===== Table cell / column =====
|
||||||
|
|
||||||
function! s:is_table_row(line) abort
|
function! s:is_table_row(line) abort
|
||||||
return a:line =~# '^\s*|.*|\s*$'
|
return nuwiki#util#is_table_row(a:line)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Returns a list of `[start_col, end_col]` byte positions (1-based,
|
" Returns a list of `[start_col, end_col]` byte positions (1-based,
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
" autoload/nuwiki/util.vim — small shared helpers used across the VimL client
|
||||||
|
" layers (commands, folding, textobjects, diary). Keeps the formerly
|
||||||
|
" copy-pasted heading / table-row / wiki-config logic in one place. Mirrors
|
||||||
|
" lua/nuwiki/util.lua so both clients behave identically.
|
||||||
|
|
||||||
|
" Heading level of `line` (1-6), or 0 when it isn't a heading. Mirrors the
|
||||||
|
" server lexer: balanced leading/trailing runs of `=` around a non-empty
|
||||||
|
" title, capped at level 6. Accepts both the spaced (`== H ==`) and spaceless
|
||||||
|
" (`==H==`) forms, matching vimwiki.
|
||||||
|
function! nuwiki#util#heading_level(line) abort
|
||||||
|
let l:lead = matchstr(a:line, '^\s*\zs=\+')
|
||||||
|
if empty(l:lead)
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
let l:lvl = strlen(l:lead)
|
||||||
|
if l:lvl > 6
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
" Same-length trailing run of `=` at end of line (after optional trailing ws).
|
||||||
|
let l:trail = matchstr(a:line, '=\+\ze\s*$')
|
||||||
|
if empty(l:trail) || strlen(l:trail) != l:lvl
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
" Non-empty title between the runs (rules out marker-only lines like
|
||||||
|
" `======`). `.\{-}` is non-greedy so the `=\+` runs keep their length.
|
||||||
|
let l:body = matchstr(a:line, '^\s*=\+\zs.\{-}\ze=\+\s*$')
|
||||||
|
if l:body =~# '^\s*$'
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
return l:lvl
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" True when `line` looks like a table row (`| … |`).
|
||||||
|
function! nuwiki#util#is_table_row(line) abort
|
||||||
|
return a:line =~# '^\s*|.*|\s*$'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Resolve the config dict for wiki #n (0-based), falling back to the scalar
|
||||||
|
" g:nuwiki_* globals. Returns root/ext/idx/diary_rel/diary_idx/space.
|
||||||
|
function! nuwiki#util#wiki_cfg(n) abort
|
||||||
|
let l:wikis = nuwiki#config#wikis()
|
||||||
|
let l:w = (a:n >= 0 && a:n < len(l:wikis)) ? l:wikis[a:n] : {}
|
||||||
|
let l:root = expand(get(l:w, 'root',
|
||||||
|
\ get(g:, 'nuwiki_wiki_root', '~/vimwiki')))
|
||||||
|
let l:ext = get(l:w, 'file_extension',
|
||||||
|
\ get(g:, 'nuwiki_file_extension', '.wiki'))
|
||||||
|
if l:ext[0] !=# '.' | let l:ext = '.' . l:ext | endif
|
||||||
|
let l:idx = get(l:w, 'index', 'index')
|
||||||
|
let l:diary_rel = get(l:w, 'diary_rel_path',
|
||||||
|
\ get(g:, 'nuwiki_diary_rel_path', 'diary'))
|
||||||
|
let l:diary_idx = get(l:w, 'diary_index', 'diary')
|
||||||
|
let l:space = get(l:w, 'links_space_char',
|
||||||
|
\ get(g:, 'nuwiki_links_space_char', ' '))
|
||||||
|
return { 'root': l:root, 'ext': l:ext, 'idx': l:idx,
|
||||||
|
\ 'diary_rel': l:diary_rel, 'diary_idx': l:diary_idx, 'space': l:space }
|
||||||
|
endfunction
|
||||||
+3
-2
@@ -4,8 +4,9 @@
|
|||||||
" their config (lazy.nvim does this automatically through `opts`). On Vim
|
" their config (lazy.nvim does this automatically through `opts`). On Vim
|
||||||
" we start the LSP client when a vimwiki buffer is loaded.
|
" we start the LSP client when a vimwiki buffer is loaded.
|
||||||
"
|
"
|
||||||
" This file contains wiring only — all logic lives in
|
" This file contains wiring only. The editor layers (VimL + Lua) are thin
|
||||||
" the Rust language server.
|
" clients; the heavy lifting is done by the nuwiki-ls language server, which
|
||||||
|
" is built from the separate nuwiki-rs repo and downloaded at install time.
|
||||||
|
|
||||||
if exists('g:loaded_nuwiki')
|
if exists('g:loaded_nuwiki')
|
||||||
finish
|
finish
|
||||||
|
|||||||
Reference in New Issue
Block a user