From 1db58baedbc703d49c5fcbf7256fff8a5296caf2 Mon Sep 17 00:00:00 2001 From: Daniel Kraus Date: Tue, 14 Jul 2026 22:17:46 +0200 Subject: [PATCH 1/2] Make evil-ghostel ESC routing discoverable New evil users starting a fullscreen TUI (e.g. Claude Code) felt trapped: with the default auto routing, alt-screen ESC goes to the app, so normal state is unreachable via ESC and nothing pointed at the escape hatch. - Show a one-time echo-area hint the first time auto routing sends ESC to an alt-screen app. - Bind C-c C-r to evil-ghostel-toggle-send-escape and turn it into a two-state toggle: auto flips to whichever mode differs from auto's current effect (evil in alt-screen, terminal otherwise); explicit modes return to auto. Every press now visibly changes the routing. - Show the effective routing in the toggle's message when landing on auto. - Bind C-c to evil-force-normal-state as a one-shot switch that leaves the routing untouched (function-key event: GUI frames, or ttys with the kitty keyboard protocol via kkp.el). - Document ESC routing in the manual, the main README, a new extension README, and the package commentary. Closes #539 --- README.md | 9 +++ README.org | 45 ++++++++++-- extensions/evil-ghostel/README.md | 42 +++++++++++ extensions/evil-ghostel/evil-ghostel.el | 70 +++++++++++++----- test/evil-ghostel-test.el | 95 ++++++++++++++++++++++--- 5 files changed, 230 insertions(+), 31 deletions(-) create mode 100644 extensions/evil-ghostel/README.md diff --git a/README.md b/README.md index 145b2924..66b80a45 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,15 @@ If you're an evil user you can install the [evil-ghostel](https://melpa.org/#/ev :hook (ghostel-mode . evil-ghostel-mode)) ``` +Note: in alt-screen apps — vim, less, fullscreen TUIs like Claude Code +(`/tui fullscreen`) — ESC is by default sent to the app instead of switching +to normal state, so you stay in insert state and a leader key like `SPC` goes +to the terminal too (`M-x`, `C-x …`, `C-c …` still work). Toggle the routing +with `C-c C-r` (`evil-ghostel-toggle-send-escape`), or hit `C-c ESC` for a +one-shot switch to normal state; `evil-ghostel-escape` sets the default +routing. See [Evil-mode](https://dakra.github.io/ghostel/#evil-mode) +in the manual. + ## Shell integration Directory tracking and prompt navigation are on by default for local bash, zsh, fish or nushell sessions. diff --git a/README.org b/README.org index f204e900..12daf8f8 100644 --- a/README.org +++ b/README.org @@ -1403,7 +1403,8 @@ subdirectory inside the ghostel monorepo: When =evil-ghostel-mode= is active: - Ghostel starts in *insert state* (terminal input works normally). -- Pressing *ESC* enters normal state and snaps point to the terminal cursor. +- Pressing *ESC* enters normal state and snaps point to the terminal cursor + (outside alt-screen; see [[#evil-escape-routing][ESC routing]] below). - Normal-mode navigation (=h=, =j=, =k=, =l=, =w=, =b=, =e=, =0=, =$=, ...) works as expected. - *Insert/append* (=i=, =a=, =I=, =A=) sync the terminal cursor to point before entering insert state. @@ -1414,11 +1415,45 @@ When =evil-ghostel-mode= is active: - *Paste* (=p=, =P=) pastes from the kill ring via bracketed paste. - *Undo* (=u=) sends readline undo (=Ctrl+_=). - Cursor shape follows evil state (block for normal, bar for insert). -- Alt-screen programs (vim, less, htop) are unaffected. +- Alt-screen programs (vim, less, htop) are unaffected: ESC goes to the app + (see below). -The initial state and the ESC behavior are configurable via -=evil-ghostel-initial-state= (default =insert=) and =evil-ghostel-escape= (default -=auto=). +The initial state is configurable via =evil-ghostel-initial-state= (default +=insert=). + +*** ESC routing +:properties: +:custom_id: evil-escape-routing +:end: +#+cindex: escape routing + +Where insert-state ESC goes is controlled by =evil-ghostel-escape=: + +- =auto= (default) :: to the terminal while an alt-screen app runs (DECSET + 1049: vim, less, htop, fullscreen TUIs like Claude Code); otherwise evil's + binding switches to normal state. +- =terminal= :: always to the terminal. +- =evil= :: always run evil's binding. + +The =auto= default keeps ESC working inside vim and friends, but it also +means that while a fullscreen TUI such as OpenCode (=/tui fullscreen=) +runs, ESC does /not/ enter normal state — you stay in insert state, and a +leader key like =SPC= goes to the terminal too. Regular Emacs bindings +(=M-x=, =C-x ...=, =C-c ...=) keep working. The first time ESC is routed to +an alt-screen app this way, a one-time hint in the echo area points at the +toggle command. + +=C-c C-r= (=evil-ghostel-toggle-send-escape=) toggles the routing for the +current buffer: from =auto= it switches to whichever mode differs from +auto's current effect (=evil= while an alt-screen app runs, =terminal= +otherwise), and from an explicit mode back to =auto=. Numeric prefixes +1/2/3 set =auto=/=terminal=/=evil= directly. + +=C-c ESC= (=evil-force-normal-state=) switches to normal state once without +changing the routing — useful to scroll or copy while the TUI keeps ESC. +The binding is on the == function key, which exists on GUI frames +and, on a tty, in terminals speaking the kitty keyboard protocol with +[[https://github.com/benjaminor/kkp][kkp.el]] enabled; on a legacy tty use =M-x evil-force-normal-state=. ** Compilation mode :properties: diff --git a/extensions/evil-ghostel/README.md b/extensions/evil-ghostel/README.md new file mode 100644 index 00000000..3f8c5e64 --- /dev/null +++ b/extensions/evil-ghostel/README.md @@ -0,0 +1,42 @@ +# evil-ghostel + +[Evil-mode](https://github.com/emacs-evil/evil) integration for the +[ghostel](https://github.com/dakra/ghostel) terminal emulator, modeled on +`evil-collection-vterm`. + +Install from [MELPA](https://melpa.org/#/evil-ghostel): + +```emacs-lisp +(use-package evil-ghostel + :after (ghostel evil) + :hook (ghostel-mode . evil-ghostel-mode)) +``` + +When `evil-ghostel-mode` is active, ghostel buffers start in insert state, +ESC enters normal state, normal-state motions work over the rendered +terminal, and the editing operators (`d`, `c`, `x`, `r`, `p`, `u`, …) drive +the shell's line editor over the PTY. See the +[manual](https://dakra.github.io/ghostel/#evil-mode) for the full list. + +## ESC in fullscreen apps + +In alt-screen apps — vim, less, and fullscreen TUIs like Claude Code +(`/tui fullscreen`) — insert-state ESC is by default routed to the app +instead of switching to normal state, so the app keeps its ESC key. This +means you stay in insert state while such an app runs: a leader key like +`SPC` goes to the terminal too. Regular Emacs bindings (`M-x`, `C-x …`, +`C-c …`) still work. + +To get ESC back for evil, toggle the per-buffer routing with `C-c C-r` +(`evil-ghostel-toggle-send-escape`): from `auto` it switches to whichever +mode differs from auto's current effect (`evil` while an alt-screen app +runs, `terminal` otherwise), and from an explicit mode back to `auto`; +numeric prefixes 1/2/3 set auto/terminal/evil directly. The default comes +from the `evil-ghostel-escape` option (`auto`, `terminal`, or `evil`). + +To switch to normal state just once — without changing the routing — use +`C-c ESC` (`evil-force-normal-state`). This binding uses the `` +function key, so it works on GUI frames and, on a tty, in terminals +speaking the kitty keyboard protocol with +[kkp.el](https://github.com/benjaminor/kkp) enabled; `M-x +evil-force-normal-state` works everywhere. diff --git a/extensions/evil-ghostel/evil-ghostel.el b/extensions/evil-ghostel/evil-ghostel.el index 70dc1438..db86b7ea 100644 --- a/extensions/evil-ghostel/evil-ghostel.el +++ b/extensions/evil-ghostel/evil-ghostel.el @@ -27,6 +27,14 @@ ;; Outside semi-char input mode (`line' / `copy' / `emacs' / `char' modes, ;; or an alt-screen TUI) every command falls through to `evil-*'. ;; +;; In alt-screen apps (vim, less, fullscreen TUIs like Claude Code) +;; insert-state ESC is by default routed to the app instead of switching +;; to normal state, so the app keeps its ESC key. `C-c C-r' +;; (`evil-ghostel-toggle-send-escape') toggles the routing per buffer; +;; the `evil-ghostel-escape' option sets the default. `C-c ' +;; switches to normal state once without changing the routing (GUI +;; frames; on a tty it needs the kitty keyboard protocol via kkp.el). +;; ;; Enable by adding to your init: ;; ;; (use-package evil-ghostel @@ -87,6 +95,10 @@ Each iteration waits up to 50 ms, bounding the total wait at ~500 ms." ;; Guard predicates +(defun evil-ghostel--alt-screen-p () + "Return non-nil when the terminal is in alt-screen mode (DECSET 1049)." + (and ghostel--term (ghostel--mode-enabled ghostel--term 1049))) + (defun evil-ghostel--active-p () "Return non-nil when evil-ghostel PTY routing should intercept. True in `semi-char' input mode and outside alt-screen — the only state in @@ -808,8 +820,11 @@ rather than forward-delete in the shell." Initialized from `evil-ghostel-escape' when the minor mode turns on. Valid values: `auto', `terminal', `evil'.") +(defvar evil-ghostel--escape-hint-shown nil + "Non-nil after the one-time hint about ESC routing has been shown.") + (defconst evil-ghostel--escape-modes '(auto terminal evil) - "Cycle order for `evil-ghostel-toggle-send-escape'.") + "Prefix-argument order (1/2/3) for `evil-ghostel-toggle-send-escape'.") (defun evil-ghostel--escape () "Dispatch insert-state ESC based on `evil-ghostel--escape-mode'. @@ -821,37 +836,56 @@ keystroke is never dropped." (let* ((mode evil-ghostel--escape-mode) (to-terminal (or (eq mode 'terminal) (and (eq mode 'auto) - ghostel--term - (ghostel--mode-enabled ghostel--term 1049))))) + (evil-ghostel--alt-screen-p))))) (if to-terminal (progn (ghostel--on-user-input) - (ghostel--send-encoded "escape" "")) + (ghostel--send-encoded "escape" "") + (when (and (eq mode 'auto) (not evil-ghostel--escape-hint-shown)) + (setq evil-ghostel--escape-hint-shown t) + (message (substitute-command-keys + "ESC sent to the terminal app (alt-screen); \ +\\[evil-ghostel-toggle-send-escape] routes it to evil instead")))) (let ((cmd (lookup-key evil-insert-state-map (kbd "")))) (call-interactively (if (commandp cmd) cmd #'evil-force-normal-state)))))) (defun evil-ghostel-toggle-send-escape (&optional arg) - "Cycle or set the ESC routing mode for the current buffer. -Without ARG, cycle `auto' → `terminal' → `evil'. With numeric prefix 1/2/3 -set `auto'/`terminal'/`evil'; other prefixes signal a `user-error'. The -mode is buffer-local; see `evil-ghostel-escape' for the default." + "Toggle or set the ESC routing mode for the current buffer. +Without ARG, toggle: from `auto' switch to whichever mode differs from +auto's current effect (`evil' while an alt-screen app runs, `terminal' +otherwise); from an explicit mode switch back to `auto'. With numeric +prefix 1/2/3 set `auto'/`terminal'/`evil'; other prefixes signal a +`user-error'. The mode is buffer-local; see `evil-ghostel-escape' for +the default." (interactive "P") (let ((target - (if arg - (let ((n (prefix-numeric-value arg))) - (or (nth (1- n) evil-ghostel--escape-modes) - (user-error - "Invalid prefix %d; use 1 (auto), 2 (terminal), or 3 (evil)" - n))) - (let ((next (cdr (memq evil-ghostel--escape-mode - evil-ghostel--escape-modes)))) - (or (car next) (car evil-ghostel--escape-modes)))))) + (cond (arg + (let ((n (prefix-numeric-value arg))) + (or (nth (1- n) evil-ghostel--escape-modes) + (user-error + "Invalid prefix %d; use 1 (auto), 2 (terminal), or 3 (evil)" + n)))) + ((eq evil-ghostel--escape-mode 'auto) + (if (evil-ghostel--alt-screen-p) 'evil 'terminal)) + (t 'auto)))) (setq evil-ghostel--escape-mode target) - (message "evil-ghostel ESC mode: %s" target))) + (if (eq target 'auto) + (message "evil-ghostel ESC mode: auto (now → %s)" + (if (evil-ghostel--alt-screen-p) 'terminal 'evil)) + (message "evil-ghostel ESC mode: %s" target)))) (evil-define-key* 'insert evil-ghostel-mode-map (kbd "") #'evil-ghostel--escape) +(define-key evil-ghostel-mode-map (kbd "C-c C-r") + #'evil-ghostel-toggle-send-escape) + +;; The function-key event exists on GUI frames and on ttys with +;; the kitty keyboard protocol (kkp.el); legacy ttys never generate it, +;; so this binding cannot shadow the ESC-prefixed C-c M-... keys there. +(define-key evil-ghostel-mode-map (kbd "C-c ") + #'evil-force-normal-state) + ;; Minor mode diff --git a/test/evil-ghostel-test.el b/test/evil-ghostel-test.el index 895b3c6c..a7b94d9d 100644 --- a/test/evil-ghostel-test.el +++ b/test/evil-ghostel-test.el @@ -1788,16 +1788,31 @@ and with `ghostel--send-encoded' captured into the local list `sent'." (should-not (member '("escape" . "") sent)) (should-not (eq evil-state 'insert))))) -(ert-deftest evil-ghostel-test-escape-toggle-cycle () - "Calling toggle without a prefix cycles auto → terminal → evil → auto." +(ert-deftest evil-ghostel-test-escape-toggle-altscreen () + "In alt-screen the toggle flips auto ↔ evil; explicit modes go to auto." (evil-ghostel-test--with-evil-buffer (setq evil-ghostel--escape-mode 'auto) - (evil-ghostel-toggle-send-escape) - (should (eq 'terminal evil-ghostel--escape-mode)) - (evil-ghostel-toggle-send-escape) - (should (eq 'evil evil-ghostel--escape-mode)) - (evil-ghostel-toggle-send-escape) - (should (eq 'auto evil-ghostel--escape-mode)))) + (evil-ghostel-test--with-escape-stubs t + (evil-ghostel-toggle-send-escape) + (should (eq 'evil evil-ghostel--escape-mode)) + (evil-ghostel-toggle-send-escape) + (should (eq 'auto evil-ghostel--escape-mode)) + (setq evil-ghostel--escape-mode 'terminal) + (evil-ghostel-toggle-send-escape) + (should (eq 'auto evil-ghostel--escape-mode))))) + +(ert-deftest evil-ghostel-test-escape-toggle-no-altscreen () + "Outside alt-screen the toggle flips auto ↔ terminal; evil goes to auto." + (evil-ghostel-test--with-evil-buffer + (setq evil-ghostel--escape-mode 'auto) + (evil-ghostel-test--with-escape-stubs nil + (evil-ghostel-toggle-send-escape) + (should (eq 'terminal evil-ghostel--escape-mode)) + (evil-ghostel-toggle-send-escape) + (should (eq 'auto evil-ghostel--escape-mode)) + (setq evil-ghostel--escape-mode 'evil) + (evil-ghostel-toggle-send-escape) + (should (eq 'auto evil-ghostel--escape-mode))))) (ert-deftest evil-ghostel-test-escape-toggle-prefix-set () "Numeric prefix sets the mode directly: 1=auto, 2=terminal, 3=evil." @@ -1841,6 +1856,70 @@ and with `ghostel--send-encoded' captured into the local list `sent'." (kill-buffer buf-a) (kill-buffer buf-b)))) +(defmacro evil-ghostel-test--with-captured-messages (var &rest body) + "Run BODY with `message' output collected into the local list VAR." + (declare (indent 1) (debug t)) + `(let ((,var '())) + (cl-letf (((symbol-function 'message) + (lambda (fmt &rest args) + (when fmt (push (apply #'format fmt args) ,var))))) + ,@body))) + +(ert-deftest evil-ghostel-test-escape-hint-shown-once () + "The first auto-routed ESC shows the routing hint; later ones don't." + (evil-ghostel-test--with-evil-buffer + (setq evil-ghostel--escape-mode 'auto) + (let ((evil-ghostel--escape-hint-shown nil)) + (evil-ghostel-test--with-escape-stubs t + (evil-ghostel-test--with-captured-messages messages + (evil-ghostel--escape) + (evil-ghostel--escape) + (should (= 2 (length sent))) + (should evil-ghostel--escape-hint-shown) + (should (= 1 (cl-count-if + (lambda (m) (string-match-p "ESC sent to the" m)) + messages)))))))) + +(ert-deftest evil-ghostel-test-escape-hint-only-in-auto-mode () + "Explicit `terminal' routing and evil routing never show the hint." + (let ((evil-ghostel--escape-hint-shown nil)) + (evil-ghostel-test--with-evil-buffer + (setq evil-ghostel--escape-mode 'terminal) + (evil-ghostel-test--with-escape-stubs t + (evil-ghostel--escape))) + (evil-ghostel-test--with-evil-buffer + (setq evil-ghostel--escape-mode 'auto) + (evil-insert-state) + (evil-ghostel-test--with-escape-stubs nil + (evil-ghostel--escape))) + (should-not evil-ghostel--escape-hint-shown))) + +(ert-deftest evil-ghostel-test-escape-toggle-message-shows-effect () + "Setting `auto' messages where ESC currently goes." + (evil-ghostel-test--with-evil-buffer + (evil-ghostel-test--with-escape-stubs t + (evil-ghostel-test--with-captured-messages messages + (evil-ghostel-toggle-send-escape 1) + (should (string-match-p "auto (now → terminal)" (car messages))))) + (evil-ghostel-test--with-escape-stubs nil + (evil-ghostel-test--with-captured-messages messages + (evil-ghostel-toggle-send-escape 1) + (should (string-match-p "auto (now → evil)" (car messages))))))) + +(ert-deftest evil-ghostel-test-escape-toggle-keybinding () + "C-c C-r is bound to the toggle in `evil-ghostel-mode-map'." + (should (eq #'evil-ghostel-toggle-send-escape + (lookup-key evil-ghostel-mode-map (kbd "C-c C-r"))))) + +(ert-deftest evil-ghostel-test-escape-one-shot-keybinding () + "C-c gives a one-shot switch to normal state. +The binding must be on the function key, never the ESC +character: `C-c ESC' as a char sequence would shadow the C-c M-... +bindings on a tty." + (should (eq #'evil-force-normal-state + (lookup-key evil-ghostel-mode-map (kbd "C-c ")))) + (should-not (lookup-key evil-ghostel-mode-map (kbd "C-c ESC")))) + (ert-deftest evil-ghostel-test-escape-evil-fallback-when-lookup-nil () "When `lookup-key' yields no command (user rebound ESC to a chord prefix), the dispatcher must fall back to `evil-force-normal-state' From 4de27ab5b535503d9b5b9e0644fd13e5dec07c37 Mon Sep 17 00:00:00 2001 From: Daniel Kraus Date: Tue, 14 Jul 2026 22:37:45 +0200 Subject: [PATCH 2/2] Unify alt-screen detection behind a public ghostel-alt-screen-p MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three different alt-screen checks existed: the native ghostel--alt-screen-p (reads the active screen), line-mode's 1049-or-1047 mode query, and evil-ghostel's 1049-only query. The mode queries miss alt screens entered via other DEC modes (47, 1047) — e.g. evil-ghostel's auto ESC routing kept ESC in evil for a TUI using 1047. Add ghostel-alt-screen-p, a public wrapper around the native check, and use it for line-mode pause/resume and all evil-ghostel alt-screen decisions. Tests stub the native ghostel--alt-screen-p instead of ghostel--mode-enabled. Also give the extension .elc rule a dependency on the core .elc files so a parallel build cannot compile evil-ghostel against a stale ghostel.elc that predates a newly added core function. --- Makefile | 5 +- README.org | 2 +- extensions/evil-ghostel/evil-ghostel.el | 24 ++--- lisp/ghostel-line-mode.el | 20 ++-- lisp/ghostel.el | 7 +- test/evil-ghostel-test.el | 122 +++++++++++----------- test/ghostel-line-mode-test.el | 132 +++++++++++------------- test/ghostel-line-mode-undo-test.el | 2 +- 8 files changed, 152 insertions(+), 162 deletions(-) diff --git a/Makefile b/Makefile index 8e3d4308..4cdb4a6e 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,10 @@ lisp/%.elc: lisp/%.el $(EVIL_DIR): git clone --depth 1 https://github.com/emacs-evil/evil.git "$@" -extensions/evil-ghostel/%.elc: extensions/evil-ghostel/%.el | $(EVIL_DIR) +# Depend on the core .elc files: `require' prefers a stale core .elc over +# the fresh .el, so a parallel build could otherwise compile the extension +# before a core function it uses exists in the loaded bytecode. +extensions/evil-ghostel/%.elc: extensions/evil-ghostel/%.el $(filter lisp/%.elc,$(ELC)) | $(EVIL_DIR) $(EMACS) --batch $(EMACSFLAGS) -Q -L "$(EVIL_DIR)" -L lisp -L extensions/evil-ghostel \ --eval "(setq byte-compile-error-on-warn t)" -f batch-byte-compile $< diff --git a/README.org b/README.org index 12daf8f8..d3ced9b1 100644 --- a/README.org +++ b/README.org @@ -1430,7 +1430,7 @@ The initial state is configurable via =evil-ghostel-initial-state= (default Where insert-state ESC goes is controlled by =evil-ghostel-escape=: - =auto= (default) :: to the terminal while an alt-screen app runs (DECSET - 1049: vim, less, htop, fullscreen TUIs like Claude Code); otherwise evil's + 1049: vim, less, htop, fullscreen TUIs like OpenCode); otherwise evil's binding switches to normal state. - =terminal= :: always to the terminal. - =evil= :: always run evil's binding. diff --git a/extensions/evil-ghostel/evil-ghostel.el b/extensions/evil-ghostel/evil-ghostel.el index db86b7ea..c72b6383 100644 --- a/extensions/evil-ghostel/evil-ghostel.el +++ b/extensions/evil-ghostel/evil-ghostel.el @@ -46,7 +46,7 @@ (require 'evil) (require 'ghostel) -(declare-function ghostel--mode-enabled "ghostel-module") +(declare-function ghostel--alt-screen-p "ghostel-module") (defvar evil-ghostel-mode) @@ -73,8 +73,8 @@ change immediately through `evil-set-initial-state'." (defcustom evil-ghostel-escape 'auto "Where insert-state ESC is routed in ghostel buffers. -`auto' - to the terminal in alt-screen mode (DECSET 1049: vim, less, - htop, …); otherwise evil's binding switches to normal state. +`auto' - to the terminal in alt-screen mode (vim, less, htop, …); + otherwise evil's binding switches to normal state. `terminal' - always send ESC to the terminal. `evil' - always run evil's binding. @@ -95,17 +95,13 @@ Each iteration waits up to 50 ms, bounding the total wait at ~500 ms." ;; Guard predicates -(defun evil-ghostel--alt-screen-p () - "Return non-nil when the terminal is in alt-screen mode (DECSET 1049)." - (and ghostel--term (ghostel--mode-enabled ghostel--term 1049))) - (defun evil-ghostel--active-p () "Return non-nil when evil-ghostel PTY routing should intercept. True in `semi-char' input mode and outside alt-screen — the only state in which `evil-ghostel-*' commands send PTY keys rather than running `evil-*'." (and evil-ghostel-mode ghostel--term - (not (ghostel--mode-enabled ghostel--term 1049)) + (not (ghostel-alt-screen-p)) (eq ghostel--input-mode 'semi-char))) (defun evil-ghostel--ctrl-passthrough-active-p () @@ -161,9 +157,9 @@ No window showing the buffer counts as following." (defun evil-ghostel--around-redraw (orig-fn term &optional full force-sync) "Apply Evil point/visual handling around `ghostel--redraw'. ORIG-FN is the advised function (TERM, FULL, FORCE-SYNC). Skipped in -alt-screen (1049) and when the native renderer defers synchronized output." +alt-screen and when the native renderer defers synchronized output." (if (and evil-ghostel-mode - (not (ghostel--mode-enabled term 1049))) + (not (ghostel--alt-screen-p term))) (let* ((visual-p (eq evil-state 'visual)) ;; Sampled pre-render (window check included): only then does ;; point on the cursor's row mean the user has not left the @@ -226,7 +222,7 @@ evil state with point off the cursor, unless FORCE." ORIG-FN is the advised setter (STYLE, VISIBLE); deferred to in alt-screen." (if (and evil-ghostel-mode ghostel--term - (not (ghostel--mode-enabled ghostel--term 1049))) + (not (ghostel-alt-screen-p))) ;; Evil owns the cursor now; end any terminal-driven blink that a ;; full-screen app left running before we exited the alt-screen. (progn (ghostel--cursor-blink-stop) @@ -836,7 +832,7 @@ keystroke is never dropped." (let* ((mode evil-ghostel--escape-mode) (to-terminal (or (eq mode 'terminal) (and (eq mode 'auto) - (evil-ghostel--alt-screen-p))))) + (ghostel-alt-screen-p))))) (if to-terminal (progn (ghostel--on-user-input) @@ -866,12 +862,12 @@ the default." "Invalid prefix %d; use 1 (auto), 2 (terminal), or 3 (evil)" n)))) ((eq evil-ghostel--escape-mode 'auto) - (if (evil-ghostel--alt-screen-p) 'evil 'terminal)) + (if (ghostel-alt-screen-p) 'evil 'terminal)) (t 'auto)))) (setq evil-ghostel--escape-mode target) (if (eq target 'auto) (message "evil-ghostel ESC mode: auto (now → %s)" - (if (evil-ghostel--alt-screen-p) 'terminal 'evil)) + (if (ghostel-alt-screen-p) 'terminal 'evil)) (message "evil-ghostel ESC mode: %s" target)))) (evil-define-key* 'insert evil-ghostel-mode-map diff --git a/lisp/ghostel-line-mode.el b/lisp/ghostel-line-mode.el index cf4bdb3c..9dd04fd5 100644 --- a/lisp/ghostel-line-mode.el +++ b/lisp/ghostel-line-mode.el @@ -22,7 +22,6 @@ (declare-function ghostel--ensure-ghostel-buffer "ghostel") (declare-function ghostel--invalidate "ghostel") (declare-function ghostel--leave-readonly-state "ghostel") -(declare-function ghostel--mode-enabled "ghostel-module") (declare-function ghostel--mode-line-refresh "ghostel") (declare-function ghostel--mode-line-tag-make "ghostel") (declare-function ghostel--open-link "ghostel") @@ -32,6 +31,7 @@ (declare-function ghostel--send-encoded "ghostel") (declare-function ghostel--uri-at-pos "ghostel") (declare-function ghostel--write-pty "ghostel-module") +(declare-function ghostel-alt-screen-p "ghostel") (declare-function ghostel-beginning-of-input-or-line "ghostel") (declare-function ghostel-input-start-point "ghostel") (declare-function bash-completion-capf-nonexclusive "bash-completion") @@ -230,14 +230,6 @@ read-only scrollback portion, mirroring `ghostel-line-mode-self-insert'." (goto-char end))) (insert "\n")) -(defun ghostel--line-mode-alt-screen-p () - "Return non-nil if libghostty is on its alternate screen. -Checks DEC private modes 1049 and 1047 (the modern alt-screen -modes used by less, htop, vim, etc.)." - (and ghostel--term - (or (ghostel--mode-enabled ghostel--term 1049) - (ghostel--mode-enabled ghostel--term 1047)))) - (defun ghostel--line-mode-prompt-on-screen-p () "Return non-nil when a real OSC 133 prompt char sits on the cursor's row. Only a `ghostel-prompt' property counts (no regex or cursor fallback), @@ -428,7 +420,7 @@ in line mode (the interactive entry validates these)." (setq ghostel--char-mode-override-active nil) ;; A deliberate alt-screen entry must survive the next redraw's ;; auto-pause, and supersedes any armed sentinel. - (setq ghostel--line-mode-on-alt-screen (ghostel--line-mode-alt-screen-p)) + (setq ghostel--line-mode-on-alt-screen (ghostel-alt-screen-p)) (setq ghostel--line-mode-paused nil) (setq ghostel--input-mode 'line) (use-local-map ghostel-line-mode-map) @@ -487,12 +479,12 @@ when the TUI exits. A prefix arg FORCE forces immediate entry." (message "Line mode: RET sends the whole line; C-c C-j to exit") (user-error "Line mode could not locate the cursor or a prompt"))) ;; Alt screen with a real prompt on the cursor row (inner shell) — enter. - ((and (ghostel--line-mode-alt-screen-p) + ((and (ghostel-alt-screen-p) (ghostel--line-mode-prompt-on-screen-p) (ghostel--line-mode-enter)) (message "Line mode: RET sends the whole line; C-c C-j to exit")) ;; Alt screen, no detectable prompt (raw TUI) — arm instead. - ((ghostel--line-mode-alt-screen-p) + ((ghostel-alt-screen-p) (ghostel--line-mode-defer-entry)) ;; Primary screen — normal entry. ((ghostel--line-mode-enter) @@ -646,7 +638,7 @@ overwrites the buffer. A deliberate alt-screen entry \(`ghostel--line-mode-on-alt-screen') is exempt; the flag clears once the alt screen goes away so a later TUI pauses normally." (when (eq ghostel--input-mode 'line) - (if (ghostel--line-mode-alt-screen-p) + (if (ghostel-alt-screen-p) (unless ghostel--line-mode-on-alt-screen (ghostel--line-mode-pause)) ;; Back on the primary screen — re-arm the pause for the next TUI. @@ -662,7 +654,7 @@ new prompt one or more redraws after libghostty leaves the alt screen. Also drives the deferred startup entry when `ghostel-initial-input-mode' is `line'." (when (and ghostel--line-mode-paused - (not (ghostel--line-mode-alt-screen-p))) + (not (ghostel-alt-screen-p))) (ghostel--line-mode-try-resume)) (ghostel--line-mode-maybe-enter-initial)) diff --git a/lisp/ghostel.el b/lisp/ghostel.el index 8d0287fd..8856a498 100644 --- a/lisp/ghostel.el +++ b/lisp/ghostel.el @@ -1151,7 +1151,6 @@ is non-nil." (unless (memq 'ghostel--emulation-alist emulation-mode-map-alists) (push 'ghostel--emulation-alist emulation-mode-map-alists)) - ;;; Input mode predicates @@ -1174,7 +1173,13 @@ across the rewrite." "Non-nil when the terminal is frozen (copy mode)." (eq ghostel--input-mode 'copy)) +(defun ghostel-alt-screen-p () + "Return non-nil when the terminal is on its alternate screen. +True while a fullscreen TUI (vim, less, htop, …) runs, regardless of +which DEC mode (47, 1047, or 1049) it used to get there." + (and ghostel--term (ghostel--alt-screen-p ghostel--term))) + ;;; Keymap (defun ghostel--define-terminal-keys (map &optional no-exceptions) diff --git a/test/evil-ghostel-test.el b/test/evil-ghostel-test.el index a7b94d9d..27bbf6b2 100644 --- a/test/evil-ghostel-test.el +++ b/test/evil-ghostel-test.el @@ -250,8 +250,8 @@ The mock erases and reinserts the same text so these tests exercise (erase-buffer) (insert text) t))) - ((symbol-function 'ghostel--mode-enabled) - (lambda (_term _mode) nil))) + ((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) nil))) ,@body)) (ert-deftest evil-ghostel-test-around-redraw-does-not-restore-normal-point () @@ -268,8 +268,8 @@ The mock erases and reinserts the same text so these tests exercise (lambda (_term &optional _full _force-sync) (goto-char renderer-point) t)) - ((symbol-function 'ghostel--mode-enabled) - (lambda (_term _mode) nil))) + ((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) nil))) (evil-ghostel--around-redraw (symbol-function 'ghostel--redraw) nil)) (should (= renderer-point (point)))))) @@ -284,8 +284,8 @@ The mock appends rows below, advances the cursor to the new prompt at (evil-ghostel-test--insert "\nout-1\nout-2\n$ ")) (setq ghostel--cursor-char-pos (point-max) ghostel--cursor-pos '(2 . 5)))) - ((symbol-function 'ghostel--mode-enabled) - (lambda (_term _mode) nil))) + ((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) nil))) (evil-ghostel--around-redraw (symbol-function 'ghostel--redraw) 'fake))) (ert-deftest evil-ghostel-test-around-redraw-tracks-parked-normal-point () @@ -346,8 +346,8 @@ snapping to the cursor or stranding in scrollback." (goto-char (point-min)) (search-forward "five") (cl-letf (((symbol-function 'ghostel--redraw) (lambda (&rest _) t)) - ((symbol-function 'ghostel--mode-enabled) - (lambda (_term _mode) nil))) + ((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) nil))) (evil-ghostel--around-redraw (symbol-function 'ghostel--redraw) 'fake)) (should (= 3 (line-number-at-pos))) (should (= 0 (current-column))))) @@ -375,8 +375,8 @@ snapping to the cursor or stranding in scrollback." (evil-ghostel-test--with-evil-buffer (let ((evil-state 'insert) reset-called) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term _mode) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) nil)) ((symbol-function 'evil-ghostel--reset-cursor-point) (lambda () (setq reset-called t)))) (should-not @@ -400,8 +400,8 @@ advice must not restore point or visual markers there." (insert text) (goto-char (point-min)) t))) - ((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049)))) + ((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t))) (evil-ghostel--around-redraw (symbol-function 'ghostel--redraw) nil)) ;; Advice bypassed → the mock's point placement (point-min) wins. (should (= (point-min) (point))))) @@ -430,7 +430,7 @@ it still snaps point to the cursor." (setq ghostel--cursor-char-pos (point)) ;; Viewport-relative cursor: last row, column past the prompt. (setq ghostel--cursor-pos (cons (current-column) (1- ghostel--term-rows))) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) ;; Bind `evil-state' directly: entering insert via ;; `evil-insert-state' would fire entry hooks that touch the @@ -467,7 +467,7 @@ insert state. Inert (never vetoes) when not active, e.g. in alt-screen." (setq-local ghostel--cursor-char-pos (point)) (let ((off (point-min))) ;; Active: semi-char input mode, not alt-screen. - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (let ((evil-state 'normal)) ;; Normal state, point off the cursor: veto, unless FORCE. @@ -483,7 +483,7 @@ insert state. Inert (never vetoes) when not active, e.g. in alt-screen." (should-not (evil-ghostel--anchor-inhibit nil nil)))) ;; Not active (alt-screen): ghostel owns the anchor, never vetoed even ;; while roaming off the cursor in a motion state. - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) t))) (let ((evil-state 'normal)) (goto-char off) @@ -792,7 +792,7 @@ The command calls `evil-ghostel-goto-input-position' which moves the terminal cursor to point's buffer position." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0))) (evil-normal-state) (let ((sync-called nil)) @@ -806,7 +806,7 @@ terminal cursor to point's buffer position." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) (insert "hello") - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(5 . 0))) (evil-normal-state) (goto-char (point-min)) @@ -834,7 +834,7 @@ stays on `d'. The guard skips the +1 step when point is at or past (insert "word") (insert (make-string 10 ?\s)) (insert "rprompt")) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ;; Isolate target-computation from PTY mechanics: simulate ;; goto-input-position's net effect on point. ((symbol-function 'evil-ghostel-goto-input-position) @@ -862,7 +862,7 @@ through when the cell at the cursor is non-blank typed text." ;; (end of input) back to pos 2 (on `i'). Now they press `' ;; then `a' — the cursor is at pos 2, the same as point. (insert "hi") - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'evil-ghostel-goto-input-position) (lambda (pos &rest _) (goto-char pos) t)) ((symbol-function 'evil-ghostel--insert-state-entry) #'ignore) @@ -884,7 +884,7 @@ still advance by one cell (vim semantics)." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) (insert "hello world") - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'evil-ghostel-goto-input-position) (lambda (pos &rest _) (goto-char pos) t)) ((symbol-function 'evil-ghostel--insert-state-entry) #'ignore) @@ -977,7 +977,7 @@ arrows are sent (which the old `sync-inhibit' path mistakenly did)." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) (insert "line one\nline two\nline three") - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(10 . 2))) (evil-normal-state) (goto-char (point-min)) @@ -1064,7 +1064,7 @@ without a real native module." (setq ghostel--cursor-pos (cons (current-column) 0)) (evil-local-mode 1) (evil-ghostel-mode 1) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) ,@body)) (kill-buffer buf)))) @@ -1112,7 +1112,7 @@ on and the terminal mocked." (setq ghostel--term-rows 1) (evil-local-mode 1) (evil-ghostel-mode 1) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) ,@body)) (kill-buffer buf)))) @@ -1257,7 +1257,7 @@ bounds total wait at ~max-iter × 50 ms." (setq-local ghostel--term t) (insert "hello world") (goto-char (point-min)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0)) ((symbol-function 'evil-ghostel-goto-input-position) #'ignore)) (evil-normal-state) @@ -1283,7 +1283,7 @@ shortcut is invoked." (insert "hello")) (setq-local ghostel--cursor-pos '(7 . 0)) (setq-local ghostel--cursor-char-pos 8) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (evil-normal-state) (let ((keys-sent '())) (cl-letf (((symbol-function 'ghostel--send-encoded) @@ -1308,7 +1308,7 @@ then enters insert state. Same vterm-style shape as `dd'." (insert "hello")) (setq-local ghostel--cursor-pos '(7 . 0)) (setq-local ghostel--cursor-char-pos 8) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (evil-normal-state) (let ((keys-sent '())) (cl-letf (((symbol-function 'ghostel--send-encoded) @@ -1336,7 +1336,7 @@ line)." (setq-local ghostel--term t) (insert "line one\nline two\nline three") ;; Terminal cursor reported at end of line three (col 10, row 2) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(10 . 2))) (evil-normal-state) (goto-char (point-min)) @@ -1360,7 +1360,7 @@ line)." (setq-local ghostel--term t) (insert "hello") (goto-char (point-min)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0)) ((symbol-function 'evil-ghostel-goto-input-position) #'ignore) ((symbol-function 'ghostel--send-encoded) #'ignore)) @@ -1378,7 +1378,7 @@ line)." (setq-local ghostel--term t) (insert "hello world") (goto-char (point-min)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0)) ((symbol-function 'evil-ghostel-goto-input-position) #'ignore)) (evil-normal-state) @@ -1397,7 +1397,7 @@ line)." (setq-local ghostel--term t) (insert "hello world") (goto-char (point-min)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0)) ((symbol-function 'ghostel--send-encoded) #'ignore)) (evil-normal-state) @@ -1414,7 +1414,7 @@ line)." (setq-local ghostel--term t) (insert "hello") (goto-char (point-min)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0)) ((symbol-function 'evil-ghostel-goto-input-position) #'ignore)) (evil-normal-state) @@ -1440,7 +1440,7 @@ line)." (setq-local ghostel--term t) (insert "hello") (kill-new "world") - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0)) ((symbol-function 'evil-ghostel-goto-input-position) #'ignore)) (evil-normal-state) @@ -1478,7 +1478,7 @@ live-terminal detection." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) (insert "hello world") - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(11 . 0))) (evil-insert-state) ;; Test a sample of keys from evil-ghostel--ctrl-passthrough-keys @@ -1498,8 +1498,8 @@ instead of invoking Evil's insert-state editing commands." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) (setq-local ghostel--input-mode 'semi-char) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049)))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t))) (should-not (evil-ghostel--active-p)) (should (evil-ghostel--ctrl-passthrough-active-p)) (let (sent) @@ -1520,7 +1520,7 @@ Prevents up/down arrows being sent as history navigation." (setq-local ghostel--term t) (insert "line one\nline two\nline three") ;; Terminal cursor on row 2 (last line), col 5 - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(5 . 2))) (evil-normal-state) ;; Move point to row 0 (first line) simulating `kk` @@ -1546,7 +1546,7 @@ Prevents up/down arrows being sent as history navigation." (setq-local ghostel--term t) (insert "hello world") ;; Terminal cursor on row 0, col 0 - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0))) (evil-normal-state) ;; Move point to col 5 on the same row @@ -1579,7 +1579,7 @@ become `ghostel--line-input-start' / `--line-input-end'." (insert ,input-text) (setq-local ghostel--line-input-start (copy-marker ,input-start nil)) (setq-local ghostel--line-input-end (copy-marker ,input-end t)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) ,@body))) (ert-deftest evil-ghostel-test-line-mode-active-p () @@ -1615,7 +1615,7 @@ Point and the terminal cursor are intentionally decoupled there." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) (setq-local ghostel--input-mode 'copy) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0))) (evil-normal-state) (let ((sync-called nil)) @@ -1665,7 +1665,7 @@ C-d (`ghostel-line-mode-delete-char-or-eof')." (map (make-sparse-keymap))) (define-key map (kbd "C-a") sentinel) (use-local-map map) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (evil-insert-state) (evil-ghostel--passthrough-ctrl "a") (should called))))) @@ -1691,7 +1691,7 @@ C-d (`ghostel-line-mode-delete-char-or-eof')." "`evil-ghostel-undo' sends Ctrl+_ to the terminal." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(0 . 0))) (evil-normal-state) (let ((keys-sent '())) @@ -1721,12 +1721,12 @@ C-d (`ghostel-line-mode-delete-char-or-eof')." ;; ----------------------------------------------------------------------- (defmacro evil-ghostel-test--with-escape-stubs (alt-screen-p &rest body) - "Run BODY with `ghostel--mode-enabled' returning ALT-SCREEN-P for 1049 + "Run BODY with `ghostel--alt-screen-p' returning ALT-SCREEN-P and with `ghostel--send-encoded' captured into the local list `sent'." (declare (indent 1) (debug t)) `(let ((sent '())) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (and (= mode 1049) ,alt-screen-p))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) ,alt-screen-p)) ((symbol-function 'ghostel--anchor-window) #'ignore) ((symbol-function 'ghostel--send-encoded) (lambda (key mods &rest _) (push (cons key mods) sent)))) @@ -1944,7 +1944,7 @@ Trailing whitespace in single-line ranges is real user content." (insert "word word word") (goto-char (point-min)) (move-to-column 5) ; start of word2 - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(14 . 0))) (let ((bs-count 0)) (cl-letf (((symbol-function 'ghostel--send-encoded) @@ -1971,7 +1971,7 @@ padding/blanks past end-of-input." (insert "word word") (insert "\n\n\n\n")) ; blank renderer rows below row 0 (goto-char 8) ; col 5 in input = start of last "word" - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(7 . 0)) (ghostel--cursor-char-pos 8)) (evil-normal-state) @@ -2000,7 +2000,7 @@ mirror that drain behaviour." (move-to-column 6) (setq ghostel--cursor-pos '(17 . 0)) (setq ghostel--cursor-char-pos (+ (point-min) 17)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'evil-ghostel--sync-render) (lambda (&rest _) nil))) ; we already update pos inline (let ((keys-sent '())) @@ -2052,7 +2052,7 @@ and silently undoing the user's `^' / `$' / `0' navigation." ;; Push 7 buffer lines so point's buffer line (line 7) is far from ;; the cursor's viewport row (0) when measured in raw line numbers. (insert "scroll-0\nscroll-1\nscroll-2\nscroll-3\nscroll-4\nscroll-5\nscroll-6\n$ ") - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ;; Cursor on the cursor's row at viewport row 4 (last). (ghostel--cursor-pos '(2 . 4))) ;; Park point at col 0 of the cursor row (buffer line 7) — this is @@ -2104,7 +2104,7 @@ sticks." (let ((inhibit-read-only t)) (insert "long scrollback line\n") (insert (propertize "$ " 'ghostel-prompt t))) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(2 . 1)) (ghostel--cursor-char-pos 24)) (evil-normal-state) @@ -2131,7 +2131,7 @@ prompt." (insert (propertize "$ " 'ghostel-prompt t)) (insert "cmd") (insert "\n\n\n\n")) ; blank renderer rows below row 0 - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(5 . 0))) (evil-normal-state) (goto-char (point-min)) @@ -2160,7 +2160,7 @@ semi-char. Replaces `evil-goto-line' so `G' lands on the live prompt instead of the (post-cursor) end of buffer." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (let ((reset-called nil)) (cl-letf (((symbol-function 'evil-ghostel--reset-cursor-point) (lambda () (setq reset-called t)))) @@ -2196,7 +2196,7 @@ cursor jumps to the right edge of the window." ;; "cmd" + render padding to column 20 (e.g. RPROMPT padding). (insert "cmd") (insert " ")) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ;; Live cursor at column 5 (just after "cmd"). Point is ;; one to the left of the cursor — vanilla fall-through. (ghostel--cursor-pos '(5 . 0)) @@ -2216,7 +2216,7 @@ cursor jumps to the right edge of the window." "`' in insert state sends the `delete' PTY key in semi-char." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (let ((keys-sent '())) (cl-letf (((symbol-function 'ghostel--send-encoded) (lambda (key _mods &rest _) (push key keys-sent)))) @@ -2228,8 +2228,8 @@ cursor jumps to the right edge of the window." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) ;; Report alt-screen (1049) as active, every other mode as inactive. - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049)))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t))) (let ((keys-sent '()) (fell-back nil)) (cl-letf (((symbol-function 'ghostel--send-encoded) (lambda (key _mods &rest _) (push key keys-sent))) @@ -2244,7 +2244,7 @@ cursor jumps to the right edge of the window." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) (setq-local ghostel--input-mode 'line) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (let ((keys-sent '()) (fell-back nil)) (cl-letf (((symbol-function 'ghostel--send-encoded) (lambda (key _mods &rest _) (push key keys-sent))) @@ -2463,7 +2463,7 @@ does not push BEG up to the cursor and collapse the range." (evil-ghostel-test--with-evil-buffer (setq-local ghostel--term t) (insert "word1 word2") - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(11 . 0)) (ghostel--cursor-char-pos (point))) (let ((clamped (evil-ghostel--clamp 1 7))) @@ -2477,7 +2477,7 @@ does not push BEG up to the cursor and collapse the range." (let ((inhibit-read-only t)) (insert (propertize "$ " 'ghostel-prompt t)) (insert "cmd ")) ; trailing renderer padding - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(5 . 0)) (ghostel--cursor-char-pos 6)) (evil-normal-state) @@ -2494,7 +2494,7 @@ does not push BEG up to the cursor and collapse the range." (insert (propertize "$ " 'ghostel-prompt t)) (insert (propertize "echo" 'ghostel-input t 'face '(:foreground "#ffffff"))) (insert (propertize " ls" 'ghostel-input t 'face '(:foreground "#4d4d4d")))) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(6 . 0)) (ghostel--cursor-char-pos 7)) ; after "echo" (evil-normal-state) @@ -2510,7 +2510,7 @@ does not push BEG up to the cursor and collapse the range." (insert "$ command") (let ((inhibit-read-only t)) (put-text-property 1 3 'ghostel-prompt t)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (evil-normal-state) (goto-char (point-max)) (evil-ghostel-first-non-blank) @@ -2529,7 +2529,7 @@ character, so it must not consume a backspace or a replacement char." (insert "C")) ;; Terminal cursor at the end of input (after "C"), as right after ;; typing; the input region spans the whole buffer. - (cl-letf (((symbol-function 'ghostel--mode-enabled) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-pos '(1 . 0)) (ghostel--cursor-char-pos (point-max)) ((symbol-function 'evil-ghostel-goto-input-position) #'ignore)) diff --git a/test/ghostel-line-mode-test.el b/test/ghostel-line-mode-test.el index c1ea4a67..cbb02db3 100644 --- a/test/ghostel-line-mode-test.el +++ b/test/ghostel-line-mode-test.el @@ -89,8 +89,8 @@ copy mode behind the user's back." (with-temp-buffer (setq-local ghostel--term 'fake) (setq-local ghostel--input-mode 'line) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term _mode) nil)) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) nil)) ((symbol-function 'mouse-set-region) (lambda (event) (setq set-region-arg event))) ((symbol-function 'ghostel-copy-mode) @@ -305,7 +305,7 @@ Also verifies the documented nil-return when no cursor is available." (with-current-buffer buf (ghostel-mode) (let ((ghostel--term 'fake)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (should-error (ghostel-line-mode) :type 'user-error)))) (kill-buffer buf)))) @@ -324,7 +324,7 @@ but the cursor is at the end of the REPL's prompt." (setq ghostel--term 'fake) (setq ghostel--term-rows 1) (setq ghostel--process 'fake-proc) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-char-pos 4) ((symbol-function 'process-live-p) (lambda (_p) t)) @@ -361,7 +361,7 @@ without waiting for another PTY byte." (setq ghostel--term 'fake) (setq ghostel--term-rows 1) (setq ghostel--process 'fake-proc) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-char-pos 4) ((symbol-function 'ghostel--invalidate) @@ -393,7 +393,7 @@ the hot path." (setq ghostel--term 'fake) (setq ghostel--term-rows 1) (setq ghostel--process 'fake-proc) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) (ghostel--cursor-char-pos 4) ((symbol-function 'ghostel--invalidate) @@ -421,8 +421,8 @@ sentinel and enters line mode for real once the TUI exits." (ghostel-mode) (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049)))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t))) ;; Buffer is in semi-char, alt-screen is on. (should (eq ghostel--input-mode 'semi-char)) (ghostel-line-mode) @@ -448,9 +448,8 @@ preserved." (let ((alt-on nil) (ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) - (and alt-on (memq mode '(1049 1047)) t))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) alt-on)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -488,9 +487,8 @@ restored." (let ((alt-on nil) (ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) - (and alt-on (memq mode '(1049 1047)) t))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) alt-on)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -527,9 +525,8 @@ restored." (let ((alt-on nil) (ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) - (and alt-on (memq mode '(1049 1047)) t))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) alt-on)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -567,9 +564,8 @@ restored." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((alt-on t) (ghostel--term 'fake)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) - (and alt-on (memq mode '(1049 1047)) t))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) alt-on)) ((symbol-function 'ghostel--invalidate) #'ignore) ((symbol-function 'ghostel--anchor-window) #'ignore)) ;; Defer entry while alt-screen is on — paused armed. @@ -594,7 +590,7 @@ a literal newline." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) @@ -638,7 +634,7 @@ a literal newline." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) @@ -669,7 +665,7 @@ pi), the trailing encoded `return' is the submit and any embedded (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) @@ -701,7 +697,7 @@ pi), the trailing encoded `return' is the submit and any embedded (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) @@ -730,7 +726,7 @@ pi), the trailing encoded `return' is the submit and any embedded (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) @@ -771,7 +767,7 @@ a duplicated line." (ghostel-test--insert-rendered (propertize "ls -la" 'ghostel-input t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) @@ -814,7 +810,7 @@ a duplicated line." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) @@ -849,7 +845,7 @@ should land at the position right after the prompt prefix." (ghostel-test--insert-rendered "ls -la") (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore) @@ -883,7 +879,7 @@ back to the active prompt's input area." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore) @@ -1023,7 +1019,7 @@ on every empty prompt the user pressed `RET' to.)" (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) @@ -1056,7 +1052,7 @@ user can continue editing at the shell prompt." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) @@ -1083,7 +1079,7 @@ user can continue editing at the shell prompt." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) @@ -1105,7 +1101,7 @@ user can continue editing at the shell prompt." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -1138,7 +1134,7 @@ normally." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -1174,7 +1170,7 @@ normally." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1204,7 +1200,7 @@ normally." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1231,7 +1227,7 @@ normally." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1271,7 +1267,7 @@ normally." nil))) ;; Skip bash-completion in this test regardless of host config. (ghostel-line-mode-use-bash-completion nil)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1309,7 +1305,7 @@ ambiguous)." (ghostel-line-mode-use-bash-completion nil) (ghostel-line-mode-completion-at-point-functions '(comint-filename-completion))) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1339,7 +1335,7 @@ ambiguous)." ;; A capf that would crash if called on a non-string — ;; ensures empty-input path doesn't blow up. (list (lambda () nil)))) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1364,7 +1360,7 @@ ambiguous)." (list (lambda () (setq snapped-point (point)) nil)))) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1389,7 +1385,7 @@ ambiguous)." (ghostel-line-mode-use-bash-completion nil) (ghostel-line-mode-completion-at-point-functions (list (lambda () nil)))) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1441,7 +1437,7 @@ ambiguous)." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1472,7 +1468,7 @@ ambiguous)." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1498,7 +1494,7 @@ ambiguous)." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1545,7 +1541,7 @@ not get linkified (which would steal RET from line-mode-send)." (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1580,7 +1576,7 @@ snapshot/restore must leave the status-bar text untouched." (ghostel-test--insert-rendered "\n--- status ---\n") (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1623,7 +1619,7 @@ instead of being discarded." (ghostel-test--insert-rendered (propertize "cd src" 'ghostel-input t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1651,7 +1647,7 @@ running through a redraw cycle." (ghostel-test--insert-rendered "\n[status: ok]\n") (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)) @@ -1673,7 +1669,7 @@ Entering line mode forces the editor default; teardown restores the saved value. (ghostel-test--insert-rendered (propertize "$ " 'ghostel-prompt t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore) @@ -1706,8 +1702,8 @@ enter at that prompt instead of arming." (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) (setq ghostel--cursor-char-pos (point)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -1736,8 +1732,8 @@ it would scrape garbage. It arms a deferred sentinel instead." (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) (setq ghostel--cursor-char-pos (point)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t)) ((symbol-function 'ghostel--invalidate) #'ignore)) (should (eq ghostel--input-mode 'semi-char)) (ghostel-line-mode) @@ -1763,8 +1759,8 @@ cursor to anchor on, a prefix arg bypasses the gate and enters." (ghostel--process 'fake-proc) (ghostel-prompt-regexp nil)) ; force the bare-cursor path (setq ghostel--cursor-char-pos (point)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -1791,8 +1787,8 @@ rather than leave the mode unchanged." (insert "no prompt here")) (let ((ghostel--term 'fake) (ghostel--cursor-char-pos nil)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049)))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t))) (let ((current-prefix-arg '(4))) (should-error (call-interactively #'ghostel-line-mode) :type 'user-error))))) @@ -1812,8 +1808,8 @@ alt-screen is still on, making the whole entry a no-op." (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) (setq ghostel--cursor-char-pos (point)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (= mode 1049))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) t)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -1840,9 +1836,8 @@ transition pauses as before (type-ahead discarded)." (let ((alt-on nil) (ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) - (and alt-on (memq mode '(1049 1047)) t))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) alt-on)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -1906,8 +1901,8 @@ typed input (it restores the empty armed snapshot)." (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) (setq ghostel--cursor-char-pos (point)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) (and alt-on (= mode 1049)))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) alt-on)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--send-encoded) #'ignore) @@ -1951,9 +1946,8 @@ the flag must not keep suppressing the pause forever." (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) (setq ghostel--cursor-char-pos (point)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) - (lambda (_term mode) - (and alt-on (memq mode '(1049 1047)) t))) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) + (lambda (_term) alt-on)) ((symbol-function 'process-live-p) (lambda (_p) t)) ((symbol-function 'ghostel--write-pty) #'ignore) ((symbol-function 'ghostel--redraw) #'ignore) @@ -2059,7 +2053,7 @@ snap-to-`ghostel--cursor-char-pos' behaviour is preserved for the other modes." (unwind-protect ;; No native module: stub the alt-screen DEC-mode query so line-mode ;; entry takes the primary-screen path. - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil))) (set-window-buffer (selected-window) buf) (with-current-buffer buf diff --git a/test/ghostel-line-mode-undo-test.el b/test/ghostel-line-mode-undo-test.el index 57f68bb9..5ff6b413 100644 --- a/test/ghostel-line-mode-undo-test.el +++ b/test/ghostel-line-mode-undo-test.el @@ -65,7 +65,7 @@ live PTY. Leaves the buffer in line mode with point at the input." (should (eq buffer-undo-list t)) (let ((ghostel--term 'fake) (ghostel--process 'fake-proc)) - (cl-letf (((symbol-function 'ghostel--mode-enabled) + (cl-letf (((symbol-function 'ghostel--alt-screen-p) (lambda (&rest _) nil)) ((symbol-function 'ghostel--redraw) #'ignore) ((symbol-function 'ghostel--invalidate) #'ignore)