From d52d160645b560542738b6594096e85dd9ae6ff4 Mon Sep 17 00:00:00 2001 From: scheidan Date: Mon, 22 Jun 2026 10:07:11 +0200 Subject: [PATCH 1/5] Add Ghostel terminal backend --- README.md | 6 +++++- julia-repl.el | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 54134b4..7ab3a7d 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ then the next time you open a REPL, it will have the name `*julia-master-tests*` The default is `ansi-term`, which is included in Emacs, but it is recommended that you use [`vterm` via `emacs-libvterm`](https://github.com/akermu/emacs-libvterm) (it is not the default since you need to install an extra package and the binary). -You can also use [`eat`](https://codeberg.org/akib/emacs-eat/) as a backend. +You can also use [`eat`](https://codeberg.org/akib/emacs-eat/) or [`ghostel`](https://github.com/dakra/ghostel) as a backend. **Note to Windows users**: you may not be able to use `eat` and/or `vterm` directly from native Windows Emacs, but there have been reports of people using them successfully from WSL (Windows Subsistem for Linux) 2. Please understand that supporting those terminal emulators is outside the scope of this package; `julia-repl` merely provides bindings for them conditional on availability on your system. @@ -150,6 +150,10 @@ See the help of `term` for more. Install [`eat`](https://codeberg.org/akib/emacs-eat/) and use `(julia-repl-set-terminal-backend 'eat)` in your config file. +#### Using `ghostel` + +Install [`ghostel`](https://github.com/dakra/ghostel) and use `(julia-repl-set-terminal-backend 'ghostel)` in your config file. + ## Using the @edit macro The `@edit` macro can be called with `C-c C-e` when the `julia-repl-mode` minor mode is enabled. The behavior depends on the value of the `JULIA_EDITOR` envoronment variable in the Julia session. The command `julia-repl-set-julia-editor` is provided to conveniently control this from emacs. diff --git a/julia-repl.el b/julia-repl.el index fb99ae2..3c478ba 100644 --- a/julia-repl.el +++ b/julia-repl.el @@ -268,6 +268,48 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit (when ret-p (eat-term-send-string eat-terminal "\^M"))))) + +;;; ghostel term + +(with-eval-after-load 'ghostel + + (defvar ghostel--process) + (defvar ghostel-use-native-pty) + + (cl-defstruct julia-repl--buffer-ghostel + "Terminal backend using ‘ghostel’, which needs to be installed and loaded.") + + (cl-defmethod julia-repl--locate-live-buffer ((_terminal-backend julia-repl--buffer-ghostel) + name) + (if-let ((inferior-buffer (get-buffer (julia-repl--add-earmuffs name)))) + (with-current-buffer inferior-buffer + (cl-assert (eq major-mode 'ghostel-mode) nil "Expected ghostel-mode. Changed mode or backends?") + (when (process-live-p ghostel--process) + inferior-buffer)))) + + (cl-defmethod julia-repl--make-buffer ((_terminal-backend julia-repl--buffer-ghostel) + name executable-path switches) + (let ((inferior-buffer (get-buffer-create (julia-repl--add-earmuffs name)))) + (with-current-buffer inferior-buffer + (setq-local ghostel-buffer-name-function nil) + (let ((ghostel-use-native-pty nil)) + (ghostel-exec inferior-buffer executable-path switches)) + (mapc (lambda (k) + (define-key ghostel-semi-char-mode-map k (global-key-binding k))) + julia-repl-captures) + (local-set-key (kbd "C-c C-z") #'julia-repl--switch-back)) + inferior-buffer)) + + (cl-defmethod julia-repl--send-to-backend ((_terminal-backend julia-repl--buffer-ghostel) + buffer string paste-p ret-p) + (with-current-buffer buffer + (if paste-p + (ghostel-paste-string string) + (ghostel-send-string string)) + (when ret-p + (ghostel-send-key "return"))))) + + ;;; compiler output regexps for navigation (defconst julia-repl--CR-path @@ -330,7 +372,9 @@ Valid backends are currently: - ‘vterm’, which requires that vterm is installed. See URL ‘https://github.com/akermu/emacs-libvterm’. -- ‘eat’, which requires that eat is installed. See URL ‘https://codeberg.org/akib/emacs-eat’." +- ‘eat’, which requires that eat is installed. See URL ‘https://codeberg.org/akib/emacs-eat’. + +- ‘ghostel’, which requires that ghostel is installed. See URL ‘https://github.com/dakra/ghostel’." (interactive "S") (cl-case backend (ansi-term @@ -342,6 +386,9 @@ Valid backends are currently: (eat (require 'eat) (setq julia-repl--terminal-backend (make-julia-repl--buffer-eat))) + (ghostel + (require 'ghostel) + (setq julia-repl--terminal-backend (make-julia-repl--buffer-ghostel))) (otherwise (error "Unrecognized backend “%s”." backend)))) From 7460d4cdbf5f02f1d91184e9feeaa2377dd8de7d Mon Sep 17 00:00:00 2001 From: scheidan Date: Mon, 22 Jun 2026 10:55:00 +0200 Subject: [PATCH 2/5] stop open new sessions when sending code --- julia-repl.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/julia-repl.el b/julia-repl.el index 3c478ba..bee093b 100644 --- a/julia-repl.el +++ b/julia-repl.el @@ -274,7 +274,9 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit (with-eval-after-load 'ghostel (defvar ghostel--process) + (defvar ghostel--managed-buffer-name) (defvar ghostel-use-native-pty) + (defvar ghostel-buffer-name-function) (cl-defstruct julia-repl--buffer-ghostel "Terminal backend using ‘ghostel’, which needs to be installed and loaded.") @@ -291,9 +293,10 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit name executable-path switches) (let ((inferior-buffer (get-buffer-create (julia-repl--add-earmuffs name)))) (with-current-buffer inferior-buffer - (setq-local ghostel-buffer-name-function nil) (let ((ghostel-use-native-pty nil)) (ghostel-exec inferior-buffer executable-path switches)) + (setq-local ghostel-buffer-name-function nil) + (setq-local ghostel--managed-buffer-name (buffer-name)) (mapc (lambda (k) (define-key ghostel-semi-char-mode-map k (global-key-binding k))) julia-repl-captures) From 5c06b1f8b791abb251a06287a07179f2e2f97f9a Mon Sep 17 00:00:00 2001 From: scheidan Date: Tue, 23 Jun 2026 11:48:17 +0200 Subject: [PATCH 3/5] when sending a command, scroll to the bottom of the REPL buffer --- julia-repl.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/julia-repl.el b/julia-repl.el index bee093b..1d55055 100644 --- a/julia-repl.el +++ b/julia-repl.el @@ -281,6 +281,11 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit (cl-defstruct julia-repl--buffer-ghostel "Terminal backend using ‘ghostel’, which needs to be installed and loaded.") + (defun julia-repl--ghostel-scroll-to-bottom () + "Scroll visible windows displaying the current ghostel buffer to the bottom." + (dolist (window (get-buffer-window-list (current-buffer) nil t)) + (ghostel--anchor-window window))) + (cl-defmethod julia-repl--locate-live-buffer ((_terminal-backend julia-repl--buffer-ghostel) name) (if-let ((inferior-buffer (get-buffer (julia-repl--add-earmuffs name)))) @@ -306,6 +311,7 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit (cl-defmethod julia-repl--send-to-backend ((_terminal-backend julia-repl--buffer-ghostel) buffer string paste-p ret-p) (with-current-buffer buffer + (julia-repl--ghostel-scroll-to-bottom) (if paste-p (ghostel-paste-string string) (ghostel-send-string string)) From 400e715d2d70d9395395751562fa59d2dc3f7036 Mon Sep 17 00:00:00 2001 From: scheidan Date: Tue, 23 Jun 2026 13:40:32 +0200 Subject: [PATCH 4/5] simplify implementation --- julia-repl.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/julia-repl.el b/julia-repl.el index 1d55055..246c8eb 100644 --- a/julia-repl.el +++ b/julia-repl.el @@ -274,7 +274,6 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit (with-eval-after-load 'ghostel (defvar ghostel--process) - (defvar ghostel--managed-buffer-name) (defvar ghostel-use-native-pty) (defvar ghostel-buffer-name-function) @@ -298,10 +297,10 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit name executable-path switches) (let ((inferior-buffer (get-buffer-create (julia-repl--add-earmuffs name)))) (with-current-buffer inferior-buffer - (let ((ghostel-use-native-pty nil)) + (let ((ghostel-use-native-pty nil) + (ghostel-buffer-name-function nil)) (ghostel-exec inferior-buffer executable-path switches)) (setq-local ghostel-buffer-name-function nil) - (setq-local ghostel--managed-buffer-name (buffer-name)) (mapc (lambda (k) (define-key ghostel-semi-char-mode-map k (global-key-binding k))) julia-repl-captures) From 2e96e747264b9938a6e1d955e5ddb1e37d065919 Mon Sep 17 00:00:00 2001 From: scheidan Date: Tue, 23 Jun 2026 16:03:23 +0200 Subject: [PATCH 5/5] add comments --- julia-repl.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/julia-repl.el b/julia-repl.el index 246c8eb..5b65f2b 100644 --- a/julia-repl.el +++ b/julia-repl.el @@ -273,6 +273,7 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit (with-eval-after-load 'ghostel + ;; this variables are defined by ghostel.el and are only locally changed. (defvar ghostel--process) (defvar ghostel-use-native-pty) (defvar ghostel-buffer-name-function) @@ -290,15 +291,15 @@ When PASTE-P, “bracketed paste” mode will be used. When RET-P, terminate wit (if-let ((inferior-buffer (get-buffer (julia-repl--add-earmuffs name)))) (with-current-buffer inferior-buffer (cl-assert (eq major-mode 'ghostel-mode) nil "Expected ghostel-mode. Changed mode or backends?") - (when (process-live-p ghostel--process) + (when (process-live-p ghostel--process) ; check if Julia sessions is still live inferior-buffer)))) (cl-defmethod julia-repl--make-buffer ((_terminal-backend julia-repl--buffer-ghostel) name executable-path switches) (let ((inferior-buffer (get-buffer-create (julia-repl--add-earmuffs name)))) (with-current-buffer inferior-buffer - (let ((ghostel-use-native-pty nil) - (ghostel-buffer-name-function nil)) + (let ((ghostel-use-native-pty nil) ; use Emacs process machinery + (ghostel-buffer-name-function nil)) ; avoid ghostel's renaming (ghostel-exec inferior-buffer executable-path switches)) (setq-local ghostel-buffer-name-function nil) (mapc (lambda (k)