Skip to content

Commit 75dc57a

Browse files
committed
Add default session feature to bypass sesman's project-based dispatch
Some users want a simpler model: designate one session as the "default" and have all evaluations go there, regardless of project context. This is useful for monorepo setups, scratch buffers, or when working across multiple projects that share a single REPL. New commands: - `cider-set-default-session` - pick a session to use for all lookups - `cider-clear-default-session` - revert to normal sesman dispatch When set, `cider-repls` returns REPLs from the default session (with type filtering still applied). Stale sessions produce a warning and yield no REPLs. `cider-describe-connection` shows the default session in its output. Both commands are available from the CIDER menu.
1 parent ae247d8 commit 75dc57a

File tree

5 files changed

+186
-42
lines changed

5 files changed

+186
-42
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## master (unreleased)
44

5+
### New features
6+
7+
- [#3865](https://github.com/clojure-emacs/cider/pull/3865): Add default session feature to bypass sesman's project-based dispatch (`cider-set-default-session`, `cider-clear-default-session`).
8+
59
## 1.21.0 (2026-02-07)
610

711
### Changes

doc/modules/ROOT/pages/usage/managing_connections.adoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,22 @@ By default https://github.com/vspinu/sesman[Sesman] allows multiple simultaneous
126126
directories, but only one link per buffer. See `sesman-single-link-contexts` if
127127
you would like to change that.
128128

129+
== Default Session
130+
131+
If you'd rather bypass sesman's context-based session inference and always use a
132+
specific session, you can designate one as the *default session*. When a default
133+
session is set, all REPL lookups (evaluation, completion, etc.) use it regardless
134+
of project context. This is useful for monorepo setups, scratch buffers, or when
135+
working across multiple projects that share a single REPL.
136+
137+
* `cider-set-default-session` -- prompts you to pick from the active sessions and sets it as the default.
138+
* `cider-clear-default-session` -- clears the default session, reverting to normal project-based session association.
139+
140+
Both commands are also available from the CIDER menu.
141+
142+
If the default session no longer exists (e.g. it was closed), CIDER will warn you
143+
and fall through to the normal session lookup.
144+
129145
== Current REPL
130146

131147
The current REPL is the most relevant REPL from the current session. REPL relevance

lisp/cider-connection.el

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ All other values do not combine any sessions."
8282
:safe #'symbolp
8383
:package-version '(cider . "1.5"))
8484

85+
(defvar cider-default-session nil
86+
"When non-nil, bypass sesman and use this session for all REPL lookups.
87+
Set interactively with `cider-set-default-session'.")
88+
8589
(defcustom cider-reuse-dead-repls 'prompt
8690
"How to deal with existing dead REPL buffers when initializing a connection.
8791
@@ -481,30 +485,33 @@ Info contains project name, current REPL namespace, host:port endpoint and
481485
runtime details. When GENERICP is non-nil, don't provide specific info
482486
about this buffer (like variable `cider-repl-type')."
483487
(with-current-buffer connection-buffer
484-
(cond
485-
((cider--clojure-version)
486-
(format "%s%s@%s:%s (Java %s, Clojure %s, nREPL %s)"
487-
(if genericp "" (upcase (concat (symbol-name cider-repl-type) " ")))
488-
(or (cider--project-name nrepl-project-dir) "<no project>")
489-
(plist-get nrepl-endpoint :host)
490-
(plist-get nrepl-endpoint :port)
491-
(cider--java-version)
492-
(cider--clojure-version)
493-
(cider--nrepl-version)))
494-
((cider--babashka-version)
495-
(format "%s%s@%s:%s (Babashka %s, babashka.nrepl %s)"
496-
(if genericp "" (upcase (concat (symbol-name cider-repl-type) " ")))
497-
(or (cider--project-name nrepl-project-dir) "<no project>")
498-
(plist-get nrepl-endpoint :host)
499-
(plist-get nrepl-endpoint :port)
500-
(cider--babashka-version)
501-
(cider--babashka-nrepl-version)))
502-
(t
503-
(format "%s%s@%s:%s"
504-
(if genericp "" (upcase (concat (symbol-name cider-repl-type) " ")))
505-
(or (cider--project-name nrepl-project-dir) "<no project>")
506-
(plist-get nrepl-endpoint :host)
507-
(plist-get nrepl-endpoint :port))))))
488+
(let ((info (cond
489+
((cider--clojure-version)
490+
(format "%s%s@%s:%s (Java %s, Clojure %s, nREPL %s)"
491+
(if genericp "" (upcase (concat (symbol-name cider-repl-type) " ")))
492+
(or (cider--project-name nrepl-project-dir) "<no project>")
493+
(plist-get nrepl-endpoint :host)
494+
(plist-get nrepl-endpoint :port)
495+
(cider--java-version)
496+
(cider--clojure-version)
497+
(cider--nrepl-version)))
498+
((cider--babashka-version)
499+
(format "%s%s@%s:%s (Babashka %s, babashka.nrepl %s)"
500+
(if genericp "" (upcase (concat (symbol-name cider-repl-type) " ")))
501+
(or (cider--project-name nrepl-project-dir) "<no project>")
502+
(plist-get nrepl-endpoint :host)
503+
(plist-get nrepl-endpoint :port)
504+
(cider--babashka-version)
505+
(cider--babashka-nrepl-version)))
506+
(t
507+
(format "%s%s@%s:%s"
508+
(if genericp "" (upcase (concat (symbol-name cider-repl-type) " ")))
509+
(or (cider--project-name nrepl-project-dir) "<no project>")
510+
(plist-get nrepl-endpoint :host)
511+
(plist-get nrepl-endpoint :port))))))
512+
(if cider-default-session
513+
(format "%s [default session: %s]" info cider-default-session)
514+
info))))
508515

