fix(vim): buffer commands honour g:vimwiki_list (<Leader>ww opened ~/vimwiki)
The g:vimwiki_* drop-in only fed the LSP payload (lsp.vim s:settings). The buffer-side commands — <Leader>ww (wiki_index), :VimwikiSearch, auto_chdir, diary, completion — resolve the wiki list independently via s:wiki_cfg / nuwiki#commands#wiki_list, which read only g:nuwiki_wikis / g:nuwiki_wiki_root. So with a g:vimwiki_list config the server knew the wikis but <Leader>ww fell back to the default ~/vimwiki and opened an empty index. Extract the resolution into a single source of truth, autoload/nuwiki/config.vim (nuwiki#config#wikis / #scalar_globals), which resolves g:nuwiki_wikis or an upstream g:vimwiki_list and folds the global scalar defaults. lsp.vim (payload), commands.vim, and diary.vim all route through it — also dedups the s:wiki_cfg copy that lived in both commands.vim and diary.vim. Regression guard in test-vimwiki-compat-vim: nuwiki#commands#wiki_list() must resolve the g:vimwiki_list roots (21 checks). All Vim harnesses + config-parity goldens green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -588,14 +588,13 @@ endfunction
|
|||||||
" open their wiki from any buffer. Files are opened directly from config;
|
" open their wiki from any buffer. Files are opened directly from config;
|
||||||
" the LSP auto-starts via the FileType autocmd once the buffer loads.
|
" the LSP auto-starts via the FileType autocmd once the buffer loads.
|
||||||
|
|
||||||
" Return a dict with {root, ext, idx, diary_rel, diary_idx} for wiki #n
|
" Return a dict with {root, ext, idx, diary_rel, diary_idx, space} for wiki #n
|
||||||
" (0-based). Prefers g:nuwiki_wikis[n]; falls back to scalar g:nuwiki_*
|
" (0-based). Resolves through nuwiki#config#wikis() — so g:nuwiki_wikis AND an
|
||||||
" vars and finally to built-in defaults.
|
" upstream g:vimwiki_list both work — and falls back to the scalar g:nuwiki_*
|
||||||
|
" vars (single-wiki shorthand) and finally built-in defaults.
|
||||||
function! s:wiki_cfg(n) abort
|
function! s:wiki_cfg(n) abort
|
||||||
let l:w = {}
|
let l:wikis = nuwiki#config#wikis()
|
||||||
if exists('g:nuwiki_wikis') && len(g:nuwiki_wikis) > a:n
|
let l:w = (a:n >= 0 && a:n < len(l:wikis)) ? l:wikis[a:n] : {}
|
||||||
let l:w = g:nuwiki_wikis[a:n]
|
|
||||||
endif
|
|
||||||
let l:root = expand(get(l:w, 'root',
|
let l:root = expand(get(l:w, 'root',
|
||||||
\ get(g:, 'nuwiki_wiki_root', '~/vimwiki')))
|
\ get(g:, 'nuwiki_wiki_root', '~/vimwiki')))
|
||||||
let l:ext = get(l:w, 'file_extension',
|
let l:ext = get(l:w, 'file_extension',
|
||||||
@@ -612,14 +611,15 @@ function! s:wiki_cfg(n) abort
|
|||||||
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,
|
||||||
" diary_idx} dicts, straight from config — no LSP round-trip. Drives the wiki
|
" diary_idx, space} dicts, straight from config — no LSP round-trip. Drives the
|
||||||
" picker so it works before any wiki buffer (and therefore the server) exists.
|
" wiki picker so it works before any wiki buffer (and therefore the server)
|
||||||
" Falls back to a single entry from the scalar `g:nuwiki_wiki_root` config.
|
" exists. Falls back to a single entry from the scalar `g:nuwiki_wiki_root`.
|
||||||
function! nuwiki#commands#wiki_list() abort
|
function! nuwiki#commands#wiki_list() abort
|
||||||
|
let l:wikis = nuwiki#config#wikis()
|
||||||
let l:list = []
|
let l:list = []
|
||||||
if exists('g:nuwiki_wikis') && !empty(g:nuwiki_wikis)
|
if !empty(l:wikis)
|
||||||
let l:n = 0
|
let l:n = 0
|
||||||
for l:w in g:nuwiki_wikis
|
for l:w in l:wikis
|
||||||
let l:c = s:wiki_cfg(l:n)
|
let l:c = s:wiki_cfg(l:n)
|
||||||
let l:c['name'] = get(l:w, 'name', fnamemodify(l:c.root, ':t'))
|
let l:c['name'] = get(l:w, 'name', fnamemodify(l:c.root, ':t'))
|
||||||
call add(l:list, l:c)
|
call add(l:list, l:c)
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
" autoload/nuwiki/config.vim — single source of truth for the configured wiki
|
||||||
|
" list, shared by the LSP payload (lsp.vim) and the buffer-side commands
|
||||||
|
" (commands.vim, diary.vim, complete.vim).
|
||||||
|
"
|
||||||
|
" Resolves wikis from g:nuwiki_wikis (native) or, when that's unset, an upstream
|
||||||
|
" g:vimwiki_list (drop-in compatibility), translating upstream key names and
|
||||||
|
" folding the global scalar defaults (g:vimwiki_* / g:nuwiki_*) into each entry.
|
||||||
|
" Everything downstream — `<Leader>ww`, link resolution, the server payload —
|
||||||
|
" then sees the same wikis.
|
||||||
|
|
||||||
|
" Per-wiki dict keys: upstream `g:vimwiki_list[i]` key -> nuwiki/server key.
|
||||||
|
let s:vimwiki_wiki_map = {
|
||||||
|
\ 'path': 'root',
|
||||||
|
\ 'path_html': 'html_path',
|
||||||
|
\ 'template_path': 'template_path',
|
||||||
|
\ 'template_default': 'template_default',
|
||||||
|
\ 'template_ext': 'template_ext',
|
||||||
|
\ 'css_name': 'css_name',
|
||||||
|
\ 'auto_export': 'auto_export',
|
||||||
|
\ 'auto_toc': 'auto_toc',
|
||||||
|
\ 'syntax': 'syntax',
|
||||||
|
\ 'ext': 'file_extension',
|
||||||
|
\ 'index': 'index',
|
||||||
|
\ 'diary_rel_path': 'diary_rel_path',
|
||||||
|
\ 'diary_index': 'diary_index',
|
||||||
|
\ 'name': 'name',
|
||||||
|
\ }
|
||||||
|
|
||||||
|
" Global scalar settings vimwiki applies to every wiki (via wikilocal
|
||||||
|
" defaults): upstream suffix (`g:vimwiki_<suffix>`) -> nuwiki/server key.
|
||||||
|
let s:scalar_global_map = {
|
||||||
|
\ 'toc_header': 'toc_header',
|
||||||
|
\ 'toc_header_level': 'toc_header_level',
|
||||||
|
\ 'toc_link_format': 'toc_link_format',
|
||||||
|
\ 'links_header': 'links_header',
|
||||||
|
\ 'links_header_level': 'links_header_level',
|
||||||
|
\ 'tags_header': 'tags_header',
|
||||||
|
\ 'tags_header_level': 'tags_header_level',
|
||||||
|
\ 'html_header_numbering': 'html_header_numbering',
|
||||||
|
\ 'html_header_numbering_sym': 'html_header_numbering_sym',
|
||||||
|
\ 'links_space_char': 'links_space_char',
|
||||||
|
\ 'list_margin': 'list_margin',
|
||||||
|
\ 'listsyms': 'listsyms',
|
||||||
|
\ 'listsym_rejected': 'listsym_rejected',
|
||||||
|
\ 'auto_export': 'auto_export',
|
||||||
|
\ 'auto_toc': 'auto_toc',
|
||||||
|
\ 'auto_generate_links': 'auto_generate_links',
|
||||||
|
\ 'auto_generate_tags': 'auto_generate_tags',
|
||||||
|
\ 'auto_diary_index': 'auto_diary_index',
|
||||||
|
\ }
|
||||||
|
|
||||||
|
" Resolve the per-wiki scalar globals: vimwiki values first (compat), then
|
||||||
|
" nuwiki-native `g:nuwiki_<key>` overrides on top.
|
||||||
|
function! nuwiki#config#scalar_globals() abort
|
||||||
|
let l:g = {}
|
||||||
|
for [l:src, l:dst] in items(s:scalar_global_map)
|
||||||
|
if exists('g:vimwiki_' . l:src)
|
||||||
|
let l:g[l:dst] = get(g:, 'vimwiki_' . l:src)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
for l:dst in values(s:scalar_global_map)
|
||||||
|
if exists('g:nuwiki_' . l:dst)
|
||||||
|
let l:g[l:dst] = get(g:, 'nuwiki_' . l:dst)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
return l:g
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Translate an upstream g:vimwiki_list into nuwiki's wiki list, folding the
|
||||||
|
" given global scalars into each entry. Returns [] when unset/malformed.
|
||||||
|
function! s:wikis_from_vimwiki(globals) abort
|
||||||
|
if !exists('g:vimwiki_list') || type(g:vimwiki_list) != type([]) || empty(g:vimwiki_list)
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
let l:wikis = []
|
||||||
|
for l:vw in g:vimwiki_list
|
||||||
|
if type(l:vw) != type({}) | continue | endif
|
||||||
|
let l:w = copy(a:globals)
|
||||||
|
for [l:src, l:dst] in items(s:vimwiki_wiki_map)
|
||||||
|
if has_key(l:vw, l:src)
|
||||||
|
let l:w[l:dst] = l:vw[l:src]
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
if has_key(l:w, 'root')
|
||||||
|
call add(l:wikis, l:w)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
return l:wikis
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" The configured wikis as normalized dicts (nuwiki/server key names), with the
|
||||||
|
" global scalar defaults folded in (per-wiki value wins). Priority:
|
||||||
|
" 1. g:nuwiki_wikis (native)
|
||||||
|
" 2. g:vimwiki_list (upstream drop-in)
|
||||||
|
" Returns [] when neither is set — callers fall back to the single-wiki
|
||||||
|
" shorthand (g:nuwiki_wiki_root).
|
||||||
|
function! nuwiki#config#wikis() abort
|
||||||
|
let l:globals = nuwiki#config#scalar_globals()
|
||||||
|
if exists('g:nuwiki_wikis') && !empty(g:nuwiki_wikis)
|
||||||
|
return map(copy(g:nuwiki_wikis), {_, w -> extend(copy(l:globals), w, 'force')})
|
||||||
|
endif
|
||||||
|
return s:wikis_from_vimwiki(l:globals)
|
||||||
|
endfunction
|
||||||
@@ -75,13 +75,12 @@ function! nuwiki#diary#calendar_sign(day, month, year) abort
|
|||||||
return ''
|
return ''
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Helper: get wiki configuration for wiki n (0-based).
|
" Helper: get wiki configuration for wiki n (0-based). Resolves through
|
||||||
" Mirrors the same logic used by nuwiki#commands#open_diary_path etc.
|
" 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.
|
||||||
function! s:wiki_cfg(n) abort
|
function! s:wiki_cfg(n) abort
|
||||||
let l:w = {}
|
let l:wikis = nuwiki#config#wikis()
|
||||||
if exists('g:nuwiki_wikis') && len(g:nuwiki_wikis) > a:n
|
let l:w = (a:n >= 0 && a:n < len(l:wikis)) ? l:wikis[a:n] : {}
|
||||||
let l:w = g:nuwiki_wikis[a:n]
|
|
||||||
endif
|
|
||||||
let l:root = expand(get(l:w, 'root',
|
let l:root = expand(get(l:w, 'root',
|
||||||
\ get(g:, 'nuwiki_wiki_root', '~/vimwiki')))
|
\ get(g:, 'nuwiki_wiki_root', '~/vimwiki')))
|
||||||
let l:ext = get(l:w, 'file_extension',
|
let l:ext = get(l:w, 'file_extension',
|
||||||
|
|||||||
+9
-113
@@ -12,97 +12,6 @@ let s:plugin_root = fnamemodify(resolve(expand('<sfile>:p')), ':h:h:h')
|
|||||||
|
|
||||||
let s:started = 0
|
let s:started = 0
|
||||||
|
|
||||||
" ===== Upstream vimwiki config compatibility =====
|
|
||||||
"
|
|
||||||
" nuwiki is a drop-in vimwiki replacement, so a user who keeps their original
|
|
||||||
" `g:vimwiki_list` + `g:vimwiki_*` globals shouldn't have to rewrite anything.
|
|
||||||
" These tables translate the upstream names into the server's config schema.
|
|
||||||
" nuwiki-native config (`g:nuwiki_wikis` / `g:nuwiki_*`) always wins.
|
|
||||||
|
|
||||||
" Per-wiki dict keys: upstream `g:vimwiki_list[i]` key -> server key.
|
|
||||||
let s:vimwiki_wiki_map = {
|
|
||||||
\ 'path': 'root',
|
|
||||||
\ 'path_html': 'html_path',
|
|
||||||
\ 'template_path': 'template_path',
|
|
||||||
\ 'template_default': 'template_default',
|
|
||||||
\ 'template_ext': 'template_ext',
|
|
||||||
\ 'css_name': 'css_name',
|
|
||||||
\ 'auto_export': 'auto_export',
|
|
||||||
\ 'auto_toc': 'auto_toc',
|
|
||||||
\ 'syntax': 'syntax',
|
|
||||||
\ 'ext': 'file_extension',
|
|
||||||
\ 'index': 'index',
|
|
||||||
\ 'diary_rel_path': 'diary_rel_path',
|
|
||||||
\ 'diary_index': 'diary_index',
|
|
||||||
\ 'name': 'name',
|
|
||||||
\ }
|
|
||||||
|
|
||||||
" Global scalar settings vimwiki applies to every wiki (via wikilocal
|
|
||||||
" defaults): upstream suffix (`g:vimwiki_<suffix>`) -> server key. The server
|
|
||||||
" reads these per-wiki, so we fold them into each wiki entry (and into the
|
|
||||||
" single-wiki shorthand payload).
|
|
||||||
let s:scalar_global_map = {
|
|
||||||
\ 'toc_header': 'toc_header',
|
|
||||||
\ 'toc_header_level': 'toc_header_level',
|
|
||||||
\ 'toc_link_format': 'toc_link_format',
|
|
||||||
\ 'links_header': 'links_header',
|
|
||||||
\ 'links_header_level': 'links_header_level',
|
|
||||||
\ 'tags_header': 'tags_header',
|
|
||||||
\ 'tags_header_level': 'tags_header_level',
|
|
||||||
\ 'html_header_numbering': 'html_header_numbering',
|
|
||||||
\ 'html_header_numbering_sym': 'html_header_numbering_sym',
|
|
||||||
\ 'links_space_char': 'links_space_char',
|
|
||||||
\ 'list_margin': 'list_margin',
|
|
||||||
\ 'listsyms': 'listsyms',
|
|
||||||
\ 'listsym_rejected': 'listsym_rejected',
|
|
||||||
\ 'auto_export': 'auto_export',
|
|
||||||
\ 'auto_toc': 'auto_toc',
|
|
||||||
\ 'auto_generate_links': 'auto_generate_links',
|
|
||||||
\ 'auto_generate_tags': 'auto_generate_tags',
|
|
||||||
\ 'auto_diary_index': 'auto_diary_index',
|
|
||||||
\ }
|
|
||||||
|
|
||||||
" Resolve the per-wiki scalar globals: vimwiki values first (compat), then
|
|
||||||
" nuwiki-native `g:nuwiki_<key>` overrides on top.
|
|
||||||
function! s:scalar_globals() abort
|
|
||||||
let l:g = {}
|
|
||||||
for [l:src, l:dst] in items(s:scalar_global_map)
|
|
||||||
if exists('g:vimwiki_' . l:src)
|
|
||||||
let l:g[l:dst] = get(g:, 'vimwiki_' . l:src)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
for l:dst in values(s:scalar_global_map)
|
|
||||||
if exists('g:nuwiki_' . l:dst)
|
|
||||||
let l:g[l:dst] = get(g:, 'nuwiki_' . l:dst)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return l:g
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Build nuwiki's `wikis` list from an upstream `g:vimwiki_list`, folding the
|
|
||||||
" global scalar settings into each entry. Returns [] when unset/malformed.
|
|
||||||
function! s:wikis_from_vimwiki() abort
|
|
||||||
if !exists('g:vimwiki_list') || type(g:vimwiki_list) != type([]) || empty(g:vimwiki_list)
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
let l:globals = s:scalar_globals()
|
|
||||||
let l:wikis = []
|
|
||||||
for l:vw in g:vimwiki_list
|
|
||||||
if type(l:vw) != type({}) | continue | endif
|
|
||||||
let l:w = copy(l:globals)
|
|
||||||
for [l:src, l:dst] in items(s:vimwiki_wiki_map)
|
|
||||||
if has_key(l:vw, l:src)
|
|
||||||
let l:w[l:dst] = l:vw[l:src]
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
" A wiki needs a root; skip entries without one.
|
|
||||||
if has_key(l:w, 'root')
|
|
||||||
call add(l:wikis, l:w)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return l:wikis
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! nuwiki#lsp#start() abort
|
function! nuwiki#lsp#start() abort
|
||||||
if s:started
|
if s:started
|
||||||
return
|
return
|
||||||
@@ -225,29 +134,16 @@ function! s:settings() abort
|
|||||||
\ 'link_severity': get(g:, 'nuwiki_link_severity', 'warn'),
|
\ 'link_severity': get(g:, 'nuwiki_link_severity', 'warn'),
|
||||||
\ },
|
\ },
|
||||||
\ }
|
\ }
|
||||||
" Global scalar settings (g:vimwiki_* then g:nuwiki_* overrides) act as
|
" Wiki list comes from the shared resolver (nuwiki#config#wikis), so the
|
||||||
" defaults applied to every wiki, vimwiki-style. A per-wiki value always
|
" server payload and the buffer-side commands agree on which wikis exist —
|
||||||
" wins. Resolved once and folded into whichever wiki shape we send.
|
" native g:nuwiki_wikis or an upstream g:vimwiki_list, globals already folded.
|
||||||
let l:globals = s:scalar_globals()
|
let l:wikis = nuwiki#config#wikis()
|
||||||
|
if !empty(l:wikis)
|
||||||
" Wiki list resolution, in priority order:
|
let l:cfg['wikis'] = l:wikis
|
||||||
" 1. g:nuwiki_wikis (native multi-wiki config)
|
|
||||||
" 2. g:vimwiki_list (upstream vimwiki config — drop-in compat)
|
|
||||||
" 3. wiki_root shorthand (single wiki)
|
|
||||||
" Without a list the server only sees wiki_root and resolves links relative
|
|
||||||
" to that directory instead of each individual wiki's root.
|
|
||||||
if exists('g:nuwiki_wikis') && !empty(g:nuwiki_wikis)
|
|
||||||
let l:cfg['wikis'] = map(copy(g:nuwiki_wikis),
|
|
||||||
\ {_, w -> extend(copy(l:globals), w, 'force')})
|
|
||||||
else
|
else
|
||||||
let l:vw_wikis = s:wikis_from_vimwiki()
|
" Single-wiki shorthand: fold the global scalars into the top-level payload
|
||||||
if !empty(l:vw_wikis)
|
" so the server's single-wiki desugaring honours them.
|
||||||
let l:cfg['wikis'] = l:vw_wikis
|
call extend(l:cfg, nuwiki#config#scalar_globals(), 'force')
|
||||||
else
|
|
||||||
" Single-wiki shorthand: fold the global scalars into the top-level
|
|
||||||
" payload so the server's single-wiki desugaring honours them.
|
|
||||||
call extend(l:cfg, l:globals, 'force')
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
return l:cfg
|
return l:cfg
|
||||||
endfunction
|
endfunction
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ call s:check('w0 numbering_sym', get(s:w0, 'html_header_numbering_sym', '')
|
|||||||
call s:check('w1 root', get(s:w1, 'root', '') ==# '~/.vimwiki/ifood_wiki')
|
call s:check('w1 root', get(s:w1, 'root', '') ==# '~/.vimwiki/ifood_wiki')
|
||||||
call s:check('w1 globals applied', get(s:w1, 'toc_header_level', 0) == 2)
|
call s:check('w1 globals applied', get(s:w1, 'toc_header_level', 0) == 2)
|
||||||
|
|
||||||
|
" The buffer-side commands (e.g. <Leader>ww) must resolve the SAME wikis from
|
||||||
|
" g:vimwiki_list — not just the LSP payload. Regression guard for "<Leader>ww
|
||||||
|
" opens an empty ~/vimwiki".
|
||||||
|
let s:wl = nuwiki#commands#wiki_list()
|
||||||
|
call s:check('wiki_list sees vimwiki config', len(s:wl) == 2)
|
||||||
|
call s:check('wiki_list w0 root', len(s:wl) >= 1 && s:wl[0].root ==# expand('~/.vimwiki/personal_wiki'))
|
||||||
|
call s:check('wiki_list w1 root', len(s:wl) >= 2 && s:wl[1].root ==# expand('~/.vimwiki/ifood_wiki'))
|
||||||
|
|
||||||
" ----- nuwiki-native config wins over vimwiki -----
|
" ----- nuwiki-native config wins over vimwiki -----
|
||||||
let g:nuwiki_wikis = [{'root': '~/native', 'name': 'native'}]
|
let g:nuwiki_wikis = [{'root': '~/native', 'name': 'native'}]
|
||||||
let s:cfg2 = nuwiki#lsp#settings()
|
let s:cfg2 = nuwiki#lsp#settings()
|
||||||
|
|||||||
Reference in New Issue
Block a user