docs: rewrite README into a proper user-facing intro
CI / cargo fmt --check (push) Successful in 26s
CI / cargo clippy (push) Successful in 1m20s
CI / cargo test (push) Successful in 1m22s
CI / editor keymaps (push) Successful in 2m8s

The old README was mostly a phase-status table — useful for tracking
progress but unhelpful for a first-time reader landing on the repo.
Restructured around the three things a new user actually needs:

1. **What it is.** One-paragraph pitch + a feature checklist that
   mirrors the SPEC §13.3 status without burying the reader in phase
   numbers. Architecture details + the deferred §13.1 work stay in
   `SPEC.md`, linked from the intro.

2. **How to install.** Plugin-manager snippets for lazy.nvim,
   vim-plug, dein, and a plain-Vim packpath path. Plus a
   "try it without touching your config" pointer to
   `./start-nvim.sh` / `./start-vim.sh` so curious users can kick the
   tyres in 5 seconds.

3. **How to use.** A compact `setup({})` example covering wiki_root,
   multi-wiki, mappings groups, folding strategy, and diagnostic
   severity. Then command and keymap cheatsheets that distinguish
   "vimwiki-compat surface" from "things the LSP server returns",
   plus the migrating-from-vimwiki notes (two behaviour deltas the
   user might trip on).

Kept:
- The repository layout diagram (updated to reflect the renamed
  ftplugin/syntax files and the new `scripts/` test harness).
- The implementation-status tables, now under `Development` so
  contributors find them but new users aren't drowned in them.
- The dual MIT/Apache license footer.

