Files
nuwiki/lua/nuwiki/init.lua
T
gffranco 0d1a73a3ba
CI / cargo fmt --check (push) Failing after 11s
CI / cargo clippy (push) Successful in 32s
CI / cargo test (push) Successful in 57s
CI / editor keymaps (push) Successful in 1m33s
feat(config): bridge setup({wikis}) to g:nuwiki_wikis for VimL plugins
A Lua-only `setup({ wikis = … })` config is invisible to the VimL side:
the buffer helpers in autoload/nuwiki/config.vim and the vimwiki compat
shim (autoload/vimwiki/vars.vim, which third-party plugins like
vimwiki-sync call via vimwiki#vars#get_wikilocal) read g:nuwiki_wikis. So
a Neovim user who migrated from g:vimwiki_list to native setup({wikis})
would break vimwiki-sync (it'd resolve the default ~/vimwiki).

setup() now publishes the resolved wiki list to g:nuwiki_wikis when the
config came from setup() opts (the only case VimL can't already see —
g:nuwiki_wikis / g:vimwiki_list configs are global and visible). Verified
vimwiki#vars#get_wikilocal('path', n) returns the right roots from a
pure-Lua setup() config. test-global-shorthand grows two bridge checks
(17). Goldens + keymap harnesses green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 01:34:24 +00:00

157 lines
6.9 KiB
Lua

-- lua/nuwiki/init.lua — Neovim entry point.
--
-- Public surface:
-- require('nuwiki').setup(opts) — apply user config + register LSP
-- require('nuwiki').install() — install / build the language server
-- require('nuwiki').health() — :checkhealth nuwiki target
--
-- This layer is wiring only. Everything substantive
-- happens in the Rust language server.
local M = {}
local config = require('nuwiki.config')
local lsp = require('nuwiki.lsp')
-- Open a file directly, expanding ~ / env vars in the path.
local function _open(path, open_cmd)
vim.cmd((open_cmd or 'edit') .. ' ' .. vim.fn.fnameescape(vim.fn.expand(path)))
end
-- Return the config dict for wiki #n (0-based). See config.wiki_cfg.
local function _wiki_cfg(n)
return config.wiki_cfg(n)
end
-- Compute the wiki index path for wiki #n (0-based) from config.
local function _wiki_index_path(n)
local c = _wiki_cfg(n)
return c.root .. '/' .. c.idx .. c.ext
end
-- Compute a diary file path from config. day_offset=0 → today.
-- Pass nil to get the diary index file instead.
local function _diary_path(day_offset)
local c = _wiki_cfg(0)
if day_offset == nil then
return c.root .. '/' .. c.diary_rel .. '/' .. c.diary_idx .. c.ext
end
local t = os.time() + day_offset * 86400
return c.root .. '/' .. c.diary_rel .. '/' .. os.date('%Y-%m-%d', t) .. c.ext
end
-- Register global (non-buffer-local) entry-point keymaps so users can open
-- their wiki from any buffer, not just from inside a .wiki file. Files are
-- opened directly from config — no LSP client required; the server auto-starts
-- once the vimwiki FileType fires on the newly opened buffer.
local function _setup_global_mappings()
if vim.g.nuwiki_no_default_mappings then return end
local kmap = vim.keymap.set
local function o(d) return { silent = true, desc = 'nuwiki: ' .. d } end
-- Same configurable prefix as the buffer-local maps (vimwiki map_prefix).
local p = config.options.map_prefix or '<Leader>w'
kmap('n', p .. 'w', function() _open(_wiki_index_path(0)) end, o('wiki index'))
kmap('n', p .. 't', function() _open(_wiki_index_path(0), 'tabedit') end, o('wiki index (tab)'))
kmap('n', p .. 's', function() require('nuwiki.commands').wiki_ui_select() end, o('pick wiki'))
kmap('n', p .. 'i', function() _open(_diary_path(nil)) end, o('diary index'))
kmap('n', p .. '<Leader>w', function() _open(_diary_path(0)) end, o('today diary'))
kmap('n', p .. '<Leader>y', function() _open(_diary_path(-1)) end, o('yesterday diary'))
kmap('n', p .. '<Leader>t', function() _open(_diary_path(0), 'tabedit') end, o('today diary (tab)'))
kmap('n', p .. '<Leader>m', function() _open(_diary_path(1)) end, o('tomorrow diary'))
kmap('n', p .. '<Leader>i', function() require('nuwiki.commands').diary_generate_index() end, o('rebuild diary index'))
end
-- Global wiki-picker commands so a wiki can be chosen from any buffer before
-- a .wiki file exists. The picker reads its list from config (no LSP); the
-- buffer-local versions in ftplugin/vimwiki.vim shadow these inside wiki
-- buffers but dispatch to the same function.
local function _setup_global_commands()
local function ui_select() require('nuwiki.commands').wiki_ui_select() end
vim.api.nvim_create_user_command('VimwikiUISelect', ui_select, {})
vim.api.nvim_create_user_command('NuwikiUISelect', ui_select, {})
local function show_version() require('nuwiki.commands').show_version() end
vim.api.nvim_create_user_command('VimwikiShowVersion', show_version, {})
vim.api.nvim_create_user_command('NuwikiShowVersion', show_version, {})
-- Global Index / TabIndex entry points (upstream defines the Index family
-- globally). The buffer-local copies shadow these inside wiki buffers.
local function index(o) require('nuwiki.commands').wiki_index(o.count) end
local function tab_index(o) require('nuwiki.commands').wiki_tab_index(o.count) end
vim.api.nvim_create_user_command('VimwikiIndex', index, { count = 0 })
vim.api.nvim_create_user_command('NuwikiIndex', index, { count = 0 })
vim.api.nvim_create_user_command('VimwikiTabIndex', tab_index, { count = 0 })
vim.api.nvim_create_user_command('NuwikiTabIndex', tab_index, { count = 0 })
-- Get/set nuwiki client config (upstream's :VimwikiVar).
local function var(o) require('nuwiki.commands').var(o.args) end
vim.api.nvim_create_user_command('VimwikiVar', var, { nargs = '*' })
vim.api.nvim_create_user_command('NuwikiVar', var, { nargs = '*' })
end
function M.setup(opts)
config.apply(opts or {})
-- Bridge a Lua-only `setup({ wikis = … })` config to VimL. The buffer-side
-- VimL helpers (autoload/nuwiki/config.vim) and the vimwiki compat shim
-- (autoload/vimwiki/vars.vim — used by third-party plugins such as
-- vimwiki-sync) read `g:nuwiki_wikis`, which can't see a config that only
-- lives in Lua. Publishing the resolved list keeps both worlds in sync. (A
-- `g:nuwiki_wikis` / `g:vimwiki_list` config is already VimL-visible, so this
-- only fires for the pure-`setup()` case.)
if type(config.options.wikis) == 'table' and #config.options.wikis > 0 then
vim.g.nuwiki_wikis = config.wikis()
end
-- Neovim 0.7+ resolves filetypes via `vim.filetype.match` before any
-- `ftdetect/*.vim` autocmd fires, and its bundled rule for `*.wiki`
-- returns `mediawiki`. Register an authoritative rule here so this
-- plugin's filetype (vimwiki) wins.
if vim.filetype and vim.filetype.add then
local extensions = { wiki = 'vimwiki' }
local ext = (config.options.file_extension or '.wiki'):gsub('^%.', '')
if ext ~= 'wiki' and ext ~= '' then
extensions[ext] = 'vimwiki'
end
vim.filetype.add({ extension = extensions })
end
-- Calendar-vim wiring lives in plugin/nuwiki.vim's FileType autocmd, which
-- runs for both Vim and Neovim. Translate the Lua-side opt-out into the
-- g: flag that autocmd reads so `use_calendar = false` fully disables it.
if config.options.use_calendar == false then
vim.g.nuwiki_no_calendar = 1
end
-- vimwiki `auto_header` (default off): insert a level-1 header from the
-- filename on new wiki pages. BufNewFile (not FileType) so it only fires for
-- genuinely new files.
if config.options.auto_header == true then
local ext = (config.options.file_extension or '.wiki'):gsub('^%.', '')
local pats = { '*.wiki' }
if ext ~= 'wiki' and ext ~= '' then
pats[#pats + 1] = '*.' .. ext
end
vim.api.nvim_create_autocmd('BufNewFile', {
pattern = pats,
group = vim.api.nvim_create_augroup('nuwiki_auto_header', { clear = true }),
callback = function(a) require('nuwiki.commands').auto_header(a.buf) end,
})
end
lsp.register()
_setup_global_mappings()
_setup_global_commands()
end
function M.install()
return require('nuwiki.install').install()
end
function M.health()
return require('nuwiki.health').check()
end
return M