github saberzero1/motions 0.5.0

latest releases: 1.2.0, 1.1.1, 1.1.0...
3 months ago

Added

New Vim commands

  • Q — replay last recorded macro (Neovim default, maps to @@)
  • Y — yank to end of line (Neovim default, maps to y$; overrides CM Vim's yy behavior)
  • ga — show character info under cursor (codepoint, hex, octal) via Notice
  • gp — paste and move cursor past pasted text
  • gn / gN — select next/previous search match (CM Vim native, now tested)
  • g; / g, — jump to older/newer change position (changelist navigation)
  • zO / zC / zA — recursive fold open/close/toggle (maps to Obsidian's fold commands)
  • it / at — HTML/XML tag text objects, implemented via raw text scanning since CM Vim's built-in expandToTag is inactive in Markdown mode. Supports single-line, multiline, and nested tags.
  • <C-v> — visual block mode (CM Vim native, now tested)

New Ex commands

  • :e {file} / :edit {file} — open file by name in vault
  • :e! / :edit! — revert current file to saved version
  • :enew — create new untitled note
  • :saveas {file} — save current buffer as new file
  • :update / :up — save current file (alias for :w)
  • :x / :xit — write-if-modified and close
  • :xa / :xall — write-if-modified all and close all
  • :find {file} / :fin — find and open file by partial name match
  • :read {file} / :r — insert file contents at cursor position
  • :b {name} / :buffer {name} — switch to tab matching name
  • :bf / :bfirst — go to first tab
  • :bl / :blast — go to last tab
  • :bw / :bwipeout — close current tab
  • :sp / :split — horizontal split
  • :vs / :vsplit — vertical split
  • :new — horizontal split with new note
  • :vnew — vertical split with new note
  • :tabnew / :tabedit — open new tab (optionally with file)
  • :tabclose / :tabc — close current tab
  • :tabonly / :tabo — close all other tabs
  • :tabfirst / :tabrewind — go to first tab
  • :tablast / :tabl — go to last tab
  • :version / :ve — show plugin version
  • :delmarks {marks} — delete specified marks
  • :changes — show change list in modal

Test infrastructure

  • Shared test helpers module (test/helpers.ts) with setupEditor, getCursorPos, getEditorValue, getRegisterContent, getVimMode, vimKeys, and timing constants
  • unsupported() and deviation() test helpers for documenting known limitations and behavioral differences in test reports
  • Neovim command index manifest (test/neovim-command-index.yaml) tracking 227 commands with tier classification, test status, and test file references
  • Coverage report script (test/coverage-report.ts) — run via npm run test:coverage
  • 16 new test files in test/specs/vim-builtin/ covering normal mode motions, search, editing, yank/put, insert entry, scroll, marks/jumps, g-commands, z-commands, bracket commands, text objects, operators, visual mode, insert mode, and Ex commands
  • 7 spike tests for register access, paste marks, editor extensions, tag text objects, CM Vim Ex command probing, Ex command conflict checking, and vimrc mapping diagnostics
  • Comprehensive E2E test coverage for <C-w>h/j/k/l pane focus, H/M/L screen-relative motions, ? backward search, zO/zC/zA recursive folds, and all new Ex commands
  • E2E test for scrolloff hot-reload: verifies scroll margins update when scrolloffLines changes
  • E2E test for Y/Q independence from workspace navigation: verifies Y still yanks to end of line when workspace nav is disabled
  • GitHub issue templates (bug report, feature request) with required KNOWN_LIMITATIONS.md checklist

Fixed

  • Scrolloff now works correctly — previously used CSS scroll-padding which CodeMirror 6 ignores (it uses manual scroll calculations, not Element.scrollIntoView). Replaced with EditorView.scrollMargins facet, which CM6 respects when scrolling the cursor into view
  • Scrolloff setting now applies immediately when changed in settings — previously required a plugin reload because the slider's onChange handler did not trigger reloadFeatures() and reloadFeatures() itself had no scrolloff handling
  • Removed deprecated setDynamicTooltip() call on scrolloff slider — the value is now always shown inline by Obsidian
  • Y (y$) and Q (@@) Neovim default remaps now work regardless of the "Workspace navigation" toggle — previously these were registered inside registerWorkspaceNavigation() and would stop working when workspace nav was disabled
  • Vimrc loader now shows a Notice on load: reports the number of commands applied on success, warns when the file is not found, and warns when the file contains no commands
  • Vimrc commands are now processed through codemirror-vim's Ex command handler (handleEx) instead of the programmatic API, matching obsidian-vimrc-support's approach for improved compatibility
  • ESLint import/no-extraneous-dependencies error on @codemirror/view — added import/core-modules setting and peerDependencies for @codemirror/* packages provided by Obsidian at runtime
  • Removed unused variables: totalLines in tag.ts, openEndIndex/closeStartIndex in tag.ts, active in commands.ts, newLeaf in commands.ts

Changed

  • Scrolloff implementation rewritten from CSS scroll-padding inline styles to EditorView.scrollMargins extension registered via registerEditorExtension. The ScrolloffManager class no longer manages event listeners or DOM manipulation — it updates a shared margin variable read by the CM6 facet callback.
  • Refactored 8 existing test files to use shared helpers from test/helpers.ts instead of locally defined getEditorValue, getCursorLine, and vimKeys functions
  • Test-vault hotkeys.json now unbinds Obsidian shortcuts that conflict with Vim commands (Ctrl+W, Ctrl+N, Ctrl+P, Ctrl+S, Ctrl+O)
  • Tag text objects (it/at) changed from unsupported skip to working plugin-implemented text objects
  • ChangeList class gains getEntries() and getIndex() public accessors for the :changes Ex command
  • Y and Q Neovim default remaps moved from registerWorkspaceNavigation() to the always-on initialization path in onload() and reloadFeatures()
  • Vimrc loader's loadVimrc() now returns a VimrcLoadResult with found, commandCount, path, and maps fields
  • Vimrc loader refactored to use vim.handleEx() for command application instead of direct vim.map()/vim.setOption() API calls, improving compatibility with obsidian-vimrc-support configurations
  • Vimrc loader now collects parsed map commands as DeferredMap entries and re-applies them via vim.map()/vim.noremap() on subsequent active-leaf-change events, attempting to restore mappings that CM Vim may lose during editor reinitialization
  • Vimrc loader intercepts set textwidth=N / set tw=N lines and directly updates the plugin's internal textwidthValue, bypassing CM Vim's option callback chain
  • getTextwidth() now reads from CM Vim's option via Vim.getOption('textwidth') as a fallback when the plugin's internal value hasn't been updated
  • Vimrc loading deferred to first active-leaf-change event to guarantee editor availability, matching obsidian-vimrc-support's loading strategy

Documentation

  • README: added :wa / :wall to Ex commands table, g<C-t> to workspace keybindings table
  • README: corrected set textwidth=N claim — now notes the known limitation and provides the runtime workaround via developer console
  • KNOWN_LIMITATIONS.md expanded with comprehensive "Neovim Ex commands not applicable in Obsidian" section covering 30+ commands across 8 categories (shell, quickfix, tags, scripting, diff, etc.) with specific reasoning
  • KNOWN_LIMITATIONS.md expanded with "Behavioral deviations" section documenting 6 commands that work differently from Neovim (Y, Q, :wall, gf, zO/zC/zA, it/at)
  • KNOWN_LIMITATIONS.md: added "nmap L $ does not work via vimrc" section with full diagnostic findings
  • KNOWN_LIMITATIONS.md: added "set textwidth via vimrc does not affect gq" section with root cause analysis
  • KNOWN_LIMITATIONS.md: replaced "Scrolloff cleanup on disable" section with "Scrolloff line height assumption" (22px hardcoded)

Full Changelog: 0.4.0...0.5.0

Don't miss a new motions release

NewReleases is sending notifications on new releases.