gffranco 94cb58064d
CI / cargo fmt --check (push) Successful in 35s
CI / cargo clippy (push) Successful in 39s
CI / cargo test (push) Successful in 50s
CI / editor keymaps (push) Successful in 1m25s
feat(toc): insert a fresh TOC at the cursor line
:NuwikiTOC inserted a new table of contents at the top of the file. It now
inserts at the cursor line instead, so you can place the TOC where you want
it (a blank line separates it from preceding text). An existing TOC is
still refreshed in place, and auto_toc-on-save is unaffected.

The Vim/Lua clients send the 0-based cursor line with nuwiki.toc.generate;
the server threads it into toc_edit (clamped to the document) and falls
back to the top of the file when absent. toc_rebuild_edit passes None.

Tests: toc_edit_inserts_at_cursor_line +
toc_edit_cursor_line_clamped_and_existing_replaced_in_place. 575 passed,
clippy clean, keymap harnesses green. Doc updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:51:40 +00:00

nuwiki

A vimwiki-compatible Vim/Neovim plugin backed by a Rust language server.

nuwiki replaces the original vimwiki plugin while keeping its file format, keymaps, and :Vimwiki* command surface intact. The substantive work happens in a Rust LSP daemon — Vim and Neovim are thin client layers that wire up keystrokes and display results.

Features

Syntax & rendering

  • Full vimwiki syntax (.wiki) — headings, lists with checkboxes, numbered / lettered / Roman lists, tables (with |---|, |:--|--:|:--:| alignment markers and > / \/ colspan/rowspan), inline math, code fences, tags, comments, and links (wiki, interwiki, diary, file, local, raw URL, transclusion).
  • Transclusions support attributes: {{image.png|alt|style="border:1px"}}.
  • HTML export with templates, CSS, RSS feed, and incremental :VimwikiAll2HTML.

Editor intelligence (LSP)

  • Goto-definition (follow wikilinks), backlinks, hover preview, completion on [[, document outline, workspace symbol search.
  • Semantic-token highlighting (no syntax-file fallback needed). Code fences tagged with a language ({{{python … }}}) get that language's syntax automatically — no nested_syntaxes config needed.
  • Broken-link diagnostics and an orphan-page finder.
  • Folding: server-driven foldingRange by default, regex fallback when the server isn't ready.

Editing

  • Insert-mode smart <CR>: continues list markers (-, *, 1., a), i), …) and checkboxes; breaks out of an empty bullet; inserts a fresh row when inside a |…| table.
  • Insert-mode <Tab> / <S-Tab> jumps between table cells, adding a new row past the last column.
  • <C-D> / <C-T> indent/dedent the current list item; <C-L><C-J> / <C-L><C-K> cycle through the marker styles; <C-L><C-M> toggles or adds a checkbox.
  • Five text-object pairs in operator-pending + visual mode: ah/ih (heading section), aH/iH (heading + subtree), al/il (list item), a\/i\ (table cell), ac/ic (table column).
  • Two-step <CR> on a bare word: wraps it as [[word]], second press follows the link.

Diary

  • Daily diary out of the box (<Leader>w<Leader>w, <C-Down> / <C-Up>).
  • Configurable cadence: set diary_frequency = 'weekly' (or 'monthly' / 'yearly') per wiki and the commands address 2026-W19.wiki / 2026-05.wiki / 2026.wiki instead. Navigation stays at the same cadence as the entry under the cursor.
  • Diary index page generation (:VimwikiDiaryGenerateLinks).

Other

  • Multi-wiki with cross-wiki [[wn.name:Page]] interwiki links and a :VimwikiUISelect picker.
  • TOC generation, tag search, tag-to-page link lists.
  • :Vimwiki* command compat + canonical :Nuwiki* aliases.
  • Plain Vim and Neovim both supported with feature parity (text objects, folding, smart insert-mode bindings).

Installation

The plugin ships a nuwiki-ls binary that the editor talks to over LSP stdio. The install() helper downloads a pre-built release for your platform, falling back to cargo build --release if no asset matches. You can run it any time with :NuwikiInstall (works in both Vim and Neovim) instead of relying on a plugin-manager build hook.

Requirements

  • Neovim 0.11+ — uses the built-in LSP client; no extra plugin. Older releases fall back to a vim.lsp.start autocmd but aren't officially supported.
  • Vim 9+ — needs a third-party LSP client: vim-lsp or coc.nvim — both auto-registered, no manual config (see Vim LSP client setup).
  • Rust toolchain (1.83+ stable) — only needed when building the binary from source; pre-built release downloads skip this.

lazy.nvim

