Files
gffranco e6f400b370
CI / cargo fmt --check (push) Successful in 2m12s
CI / cargo clippy (push) Successful in 2m18s
CI / cargo test (push) Successful in 2m24s
CI / editor keymaps (push) Successful in 1m27s
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>
2026-06-06 01:15:43 +00:00

269 lines
9.9 KiB
Lua

-- lua/nuwiki/config.lua — defaults and user-config merge.
--
-- Keep this aligned with `doc/nuwiki.txt`.
local M = {}
M.defaults = {
-- Single-wiki shorthand. The server desugars these into a
-- one-entry `wikis = {…}` list. Use either this or the multi-wiki
-- form below; if both are set, `wikis` wins.
wiki_root = '~/vimwiki',
file_extension = '.wiki',
syntax = 'vimwiki',
log_level = 'warn',
-- Prefix for the global/buffer wiki command family (`<prefix>w`,
-- `<prefix>t`, `<prefix><Leader>w`, …). Mirrors vimwiki's
-- `g:vimwiki_map_prefix`. Vim users set `g:nuwiki_map_prefix` instead.
map_prefix = '<Leader>w',
-- Multi-wiki shape. Each entry honours every per-wiki key the
-- server understands. Leave nil to fall through to the shorthand
-- above.
--
-- Per-wiki keys (all optional, server defaults documented in
-- `doc/nuwiki.txt`):
-- name, root, file_extension, syntax, index
-- diary_rel_path, diary_index, diary_frequency,
-- diary_weekly_style, diary_start_week_day,
-- diary_caption_level, diary_sort, diary_header
-- html_path, template_path, template_default, template_ext,
-- template_date_format, css_name, auto_export, auto_toc,
-- auto_generate_links, auto_generate_tags, auto_diary_index,
-- html_filename_parameterization, exclude_files, color_dic,
-- custom_wiki2html, custom_wiki2html_args, base_url,
-- toc_header, toc_header_level, links_header, links_header_level,
-- tags_header, tags_header_level,
-- html_header_numbering, html_header_numbering_sym,
-- listsyms, listsym_rejected, listsyms_propagate, list_margin,
-- links_space_char
wikis = nil,
-- TOC defaults (per-wiki, also accepted as top-level for single-wiki setups)
toc_header = 'Contents',
toc_header_level = 1,
-- HTML export defaults (per-wiki, also accepted as top-level for single-wiki setups)
html_header_numbering = 0,
html_header_numbering_sym = '',
-- Per-buffer glue. Each subgroup mirrors vimwiki's
-- `g:vimwiki_key_mappings` shape and can be flipped off
-- independently to suppress that group of keymaps.
-- The <Leader>w prefix in wiki_prefix/links/html_export follows map_prefix.
mappings = {
enabled = true,
wiki_prefix = true, -- <Leader>w{w,t,s,i}, <Leader>w<Leader>{w,y,t,m,i}
links = true, -- <CR>, <S-CR>, <C-CR>, <C-S-CR>, <D-CR>, <M-CR>, <BS>, <Tab>, <S-Tab>, + (n/x), <Leader>w{n,d,r}, <Leader>wc (n/x)
lists = true, -- <C-Space>, gnt, gln, glp, glx, glh, gll, gLh, gLl, glr, gLr, gl{-,*,#,1,i,I,a,A}, gL{…}, gl, gL, o, O; insert <C-D>, <C-T>, <C-L><C-J/K/M>, <CR>
headers = true, -- =, -, ]], [[, ]=, [=, ]u, [u
table_editing = true, -- gqq, gq1, gww, gw1, <A-Left>, <A-Right>; insert <Tab>, <S-Tab>
diary = true, -- <C-Down>, <C-Up>
html_export = true, -- <Leader>wh, <Leader>whh, <Leader>wha
text_objects = true, -- ah, ih, aH, iH, al, il, a\, i\, ac, ic
mouse = false, -- <2-LeftMouse>, <S-2-LeftMouse>, <C-2-LeftMouse>, <MiddleMouse>, <RightMouse> (opt-in)
},
-- Folding. `'lsp'` uses the server's `foldingRange`
-- provider (Neovim 0.11+ wires it automatically). `'expr'` falls
-- back to a regex-based `foldexpr`. `'off'` skips folding setup.
folding = 'lsp',
-- vimwiki `autowriteall` (default on): while a wiki buffer is current,
-- mirror Vim's global `'autowriteall'` so a modified buffer auto-saves on
-- page switch / `:make` etc., restoring the prior value on leave.
autowriteall = true,
-- vimwiki `table_auto_fmt` (default on): re-align the table under the
-- cursor when leaving insert mode.
table_auto_fmt = true,
-- vimwiki `auto_chdir` (default off): `:lcd` into the owning wiki's root
-- when a wiki buffer becomes current.
auto_chdir = false,
-- vimwiki `auto_header` (default off): insert a level-1 header from the
-- filename on new wiki pages.
auto_header = false,
-- Broken-link diagnostic severity. Sent to the server, which downgrades
-- or suppresses the diagnostic accordingly.
-- 'off' | 'hint' | 'warn' | 'error'
diagnostic = {
link_severity = 'warn',
},
-- Calendar-vim integration. On by default — set to `false` to opt out.
-- When on, nuwiki detects calendar-vim on the runtimepath and wires
-- `g:calendar_action` / `g:calendar_sign` automatically.
-- Also respects `g:nuwiki_no_calendar` set before setup() to disable.
use_calendar = true,
}
M.options = vim.deepcopy(M.defaults)
-- The raw table the user passed to setup(), kept separate from the
-- defaults-merged `options`. Used to tell an explicitly-set value apart from
-- a built-in default — e.g. so the LSP client only treats a per-wiki key as a
-- global default when the user actually set it.
M.user = {}
function M.apply(user)
M.user = user or {}
M.options = vim.tbl_deep_extend('force', M.defaults, user or {})
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.
-- Returns { name, root, ext, idx, diary_rel, diary_idx, space }.
function M.wiki_cfg(n)
local wikis = M.wikis()
local w = wikis[(n or 0) + 1]
local root = (w and w.root) or M.options.wiki_root or vim.g.nuwiki_wiki_root or '~/vimwiki'
local ext = (w and w.file_extension) or M.options.file_extension
or vim.g.nuwiki_file_extension or '.wiki'
if not ext:match('^%.') then ext = '.' .. ext end
return {
name = (w and w.name) or vim.fn.fnamemodify(vim.fn.expand(root), ':t'),
root = root,
ext = ext,
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_idx = (w and w.diary_index) or 'diary',
space = (w and w.links_space_char) or M.options.links_space_char
or vim.g.nuwiki_links_space_char or ' ',
}
end
-- 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.
function M.wiki_list()
local wikis = M.wikis()
local list = {}
if #wikis > 0 then
for i = 1, #wikis do
list[i] = M.wiki_cfg(i - 1)
end
else
list[1] = M.wiki_cfg(0)
end
return list
end
-- Absolute root (trailing slash) of the wiki that owns `path`, or nil when the
-- file is under no configured wiki (callers no-op / fall back to CWD).
-- Used by auto_chdir + search scoping.
function M.wiki_root_for(path)
for _, w in ipairs(M.wiki_list()) do
local wroot = vim.fn.fnamemodify(vim.fn.expand(w.root), ':p')
if wroot:sub(-1) ~= '/' then wroot = wroot .. '/' end
if path:sub(1, #wroot) == wroot then
return wroot
end
end
return nil
end
return M