@@ -1447,6 +1447,94 @@ for new size inside BSU/ESU → verify buffer shows new content."
14471447 (should-not (string-match-p " OLD-LINE" content)))))
14481448 (kill-buffer buf))))
14491449
1450+ ; ; -----------------------------------------------------------------------
1451+ ; ; Test: resize preserves old frame until redraw replaces it
1452+ ; ; -----------------------------------------------------------------------
1453+
1454+ (ert-deftest ghostel-test-resize-no-blank-flash ()
1455+ " Buffer keeps old content after resize; redraw replaces it atomically.
1456+ Regression test: fnSetSize used to call erase-buffer synchronously,
1457+ leaving the buffer visibly empty until the next timer-driven redraw.
1458+ Now the erasure is deferred into redraw() under inhibit-redisplay."
1459+ (let ((buf (generate-new-buffer " *ghostel-test-resize-no-blank*" )))
1460+ (unwind-protect
1461+ (with-current-buffer buf
1462+ (ghostel-mode)
1463+ (let* ((term (ghostel--new 10 40 100 ))
1464+ (ghostel--term term )
1465+ (ghostel--term-rows 10 )
1466+ (inhibit-read-only t ))
1467+ ; ; Fill the viewport with identifiable content.
1468+ (dotimes (i 10 )
1469+ (ghostel--write-input term (format " LINE-%0 2d\r\n " i)))
1470+ (ghostel--redraw term t )
1471+ (let ((pre-content (buffer-substring-no-properties
1472+ (point-min ) (point-max ))))
1473+ (should (string-match-p " LINE-00" pre-content))
1474+ (should (string-match-p " LINE-09" pre-content))
1475+
1476+ ; ; Resize — old content must survive in the buffer.
1477+ (ghostel--set-size term 6 40 )
1478+ (setq ghostel--term-rows 6 )
1479+ (let ((mid-content (buffer-substring-no-properties
1480+ (point-min ) (point-max ))))
1481+ (should (> (length mid-content) 0 ))
1482+ (should (string-match-p " LINE-" mid-content)))
1483+
1484+ ; ; Redraw rebuilds the buffer from the new terminal state.
1485+ (ghostel--redraw term t )
1486+ (let ((post-content (buffer-substring-no-properties
1487+ (point-min ) (point-max ))))
1488+ (should (> (length post-content) 0 ))
1489+ ; ; Viewport should have the new row count; extra lines
1490+ ; ; above are scrollback from the old viewport rows.
1491+ (should (>= (count-lines (point-min ) (point-max )) 6 ))))))
1492+ (kill-buffer buf))))
1493+
1494+ (ert-deftest ghostel-test-resize-redraw-anchors-window-start ()
1495+ " After resize + redraw, window-start is at the viewport origin.
1496+ Without explicit anchoring, erase+rebuild inside redraw() clamps
1497+ window-start to 1 (top of scrollback), causing a visible jump when
1498+ Emacs auto-scrolls to make point visible."
1499+ (let ((buf (generate-new-buffer " *ghostel-test-resize-anchor*" ))
1500+ (orig-buf (window-buffer (selected-window ))))
1501+ (unwind-protect
1502+ (with-current-buffer buf
1503+ (ghostel-mode)
1504+ (let* ((term (ghostel--new 10 40 200 ))
1505+ (ghostel--term term )
1506+ (ghostel--term-rows 10 )
1507+ (ghostel--force-next-redraw nil )
1508+ (inhibit-read-only t ))
1509+ ; ; Build up scrollback so the viewport is not at buffer start.
1510+ (dotimes (i 30 )
1511+ (ghostel--write-input term (format " scroll-%0 2d\r\n " i)))
1512+ (ghostel--write-input term " prompt> " )
1513+ (ghostel--redraw term t )
1514+ (should (> (line-number-at-pos (point-max )) 10 ))
1515+
1516+ ; ; Display in a real window so we can test window-start.
1517+ (set-window-buffer (selected-window ) buf)
1518+
1519+ ; ; Resize + redraw via delayed-redraw (simulates the real path).
1520+ (ghostel--set-size term 6 40 )
1521+ (setq ghostel--term-rows 6 )
1522+ (setq ghostel--force-next-redraw t )
1523+ (ghostel--delayed-redraw buf)
1524+
1525+ ; ; window-start should be at the viewport, not at buffer start.
1526+ (let* ((ws (window-start (selected-window )))
1527+ (wp (window-point (selected-window )))
1528+ (vp-start (save-excursion
1529+ (goto-char (point-max ))
1530+ (forward-line -5 )
1531+ (line-beginning-position ))))
1532+ (should (= ws vp-start))
1533+ (should (>= wp vp-start)))))
1534+ (when (buffer-live-p orig-buf)
1535+ (set-window-buffer (selected-window ) orig-buf))
1536+ (kill-buffer buf))))
1537+
14501538; ; -----------------------------------------------------------------------
14511539; ; Test: resize with real process — verify PTY and buffer content
14521540; ; -----------------------------------------------------------------------
@@ -2398,12 +2486,12 @@ ncurses apps like htop at start-up size and breaks live resize."
23982486 (let ((ghostel--term 'fake )
23992487 (ghostel--force-next-redraw nil )
24002488 (set-size-args nil )
2401- (invalidate -called nil ))
2489+ (redraw -called nil ))
24022490 (let ((cur-buf (current-buffer )))
24032491 (cl-letf (((symbol-function 'ghostel--set-size )
24042492 (lambda (_term h w ) (setq set-size-args (list h w))))
2405- ((symbol-function 'ghostel--invalidate )
2406- (lambda () (setq invalidate -called t )))
2493+ ((symbol-function 'ghostel--delayed-redraw )
2494+ (lambda (_buf ) (setq redraw -called t )))
24072495 ((symbol-function 'process-buffer )
24082496 (lambda (_proc ) cur-buf))
24092497 ((default-value 'window-adjust-process-window-size-function )
@@ -2413,7 +2501,7 @@ ncurses apps like htop at start-up size and breaks live resize."
24132501 (should (equal '(120 . 40 ) result))
24142502 (should (equal '(40 120 ) set-size-args))
24152503 (should ghostel--force-next-redraw)
2416- (should invalidate -called)))))))
2504+ (should redraw -called)))))))
24172505
24182506(ert-deftest ghostel-test-resize-nil-size ()
24192507 " When default function returns nil, no resize happens."
@@ -2564,7 +2652,7 @@ while :; do sleep 0.1; done'\n")
25642652 (let ((ghostel--term 'fake-term ))
25652653 (cl-letf (((symbol-function 'ghostel--set-size )
25662654 (lambda (_t _h _w ) nil ))
2567- ((symbol-function 'ghostel--invalidate ) #'ignore )
2655+ ((symbol-function 'ghostel--delayed-redraw ) #'ignore )
25682656 ((default-value 'window-adjust-process-window-size-function )
25692657 (lambda (_p _w ) (cons 120 30 ))))
25702658 ; ; Invoke the handler as Emacs would.
0 commit comments