feat(config): P3 config batch — group 2 (create_link, dir_link, auto_header)
- create_link (default true): server resolve_target_uri now only synthesises a missing-page URI when create_link is set; when off, following a link to a non-existent page returns no location (no-op). - dir_link: a [[dir/]] link now resolves to <dir>/<dir_link><ext> when dir_link is set, else opens the directory itself. Uses the already-parsed LinkTarget.is_directory. - auto_header (default off): new wiki pages get a `= Stem =` header derived from the filename, skipping the wiki index + diary index. Client-side BufNewFile autocmd in both clients (init.lua + plugin/nuwiki.vim), with auto_header handlers in both command layers (trailing-slash-robust root matching). Tests: cmd.auto_header_inserts + cmd.auto_header_skips_diary_index (nvim) / cmd.auto_header_skips_index (vim). Full rust suite + both harnesses green (Neovim 307, Vim 301/18/21). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -190,6 +190,30 @@ function! nuwiki#commands#auto_chdir() abort
|
|||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" vimwiki `auto_header`: on a new wiki page, insert a level-1 header derived
|
||||||
|
" from the filename. Skips the wiki index + diary index pages; only acts on an
|
||||||
|
" empty new buffer. Wired from a BufNewFile autocmd.
|
||||||
|
function! nuwiki#commands#auto_header() abort
|
||||||
|
if line('$') > 1 || getline(1) !=# ''
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let l:file = expand('%:p')
|
||||||
|
for l:c in nuwiki#commands#wiki_list()
|
||||||
|
let l:root = fnamemodify(expand(l:c.root), ':p')
|
||||||
|
if l:root[len(l:root) - 1:] !=# '/' | let l:root .= '/' | endif
|
||||||
|
if l:file[: len(l:root) - 1] ==# l:root
|
||||||
|
let l:index_path = l:root . l:c.idx . l:c.ext
|
||||||
|
let l:diary_index_path = l:root . l:c.diary_rel . '/' . l:c.diary_idx . l:c.ext
|
||||||
|
if l:file ==# l:index_path || l:file ==# l:diary_index_path
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
call setline(1, '= ' . expand('%:t:r') . ' =')
|
||||||
|
call append(1, '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
" :VimwikiShowVersion / :NuwikiShowVersion — echo the nuwiki version and the
|
" :VimwikiShowVersion / :NuwikiShowVersion — echo the nuwiki version and the
|
||||||
" host editor, mirroring upstream's version banner.
|
" host editor, mirroring upstream's version banner.
|
||||||
function! nuwiki#commands#show_version() abort
|
function! nuwiki#commands#show_version() abort
|
||||||
|
|||||||
@@ -269,7 +269,29 @@ impl Backend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let path = target.path.as_deref()?;
|
let path = target.path.as_deref()?;
|
||||||
return synthesise_page_uri(&source_wiki.config, path);
|
// vimwiki `dir_link`: a `[[dir/]]` link opens `<dir>/<dir_link>`
|
||||||
|
// (e.g. `index` → `dir/index.wiki`); empty → the directory itself.
|
||||||
|
if target.is_directory {
|
||||||
|
let dl = source_wiki.config.dir_link.trim();
|
||||||
|
if dl.is_empty() {
|
||||||
|
let mut p = source_wiki.config.root.clone();
|
||||||
|
for seg in path.split('/').filter(|s| !s.is_empty()) {
|
||||||
|
p.push(seg);
|
||||||
|
}
|
||||||
|
return Url::from_file_path(p).ok();
|
||||||
|
}
|
||||||
|
let joined = format!("{}/{dl}", path.trim_end_matches('/'));
|
||||||
|
return synthesise_page_uri(&source_wiki.config, &joined);
|
||||||
|
}
|
||||||
|
// vimwiki `create_link`: when off, only follow to a page that
|
||||||
|
// already exists on disk — never synthesise a new one.
|
||||||
|
let uri = synthesise_page_uri(&source_wiki.config, path)?;
|
||||||
|
if !source_wiki.config.create_link
|
||||||
|
&& !uri.to_file_path().map(|p| p.exists()).unwrap_or(false)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(uri);
|
||||||
}
|
}
|
||||||
// No wiki registered (no `initializationOptions`, no
|
// No wiki registered (no `initializationOptions`, no
|
||||||
// workspace folder). Fall back to the source buffer's
|
// workspace folder). Fall back to the source buffer's
|
||||||
|
|||||||
@@ -728,6 +728,23 @@ endtry
|
|||||||
call s:record(s:nm_err ==# '' ? 1 : 0,
|
call s:record(s:nm_err ==# '' ? 1 : 0,
|
||||||
\ 'cmd.VimwikiSearch_no_match_graceful', 'err=' . s:nm_err)
|
\ 'cmd.VimwikiSearch_no_match_graceful', 'err=' . s:nm_err)
|
||||||
|
|
||||||
|
" ===== auto_header inserts `= Stem =` on a new wiki page; skips the index =====
|
||||||
|
let s:ah_root = fnamemodify(expand(nuwiki#commands#wiki_list()[0].root), ':p')
|
||||||
|
if s:ah_root[len(s:ah_root)-1:] !=# '/' | let s:ah_root .= '/' | endif
|
||||||
|
new
|
||||||
|
execute 'file ' . fnameescape('/tmp/nuwiki-ah-plain/MyNewPage.wiki')
|
||||||
|
call nuwiki#commands#auto_header()
|
||||||
|
call s:record(getline(1) ==# '= MyNewPage =' ? 1 : 0,
|
||||||
|
\ 'cmd.auto_header_inserts', 'line1=' . getline(1))
|
||||||
|
bwipeout!
|
||||||
|
new
|
||||||
|
execute 'file ' . fnameescape(s:ah_root . 'index.wiki')
|
||||||
|
call nuwiki#commands#auto_header()
|
||||||
|
call s:record(getline(1) ==# '' ? 1 : 0,
|
||||||
|
\ 'cmd.auto_header_skips_index', 'line1=' . getline(1))
|
||||||
|
bwipeout!
|
||||||
|
unlet s:ah_root
|
||||||
|
|
||||||
" ===== :VimwikiGoto -nargs=* =====
|
" ===== :VimwikiGoto -nargs=* =====
|
||||||
" Was -nargs=1, so a page name with a space raised E488 (and the empty-arg
|
" Was -nargs=1, so a page name with a space raised E488 (and the empty-arg
|
||||||
" prompt fallback was unreachable). Now -nargs=*: a multi-word arg must parse.
|
" prompt fallback was unreachable). Now -nargs=*: a multi-word arg must parse.
|
||||||
|
|||||||
@@ -305,6 +305,31 @@ vim.defer_fn(function()
|
|||||||
vim.cmd('bwipeout!')
|
vim.cmd('bwipeout!')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- auto_header: the function inserts `= Stem =` on an empty new wiki buffer,
|
||||||
|
-- and skips the wiki index page. Operate on dedicated buffer handles so the
|
||||||
|
-- harness's own buffer is untouched.
|
||||||
|
do
|
||||||
|
local wroot = require('nuwiki.config').wiki_cfg(0).root
|
||||||
|
local root = vim.fn.fnamemodify(vim.fn.expand(wroot), ':p')
|
||||||
|
if root:sub(-1) ~= '/' then root = root .. '/' end
|
||||||
|
local function ah_line(name)
|
||||||
|
local buf = vim.api.nvim_create_buf(true, false)
|
||||||
|
vim.api.nvim_buf_set_name(buf, name)
|
||||||
|
require('nuwiki.commands').auto_header(buf)
|
||||||
|
local line = vim.api.nvim_buf_get_lines(buf, 0, 1, false)[1] or ''
|
||||||
|
vim.api.nvim_buf_delete(buf, { force = true })
|
||||||
|
return line
|
||||||
|
end
|
||||||
|
-- A normal page (outside any wiki root) → header inserted.
|
||||||
|
local got = ah_line('/tmp/nuwiki-ah-plain/MyNewPage.wiki')
|
||||||
|
record(got == '= MyNewPage =', 'cmd.auto_header_inserts', 'line1=' .. got)
|
||||||
|
-- The diary index page → skipped (no header). (The wiki index itself is the
|
||||||
|
-- harness's open buffer, so use the diary index to avoid an E95 collision.)
|
||||||
|
local c = require('nuwiki.config').wiki_cfg(0)
|
||||||
|
local idx_line = ah_line(root .. c.diary_rel .. '/' .. c.diary_idx .. '.wiki')
|
||||||
|
record(idx_line == '', 'cmd.auto_header_skips_diary_index', 'line1=' .. idx_line)
|
||||||
|
end
|
||||||
|
|
||||||
-- ===== Lists =====
|
-- ===== Lists =====
|
||||||
|
|
||||||
run('list.toggle_via_C-Space', {
|
run('list.toggle_via_C-Space', {
|
||||||
|
|||||||
@@ -285,6 +285,37 @@ function M.show_version()
|
|||||||
}, false, {})
|
}, false, {})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- vimwiki `auto_header`: on a new wiki page, insert a level-1 header derived
|
||||||
|
-- from the filename. Skips the wiki index + diary index pages, and only acts
|
||||||
|
-- on a genuinely empty buffer. Called from a BufNewFile autocmd.
|
||||||
|
function M.auto_header(bufnr)
|
||||||
|
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
||||||
|
if #lines > 1 or (lines[1] or '') ~= '' then
|
||||||
|
return -- not an empty new buffer
|
||||||
|
end
|
||||||
|
local file = vim.api.nvim_buf_get_name(bufnr)
|
||||||
|
local config = require('nuwiki.config')
|
||||||
|
for i = 0, 64 do
|
||||||
|
local c = config.wiki_cfg(i)
|
||||||
|
if not c then break end
|
||||||
|
local root = vim.fn.fnamemodify(vim.fn.expand(c.root), ':p')
|
||||||
|
if root:sub(-1) ~= '/' then root = root .. '/' end
|
||||||
|
if file:sub(1, #root) == root then
|
||||||
|
-- Skip the wiki index and the diary index pages.
|
||||||
|
local index_path = root .. c.idx .. c.ext
|
||||||
|
local diary_index_path = root .. c.diary_rel .. '/' .. c.diary_idx .. c.ext
|
||||||
|
if file == index_path or file == diary_index_path then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if not (config.options.wikis or vim.g.nuwiki_wikis) then break end
|
||||||
|
end
|
||||||
|
local title = vim.fn.fnamemodify(file, ':t:r')
|
||||||
|
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, { '= ' .. title .. ' =', '' })
|
||||||
|
end
|
||||||
|
|
||||||
-- :VimwikiSearch / :VWS {pattern} — search the current wiki's files (upstream
|
-- :VimwikiSearch / :VWS {pattern} — search the current wiki's files (upstream
|
||||||
-- scopes to the wiki, not the editor CWD). Resolves the wiki whose root holds
|
-- scopes to the wiki, not the editor CWD). Resolves the wiki whose root holds
|
||||||
-- the current file, else the first configured wiki, else CWD. Empty pattern
|
-- the current file, else the first configured wiki, else CWD. Empty pattern
|
||||||
|
|||||||
@@ -113,6 +113,22 @@ function M.setup(opts)
|
|||||||
vim.g.nuwiki_no_calendar = 1
|
vim.g.nuwiki_no_calendar = 1
|
||||||
end
|
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()
|
lsp.register()
|
||||||
_setup_global_mappings()
|
_setup_global_mappings()
|
||||||
_setup_global_commands()
|
_setup_global_commands()
|
||||||
|
|||||||
@@ -69,6 +69,19 @@ augroup nuwiki_vim_lsp_start
|
|||||||
autocmd FileType vimwiki call nuwiki#lsp#start()
|
autocmd FileType vimwiki call nuwiki#lsp#start()
|
||||||
augroup END
|
augroup END
|
||||||
|
|
||||||
|
" vimwiki `auto_header` (default off): insert a level-1 header from the filename
|
||||||
|
" on new wiki pages. BufNewFile fires only for genuinely new files. Matches the
|
||||||
|
" configured extension(s).
|
||||||
|
if get(g:, 'nuwiki_auto_header', 0)
|
||||||
|
let s:awh_ext = get(g:, 'nuwiki_file_extension', '.wiki')
|
||||||
|
let s:awh_ext = s:awh_ext[0] ==# '.' ? s:awh_ext : '.' . s:awh_ext
|
||||||
|
augroup nuwiki_auto_header
|
||||||
|
autocmd!
|
||||||
|
execute 'autocmd BufNewFile *' . s:awh_ext . ' call nuwiki#commands#auto_header()'
|
||||||
|
augroup END
|
||||||
|
unlet s:awh_ext
|
||||||
|
endif
|
||||||
|
|
||||||
" Global wiki-picker commands — available from any buffer so a wiki can be
|
" Global wiki-picker commands — available from any buffer so a wiki can be
|
||||||
" chosen before a .wiki file exists. The picker reads its list from config
|
" chosen before a .wiki file exists. The picker reads its list from config
|
||||||
" (no LSP); opening the chosen index then auto-starts the server. The
|
" (no LSP); opening the chosen index then auto-starts the server. The
|
||||||
|
|||||||
Reference in New Issue
Block a user