fix(follow-link): resolve+open definitions ourselves on the Vim clients
The Vim follow-link path delegated to the LSP client's jump UI
(:LspDefinition / coc jumpDefinition), which broke two ways for wiki
link-following:
1. **No create-on-follow (vim-lsp + coc).** vim-lsp's location handler
readfile()s the target to build a quickfix entry; for a not-yet-created
page that throws E484 and aborts the jump, so <CR> on [[NewPage]] did
nothing. The server was correct throughout — textDocument/definition
returns a *synthesised* location for missing pages (verified over
JSON-RPC).
2. **Wrong window placement (coc).** Without an explicit open command coc
fell back to coc.preferences.jumpCommand (e.g. a tab command).
Stop delegating: nuwiki#commands#follow_link_or_create() /
follow_link_drop() now resolve textDocument/definition directly and open
the URI themselves via a shared s:open_definition(open_cmd) helper — :edit
for <CR>, `tab drop` for <C-S-CR>. :edit opens a buffer for a missing path
(save creates it, matching vimwiki) and gives exact current-window
placement regardless of the user's coc jumpCommand. Removes
s:jump_definition / s:drop_from_response.
Also fix the coc action name: CocAction('getDefinition') does not exist
(E605 "Action getDefinition does not exist") — the registered action is
'definitions'. Fixed in s:open_definition and badd_link.
coc config delivery: the setup guidance shipped without
initializationOptions, so coc users never sent wiki_root and the server
resolved links against its default root (existing pages flagged broken,
follow-to-create landed in the cwd). The printed snippet
(autoload/nuwiki/lsp.vim) now emits initializationOptions populated with
the resolved settings, and the README coc snippet documents it as required.
Add development/start-vim-coc.sh — a coc.nvim dev launcher (sibling of
start-vim.sh) that wires coc's prebuilt release branch + a generated
coc-settings.json (with initializationOptions), deliberately omitting
vim-lsp so the coc path is exercised; doubles as a reproducer.
Tests: new cr.follow_opens_missing_page_in_current_window case in
test-keymaps-vim.vim (stubs CocAction to a missing page, asserts
current-window :edit). Keymap suite 254+18 green; config-parity (Vim +
Neovim) green. Neovim path unchanged and re-confirmed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+178
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# start-vim-coc.sh — launch Vim with a minimal config that loads nuwiki
|
||||
# through coc.nvim (instead of vim-lsp).
|
||||
#
|
||||
# The plugin's Vim path (autoload/nuwiki/lsp.vim) prefers `vim-lsp` and falls
|
||||
# back to `coc.nvim`. start-vim.sh exercises the vim-lsp path; this script
|
||||
# exercises the coc.nvim path. vim-lsp is deliberately kept OFF the runtimepath
|
||||
# so `:LspDefinition` doesn't exist and nuwiki's coc branch is the one that runs
|
||||
# (s:jump_definition() → CocActionAsync('jumpDefinition', 'edit')).
|
||||
#
|
||||
# This doubles as a reproducer for the "<CR> opens a new tab" regression:
|
||||
# coc-settings.json sets coc.preferences.jumpCommand to `tabe`, so without the
|
||||
# fix `<CR>` on a link opens a new tab. With the fix nuwiki passes 'edit'
|
||||
# explicitly and the target opens in the *current* window regardless.
|
||||
#
|
||||
# It clones coc.nvim's prebuilt `release` branch into the dev cache on first
|
||||
# run (no yarn/build needed — it just needs Node.js at runtime).
|
||||
#
|
||||
# Usage: ./development/start-vim-coc.sh [extra args...]
|
||||
# ./development/start-vim-coc.sh # open the scratch wiki's index
|
||||
# ./development/start-vim-coc.sh path/to/note.wiki # open a specific file
|
||||
# NUWIKI_DEV_WIKI=/tmp/foo ./development/start-vim-coc.sh
|
||||
# NUWIKI_DEV_NO_SEED=1 ./development/start-vim-coc.sh # use WIKI_DIR as-is (no scratch seeding)
|
||||
# NUWIKI_DEV_SKIP_BUILD=1 ./development/start-vim-coc.sh # reuse the cached binary
|
||||
# NUWIKI_DEV_COC_JUMP=edit ./development/start-vim-coc.sh # change coc.preferences.jumpCommand
|
||||
#
|
||||
# The release binary is rebuilt on every launch so source changes always reach
|
||||
# the running LSP. `cargo build --release` is incremental, so this is a fast
|
||||
# no-op when nothing changed. Set NUWIKI_DEV_SKIP_BUILD=1 to skip the build.
|
||||
#
|
||||
# Tested with Vim 9.1+ and Node 18+. State (viminfo/sessions, coc data) lives
|
||||
# under $XDG_CACHE_HOME/nuwiki-dev/ so your real Vim install stays untouched.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Shared paths + helpers (log, ensure_binary, write_sample_wiki, seed_wiki).
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||
|
||||
VIMRC="$DEV_DIR/vimrc-coc"
|
||||
VIM_STATE="$DEV_DIR/vim-coc-state"
|
||||
COC_DIR="$DEV_DIR/coc.nvim"
|
||||
COC_DATA="$DEV_DIR/coc-data"
|
||||
COC_SETTINGS="$DEV_DIR/coc-settings.json"
|
||||
COC_JUMP="${NUWIKI_DEV_COC_JUMP:-tabe}"
|
||||
|
||||
ensure_node() {
|
||||
if ! command -v node >/dev/null 2>&1; then
|
||||
log 'node not found — coc.nvim needs Node.js at runtime; skipping'
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_coc() {
|
||||
mkdir -p "$DEV_DIR"
|
||||
if [[ -d "$COC_DIR/.git" ]]; then
|
||||
return
|
||||
fi
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
log 'git not found — cannot clone coc.nvim; skipping'
|
||||
exit 0
|
||||
fi
|
||||
log "cloning coc.nvim (release branch) → $COC_DIR"
|
||||
git clone --depth 1 --branch release \
|
||||
https://github.com/neoclide/coc.nvim.git "$COC_DIR" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
write_coc_settings() {
|
||||
mkdir -p "$DEV_DIR"
|
||||
# Mirror what the vim-lsp client sends (autoload/nuwiki/lsp.vim s:settings()):
|
||||
# both `initializationOptions` (sent on initialize) and `settings.nuwiki`
|
||||
# (served via workspace/configuration). Without these the server falls back
|
||||
# to its own default wiki_root (~/vimwiki) instead of $WIKI_DIR, so it can't
|
||||
# resolve links (e.g. Notes shows as broken) or create-on-follow correctly.
|
||||
cat > "$COC_SETTINGS" <<EOF
|
||||
{
|
||||
"coc.preferences.jumpCommand": "$COC_JUMP",
|
||||
"languageserver": {
|
||||
"nuwiki": {
|
||||
"command": "$REPO_ROOT/bin/nuwiki-ls",
|
||||
"filetypes": ["vimwiki"],
|
||||
"initializationOptions": {
|
||||
"wiki_root": "$WIKI_DIR",
|
||||
"file_extension": ".wiki",
|
||||
"syntax": "vimwiki",
|
||||
"log_level": "info",
|
||||
"diagnostic": { "link_severity": "warn" }
|
||||
},
|
||||
"settings": {
|
||||
"nuwiki": {
|
||||
"wiki_root": "$WIKI_DIR",
|
||||
"file_extension": ".wiki",
|
||||
"syntax": "vimwiki",
|
||||
"log_level": "info",
|
||||
"diagnostic": { "link_severity": "warn" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
write_vimrc() {
|
||||
mkdir -p "$DEV_DIR"
|
||||
cat > "$VIMRC" <<EOF
|
||||
" start-vim-coc.sh: generated minimal config for nuwiki development (coc.nvim).
|
||||
" Regenerated on every launch; edit start-vim-coc.sh, not this file.
|
||||
|
||||
" Confine state to the dev cache so we never touch the user's real Vim
|
||||
" install.
|
||||
set viminfo='100,n$VIM_STATE/viminfo
|
||||
let &directory = '$VIM_STATE/swap//'
|
||||
let &backupdir = '$VIM_STATE/backup//'
|
||||
let &undodir = '$VIM_STATE/undo//'
|
||||
|
||||
" Make Vim look for runtime paths in the dev cache. vim-lsp is intentionally
|
||||
" absent so nuwiki dispatches jump-to-definition through coc.
|
||||
set nocompatible
|
||||
let &runtimepath = '$REPO_ROOT' . ',' . &runtimepath
|
||||
let &runtimepath .= ',$COC_DIR'
|
||||
|
||||
" Point coc at the generated settings + a private data dir.
|
||||
let g:coc_config_home = '$DEV_DIR'
|
||||
let g:coc_data_home = '$COC_DATA'
|
||||
|
||||
let g:nuwiki_binary_path = '$REPO_ROOT/bin/nuwiki-ls'
|
||||
let g:nuwiki_wiki_root = '$WIKI_DIR'
|
||||
let g:nuwiki_file_extension = '.wiki'
|
||||
let g:nuwiki_syntax = 'vimwiki'
|
||||
let g:nuwiki_log_level = 'info'
|
||||
|
||||
filetype plugin indent on
|
||||
syntax enable
|
||||
set hidden
|
||||
set termguicolors
|
||||
set number
|
||||
set signcolumn=yes
|
||||
set noswapfile
|
||||
set nobackup
|
||||
set nowritebackup
|
||||
let mapleader = ' '
|
||||
|
||||
" Auto-detect filetype for .wiki files (the plugin ships ftdetect, but
|
||||
" --clean disables those — copy the rule here).
|
||||
augroup NuwikiFtdetect
|
||||
autocmd!
|
||||
autocmd BufRead,BufNewFile *.wiki setfiletype vimwiki
|
||||
augroup END
|
||||
|
||||
" coc starts the server automatically from coc-settings.json once a vimwiki
|
||||
" buffer loads — no explicit nuwiki#lsp#start() needed.
|
||||
|
||||
echomsg '[nuwiki-dev] ready (coc.nvim) — wiki root: $WIKI_DIR'
|
||||
echomsg '[nuwiki-dev] coc.preferences.jumpCommand = $COC_JUMP'
|
||||
echomsg '[nuwiki-dev] <CR> on a [[link]] should open in the CURRENT window'
|
||||
echomsg '[nuwiki-dev] :CocList services for status, :messages for log'
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
ensure_node
|
||||
ensure_binary
|
||||
ensure_coc
|
||||
write_coc_settings
|
||||
seed_wiki
|
||||
write_vimrc
|
||||
mkdir -p "$VIM_STATE/swap" "$VIM_STATE/backup" "$VIM_STATE/undo" "$COC_DATA"
|
||||
|
||||
log "launching: vim --clean -u $VIMRC"
|
||||
if [[ $# -gt 0 ]]; then
|
||||
exec vim --clean -u "$VIMRC" "$@"
|
||||
else
|
||||
exec vim --clean -u "$VIMRC" "$WIKI_DIR/index.wiki"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user