Repository navigation
Keep panes and gutters aligned under a winbar - #16
Conversation
A winbar takes the top row of a window. Breadcrumb plugins such as LspSaga set one on the source panes only, shifting the code a row below its number/connector gutters; a global 'winbar' reaches every split, but the Kitty canvas was placed at the connector's top row (the bar), one row above the code. A global winbar cannot be hidden per window (an empty local value falls back to it), so instead the bar row is kept uniform: when any aligned window shows a winbar, gutters, overview strips and bar-less panes get a blank one. The user's own bars are kept. Session, merge and folder hosts re-align on OptionSet winbar and BufWinEnter (buffer swaps reset it). The Kitty canvas now starts below the connector's winbar, and viewport heights use text rows (winheight) instead of nvim_win_get_height, which counts the bar row. Fixes #14
|
Thanks for looking into that @CoreyKaylor. It works when winbar is rendered immediately(focus on right diff panel from the start)
but when left panel is selected initially(e.g switching files with offset.mp4Basically when winbar is rendered once diff lines were generated the issue remains. I dont know TBH why lspsaga defers winbar rendering, maybe I am able to somehow force it to be rendered eagerly |
LspSaga renders breadcrumbs from its CursorMoved, BufEnter and symbol-update callbacks. OptionSet does not fire there (autocmds are not nested), and a bar appearing fires neither WinResized nor WinScrolled, so a bar added after the first render (focus moving to the right pane, ]f/[f) left the gutters a row off. Showing a winbar always redraws its window, so the watcher now rides on a decoration provider: on_win checks (read-only) whether a host's bar rows are in step and schedules the realign when they are not. This covers any source of change: nested or top-level sets, global toggles, and buffer swaps.
|
Thanks for the video @tpodolak, that pinned it down. LspSaga sets the breadcrumbs from inside its own 5fcdd26 hooks the check into redraws instead: showing a winbar always redraws its window, so the next redraw re-aligns the gutters no matter how the bar was set. I reproduced your flow (left pane focused first, then a You shouldn't need to make LspSaga render eagerly. Could you update the branch and try again? |
Re-sending an image id with a new c/r does not resize its existing virtual placement in Ghostty: the old grid is kept and the new image is stretched over it. A winbar arriving after the first paint takes one row from the connector, so the ribbons drifted further off the further down the screen they were, until a later same-grid transmit happened to fix it. Delete the old image and placement before transmitting a different grid; same-grid repaints still replace the image in place.
|
Thanks @tpodolak, glad cells is sorted. I reproduced the Kitty one in Ghostty. The offset wasn't a whole row: it grew further down the screen, about half a row by line 15. DiffBandit was sending the right thing; when the lazy winbar takes a row, it sends a new image one row shorter. But Ghostty doesn't resize an image's existing virtual placement when the same image id is re-sent with a new cell grid. It keeps the old 35-row grid and stretches the 34-row image over it. Scrolling fixed it only because a later transmit happened to replace the placement. 7eb0b1e deletes the old image and placement before sending a different grid (same-grid repaints, like scrolling, still replace in place). With that, the change band and add wedges land on their rows in Ghostty after the bar loads lazily. This probably also fixes the same drift after resizing the terminal or a split. Could you pull the branch once more? |
|
Works fine now with both Kitty and cell rendering. Thanks |
|
Thanks for all the feedback. |


Fixes #14.
The problem
A winbar takes the top screen row of a window, which moves that window's text down one row.
winbar: every split gets one, so the cell gutters line up, but the Kitty canvas was placed at the connector window's top row, the bar row. That puts it one row above the code.The fix
A global
winbarcan't be hidden on one window: an empty local value falls back to the global one. So instead of removing bars, DiffBandit keeps the bar row the same across the windows that must line up.on_win, read-only, which schedules the realign). A bar a plugin sets later, even from inside its own autocmd whereOptionSetdoesn't fire, is picked up on the next redraw.nvim_win_get_heightincludes the winbar row).Testing
nvim --headless -u tests/run.luapasses.Please confirm
@tpodolak @linduxed, could you try this branch with your setup (LspSaga breadcrumbs /
vim.opt.winbar = "%=%m %f%=", cells and Kitty renderers) and confirm the rows line up? With lazy.nvim:{ "CoreyKaylor/diffbandit.nvim", branch = "winbar-alignment" }linduxed: you can drop your autocmd that turns the winbar off.