Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions lisp/ghostel-compile.el
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,9 @@ so there is no remote-integration round-trip on TRAMP buffers."
(ghostel--load-module t)
(let* ((buffer (get-buffer-create name))
(win (or (get-buffer-window buffer t) (selected-window)))
(height (if (window-live-p win) (window-body-height win) 24))
(height (if (window-live-p win)
(with-selected-window win (floor (window-screen-lines)))
24))
(width (if (window-live-p win) (window-max-chars-per-line win) 80)))
(with-current-buffer buffer
;; Set `default-directory' before `ghostel-mode' so the mode's
Expand Down Expand Up @@ -626,7 +628,8 @@ honour custom compile-mode subclasses the caller passed to
;; column and look garbled until the user's first resize triggers
;; `ghostel--window-adjust-process-window-size'.
(when (and outwin ghostel--term)
(let ((oh (max 1 (window-body-height outwin)))
(let ((oh (max 1 (with-selected-window outwin
(floor (window-screen-lines)))))
(ow (max 1 (window-max-chars-per-line outwin))))
(ghostel--set-size ghostel--term oh ow)
(setq ghostel--term-rows oh)))
Expand Down Expand Up @@ -659,8 +662,9 @@ honour custom compile-mode subclasses the caller passed to
;; window, e.g. `allow-no-window'). Use `window-max-chars-per-line'
;; as the canonical width measure, matching `ghostel--spawn-pty'.
(let* ((height (max 1 (if outwin
(window-body-height outwin)
(window-body-height))))
(with-selected-window outwin
(floor (window-screen-lines)))
(floor (window-screen-lines)))))
(width (max 1 (if outwin
(window-max-chars-per-line outwin)
(window-max-chars-per-line))))
Expand Down
33 changes: 22 additions & 11 deletions lisp/ghostel-debug.el
Original file line number Diff line number Diff line change
Expand Up @@ -570,11 +570,13 @@ ghostel settings into *ghostel-debug* for pasting into bug reports."
(if copy "active" "off"))))
(insert "Term handle: nil (no terminal)\n"))
;; Size sync — surfaces #192-class bugs.
;; If body-rows ≠ term-rows but cur=recorded body pixels, then
;; Emacs already absorbed the chrome change but ghostel didn't
;; reconcile (a real ghostel bug). If both differ, the next
;; redisplay will fire `window-{size,configuration}-change-hook'
;; and `--window-adjust-process-window-size' will reconcile.
;; Compare term-rows against `floor(window-screen-lines)' (what
;; `window-adjust-process-window-size-smallest' uses), NOT
;; `window-body-height': the latter divides by frame char
;; height while screen-lines divides by `default-line-height'
;; (face-remap-aware). When a theme remaps the default face
;; height, the two disagree and the body-height comparison
;; cries wolf.
(when (and term (window-live-p win))
(insert "\n--- Size sync ---\n")
(let* ((cur-body-px (window-body-height win t))
Expand All @@ -584,12 +586,21 @@ ghostel settings into *ghostel-debug* for pasting into bug reports."
(screen-lines (with-selected-window win
(window-screen-lines)))
(body-rows (window-body-height win))
(rows-match (eql body-rows term-rows))
(frame-ch (frame-char-height))
(default-lh (with-selected-window win
(default-line-height)))
(target-rows (floor screen-lines))
(rows-match (eql target-rows term-rows))
(px-match (eql cur-body-px old-body-px)))
(insert (format "Body rows: %d (window) vs %s (term) %s\n"
body-rows term-rows
(insert (format "screen-lines: %.3f → target %d (term=%s) %s\n"
screen-lines target-rows term-rows
(if rows-match "[in sync]" "[MISMATCH]")))
(insert (format "window-screen-lines: %s\n" screen-lines))
(insert (format "Body rows (frame): %d (window-body-height — frame chars)\n"
body-rows))
(insert (format "Line height: frame=%d px default-face=%d px%s\n"
frame-ch default-lh
(if (eql frame-ch default-lh) ""
" [face-remap or theme bumps height]")))
(insert (format "Body pixels: cur=%d recorded=%d %s\n"
cur-body-px old-body-px
(if px-match "" "[redisplay pending]")))
Expand All @@ -599,8 +610,8 @@ ghostel settings into *ghostel-debug* for pasting into bug reports."
(rows-match
(insert "Diagnosis: in sync\n"))
(px-match
(insert "Diagnosis: Emacs absorbed the chrome change\n")
(insert " but ghostel didn't reconcile (#192)\n"))
(insert "Diagnosis: Emacs absorbed the change but\n")
(insert " ghostel didn't reconcile (#192)\n"))
(t
(insert "Diagnosis: pending redisplay; hooks will fire\n")
(insert " on next paint\n"))))))))
Expand Down
70 changes: 26 additions & 44 deletions lisp/ghostel.el
Original file line number Diff line number Diff line change
Expand Up @@ -3454,7 +3454,8 @@ window (not when it has just been deselected)."
ghostel--term
ghostel--process
(process-live-p ghostel--process))
(let ((height (window-body-height window))
(let ((height (with-selected-window window
(floor (window-screen-lines))))
Comment thread
dakra marked this conversation as resolved.
(width (window-max-chars-per-line window))
(buf (current-buffer)))
(unless (and (eql height ghostel--term-rows)
Expand All @@ -3471,41 +3472,6 @@ window (not when it has just been deselected)."
(setq ghostel--redraw-timer nil))
(let ((ghostel--redraw-resize-active t))
(ghostel--delayed-redraw buf))))))

(defun ghostel--reconcile-display-size (window)
"Reconcile terminal size when this buffer is (re-)displayed in WINDOW.
Buffer migration to a window of a different size produces no
window-size-change event — Emacs's `adjust-window-size-function'
machinery does not fire — but `window-buffer-change-functions' does.
Catch it here and resize libghostty + PTY to match WINDOW.

Intended for buffer-local `window-buffer-change-functions'. The
single-window guard avoids ping-pong if the buffer is shown in two
differently-sized windows simultaneously — that case is handled by
the existing `window-adjust-process-window-size-smallest' path."
(when (and (window-live-p window)
(eq (window-buffer window) (current-buffer))
ghostel--term
ghostel--process
(process-live-p ghostel--process)
(= 1 (length (get-buffer-window-list (current-buffer) nil t))))
(let ((height (window-body-height window))
(width (window-max-chars-per-line window)))
(unless (and (eql height ghostel--term-rows)
(eql width ghostel--term-cols))
(ghostel--set-size ghostel--term (max 1 height) (max 1 width))
(setq ghostel--term-rows height
ghostel--term-cols width
ghostel--force-next-redraw t)
(set-process-window-size ghostel--process
(max 1 height) (max 1 width))
(when ghostel--redraw-timer
(cancel-timer ghostel--redraw-timer)
(setq ghostel--redraw-timer nil))
(let ((ghostel--redraw-resize-active t))
(ghostel--delayed-redraw (current-buffer)))))))



;;; Major mode

Expand Down Expand Up @@ -3543,8 +3509,6 @@ the existing `window-adjust-process-window-size-smallest' path."
#'ghostel--commit-cropped-size nil t)
(add-hook 'window-buffer-change-functions
#'ghostel--reshow-snap nil t)
(add-hook 'window-buffer-change-functions
#'ghostel--reconcile-display-size nil t)
(ghostel--suppress-interfering-modes)
(setq ghostel--scroll-intercept-active t)
;; Let C-g reach the keymap instead of triggering keyboard-quit.
Expand Down Expand Up @@ -3584,17 +3548,31 @@ buffer can be found again after title-tracking renames it."
(defun ghostel--init-buffer (buffer &optional identity)
"Initialize BUFFER as a ghostel terminal if no terminal handle exists yet.
Terminal dimensions come from BUFFER's displayed window when one
exists, otherwise from the selected window. Subsequent migrations
to differently-sized windows are reconciled by
`ghostel--reconcile-display-size' on `window-buffer-change-functions'.
exists, otherwise from the selected window. Height uses
`window-screen-lines' (the metric the standard
`adjust-window-size-function' path also uses), not
`window-body-height'. The former divides the window's pixel height
by the buffer's `default-line-height', which respects
`face-remapping-alist' and `:height' on the default face; the latter
divides by frame char height. When a theme remaps default —
`nano-light' / `nano-dark' do this — the two metrics disagree, and
using `window-body-height' would size the terminal to N rows only to
have the standard adjust-fn immediately resize to N-K, sending a
startup SIGWINCH that some TUI apps (Claude Code's /tui fullscreen)
handle imperfectly (issue #192).
IDENTITY, if given, is stored as `ghostel--buffer-identity' so the
buffer can be found again after title-tracking renames it."
(with-current-buffer buffer
(unless ghostel--term
(ghostel--prepare-buffer buffer identity)
(let* ((w (or (get-buffer-window buffer t) (selected-window)))
(height (if (window-live-p w) (window-body-height w) 24))
(width (if (window-live-p w) (window-max-chars-per-line w) 80)))
(height (max 1 (if (window-live-p w)
(with-selected-window w
(floor (window-screen-lines)))
24)))
(width (max 1 (if (window-live-p w)
(window-max-chars-per-line w)
80))))
Comment thread
dakra marked this conversation as resolved.
(setq ghostel--term
(ghostel--new height width ghostel-max-scrollback))
(setq ghostel--term-rows height)
Expand Down Expand Up @@ -3658,7 +3636,11 @@ Signals `user-error' if BUFFER already has a live ghostel process."
(let ((window (or (get-buffer-window buffer t) (selected-window))))
(with-current-buffer buffer
(ghostel--prepare-buffer buffer nil)
(let* ((height (max 1 (window-body-height window)))
;; Use `window-screen-lines' (not `window-body-height') so the
;; height matches the unit `window-adjust-process-window-size-smallest'
;; uses — see `ghostel--init-buffer' for why.
(let* ((height (max 1 (with-selected-window window
(floor (window-screen-lines)))))
(width (max 1 (window-max-chars-per-line window)))
(remote-p (file-remote-p default-directory)))
(setq ghostel--term
Expand Down
Loading
Loading