{
  'gffranco/nuwiki',
  build = ":lua require('nuwiki').install()",
  ft = { 'vimwiki' },
  opts = {
    wiki_root = '~/vimwiki',
  },
}

vim-plug

Plug 'gffranco/nuwiki', { 'do': 'vim -e -s -c "source scripts/download_bin.vim" -c "q"' }

In init.lua / init.vim:

require('nuwiki').setup({ wiki_root = '~/vimwiki' })

Dein

call dein#add('gffranco/nuwiki', {
  \ 'build': 'vim -e -s -c "source scripts/download_bin.vim" -c "q"'
  \ })

Plain Vim (no plugin manager)

git clone https://code.gfran.co/gffranco/nuwiki ~/.vim/pack/gffranco/start/nuwiki
cd ~/.vim/pack/gffranco/start/nuwiki && cargo build --release -p nuwiki-ls
mkdir -p bin && cp target/release/nuwiki-ls bin/

Vim LSP client setup

Neovim 0.11+ registers the server through its built-in LSP client automatically — nothing to configure. Plain Vim needs one of the following clients on its runtimepath; nuwiki picks them up in this order when the first .wiki buffer loads.

vim-lsp (recommended) — zero configuration. Once vim-lsp (and its async.vim dependency) is installed, nuwiki calls lsp#register_server() for you and vim-lsp auto-enables it. Your wiki settings (g:nuwiki_wiki_root, g:nuwiki_wikis, …) are forwarded as the server's initialization options.