509516
(defvar-local cider-connection-capabilities '()
510517
"A list of some of the capabilities of this connection buffer.
@@ -608,6 +615,24 @@ REPL defaults to the current REPL."
608615
(mapc (lambda (mw) (insert (format " * %s\n" mw))) middleware))
609616
(display-buffer "*cider-nrepl-middleware*")))
610617

618+
(defun cider-set-default-session ()
619+
"Set the default session for all REPL lookups.
620+
When a default session is set, all evaluations use it
621+
regardless of project context."
622+
(interactive)
623+
(let* ((sessions (cider-sessions))
624+
(session-names (mapcar #'car sessions))
625+
(name (completing-read "Set default CIDER session: " session-names nil t)))
626+
(setq cider-default-session name)
627+
(message "Default CIDER session set to '%s'" name)))
628+
629+
(defun cider-clear-default-session ()
630+
"Clear the default CIDER session.
631+
Reverts to normal project-based session association."
632+
(interactive)
633+
(setq cider-default-session nil)
634+
(message "Default CIDER session cleared"))
635+
611636

612637
;;; Sesman's Session-Wise Management UI
613638

@@ -1021,24 +1046,29 @@ filters out all the REPLs that do not support the designated ops."
10211046
((listp type)
10221047
(mapcar #'cider-maybe-intern type))
10231048
((cider-maybe-intern type))))
1024-
(repls (pcase cider-merge-sessions
1025-
('host
1026-
(if ensure
1027-
(or (cider--extract-connections (cider--get-sessions-with-same-host
1028-
(sesman-current-session 'CIDER)
1029-
(sesman-current-sessions 'CIDER)))
1030-
(user-error "No linked %s sessions" 'CIDER))
1031-
(cider--extract-connections (cider--get-sessions-with-same-host
1032-
(sesman-current-session 'CIDER)
1033-
(sesman-current-sessions 'CIDER)))))
1034-
('project
1035-
(if ensure
1036-
(or (cider--extract-connections (sesman-current-sessions 'CIDER))
1037-
(user-error "No linked %s sessions" 'CIDER))
1038-
(cider--extract-connections (sesman-current-sessions 'CIDER))))
1039-
(_ (cdr (if ensure
1040-
(sesman-ensure-session 'CIDER)
1041-
(sesman-current-session 'CIDER)))))))
1049+
(repls (if cider-default-session
1050+
(if-let* ((session (sesman-session 'CIDER cider-default-session)))
1051+
(cdr session)
1052+
(message "Default CIDER session '%s' no longer exists, ignoring" cider-default-session)
1053+
nil)
1054+
(pcase cider-merge-sessions
1055+
('host
1056+
(if ensure
1057+
(or (cider--extract-connections (cider--get-sessions-with-same-host
1058+
(sesman-current-session 'CIDER)
1059+
(sesman-current-sessions 'CIDER)))
1060+
(user-error "No linked %s sessions" 'CIDER))
1061+
(cider--extract-connections (cider--get-sessions-with-same-host
1062+
(sesman-current-session 'CIDER)
1063+
(sesman-current-sessions 'CIDER)))))
1064+
('project
1065+
(if ensure
1066+
(or (cider--extract-connections (sesman-current-sessions 'CIDER))
1067+
(user-error "No linked %s sessions" 'CIDER))
1068+
(cider--extract-connections (sesman-current-sessions 'CIDER))))
1069+
(_ (cdr (if ensure
1070+
(sesman-ensure-session 'CIDER)
1071+
(sesman-current-session 'CIDER))))))))
10421072
(or (seq-filter (lambda (b)
10431073
(unless
10441074
(cider-cljs-pending-p b)

lisp/cider-mode.el

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,10 @@ If invoked with a prefix ARG eval the expression after inserting it."
296296
"--"
297297
["Connection info" cider-describe-connection
298298
:active (cider-connected-p)]
299+
["Set default session" cider-set-default-session
300+
:active (cider-connected-p)]
301+
["Clear default session" cider-clear-default-session
302+
:active cider-default-session]
299303
["Select any CIDER buffer" cider-selector]
300304
"--"
301305
["Configure CIDER" (customize-group 'cider)]

test/cider-connection-tests.el

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,3 +543,93 @@
543543
:project-dir "/Users/me/myproject"
544544
:repl-type cider-connection-tests-dummy-function))
545545
:to-equal "*cider-repl me/myproject:localhost:12345(cider-connection-tests-dummy-function)*")))
546+
547+
(describe "cider-default-session"
548+
549+
:var (sesman-sessions-hashmap sesman-links-alist ses-name ses-name2)
550+
551+
(before-each
552+
(setq sesman-sessions-hashmap (make-hash-table :test #'equal)
553+
sesman-links-alist nil
554+
cider-default-session nil
555+
ses-name "a-session"
556+
ses-name2 "b-session"))
557+
558+
(after-each
559+
(setq cider-default-session nil))
560+
561+
(describe "cider-repls with default session"
562+
(it "returns REPLs from the default session regardless of project context"
563+
(let ((a-dir (expand-file-name "/tmp/a-dir"))
564+
(b-dir (expand-file-name "/tmp/b-dir")))
565+
(let ((default-directory a-dir))
566+
(with-repl-buffer ses-name 'clj b1
567+
(with-repl-buffer ses-name 'cljs b2
568+
(let ((default-directory b-dir))
569+
(with-repl-buffer ses-name2 'clj b3
570+
(with-repl-buffer ses-name2 'cljs b4
571+
;; Without default session, we get b-dir's session
572+
(expect (cider-repls) :to-equal (list b4 b3))
573+
574+
;; Set default session to a-session
575+
(setq cider-default-session ses-name)
576+
577+
;; Now we get a-session's REPLs even though we're in b-dir
578+
(expect (cider-repls) :to-have-same-items-as (list b1 b2))))))))))
579+
580+
(it "still filters by type when default session is set"
581+
(let ((a-dir (expand-file-name "/tmp/a-dir"))
582+
(b-dir (expand-file-name "/tmp/b-dir")))
583+
(let ((default-directory a-dir))
584+
(with-repl-buffer ses-name 'clj b1
585+
(with-repl-buffer ses-name 'cljs b2
586+
(let ((default-directory b-dir))
587+
(with-repl-buffer ses-name2 'clj b3
588+
(setq cider-default-session ses-name)
589+
(expect (cider-repls 'clj) :to-equal (list b1))
590+
(expect (cider-repls 'cljs) :to-equal (list b2)))))))))
591+
592+
(it "returns nil and warns when default session no longer exists"
593+
(let ((default-directory (expand-file-name "/tmp/a-dir")))
594+
(with-repl-buffer ses-name 'clj _b1
595+
(setq cider-default-session "nonexistent-session")
596+
;; Should warn and return nil (stale default session yields no REPLs)
597+
(expect (cider-repls) :to-equal nil)))))
598+
599+
(describe "cider-set-default-session"
600+
(it "sets the default session from active sessions"
601+
(let ((default-directory (expand-file-name "/tmp/a-dir")))
602+
(with-repl-buffer ses-name 'clj b1
603+
(spy-on 'completing-read :and-return-value ses-name)
604+
(cider-set-default-session)
605+
(expect cider-default-session :to-equal ses-name)))))
606+
607+
(describe "cider-clear-default-session"
608+
(it "clears the default session"
609+
(setq cider-default-session "some-session")
610+
(cider-clear-default-session)
611+
(expect cider-default-session :to-equal nil)))
612+
613+
(describe "cider--connection-info with default session"
614+
(before-each
615+
(spy-on 'cider--java-version :and-return-value "1.7")
616+
(spy-on 'cider--clojure-version :and-return-value "1.7.0")
617+
(spy-on 'cider--nrepl-version :and-return-value "0.2.1"))
618+
619+
(it "appends default session info when set"
620+
(with-temp-buffer
621+
(setq-local nrepl-endpoint '(:host "localhost" :port 4005))
622+
(setq-local nrepl-project-dir "proj")
623+
(setq-local cider-repl-type 'clj)
624+
(setq cider-default-session "my-session")
625+
(expect (cider--connection-info (current-buffer))
626+
:to-equal "CLJ proj@localhost:4005 (Java 1.7, Clojure 1.7.0, nREPL 0.2.1) [default session: my-session]")))
627+
628+
(it "does not append default session info when not set"
629+
(with-temp-buffer
630+
(setq-local nrepl-endpoint '(:host "localhost" :port 4005))
631+
(setq-local nrepl-project-dir "proj")
632+
(setq-local cider-repl-type 'clj)
633+
(setq cider-default-session nil)
634+
(expect (cider--connection-info (current-buffer))
635+
:to-equal "CLJ proj@localhost:4005 (Java 1.7, Clojure 1.7.0, nREPL 0.2.1)")))))

0 commit comments

Comments
 (0)