diff --git a/lisp/ghostel.el b/lisp/ghostel.el index 723af301..51cd965b 100644 --- a/lisp/ghostel.el +++ b/lisp/ghostel.el @@ -5197,7 +5197,8 @@ spawn after initialization." DISPLAY-ACTION, when non-nil, is passed to `pop-to-buffer' before terminal creation so size detection observes the window that will display the terminal. Optional ROWS and COLS are passed through to -`ghostel--init-buffer'." +`ghostel--init-buffer'. If initialization is interrupted by an error +or quit, the partially created buffer is killed before re-signaling." (let ((buffer (generate-new-buffer name))) (condition-case err (progn @@ -5209,7 +5210,7 @@ display the terminal. Optional ROWS and COLS are passed through to (pop-to-buffer buffer display-action)) (ghostel--init-buffer buffer rows cols) buffer) - (error + ((error quit) (when (buffer-live-p buffer) (kill-buffer buffer)) (signal (car err) (cdr err)))))) diff --git a/test/ghostel-project-test.el b/test/ghostel-project-test.el index 3a891605..30b66449 100644 --- a/test/ghostel-project-test.el +++ b/test/ghostel-project-test.el @@ -295,6 +295,23 @@ same name must get separate buffers." (when (buffer-live-p buf) (kill-buffer buf))))) +(ert-deftest ghostel-test-create-kills-buffer-on-quit () + "`ghostel--create' kills the partially created buffer on quit. +A keyboard quit can arrive during initialization, e.g. at a dir-locals +prompt in `ghostel-mode'. Uses `condition-case' directly since +`should-error' only traps `error', not `quit'." + (cl-letf (((symbol-function 'ghostel--init-buffer) + (lambda (&rest _) (signal 'quit nil)))) + (unwind-protect + (progn + (should (eq 'quit + (condition-case err + (progn (ghostel--create " *ghostel-test-quit*") nil) + (quit (car err))))) + (should-not (get-buffer " *ghostel-test-quit*"))) + (when-let* ((leftover (get-buffer " *ghostel-test-quit*"))) + (kill-buffer leftover))))) + (ert-deftest ghostel-test-returns-buffer () "`ghostel' returns the (live) Ghostel buffer." (let ((created (generate-new-buffer "*ghostel-return-test*")) diff --git a/test/ghostel-shell-test.el b/test/ghostel-shell-test.el index 1a28acb6..1ea54a76 100644 --- a/test/ghostel-shell-test.el +++ b/test/ghostel-shell-test.el @@ -119,8 +119,8 @@ newest-first list aligns with the buffer-order regions." ;; Send a real command before testing line editing. The initial ;; output may be a terminal query or startup redraw; waiting for ;; command output proves fish's reader is accepting input. Private - ;; mode keeps history/autosuggestions from repainting `abc' after - ;; it has been backspaced to `ab'. + ;; mode keeps history/autosuggestions from repainting `wxyz' after + ;; it has been backspaced to `wxy'. (ghostel--write-pty ghostel--term "printf '%s%s\\n' GHOSTEL_FISH _READY\n") (ghostel-test--wait-until @@ -129,25 +129,30 @@ newest-first list aligns with the buffer-order regions." (ghostel-test--rendered-terminal-text))) proc 10) - ;; Type "abc" then backspace. - (ghostel--write-pty ghostel--term "abc") + ;; Type "wxyz" then backspace. The typed text must + ;; contain letters outside [0-9a-f]: fish's default + ;; prompt shows the checkout's VCS state, and on a + ;; detached HEAD (as in CI) that is the short commit + ;; sha, so a hex-only marker can appear verbatim in + ;; the prompt and never leave the screen. + (ghostel--write-pty ghostel--term "wxyz") (ghostel-test--wait-until (lambda () - (string-match-p "abc" (ghostel-test--rendered-terminal-text))) + (string-match-p "wxyz" (ghostel-test--rendered-terminal-text))) proc 5) - (should (string-match-p "abc" (ghostel-test--rendered-terminal-text))) + (should (string-match-p "wxyz" (ghostel-test--rendered-terminal-text))) ;; Send backspace (\x7f) and verify it works. (ghostel--write-pty ghostel--term "\x7f") (ghostel-test--wait-until (lambda () (let ((state (ghostel-test--rendered-terminal-text))) - (and (string-match-p "ab" state) - (not (string-match-p "abc" state))))) + (and (string-match-p "wxy" state) + (not (string-match-p "wxyz" state))))) proc 5) (let ((state (ghostel-test--rendered-terminal-text))) - (should (string-match-p "ab" state)) - (should-not (string-match-p "abc" state))))))) + (should (string-match-p "wxy" state)) + (should-not (string-match-p "wxyz" state))))))) (ert-deftest ghostel-test-fish-auto-inject-loads-integration () "Fish auto-inject shim chains to ghostel.fish and cleans XDG_DATA_DIRS."