coc.nvim — also zero configuration. nuwiki registers itself with coc.nvim programmatically (coc#config('languageserver.nuwiki', …)) when the first .wiki buffer loads, forwarding the same wiki settings (g:nuwiki_wiki_root, g:nuwiki_wikis, your g:vimwiki_* config, the global shorthand, …) as the server's initialization options. No coc-settings.json languageserver entry needed — change your wiki config and reload; the new settings are picked up.

To manage the entry yourself instead, set let g:nuwiki_no_coc_register = 1 and add it to coc-settings.json manually (nuwiki then just prints the snippet on first load):

{
  "languageserver": {
    "nuwiki": {
      "command": "~/.vim/pack/gffranco/start/nuwiki/bin/nuwiki-ls",
      "filetypes": ["vimwiki"],
      "initializationOptions": {
        "wiki_root": "~/vimwiki",
        "file_extension": ".wiki",
        "syntax": "vimwiki"
      }
    }
  }
}

Point command at the installed binary — by default it lives in the plugin's bin/ directory (adjust the path for your plugin manager), or set g:nuwiki_binary_path and reuse that value.

initializationOptions is required — it carries wiki_root (and the other config keys) to the server, exactly as the vim-lsp registration does automatically. Without it the server resolves links against its default root, so existing pages show up as broken links and following a link to a new page creates it in the wrong directory. (Run :NuwikiInstall-time guidance, or :call nuwiki#lsp#start() once, to have nuwiki print this snippet with your configured paths already filled in.) With coc you can also invoke server commands directly via :CocCommand nuwiki.<command> instead of the :Vimwiki* / :Nuwiki* aliases.

Try it without touching your config

./development/start-nvim.sh   # spawns Neovim against an isolated sample wiki
./development/start-vim.sh    # same, for plain Vim (clones vim-lsp on first run)

Both scripts build the LSP binary, seed a scratch wiki, and launch the editor against an isolated state dir under $XDG_CACHE_HOME/nuwiki-dev.


Configuration

Defaults are vimwiki-compatible. Every key has a sensible default — the example below shows the full surface for reference.

require('nuwiki').setup({
  -- Single-wiki shorthand (vimwiki-compatible).
  wiki_root      = '~/vimwiki',
  file_extension = '.wiki',
  syntax         = 'vimwiki',     -- 'vimwiki' | 'markdown' (future)
  log_level      = 'warn',

  -- Multi-wiki: each entry honours every per-wiki key vimwiki understands.
  -- Pick either this OR the single-wiki shorthand above. If both are set,
  -- `wikis` wins.
  wikis = {
    {
      name             = 'personal',
      root             = '~/vimwiki',
      index            = 'index',        -- index page stem
      file_extension   = '.wiki',
      -- Diary
      diary_rel_path   = 'diary',
      diary_index      = 'diary',
      diary_frequency  = 'daily',        -- 'daily' | 'weekly' | 'monthly' | 'yearly'
      diary_weekly_style = 'iso',        -- 'iso' (YYYY-Www) | 'date' (week-start YYYY-MM-DD, vimwiki)
      diary_start_week_day = 'monday',   -- week start for diary_weekly_style='date'
      diary_sort       = 'desc',         -- 'desc' | 'asc'
      diary_header     = 'Diary',
      -- HTML export
      html_path        = '~/vimwiki/_html',
      template_path    = '~/vimwiki/_templates',
      template_default = 'default',
      template_ext     = '.tpl',
      css_name         = 'style.css',
      custom_wiki2html = '',             -- external converter; empty = built-in renderer
      custom_wiki2html_args = '',        -- extra args appended to the converter call
      base_url         = '',             -- public URL prefix for RSS item links
      auto_export      = false,          -- export on save
      auto_toc         = false,          -- auto-refresh TOC on save
      auto_generate_links = false,       -- regen Generated Links on save
      auto_generate_tags  = false,       -- regen Generated Tags index on save
      auto_diary_index    = false,       -- regen diary index on diary-entry save
      toc_header       = 'Contents',     -- :VimwikiTOC caption (+ toc_header_level = 1)
      links_header     = 'Generated Links',
      tags_header      = 'Generated Tags',
      exclude_files    = {},             -- glob patterns
      -- Checkbox progression characters: " .oOX" by default.
      listsyms         = ' .oOX',
      listsym_rejected = '-',           -- glyph for a cancelled checkbox [-]
      listsyms_propagate = true,
    },
  },

  -- Keymap groups. Flip subgroups off independently. Defaults all on.
  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 (aliases gLH/gLL), glr, gLr (alias 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)
  },

  -- 'lsp' (server-driven foldingRange, default) | 'expr' (regex) | 'off'.
  folding = 'lsp',

  -- Mirror Vim's &autowriteall while in a wiki buffer (auto-save on switch).
  autowriteall = true,
  -- Re-align the table under the cursor on InsertLeave.
  table_auto_fmt = true,

  -- Broken-link diagnostic severity: 'off' | 'hint' | 'warn' | 'error'.
  diagnostic = {
    link_severity = 'warn',
  },
})

Vim users without Lua set the equivalent globals before loading the plugin:

let g:nuwiki_wiki_root            = '~/vimwiki'
let g:nuwiki_file_extension       = '.wiki'
let g:nuwiki_log_level            = 'warn'
let g:nuwiki_link_severity        = 'warn' " 'off'|'hint'|'warn'|'error'
let g:nuwiki_no_default_mappings  = 0   " set to 1 to skip the keymap layer
let g:nuwiki_map_prefix           = '<Leader>w'  " wiki command prefix
let g:nuwiki_no_folding           = 0   " set to 1 to skip foldexpr setup
let g:nuwiki_autowriteall         = 1   " set to 0 to not touch &autowriteall
let g:nuwiki_table_auto_fmt       = 1   " set to 0 to skip InsertLeave table re-align
let g:nuwiki_mouse_mappings       = 0   " set to 1 to enable mouse maps
" Drop individual keymap subgroups (mirror the Lua `mappings.<group>` toggles):
" g:nuwiki_no_{wiki_prefix,links,lists,headers,table_editing,diary,html_export,text_objects}_mappings

Reference

Top-level options

Key Type Default Accepted values
wiki_root string (path) '~/vimwiki' any directory path
file_extension string '.wiki' any extension, leading .
syntax string 'vimwiki' 'vimwiki' ('markdown' planned)
log_level string 'warn' 'error' | 'warn' | 'info' | 'debug'
map_prefix string '<Leader>w' prefix for the wiki command family (<prefix>w, <prefix>t, <prefix><Leader>w, …); mirrors vimwiki's g:vimwiki_map_prefix. Vim users set g:nuwiki_map_prefix
folding string 'lsp' 'lsp' | 'expr' | 'off'
autowriteall bool true mirror Vim's 'autowriteall' while in a wiki buffer (vimwiki autowriteall); Vim users set g:nuwiki_autowriteall
table_auto_fmt bool true re-align the table under the cursor on InsertLeave (vimwiki table_auto_fmt); Vim users set g:nuwiki_table_auto_fmt
auto_chdir bool false :lcd into the owning wiki's root when a wiki buffer becomes current (vimwiki auto_chdir); Vim users set g:nuwiki_auto_chdir
auto_header bool false insert a level-1 header from the filename on new wiki pages (vimwiki auto_header); honours links_space_char. Vim users set g:nuwiki_auto_header
use_calendar bool true wire up calendar-vim integration when it's on the runtimepath (g:calendar_action/g:calendar_sign); set false (or g:nuwiki_no_calendar) to opt out
wikis list of tables nil per-wiki tables (see below); wins over the single-wiki shorthand
mappings table all on keymap subgroups (see below)
diagnostic table { link_severity = 'warn' } link_severity: 'off' | 'hint' | 'warn' | 'error'

mappings subgroups

Each is a boolean. All default to true except mouse.

The <Leader>w prefix in the wiki_prefix, links, and html_export rows is the default map_prefix and moves with it.

Key Default Controls (every binding in the group)
enabled true master switch for the whole keymap layer
wiki_prefix true <Leader>ww, <Leader>wt, <Leader>ws, <Leader>wi, <Leader>w<Leader>w, <Leader>w<Leader>y, <Leader>w<Leader>t, <Leader>w<Leader>m, <Leader>w<Leader>i
links true <CR>, <S-CR>, <C-CR>, <C-S-CR>, <D-CR>, <M-CR>, <BS>, <Tab>, <S-Tab>, + (normal + visual), <CR> (visual: normalize selection), <Leader>wn, <Leader>wd, <Leader>wr, <Leader>wc (normal + visual)
lists true <C-Space> (also <C-@>/<Nul>), gnt, gln, glp, glx, glh, gll, gLh, gLl, gLH, gLL, glr, gLr, gLR, gl-, gl*, gl#, gl1, gli, glI, gla, glA, gL-, gL*, gL#, gL1, gLi, gLI, gLa, gLA, gl, gL, o, O; insert: <C-D>, <C-T>, <C-L><C-J>, <C-L><C-K>, <C-L><C-M>, <CR>, <S-CR> (multiline item)
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)

