gffranco 95645a2b91
CI / cargo fmt --check (push) Successful in 1m10s
CI / cargo clippy (push) Successful in 19s
CI / cargo test (push) Successful in 28s
Release / build x86_64-unknown-linux-gnu (push) Successful in 1m1s
Release / build aarch64-unknown-linux-musl (push) Successful in 54s
Release / build aarch64-unknown-linux-gnu (push) Successful in 1m8s
Release / build x86_64-unknown-linux-musl (push) Successful in 1m13s
CI / editor keymaps (push) Successful in 1m32s
Release / gitea release (push) Successful in 23s
fix(syntax): highlight code blocks with embedded language syntax
`{{{lang … }}}` fences were painted as one String group. Add automatic
nested-syntax highlighting (like vimwiki): scan the buffer for the languages
used, `:syntax include` each under a cluster, and define a contained region
per language so e.g. `{{{sh` blocks get shell highlighting and `{{{python`
gets Python. Bare `{{{` / `{{{class="…"` fences fall back to nuwikiPreformatted.
A small alias map maps labels like bash/shell → sh.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 22:24:27 -03: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).
  • 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>ww, <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.

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 && ln -s ../target/release/nuwiki-ls bin/nuwiki-ls

Plain Vim users also need an LSP client — vim-lsp is the recommended path, with coc.nvim as a fallback. Neovim 0.11+ uses its built-in LSP client and needs no extra plugin.

Try it without touching your config

./start-nvim.sh           # spawns Neovim against an isolated sample wiki
./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_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',
      auto_export      = false,          -- export on save
      auto_toc         = false,          -- auto-refresh TOC on save
      exclude_files    = {},             -- glob patterns
      -- Checkbox progression characters: " .oOX" by default.
      listsyms         = ' .oOX',
      listsyms_propagate = true,
      -- Inline highlighting: 6 heading levels by default.
      maxhi            = 1,
      -- Embed other syntaxes inside `{{{lang …}}}` fences.
      nested_syntaxes  = {},
    },
  },

  -- Keymap groups. Flip subgroups off independently. Defaults all on.
  mappings = {
    enabled       = true,
    wiki_prefix   = true,  -- <Leader>w*
    links         = true,  -- <CR>, <S-CR>, <Tab>, <BS>, +, …
    lists         = true,  -- <C-Space>, gln/glp/glx, gl<Space>, o/O, …
    headers       = true,  -- =, -, ]], [[, ]=, [=, ]u, [u
    table_editing = true,  -- gqq, <A-Left>, <A-Right>, <Tab> in insert mode
    diary         = true,  -- <C-Down>, <C-Up>
    html_export   = true,  -- <Leader>wh, <Leader>whh
    text_objects  = true,  -- ah, ih, aH, iH, al, il, a\, i\, ac, ic
    mouse         = false, -- <2-LeftMouse>, <RightMouse>, …  (opt-in)
  },

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

  -- 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_no_default_mappings  = 0   " set to 1 to skip the keymap layer
let g:nuwiki_no_folding           = 0   " set to 1 to skip foldexpr setup
let g:nuwiki_mouse_mappings       = 0   " set to 1 to enable mouse maps

Usage

Commands

Both :Vimwiki* (migration compat) and :Nuwiki* (canonical native) are registered as buffer-local commands on every .wiki buffer. Selected highlights — type :Vimwiki<Tab> for the full list.

Command What it does
:VimwikiIndex [N] Open wiki N's index page (default: 1)
:VimwikiTabIndex [N] Same, in a new tab
:VimwikiUISelect Pick a wiki from a list (multi-wiki only)
:VimwikiGoto {page} Open {page}.wiki by name
:VimwikiMakeDiaryNote Open today's diary entry (or this week / month / year, depending on diary_frequency)
:VimwikiMakeYesterdayDiaryNote / :VimwikiMakeTomorrowDiaryNote Step the diary back / forward by one period
:VimwikiDiaryIndex Open the diary index page
:VimwikiDiaryGenerateLinks Rebuild the diary index from current entries
:VimwikiDiaryNextDay / :VimwikiDiaryPrevDay Chronological diary nav (same cadence as the current entry)
:VimwikiTOC Generate / refresh the table of contents on the current page
:VimwikiGenerateLinks Insert a flat list of every page in the wiki
:VimwikiCheckLinks Send broken links to the quickfix list
:VimwikiSearchTags {tag} Quickfix listing every occurrence of :tag:
:VimwikiGenerateTagLinks [tag] Insert a section linking every page that has <tag>
:VimwikiRebuildTags Force a full workspace re-index
:VimwikiRenameFile Rename the current page, rewriting incoming links
:VimwikiDeleteFile Delete the current page
:Vimwiki2HTML Render the current page to HTML
:Vimwiki2HTMLBrowse Render the current page and open it in the default browser
:VimwikiAll2HTML[!] Export the whole wiki (! forces; otherwise incremental)
:VimwikiRss Write rss.xml for diary entries
:VimwikiFollowLink Follow the link under the cursor
:VimwikiBacklinks Show all references to the current page
:VimwikiNextLink / :VimwikiPrevLink Jump to the next / previous wikilink on the page
:VimwikiBaddLink Add the target of the link under the cursor to the buffer list

Default keymaps

All buffer-local. Disable any group via mappings.<group> = false in Neovim, or let g:nuwiki_no_default_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> Follow in a new tab
<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<Space> Remove every completed item from the current list
gL<Space> Remove every completed item in the buffer
o / O Open a new line and continue the list marker (preserves any checkbox)

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

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)

Key Action
<Leader>ww Open today's diary
<Leader>ws Pick a wiki
<Leader>wi Open the diary index
<Leader>w<Leader>w / <Leader>w<Leader>y / <Leader>w<Leader>t Today / yesterday / 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

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. Point wiki_root (or each wikis[i].root) at your existing directory.

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.


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%