github saberzero1/motions 1.0.1

4 hours ago

Fixed

  • Which-key overlay no longer opens on a literal-argument leader keyr<leader>, and any other command awaiting a literal <character> argument (f, t, m, q, "), opened the leader overlay when the leader key was used as that argument. The fork signals vim-keypress only after it has consumed the argument, so the key was indistinguishable from a standalone leader press; the overlay now carries the previous key's expectLiteralNext state across the event and skips leader handling when the key was consumed as an argument. (#186)
    • Plugin: src/ui/which-key.ts, src/types/vim-api.d.ts
  • :obcommand no longer loses a charwise selection — a mapping such as vim.keymap.set("v", "<C-n>", ":obcommand templater-obsidian:create-new-note-from-template<CR>") ran the Obsidian command with no selection, so Templater and every other selection-dependent command saw nothing; the same command from the command palette, which never goes through the fork, saw it. The fork prefills '<,'> when : is pressed in visual mode, so the dispatcher received '<,'>obcommand … with selectionLine === selectionLineEnd for a selection inside one line — a case the #161 line-range restore skipped outright, while it widened a two-line charwise selection to both whole lines. The handler now rebuilds the range in document offsets from the '</'> marks and lastSelection, which survive exitVisualMode and carry columns, so charwise, linewise, and blockwise selections each restore as themselves. A typed numeric or % range keeps expanding to whole lines. (#192)
    • Plugin: src/workspace/commands.ts
  • Callouts no longer stay highlighted after a linewise yank — a callout the visual-line selection passed through kept a selection-coloured background forever, surviving the yank, further motions, and editing the block. Live Preview renders a callout the cursor is outside of as a block widget, which no CodeMirror mark decoration can reach, so linewise selection paints those widgets by toggling a class on their DOM element; the clearing loops skipped any element that was not isConnected. That is exactly the element that needs clearing — the moment the selection head enters the callout, Obsidian swaps the widget for source lines and caches the detached element, so the skipped class came back with the element on re-attach, and the element had already been dropped from the plugin's tracking set by then. Both clearing loops now remove the class unconditionally. (#190)
    • Plugin: src/vim/linewise-widget-highlight.ts
  • Yank highlight now covers rendered blocksyG over a callout flashed every line around it and left the callout itself untouched, and the same held for embedded notes, images, and tables. A block that Live Preview renders is a CodeMirror block widget, and no mark decoration can reach one: ContentBuilder.point drops the active marks when it emits a block point. Those blocks are painted through their DOM element instead, on the same timer as the decorations, and a block is painted when the yank touches any line it stands in for — it is opaque, so there is no partial state to show. The painting is derived from the highlight state on every view update rather than applied once, because a linewise yank leaves the CodeMirror selection spanning the range, which makes Live Preview reveal the blocks it touches as source lines; they only return as widgets a transaction later, when the cursor collapses. The fade mode animates background-color rather than the decorations' opacity, which on a block would take its rendered content down with it. (#190)
    • Plugin: src/vim/yank-highlight.ts, src/vim/block-widgets.ts (new — shared with linewise-widget-highlight.ts)
    • Styles: styles.css
  • K on a wikilink now opens a page preview that stays open — the preview either did nothing at all or flashed up for well under a second before vanishing, which made keyword lookup unusable. The action synthesised a bare new MouseEvent('mouseover'), and Obsidian's page preview reads two things off that event. Every hover-link source can be configured to require Ctrl/Cmd, and a modifier-less event does not open the preview — it only arms a document listener that waits for a real Mod keydown, which is why K looked inert until Cmd was pressed afterwards. Separately, page preview records the event's client coordinates as the pointer position, and the popover then re-checks every 500ms that elementFromPoint() there still resolves inside its target element, hiding itself when it does not; an event at (0, 0) resolves to the top-left corner of the window, so the preview hid itself about a second after showing. The event now carries the Mod flag — a deliberate K press is the explicit request that modifier exists to confirm — and the cursor's own viewport coordinates from coordsAtPos, which also anchors the popover to the link rather than to the corner. (#188)
    • Plugin: src/workspace/navigation.ts

Tests

  • 5 e2e tests in test/specs/yank-highlight-widgets.e2e.ts for #190yG painting a callout and an embedded note, release when the highlight expires, a yank that stops short of the callout leaving it alone, and fade mode keeping the callout's computed opacity at 1. Each was negative-controlled against a deliberate break: dropping the coverage filter painted the untouched callout (0 → 1), a no-op unpaint left it lit past expiry (0 → 1), reusing the decorations' opacity fade dropped the callout to opacity 0.646399
  • 3 e2e tests in test/specs/linewise-widget-selection-issue190.e2e.ts for #190 — two drive the stale highlight through the transition that causes it (selection head enters the callout, widget detaches) and assert the re-attached widget is clean after a yank and after <Esc>; the third selects past the callout without ever entering it and asserts the widget is highlighted, because "nothing is highlighted" would otherwise pass for a build that highlights nothing at all. The suite waits on the widget actually rendering, so it cannot pass on an editor that never produced one. Each test strips the class on entry: Obsidian's widget cache outlives editor.setValue(), so without it the leak fails the following test instead of the one that caused it
  • 4 e2e tests in test/specs/obcommand-visual-mode.e2e.ts for #192 — two drive a real <C-n> mapping and read editor.getSelection() from inside the dispatched command (single-line and two-line charwise), one runs editor:toggle-bold over a selection straddling two words, one holds :1,2obcommand to whole lines while a charwise selection sits in the marks. The straddle is deliberate: the first version of that test selected a whole word and passed against the unfixed build, because editor:toggle-bold falls back to the word under the cursor when it sees no selection
  • 2 e2e tests in test/specs/keyword-lookup.e2e.ts for #188 — one forces every registered hover-link source to require Ctrl/Cmd, reproducing the reporter's configuration, and asserts K alone still opens the preview; the other asserts the preview is still on screen 2.5s later, past the 500ms watchdog and the 300ms hide timer it starts. Both assert the popover's text contains Target.md's body, so a popover from any other surface cannot satisfy them. The first version of the require-Ctrl/Cmd test omitted the configuration step and passed against the unfixed build, because the preview source does not require the modifier by default. Both then failed red (present false in each case), and each half of the fix was controlled in isolation against the finished code: dropping ctrlKey/metaKey failed only the first test, and pinning the coordinates back to (0, 0) failed only the second

Documentation

  • CHANGELOG.md
  • KNOWN_LIMITATIONS.md: extended the ex command path entry in the Obsidian command passthrough section with the charwise restore
  • CONTRIBUTING.md: added src/vim/block-widgets.ts to the codebase structure tree
  • docs/features/quality-of-life.md: recorded that yank highlight covers rendered blocks whole
  • docs/features/quality-of-life.md: recorded that K opens the page preview regardless of the Page preview core plugin's per-source Ctrl/Cmd requirement, and that the preview stays open

Full Changelog: 1.0.0...1.0.1

Don't miss a new motions release

NewReleases is sending notifications on new releases.