diff --git a/README.md b/README.md index 242d3f5..d492ebd 100644 --- a/README.md +++ b/README.md @@ -5,33 +5,72 @@ 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 -and Neovim are thin client layers that just wire up keystrokes and -display results. +and Neovim are thin client layers that wire up keystrokes and display +results. -- ✅ Full vimwiki syntax (`.wiki`) — headings, lists with checkboxes, - tables, math, code, tags, links (wiki / interwiki / diary / file / - raw URL / transclusion). -- ✅ Goto-definition, backlinks, hover, completion, workspace symbol - search, semantic highlighting — all over LSP. -- ✅ Diary (today/yesterday/tomorrow/next/prev), tags (search + link - generation), TOC generation, broken-link diagnostics, orphan finder. -- ✅ Multi-wiki with cross-wiki interwiki links (`[[wn.name:Page]]`). -- ✅ HTML export with templates, CSS, auto-export on save, RSS feed. -- ✅ Folding (LSP `foldingRange` + regex fallback), header & link - text objects, the `` two-step link-create-and-follow. -- ✅ `:Vimwiki*` command compat + `:Nuwiki*` canonical aliases. +## Features -See [`SPEC.md`](./SPEC.md) for the architecture, design decisions, and -the full phase log. +### 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 ``: continues list markers (`-`, `*`, `1.`, + `a)`, `i)`, …) and checkboxes; breaks out of an empty bullet; inserts + a fresh row when inside a `|…|` table. +- Insert-mode `` / `` jumps between table cells, adding a + new row past the last column. +- `` / `` indent/dedent the current list item; `` + / `` cycle through the marker styles; `` 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 `` on a bare word: wraps it as `[[word]]`, second press + follows the link. + +### Diary + +- Daily diary out of the box (`ww`, `` / ``). +- 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()` Lua helper downloads a pre-built release for -your platform, falling back to `cargo build --release` if no asset -matches. +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 @@ -74,31 +113,28 @@ cd ~/.vim/pack/gffranco/start/nuwiki && cargo build --release -p nuwiki-ls mkdir -p bin && ln -s target/release/nuwiki-ls bin/nuwiki-ls ``` -Then ensure an LSP client is loaded (Vim path prefers -[`vim-lsp`](https://github.com/prabirshrestha/vim-lsp), falls back to -[`coc.nvim`](https://github.com/neoclide/coc.nvim)). Neovim 0.11+ uses -its built-in LSP client — no extra plugin needed. +Plain Vim users also need an LSP client — +[`vim-lsp`](https://github.com/prabirshrestha/vim-lsp) is the +recommended path, with [`coc.nvim`](https://github.com/neoclide/coc.nvim) +as a fallback. Neovim 0.11+ uses its built-in LSP client and needs +no extra plugin. -### Trying it without touching your config +### Try it without touching your config ```sh -./start-nvim.sh # spawns Neovim with a scratch wiki under - # $XDG_CACHE_HOME/nuwiki-dev -./start-vim.sh # same, but for plain Vim — clones vim-lsp - # into the cache on first run +./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 sample wiki, and launch -the editor against an isolated state dir. Pass a wiki file path to -open it directly; `NUWIKI_DEV_WIKI=/path/to/wiki` points at your -own sandbox instead. +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. Full schema (with type annotations and -defaults) lives in [`lua/nuwiki/config.lua`](./lua/nuwiki/config.lua). +Defaults are vimwiki-compatible. Every key has a sensible default — the +example below shows the full surface for reference. ```lua require('nuwiki').setup({ @@ -108,41 +144,55 @@ require('nuwiki').setup({ syntax = 'vimwiki', -- 'vimwiki' | 'markdown' (future) log_level = 'warn', - -- Or the multi-wiki form. The single-wiki keys above desugar into - -- a one-entry `wikis = [...]` list, so you can pick either shape. + -- 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', - file_extension = '.wiki', - diary_rel_path = 'diary', - diary_index = 'diary', - -- HTML export (Phase 17) + 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 - exclude_files = {}, -- glob patterns + 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. + -- Keymap groups. Flip subgroups off independently. Defaults all on. mappings = { enabled = true, wiki_prefix = true, -- w* links = true, -- , , , , +, … - lists = true, -- , gln/glp/glx, gl, o/O + lists = true, -- , gln/glp/glx, gl, o/O, … headers = true, -- =, -, ]], [[, ]=, [=, ]u, [u - table_editing = true, -- gqq, gq1, gww, gw1, , + table_editing = true, -- gqq, , , in insert mode diary = true, -- , html_export = true, -- wh, whh - text_objects = true, -- ah, ih + text_objects = true, -- ah, ih, aH, iH, al, il, a\, i\, ac, ic + mouse = false, -- <2-LeftMouse>, , … (opt-in) }, - -- Folding strategy: 'lsp' (server-driven foldingRange — default on - -- Neovim 0.11+), 'expr' (pure regex), or 'off'. + -- 'lsp' (server-driven foldingRange, default) | 'expr' (regex) | 'off'. folding = 'lsp', -- Broken-link diagnostic severity: 'off' | 'hint' | 'warn' | 'error'. @@ -152,14 +202,16 @@ require('nuwiki').setup({ }) ``` -Vim users without Lua should set the equivalent globals before sourcing -the plugin: +Vim users without Lua set the equivalent globals before loading the +plugin: ```vim -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_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 ``` --- @@ -170,89 +222,122 @@ let g:nuwiki_no_default_mappings = 0 " set to 1 to skip the keymap layer Both `:Vimwiki*` (migration compat) and `:Nuwiki*` (canonical native) are registered as buffer-local commands on every `.wiki` buffer. -Selected highlights — see `:Vimwiki` for the full list. +Selected highlights — type `:Vimwiki` for the full list. | Command | What it does | |---|---| -| `:VimwikiIndex [N]` | Open wiki N's `index.wiki` (default: 1) | +| `: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) | -| `:VimwikiMakeDiaryNote` | Open today's diary page | -| `:VimwikiDiaryNextDay` / `:VimwikiDiaryPrevDay` | Chronological diary nav | -| `:VimwikiTOC` | Generate / refresh table of contents on the current page | -| `:VimwikiGenerateLinks` | Flat list of every page in the wiki | +| `: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 of all occurrences of `:tag:` | -| `:VimwikiGenerateTagLinks [tag]` | Insert a section linking all pages with `` | +| `:VimwikiSearchTags {tag}` | Quickfix listing every occurrence of `:tag:` | +| `:VimwikiGenerateTagLinks [tag]` | Insert a section linking every page that has `` | | `:VimwikiRebuildTags` | Force a full workspace re-index | -| `:VimwikiRenameFile` | Rename current page; rewrites incoming links | -| `:VimwikiDeleteFile` | Delete current page (server-side `DeleteFile`) | -| `:Vimwiki2HTML` | Render current page to HTML | -| `:Vimwiki2HTMLBrowse` | Render + open in default browser | -| `:VimwikiAll2HTML[!]` | Export the whole wiki (`!` forces, otherwise incremental) | -| `:VimwikiRss` | Write `rss.xml` of diary entries | -| `:VimwikiFollowLink` | Follow link under cursor (``) | -| `:VimwikiBacklinks` | Show references to current page | +| `: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. = false` in Neovim, or `let g:nuwiki_no_default_mappings = 1` in Vim. -**Links** +**Links** (normal mode) | Key | Action | |---|---| -| `` | Smart follow: inside `[[…]]` → jump; on a bare word → wrap as `[[word]]` (second `` follows) | +| `` | Smart follow — inside `[[…]]` jumps; on a bare word wraps as `[[word]]` (second `` follows) | | `` | Follow in horizontal split | | `` | Follow in vertical split | -| `` | Follow in new tab | +| `` | Follow in a new tab | | `` | Jump back (``) | | `` / `` | Next / previous wikilink on or after the cursor | +| `+` | Wrap word / visual selection as a wikilink (no follow) | -**Lists** +**Lists** (normal mode) | Key | Action | |---|---| -| `` / `` / `` | Toggle checkbox (terminal byte aliases) | -| `gln` / `glp` | Cycle checkbox state (forward / backward) | +| `` / `` / `` | 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 | -| `o` / `O` | Open a new line and continue the list marker (and checkbox if any) | +| `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` | Remove every completed item from the current list | +| `gL` | 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 | +|---|---| +| `` | Continue the list with the same marker (preserves checkbox), or break out on an empty bullet | +| `` / `` | Dedent / indent the current item | +| `` / `` | Cycle the marker style (`-` → `*` → `#` → `1.` → `1)` → `a)` → `A)` → `i)` → `I)`) | +| `` | Toggle / add a checkbox on the current item | **Headers** | Key | Action | |---|---| -| `=` / `-` | Add / remove a heading level | -| `]]` / `[[` | Next / previous heading | +| `=` / `-` | Increase / decrease the heading level | +| `]]` / `[[` | Next / previous heading (any level) | | `]=` / `[=` | Next / previous sibling heading | -| `]u` / `[u` | Jump to parent heading | +| `]u` / `[u` | Jump to the parent heading | -**Wiki / diary / export** +**Tables** | Key | Action | |---|---| -| `ww` | Today's diary | -| `ws` | Pick a wiki (`vim.ui.select` / `inputlist`) | -| `wi` | Diary index | +| `gqq` / `gq1` / `gww` / `gw1` | Align the table under the cursor | +| `` / `` | Move the column under the cursor left / right | +| `` / `` (insert) | Jump to the next / previous cell; `` past the last cell inserts a fresh row | +| `` (insert) | Insert a fresh empty row below the current one | + +**Wiki / diary / export** (normal mode) + +| Key | Action | +|---|---| +| `ww` | Open today's diary | +| `ws` | Pick a wiki | +| `wi` | Open the diary index | | `ww` / `wy` / `wt` | Today / yesterday / tomorrow | -| `wi` | Rebuild diary index page | +| `wi` | Rebuild the diary index page | | `wn` / `wd` / `wr` | Goto / delete / rename page | -| `wh` / `whh` | Export current page → HTML / open in browser | +| `wh` / `whh` | Export the current page to HTML / open in browser | | `wha` | Export every page | +| `wc` | Wrap word (or visual selection) in a colour span | | `` / `` | Next / previous diary entry | -**Text objects** +**Text objects** (operator-pending + visual) -| Key | Selection | +| Object | Selection | |---|---| -| `ah` / `ih` | A heading (with / without the heading line itself) | +| `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) | -Additional text objects (`aH`, `iH`, `a\`, `i\`, `ac`, `ic`, `al`, -`il`) are planned follow-ups now that the table/list rewriter -commands they depend on have shipped. - -### Health check +### Health check (Neovim) ```vim :checkhealth nuwiki @@ -265,96 +350,17 @@ whether the configured HTML output directory is writable. ### Migrating from vimwiki The file extension, syntax, command names, and default keymaps all -match vimwiki. Drop the original `vimwiki` plugin from your config, -install nuwiki, and point `wiki_root` at the same directory. Existing -pages, diary entries, tags, and templates Just Work. +match vimwiki. To migrate: -Two known behavior deltas vs. upstream vimwiki: +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. -- nuwiki's index is built lazily on workspace scan; the very first - `:VimwikiCheckLinks` after launch may be empty until the background - task completes. Subsequent runs are instant. -- `gln` and `glp` both call `nuwiki.list.cycleCheckbox`, which is - forward-only at present. A reverse cycle lands once the v1.1 list - rewriters do. - ---- - -## Repository layout - -``` -nuwiki/ -├── Cargo.toml workspace root -├── crates/ -│ ├── nuwiki-core/ parser, AST, renderer (editor-independent) -│ ├── nuwiki-lsp/ LSP protocol bridge -│ └── nuwiki-ls/ stdio LSP binary entry point -├── plugin/ universal Vim/Neovim entry point -├── lua/nuwiki/ Neovim Lua glue -├── autoload/nuwiki/ Vim VimL glue -├── ftdetect/ filetype detection for .wiki -├── ftplugin/vimwiki.vim per-buffer settings + commands + keymaps -├── syntax/vimwiki.vim static fallback highlighting -├── doc/ `:h nuwiki` -├── scripts/ test harness + build helpers -└── .gitea/workflows/ CI / release pipelines -``` - -## Development - -### Build + test - -```sh -cargo build --workspace -cargo test --workspace # 381 Rust tests -./scripts/test-keymaps.sh # 19 Neovim keymap cases (LSP-driven) -./scripts/test-keymaps-vim.sh # 12 Vim keymap cases (pure-VimL) -``` - -CI runs all four on every push (`.gitea/workflows/ci.yaml`). MSRV: Rust -1.83. - -### Trying changes against a real wiki - -```sh -./start-nvim.sh # isolated state under -./start-vim.sh # $XDG_CACHE_HOME/nuwiki-dev -``` - -Both regenerate their minimal config on every launch and seed a -scratch wiki with sample pages, links, checkboxes, and tags. - -### Implementation status - -#### v1.0 — foundation - -| Phase | Name | Status | -|---|---|---| -| 0 | Scaffolding | ✅ done | -| 1 | Core AST | ✅ done | -| 2 | Syntax Plugin Interface | ✅ done | -| 3 | Vimwiki Lexer | ✅ done | -| 4 | Vimwiki Parser | ✅ done | -| 5 | Renderer | ✅ done | -| 6 | LSP Foundation | ✅ done | -| 7 | Semantic Tokens | ✅ done | -| 8 | Navigation | ✅ done | -| 9 | Editor Glue | ✅ done | -| 10 | CI/CD release pipeline | ✅ done | - -#### v1.1 — full vimwiki replacement - -| Phase | Name | Status | -|---|---|---| -| 11 | Plumbing prerequisites | ✅ done | -| 12 | Tags | ✅ done | -| 13 | Workspace edits + executeCommand | ✅ done | -| 14 | List & table edit commands | ✅ done | -| 15 | Link health + TOC/index generation | ✅ done | -| 16 | Diary | ✅ done | -| 17 | HTML export commands | ✅ done | -| 18 | Multi-wiki | ✅ done | -| 19 | Editor glue v2 (`:Vimwiki*` compat, keymaps, text objects, folding) | ✅ done | +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. --- diff --git a/doc/nuwiki.txt b/doc/nuwiki.txt index f202b54..ff412da 100644 --- a/doc/nuwiki.txt +++ b/doc/nuwiki.txt @@ -1,4 +1,4 @@ -*nuwiki.txt* LSP-backed vimwiki support for Vim and Neovim. +*nuwiki.txt* A vimwiki-compatible plugin backed by a Rust language server. Author: Gabriel Fróes Franco License: Dual MIT / Apache-2.0 @@ -10,17 +10,42 @@ CONTENTS *nuwiki-contents* 2. Requirements ............ |nuwiki-requirements| 3. Installation ............ |nuwiki-installation| 4. Configuration ........... |nuwiki-config| - 5. Health check ............ |nuwiki-health| - 6. LSP features ............ |nuwiki-features| - 7. Commands ................ |nuwiki-commands| + 5. Commands ................ |nuwiki-commands| + 6. Keymaps ................. |nuwiki-keymaps| + 7. Text objects ............ |nuwiki-text-objects| + 8. Insert-mode bindings .... |nuwiki-insert-mode| + 9. Diary ................... |nuwiki-diary| + 10. Tables ................... |nuwiki-tables| + 11. HTML export .............. |nuwiki-html| + 12. Folding .................. |nuwiki-folding| + 13. Health check ............. |nuwiki-health| + 14. Migrating from vimwiki ... |nuwiki-migrating| ============================================================================== 1. INTRODUCTION *nuwiki-introduction* -nuwiki brings full vimwiki syntax support to Vim and Neovim via a Rust- -based language server (|nuwiki-ls|). It is architecturally distinct from -vimwiki itself — installable through any standard plugin manager, with the -heavy lifting done in a single binary that speaks LSP over stdio. +nuwiki keeps vimwiki's file format, keymaps, and `:Vimwiki*` command surface +intact, but moves the heavy lifting into a Rust language server that the +editor talks to over LSP stdio. The result feels like vimwiki — same files, +same shortcuts — with goto-definition, backlinks, completion, semantic +highlighting, broken-link diagnostics, and incremental HTML export. + +Highlights: + + * Full vimwiki syntax — headings, lists, checkboxes, tables (with + alignment / colspan / rowspan), inline math, code, tags, every link + kind (wiki, interwiki, diary, file, local, raw URL, transclusion with + attributes). + * LSP intelligence — goto-definition, backlinks, hover, completion on + `[[`, document outline, workspace symbol search, broken-link + diagnostics, orphan-page finder. + * Editing helpers — smart `` continues lists / tables, `` + cycles between table cells, five text-object pairs, list-marker + cycling. + * Diary at four cadences — daily, weekly, monthly, or yearly. + * Multi-wiki with `[[wn.name:Page]]` interwiki links. + * HTML export with templates, CSS, RSS, and on-save export. + * Plain Vim and Neovim both supported with feature parity. ============================================================================== 2. REQUIREMENTS *nuwiki-requirements* @@ -29,15 +54,15 @@ heavy lifting done in a single binary that speaks LSP over stdio. * Vim 9.1+ with one of: - vim-lsp (prabirshrestha/vim-lsp) - coc.nvim (neoclide/coc.nvim) - * `curl` and `tar` (only for binary download; not needed if you build - from source) + * `curl` and `tar` (only for the binary download path; not needed if + you build from source) * `cargo` and a Rust toolchain (only if you opt into source builds) ============================================================================== 3. INSTALLATION *nuwiki-installation* -Install via your plugin manager of choice; the build hook will download -the pre-built `nuwiki-ls` binary into the plugin's `bin/` directory. +Install via your plugin manager; the build hook downloads a pre-built +`nuwiki-ls` binary into the plugin's `bin/` directory. lazy.nvim: > @@ -45,7 +70,7 @@ lazy.nvim: > "gffranco/nuwiki", build = "lua require('nuwiki').install()", ft = { "vimwiki" }, - opts = {}, + opts = { wiki_root = "~/vimwiki" }, } @@ -58,7 +83,7 @@ lazy.nvim: > \ 'build': 'vim -e -s -c "source scripts/download_bin.vim" -c "q"', \ }) - + let g:nuwiki_build_from_source = 1 @@ -70,7 +95,8 @@ lazy.nvim: > <============================================================================== 4. CONFIGURATION *nuwiki-config* -Neovim (`require('nuwiki').setup{}`): > +Neovim users call `setup()` (omit the block entirely to take every +default): > require('nuwiki').setup({ wiki_root = '~/vimwiki', @@ -79,85 +105,533 @@ Neovim (`require('nuwiki').setup{}`): > log_level = 'warn', }) - + - let g:nuwiki_wiki_root = '~/vimwiki' - let g:nuwiki_file_extension = '.wiki' - let g:nuwiki_syntax = 'vimwiki' - let g:nuwiki_log_level = 'warn' + require('nuwiki').setup({ + wikis = { + { + name = 'personal', + root = '~/vimwiki', + index = 'index', + file_extension = '.wiki', + diary_rel_path = 'diary', + diary_frequency = 'daily', -- daily | weekly | monthly | yearly + diary_sort = 'desc', + html_path = '~/vimwiki/_html', + template_path = '~/vimwiki/_templates', + template_default = 'default', + css_name = 'style.css', + auto_export = false, + nested_syntaxes = { python = 'python' }, + }, + }, + }) - + + let g:nuwiki_wiki_root = '~/vimwiki' + let g:nuwiki_file_extension = '.wiki' + let g:nuwiki_log_level = 'warn' + +.tpl` templates. +`template_default` `'default'` +`template_ext` `'.tpl'` +`css_name` `'style.css'` +`auto_export` `false` — export to HTML on save. +`auto_toc` `false` — refresh TOC on save. +`exclude_files` List of glob patterns excluded from export. +`listsyms` `' .oOX'` — checkbox progression characters. +`listsyms_propagate` `true` +`maxhi` `1` — inline heading-level highlighting count. +`nested_syntaxes` `{}` — embed other syntaxes inside + `{{{lang …}}}` fenced blocks. +`links_space_char` `' '` + +Vim-specific globals ~ + + *g:nuwiki_no_default_mappings* +`g:nuwiki_no_default_mappings` 0 + When 1, the Vim path skips every buffer-local keymap. Equivalent to + `mappings.enabled = false` in Neovim. + + *g:nuwiki_no_folding* +`g:nuwiki_no_folding` 0 + When 1, the Vim path skips `foldexpr` / `foldmethod` setup. + + *g:nuwiki_mouse_mappings* +`g:nuwiki_mouse_mappings` 0 + When 1, the Vim path registers mouse keymaps (double-click follows, + middle-click `:badd`s the link target, etc.). Mirrors + `mappings.mouse = true` in Neovim. + + *g:nuwiki_build_from_source* +`g:nuwiki_build_from_source` 0 + When 1, the install step always builds the server with `cargo` and + skips the release-asset download. + + *g:nuwiki_binary_path* `g:nuwiki_binary_path` - Override the auto-discovered server path. If set and the file is - readable, `autoload/nuwiki/lsp.vim` uses it instead of the - `{plugin}/bin/nuwiki-ls` default. + Override the auto-discovered server binary path. If set and the + file is readable, it overrides the `{plugin}/bin/nuwiki-ls` default. ============================================================================== -5. HEALTH CHECK *nuwiki-health* +5. COMMANDS *nuwiki-commands* -Neovim users can run: > +Every command listed below is registered buffer-local on `.wiki` files +under both names: the `:Vimwiki*` form (for migration from vimwiki) and +the canonical `:Nuwiki*` alias. Only the `:Vimwiki*` form is shown. - :checkhealth nuwiki +Wiki / navigation ~ -`. With no + argument, generates a section per tag found in the workspace. + + *:VimwikiRebuildTags* +:VimwikiRebuildTags + Force a full workspace re-index. + +HTML export ~ + + *:Vimwiki2HTML* +:Vimwiki2HTML + Render the current page to HTML. + + *:Vimwiki2HTMLBrowse* +:Vimwiki2HTMLBrowse + Render the current page and open it in the default browser. + + *:VimwikiAll2HTML* +:VimwikiAll2HTML[!] + Export every page in the wiki. `!` forces a full rebuild; otherwise + only out-of-date pages are re-rendered. + + *:VimwikiRss* +:VimwikiRss + Write `rss.xml` summarising recent diary entries. + +Other ~ *:NuwikiInstall* :NuwikiInstall Install (or re-install) the `nuwiki-ls` binary into the plugin's `bin/` directory. Equivalent to running the build hook by hand. +============================================================================== +6. KEYMAPS *nuwiki-keymaps* + +Every keymap is buffer-local. Disable a group via `mappings. = +false` in Neovim, or `let g:nuwiki_no_default_mappings = 1` in Vim. + +Links (normal mode) ~ + + Smart follow — inside `[[…]]` jumps; on a bare word + wraps as `[[word]]` (second follows the link). + Follow in a horizontal split. + Follow in a vertical split. + Follow in a new tab. + Jump back (``). + Next wikilink on or after the cursor. + Previous wikilink. + + Wrap word (or visual selection) as `[[word]]`. No follow. + +Lists (normal mode) ~ + + Toggle the checkbox under the cursor. Also bound to + and to cover terminal byte differences. + gln Cycle the checkbox state forward. + glp Cycle the checkbox state backward. + glx Toggle the rejected marker `[-]`. + gnt Jump to the next unfinished task. + glh Dedent the current list item. + gll Indent the current list item. + gLh Dedent the item including its sublist. + gLl Indent the item including its sublist. + glr Renumber the current ordered list. + gLr Renumber every ordered list in the buffer. + gl Remove every completed item from the current list. + gL Remove every completed item in the buffer. + o Open a new line and continue the list marker (preserves + any checkbox). + O Same, opening above the current line. + +Headers ~ + + = Increase the heading level under the cursor. + - Decrease the heading level. + ]] Next heading (any level). + [[ Previous heading. + ]= Next sibling heading. + [= Previous sibling heading. + ]u Jump to the parent heading. + [u Same — alternate binding. + +Tables (normal mode) ~ + + gqq Align the table under the cursor. Also `gq1`, `gww`, `gw1`. + Move the column under the cursor left. + Move the column under the cursor right. + +Wiki / diary / export ~ + + ww Open today's diary. + ws Pick a wiki. + wi Open the diary index. + ww Today. + wy Yesterday. + wt Tomorrow. + wi Rebuild the diary index page. + wn Goto page (prompts for name). + wd Delete the current page. + wr Rename the current page. + wh Export the current page to HTML. + whh Export and open in the browser. + wha Export every page. + wc Wrap word / selection in a colour span. + Next diary entry. + Previous diary entry. + +Mouse (opt-in via |g:nuwiki_mouse_mappings|) ~ + + <2-LeftMouse> Follow the link clicked. + Follow in a horizontal split. + Follow in a vertical split. + Add the link target to the buffer list. + Jump back (``). + +============================================================================== +7. TEXT OBJECTS *nuwiki-text-objects* + +Operator-pending + visual. Disable via `mappings.text_objects = false`. + + ah A heading section — the heading line and everything up to + the next heading at any level. + ih Same, but excluding the heading line itself. + aH A heading section plus every subheading underneath — stops + at the next heading of same-or-shallower level. + iH Same, but excluding the heading line. + al The list item under the cursor. + il Same, but excluding the marker / checkbox prefix. + a\ The table cell under the cursor (includes the trailing `|`). + i\ Same, content only — no surrounding `|`s or padding. + ac The table column under the cursor (includes the header + separator row). + ic Same, content cells only. + +============================================================================== +8. INSERT-MODE BINDINGS *nuwiki-insert-mode* + +Smart return ~ + +`` is bound to a smart helper that does the right thing depending +on context: + + * On a list item with content — continue the list with the same marker + on a new line. Preserves a leading checkbox if present. + * On an empty list item (marker only) — clear the marker and break + out of the list with a plain newline. + * Inside a `|…|` table row — insert a fresh empty row below with the + same column count; cursor lands inside the first cell. + * Otherwise — plain ``. + +Table cell navigation ~ + + Jump to the next cell. Past the last cell, insert a fresh + row below and land in its first cell. + Jump to the previous cell. + +Outside a table row both pass through to their default insert-mode +behaviour (literal tab / shift-tab). + +List editing ~ + + Dedent the current list item. + Indent the current list item. + Cycle the marker forward through the canonical run: + `-` → `*` → `#` → `1.` → `1)` → `a)` → `A)` → `i)` → `I)` + Cycle the marker backward. + Toggle the checkbox on the current item, or insert + `[ ]` after the marker when there isn't one. + +============================================================================== +9. DIARY *nuwiki-diary* + +The diary holds dated entries under `//` — +`diary/` by default. + +Frequencies ~ + +The `diary_frequency` per-wiki option controls the cadence: + + daily YYYY-MM-DD e.g. `2026-05-12.wiki` (default) + weekly YYYY-Www ISO 8601 week, e.g. `2026-W19.wiki` + monthly YYYY-MM e.g. `2026-05.wiki` + yearly YYYY e.g. `2026.wiki` + +`:VimwikiMakeDiaryNote` opens the entry for the current period at the +configured cadence; the yesterday / tomorrow commands step back and +forward by one period. `` / `` walk between indexed +entries of the same flavour as the one under the cursor — so on a +weekly page, navigation stays weekly. + +Index ~ + +`:VimwikiDiaryGenerateLinks` rebuilds the diary index page (`diary.wiki` +by default) with a chronological list of every entry on disk, grouped +by year / month. The page name is set by `diary_index`; the heading is +set by `diary_header`. + +============================================================================== +10. TABLES *nuwiki-tables* + +Tables use vimwiki's pipe syntax: > + + | Name | Score | + |-------|-------| + | Alice | 97 | + | Bob | 72 | + +` merges with the cell to its left (colspan); +a cell containing just `\/` merges with the cell directly above +(rowspan). The HTML renderer emits proper `colspan="N"` / `rowspan="N"` +attributes plus `style="text-align: …;"` per cell when alignment is +specified. + +See |nuwiki-keymaps| for the table-editing shortcuts (alignment, +column moves, cell navigation, new-row insertion). + +============================================================================== +11. HTML EXPORT *nuwiki-html* + +`:Vimwiki2HTML` renders the current page; `:Vimwiki2HTMLBrowse` opens +the result in the default browser; `:VimwikiAll2HTML` exports every +page (incremental by default; `!` forces a full rebuild). + +Per-wiki knobs: + + `html_path` Output directory (created if missing). + `template_path` Where to find `.tpl` files. + `template_default` Default template name (without extension). + `template_ext` Template file extension (default `.tpl`). + `css_name` CSS file copied into `html_path`. + `auto_export` When `true`, exports on every save. + `exclude_files` Glob patterns excluded from export. + +Templates may include `{title}`, `{rootpath}`, `{content}`, `{css}`, +`{date}` placeholders. RSS for the diary is written by `:VimwikiRss`. + +============================================================================== +12. FOLDING *nuwiki-folding* + +Folds follow the heading outline: each `= H1 =` opens a level-1 fold, +each `== H2 ==` opens a level-2 fold, etc. Folds close at the next +heading of same-or-shallower level. + +Neovim picks between two providers based on the `folding` setup option: + + `'lsp'` Server-driven `foldingRange` (Neovim 0.11+ wires it + automatically; the editor falls back to the regex variant + if the server isn't yet attached). + `'expr'` Regex `foldexpr` over `getline()` — no server roundtrip. + `'off'` No folding setup. + +Vim users get the regex variant via `nuwiki#folding#expr()` unless +|g:nuwiki_no_folding| is set. + +============================================================================== +13. HEALTH CHECK *nuwiki-health* + + *:checkhealth-nuwiki* +Neovim users can run: > + + :checkhealth nuwiki + +