No behaviour changes; documentation-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 14:20:18 +00:00
parent a229977b77
commit 7c9e679169
+331 -42
View File
@@ -1,19 +1,335 @@
# nuwiki
A Vim/Neovim plugin providing full vimwiki syntax support, implemented as a
Rust-based language server (LSP).
**A vimwiki-compatible Vim/Neovim plugin backed by a Rust language server.**
> **Status:** v1.0 (Phases 010) shipped — parsing, highlighting, navigation,
> editor glue, and release pipeline are all live. v1.1 (Phases 1119) in
> progress, closing the gap to a full vimwiki replacement: tags, diary,
> server-side edit commands, link health, HTML export commands, multi-wiki,
> and the `:Vimwiki*` keymap layer.
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.
See [`SPEC.md`](./SPEC.md) for the full project specification.
- ✅ 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 `<CR>` two-step link-create-and-follow.
-`:Vimwiki*` command compat + `:Nuwiki*` canonical aliases.
## Implementation status
See [`SPEC.md`](./SPEC.md) for the architecture, design decisions, and
the full phase log; the [pending-work section](./SPEC.md#13-pending-implementation)
lists the few items still in flight (table/list rewriter commands and
colorize).
### v1.0 — foundation
---
## 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.
### 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
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.
### Trying 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
```
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.
---
## Configuration
Defaults are vimwiki-compatible. Full schema (with type annotations and
defaults) lives in [`lua/nuwiki/config.lua`](./lua/nuwiki/config.lua).
```lua
require('nuwiki').setup({
-- Single-wiki shorthand (vimwiki-compatible).
wiki_root = '~/vimwiki',
file_extension = '.wiki',
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.
wikis = {
{
name = 'personal',
root = '~/vimwiki',
file_extension = '.wiki',
diary_rel_path = 'diary',
diary_index = 'diary',
-- HTML export (Phase 17)
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
},
},
-- 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, gq1, gww, gw1, <A-Left>, <A-Right>
diary = true, -- <C-Down>, <C-Up>
html_export = true, -- <Leader>wh, <Leader>whh
text_objects = true, -- ah, ih
},
-- Folding strategy: 'lsp' (server-driven foldingRange — default on
-- Neovim 0.11+), 'expr' (pure regex), or 'off'.
folding = 'lsp',
-- Broken-link diagnostic severity: 'off' | 'hint' | 'warn' | 'error'.
diagnostic = {
link_severity = 'warn',
},
})
```
Vim users without Lua should set the equivalent globals before sourcing
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
```
---
## Usage
### Commands
Both `:Vimwiki*` (migration compat) and `:Nuwiki*` (canonical native)
are registered as buffer-local commands on every `.wiki` buffer.
Selected highlights — see `:Vimwiki<Tab>` for the full list.
| Command | What it does |
|---|---|
| `:VimwikiIndex [N]` | Open wiki N's `index.wiki` (default: 1) |
| `: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 |
| `: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 `<tag>` |
| `: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 (`<CR>`) |
| `:VimwikiBacklinks` | Show references to current page |
### 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**
| Key | Action |
|---|---|
| `<CR>` | Smart follow: inside `[[…]]` → jump; on a bare word → wrap as `[[word]]` (second `<CR>` follows) |
| `<S-CR>` | Follow in horizontal split |
| `<C-CR>` | Follow in vertical split |
| `<C-S-CR>` | Follow in new tab |
| `<BS>` | Jump back (`<C-o>`) |
| `<Tab>` / `<S-Tab>` | Next / previous wikilink on or after the cursor |
**Lists**
| Key | Action |
|---|---|
| `<C-Space>` / `<C-@>` / `<Nul>` | Toggle checkbox (terminal byte aliases) |
| `gln` / `glp` | Cycle 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) |
**Headers**
| Key | Action |
|---|---|
| `=` / `-` | Add / remove a heading level |
| `]]` / `[[` | Next / previous heading |
| `]=` / `[=` | Next / previous sibling heading |
| `]u` / `[u` | Jump to parent heading |
**Wiki / diary / export**
| Key | Action |
|---|---|
| `<Leader>ww` | Today's diary |
| `<Leader>ws` | Pick a wiki (`vim.ui.select` / `inputlist`) |
| `<Leader>wi` | Diary index |
| `<Leader>w<Leader>w` / `<Leader>w<Leader>y` / `<Leader>w<Leader>t` | Today / yesterday / tomorrow |
| `<Leader>w<Leader>i` | Rebuild diary index page |
| `<Leader>wn` / `<Leader>wd` / `<Leader>wr` | Goto / delete / rename page |
| `<Leader>wh` / `<Leader>whh` | Export current page → HTML / open in browser |
| `<Leader>wha` | Export every page |
| `<C-Down>` / `<C-Up>` | Next / previous diary entry |
**Text objects**
| Key | Selection |
|---|---|
| `ah` / `ih` | A heading (with / without the heading line itself) |
Additional text objects (`aH`, `iH`, `a\`, `i\`, `ac`, `ic`, `al`,
`il`) ship once the table/list rewriter commands from
[SPEC §13.1](./SPEC.md#131-phase-14--listtablelinkcolorize-commands)
land.
### Health check
```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
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.
Two known behavior deltas vs. upstream vimwiki:
- 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 |
|---|---|---|
@@ -29,48 +345,21 @@ See [`SPEC.md`](./SPEC.md) for the full project specification.
| 9 | Editor Glue | ✅ done |
| 10 | CI/CD release pipeline | ✅ done |
### v1.1 — full vimwiki replacement
#### 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 (focused subset; table/list-renumber/colorize deferred) |
| 14 | List & table edit commands | ✅ done (focused subset; table/list-renumber/colorize deferred — see [SPEC §13.1](./SPEC.md#131-phase-14--listtablelinkcolorize-commands)) |
| 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 |
## Repository layout
```
nuwiki/
├── Cargo.toml workspace root
├── crates/
│ ├── nuwiki-core/ parser, AST, renderer (no editor deps)
│ ├── nuwiki-lsp/ LSP protocol bridge
│ └── nuwiki-ls/ binary that speaks LSP over stdio
├── plugin/ universal Vim/Neovim entry point
├── lua/nuwiki/ Neovim Lua glue
├── autoload/nuwiki/ Vim VimL glue
├── ftdetect/ filetype detection for .wiki
├── ftplugin/ per-buffer filetype settings
├── syntax/ static fallback highlighting
├── doc/ `:h nuwiki`
├── scripts/ build-time helpers
└── .gitea/workflows/ CI / release pipelines
```
## Building
```sh
cargo build --workspace
cargo test --workspace
```
MSRV: Rust 1.83.
---
## License
@@ -80,5 +369,5 @@ Dual-licensed under either of:
- MIT license ([`LICENSE-MIT`](./LICENSE-MIT))
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.
intentionally submitted for inclusion in this work shall be dual licensed
as above, without any additional terms or conditions.