feat(config): read g:vimwiki_list on Neovim too (lazy.nvim drop-in)
The g:vimwiki_* drop-in was Vim-only: the Lua client read only setup() opts and g:nuwiki_wikis, so swapping the vimwiki plugin for nuwiki under lazy.nvim left the existing vim.g.vimwiki_list ignored and nuwiki pointed at the default ~/vimwiki. Mirror autoload/nuwiki/config.vim on the Lua side: config.lua now owns a single resolver (M.wikis / M.scalar_globals) that resolves setup() wikis → g:nuwiki_wikis → g:vimwiki_list (translating path->root, path_html->html_path, template_*, ext->file_extension, …) and folds the global scalar defaults (g:vimwiki_* then g:nuwiki_* then explicit setup() values; built-in defaults excluded). lsp.lua (payload) and wiki_cfg/wiki_list (buffer commands) both route through it, so the server and <Leader>ww agree on the wikis. Extends test-global-shorthand (15 checks) with the vimwiki_list drop-in + buffer-command resolution + native-wins cases. Config-parity goldens and keymap harnesses green on both clients. README + known-issues updated (drop-in is now Vim & Neovim). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -679,15 +679,17 @@ match vimwiki. To migrate:
|
|||||||
3. Keep your existing config, or point `wiki_root` / `wikis[i].root` at
|
3. Keep your existing config, or point `wiki_root` / `wikis[i].root` at
|
||||||
your directory.
|
your directory.
|
||||||
|
|
||||||
**Existing `g:vimwiki_list` config works as-is (Vim).** When you haven't
|
**Existing `g:vimwiki_list` config works as-is (Vim & Neovim).** When you
|
||||||
configured nuwiki natively (`g:nuwiki_wikis` / `g:nuwiki_*`), the Vim
|
haven't configured nuwiki natively (`g:nuwiki_wikis` / `setup()` / `g:nuwiki_*`),
|
||||||
client reads your upstream `g:vimwiki_list` and `g:vimwiki_*` globals and
|
both clients read your upstream `g:vimwiki_list` and `g:vimwiki_*` globals and
|
||||||
translates them: each wiki's `path`/`path_html`/`template_*`/`auto_export`
|
translate them: each wiki's `path`/`path_html`/`template_*`/`auto_export`
|
||||||
plus globals like `toc_header_level`, `html_header_numbering`,
|
plus globals like `toc_header_level`, `html_header_numbering`,
|
||||||
`html_header_numbering_sym`, `links_space_char`, and `list_margin`.
|
`html_header_numbering_sym`, `links_space_char`, and `list_margin`.
|
||||||
Native `g:nuwiki_*` config always takes precedence. (Settings nuwiki
|
Native config always takes precedence. (Settings nuwiki implements
|
||||||
implements differently — see [`known-issues.md`](./known-issues.md) — are
|
differently — see [`known-issues.md`](./known-issues.md) — are ignored.)
|
||||||
ignored.)
|
On Neovim with lazy.nvim, swap the `vimwiki` plugin spec for nuwiki and
|
||||||
|
call `require('nuwiki').setup()` — your `vim.g.vimwiki_list` is picked up
|
||||||
|
unchanged.
|
||||||
|
|
||||||
Existing pages, diary entries, tags, and templates work without
|
Existing pages, diary entries, tags, and templates work without
|
||||||
modification. The first workspace scan after launch may show an empty
|
modification. The first workspace scan after launch may show an empty
|
||||||
|
|||||||
@@ -48,6 +48,29 @@ local io3 = lsp.init_options()
|
|||||||
check('g:nuwiki_ global folds', io3.wikis[1].toc_header_level == 5)
|
check('g:nuwiki_ global folds', io3.wikis[1].toc_header_level == 5)
|
||||||
vim.g.nuwiki_toc_header_level = nil
|
vim.g.nuwiki_toc_header_level = nil
|
||||||
|
|
||||||
|
-- ----- upstream vim.g.vimwiki_list drop-in (the lazy.nvim vimwiki-swap case) --
|
||||||
|
config.apply({}) -- setup() with no native config
|
||||||
|
vim.g.vimwiki_list = {
|
||||||
|
{ path = '~/.vimwiki/personal', path_html = '~/public_html/personal', auto_export = 1 },
|
||||||
|
{ path = '~/.vimwiki/work' },
|
||||||
|
}
|
||||||
|
vim.g.vimwiki_toc_header_level = 2
|
||||||
|
local io4 = lsp.init_options()
|
||||||
|
check('vimwiki_list -> 2 wikis', io4.wikis ~= nil and #io4.wikis == 2)
|
||||||
|
check('path -> root', io4.wikis[1].root == '~/.vimwiki/personal')
|
||||||
|
check('path_html -> html_path', io4.wikis[1].html_path == '~/public_html/personal')
|
||||||
|
check('vimwiki global folds', io4.wikis[1].toc_header_level == 2)
|
||||||
|
check('w2 root', io4.wikis[2].root == '~/.vimwiki/work')
|
||||||
|
-- Buffer-side commands (<Leader>ww) resolve the same wikis.
|
||||||
|
check('wiki_list reads vimwiki_list', config.wiki_list()[1].root == '~/.vimwiki/personal')
|
||||||
|
-- Native g:nuwiki_wikis wins over g:vimwiki_list.
|
||||||
|
vim.g.nuwiki_wikis = { { root = '~/native', name = 'native' } }
|
||||||
|
local io5 = lsp.init_options()
|
||||||
|
check('native g:nuwiki_wikis wins', #io5.wikis == 1 and io5.wikis[1].root == '~/native')
|
||||||
|
vim.g.nuwiki_wikis = nil
|
||||||
|
vim.g.vimwiki_list = nil
|
||||||
|
vim.g.vimwiki_toc_header_level = nil
|
||||||
|
|
||||||
local f = assert(io.open(os.getenv('NUWIKI_GS_OUT'), 'w'))
|
local f = assert(io.open(os.getenv('NUWIKI_GS_OUT'), 'w'))
|
||||||
f:write(table.concat(out, '\n') .. '\n')
|
f:write(table.concat(out, '\n') .. '\n')
|
||||||
f:close()
|
f:close()
|
||||||
|
|||||||
+8
-7
@@ -128,15 +128,16 @@ correct as-is; the deferral is a deliberate risk/reward call.
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- **Upstream `g:vimwiki_list` config (Vim).** When you haven't configured
|
- **Upstream `g:vimwiki_list` config (Vim & Neovim).** When you haven't
|
||||||
nuwiki natively, the Vim client reads your upstream `g:vimwiki_list` +
|
configured nuwiki natively, both clients read your upstream `g:vimwiki_list` +
|
||||||
`g:vimwiki_*` globals and translates them into nuwiki's schema (per-wiki
|
`g:vimwiki_*` globals and translate them into nuwiki's schema (per-wiki
|
||||||
`path`/`path_html`/`template_*`/`auto_export`, plus globals `toc_header`,
|
`path`/`path_html`/`template_*`/`auto_export`, plus globals `toc_header`,
|
||||||
`toc_header_level`, `html_header_numbering`, `html_header_numbering_sym`,
|
`toc_header_level`, `html_header_numbering`, `html_header_numbering_sym`,
|
||||||
`links_space_char`, `list_margin`). `g:nuwiki_*` always wins. Globals nuwiki
|
`links_space_char`, `list_margin`). `g:nuwiki_*` / `setup()` config always
|
||||||
doesn't model (e.g. `automatic_nested_syntaxes`) are ignored — see the
|
wins. Globals nuwiki doesn't model (e.g. `automatic_nested_syntaxes`) are
|
||||||
divergence list above. **Limitation:** this drop-in translation is currently
|
ignored — see the divergence list above. On Neovim this means swapping the
|
||||||
**Vim-only**; on Neovim, configure via `setup()` / `g:nuwiki_wikis`.
|
`vimwiki` plugin for nuwiki under lazy.nvim works with your existing
|
||||||
|
`vim.g.vimwiki_list` untouched (call `require('nuwiki').setup()` with no args).
|
||||||
- **Third-party plugin compatibility.** A shim at `autoload/vimwiki/vars.vim`
|
- **Third-party plugin compatibility.** A shim at `autoload/vimwiki/vars.vim`
|
||||||
exposes the subset of `vimwiki#vars#get_wikilocal` that plugins like
|
exposes the subset of `vimwiki#vars#get_wikilocal` that plugins like
|
||||||
vimwiki-sync and vim-zettel call (`path`, `ext`/`extension`, `syntax`,
|
vimwiki-sync and vim-zettel call (`path`, `ext`/`extension`, `syntax`,
|
||||||
|
|||||||
+110
-10
@@ -114,15 +114,115 @@ function M.apply(user)
|
|||||||
M.options = vim.tbl_deep_extend('force', M.defaults, user or {})
|
M.options = vim.tbl_deep_extend('force', M.defaults, user or {})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- ===== Upstream vimwiki config compatibility (drop-in) =====
|
||||||
|
--
|
||||||
|
-- Single source of truth for the configured wikis, shared by the LSP payload
|
||||||
|
-- (lsp.lua) and the buffer-side commands. Mirrors autoload/nuwiki/config.vim so
|
||||||
|
-- a user who keeps their original vim.g.vimwiki_list + g:vimwiki_* config (e.g.
|
||||||
|
-- swapping the vimwiki plugin for nuwiki under lazy.nvim) needs no rewrite.
|
||||||
|
-- Native config (setup() wikis / g:nuwiki_*) always wins.
|
||||||
|
|
||||||
|
-- Upstream vimwiki per-wiki dict key -> nuwiki/server key.
|
||||||
|
local 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',
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Per-wiki settings that double as wiki-wide global defaults.
|
||||||
|
local SCALAR_GLOBAL_KEYS = {
|
||||||
|
'toc_header', 'toc_header_level', 'toc_link_format',
|
||||||
|
'links_header', 'links_header_level',
|
||||||
|
'tags_header', 'tags_header_level',
|
||||||
|
'html_header_numbering', 'html_header_numbering_sym',
|
||||||
|
'links_space_char', 'list_margin',
|
||||||
|
'listsyms', 'listsym_rejected',
|
||||||
|
'auto_export', 'auto_toc',
|
||||||
|
'auto_generate_links', 'auto_generate_tags', 'auto_diary_index',
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Resolve the global scalar defaults applied to every wiki. Priority (low to
|
||||||
|
-- high): g:vimwiki_<key>, g:nuwiki_<key>, explicit setup() value. Built-in
|
||||||
|
-- defaults are excluded (reads M.user, not M.options) so they don't get folded
|
||||||
|
-- onto every wiki and override per-wiki values.
|
||||||
|
function M.scalar_globals()
|
||||||
|
local g = {}
|
||||||
|
for _, key in ipairs(SCALAR_GLOBAL_KEYS) do
|
||||||
|
if vim.g['vimwiki_' .. key] ~= nil then
|
||||||
|
g[key] = vim.g['vimwiki_' .. key]
|
||||||
|
end
|
||||||
|
if vim.g['nuwiki_' .. key] ~= nil then
|
||||||
|
g[key] = vim.g['nuwiki_' .. key]
|
||||||
|
end
|
||||||
|
if M.user[key] ~= nil then
|
||||||
|
g[key] = M.user[key]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return g
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Translate vim.g.vimwiki_list into nuwiki's wiki list (server key names),
|
||||||
|
-- folding the global scalars into each entry. Returns {} when unset/malformed.
|
||||||
|
local function wikis_from_vimwiki(globals)
|
||||||
|
local list = vim.g.vimwiki_list
|
||||||
|
if type(list) ~= 'table' or vim.tbl_isempty(list) then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
local out = {}
|
||||||
|
for _, vw in ipairs(list) do
|
||||||
|
if type(vw) == 'table' then
|
||||||
|
local w = vim.tbl_extend('force', {}, globals)
|
||||||
|
for src, dst in pairs(VIMWIKI_WIKI_MAP) do
|
||||||
|
if vw[src] ~= nil then
|
||||||
|
w[dst] = vw[src]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if w.root ~= nil then
|
||||||
|
table.insert(out, w)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The configured wikis as normalized dicts (nuwiki/server key names), with the
|
||||||
|
-- global scalars folded in (per-wiki value wins). Priority:
|
||||||
|
-- 1. setup() opts.wikis
|
||||||
|
-- 2. g:nuwiki_wikis
|
||||||
|
-- 3. g:vimwiki_list (upstream drop-in)
|
||||||
|
-- Returns {} when none is set — callers fall back to the single-wiki shorthand.
|
||||||
|
function M.wikis()
|
||||||
|
local globals = M.scalar_globals()
|
||||||
|
local native = M.options.wikis or vim.g.nuwiki_wikis
|
||||||
|
if type(native) == 'table' and #native > 0 then
|
||||||
|
local out = {}
|
||||||
|
for i, w in ipairs(native) do
|
||||||
|
out[i] = vim.tbl_extend('force', globals, w)
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
return wikis_from_vimwiki(globals)
|
||||||
|
end
|
||||||
|
|
||||||
-- Resolve the config for wiki #n (0-based) without touching the LSP.
|
-- Resolve the config for wiki #n (0-based) without touching the LSP.
|
||||||
-- Priority: setup() opts.wikis → g:nuwiki_wikis (VimL) → scalar opts/g: vars.
|
-- Returns { name, root, ext, idx, diary_rel, diary_idx, space }.
|
||||||
-- Returns { name, root, ext, idx, diary_rel, diary_idx }.
|
|
||||||
function M.wiki_cfg(n)
|
function M.wiki_cfg(n)
|
||||||
local opts = M.options
|
local wikis = M.wikis()
|
||||||
local wikis = opts.wikis or vim.g.nuwiki_wikis or nil
|
local w = wikis[(n or 0) + 1]
|
||||||
local w = wikis and wikis[(n or 0) + 1] or nil
|
local root = (w and w.root) or M.options.wiki_root or vim.g.nuwiki_wiki_root or '~/vimwiki'
|
||||||
local root = (w and w.root) or opts.wiki_root or vim.g.nuwiki_wiki_root or '~/vimwiki'
|
local ext = (w and w.file_extension) or M.options.file_extension
|
||||||
local ext = (w and w.file_extension) or opts.file_extension or vim.g.nuwiki_file_extension or '.wiki'
|
or vim.g.nuwiki_file_extension or '.wiki'
|
||||||
if not ext:match('^%.') then ext = '.' .. ext end
|
if not ext:match('^%.') then ext = '.' .. ext end
|
||||||
return {
|
return {
|
||||||
name = (w and w.name) or vim.fn.fnamemodify(vim.fn.expand(root), ':t'),
|
name = (w and w.name) or vim.fn.fnamemodify(vim.fn.expand(root), ':t'),
|
||||||
@@ -131,7 +231,7 @@ function M.wiki_cfg(n)
|
|||||||
idx = (w and w.index) or 'index',
|
idx = (w and w.index) or 'index',
|
||||||
diary_rel = (w and w.diary_rel_path) or vim.g.nuwiki_diary_rel_path or 'diary',
|
diary_rel = (w and w.diary_rel_path) or vim.g.nuwiki_diary_rel_path or 'diary',
|
||||||
diary_idx = (w and w.diary_index) or 'diary',
|
diary_idx = (w and w.diary_index) or 'diary',
|
||||||
space = (w and w.links_space_char) or opts.links_space_char
|
space = (w and w.links_space_char) or M.options.links_space_char
|
||||||
or vim.g.nuwiki_links_space_char or ' ',
|
or vim.g.nuwiki_links_space_char or ' ',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -139,9 +239,9 @@ end
|
|||||||
-- The full list of configured wikis as wiki_cfg dicts. Falls back to a single
|
-- The full list of configured wikis as wiki_cfg dicts. Falls back to a single
|
||||||
-- entry built from the scalar wiki_root config when no list is configured.
|
-- entry built from the scalar wiki_root config when no list is configured.
|
||||||
function M.wiki_list()
|
function M.wiki_list()
|
||||||
local wikis = M.options.wikis or vim.g.nuwiki_wikis or nil
|
local wikis = M.wikis()
|
||||||
local list = {}
|
local list = {}
|
||||||
if type(wikis) == 'table' and #wikis > 0 then
|
if #wikis > 0 then
|
||||||
for i = 1, #wikis do
|
for i = 1, #wikis do
|
||||||
list[i] = M.wiki_cfg(i - 1)
|
list[i] = M.wiki_cfg(i - 1)
|
||||||
end
|
end
|
||||||
|
|||||||
+13
-54
@@ -14,63 +14,22 @@ local function command()
|
|||||||
return { install.expected_path() }
|
return { install.expected_path() }
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Per-wiki settings that double as wiki-wide defaults (vimwiki-style global
|
-- Build the server config payload. The wiki list comes from the shared
|
||||||
-- shorthand): set once at the top level — via setup() or `g:nuwiki_<key>` —
|
-- resolver (config.wikis) — native setup() wikis, g:nuwiki_wikis, or an
|
||||||
-- and every wiki inherits it; a per-wiki value overrides. Mirrors the Vim
|
-- upstream g:vimwiki_list, with global scalar defaults already folded — so the
|
||||||
-- client's `s:scalar_global_map`.
|
-- payload and the buffer-side commands agree on which wikis exist.
|
||||||
local SCALAR_GLOBALS = {
|
|
||||||
'toc_header', 'toc_header_level', 'toc_link_format',
|
|
||||||
'links_header', 'links_header_level',
|
|
||||||
'tags_header', 'tags_header_level',
|
|
||||||
'html_header_numbering', 'html_header_numbering_sym',
|
|
||||||
'links_space_char', 'list_margin',
|
|
||||||
'listsyms', 'listsym_rejected',
|
|
||||||
'auto_export', 'auto_toc',
|
|
||||||
'auto_generate_links', 'auto_generate_tags', 'auto_diary_index',
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Resolve the global scalar defaults from config the user *explicitly* set:
|
|
||||||
-- the raw setup() table first, then the `g:nuwiki_<key>` global. Built-in
|
|
||||||
-- defaults are deliberately excluded so they don't get folded into every wiki
|
|
||||||
-- (that would diverge from the Vim client and override per-wiki values with a
|
|
||||||
-- default).
|
|
||||||
local function scalar_globals()
|
|
||||||
local user = config.user or {}
|
|
||||||
local g = {}
|
|
||||||
for _, key in ipairs(SCALAR_GLOBALS) do
|
|
||||||
if user[key] ~= nil then
|
|
||||||
g[key] = user[key]
|
|
||||||
elseif vim.g['nuwiki_' .. key] ~= nil then
|
|
||||||
g[key] = vim.g['nuwiki_' .. key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return g
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Merge g:nuwiki_wikis (VimL config) into opts.wikis when the user has not
|
|
||||||
-- passed wikis through setup(). This lets users who configure via a .vim
|
|
||||||
-- file avoid duplicating the list in their Lua setup() call.
|
|
||||||
local function resolved_opts()
|
local function resolved_opts()
|
||||||
local opts = config.options
|
local opts = config.options
|
||||||
if not opts.wikis and vim.g.nuwiki_wikis then
|
local wikis = config.wikis()
|
||||||
opts = vim.tbl_extend('force', opts, { wikis = vim.g.nuwiki_wikis })
|
if #wikis > 0 then
|
||||||
end
|
opts = vim.tbl_extend('force', opts, { wikis = wikis })
|
||||||
local globals = scalar_globals()
|
|
||||||
if vim.tbl_isempty(globals) then
|
|
||||||
return opts
|
|
||||||
end
|
|
||||||
if opts.wikis then
|
|
||||||
-- Fold the globals into each wiki as defaults (per-wiki value wins),
|
|
||||||
-- without mutating the user's setup table.
|
|
||||||
local folded = {}
|
|
||||||
for i, w in ipairs(opts.wikis) do
|
|
||||||
folded[i] = vim.tbl_extend('force', globals, w)
|
|
||||||
end
|
|
||||||
opts = vim.tbl_extend('force', opts, { wikis = folded })
|
|
||||||
else
|
else
|
||||||
-- Single-wiki shorthand: ensure the globals (incl. the g:nuwiki_* form)
|
-- Single-wiki shorthand: fold the global scalars into the top-level payload
|
||||||
-- sit at the top level for the server's single-wiki desugaring.
|
-- so the server's single-wiki desugaring honours them.
|
||||||
opts = vim.tbl_extend('keep', opts, globals)
|
local globals = config.scalar_globals()
|
||||||
|
if not vim.tbl_isempty(globals) then
|
||||||
|
opts = vim.tbl_extend('keep', opts, globals)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return opts
|
return opts
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user