Added
- Table debug state inspector — new
:tablestate(:tables) ex command andwindow.CodeMirrorAdapter.getTableDebugState(app)API that snapshots all hidden table interaction state into a single queryable object. Exposes: table-nav session (WeakMap state, widget connection, scopes, timers), CM6 StateField, mode tracker status, cell editor status, cursor suppression (global, per-view, override count), fork key intercept flag, cell crossing coordination, DOM markers, and table scroll metrics. Designed to make table interaction bugs observable instead of invisible. (#167)- Plugin:
src/vim/table-debug-state.ts(new — snapshot and formatter) - Plugin:
src/vim/table-nav-controller.ts(getTableNavSessionSnapshot()export,__DEV__lifecycle logging) - Plugin:
src/vim/table-cell-motions.ts(getCrossingState()export) - Plugin:
src/vim/bundled-vim.ts(registerTableDebugState()lazy registration) - Plugin:
src/workspace/commands.ts(:tablestateex command) - Plugin:
src/main.ts(debug state registration at startup and reload) - Plugin:
src/types/codemirror-vim.d.ts(fork type declarations for new exports) - Fork:
src/block-cursor.ts(getViewOverrideCount(),isCursorSuppressed()re-export) - Fork:
src/index.ts(isKeyInterceptActive(), updated exports) - Fork:
DIFFERENCES.md(documented new exports)
- Plugin:
Fixed
- Key intercept stuck after switching from Live Preview to source mode during table-nav —
setKeyInterceptActive(true)set during table-nav was never cleared when switching LP→source because theTableNavControllerViewPlugin doesn't receiveupdate()calls ordestroy()during view reconfiguration. All vim key processing was suppressed globally, leaving the editor unresponsive. Fixed with awindowcapture-phasekeydownsafety handler that detects stale key intercept (active but no.vim-motions-table-nav-modein DOM) and clears it. Pressing Escape restores key processing. Cursor suppression and stale Obsidian Scopes remain as a known limitation requiring fork-level fixes. (#167)- Plugin:
src/main.ts(window keydown safety handler) - Plugin:
src/vim/bundled-vim.ts(setKeyInterceptActiveandclearCursorSuppressedForViewexposed on bridge) - Plugin:
src/vim/table-nav-controller.ts(forceTableNavCleanup()export,logTableEventlifecycle logging) - Plugin:
src/vim/table-debug-state.ts(event log:logTableEvent,getTableEventLog,recentEventsin state output,mainCursorLayerHiddenfield)
- Plugin:
- Horizontal scrolling missing in table-nav mode — navigating to off-screen columns in wide tables left the highlighted cell outside the visible viewport. The table widget had
overflow: visiblewhich prevented horizontal scrolling entirely — no ancestor element was scrollable. Fixed by changing the table widget's overflow tooverflow-x: autoduring table-nav mode and scrolling the widget element directly inscrollHighlightedCellIntoView(). (#167)- Plugin:
src/vim/table-nav-controller.ts(horizontal scroll logic targetings.widgetEl) - Styles:
styles.css(.vim-motions-table-nav-mode:overflow-x: auto; overflow-y: visible)
- Plugin:
- Hot-reload and manual reload fail intermittently — when the initial config load hit Obsidian's adapter timing race (file exists on disk but
adapter.read()returns empty during early lifecycle),vimrcWatchPath/luaWatchPathwere set to null becausefoundwas derived from the read result, not the stat. This broke both the file watcher (never fires) and the reload command (softReloadVimrcbails on null path). Three fixes: (1) watch paths are now resolved viaresolveVimrcPath/resolveLuaConfigPath(stat-based) as a fallback when the read-based load returnsfound: false; (2)softReloadVimrcno longer bails on empty commands — an empty parse is a valid reload (clears all vimrc mappings); (3)reloadAllConfigsresolvesvimrcWatchPathon-demand when null. (#168)- Plugin:
src/main.ts(stat-based watch path fallback in initial load,softReloadVimrcguard relaxed,reloadAllConfigson-demand resolution)
- Plugin:
- Removed Lua keymaps persist after config reload — keymaps registered via
vim.keymap.set()ininit.luawere not cleaned up when removed from the config and reloaded. Two root causes: (1)softReloadLuaConfigdid not unmap old Lua keymaps or undefine old ex commands before re-loading; (2) Lua keymaps were double-registered (eagerly duringloadInitLuaand again viaapplyLuaMapsinreloadFeatures), so a singlevim.unmaponly removed one entry. Fixed by adding an unmap loop insoftReloadLuaConfigthat removes all occurrences of each old mapping. (#168)- Plugin:
src/main.ts(softReloadLuaConfigunmap/undefineEx cleanup with multi-occurrence loop)
- Plugin:
- Scroll offset activates during mouse selection — dragging to select text near the viewport edge triggered scrolloff-based scrolling prematurely. With high scrolloff values (e.g.,
scrolloff=999for centered scrolling), the viewport jumped while the mouse was still well within the editor. Fixed by tracking pointer-down state via a CM6 ViewPlugin witheventObserversand suppressing the scrolloff listener while a mouse button is held (plus a 100ms settle delay after release to prevent post-selection scroll drift). (#175)- Plugin:
src/vim/scrolloff.ts(addedmouseTrackerViewPlugin,pointerdown/pointerupobservers, document-levelpointerupsafety listener, 100ms settle timer)
- Plugin:
- Subword motion
dwdeletes across line boundaries — with subword motions enabled,dwon the last word of a line deleted the newline and text from the next line instead of stopping at end of line. Two root causes: (1) the subword motionmapCommandcalls were missingforward: true/forward: falsein motionArgs, so the fork'sclipToLine(which preventsdwfrom crossing line boundaries) was never triggered; (2) the subword motion only recognized word-character boundaries (letters, numbers) and completely skipped non-word non-whitespace characters (:,.,!, etc.), causingwto jump past trailing punctuation to the next line instead of stopping at the punctuation group. Verified against Neovim 0.12.5 — all test scenarios now match Neovim's behavior. (#174)- Plugin:
src/motions/register.ts(addedforward: truetow/eandforward: falsetob/gesubword motion registrations) - Plugin:
src/motions/subword.ts(added punctuation group boundary detection viaPUNCT_GROUP_RE, merged with subword boundaries ingetLineStarts/getLineEnds)
- Plugin:
- Hover tooltips from other plugins clipped within scrolloff zone — hover tooltips (page preview, auto-linker, LanguageTool, and any CM6
hoverTooltipextension) were hidden for text within the top/bottom scrolloff lines. Root cause: the scrolloff implementation usedEditorView.scrollMargins, which CM6's tooltip plugin reads to determine the "visible" viewport area — tooltips positioned within the margin zone were clipped totop: -10000px. With the default scrolloff of 5, the first ~5 lines were affected; withscrolloff=999(centered scrolling), the entire top half of the viewport was affected.mousedownwas unaffected because the mouse-down guard already returnednullfrom scroll margins. Fixed by replacingEditorView.scrollMarginswith anEditorView.updateListenerthat manually adjustsscrollDOM.scrollTopafter cursor movement, preserving the scrolloff scroll behavior without marking the margin zone as invisible to the tooltip system. (#170)- Plugin:
src/vim/scrolloff.ts(replacedscrollMarginsfacet withupdateListener-based manual scroll adjustment, added 100ms settle delay after pointerup to prevent scroll drift on mouse selection end)
- Plugin:
Tests
- 3 e2e tests in
test/specs/table-cursor-vanish.e2e.tsfor #167 (stuck state detection, bridge cleanup, automatic keydown safety handler) - 2 e2e tests in
test/specs/table-debug-state.e2e.tsfor table debug state instrumentation (#167) - 3 additional e2e tests in
test/specs/config-management.e2e.tsfor #168 (removed vimrc mapping cleaned up via reload command; removed vimrc mapping cleaned up on disk change; removed Lua keymap cleaned up via reload command) - 2 e2e tests in
test/specs/scrolloff-mouse.e2e.tsfor #175 (mouse drag near viewport edge should not cause scroll drift; keyboard navigation should still trigger scrolloff) - 3 e2e tests in
test/specs/subword-motions.e2e.tsfor #174 (dwat end of line,dwon last word,dwbefore trailing punctuation) - 6 e2e tests in
test/specs/cursor-pointer-events.e2e.tsfor #170 (pointer-events, mousemove targeting, Decoration.mark hit-testing, caretRangeFromPoint, mouseover, hoverTooltip callback)
Documentation
CHANGELOG.mdKNOWN_LIMITATIONS.md: added horizontal scrolling fix, key intercept stuck limitation, table debug state documentationCONTRIBUTING.md: addedtable-debug-state.tsto file tree, updatedtable-nav-controller.tsandtable-cell-motions.tsdescriptions, updatedscrolloff.tsdescription to reflect new implementationAGENTS.md: updated fork API surface with new diagnostic exportsdocs/features/tables.md: updated viewport scrolling callout to mention horizontal scrolling
Full Changelog: 0.145.0...0.146.0