2026-05-10 16:01:58 +00:00
# nuwiki
2026-05-12 14:20:18 +00:00
**A vimwiki-compatible Vim/Neovim plugin backed by a Rust language server. **
2026-05-10 16:01:58 +00:00
2026-05-12 14:20:18 +00:00
nuwiki replaces the original [vimwiki ](https://github.com/vimwiki/vimwiki )
plugin while keeping its file format, keymaps, and `:Vimwiki*` command
surface intact. The substantive work happens in a Rust LSP daemon — Vim
2026-05-12 22:46:16 +00:00
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.
2026-05-30 23:12:14 -03:00
- 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.
2026-05-12 22:46:16 +00:00
- 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
2026-05-31 19:33:20 +00:00
- Daily diary out of the box (`<Leader>w<Leader>w` , `<C-Down>` / `<C-Up>` ).
2026-05-12 22:46:16 +00:00
- 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).
2026-05-10 17:20:46 +00:00
2026-05-12 14:20:18 +00:00
---
## Installation
2026-05-12 22:46:16 +00:00
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.
2026-05-30 15:54:12 -03:00
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` ](https://github.com/prabirshrestha/vim-lsp ) (recommended,
auto-registered) or [`coc.nvim` ](https://github.com/neoclide/coc.nvim )
(one-time `coc-settings.json` entry — see [Vim LSP client
setup ](#vim-lsp-client-setup )).
- **Rust toolchain (1.83+ stable)** — only needed when building the
binary from source; pre-built release downloads skip this.
2026-05-12 14:20:18 +00:00
### lazy.nvim
``` lua
{
' gffranco/nuwiki ' ,
build = " :lua require('nuwiki').install() " ,
ft = { ' vimwiki ' } ,
opts = {
wiki_root = ' ~/vimwiki ' ,
} ,
}
```
### vim-plug
``` vim
Plug 'gffranco/nuwiki' , { 'do' : 'vim -e -s -c "source scripts/download_bin.vim" -c "q"' }
```
In `init.lua` / `init.vim` :
``` lua
require ( ' nuwiki ' ) . setup ( { wiki_root = ' ~/vimwiki ' } )
```
### Dein
``` vim
call dein #add ( 'gffranco/nuwiki' , {
\ 'build' : 'vim -e -s -c "source scripts/download_bin.vim" -c "q"'
\ })
```
### Plain Vim (no plugin manager)
``` sh
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
2026-05-21 20:39:37 -03:00
mkdir -p bin && ln -s ../target/release/nuwiki-ls bin/nuwiki-ls
2026-05-12 14:20:18 +00:00
```
2026-05-30 15:54:12 -03:00
### 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` ](https://github.com/prabirshrestha/vim-lsp ) (and its
[`async.vim` ](https://github.com/prabirshrestha/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 ** — [`coc.nvim` ](https://github.com/neoclide/coc.nvim ) reads
its server list from `coc-settings.json` , which the plugin can't edit
on your behalf, so add the entry once yourself (open it with
`:CocConfig` ):
``` json
{
"languageserver" : {
"nuwiki" : {
"command" : "~/.vim/pack/gffranco/start/nuwiki/bin/nuwiki-ls" ,
2026-05-31 15:00:59 +00:00
"filetypes" : [ "vimwiki" ] ,
"initializationOptions" : {
"wiki_root" : "~/vimwiki" ,
"file_extension" : ".wiki" ,
"syntax" : "vimwiki"
}
2026-05-30 15:54:12 -03:00
}
}
}
```
Point `command` at the installed binary — by default it lives in the
plugin's `bin/` directory (adjust the path for your plugin manager), or
2026-05-31 15:00:59 +00:00
set `g:nuwiki_binary_path` and reuse that value.
`initializationOptions` is **required ** — it carries `wiki_root` (and the
other [config keys ](#configuration )) 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.
2026-05-12 14:20:18 +00:00
2026-05-12 22:46:16 +00:00
### Try it without touching your config
2026-05-12 14:20:18 +00:00
``` sh
2026-05-30 18:35:40 +00:00
./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)
2026-05-12 14:20:18 +00:00
```
2026-05-12 22:46:16 +00:00
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` .
2026-05-12 14:20:18 +00:00
---
## Configuration
2026-05-12 22:46:16 +00:00
Defaults are vimwiki-compatible. Every key has a sensible default — the
example below shows the full surface for reference.
2026-05-12 14:20:18 +00:00
``` lua
require ( ' nuwiki ' ) . setup ( {
-- Single-wiki shorthand (vimwiki-compatible).
wiki_root = ' ~/vimwiki ' ,
file_extension = ' .wiki ' ,
syntax = ' vimwiki ' , -- 'vimwiki' | 'markdown' (future)
log_level = ' warn ' ,
2026-05-12 22:46:16 +00:00
-- 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.
2026-05-12 14:20:18 +00:00
wikis = {
{
2026-05-12 22:46:16 +00:00
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'
2026-05-31 17:06:09 +00:00
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'
2026-05-12 22:46:16 +00:00
diary_sort = ' desc ' , -- 'desc' | 'asc'
diary_header = ' Diary ' ,
-- HTML export
2026-05-12 14:20:18 +00:00
html_path = ' ~/vimwiki/_html ' ,
template_path = ' ~/vimwiki/_templates ' ,
template_default = ' default ' ,
template_ext = ' .tpl ' ,
css_name = ' style.css ' ,
2026-05-31 19:06:42 +00:00
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
2026-05-12 22:46:16 +00:00
auto_export = false , -- export on save
auto_toc = false , -- auto-refresh TOC on save
2026-05-31 18:55:51 +00:00
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
2026-05-31 18:44:35 +00:00
toc_header = ' Contents ' , -- :VimwikiTOC caption (+ toc_header_level = 1)
links_header = ' Generated Links ' ,
tags_header = ' Generated Tags ' ,
2026-05-12 22:46:16 +00:00
exclude_files = { } , -- glob patterns
-- Checkbox progression characters: " .oOX" by default.
listsyms = ' .oOX ' ,
2026-05-31 18:33:25 +00:00
listsym_rejected = ' - ' , -- glyph for a cancelled checkbox [-]
2026-05-12 22:46:16 +00:00
listsyms_propagate = true ,
2026-05-12 14:20:18 +00:00
} ,
} ,
2026-05-12 22:46:16 +00:00
-- Keymap groups. Flip subgroups off independently. Defaults all on.
2026-05-12 14:20:18 +00:00
mappings = {
enabled = true ,
2026-05-31 19:40:06 +00:00
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)
2026-06-03 00:28:51 +00:00
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>
2026-05-12 14:20:18 +00:00
headers = true , -- =, -, ]], [[, ]=, [=, ]u, [u
2026-05-31 19:40:06 +00:00
table_editing = true , -- gqq, gq1, gww, gw1, <A-Left>, <A-Right>; insert <Tab>, <S-Tab>
2026-05-12 14:20:18 +00:00
diary = true , -- <C-Down>, <C-Up>
2026-05-31 19:40:06 +00:00
html_export = true , -- <Leader>wh, <Leader>whh, <Leader>wha
2026-05-12 22:46:16 +00:00
text_objects = true , -- ah, ih, aH, iH, al, il, a\, i\, ac, ic
2026-05-31 19:40:06 +00:00
mouse = false , -- <2-LeftMouse>, <S-2-LeftMouse>, <C-2-LeftMouse>, <MiddleMouse>, <RightMouse> (opt-in)
2026-05-12 14:20:18 +00:00
} ,
2026-05-12 22:46:16 +00:00
-- 'lsp' (server-driven foldingRange, default) | 'expr' (regex) | 'off'.
2026-05-12 14:20:18 +00:00
folding = ' lsp ' ,
2026-06-03 00:59:33 +00:00
-- 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 ,
2026-05-12 14:20:18 +00:00
-- Broken-link diagnostic severity: 'off' | 'hint' | 'warn' | 'error'.
diagnostic = {
link_severity = ' warn ' ,
} ,
} )
```
2026-05-12 22:46:16 +00:00
Vim users without Lua set the equivalent globals before loading the
plugin:
2026-05-12 14:20:18 +00:00
``` vim
2026-05-12 22:46:16 +00:00
let g :nuwiki_wiki_root = '~/vimwiki'
let g :nuwiki_file_extension = '.wiki'
let g :nuwiki_log_level = 'warn'
2026-05-30 21:53:56 -03:00
let g :nuwiki_link_severity = 'warn' " 'off'|'hint'|'warn'|'error'
2026-05-12 22:46:16 +00:00
let g :nuwiki_no_default_mappings = 0 " set to 1 to skip the keymap layer
2026-05-31 19:18:06 +00:00
let g :nuwiki_map_prefix = '<Leader>w' " wiki command prefix
2026-05-12 22:46:16 +00:00
let g :nuwiki_no_folding = 0 " set to 1 to skip foldexpr setup
2026-06-03 00:59:33 +00:00
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
2026-05-12 22:46:16 +00:00
let g :nuwiki_mouse_mappings = 0 " set to 1 to enable mouse maps
2026-05-30 23:40:29 -03:00
" 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
2026-05-12 14:20:18 +00:00
```
2026-05-30 19:24:08 -03:00
### 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'` |
2026-05-31 19:18:06 +00:00
| `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` |
2026-05-30 19:24:08 -03:00
| `folding` | string | `'lsp'` | `'lsp'` \| `'expr'` \| `'off'` |
2026-06-03 00:59:33 +00:00
| `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` |
2026-05-30 19:24:08 -03:00
| `wikis` | list of tables | `nil` | per-wiki tables (see below); wins over the single-wiki shorthand |
| `mappings` | table | all on | keymap subgroups (see below) |
2026-05-30 21:53:56 -03:00
| `diagnostic` | table | `{ link_severity = 'warn' }` | `link_severity` : `'off'` \| `'hint'` \| `'warn'` \| `'error'` |
2026-05-30 19:24:08 -03:00
#### `mappings` subgroups
Each is a boolean. All default to `true` except `mouse` .
2026-05-31 19:40:06 +00:00
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) |
2026-05-30 19:24:08 -03:00
|-----|---------|----------|
| `enabled` | `true` | master switch for the whole keymap layer |
2026-05-31 19:40:06 +00:00
| `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` |
2026-06-03 11:04:56 +00:00
| `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) |
2026-05-30 19:24:08 -03:00
| `headers` | `true` | `=` , `-` , `]]` , `[[` , `]=` , `[=` , `]u` , `[u` |
2026-05-31 19:40:06 +00:00
| `table_editing` | `true` | `gqq` , `gq1` , `gww` , `gw1` , `<A-Left>` , `<A-Right>` ; insert: `<Tab>` , `<S-Tab>` |
2026-05-30 19:24:08 -03:00
| `diary` | `true` | `<C-Down>` , `<C-Up>` |
2026-05-31 19:40:06 +00:00
| `html_export` | `true` | `<Leader>wh` , `<Leader>whh` , `<Leader>wha` |
2026-05-30 19:24:08 -03:00
| `text_objects` | `true` | `ah` , `ih` , `aH` , `iH` , `al` , `il` , `a\` , `i\` , `ac` , `ic` |
2026-05-31 19:40:06 +00:00
| `mouse` | `false` | `<2-LeftMouse>` , `<S-2-LeftMouse>` , `<C-2-LeftMouse>` , `<MiddleMouse>` , `<RightMouse>` (opt-in) |
2026-05-30 19:24:08 -03:00
#### Per-wiki keys (`wikis[]`)
| 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'` |
2026-05-31 17:06:09 +00:00
| `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` | `0` – `6` (level of the index caption) |
2026-05-30 19:24:08 -03:00
| `diary_sort` | string | `'desc'` | `'desc'` \| `'asc'` |
| `diary_header` | string | `'Diary'` | any heading text |
| `listsyms` | string | `' .oOX'` | checkbox progression chars |
2026-05-31 18:33:25 +00:00
| `listsym_rejected` | string | `'-'` | glyph for a cancelled checkbox (`[-]` ); first char used |
2026-05-30 19:24:08 -03:00
| `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` |
2026-05-31 18:55:51 +00:00
| `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 |
2026-05-31 18:44:35 +00:00
| `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 |
2026-05-30 19:24:08 -03:00
#### 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` |
2026-05-31 19:06:42 +00:00
| `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://` |
2026-05-30 19:24:08 -03:00
| `exclude_files` | list | `{}` | glob patterns |
| `color_dic` | table | `{}` | `{ name = 'color', … }` |
#### 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 |
2026-05-31 19:33:20 +00:00
| `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 |
2026-05-30 19:24:08 -03:00
| `g:nuwiki_log_level` | `'warn'` | `error` \| `warn` \| `info` \| `debug` |
2026-05-30 21:53:56 -03:00
| `g:nuwiki_link_severity` | `'warn'` | broken-link severity: `off` \| `hint` \| `warn` \| `error` |
2026-05-31 19:33:20 +00:00
| `g:nuwiki_map_prefix` | `'<Leader>w'` | prefix for the wiki command family |
2026-05-30 23:40:29 -03:00
| `g:nuwiki_no_default_mappings` | `0` | `1` skips the whole keymap layer |
2026-05-31 19:40:06 +00:00
| `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}` ) |
2026-06-03 00:28:51 +00:00
| `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>` ) |
2026-05-31 19:40:06 +00:00
| `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` ) |
2026-05-30 19:24:08 -03:00
| `g:nuwiki_no_folding` | `0` | `1` skips foldexpr setup |
| `g:nuwiki_mouse_mappings` | `0` | `1` enables mouse maps |
2026-05-31 19:33:20 +00:00
| `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 |
2026-05-30 19:24:08 -03:00
2026-05-12 14:20:18 +00:00
---
## Usage
### Commands
2026-05-30 15:54:12 -03:00
`: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
2026-05-31 07:54:32 -03:00
command is mirrored. The split / tab link-following commands are
available on both the Neovim and plain-Vim paths.
2026-05-30 15:54:12 -03:00
**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 |
2026-05-31 07:54:32 -03:00
| `: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 |
2026-05-30 15:54:12 -03:00
| `: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 |
2026-05-30 17:36:05 -03:00
| `:NuwikiNormalizeLink` | `:VimwikiNormalizeLink` | Wrap the word / visual selection under the cursor as a wikilink |
2026-06-03 01:23:07 +00:00
| — | `: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 |
2026-05-30 15:54:12 -03:00
**Diary **
| Nuwiki | Vimwiki | Action |
|---|---|---|
| `:NuwikiMakeDiaryNote` (`:NuwikiDiaryToday` ) | `:VimwikiMakeDiaryNote` | Open today's entry (or this week / month / year, per `diary_frequency` ) |
2026-05-30 17:36:05 -03:00
| `:NuwikiTabMakeDiaryNote` | `:VimwikiTabMakeDiaryNote` | Open today's entry in a new tab |
2026-05-30 15:54:12 -03:00
| `: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 |
|---|---|---|
2026-05-30 17:36:05 -03:00
| `:NuwikiRenameFile` | `:VimwikiRenameFile` (`:VimwikiRenameLink` ) | Rename the current page, rewriting incoming links |
| `:NuwikiDeleteFile` | `:VimwikiDeleteFile` (`:VimwikiDeleteLink` ) | Delete the current page |
2026-05-30 15:54:12 -03:00
**Lists, tasks & tables **
| Nuwiki | Vimwiki | Action |
|---|---|---|
| `:NuwikiNextTask` | `:VimwikiNextTask` | Jump to the next unfinished task |
2026-05-31 17:57:03 +00:00
| `:NuwikiToggleListItem` | `:VimwikiToggleListItem` | Toggle the checkbox under the cursor (`-range` : every item in the selection) |
2026-05-30 15:54:12 -03:00
| `:NuwikiToggleRejected` | `:VimwikiToggleRejectedListItem` | Toggle the rejected marker `[-]` |
2026-05-30 17:36:05 -03:00
| `:NuwikiListToggle` | `:VimwikiListToggle` | Toggle a checkbox on the current item (adds `[ ]` if none) |
2026-05-31 17:57:03 +00:00
| `:NuwikiIncrementListItem` / `:NuwikiDecrementListItem` | `:VimwikiIncrementListItem` / `:VimwikiDecrementListItem` | Cycle the list marker to the next / previous symbol (`-range` : every item in the selection) |
2026-05-30 17:36:05 -03:00
| `: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}` |
2026-05-31 08:41:33 -03:00
| `:NuwikiRemoveDone[!]` | `:VimwikiRemoveDone[!]` | Remove every completed item from the current list; with `!` , from the whole buffer |
2026-05-30 17:36:05 -03:00
| `:NuwikiRemoveCheckbox` | `:VimwikiRemoveSingleCB` | Strip the checkbox from the current list item |
| `:NuwikiRemoveCheckboxInList` | `:VimwikiRemoveCBInList` | Strip the checkbox from every item in the current list |
2026-05-30 15:54:12 -03:00
| `:NuwikiListChangeLvl {increase\|decrease}` | `:VimwikiListChangeLvl {increase\|decrease}` | Indent / dedent the current list item |
2026-05-30 17:36:05 -03:00
| `:NuwikiRenumberList` | `:VimwikiRenumberList` | Renumber the current ordered list |
| `:NuwikiRenumberAllLists` | `:VimwikiRenumberAllLists` | Renumber every ordered list in the buffer |
2026-05-30 15:54:12 -03:00
| `:NuwikiTable {cols} [rows]` | `:VimwikiTable {cols} [rows]` | Insert a table at the cursor |
| `:NuwikiTableMoveColumnLeft` / `:NuwikiTableMoveColumnRight` | `:VimwikiTableMoveColumnLeft` / `:VimwikiTableMoveColumnRight` | Move the current table column left / right |
2026-05-30 17:36:05 -03:00
| `:NuwikiTableAlign` | `:VimwikiTableAlignQ` / `:VimwikiTableAlignW` | Re-align the current table's columns |
2026-05-30 15:54:12 -03:00
**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 |
2026-05-31 17:57:03 +00:00
| `:NuwikiCheckLinks` | `:VimwikiCheckLinks` | Send broken links to the quickfix list (`-range` : limit to the current buffer's selected lines) |
2026-05-30 15:54:12 -03:00
| `:NuwikiFindOrphans` | `:VimwikiFindOrphans` | List pages with no incoming links in the quickfix list |
2026-05-31 17:57:03 +00:00
| `:NuwikiRebuildTags[!]` | `:VimwikiRebuildTags[!]` | Re-index the current wiki; `!` re-indexes every configured wiki |
2026-05-30 15:54:12 -03:00
| `:NuwikiSearchTags {tag}` | `:VimwikiSearchTags {tag}` | Quickfix listing every occurrence of `:tag:` |
2026-05-30 17:36:05 -03:00
| `:NuwikiGenerateTagLinks [tag]` | `:VimwikiGenerateTagLinks [tag]` (`:VimwikiGenerateTags` ) | Insert a section linking every page that has `<tag>` |
2026-05-30 15:54:12 -03:00
| `: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 |
2026-05-30 17:36:05 -03:00
| `:NuwikiCatUrl` | `:VimwikiCatUrl` | Echo the `file://` URL of the current page's HTML export |
2026-05-30 15:54:12 -03:00
**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 |
2026-05-12 14:20:18 +00:00
### Default keymaps
2026-05-30 23:40:29 -03:00
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.
2026-05-12 14:20:18 +00:00
2026-05-12 22:46:16 +00:00
**Links ** (normal mode)
2026-05-12 14:20:18 +00:00
| Key | Action |
|---|---|
2026-05-12 22:46:16 +00:00
| `<CR>` | Smart follow — inside `[[…]]` jumps; on a bare word wraps as `[[word]]` (second `<CR>` follows) |
2026-05-12 14:20:18 +00:00
| `<S-CR>` | Follow in horizontal split |
| `<C-CR>` | Follow in vertical split |
2026-05-31 17:28:06 +00:00
| `<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) |
2026-05-31 16:21:49 +00:00
| `<M-CR>` | Add the link target to the buffer list (`:badd` , no jump) |
2026-05-12 14:20:18 +00:00
| `<BS>` | Jump back (`<C-o>` ) |
| `<Tab>` / `<S-Tab>` | Next / previous wikilink on or after the cursor |
2026-05-12 22:46:16 +00:00
| `+` | Wrap word / visual selection as a wikilink (no follow) |
2026-05-12 14:20:18 +00:00
2026-05-12 22:46:16 +00:00
**Lists ** (normal mode)
2026-05-12 14:20:18 +00:00
| Key | Action |
|---|---|
2026-05-12 22:46:16 +00:00
| `<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 |
2026-05-12 14:20:18 +00:00
| `glx` | Toggle the rejected marker `[-]` |
| `gnt` | Jump to the next unfinished task |
2026-05-12 22:46:16 +00:00
| `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 |
2026-05-31 08:10:15 -03:00
| `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) |
2026-05-31 08:41:33 -03:00
| `gl` | Remove the checkbox from the current item, keeping its text |
| `gL` | Remove the checkbox from every item in the current list |
2026-05-12 22:46:16 +00:00
| `o` / `O` | Open a new line and continue the list marker (preserves any checkbox) |
2026-05-31 08:41:33 -03:00
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).
2026-05-12 22:46:16 +00:00
**Lists ** (insert mode)
| Key | Action |
|---|---|
| `<CR>` | Continue the list with the same marker (preserves checkbox), or break out on an empty bullet |
| `<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 |
2026-05-12 14:20:18 +00:00
**Headers **
| Key | Action |
|---|---|
2026-05-12 22:46:16 +00:00
| `=` / `-` | Increase / decrease the heading level |
| `]]` / `[[` | Next / previous heading (any level) |
2026-05-12 14:20:18 +00:00
| `]=` / `[=` | Next / previous sibling heading |
2026-05-12 22:46:16 +00:00
| `]u` / `[u` | Jump to the parent heading |
2026-05-12 14:20:18 +00:00
2026-05-12 22:46:16 +00:00
**Tables **
2026-05-12 14:20:18 +00:00
| Key | Action |
|---|---|
2026-05-12 22:46:16 +00:00
| `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)
2026-05-31 19:33:20 +00:00
The `<Leader>w` prefix below is the default `map_prefix` (`g:nuwiki_map_prefix` ); change that option to relocate the whole family.
2026-05-12 22:46:16 +00:00
| Key | Action |
|---|---|
2026-05-30 15:54:12 -03:00
| `<Leader>ww` | Open the wiki index |
| `<Leader>wt` | Open the wiki index in a new tab |
2026-05-12 22:46:16 +00:00
| `<Leader>ws` | Pick a wiki |
| `<Leader>wi` | Open the diary index |
2026-05-31 16:21:49 +00:00
| `<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 |
2026-05-12 22:46:16 +00:00
| `<Leader>w<Leader>i` | Rebuild the diary index page |
2026-05-12 14:20:18 +00:00
| `<Leader>wn` / `<Leader>wd` / `<Leader>wr` | Goto / delete / rename page |
2026-05-12 22:46:16 +00:00
| `<Leader>wh` / `<Leader>whh` | Export the current page to HTML / open in browser |
2026-05-12 14:20:18 +00:00
| `<Leader>wha` | Export every page |
2026-05-12 22:46:16 +00:00
| `<Leader>wc` | Wrap word (or visual selection) in a colour span |
2026-05-12 14:20:18 +00:00
| `<C-Down>` / `<C-Up>` | Next / previous diary entry |
2026-05-30 15:54:12 -03:00
**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>` ) |
2026-05-12 22:46:16 +00:00
**Text objects ** (operator-pending + visual)
2026-05-12 14:20:18 +00:00
2026-05-12 22:46:16 +00:00
| Object | Selection |
2026-05-12 14:20:18 +00:00
|---|---|
2026-05-12 22:46:16 +00:00
| `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) |
2026-05-12 14:20:18 +00:00
2026-05-12 22:46:16 +00:00
### Health check (Neovim)
2026-05-12 14:20:18 +00:00
``` vim
: 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
2026-05-12 22:46:16 +00:00
match vimwiki. To migrate:
2026-05-12 14:20:18 +00:00
2026-05-12 22:46:16 +00:00
1. Drop the original `vimwiki` plugin from your config.
2. Install nuwiki.
3. Point `wiki_root` (or each `wikis[i].root` ) at your existing
directory.
2026-05-12 14:20:18 +00:00
2026-05-12 22:46:16 +00:00
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.
2026-05-11 14:32:22 +00:00
2026-05-12 14:20:18 +00:00
---
2026-05-10 16:01:58 +00:00
## License
Dual-licensed under either of:
- Apache License, Version 2.0 ([`LICENSE-APACHE` ](./LICENSE-APACHE ))
- MIT license ([`LICENSE-MIT` ](./LICENSE-MIT ))
at your option. Unless you explicitly state otherwise, any contribution
2026-05-12 14:20:18 +00:00
intentionally submitted for inclusion in this work shall be dual licensed
as above, without any additional terms or conditions.