Added
set tablewidget=auto, the new default: tables are revealed while the Neovim backend is connected, and use Obsidian's table editor otherwise. It switches when the backend connects, disconnects or dies.- Why the split: Obsidian's table editor gives each cell an editor of its own, and the backend mirrors only the note's editor, so under the backend Neovim never saw a cell being edited. A revealed table is lines of the note, which Neovim edits, follows its cursor into and draws its extmarks over. With the plugin's own Vim, Obsidian's editor keeps its buttons, sorting and menus while you edit, works on mobile, and is the most tested mode, so it stays.
- The setting's options are now Automatic, Always native, Always reveal (experimental) and Raw (deprecated), in both settings implementations,
set tablewidgetandvim.opt.tablewidget. - Plugin:
src/vim/table/gates.ts(effectiveTableWidgetMode),src/main.ts(followBackendForTables),src/vim/table-nav-controller.ts,src/settings.ts,src/vim/options.ts,src/vimrc/loader.ts
Changed
- A stored
tablewidgetofnativemoves toautoonce. Settings are saved whole, defaults included, so anativesaved beforeautoexisted cannot be told apart from the old default.- Nothing changes without the Neovim backend, where
autoisnative. - With the backend, tables are now revealed. To keep Obsidian's table editor there too, choose Always native again; it is then kept, because settings saved since carry
tableWidgetAutoMigrated. rawandrevealare left alone.- Plugin:
src/settings-migration.ts(migrateTableWidgetMode)
- Nothing changes without the Neovim backend, where
Fixed
- A vimrc mapping on a key the plugin binds itself was gone once Obsidian had started (#205).
nmap gw <Plug>(easymotion-bd-w)leftgwas hard-wrap's operator, andnnoremap Y yyleftYas the plugin'sy$.- Cause: the plugin removes and re-registers its bindings at startup and on every settings change. The removal took your mapping for the same keys with it, and a mapping that survived ended up behind the re-added binding, which then won. Reloading the vimrc after startup put the mappings back, which is why it went unseen. A mapping on a key the plugin does not bind, such as
<leader>w, was never affected. - Fix: your mappings, from the vimrc and from Lua, are lifted off before the plugin re-registers its bindings and put back on top afterwards, as user mappings beat built-in commands in Vim. Each is removed exactly, so nothing of the plugin's goes with it.
- Two related leaks: every pane switch re-applied the vimrc's mappings without removing the previous copies, so they piled up. A vimrc reload removed the old mappings by key in normal mode only, so visual and insert mappings outlived their removal from the file.
- Plugin:
src/main.ts(liftUserKeyMaps,restoreUserKeyMaps,removeKeyMapsExactly),src/types/vim-api.d.ts - Fork: codemirror-vim 6.4.8 makes the engine's side exact too.
unmap(lhs, ctx, { toKeys, noremap })removes only that user mapping, andremoveMapCommandno longer removes a user mapping on the same keys.
- Cause: the plugin removes and re-registers its bindings at startup and on every settings change. The removal took your mapping for the same keys with it, and a mapping that survived ended up behind the re-added binding, which then won. Reloading the vimrc after startup put the mappings back, which is why it went unseen. A mapping on a key the plugin does not bind, such as
Kinside a preview put the preview's cursor back at the top instead of previewing the link under it (#208).Kalways read the note's own editor and cursor, whichever editor it was pressed in, so inside a focused preview it acted as the note's secondKand refocused the preview.- Fix: it now uses the editor it was pressed in. Inside a preview it opens the nested preview Obsidian's own hover would, with the preview's note as the hover parent and as the source the link resolves from.
KKthere moves into the nested preview. - Plugin:
src/workspace/navigation.ts(keywordContext)
- Fix: it now uses the editor it was pressed in. Inside a preview it opens the nested preview Obsidian's own hover would, with the preview's note as the hover parent and as the source the link resolves from.
<C-o>after switching tabs went to an older note instead of the tab before (#206). Only the plugin's own navigations recorded a jump, such asgd, the pickers and]b. A tab clicked or reached with Ctrl+Tab, or a note Obsidian opened in the current tab, recorded nothing.- Fix: every change of note is now a jump, recorded with the line the note was left at, as Neovim records a
:bswitch. Witha,bandcin three tabs, visiting them in order and pressing<C-o>,<C-o>,<C-i>lands onb,a,b, matching Neovim 0.12.5, and focuses each note's own tab. - A navigation that records its own jump, and the walk itself, are not recorded twice.
- Jumps within a note are walked in their place. After switching to a note and jumping inside it,
<C-o>used to go back to the previous note before visiting those jumps. The editor kept them in a list of its own, which the walk consulted only once the plugin's list had no older note.- Fix: the bundled engine now reports each jump it records, and the plugin keeps it in the same list as the note switches, in the order they happened. Each position is a bookmark in the note's editor, so it follows edits.
- Neovim's model: where a jump landed, or a note was entered, stands for the cursor until the next jump's start replaces it, as Neovim records only where jumps start. The first
<C-o>moves it to the cursor, and once walked past it is an ordinary entry. - Measured parity with Neovim 0.12.5:
a, thenGinb, walksb,a,b,b.<C-o>back into a note visits the jumps made there.jis not a jump, so<C-o>after it goes straight to the previous note.<C-i>comes back to where<C-o>was pressed.- The walk stays put at the oldest entry.
- Flash and EasyMotion jumps now record where they landed too, so
<C-o>returns from them.:jumpslists the jumps within notes. - Only with the bundled engine: Obsidian's own Vim key bindings and the Neovim backend do not report their jumps, so there the previous order stands.
- Still differs from Neovim: the list keeps an older entry on the same line as a newer one, where Neovim drops it. Both are recorded in
KNOWN_LIMITATIONS.md.
- Plugin:
src/workspace/note-switch-jumps.ts,src/workspace/in-note-jumps.ts,src/vim/jumplist.ts,src/workspace/global-defaults.ts,src/workspace/navigate.ts,src/flash/{jump,char,search}-mode.ts,src/easymotion/register.ts,src/main.ts - Fork:
src/vim.js(setJumpRecordedCallback), released as codemirror-vim 6.4.8
- Fix: every change of note is now a jump, recorded with the line the note was left at, as Neovim records a
- In Obsidian's table editor, keys table-nav does not use were typed into the cell (#167). Table-nav, on by default, holds vim off while it keeps the cell editor hidden but focused. So a key outside its keymap reached the cell as text and was written to the note:
u,zzandxmadeNameintouzzxName. After a click onbb,xmade itbxb. Such keys now do nothing.- A second race in the same mode: table-nav sends
ito the cell's vim only once the cell editor is up, 150 ms on. Keys typed in between ran as normal-mode commands, soiqstarted recording a macro andiHityped nothing. They are now held and played after thei. - Visual mode still ends at a native table: Obsidian's widget moves the cursor into its cell editor as soon as a selection reaches it.
set tablewidget=revealkeeps the table as lines, whereVextends through its rows. This is recorded inKNOWN_LIMITATIONS.md. - Plugin:
src/vim/table-nav-controller.ts(holdEntryKeys),src/vim/table-nav-keymap.ts(typesIntoCell,heldEntryKey,replayEntryKeys)
- A second race in the same mode: table-nav sends
- The picker's "Results" title covered the first result (#171). The title took its height from the theme's line height, so a theme with a taller one covered the first result again. At a line height of 2.4 it overlapped the first result's text by 13.6 px. Even in the default theme its edge sat 1.2 px into the first result's box. It now has a height of its own, centred on the border, and the list clears it by 3 px in any theme.
- Plugin:
styles.css
- Plugin:
Tests
vimrc-feature-key-overrides.e2e.tsloads a vimrc withnmap gw <Plug>(easymotion-bd-w)andnnoremap Y yythe way Obsidian's start does. That means a cold plugin load followed by exactly one leaf change. Earlier tests reloaded the vimrc after startup, which is what hid the defect.- Scenarios:
- both mappings work after start;
- they still work after settings changes and pane switches, with one copy each;
- removing
Yfrom the vimrc givesYback to the plugin.
- Negative controls:
- Not lifting the mappings fails the first two, with no EasyMotion labels on
gwandYyankingthree four five(the plugin'sy$). - Re-applying on a pane switch without lifting fails the second, which then finds duplicate entries.
- A vimrc reload that removes nothing fails the third, with
Ystill yanking the whole line.
- Not lifting the mappings fails the first two, with no EasyMotion labels on
- Scenarios:
keyword-preview.e2e.tspressesKon a link inside a focused preview. It expects a nested preview of that link, the first preview still focused on its second line, andKKmoving into the nested one.- Negative controls:
- Reading the note's own editor, the old behaviour, opens no nested preview.
- Using the note's view as the hover parent replaces the preview instead of nesting.
KKnever focusing a nested preview leaves focus in the first, at index 0 instead of 1.
- Negative controls:
jump-list-note-switch.e2e.tsswitches between three notes in three tabs the way a tab click does, and walks back with<C-o>.- Scenarios:
a,b,cthen<C-o>,<C-o>,<C-i>lands onb,a,b;<C-o>returns to the line the note was left at;- it focuses the previous tab without opening a fourth;
- a note opened in the same tab is a jump;
gd, a heading picked in:headingsand]bare each recorded once.
- Negative controls:
- Not installing the recorder fails the four switch scenarios, because
<C-o>has nowhere to go and stays put: oncthroughout the walk, onbinstead ofa's line 3, and oncafter the same-tab open. - Not skipping a switch that left the list at the new note fails
gdand]b, recordinga, c, a, canda, b, a, b. - Not skipping one while a navigation is still opening its note fails
:headings, recordinga, b, a, b. - Forgetting the cursor of a note whose tab has since been reused fails the same-tab scenario, landing on line 0 instead of 2.
- Not installing the recorder fails the four switch scenarios, because
- Scenarios:
jump-list-note-switch.e2e.tsalso walks the jumps made within notes among the switches, each scenario against a sequence measured on Neovim 0.12.5.- Scenarios:
a, thenGinb, walksb:0,a:0,b:0,b:2;Gina, thenb, walks backa:4,a:0,a:0;- at the oldest jump
<C-o>stays put; jjis not a jump, so<C-o>goes toa, and<C-i>back tob:2;- after
Gandk,<C-i>comes back to where<C-o>was pressed; - once walked past, where
Glanded stays put; - a line put above a jump moves it;
- a note replaced in its tab keeps where its jumps were, in
:jumpsand in the walk; <C-o>to a closed fold's heading opens it;- a Flash jump is walked back and forth.
- Negative controls:
- Not installing the engine's callback fails seven scenarios: the first
<C-o>afterGinblands onaagain, the old order. - Handing jumps within a note back to the engine's own walk fails nine.
- Each rule of the model fails its own scenarios when removed:
- keeping where a note was entered stops on
b:0instead of reachinga; - not moving the newest entry to the cursor brings
<C-i>back tob:0anda:4instead ofb:2anda:3; - moving its position but not its bookmark brings
<C-i>back toa:4; - not making it an ordinary entry once walked past brings
<C-i>toa:3instead ofa:4.
- keeping where a note was entered stops on
- Fixed positions instead of bookmarks land on
b:1instead ofb:2after the edit. - Reading a replaced editor's bookmark lists
a:2instead ofa:3in:jumps. - Letting the walk fall through to the engine's list at the oldest entry lands on
a:1. - Not marking the walk as
foldopen'smarkleaves the fold closed. - Recording only where a Flash jump started leaves
<C-o>ata:4.
- Not installing the engine's callback fails seven scenarios: the first
- Scenarios:
test/unit/jumplist.test.tscovers the list's handling of jumps within a note: landing entries replaced by the next start or departure, the cursor taking the newest one, bookmarks followed through edits, deleted text skipped, an editor gone, released marks and serialization.- Each rule fails a test when removed: comparing lines only, not releasing dropped marks, not skipping deleted text, not dropping a gone editor's mark, not replacing a landing, keeping more than the newest as a landing, not making a walked-past landing ordinary, and not clearing it when a jump starts there.
- The fork's
jumplist_recorded_callbackandjumplist_recorded_callback_throwscheck that the callback reportsGwith its positions and nothing forkor the walk, and that a throwing callback leaves the jump and the list intact. Not calling it records no call, and letting the throw escape aborts theG. table-nav-stray-keys.e2e.tspresses keys in Obsidian's own table editor with table-nav on.- Scenarios:
u,zz,x, Space and Backspace leave the cell and the note unchanged;- after a click on
bb,xdoes nothing, andiQinserts at the click, makingbQb; iHisent at once typesHi;iHthen Escape at once leavesHin the cell in normal mode.
- Negative controls:
- Not swallowing the stray keys types
uzzxinto the cell and the note, andbxbafter the click. - Not holding keys during the 150 ms loses
Hi,HandQ, and leaves the last scenario in insert mode. - Holding them but not typing them in insert mode loses the same text.
- Not swallowing the stray keys types
- Scenarios:
picker-results-title.e2e.tsmeasures the "Results" title against the first result, in the default theme and with a line height of 2.4.- Results: the first result's box sits 3 px below the title, and its text 6 px below, in both themes.
- Negative controls:
- The 1.5.0 CSS fails both: −1.2 px and −16.6 px for the box, 1.8 px and −13.6 px for the text.
- Centring the title without giving it a height of its own still fails at a line height of 2.4, at −14.6 px.
tablewidget=autois covered with and without the Neovim backend, and across a migration.- Scenarios:
rpc-table-reveal.e2e.tsA1 to A3:autoreveals the table Neovim moves into once the backend connects, and gives tables back to Obsidian's table editor when the backend disconnects (A2) or its process is killed (A3);table-nav-mode.e2e.ts: table-nav still starts onautowithout the backend;table-widget-migration.e2e.tsloads stored settings cold: anativesaved beforeautomoves and records the move, anativechosen after it stays, anativepicked on fresh settings stays, andrevealis left alone;- unit:
table-widget-mode.test.tsresolves each setting with and without the backend, andsettings-migration.test.tscovers the move with and without the marker.
- Negative controls:
- Resolving
autotonativealways fails A1, with Obsidian's widget and table-nav taking the table. - Not following the backend fails A1 and A2. A settings reload during a pending disconnect still sees the backend, so without the listener the table stayed revealed after it.
- Following only the backend connecting fails A2 and A3, with the table revealed after the backend has gone.
- Gating table-nav on the stored setting fails the no-backend scenario, A2 and A3.
- Never moving
nativefails the first migration scenario. - A marker that defaults to
falsefails the first scenario and moves anativepicked on fresh settings toauto.
- Resolving
- Scenarios:
Full Changelog: 1.5.0...1.5.1