fix(client): P2 diary tab collision + <M-CR> badd-link parity
CI / cargo fmt --check (push) Successful in 36s
CI / cargo clippy (push) Successful in 40s
CI / cargo test (push) Successful in 32s
CI / editor keymaps (push) Successful in 1m35s

Two upstream-parity keymap fixes (confirmed against upstream
ftplugin/vimwiki.vim):

1. <Leader>w<Leader>t collision — nuwiki bound both <Leader>w<Leader>t and
   <Leader>w<Leader>m to tomorrow's diary. Upstream: <Leader>w<Leader>t opens
   today's diary in a NEW TAB, <Leader>w<Leader>m opens tomorrow. <Leader>w
   <Leader>t now calls diary_today_tab; <Leader>w<Leader>m stays tomorrow.

2. <M-CR> badd-link — adding a link target to the buffer list was mouse-only
   (<MiddleMouse>) / command-only (:VimwikiBaddLink). Upstream binds
   <M-CR> -> VimwikiBaddLink. Added normal-mode <M-CR> -> badd_link to the
   links group of both clients.

Both clients (lua/nuwiki/keymaps.lua, ftplugin/vimwiki.vim); README + doc/
nuwiki.txt updated. Tests: map[n].<M-CR> in both harnesses;
diary.leader_t_opens_today_in_tab / diary.leader_m_opens_tomorrow (vim).
nvim 270, vim 263+18, all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 16:21:49 +00:00
parent 9de8543385
commit 086455e19b
7 changed files with 38 additions and 9 deletions
+4 -2
View File
@@ -480,6 +480,7 @@ via `mappings.<group> = false` in Neovim, or
| `<S-CR>` | Follow in horizontal split | | `<S-CR>` | Follow in horizontal split |
| `<C-CR>` | Follow in vertical split | | `<C-CR>` | Follow in vertical split |
| `<C-S-CR>` | Follow in a tab, reusing an existing tab if the file is already open | | `<C-S-CR>` | Follow in a tab, reusing an existing tab if the file is already open |
| `<M-CR>` | Add the link target to the buffer list (`:badd`, no jump) |
| `<BS>` | Jump back (`<C-o>`) | | `<BS>` | Jump back (`<C-o>`) |
| `<Tab>` / `<S-Tab>` | Next / previous wikilink on or after the cursor | | `<Tab>` / `<S-Tab>` | Next / previous wikilink on or after the cursor |
| `+` | Wrap word / visual selection as a wikilink (no follow) | | `+` | Wrap word / visual selection as a wikilink (no follow) |
@@ -542,8 +543,9 @@ vimwiki) they fire only after `'timeoutlen'`; type a suffix such as `gln` or
| `<Leader>wt` | Open the wiki index in a new tab | | `<Leader>wt` | Open the wiki index in a new tab |
| `<Leader>ws` | Pick a wiki | | `<Leader>ws` | Pick a wiki |
| `<Leader>wi` | Open the diary index | | `<Leader>wi` | Open the diary index |
| `<Leader>w<Leader>w` / `<Leader>w<Leader>y` / `<Leader>w<Leader>t` | Diary today / yesterday / tomorrow | | `<Leader>w<Leader>w` / `<Leader>w<Leader>y` | Diary today / yesterday |
| `<Leader>w<Leader>m` | Diary tomorrow (vimwiki-compat alias of `<Leader>w<Leader>t`) | | `<Leader>w<Leader>t` | Diary today, in a new tab |
| `<Leader>w<Leader>m` | Diary tomorrow |
| `<Leader>w<Leader>i` | Rebuild the diary index page | | `<Leader>w<Leader>i` | Rebuild the diary index page |
| `<Leader>wn` / `<Leader>wd` / `<Leader>wr` | Goto / delete / rename page | | `<Leader>wn` / `<Leader>wd` / `<Leader>wr` | Goto / delete / rename page |
| `<Leader>wh` / `<Leader>whh` | Export the current page to HTML / open in browser | | `<Leader>wh` / `<Leader>whh` | Export the current page to HTML / open in browser |
+13
View File
@@ -184,6 +184,7 @@ endfunction
let s:mapping_surface = [ let s:mapping_surface = [
\ ['<CR>', 'n'], ['<S-CR>', 'n'], ['<C-CR>', 'n'], ['<C-S-CR>', 'n'], \ ['<CR>', 'n'], ['<S-CR>', 'n'], ['<C-CR>', 'n'], ['<C-S-CR>', 'n'],
\ ['<M-CR>', 'n'],
\ ['<BS>', 'n'], ['<Tab>', 'n'], ['<S-Tab>', 'n'], ['+', 'nx'], \ ['<BS>', 'n'], ['<Tab>', 'n'], ['<S-Tab>', 'n'], ['+', 'nx'],
\ ['<C-Space>', 'nx'], ['<C-@>', 'nx'], ['<Nul>', 'nx'], \ ['<C-Space>', 'nx'], ['<C-@>', 'nx'], ['<Nul>', 'nx'],
\ ['gnt', 'n'], ['gln', 'nx'], ['glp', 'nx'], ['glx', 'nx'], \ ['gnt', 'n'], ['gln', 'nx'], ['glp', 'nx'], ['glx', 'nx'],
@@ -221,6 +222,18 @@ for s:entry in s:mapping_surface
endfor endfor
endfor endfor
" ===== Diary <Leader>w<Leader>{t,m} target (collision fix) =====
" Upstream: <Leader>w<Leader>t = today in a new tab, <Leader>w<Leader>m =
" tomorrow. nuwiki used to bind both to tomorrow.
call s:record(
\ maparg('<Leader>w<Leader>t', 'n') =~# 'diary_today_tab' ? 1 : 0,
\ 'diary.leader_t_opens_today_in_tab',
\ 'rhs=' . maparg('<Leader>w<Leader>t', 'n'))
call s:record(
\ maparg('<Leader>w<Leader>m', 'n') =~# 'diary_tomorrow' ? 1 : 0,
\ 'diary.leader_m_opens_tomorrow',
\ 'rhs=' . maparg('<Leader>w<Leader>m', 'n'))
" ===== Header nav (pure VimL) ===== " ===== Header nav (pure VimL) =====
call s:run('headers.]]_jumps_to_next', { call s:run('headers.]]_jumps_to_next', {
+1
View File
@@ -206,6 +206,7 @@ vim.defer_fn(function()
local mapping_surface = { local mapping_surface = {
-- Links -- Links
{ '<CR>', 'n' }, { '<S-CR>', 'n' }, { '<C-CR>', 'n' }, { '<C-S-CR>', 'n' }, { '<CR>', 'n' }, { '<S-CR>', 'n' }, { '<C-CR>', 'n' }, { '<C-S-CR>', 'n' },
{ '<M-CR>', 'n' },
{ '<BS>', 'n' }, { '<Tab>', 'n' }, { '<S-Tab>', 'n' }, { '+', 'nx' }, { '<BS>', 'n' }, { '<Tab>', 'n' }, { '<S-Tab>', 'n' }, { '+', 'nx' },
-- Lists -- Lists
{ '<C-Space>', 'nx' }, { '<C-@>', 'nx' }, { '<Nul>', 'nx' }, { '<C-Space>', 'nx' }, { '<C-@>', 'nx' }, { '<Nul>', 'nx' },
+12 -4
View File
@@ -81,8 +81,12 @@ fix site.
## P2 — Moderate (real users hit these) ## P2 — Moderate (real users hit these)
- [ ] **`<Leader>w<Leader>t` collision** — upstream = today-in-new-tab; nuwiki = - [x] **`<Leader>w<Leader>t` collision** — upstream = today-in-new-tab; nuwiki
tomorrow's diary. _Fix:_ `lua/nuwiki/keymaps.lua`, `ftplugin/vimwiki.vim`. bound both `<Leader>w<Leader>t` and `<Leader>w<Leader>m` to tomorrow's diary.
_Fix:_ `<Leader>w<Leader>t` now calls `diary_today_tab` (today in a new tab),
`<Leader>w<Leader>m` stays tomorrow — exact upstream parity
(`lua/nuwiki/keymaps.lua`, `ftplugin/vimwiki.vim`; docs + README updated).
Covered by `diary.leader_t_opens_today_in_tab` / `diary.leader_m_opens_tomorrow`.
- [ ] **Generated-section captions hardcoded**`toc_header` / - [ ] **Generated-section captions hardcoded**`toc_header` /
`toc_header_level`, `links_header`, `tags_header` (+levels). `toc_header_level`, `links_header`, `tags_header` (+levels).
_Fix:_ `crates/nuwiki-lsp/src/config.rs` + server TOC/generate renderers. _Fix:_ `crates/nuwiki-lsp/src/config.rs` + server TOC/generate renderers.
@@ -95,8 +99,12 @@ fix site.
converter hook + export URL prefix. _Fix:_ `config.rs` `HtmlConfig`. converter hook + export URL prefix. _Fix:_ `config.rs` `HtmlConfig`.
- [ ] **`map_prefix`** — `<Leader>w` hardcoded across the map layer. - [ ] **`map_prefix`** — `<Leader>w` hardcoded across the map layer.
_Fix:_ `plugin/nuwiki.vim`, `lua/nuwiki/keymaps.lua`, `ftplugin/vimwiki.vim`. _Fix:_ `plugin/nuwiki.vim`, `lua/nuwiki/keymaps.lua`, `ftplugin/vimwiki.vim`.
- [ ] **`<M-CR>` badd-link** — missing (badd is mouse-only via `<MiddleMouse>` / - [x] **`<M-CR>` badd-link** — was mouse-only (`<MiddleMouse>`) / command-only
`:VimwikiBaddLink`). _Fix:_ `lua/nuwiki/keymaps.lua`, `ftplugin/vimwiki.vim`. (`:VimwikiBaddLink`); upstream binds `<M-CR>``VimwikiBaddLink` (confirmed
against upstream `ftplugin/vimwiki.vim`). _Fix:_ added normal-mode `<M-CR>`
`badd_link` in the links group of both clients (`lua/nuwiki/keymaps.lua`,
`ftplugin/vimwiki.vim`; docs + README updated). Covered by `map[n].<M-CR>` in
both keymap harnesses.
- [ ] **`diary_caption_level` default divergence** — nuwiki `1` vs vimwiki `0`. - [ ] **`diary_caption_level` default divergence** — nuwiki `1` vs vimwiki `0`.
_Fix:_ `config.rs:291` (and defaults in `lua/nuwiki/config.lua`). _Fix:_ `config.rs:291` (and defaults in `lua/nuwiki/config.lua`).
- [ ] **`diary_start_week_day`** — **wrongly removed** in `c63ec67`. The removal - [ ] **`diary_start_week_day`** — **wrongly removed** in `c63ec67`. The removal
+3 -1
View File
@@ -433,6 +433,7 @@ Links (normal mode) ~
<C-CR> Follow in a vertical split. <C-CR> Follow in a vertical split.
<C-S-CR> Follow in a tab, reusing an existing tab if the file is <C-S-CR> Follow in a tab, reusing an existing tab if the file is
already open. already open.
<M-CR> Add the link target to the buffer list (`:badd`, no jump).
<BS> Jump back (`<C-o>`). <BS> Jump back (`<C-o>`).
<Tab> Next wikilink on or after the cursor. <Tab> Next wikilink on or after the cursor.
<S-Tab> Previous wikilink. <S-Tab> Previous wikilink.
@@ -491,7 +492,8 @@ Wiki / diary / export ~
<Leader>wi Open the diary index. <Leader>wi Open the diary index.
<Leader>w<Leader>w Today. <Leader>w<Leader>w Today.
<Leader>w<Leader>y Yesterday. <Leader>w<Leader>y Yesterday.
<Leader>w<Leader>t Tomorrow. <Leader>w<Leader>t Today, in a new tab.
<Leader>w<Leader>m Tomorrow.
<Leader>w<Leader>i Rebuild the diary index page. <Leader>w<Leader>i Rebuild the diary index page.
<Leader>wn Goto page (prompts for name). <Leader>wn Goto page (prompts for name).
<Leader>wd Delete the current page. <Leader>wd Delete the current page.
+2 -1
View File
@@ -206,7 +206,7 @@ if !has('nvim')
nnoremap <silent><buffer> <Leader>wi :call nuwiki#commands#diary_index()<CR> nnoremap <silent><buffer> <Leader>wi :call nuwiki#commands#diary_index()<CR>
nnoremap <silent><buffer> <Leader>w<Leader>w :call nuwiki#commands#diary_today()<CR> nnoremap <silent><buffer> <Leader>w<Leader>w :call nuwiki#commands#diary_today()<CR>
nnoremap <silent><buffer> <Leader>w<Leader>y :call nuwiki#commands#diary_yesterday()<CR> nnoremap <silent><buffer> <Leader>w<Leader>y :call nuwiki#commands#diary_yesterday()<CR>
nnoremap <silent><buffer> <Leader>w<Leader>t :call nuwiki#commands#diary_tomorrow()<CR> nnoremap <silent><buffer> <Leader>w<Leader>t :call nuwiki#commands#diary_today_tab()<CR>
nnoremap <silent><buffer> <Leader>w<Leader>m :call nuwiki#commands#diary_tomorrow()<CR> nnoremap <silent><buffer> <Leader>w<Leader>m :call nuwiki#commands#diary_tomorrow()<CR>
nnoremap <silent><buffer> <Leader>w<Leader>i :call nuwiki#commands#diary_generate_index()<CR> nnoremap <silent><buffer> <Leader>w<Leader>i :call nuwiki#commands#diary_generate_index()<CR>
endif endif
@@ -217,6 +217,7 @@ if !has('nvim')
nnoremap <silent><buffer> <S-CR> :split<CR>:call nuwiki#commands#follow_link_or_create()<CR> nnoremap <silent><buffer> <S-CR> :split<CR>:call nuwiki#commands#follow_link_or_create()<CR>
nnoremap <silent><buffer> <C-CR> :vsplit<CR>:call nuwiki#commands#follow_link_or_create()<CR> nnoremap <silent><buffer> <C-CR> :vsplit<CR>:call nuwiki#commands#follow_link_or_create()<CR>
nnoremap <silent><buffer> <C-S-CR> :call nuwiki#commands#follow_link_drop()<CR> nnoremap <silent><buffer> <C-S-CR> :call nuwiki#commands#follow_link_drop()<CR>
nnoremap <silent><buffer> <M-CR> :call nuwiki#commands#badd_link()<CR>
nnoremap <silent><buffer> <BS> <C-o> nnoremap <silent><buffer> <BS> <C-o>
nnoremap <silent><buffer> <Tab> /\[\[<CR>:nohlsearch<CR> nnoremap <silent><buffer> <Tab> /\[\[<CR>:nohlsearch<CR>
nnoremap <silent><buffer> <S-Tab> ?\[\[<CR>:nohlsearch<CR> nnoremap <silent><buffer> <S-Tab> ?\[\[<CR>:nohlsearch<CR>
+3 -1
View File
@@ -151,7 +151,7 @@ function M.attach(bufnr, mappings)
map('n', '<Leader>wi', cmd.diary_index, { desc = 'nuwiki: open diary index' }, bufnr) map('n', '<Leader>wi', cmd.diary_index, { desc = 'nuwiki: open diary index' }, bufnr)
map('n', '<Leader>w<Leader>w', cmd.diary_today, { desc = 'nuwiki: today' }, bufnr) map('n', '<Leader>w<Leader>w', cmd.diary_today, { desc = 'nuwiki: today' }, bufnr)
map('n', '<Leader>w<Leader>y', cmd.diary_yesterday, { desc = 'nuwiki: yesterday' }, bufnr) map('n', '<Leader>w<Leader>y', cmd.diary_yesterday, { desc = 'nuwiki: yesterday' }, bufnr)
map('n', '<Leader>w<Leader>t', cmd.diary_tomorrow, { desc = 'nuwiki: tomorrow' }, bufnr) map('n', '<Leader>w<Leader>t', cmd.diary_today_tab, { desc = 'nuwiki: today in a new tab' }, bufnr)
map('n', '<Leader>w<Leader>m', cmd.diary_tomorrow, { desc = 'nuwiki: tomorrow (vimwiki <Leader>w<Leader>m)' }, bufnr) map('n', '<Leader>w<Leader>m', cmd.diary_tomorrow, { desc = 'nuwiki: tomorrow (vimwiki <Leader>w<Leader>m)' }, bufnr)
map('n', '<Leader>w<Leader>i', cmd.diary_generate_index, { desc = 'nuwiki: rebuild diary index' }, bufnr) map('n', '<Leader>w<Leader>i', cmd.diary_generate_index, { desc = 'nuwiki: rebuild diary index' }, bufnr)
end end
@@ -166,6 +166,8 @@ function M.attach(bufnr, mappings)
{ desc = 'nuwiki: follow link in vsplit' }, bufnr) { desc = 'nuwiki: follow link in vsplit' }, bufnr)
map('n', '<C-S-CR>', cmd.follow_link_drop, map('n', '<C-S-CR>', cmd.follow_link_drop,
{ desc = 'nuwiki: follow link in tab (reuse existing)' }, bufnr) { desc = 'nuwiki: follow link in tab (reuse existing)' }, bufnr)
map('n', '<M-CR>', cmd.badd_link,
{ desc = 'nuwiki: add link target to buffer list' }, bufnr)
map('n', '<BS>', '<C-o>', { desc = 'nuwiki: go back', remap = true }, bufnr) map('n', '<BS>', '<C-o>', { desc = 'nuwiki: go back', remap = true }, bufnr)
map('n', '<Tab>', link.next, { desc = 'nuwiki: next wikilink' }, bufnr) map('n', '<Tab>', link.next, { desc = 'nuwiki: next wikilink' }, bufnr)
map('n', '<S-Tab>', link.prev, { desc = 'nuwiki: prev wikilink' }, bufnr) map('n', '<S-Tab>', link.prev, { desc = 'nuwiki: prev wikilink' }, bufnr)