From 7a3e11cfebd47c4432e0b914a71c90ae34b41fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Fr=C3=B3es=20Franco?= Date: Sun, 31 May 2026 21:34:41 -0300 Subject: [PATCH 1/3] feat(calendar): integrate calendar-vim with wiki diary paths Wire g:calendar_action/g:calendar_sign to nuwiki diary hooks that resolve diary paths from the wiki root config instead of calendar-vim's default ~/diary. Auto-detected on FileType vimwiki when calendar-vim is present; opt out with g:nuwiki_use_calendar=0 or g:nuwiki_no_calendar. - autoload/nuwiki/diary.vim: calendar_action/calendar_sign using wiki cfg; open diary in the previous window and close the calendar window after. - autoload/vimwiki/diary.vim: vimwiki# aliases for drop-in compatibility. - plugin/nuwiki.vim + lua/nuwiki/init.lua: auto-wire hooks, overwriting calendar-vim's defaults while respecting user-set custom hooks. - lua/nuwiki/config.lua: add use_calendar option (on by default). - development/start-*.sh + _common.sh: clone calendar-vim, fix vimrc var expansion, pass wiki root to the Vim/Neovim clients. --- autoload/nuwiki/diary.vim | 97 ++++++++++++++++++++++++++++++++++++ autoload/vimwiki/diary.vim | 14 ++++++ development/_common.sh | 14 ++++++ development/start-nvim.sh | 17 +++---- development/start-vim-coc.sh | 30 +++++------ development/start-vim.sh | 23 +++++---- lua/nuwiki/config.lua | 6 +++ lua/nuwiki/init.lua | 22 ++++++++ plugin/nuwiki.vim | 24 +++++++++ 9 files changed, 211 insertions(+), 36 deletions(-) create mode 100644 autoload/nuwiki/diary.vim create mode 100644 autoload/vimwiki/diary.vim diff --git a/autoload/nuwiki/diary.vim b/autoload/nuwiki/diary.vim new file mode 100644 index 0000000..40bbfa3 --- /dev/null +++ b/autoload/nuwiki/diary.vim @@ -0,0 +1,97 @@ +" autoload/nuwiki/diary.vim — diary-specific functions for nuwiki +" Includes calendar-vim integration functions + +" ===== Calendar-Vim Integration ===== + +" Function: nuwiki#diary#calendar_action(day, month, year, week, dir) +" Called by calendar-vim when user presses Enter on a date. +" day/month/year are numeric integers. week and dir are not used. +" Opens or creates the diary entry for the given date. +function! nuwiki#diary#calendar_action(day, month, year, week, dir) abort + " Build YYYY-MM-DD from the parts passed by calendar-vim + let l:date_str = printf('%04d-%02d-%02d', a:year, a:month, a:day) + + " Get wiki configuration for the first wiki (index 0) + let l:c = s:wiki_cfg(0) + + " Construct file path: {root}/{diary_rel}/{YYYY-MM-DD}.{ext} + let l:file_path = l:c.root . '/' . l:c.diary_rel . '/' . l:date_str . l:c.ext + + " Remember the calendar window so we can close it once the diary opens. + let l:cal_winid = win_getid() + + " Open the diary file in a different window. If a previous window exists go + " there; otherwise split / vsplit / new depending on a:dir. + if winnr('#') > 0 + execute 'wincmd p' + if !&hidden && &modified + execute 'new' + endif + elseif a:dir ==# 'V' + execute 'vsplit' + else + execute 'split' + endif + + execute 'edit ' . fnameescape(l:file_path) + if !filereadable(l:file_path) + if l:c.ext[0] ==# '.' + execute 'setfiletype ' . l:c.ext[1:] + else + execute 'setfiletype ' . l:c.ext + endif + endif + + " Close the calendar window now that the diary is open (keep at least one). + if win_getid() != l:cal_winid && win_id2win(l:cal_winid) > 0 && winnr('$') > 1 + let l:diary_winid = win_getid() + if win_gotoid(l:cal_winid) + close + endif + call win_gotoid(l:diary_winid) + endif +endfunction + +" Function: nuwiki#diary#calendar_sign(day, month, year) +" Called by calendar-vim to determine which dates show markers (*) +" day, month, year are numeric integers (1-based). +" Returns a single-character string to use as marker (e.g. '*' or ''), +" or 1/0 for 1-indexed calendars. +" calendar-vim's default expects the return value to be a single character +" to display; returning any non-empty string shows a marker. +function! nuwiki#diary#calendar_sign(day, month, year) abort + " Build YYYY-MM-DD from the parts passed by calendar-vim + let l:date_str = printf('%04d-%02d-%02d', a:year, a:month, a:day) + + " Get wiki configuration for the first wiki (index 0) + let l:c = s:wiki_cfg(0) + + " Construct expected file path + let l:file_path = l:c.root . '/' . l:c.diary_rel . '/' . l:date_str . l:c.ext + + " Return a marker if the file exists, empty string otherwise + if filereadable(l:file_path) + return '*' + endif + return '' +endfunction + +" Helper: get wiki configuration for wiki n (0-based). +" Mirrors the same logic used by nuwiki#commands#open_diary_path etc. +function! s:wiki_cfg(n) abort + let l:w = {} + if exists('g:nuwiki_wikis') && len(g:nuwiki_wikis) > a:n + let l:w = g:nuwiki_wikis[a:n] + endif + let l:root = expand(get(l:w, 'root', + \ get(g:, 'nuwiki_wiki_root', '~/vimwiki'))) + let l:ext = get(l:w, 'file_extension', + \ get(g:, 'nuwiki_file_extension', '.wiki')) + if l:ext[0] !=# '.' | let l:ext = '.' . l:ext | endif + let l:idx = get(l:w, 'index', 'index') + let l:diary_rel = get(l:w, 'diary_rel_path', + \ get(g:, 'nuwiki_diary_rel_path', 'diary')) + let l:diary_idx = get(l:w, 'diary_index', 'diary') + return { 'root': l:root, 'ext': l:ext, 'idx': l:idx, + \ 'diary_rel': l:diary_rel, 'diary_idx': l:diary_idx } +endfunction diff --git a/autoload/vimwiki/diary.vim b/autoload/vimwiki/diary.vim new file mode 100644 index 0000000..e554c7e --- /dev/null +++ b/autoload/vimwiki/diary.vim @@ -0,0 +1,14 @@ +" autoload/vimwiki/diary.vim — vimwiki namespace aliases for nuwiki diary functions +" Provides drop-in compatibility for vimwiki-dependent plugins like calendar-vim + +" vimwiki#diary#calendar_action(day, month, year, week, dir) +" Alias to nuwiki#diary#calendar_action for calendar-vim compatibility +function! vimwiki#diary#calendar_action(day, month, year, week, dir) abort + return nuwiki#diary#calendar_action(a:day, a:month, a:year, a:week, a:dir) +endfunction + +" vimwiki#diary#calendar_sign(day, month, year) +" Alias to nuwiki#diary#calendar_sign for calendar-vim compatibility +function! vimwiki#diary#calendar_sign(day, month, year) abort + return nuwiki#diary#calendar_sign(a:day, a:month, a:year) +endfunction diff --git a/development/_common.sh b/development/_common.sh index d48fe30..adab8b7 100644 --- a/development/_common.sh +++ b/development/_common.sh @@ -275,6 +275,20 @@ reset_dirs() { done } +# ensure_calendar_vim — clone calendar-vim into dev dir for testing +ensure_calendar_vim() { + local repo="$DEV_DIR/calendar-vim" + if [[ -d "$repo/.git" ]]; then + return + fi + if ! command -v git >/dev/null 2>&1; then + log "git not found — skipping calendar-vim" + return 1 + fi + log "cloning https://github.com/mattn/calendar-vim.git → $repo" + git clone --depth 1 https://github.com/mattn/calendar-vim.git "$repo" >/dev/null 2>&1 +} + seed_wiki() { if [[ "${NUWIKI_DEV_NO_SEED:-0}" == "1" ]]; then log "NUWIKI_DEV_NO_SEED=1 — skipping wiki seed (using $WIKI_DIR as-is)" diff --git a/development/start-nvim.sh b/development/start-nvim.sh index 6963e04..e7f9ee4 100755 --- a/development/start-nvim.sh +++ b/development/start-nvim.sh @@ -54,17 +54,13 @@ vim.env.XDG_DATA_HOME = '$DATA_DIR' vim.env.XDG_CONFIG_HOME = '$CONFIG_DIR' vim.opt.runtimepath:prepend('$REPO_ROOT') +vim.opt.runtimepath:append('$DEV_DIR/calendar-vim') vim.g.nuwiki_binary_path = '$REPO_ROOT/bin/nuwiki-ls' - --- Friendly defaults for an interactive smoke test. -vim.opt.number = true -vim.opt.signcolumn = 'yes' -vim.opt.termguicolors = true -vim.opt.swapfile = false -vim.opt.writebackup = false -vim.opt.undofile = false -vim.g.mapleader = ' ' +vim.g.nuwiki_wiki_root = '$WIKI_DIR' +vim.g.nuwiki_file_extension = '.wiki' +vim.g.nuwiki_syntax = 'vimwiki' +vim.g.nuwiki_diary_rel_path = 'diary' require('nuwiki').setup({ wiki_root = '$WIKI_DIR', @@ -74,13 +70,14 @@ require('nuwiki').setup({ -- they're swallowed; with it they land in :messages. vim.lsp.set_log_level('info') -print('[nuwiki-dev] ready — wiki root: $WIKI_DIR') +print('[nuwiki-dev] ready — wiki root: ' .. '$WIKI_DIR') print('[nuwiki-dev] :LspInfo to inspect, :checkhealth nuwiki for diagnostics') EOF } main() { ensure_binary + ensure_calendar_vim seed_wiki write_init reset_dirs "$STATE_DIR" "$DATA_DIR" "$CONFIG_DIR" diff --git a/development/start-vim-coc.sh b/development/start-vim-coc.sh index a6dd59c..a72b0d2 100755 --- a/development/start-vim-coc.sh +++ b/development/start-vim-coc.sh @@ -114,25 +114,27 @@ write_vimrc() { " 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//' +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' +let &runtimepath = '${REPO_ROOT}' . ',' . &runtimepath +let &runtimepath .= ',${COC_DIR}' +let &runtimepath .= ',${DEV_DIR}/calendar-vim' " 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: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_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_diary_rel_path = 'diary' let g:nuwiki_log_level = 'info' filetype plugin indent on @@ -153,11 +155,8 @@ augroup NuwikiFtdetect 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' +echo +echomsg '[nuwiki-dev] coc.preferences.jumpCommand = ' . '\$COC_JUMP' echomsg '[nuwiki-dev] on a [[link]] should open in the CURRENT window' echomsg '[nuwiki-dev] :CocList services for status, :messages for log' EOF @@ -167,6 +166,7 @@ main() { ensure_node ensure_binary ensure_coc + ensure_calendar_vim write_coc_settings seed_wiki write_vimrc diff --git a/development/start-vim.sh b/development/start-vim.sh index cc32d28..1311d21 100755 --- a/development/start-vim.sh +++ b/development/start-vim.sh @@ -70,19 +70,20 @@ write_vimrc() { " 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//' +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. set nocompatible -let &runtimepath = '$REPO_ROOT' . ',' . &runtimepath -let &runtimepath .= ',$VIM_LSP_DIR' -let &runtimepath .= ',$ASYNC_DIR' +let &runtimepath = '${REPO_ROOT}' . ',' . &runtimepath +let &runtimepath .= ',${VIM_LSP_DIR}' +let &runtimepath .= ',${ASYNC_DIR}' +let &runtimepath .= ',${DEV_DIR}/calendar-vim' -let g:nuwiki_binary_path = '$REPO_ROOT/bin/nuwiki-ls' -let g:nuwiki_wiki_root = '$WIKI_DIR' +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' @@ -113,8 +114,7 @@ augroup NuwikiStart autocmd FileType vimwiki call nuwiki#lsp#start() augroup END -" Status messages go to :messages so they don't trigger "Press ENTER". -echomsg '[nuwiki-dev] ready — wiki root: $WIKI_DIR' +echomsg '[nuwiki-dev] ready — wiki root: ' . g:nuwiki_wiki_root echomsg '[nuwiki-dev] :LspStatus for diagnostics, :messages for log' EOF } @@ -122,6 +122,7 @@ EOF main() { ensure_binary ensure_vim_lsp + ensure_calendar_vim seed_wiki write_vimrc reset_dirs "$VIM_STATE" diff --git a/lua/nuwiki/config.lua b/lua/nuwiki/config.lua index 0da64f4..50726b1 100644 --- a/lua/nuwiki/config.lua +++ b/lua/nuwiki/config.lua @@ -56,6 +56,12 @@ M.defaults = { diagnostic = { link_severity = 'warn', }, + + -- Calendar-vim integration. On by default — set to `false` to opt out. + -- When on, nuwiki detects calendar-vim on the runtimepath and wires + -- `g:calendar_action` / `g:calendar_sign` automatically. + -- Also respects `g:nuwiki_no_calendar` set before setup() to disable. + use_calendar = true, } M.options = vim.deepcopy(M.defaults) diff --git a/lua/nuwiki/init.lua b/lua/nuwiki/init.lua index b37a471..444915f 100644 --- a/lua/nuwiki/init.lua +++ b/lua/nuwiki/init.lua @@ -85,6 +85,28 @@ function M.setup(opts) vim.filetype.add({ extension = extensions }) end + -- Auto-detect calendar-vim and wire hooks when the first vimwiki buffer loads. + -- On by default; disable with use_calendar = false or g:nuwiki_no_calendar. + if config.options.use_calendar ~= false and not config.options.no_calendar then + vim.api.nvim_create_autocmd('FileType', { + pattern = 'vimwiki', + callback = function() + if vim.fn.exists('*calendar#open') == 1 or vim.fn.exists(':Calendar') == 2 then + -- Overwrite calendar-vim's own defaults (which write to ~/diary) + -- but respect a user-set custom hook. + local act = vim.g.calendar_action + if not act or act == '' or act == 'calendar#diary' then + vim.g.calendar_action = 'vimwiki#diary#calendar_action' + end + local sign = vim.g.calendar_sign + if not sign or sign == '' or sign == 'calendar#sign' then + vim.g.calendar_sign = 'vimwiki#diary#calendar_sign' + end + end + end, + }) + end + lsp.register() _setup_global_mappings() _setup_global_commands() diff --git a/plugin/nuwiki.vim b/plugin/nuwiki.vim index 8a2a71e..6298c55 100644 --- a/plugin/nuwiki.vim +++ b/plugin/nuwiki.vim @@ -27,6 +27,30 @@ else command! -nargs=0 NuwikiInstall execute 'source' fnameescape(s:plugin_root . '/scripts/download_bin.vim') endif +" Calendar-Vim Integration — auto-detect when calendar-vim is loaded. +augroup nuwiki_calendar_detect + autocmd! + autocmd FileType vimwiki call s:nuwiki_setup_calendar() +augroup END +function! s:nuwiki_setup_calendar() abort + if !get(g:, 'nuwiki_use_calendar', 1) || get(g:, 'nuwiki_no_calendar', 0) + return + endif + if exists('*calendar#open') || exists(':Calendar') == 2 + " Wire nuwiki's diary hooks unless the user set a custom (non-default) one. + " calendar-vim's own default is 'calendar#diary' (writes to ~/diary); we + " overwrite that so paths come from the wiki root config instead. + let l:act = get(g:, 'calendar_action', '') + if l:act ==# '' || l:act ==# 'calendar#diary' + let g:calendar_action = 'vimwiki#diary#calendar_action' + endif + let l:sign = get(g:, 'calendar_sign', '') + if l:sign ==# '' || l:sign ==# 'calendar#sign' + let g:calendar_sign = 'vimwiki#diary#calendar_sign' + endif + endif +endfunction + if has('nvim') " Neovim path is initialised by `require('nuwiki').setup()`. Nothing else " to do at vimscript boot — wait until the user runs setup. From 87ba4c17644d95ed4745495c7f1a95f02a0c2b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Fr=C3=B3es=20Franco?= Date: Sun, 31 May 2026 21:45:50 -0300 Subject: [PATCH 2/3] test(calendar): add Vim + Neovim integration harnesses Add headless harnesses covering the calendar-vim integration, wired into CI alongside the existing keymap/config suites: - test-calendar-vim.sh/.vim (+ -optout.vim): pure-VimL diary hooks (calendar_sign markers, calendar_action path resolution from wiki root, calendar window close), plugin/nuwiki.vim hook auto-wiring that overrides calendar-vim's defaults, and opt-out via g:nuwiki_use_calendar and g:nuwiki_no_calendar. Uses a stub calendar-vim on the runtimepath. - test-calendar.sh/.lua: Neovim setup() wiring + window-close under the real window API, and opt-out via use_calendar = false. Fixes surfaced by the suite: - diary.vim: new diary entries set filetype 'vimwiki' (was the raw extension, e.g. 'wiki'); the stray FileType autocmd also blocked the calendar window from closing. - init.lua: drop the redundant Neovim FileType autocmd (plugin/nuwiki.vim already wires both editors) and translate use_calendar=false into g:nuwiki_no_calendar so the opt-out actually disables wiring. --- .gitea/workflows/ci.yaml | 4 + autoload/nuwiki/diary.vim | 10 +- development/ONBOARDING.md | 7 +- .../tests/test-calendar-vim-optout.vim | 40 ++++++ development/tests/test-calendar-vim.sh | 121 ++++++++++++++++++ development/tests/test-calendar-vim.vim | 97 ++++++++++++++ development/tests/test-calendar.lua | 92 +++++++++++++ development/tests/test-calendar.sh | 106 +++++++++++++++ lua/nuwiki/init.lua | 25 +--- 9 files changed, 475 insertions(+), 27 deletions(-) create mode 100644 development/tests/test-calendar-vim-optout.vim create mode 100755 development/tests/test-calendar-vim.sh create mode 100644 development/tests/test-calendar-vim.vim create mode 100644 development/tests/test-calendar.lua create mode 100755 development/tests/test-calendar.sh diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 2eed90b..2ce8798 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -100,3 +100,7 @@ jobs: run: ./development/tests/test-config.sh - name: run Vim config parity harness run: ./development/tests/test-config-vim.sh + - name: run Neovim calendar integration harness + run: ./development/tests/test-calendar.sh + - name: run Vim calendar integration harness + run: ./development/tests/test-calendar-vim.sh diff --git a/autoload/nuwiki/diary.vim b/autoload/nuwiki/diary.vim index 40bbfa3..a6c28b2 100644 --- a/autoload/nuwiki/diary.vim +++ b/autoload/nuwiki/diary.vim @@ -34,12 +34,10 @@ function! nuwiki#diary#calendar_action(day, month, year, week, dir) abort endif execute 'edit ' . fnameescape(l:file_path) - if !filereadable(l:file_path) - if l:c.ext[0] ==# '.' - execute 'setfiletype ' . l:c.ext[1:] - else - execute 'setfiletype ' . l:c.ext - endif + " A brand-new entry has no file on disk yet, so ftdetect may not have run; + " ensure the vimwiki filetype so syntax/maps are active immediately. + if &filetype !=# 'vimwiki' + setfiletype vimwiki endif " Close the calendar window now that the diary is open (keep at least one). diff --git a/development/ONBOARDING.md b/development/ONBOARDING.md index c9370cb..1909afd 100644 --- a/development/ONBOARDING.md +++ b/development/ONBOARDING.md @@ -79,7 +79,12 @@ nuwiki/ │ ├── test-keymaps.sh # Neovim keymap harness │ ├── test-keymaps.lua │ ├── test-keymaps-vim.sh # Vim keymap harness -│ └── test-keymaps-vim.vim +│ ├── test-keymaps-vim.vim +│ ├── test-calendar.sh # Neovim calendar-vim integration harness +│ ├── test-calendar.lua +│ ├── test-calendar-vim.sh # Vim calendar-vim integration harness +│ ├── test-calendar-vim.vim +│ └── test-calendar-vim-optout.vim │ └── .gitea/ └── workflows/ diff --git a/development/tests/test-calendar-vim-optout.vim b/development/tests/test-calendar-vim-optout.vim new file mode 100644 index 0000000..07340d1 --- /dev/null +++ b/development/tests/test-calendar-vim-optout.vim @@ -0,0 +1,40 @@ +" development/tests/test-calendar-vim-optout.vim — driven by test-calendar-vim.sh. +" +" Asserts that the calendar-vim integration stays OFF when the user opts out +" (g:nuwiki_use_calendar = 0 or g:nuwiki_no_calendar = 1). In that case the +" FileType autocmd must leave calendar-vim's own defaults untouched, so the +" hooks still point at 'calendar#diary' / 'calendar#sign' (set by the stub). + +let s:results = [] +let s:pass = 0 +let s:fail = 0 +let s:out = $NUWIKI_CALENDAR_RESULTS + +function! s:record(ok, name, detail) abort + let l:line = (a:ok ? 'PASS' : 'FAIL') . ' ' . a:name + if a:detail !=# '' + let l:line .= ' — ' . a:detail + endif + call add(s:results, l:line) + if a:ok + let s:pass += 1 + else + let s:fail += 1 + endif +endfunction + +" The buffer is already a loaded vimwiki file (FileType has fired). nuwiki must +" NOT have rewired the hooks — they should still be calendar-vim's defaults. +call s:record(&filetype ==# 'vimwiki', 'ftplugin.attached', + \ &filetype ==# 'vimwiki' ? '' : 'filetype=' . &filetype) +call s:record(get(g:, 'calendar_action', '') !=# 'vimwiki#diary#calendar_action', + \ 'optout.action_not_wired', + \ 'g:calendar_action=' . get(g:, 'calendar_action', '')) +call s:record(get(g:, 'calendar_sign', '') !=# 'vimwiki#diary#calendar_sign', + \ 'optout.sign_not_wired', + \ 'g:calendar_sign=' . get(g:, 'calendar_sign', '')) + +call add(s:results, '') +call add(s:results, printf('SUMMARY: %d passed, %d failed', s:pass, s:fail)) +call writefile(s:results, s:out) +execute (s:fail == 0 ? 'qall!' : 'cquit!') diff --git a/development/tests/test-calendar-vim.sh b/development/tests/test-calendar-vim.sh new file mode 100755 index 0000000..455f479 --- /dev/null +++ b/development/tests/test-calendar-vim.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +# +# development/tests/test-calendar-vim.sh — calendar-vim integration harness (Vim). +# +# Exercises the pure-VimL diary hooks (nuwiki#diary#calendar_action / +# nuwiki#diary#calendar_sign) plus plugin/nuwiki.vim's auto-wiring of +# g:calendar_action / g:calendar_sign. A stub calendar-vim is placed on the +# runtimepath so :Calendar exists and the hooks start at calendar-vim's own +# defaults — the exact state nuwiki must detect and override. +# +# Two runs: +# 1. default → integration ON, hooks rewired, diary paths from wiki root +# 2. opt-out → g:nuwiki_use_calendar=0 / g:nuwiki_no_calendar=1 leave +# calendar-vim's defaults untouched +# +# No LSP binary is needed — the diary hooks are entirely client-side VimL. +# Exit code: 0 when all assertions pass, 1 otherwise. Skips (0) without vim. + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +TMP="$(mktemp -d -t nuwiki-calendar-vim-test-XXXXXX)" +trap 'rm -rf "$TMP"' EXIT + +log() { printf '\033[1;34m[calendar-vim]\033[0m %s\n' "$*"; } + +if ! command -v vim >/dev/null 2>&1; then + log 'vim not installed — skipping' + exit 0 +fi + +# --- Scratch wiki with one seeded diary entry (2026-05-30) ---------------- +WIKI="$TMP/wiki" +mkdir -p "$WIKI/diary" +echo "= index =" > "$WIKI/index.wiki" +echo "= 2026-05-30 =" > "$WIKI/diary/2026-05-30.wiki" + +# --- Stub calendar-vim ---------------------------------------------------- +# Mimics the real plugin closely enough for detection + the override path: +# defines :Calendar and seeds calendar-vim's default hook names. +CAL="$TMP/calendar-vim" +mkdir -p "$CAL/plugin" "$CAL/autoload" +cat > "$CAL/plugin/calendar.vim" <<'EOF' +if exists('g:loaded_calendar_stub') | finish | endif +let g:loaded_calendar_stub = 1 +let g:calendar_action = get(g:, 'calendar_action', 'calendar#diary') +let g:calendar_sign = get(g:, 'calendar_sign', 'calendar#sign') +command! -nargs=* Calendar echo 'stub calendar' +EOF +cat > "$CAL/autoload/calendar.vim" <<'EOF' +function! calendar#open(...) abort +endfunction +function! calendar#diary(...) abort +endfunction +function! calendar#sign(...) abort + return 0 +endfunction +EOF + +run_harness() { + local label="$1" vimrc="$2" harness="$3" + local results="$TMP/results-$label.txt" + log "running $label harness…" + NUWIKI_CALENDAR_RESULTS="$results" \ + NUWIKI_CALENDAR_WIKI="$WIKI" \ + timeout 30 vim -e -s -u "$vimrc" -c "edit $WIKI/index.wiki" \ + -c "source $harness" "$TMP/$label.log" 2>&1 || true + if [[ ! -f "$results" ]]; then + echo "calendar $label harness produced no output" >&2 + echo "--- vim log ---" >&2 + cat "$TMP/$label.log" >&2 || true + return 1 + fi + cat "$results" + grep -qE '^SUMMARY: [0-9]+ passed, 0 failed' "$results" +} + +# --- Run 1: default (integration ON) -------------------------------------- +VIMRC="$TMP/vimrc" +cat > "$VIMRC" <