Subject: [PATCH] Allow numbered buffer selection for project shell commands
From: Paul Nelson <[email-masked]>
To: [email-masked]
Date: Sun, 23 Feb 2025 12:15:18 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

This patch for project.el adds numeric prefix buffer naming to the
project-shell and project-eshell commands, aligning their behavior with
that of eshell.

Without any prefix, these commands switch to or create a shell session.
With a plain C-u, the current behavior is to create a new session with
an automatically generated numeric suffix (e.g. "*foo-shell<2>*"), but
after switching away from that buffer, there’s no convenient way to
switch back.

This patch changes that: when given a numeric prefix (e.g. C-2), the
command will switch to or create the session buffer with the
corresponding suffix.

Implementation notes:

- project-eshell: The current implementation duplicates some
functionality provided by eshell.  By removing this redundancy, the
numeric prefix behavior is inherited "for free".

- project-shell: The revised implementation borrows from that of eshell.

Any comments or feedback would be welcome.

Thanks, best,

Paul

From 73bb69e0c473668d9d10b5345963f707b8c0dc46 Mon Sep 17 00:00:00 2001
From: Paul Nelson <[email-masked]>
Date: Fri, 21 Feb 2025 11:49:46 +0100
Subject: [PATCH] Allow numbered buffer selection for project shell commands

* project.el (project-shell, project-eshell): When a numeric
prefix is supplied (e.g. C-2), the command will switch to or
create a session buffer whose name is suffixed with that number,
e.g. "*name-of-project-shell<2>*".  As before, a plain universal
argument C-u creates a new session with an automatically
generated numeric suffix.  This change makes the behavior
consistent with eshell's handling of numeric prefixes.
* etc/NEWS: Announce the change.
---
 etc/NEWS                  |  7 +++++++
 lisp/progmodes/project.el | 36 +++++++++++++++++++++++-------------
 2 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 82a653c4e1e..2b4efa41488 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -302,6 +302,13 @@ It can be used when switching between projects with similar file trees
 (such as Git worktrees of the same repository).  It supports being
 invoked standalone or from the 'project-switch-commands' dispatch menu.
 
+---
+*** 'project-shell' and 'project-eshell' support numeric prefix buffer naming.
+They now accept numeric prefix arguments to select or create numbered
+shell sessions.  For example, 'C-2 C-x p s' switches to or creates a
+buffer named "*name-of-project-shell<2>*".  By comparison, a plain
+universal argument as in 'C-u C-x p s' always creates a new session.
+
 ** Registers
 
 *** New functions 'buffer-to-register' and 'file-to-register'.
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 35bf66c9ffb..04c202a6232 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1397,36 +1397,46 @@ project-shell
   "Start an inferior shell in the current project's root directory.
 If a buffer already exists for running a shell in the project's root,
 switch to it.  Otherwise, create a new shell buffer.
-With \\[universal-argument] prefix arg, create a new inferior shell buffer even
-if one already exists."
+
+With a nonnumeric prefix arg, create a new inferior shell buffer even if
+one already exists.
+
+With a numeric prefix arg, switch to the session with that number, or
+create it if it doesn't already exist."
   (interactive)
   (require 'comint)
   (let* ((default-directory (project-root (project-current t)))
-         (default-project-shell-name (project-prefixed-buffer-name "shell"))
-         (shell-buffer (get-buffer default-project-shell-name)))
+         (base-name (project-prefixed-buffer-name "shell"))
+         (shell-buffer-name
+          (cond ((numberp current-prefix-arg)
+                 (format "%s<%d>" base-name current-prefix-arg))
+                (current-prefix-arg
+                 (generate-new-buffer-name base-name))
+                (t base-name)))
+         (shell-buffer (get-buffer shell-buffer-name)))
     (if (and shell-buffer (not current-prefix-arg))
         (if (comint-check-proc shell-buffer)
             (pop-to-buffer shell-buffer (append display-buffer--same-window-action
                                                 '((category . comint))))
           (shell shell-buffer))
-      (shell (generate-new-buffer-name default-project-shell-name)))))
+      (shell shell-buffer-name))))
 
 ;;;###autoload
 (defun project-eshell ()
   "Start Eshell in the current project's root directory.
 If a buffer already exists for running Eshell in the project's root,
 switch to it.  Otherwise, create a new Eshell buffer.
-With \\[universal-argument] prefix arg, create a new Eshell buffer even
-if one already exists."
+
+With a nonnumeric prefix arg, create a new Eshell buffer even if one
+already exists.
+
+With a numeric prefix arg, switch to the session with that number, or
+create it if it doesn't already exist."
   (interactive)
   (defvar eshell-buffer-name)
   (let* ((default-directory (project-root (project-current t)))
-         (eshell-buffer-name (project-prefixed-buffer-name "eshell"))
-         (eshell-buffer (get-buffer eshell-buffer-name)))
-    (if (and eshell-buffer (not current-prefix-arg))
-        (pop-to-buffer eshell-buffer (append display-buffer--same-window-action
-                                             '((category . comint))))
-      (eshell t))))
+         (eshell-buffer-name (project-prefixed-buffer-name "eshell")))
+    (eshell current-prefix-arg)))
 
 ;;;###autoload
 (defun project-async-shell-command ()
-- 
2.39.3 (Apple Git-145)