Per-wiki keys (wikis[])

Most display/generation keys below can also be set once at the top level as a default for every wiki (vimwiki-style global shorthand) — via setup({ … }) or g:nuwiki_<key> — and a per-wiki value overrides it. The keys that honour this are 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, and the auto_* toggles.

Key Type Default Accepted values
name string any label
root string (path) any directory path
file_extension string '.wiki' any extension
syntax string 'vimwiki' 'vimwiki'
index string 'index' index page stem
diary_rel_path string 'diary' path relative to root
diary_index string 'diary' diary index page stem
diary_frequency string 'daily' 'daily' | 'weekly' | 'monthly' | 'yearly'
diary_weekly_style string 'iso' 'iso' (YYYY-Www) | 'date'/'vimwiki' (week-start YYYY-MM-DD). Weekly only
diary_start_week_day string 'monday' 'monday''sunday'; week start when diary_weekly_style = 'date'
diary_caption_level int 0 06 (level of the index caption)
diary_sort string 'desc' 'desc' | 'asc'
diary_header string 'Diary' any heading text
diary_months list English month names month-number → display name used in the diary index
create_link bool true create the target page when following a link to a missing page; false makes the follow a no-op
dir_link string '' index stem opened when following a link to a directory (e.g. 'index'); empty opens the directory itself
bullet_types list ['-', '*', '#'] unordered-bullet glyphs for this wiki; drives cycle_bullets
cycle_bullets bool false rotate an unordered item's glyph through bullet_types as it is indented/dedented
generated_links_caption bool false emit [[page|Heading]] (first heading as caption) from :VimwikiGenerateLinks
toc_link_format int 0 0 = [[#anchor|title]] (with description); 1 = [[#anchor]] (anchor only)
table_reduce_last_col bool false don't pad the last table column to fill — keep it at its minimum width
listsyms string ' .oOX' checkbox progression chars
listsym_rejected string '-' glyph for a cancelled checkbox ([-]); first char used
listsyms_propagate bool true true | false
list_margin int -1 -1 (auto) or ≥ 0
links_space_char string ' ' char that replaces spaces in synthesised link paths
auto_toc bool false true | false
auto_generate_links bool false regenerate an existing Generated Links section on save
auto_generate_tags bool false regenerate an existing Generated Tags index on save
auto_diary_index bool false regenerate the diary index when a diary entry is saved
toc_header / toc_header_level string / int 'Contents' / 1 :VimwikiTOC caption + heading level
links_header / links_header_level string / int 'Generated Links' / 1 :VimwikiGenerateLinks caption + level
tags_header / tags_header_level string / int 'Generated Tags' / 1 :VimwikiGenerateTagLinks index caption + level

HTML export keys (per-wiki)

Key Type Default Accepted values
html_path string (path) '<root>/_html' output directory
template_path string (path) '<root>/_templates' template directory
template_default string 'default' template stem
template_ext string '.tpl' template extension
template_date_format string '%Y-%m-%d' strftime format
css_name string 'style.css' stylesheet filename
auto_export bool false true | false (export on save)
html_filename_parameterization bool false true | false
custom_wiki2html string '' external converter command; empty = built-in renderer. Called as <cmd> <force> <syntax> <ext> <out_dir> <in_file> <css> <tpl_path> <tpl_default> <tpl_ext> <root_path> <args> (- for empty optionals), matching vimwiki
custom_wiki2html_args string '' extra args appended to the custom_wiki2html call
base_url string '' public URL prefix; when set, diary RSS item links become <base_url><diary_rel_path>/<date>.html instead of file://
exclude_files list {} glob patterns
color_dic table {} { name = 'color', … } colour-tag name → CSS value
color_tag_template string '<span style="__STYLE__">__CONTENT__</span>' template for a color_dic colour span; __STYLE__color:<css>, __CONTENT__ → inner HTML
valid_html_tags string 'b,i,s,u,sub,sup,kbd,br,hr,div,center,strong,em' comma-separated inline HTML tags passed through export unescaped (span is always allowed)
emoji_enable bool true substitute :alias: emoji shortcodes with their glyph during export
text_ignore_newline bool true a single newline inside a paragraph is a space in HTML; false<br>
list_ignore_newline bool true a single newline inside a list item is a space in HTML; false<br>
rss_name string 'rss.xml' filename of the generated diary RSS feed, relative to html_path
rss_max_items int 10 cap on the number of diary items in the RSS feed
user_htmls list {} basenames of HTML files with no wiki source that :VimwikiAll2HTML must not prune

Vim globals (g:nuwiki_*)

For users configuring without Lua.

Global Default Meaning
g:nuwiki_wiki_root '~/vimwiki' single-wiki root
g:nuwiki_file_extension '.wiki' wiki file extension
g:nuwiki_syntax 'vimwiki' wiki syntax
g:nuwiki_diary_rel_path 'diary' diary subdirectory (relative to the wiki root)
g:nuwiki_wikis (unset) list of per-wiki dicts for multi-wiki setups; wins over the scalar globals
g:nuwiki_log_level 'warn' error | warn | info | debug
g:nuwiki_link_severity 'warn' broken-link severity: off | hint | warn | error
g:nuwiki_map_prefix '<Leader>w' prefix for the wiki command family
g:nuwiki_no_default_mappings 0 1 skips the whole keymap layer
g:nuwiki_no_wiki_prefix_mappings 0 1 skips the wiki_prefix group (<Leader>ww, <Leader>wt, <Leader>ws, <Leader>wi, <Leader>w<Leader>{w,y,t,m,i})
g:nuwiki_no_links_mappings 0 1 skips the links group (<CR>, <S-CR>, <C-CR>, <C-S-CR>, <D-CR>, <M-CR>, <BS>, <Tab>, <S-Tab>, +, <Leader>w{n,d,r,c})
g:nuwiki_no_lists_mappings 0 1 skips the lists group (<C-Space>, gnt, gln, glp, glx, glh, gll, gLh, gLl (aliases gLH/gLL), glr, gLr (alias gLR), gl{-,*,#,1,i,I,a,A}, gL{…}, gl, gL, o, O; insert <C-D>, <C-T>, <C-L><C-J/K/M>, <CR>)
g:nuwiki_no_headers_mappings 0 1 skips the headers group (=, -, ]], [[, ]=, [=, ]u, [u)
g:nuwiki_no_table_editing_mappings 0 1 skips the table_editing group (gqq, gq1, gww, gw1, <A-Left>, <A-Right>; insert <Tab>, <S-Tab>)
g:nuwiki_no_diary_mappings 0 1 skips the diary nav group (<C-Down>, <C-Up>)
g:nuwiki_no_html_export_mappings 0 1 skips the html_export group (<Leader>wh, <Leader>whh, <Leader>wha)
g:nuwiki_no_text_objects_mappings 0 1 skips the text_objects group (ah, ih, aH, iH, al, il, a\, i\, ac, ic)
g:nuwiki_no_folding 0 1 skips foldexpr setup
g:nuwiki_mouse_mappings 0 1 enables mouse maps
g:nuwiki_binary_path (auto) path to a prebuilt nuwiki-ls binary, bypassing the bundled one
g:nuwiki_build_from_source 0 1 builds the binary with cargo instead of downloading a release
g:nuwiki_no_calendar 0 1 opts out of calendar-vim integration
g:nuwiki_auto_chdir 0 1 :lcd into the wiki root when a wiki buffer becomes current
g:nuwiki_auto_header 0 1 insert a level-1 header from the filename on new wiki pages

Usage

Commands

:Nuwiki* is the canonical native surface; every command also has a :Vimwiki* counterpart for drop-in migration. Both are registered as buffer-local commands on every .wiki buffer (the wiki picker is also global so you can switch wikis before any .wiki file is open). Type :Nuwiki<Tab> or :Vimwiki<Tab> to browse them; coc.nvim users can also call the server directly with :CocCommand nuwiki.<command>.

Only the legacy short forms :VWB / :VWS and :VimwikiSearch keep a Vimwiki-only name (shown as in the Nuwiki column); every other command is mirrored. The split / tab link-following commands are available on both the Neovim and plain-Vim paths.

Wiki & navigation

Nuwiki Vimwiki Action
:NuwikiIndex [N] :VimwikiIndex [N] Open wiki N's index page (default: 1)
:NuwikiTabIndex [N] :VimwikiTabIndex [N] Same, in a new tab
:NuwikiUISelect :VimwikiUISelect Pick a wiki from a list (multi-wiki)
:NuwikiGoto {page} :VimwikiGoto {page} Open {page}.wiki by name
:NuwikiFollowLink :VimwikiFollowLink Follow the link under the cursor
:NuwikiSplitLink / :NuwikiVSplitLink / :NuwikiTabnewLink :VimwikiSplitLink / :VimwikiVSplitLink / :VimwikiTabnewLink Follow the link in a horizontal split / vertical split / new tab
:NuwikiTabDropLink :VimwikiTabDropLink Follow the link in a tab, reusing an existing tab if the file is already open
:NuwikiGoBackLink :VimwikiGoBackLink Jump back to where you followed the link from
:NuwikiBacklinks :VimwikiBacklinks (:VWB) Show all references to the current page
:NuwikiNextLink / :NuwikiPrevLink :VimwikiNextLink / :VimwikiPrevLink Jump to the next / previous wikilink
:NuwikiBaddLink :VimwikiBaddLink Add the link target under the cursor to the buffer list
:NuwikiNormalizeLink :VimwikiNormalizeLink Wrap the word / visual selection under the cursor as a wikilink
:NuwikiSearch {pat} :VimwikiSearch {pat} (:VWS) :lvimgrep {pat} across the current wiki's pages (empty {pat} reuses the last search)
:NuwikiVar :VimwikiVar [key [val]] Get/set nuwiki client config
:NuwikiReturn :VimwikiReturn Command form of the smart <CR> list/table continuation
:NuwikiShowVersion :VimwikiShowVersion Print the nuwiki version + host editor

Diary

Nuwiki Vimwiki Action
:NuwikiMakeDiaryNote (:NuwikiDiaryToday) :VimwikiMakeDiaryNote Open today's entry (or this week / month / year, per diary_frequency)
:NuwikiTabMakeDiaryNote :VimwikiTabMakeDiaryNote Open today's entry in a new tab
:NuwikiMakeYesterdayDiaryNote (:NuwikiDiaryYesterday) :VimwikiMakeYesterdayDiaryNote Step the diary back one period
:NuwikiMakeTomorrowDiaryNote (:NuwikiDiaryTomorrow) :VimwikiMakeTomorrowDiaryNote Step the diary forward one period
:NuwikiDiaryIndex :VimwikiDiaryIndex Open the diary index page
:NuwikiDiaryGenerateLinks :VimwikiDiaryGenerateLinks Rebuild the diary index from current entries
:NuwikiDiaryNextDay / :NuwikiDiaryPrevDay (:NuwikiDiaryNext / :NuwikiDiaryPrev) :VimwikiDiaryNextDay / :VimwikiDiaryPrevDay Chronological diary nav (same cadence as the current entry)

Pages & files

Nuwiki Vimwiki Action
:NuwikiRenameFile :VimwikiRenameFile (:VimwikiRenameLink) Rename the current page, rewriting incoming links
:NuwikiDeleteFile :VimwikiDeleteFile (:VimwikiDeleteLink) Delete the current page

Lists, tasks & tables

Nuwiki Vimwiki Action
:NuwikiNextTask :VimwikiNextTask Jump to the next unfinished task
:NuwikiToggleListItem :VimwikiToggleListItem Toggle the checkbox under the cursor (-range: every item in the selection)
:NuwikiToggleRejected :VimwikiToggleRejectedListItem Toggle the rejected marker [-]
:NuwikiListToggle :VimwikiListToggle Toggle a checkbox on the current item (adds [ ] if none)
:NuwikiIncrementListItem / :NuwikiDecrementListItem :VimwikiIncrementListItem / :VimwikiDecrementListItem Cycle the list marker to the next / previous symbol (-range: every item in the selection)
:NuwikiChangeSymbol {sym} :VimwikiChangeSymbolTo {sym} (:VimwikiListChangeSymbolI) Set the current item's marker to {sym}
:NuwikiChangeSymbolInList {sym} :VimwikiChangeSymbolInListTo {sym} Set every item in the list to {sym}
:NuwikiRemoveDone[!] :VimwikiRemoveDone[!] Remove every completed item from the current list; with !, from the whole buffer
:NuwikiRemoveCheckbox :VimwikiRemoveSingleCB Strip the checkbox from the current list item
:NuwikiRemoveCheckboxInList :VimwikiRemoveCBInList Strip the checkbox from every item in the current list
:NuwikiListChangeLvl {increase|decrease} :VimwikiListChangeLvl {increase|decrease} Indent / dedent the current list item
:NuwikiRenumberList :VimwikiRenumberList Renumber the current ordered list
:NuwikiRenumberAllLists :VimwikiRenumberAllLists Renumber every ordered list in the buffer
:NuwikiTable {cols} [rows] :VimwikiTable {cols} [rows] Insert a table at the cursor
:NuwikiTableMoveColumnLeft / :NuwikiTableMoveColumnRight :VimwikiTableMoveColumnLeft / :VimwikiTableMoveColumnRight Move the current table column left / right
:NuwikiTableAlign :VimwikiTableAlignQ / :VimwikiTableAlignW Re-align the current table's columns

Contents, links & tags

Nuwiki Vimwiki Action
:NuwikiTOC :VimwikiTOC Generate / refresh the table of contents on the current page
:NuwikiGenerateLinks :VimwikiGenerateLinks Insert a flat list of every page in the wiki
:NuwikiCheckLinks :VimwikiCheckLinks Send broken links to the quickfix list (-range: limit to the current buffer's selected lines)
:NuwikiFindOrphans :VimwikiFindOrphans List pages with no incoming links in the quickfix list
:NuwikiRebuildTags[!] :VimwikiRebuildTags[!] Re-index the current wiki; ! re-indexes every configured wiki
:NuwikiSearchTags {tag} :VimwikiSearchTags {tag} Quickfix listing every occurrence of :tag:
:NuwikiGenerateTagLinks [tag] :VimwikiGenerateTagLinks [tag] (:VimwikiGenerateTags) Insert a section linking every page that has <tag>
:NuwikiColorize {color} :VimwikiColorize {color} Wrap the word / visual selection in a coloured <span>
:NuwikiPasteLink / :NuwikiPasteUrl :VimwikiPasteLink / :VimwikiPasteUrl Paste the clipboard contents as a wikilink / raw URL
:NuwikiCatUrl :VimwikiCatUrl Echo the file:// URL of the current page's HTML export

HTML export

Nuwiki Vimwiki Action
:Nuwiki2HTML (:NuwikiExport) :Vimwiki2HTML Render the current page to HTML
:Nuwiki2HTMLBrowse (:NuwikiExportBrowse) :Vimwiki2HTMLBrowse Render the current page and open it in the default browser
:NuwikiAll2HTML[!] (:NuwikiExportAll[!]) :VimwikiAll2HTML[!] Export the whole wiki (! forces; otherwise incremental)
:NuwikiRss :VimwikiRss Write rss.xml for diary entries

Default keymaps

All buffer-local. Disable the whole layer via mappings.enabled = false in Neovim, or let g:nuwiki_no_default_mappings = 1 in Vim. Drop a single group via mappings.<group> = false in Neovim, or let g:nuwiki_no_<group>_mappings = 1 in Vim.

Links (normal mode)

Key Action
<CR> Smart follow — inside [[…]] jumps; on a bare word wraps as [[word]] (second <CR> follows)
<S-CR> Follow in horizontal split
<C-CR> Follow in vertical split
<C-S-CR> / <D-CR> Follow in a tab, reusing an existing tab if the file is already open (<D-CR> is the macOS Cmd alias)
<M-CR> Add the link target to the buffer list (:badd, no jump)
<BS> Jump back (<C-o>)
<Tab> / <S-Tab> Next / previous wikilink on or after the cursor
+ Wrap word / visual selection as a wikilink (no follow)

Lists (normal mode)

Key Action
<C-Space> / <C-@> / <Nul> Toggle the checkbox under the cursor (the three aliases cover terminal byte differences)
gln / glp Cycle the checkbox state forward / backward
glx Toggle the rejected marker [-]
gnt Jump to the next unfinished task
glh / gll Dedent / indent the current list item
gLh / gLl Dedent / indent including the item's sublist
glr Renumber the current ordered list
gLr Renumber every ordered list in the buffer
gl<sym> Set the current item's marker to <sym> — one of - * # 1 (1.) i (i)) I (I)) a (a)) A (A))
gL<sym> Set every item in the list to <sym> (same symbol keys)
gl Remove the checkbox from the current item, keeping its text
gL Remove the checkbox from every item in the current list
o / O Open a new line and continue the list marker (preserves any checkbox)

Bare gl / gL share the gl… prefix with the maps above, so (like upstream vimwiki) they fire only after 'timeoutlen'; type a suffix such as gln or gl* quickly to reach the prefixed maps. Removing done items is command-only: :NuwikiRemoveDone (current list) / :NuwikiRemoveDone! (whole buffer).

Lists (insert mode)

Key Action
<CR> Continue the list with the same marker (preserves checkbox), or break out on an empty bullet
<S-CR> Multiline list item continuation (no new marker)
<C-D> / <C-T> Dedent / indent the current item
<C-L><C-J> / <C-L><C-K> Cycle the marker style (-*#1.1)a)A)i)I))
<C-L><C-M> Toggle / add a checkbox on the current item

Headers

Key Action
= / - Increase / decrease the heading level
]] / [[ Next / previous heading (any level)
]= / [= Next / previous sibling heading
]u / [u Jump to the parent heading

Tables

Key Action
gqq / gq1 / gww / gw1 Align the table under the cursor
<A-Left> / <A-Right> Move the column under the cursor left / right
<Tab> / <S-Tab> (insert) Jump to the next / previous cell; <Tab> past the last cell inserts a fresh row
<CR> (insert) Insert a fresh empty row below the current one

Wiki / diary / export (normal mode)

The <Leader>w prefix below is the default map_prefix (g:nuwiki_map_prefix); change that option to relocate the whole family.

Key Action
<Leader>ww Open the wiki index
<Leader>wt Open the wiki index in a new tab
<Leader>ws Pick a wiki
<Leader>wi Open the diary index
<Leader>w<Leader>w / <Leader>w<Leader>y Diary today / yesterday
<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>wn / <Leader>wd / <Leader>wr Goto / delete / rename page
<Leader>wh / <Leader>whh Export the current page to HTML / open in browser
<Leader>wha Export every page
<Leader>wc Wrap word (or visual selection) in a colour span
<C-Down> / <C-Up> Next / previous diary entry

Mouse (normal mode, opt-in via mappings.mouse = true / let g:nuwiki_mouse_mappings = 1)

Key Action
<2-LeftMouse> Follow the link under the pointer
<S-2-LeftMouse> / <C-2-LeftMouse> Follow in a horizontal / vertical split
<MiddleMouse> Add the link target to the buffer list
<RightMouse> Jump back (<C-o>)

Text objects (operator-pending + visual)

Object Selection
ah / ih The heading's section (ih excludes the heading line)
aH / iH The heading's section plus every subheading underneath
al / il The list item under the cursor (il excludes the marker / checkbox)
a\ / i\ The table cell under the cursor (i\ excludes the surrounding |)
ac / ic The table column under the cursor (ic excludes the header separator row)

Health check (Neovim)

:checkhealth nuwiki

Reports the binary path, the LSP client status, registered executeCommand entries, whether foldingRange was negotiated, and whether the configured HTML output directory is writable.

Migrating from vimwiki

The file extension, syntax, command names, and default keymaps all match vimwiki. To migrate:

  1. Drop the original vimwiki plugin from your config.
  2. Install nuwiki.
  3. Keep your existing config, or point wiki_root / wikis[i].root at your directory.

Existing g:vimwiki_list config works as-is (Vim). When you haven't configured nuwiki natively (g:nuwiki_wikis / g:nuwiki_*), the Vim client reads your upstream g:vimwiki_list and g:vimwiki_* globals and translates them: each wiki's path/path_html/template_*/auto_export plus globals like toc_header_level, html_header_numbering, html_header_numbering_sym, links_space_char, and list_margin. Native g:nuwiki_* config always takes precedence. (Settings nuwiki implements differently — see known-issues.md — are ignored.)

Existing pages, diary entries, tags, and templates work without modification. The first workspace scan after launch may show an empty :VimwikiCheckLinks result until the background index completes; subsequent runs are instant.

A few upstream options are implemented differently or not at all — by design, since nuwiki is LSP-backed rather than pure VimL. See known-issues.md for the full list of divergences.


License

Dual-licensed under either of:

at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work shall be dual licensed as above, without any additional terms or conditions.

S
Description
No description provided
Readme 1.1 MiB
v0.5.2 Latest
2026-07-02 12:02:20 +00:00
Languages
Vim Script 49.1%
Lua 36.7%
Shell 11.2%
HTML 3%