github saberzero1/motions 1.6.0

one hour ago

Added

  • set tablecolumnhighlight, to turn off the highlight on the cursor's column in a revealed table (#167). On by default, as before. Off, only the cursor's own cell is highlighted. Also Settings → Vim Motions → General → Highlight table cursor column, in both settings implementations, and vim.opt.tablecolumnhighlight. A change restyles an open table at once, without the cursor moving.
    • Plugin: src/vim/table/reveal/grid-decorations.ts, src/settings.ts, src/vim/options.ts, src/vimrc/loader.ts
  • set tableautorealign=typing: a revealed table realigns as you type (#167). Every typed edit realigns the table straight away, so the columns widen and narrow with the text, and leaving insert mode realigns once more. Each realign changes only the padding that differs; realigning a 1,000-row, 8-column table takes 0.72 ms, a 20-row one 0.02 ms. During an IME composition it waits for the commit, and a table with a row that is still missing its closing pipe is left alone, as with insertleave. A space typed at the end of a cell's text cannot be told from padding, so the realign waits for the next character there rather than trim it. Typing | in a row adds a column to every row at once, as vim-table-mode does; the caret stays after the |, the regression that ended an earlier realign-on-| (#66), and an escaped \| stays text (#67).
    • One u undoes an edit and its realign together, and . and macros repeat only the typed text.
    • Fork: codemirror-vim 6.4.11 (notTypedAnnotation)
    • Plugin: src/vim/table/reveal/auto-realign.ts (was realign-on-leave.ts)

Changed

  • tableautorealign is three-way: off, insertleave and typing. It was a toggle. A stored true moves to insertleave and false to off, saved vimrc and Lua overrides included, and the old forms still work: a bare set tableautorealign and vim.opt.tableautorealign = true mean insertleave, set notableautorealign and false mean off. In settings it is the dropdown Realign revealed tables on edits, in both implementations.
    • Plugin: src/settings.ts, src/settings-migration.ts (migrateTableAutoRealign), src/vim/options.ts (tableAutoRealignValue), src/vimrc/loader.ts (bare/negated for a string option that was boolean)
  • Visual-line mode (V) now gives the editor the whole lines it selects (#231). It used to give it only a cursor, so EditorState.selection and listSelections() showed nothing selected, and other plugins could not see the selection. It now works like v, like upstream codemirror-vim and like Obsidian's own Vim key bindings.
    • What you will see: in Live Preview, links, formatting marks and callouts on the selected lines show as source, as they already do under v. A table stays rendered and keeps its highlight.
    • The cursor keeps its column, as in Neovim. It was drawn at column 0. Measured in Neovim 0.12.5: wwVj reports col('.') == 12.
    • Fork: codemirror-vim 6.4.10 (updateCmSelection, makeCmSelection, measureCursor)
    • Plugin: src/vim/visual-line-cursor.ts, src/vim/animated-cursor/controller.ts

Removed

  • The workaround layer for the old visual-line selection. src/vim/visual-line-command-fix.ts patched Obsidian's Editor methods, the command registry and every command's checkCallback. The fork also widened the selection for each key vim did not handle. With the real selection, Obsidian's commands, Note Composer and async callers such as Note Refactor see it unaided.

Fixed

  • gj after a click went back to the column of the gj before it (#228). A click moves the cursor without a motion, so the screen column gj and gk keep was not reset, and the next gj headed for wherever the earlier ones had been going. Vim resets the column on a click. Measured on Obsidian 1.15.0: after gj presses at x 348, a click on column 13 and then gj went back to x 348. Obsidian's own Vim key bindings have the same gap, from the same upstream code.
    • gj also stopped short of a last display row shorter than the column, where Neovim moves to the end of that row. The check for "nothing to move to" compared the character column with the column in pixels. Obsidian's own Vim key bindings stop there too.
    • Not changed: in a paragraph with links or bold text, Live Preview shows each span's markup only while the cursor is in it. The paragraph re-wraps as the cursor leaves, and gj loses the column, in Obsidian's own Vim as well. This is recorded in KNOWN_LIMITATIONS.md.
    • Fork: codemirror-vim 6.4.9 (handleExternalSelection, findPosV)
  • Plugins reading the selection saw nothing in visual-line mode (#231). cm.listSelections() and EditorState.selection put the anchor and head at one point, while only Editor.getSelection() returned the lines. See Changed.
  • Escape in a focused nested preview left the preview beneath it open for good (#208). Closing the focused preview left the focus nowhere. The next Escape went to the note, and the preview beneath stayed open with no key left to close it. Closing a focused preview, by Escape or q, now returns you to where it was opened from: the preview beneath it, with its cursor where it was, or the note. This is what closing a Neovim float does.
    • Plugin: src/vim/escape-guard.ts (dismissParentPopover)
  • A revealed table drew Obsidian's blue search ring around rows after an edit (#167). yyp drew it around the pasted row, pasting several rows drew one around each, and a deletion that took the start of a row drew one around what was left. The reveal keeps a table as source with one search-match highlight per row, styled to stay invisible. Two bugs left a second one on a row, which looks like a real search match:
    • The reveal ran twice on every edit. Obsidian's own fold filter makes CodeMirror run transaction extenders a second time. Both runs added each new row's highlight, and only one of them could be removed.
    • A deletion across a row's start dropped that row from the plugin's record, while CodeMirror kept the rest of the highlight. The plugin could not remove what it no longer knew about.
    • Not font-dependent. Measured from the report's video, every character in the revealed rows has the same advance. The uneven pipes there come from a row with more padding than the rows above it; :tablerealign, or tableautorealign, lines them up.
    • Plugin: src/vim/table/reveal/reveal-field.ts (revealExtender, mapReveal)
  • . after a revealed table's Tab or Enter added a row typed the row back in. The vim engine records every change made in insert mode as typed text, whatever made it. ix, Tab from the last cell, y, <Esc>, then . on another line inserted x, a line break, an empty row and y. Neovim leaves text an insert-mode <Cmd> mapping sets through the API out of ., and its cursor move does not start a new insert; measured on 0.12.6, the same session repeats xy. The row-adding keys and the moves between cells are now marked as not typed, so . repeats xy, and iab, Tab to the next cell, cd repeats abcd where it repeated cd. The <br> of Shift-Enter is typed at the cursor and is still repeated, as a key mapping to <br> is in Neovim.
    • Fork: codemirror-vim 6.4.11 (notTypedAnnotation; the adapter gives such a change the origin +notTyped, which onChange does not record, and onCursorActivity does not start a new insert for its move)
    • Plugin: src/vim/table/reveal/cell-keys.ts

Tests

  • display-line-goal.e2e.ts presses gj after a real click, and onto a short last display row, on Obsidian 1.13.7 and 1.15.0.
    • Negative controls:
      • Without the reset, gj after the click returns to the old column.
      • With the old check, gj stays at column 239 instead of reaching the last row's end at 254.
    • The fork's gj_after_external_cursor_move and gj_onto_shorter_last_row fail the same two ways, on [0,14] and [0,59].
  • visual-line-editor-selection.e2e.ts reads what a V selection gives the editor: EditorState.selection, listSelections(), getSelection() and the column the cursor is drawn at, for V, Vj and an upward Vk. animated-cursor-edits.e2e.ts checks the animated cursor's column.
    • Negative controls:
      • With the old fork, every case fails as the report describes: head equal to anchor at (0,0), and getSelection() empty. The visual-line command, Note Composer and Note Refactor specs fail too, now that the workaround layer is gone.
      • With the fork's cursor branch removed, the cursor is drawn at the end of the range: ch 10 and 16 instead of 6.
      • With the plugin helper removed, the animated cursor sits on the line end.
    • The fork's visual_line_editor_selection and visual_line_editor_selection_backwards fail on the old bundle.
    • Golden comparisons now read a V cursor from vim's head, since the editor's head is now a line boundary.
    • linewise-widget-selection-issue190.e2e.ts proves the widget highlight on a table, which stays rendered under the selection, instead of a callout, which now shows as source.
    • The synthetic #157 test that pressed <Esc> before replaceSelection() was retired. It exercised the removed snapshot rather than a user path. The real command-palette Note Composer extract still runs.
  • keyword-preview.e2e.ts presses Escape twice in a nested preview opened by K/KK, and q once.
    • Negative control: without the refocus, the focus is lost after the first Escape (focusedIndex -1), and the first preview is still open after the second (count 1). The q case fails the same way.
  • table-reveal-highlight-rings-issue167.e2e.ts reads Obsidian's own highlight field after yyp, yjP and a deletion across a row's start, and the nested highlights that draw the ring. reveal-field.test.ts adds the same cases behind a filter shaped like Obsidian's fold filter.
    • Negative controls, recorded in table-reveal-negative-controls.md (E11, E12, U8, U9):
      • Rebuilding from the start state on the second run leaves a second mark on each pasted row, nested at lines 4 and 5 for yjP.
      • Mapping a row's start with TrackDel leaves 4:5-4:20, the rest of the deleted row's mark.
  • table-reveal-editing.e2e.ts turns tablecolumnhighlight off and on with the cursor still, and reads the highlighted column and cell each time.
    • Negative controls: with the setting ignored, and with the setting read only when the decorations would rebuild anyway, the column stays highlighted after set notablecolumnhighlight (Value, 11, 22).
  • table-reveal-editing.e2e.ts covers tableautorealign=typing and . across the cell keys: the rows realign before insert mode ends, one u takes back the edits and their realigns, . repeats only the typed text, . does not replay a row Tab adds, and . repeats the text on both sides of a Tab to the next cell. It also types | outside a table and inside a row, an escaped \|, and a space between words, with typing on. known-set-options.test.ts reads every vimrc form of tableautorealign, and settings-migration.test.ts the stored booleans. table-settings-labels.e2e.ts checks the dropdown.
    • Negative controls (S11 to S15 in table-reveal-editing-negative-controls.md): without the live realign the rows stay unaligned in insert mode; without the annotation on the realign . types the padding back (Bx ---- | ----- xx - x - elow…); without it on the added row . adds a line; without it on the move . repeats cd; without the hold in a cell's trailing space, aa b c comes out aa bc (S16). A bare vimrc set tableautorealign wrote nothing before the loader read '' as bare.
    • The fork's insert_not_typed_change_not_repeated, insert_not_typed_move_keeps_insert and insert_not_typed_edit_then_real_move fail without the origin, without the cursor-activity exemption, and when a not-typed change arms expectCursorActivityForChange, which made a real cursor jump after a realign keep the insert going (abcd for cd).
  • jump-list-open-tab-settings.e2e.ts runs <C-o> to a closed tab with Open Tab Settings 3.4.0 enabled (#206). The note opens in a new tab and the current tab keeps its note; without the plugin it opens in the current tab, as Vim reuses the current window. The jump list asks getLeaf(false) for the leaf, which Open Tab Settings patches, so no integration code is needed. The plugin is added to wdio.conf.mts disabled, like the other community plugins there.
    • Negative control: taking the active leaf instead of asking getLeaf(false) opens the note in the current tab with Open Tab Settings on, which is the behaviour the report describes (newLeaf false, OtsC.md gone).

Documentation

  • The pages describing plugin features under Obsidian's built-in Vim mode were wrong. Since the Vim toggle commands (2026-08-31), the plugin stands its whole Vim layer down while built-in Vim mode is on, so none of its motions, text objects, flash, EasyMotion, which-key, jump list or configuration apply there. Measured on 1.13.7: ]h does not move, and <C-o> never leaves the note. recommended-setup.md now says so, and README.md, the flash, EasyMotion, surround, which-key, status bar, jump list, architecture and ecosystem pages point to it. The reveal table mode, registered outside the Vim layer, still applies.

Full Changelog: 1.5.1...1.6.0

Don't miss a new motions release

NewReleases is sending notifications on new releases.