phase 19: editor glue v2
Server-side:
- New `folding.rs` module with `folding_ranges(ast, total_lines)`.
Emits one fold per top-level heading (start → line before the
next same-or-higher-level heading, or EOF) plus one per top-level
list block. Nested headings fold inside their parent thanks to the
level-aware end-line computation; sublists fold implicitly via
their parent item's source span. `FoldingRangeKind::Region` is set
on every fold so collapsing UIs render them as section folds.
- `Backend::folding_range` handler wires the module into
`textDocument/foldingRange`; `ServerCapabilities.folding_range_provider`
advertises it.
- `folding::line_count` exposed for the handler and tests; treats a
trailing newline as a virtual empty line (the line LSP positions
use for EOF).
Editor glue (Neovim primary, Vim minimal):
- `lua/nuwiki/commands.lua` — async `workspace/executeCommand`
wrappers for every server command shipped through Phase 18. The
open-* family handles `{ uri }` responses by opening the file
(with `tab` / `split` variants). `check_links` and `find_orphans`
hand results to `setqflist` + `:copen` for quickfix-style review.
§13.1-deferred commands (`list.changeSymbol`, table rewriters,
`link.pasteWikilink/pasteUrl`, `colorize`) stub out with
`vim.notify` so users get a clear "not yet implemented" signal
instead of an LSP "unknown command" error.
- `lua/nuwiki/keymaps.lua` — buffer-local default mappings. Subgroups
(`list_editing`, `header_nav`, `diary`, `html_export`,
`text_objects`) flip independently via the new
`mappings.<group>` config. Heading promote/demote uses `g=`/`g-`
to avoid clobbering Vim's built-in `=`/`-` operators.
- `lua/nuwiki/textobjects.lua` — `ah`/`ih` (around/inside heading)
using a buffer scan for the heading-block boundary. The four
remaining text objects from SPEC §12.10 wait until §13.1 lands
the table/list rewriters they share infrastructure with.
- `lua/nuwiki/folding.lua` — pure regex `foldexpr` + `foldtext`
fallback for clients without `foldingRange`. Same heading-block
model as the server.
- `lua/nuwiki/ftplugin.lua` — single per-buffer attach entry point.
`folding = 'lsp'` (default) uses Neovim 0.11+'s `vim.lsp.foldexpr`,
falling back to the regex on older versions; `'expr'` forces the
fallback; `'off'` skips folding setup.
- `lua/nuwiki/config.lua` — extends defaults with `mappings = {...}`
(P10 keymap layer) and `folding` (P14 resolved).
- `ftplugin/nuwiki.vim` — declares every `:Vimwiki*` / `:Nuwiki*`
command from SPEC §12.10 by inlining `lua require(...).fn()`
bodies (no script-local function indirection so commands stay
callable after re-source). Plain-Vim users get only the buffer
options; they're expected to drive the LSP via vim-lsp / coc's
built-in commands.
Health check (§12.10 additions):
- `:checkhealth nuwiki` now reports the count of `executeCommand`
entries the server advertises, whether `foldingRange` capability
was negotiated, and whether the configured HTML output directory
exists + is writable. Default keymap subgroup status is also
surfaced.
Tests: 8 new in `phase19_folding.rs` covering empty docs, single
heading → EOF, sibling headings each getting their own fold,
nested heading bounded by parent, top-level list folds, single-line
heading non-fold, fold-kind classification, and `line_count`
semantics. Total 377 tests pass; fmt + clippy clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+109
-4
@@ -1,8 +1,12 @@
|
||||
" ftplugin/nuwiki.vim — per-buffer settings for `.wiki` buffers.
|
||||
" ftplugin/nuwiki.vim — per-buffer settings + Phase 19 command/keymap glue.
|
||||
"
|
||||
" Keeps this minimal: only the options that affect editing ergonomics for
|
||||
" markup files. Anything richer (folding, navigation keymaps, …) ships
|
||||
" downstream once users opt in.
|
||||
" Wires up:
|
||||
" - basic edit-time options (commentstring, suffixesadd, …)
|
||||
" - every `:Vimwiki*` / `:Nuwiki*` command from SPEC §12.10 that has a
|
||||
" server-side counterpart (deferred §13.1 commands stub out with a
|
||||
" "not yet implemented" notification)
|
||||
" - on Neovim: keymaps + text objects + folding via
|
||||
" `nuwiki.ftplugin.attach()`
|
||||
|
||||
if exists('b:did_ftplugin')
|
||||
finish
|
||||
@@ -16,3 +20,104 @@ setlocal suffixesadd=.wiki
|
||||
setlocal iskeyword+=-
|
||||
|
||||
let b:undo_ftplugin = 'setlocal commentstring< comments< formatoptions< suffixesadd< iskeyword<'
|
||||
|
||||
if !has('nvim')
|
||||
" Plain Vim — the buffer-local options above are all we ship. Vim users
|
||||
" interact via the LSP client (vim-lsp / coc) which already exposes
|
||||
" `:LspDefinition`, `:LspReferences`, `:LspRename`, etc.
|
||||
finish
|
||||
endif
|
||||
|
||||
" ===== Neovim path =====
|
||||
|
||||
" :Vimwiki* compat — every command dispatches to a Lua wrapper in
|
||||
" `nuwiki.commands` that either issues a `workspace/executeCommand`
|
||||
" or, for client-side operations, calls `vim.lsp.buf.*` directly.
|
||||
|
||||
command! -buffer -count VimwikiIndex lua require('nuwiki.commands').wiki_index(vim.v.count)
|
||||
command! -buffer -count VimwikiTabIndex lua require('nuwiki.commands').wiki_tab_index(vim.v.count)
|
||||
command! -buffer VimwikiUISelect lua require('nuwiki.commands').wiki_ui_select()
|
||||
command! -buffer VimwikiDiaryIndex lua require('nuwiki.commands').diary_index()
|
||||
command! -buffer VimwikiMakeDiaryNote lua require('nuwiki.commands').diary_today()
|
||||
command! -buffer VimwikiMakeYesterdayDiaryNote lua require('nuwiki.commands').diary_yesterday()
|
||||
command! -buffer VimwikiMakeTomorrowDiaryNote lua require('nuwiki.commands').diary_tomorrow()
|
||||
command! -buffer VimwikiDiaryNextDay lua require('nuwiki.commands').diary_next()
|
||||
command! -buffer VimwikiDiaryPrevDay lua require('nuwiki.commands').diary_prev()
|
||||
command! -buffer VimwikiDiaryGenerateLinks lua require('nuwiki.commands').diary_generate_index()
|
||||
|
||||
command! -buffer VimwikiFollowLink lua vim.lsp.buf.definition()
|
||||
command! -buffer VimwikiGoBackLink normal!
|
||||
command! -buffer VimwikiSplitLink split | lua vim.lsp.buf.definition()
|
||||
command! -buffer VimwikiVSplitLink vsplit | lua vim.lsp.buf.definition()
|
||||
command! -buffer VimwikiTabnewLink tabnew | lua vim.lsp.buf.definition()
|
||||
command! -buffer VimwikiTabDropLink tabnew | lua vim.lsp.buf.definition()
|
||||
command! -buffer -nargs=1 VimwikiGoto lua require('nuwiki.commands').wiki_goto_page(<q-args>)
|
||||
command! -buffer VimwikiBacklinks lua vim.lsp.buf.references()
|
||||
command! -buffer VWB lua vim.lsp.buf.references()
|
||||
command! -buffer -nargs=1 VimwikiSearch lvimgrep /<args>/ **
|
||||
command! -buffer -nargs=1 VWS lvimgrep /<args>/ **
|
||||
|
||||
command! -buffer VimwikiDeleteFile lua require('nuwiki.commands').delete_file()
|
||||
command! -buffer VimwikiRenameFile lua require('nuwiki.commands').rename_file()
|
||||
|
||||
command! -buffer VimwikiNextTask lua require('nuwiki.commands').next_task()
|
||||
command! -buffer VimwikiToggleListItem lua require('nuwiki.commands').toggle_list_item()
|
||||
command! -buffer VimwikiToggleRejectedListItem lua require('nuwiki.commands').reject_list_item()
|
||||
command! -buffer VimwikiRemoveDone lua require('nuwiki.commands').list_remove_done()
|
||||
command! -buffer -nargs=? VimwikiListChangeLvl lua require('nuwiki.commands').list_change_lvl()
|
||||
|
||||
command! -buffer Vimwiki2HTML lua require('nuwiki.commands').export_current()
|
||||
command! -buffer Vimwiki2HTMLBrowse lua require('nuwiki.commands').export_browse()
|
||||
command! -buffer -bang VimwikiAll2HTML execute (<bang>0 ? "lua require('nuwiki.commands').export_all_force()" : "lua require('nuwiki.commands').export_all()")
|
||||
command! -buffer VimwikiRss lua require('nuwiki.commands').export_rss()
|
||||
|
||||
command! -buffer VimwikiTOC lua require('nuwiki.commands').toc_generate()
|
||||
command! -buffer VimwikiGenerateLinks lua require('nuwiki.commands').links_generate()
|
||||
command! -buffer VimwikiCheckLinks lua require('nuwiki.commands').check_links()
|
||||
command! -buffer VimwikiFindOrphans lua require('nuwiki.commands').find_orphans()
|
||||
|
||||
command! -buffer VimwikiRebuildTags lua require('nuwiki.commands').tags_rebuild()
|
||||
command! -buffer -nargs=? VimwikiSearchTags lua require('nuwiki.commands').tags_search(<q-args>)
|
||||
command! -buffer -nargs=? VimwikiGenerateTagLinks lua require('nuwiki.commands').tags_generate_links(<q-args>)
|
||||
|
||||
" §13.1 deferred — stubs notify the user instead of erroring.
|
||||
command! -buffer -nargs=1 VimwikiTable lua require('nuwiki.commands').table_insert()
|
||||
command! -buffer VimwikiTableMoveColumnLeft lua require('nuwiki.commands').table_move_column_left()
|
||||
command! -buffer VimwikiTableMoveColumnRight lua require('nuwiki.commands').table_move_column_right()
|
||||
command! -buffer -nargs=1 VimwikiColorize lua require('nuwiki.commands').colorize()
|
||||
command! -buffer VimwikiPasteLink lua require('nuwiki.commands').paste_link()
|
||||
command! -buffer VimwikiPasteUrl lua require('nuwiki.commands').paste_url()
|
||||
|
||||
" Canonical :Nuwiki* aliases — P10.
|
||||
command! -buffer -count NuwikiIndex lua require('nuwiki.commands').wiki_index(vim.v.count)
|
||||
command! -buffer NuwikiTabIndex lua require('nuwiki.commands').wiki_tab_index(vim.v.count)
|
||||
command! -buffer NuwikiUISelect lua require('nuwiki.commands').wiki_ui_select()
|
||||
command! -buffer NuwikiDiaryIndex lua require('nuwiki.commands').diary_index()
|
||||
command! -buffer NuwikiDiaryToday lua require('nuwiki.commands').diary_today()
|
||||
command! -buffer NuwikiDiaryYesterday lua require('nuwiki.commands').diary_yesterday()
|
||||
command! -buffer NuwikiDiaryTomorrow lua require('nuwiki.commands').diary_tomorrow()
|
||||
command! -buffer NuwikiDiaryNext lua require('nuwiki.commands').diary_next()
|
||||
command! -buffer NuwikiDiaryPrev lua require('nuwiki.commands').diary_prev()
|
||||
command! -buffer NuwikiDiaryGenerateLinks lua require('nuwiki.commands').diary_generate_index()
|
||||
command! -buffer NuwikiFollowLink lua vim.lsp.buf.definition()
|
||||
command! -buffer NuwikiBacklinks lua vim.lsp.buf.references()
|
||||
command! -buffer NuwikiDeleteFile lua require('nuwiki.commands').delete_file()
|
||||
command! -buffer NuwikiRenameFile lua require('nuwiki.commands').rename_file()
|
||||
command! -buffer NuwikiNextTask lua require('nuwiki.commands').next_task()
|
||||
command! -buffer NuwikiToggleListItem lua require('nuwiki.commands').toggle_list_item()
|
||||
command! -buffer NuwikiToggleRejected lua require('nuwiki.commands').reject_list_item()
|
||||
command! -buffer NuwikiExport lua require('nuwiki.commands').export_current()
|
||||
command! -buffer NuwikiExportBrowse lua require('nuwiki.commands').export_browse()
|
||||
command! -buffer -bang NuwikiExportAll execute (<bang>0 ? "lua require('nuwiki.commands').export_all_force()" : "lua require('nuwiki.commands').export_all()")
|
||||
command! -buffer NuwikiRss lua require('nuwiki.commands').export_rss()
|
||||
command! -buffer NuwikiTOC lua require('nuwiki.commands').toc_generate()
|
||||
command! -buffer NuwikiGenerateLinks lua require('nuwiki.commands').links_generate()
|
||||
command! -buffer NuwikiCheckLinks lua require('nuwiki.commands').check_links()
|
||||
command! -buffer NuwikiFindOrphans lua require('nuwiki.commands').find_orphans()
|
||||
command! -buffer NuwikiRebuildTags lua require('nuwiki.commands').tags_rebuild()
|
||||
command! -buffer -nargs=? NuwikiSearchTags lua require('nuwiki.commands').tags_search(<q-args>)
|
||||
command! -buffer -nargs=? NuwikiGenerateTagLinks lua require('nuwiki.commands').tags_generate_links(<q-args>)
|
||||
command! -buffer -nargs=1 NuwikiGoto lua require('nuwiki.commands').wiki_goto_page(<q-args>)
|
||||
|
||||
" Phase 19 buffer attach: keymaps + text objects + folding.
|
||||
lua require('nuwiki.ftplugin').attach(0)
|
||||
|
||||
Reference in New Issue
Block a user