Skip to content

0.112.0

Choose a tag to compare

@github-actions github-actions released this 16 Aug 20:47
· 4 commits to master since this release
0.112.0
933b375

Fixed

  • Cursor shape dropdowns always disabled in Settings UI — the 5 cursor shape dropdowns (Normal, Insert, Visual, Replace, Operator-pending) on the Appearance page were permanently disabled even when Obsidian's built-in Vim mode was off. Root cause: Obsidian's addSettingTab() immediately calls getSettingDefinitions() and caches the result for rendering and search indexing. In onload(), addSettingTab() ran before createBundledVimExtension(), so the disabled callbacks closed over forkActive = false (a const captured at the top of getSettingDefinitions()). The callbacks always returned true (disabled) regardless of the actual fork activation state. Fixed by replacing the captured forkActive const in all 5 disabled callbacks with a direct isBundledVimActive() call, so Obsidian's refreshDomState() always evaluates the current state. Additionally, this.declarativeSettingTab.update() is now called after createBundledVimExtension() to refresh the cached getSettingDefinitions() result — this updates the static description text which cannot use a callback. (#128)
    • Plugin: src/settings.ts (5 cursor shape disabled callbacks — !forkActive!isBundledVimActive())
    • Plugin: src/main.ts (store setting tab reference as declarativeSettingTab; call declarativeSettingTab.update() after createBundledVimExtension())
  • Animated cursor suppression not synced on reloadFeatures()setCursorSuppressed(this.settings.animatedCursor) was only called during initial plugin load (onload()), not during reloadFeatures(). Any runtime setting change that called reloadFeatures() (settings UI toggle, vimrc set smoothcursor, Lua vim.opt.smoothcursor) did not update the global cursor suppression flag in the codemirror-vim fork. The animated cursor canvas would draw but the native CM6 block cursor was not suppressed, causing both cursors to render simultaneously. Also fixed the born-broken table-cursor-suppression.e2e.ts test (5 of 6 failures since commit 99e5fea) whose enableAnimatedCursor() helper set the setting and called reloadFeatures() but never triggered the global suppression. (#127)
    • Plugin: src/main.ts (reloadFeatures() — added setCursorSuppressed(this.settings.animatedCursor) call)
  • Doubled cursors when animated cursor is disabled — when animated cursor was disabled, the native CM6 text caret (thin blinking bar) appeared alongside the fork's vim cursor (block/hollow) in normal, operator-pending, and replace modes after entering and leaving insert mode. Root cause: the fork's BlockCursorPlugin.update() relied on a CSS baseTheme rule to hide native cursor layers, but mode transitions (insert removes .cm-vimMode, normal re-adds it) and CM6's drawSelection extension left native layers visible due to CSS specificity conflicts. Fixed in the fork by unconditionally hiding native CM6 cursor layers and setting caretColor to match the vim cursor color (var(--interactive-accent)) in insert mode. (#129)
    • Fork: ~/Repos/codemirror-vim/src/block-cursor.ts (BlockCursorPlugin.update() — unconditional native layer hiding, mode-aware caretColor)
    • Fork: ~/Repos/codemirror-vim/DIFFERENCES.md (updated setCursorSuppressed API section)
  • Doubled cursors in embedded editors (textarea vim overlay) — in the textarea vim overlay, caretColor was the accent color instead of transparent in normal mode, causing the native text caret to appear alongside the fork's block cursor. Root cause: BlockCursorPlugin.update() checked the .cm-vimMode DOM class to determine insert/normal mode, but CM6 ViewPlugin update ordering meant the class wasn't yet present when the block cursor plugin ran. Fixed in the fork by checking this.cm.state.vim.insertMode directly instead of the DOM class. Also uses setProperty("caret-color", ..., "important") for CSS specificity robustness. (#130)
    • Fork: ~/Repos/codemirror-vim/src/block-cursor.ts (BlockCursorPlugin.update() — vim-state-based caretColor instead of DOM class check)
    • Fork: ~/Repos/codemirror-vim/DIFFERENCES.md (added "Vim-state-based caretColor" subsection)
  • Escape does not close footnote popover — pressing Escape twice (insert→normal, then idle normal) in the footnote popover editor did not close the popover. The user had to click outside to dismiss it. Root cause: the fork's findKey consumed <Esc> unconditionally in idle normal mode, preventing the event from reaching Obsidian's popover close handler. Fixed with a two-part approach: (1) the fork now exposes setIdleEscapeCallback(fn) which fires when Escape is pressed in idle normal mode, and (2) the plugin registers a callback (installEscapeGuard) that dismisses the popover via HoverPopover.hide() for non-workspace-leaf editors while silently consuming Escape in workspace-leaf editors (preventing Obsidian hotkey interference). (#130)
    • Fork: ~/Repos/codemirror-vim/src/vim.js (setIdleEscapeCallback API, wasIdleNormal pre-capture in findKey)
    • Fork: ~/Repos/codemirror-vim/DIFFERENCES.md (added setIdleEscapeCallback API section)
    • Plugin: src/vim/escape-guard.ts (NEW — installEscapeGuard with HoverPopover.hide() dismissal)
    • Plugin: src/main.ts (installEscapeGuard(this.app) call in feature registration)
  • Invisible cursor in footnote popover with animated cursor enabled — the animated cursor canvas (z-index: 15) renders behind Obsidian's popover (z-index: 30). The fork's vim cursor was also suppressed (global setCursorSuppressed(true)), resulting in no visible cursor. Fixed by detecting editors inside .popover or .modal-container in the CursorController and un-suppressing the fork's vim cursor for those views (setCursorSuppressedForView(view, false)). The animated cursor tick() skips rendering for above-canvas editors. (#130)
    • Plugin: src/vim/animated-cursor/controller.ts (isAboveCanvas flag, per-view un-suppression for popover/modal editors, tick() early return)
  • Stale cursor suppression after animated cursor toggle — when animated cursor was disabled at runtime, CursorController.update() returned early without clearing the per-view suppression override set in the constructor, leaving the fork's vim cursor hidden. Also, the constructor unconditionally suppressed the cursor regardless of config.enabled. Fixed by gating constructor suppression on config.enabled and calling clearCursorSuppressedForView() in the disabled early-return path. (#130)
    • Plugin: src/vim/animated-cursor/controller.ts (constructor gates on config.enabled, update() clears per-view override when disabled)

Changed

  • Internal API type safety — obsidian-typings migration (round 2) — eliminated 23 additional as unknown as casts across 16 source files by leveraging @obsidian-typings/obsidian-public-latest v6.32.0 typed APIs. Total as unknown as count reduced from 90 → 67. The remaining 67 casts are inherent to plugin architecture (dynamic settings indexing, codemirror-vim fork adapter access, external plugin window globals, fengari Lua bridge, minAppVersion compatibility guards).
    • src/util/commands.ts: app.commands.executeCommandById() and app.commands.commands accessed directly via typed Commands interface; custom ObsidianCommand narrowed to Pick<Command, 'id' | 'name'>
    • src/util/leaf.ts: leaf.id and leaf.pinned used directly (required properties via WorkspaceItem/WorkspaceLeaf augmentation); getViewFilePath()/getViewFileBasename() use instanceof FileView guard instead of as unknown as { file? } cast
    • src/util/vault.ts: ConfigItem imported from @obsidian-typings/obsidian-public-latest replacing custom VaultConfigKey type inference
    • src/workspace/global-defaults.ts: mdView.getMode() called directly (typed as MarkdownViewModeType)
    • src/editors/embeddable-editor.ts: app.embedRegistry accessed directly; editorApp.scope accessed directly (official API); workspace.activeEditor assignment typed via MarkdownFileInfo
    • src/oil/keybindings.ts, src/oil/manager.ts: app.internalPlugins.getEnabledPluginById('file-explorer') returns typed FileExplorerPluginInstance with revealInFolder(item: TAbstractFile)
    • src/oil/oil-view.ts: this.leaf.updateHeader() called directly (typed on WorkspaceLeaf augmentation)
    • src/oil/manager.ts: app.openWithDefaultApp(path) called directly (typed on App augmentation)
    • src/vim/native-table-adapter.ts: EditMode type extends MarkdownEditView instead of Record<string, unknown>; view.editMode accessed directly; isInLivePreview() uses view.getMode() + editMode.sourceMode instead of getState() cast; getEditModeForView() uses instanceof MarkdownView guard
    • src/vim/table-cell-cursor-guard.ts: mdView.editor.cm accessed directly (typed as EditorView via Editor augmentation)
    • src/ui/global-ex-command.ts: this.inputEl accessed directly (official SuggestModal.inputEl)
    • src/lua/loader.ts: view.getViewType() called directly (official View API) — 3 instances
    • src/settings.ts: this.display() and this.refreshDomState() — reverted, casts retained to bypass obsidianmd/no-unsupported-api and @typescript-eslint/no-deprecated lint rules (plugin minAppVersion is 1.7.2; these APIs require/deprecate at 1.13.0)
    • src/picker/sources/tasks.ts: app.plugins.plugins['obsidian-tasks-plugin'] accessed directly via typed Plugins interface

Documentation

  • CHANGELOG.md
  • KNOWN_LIMITATIONS.md: Updated cursor shapes section with addSettingTab() caching fix (#128); added doubled cursors fix (#129); added #130 fixes (doubled cursors in embedded editors, Escape popover dismiss, invisible cursor in popovers, stale cursor suppression)
  • AGENTS.md: Updated codemirror-vim fork cursor suppression description (vim-state-based caretColor, setIdleEscapeCallback API)
  • CONTRIBUTING.md: Added escape-guard.ts to codebase structure; updated controller.ts description with isAboveCanvas flag and popover/modal fallback
  • docs/features/animated-cursor.md: Updated embeddable editors section with popover/modal fallback and z-index explanation
  • Fork DIFFERENCES.md: Added setIdleEscapeCallback API section; added "Vim-state-based caretColor" subsection; updated findKey Escape handling description

Full Changelog: 0.111.0...0.112.0