Repository navigation
Add ghostel-window-padding-balance to align the grid vertically - #664
Conversation
91f6635 to
bc73aad
Compare
bc73aad to
2f3d682
Compare
|
@mallet can you check again, I added a bottom option so you can choose between top (default), center and bottom alignment. The color leak issue should also be fixed. |
A window is rarely a whole number of terminal rows tall. When nothing precedes the first row (alternate screen, unscrolled primary screen) the leftover pixels sit as a gap below the last row, so tmux's status bar floats above the mode line while a fixed top row (htop, emacs -nw) looks truncated. The option picks where the leftover goes: top (default) keeps it below the last row, center splits it like ghostty's window-padding-balance, bottom moves it all above the first row so the last row sits flush against the mode line. The pad is a before-string display line above row 1 (a line-height on row 1's own newline is dropped by redisplay when the row fills the window width, and the renderer rewrites that newline). A leftover of a row or more never pads: the grid does not fill the window yet, or the body-capped pixel measurement lost the pad row, which would otherwise ratchet the pad up without bound. Graphical frames on Emacs 29+ only. Fixes #663
2f3d682 to
dcb58fc
Compare
|
@dakra Thank you very much. This is an excellent design, and it will be very useful. However, at the moment, the options center & bottom both are unstable, behave exactly the same and introduce the same gaps. In a new Bash shell (Ghostel just launched), pressing any key makes the shell jump up or down (alternately). See below the difference after pressing backspace (once or twice): In tmux, even after a command has been executed (inside tmux and in the hosting shell too), pressing a key makes the tmux area toggle between bottom alignment and top alignment (regardless of the option: center or bottom--but top is fine). |
dcb58fc to
17d7b76
Compare
|
@mallet can you try again? and what Emacs version are you running btw? Because I'm on latest master 32 and there it worked but apparently this part changed multiple times in Emacs 30 and 31. |
|
@dakra This is much better. Very stable, no glitches. I have noticed a slight problem at the start of Ghostel, hence for a raw Bash shell which is not yet full of lines. In bottom mode, it is perfect. But in center & top mode, gaps are applied as if the Bash shell were an alt screen. In top mode, the initial shell prompt is aligned at the top: In center mode, there is the slight gap that would be applied with an alt screen: The rest is perfect. I have tested center, bottom and top. Except at startup with center & top, I see no issue in raw Bash or tmux, even when resizing. My exact version is GNU Emacs 30.2 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.50, cairo version 1.18.4) of 2025-11-22, modified by Debian. |
17d7b76 to
b46413d
Compare
|
@mallet thanks for testing so extensively. |
|
Thank you very much for implementing this @dakra ! Much appreciated. |







Fixes #663.
A window is rarely a whole number of terminal rows tall. When nothing precedes the first row (alternate screen, unscrolled primary screen) the leftover pixels sit as a gap below the last row — so tmux's status bar floats above the mode line, while a fixed top row (htop,
emacs -nw) looks truncated.What this adds
ghostel-window-padding-balance(graphical frames on Emacs 29+ only) picks where the leftover goes:top(default) — below the last row, as before.center— split between top and bottom, like ghostty'swindow-padding-balance.tis accepted ascenter.bottom— all of it above the first row, so the last row sits flush against the mode line. Natural for a shell under tmux, and consistent with how the primary screen already clips at the top once scrollback exists.Any other value falls back to
top.Implementation
The pad is a
before-stringdisplay line above grid row 1 — an empty overlay atpoint-minwhose before-string is a tiny-face newline carryingline-height= pad pixels. Aline-heighton row 1's own newline was tried first but redisplay drops it when the row fills the window width (emacs -nwmenu bar, full echo lines), and the native renderer rewrites that newline; the separate pad line is immune to both. The pad is buffer-wide (the smallest graphical window showing the buffer bounds it), removed once scrollback precedes row 1, and dropped on major-mode change and buffer reuse.A leftover of a row or more never pads: it means the grid does not fill the window yet (startup, pre-resize), or the body-capped pixel measurement lost the pad row. Without this guard, enabling the option before the terminal started seeded an oversized pad that ratcheted up without bound (found in live testing); such a pad now self-heals on the next anchor.
Default = no impact
With
topthe pad overlay is never created andwindow-start/vscrollare byte-for-byte what they were before; the anchor path adds ~0.28 µs of pure elisp per anchor (no extrawindow-text-pixel-sizecall), well under 1% of an anchor.Testing
test/ghostel-scroll-test.el): alt-screen split, floor rounding, bottom takes the full leftover, unfilled grid gets no pad, oversized-pad recovery, row-1 rewrite (full-width and empty), sub-row shrink rebalance, scrollback yield, buffer-wide min across windows, option toggling (includingt= center), major-mode drop. The mocked pixel measurement models the real body-capped scan: a pad of a row or more is not counted.bottomset before the terminal (the previously wedging case) settles at the exact sub-row leftover and stays put across output floods; runtime toggling between all three values; pixelwise resize re-settling; plus the original alt-screen matrix (tmux, htop, less, vim,emacs -nw) and dynamic-geometry/lifecycle paths.make -j8 allgreen.