Skip to content

Commit

Permalink
Allow combining sesman sessions of a project
Browse files Browse the repository at this point in the history
- Makes cider-repls return the combination of all sesman sessions
  or those sessions with same host associated with a project
- Adds a custom vars for toggling the new functionality

Closes clojure-emacs#2946.
  • Loading branch information
lycheese committed May 28, 2022
1 parent 69d3748 commit 3ae7717
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

* [#3195](https://github.com/clojure-emacs/cider/issues/3195): Revert the change that resulted in `(error "Cyclic keymap inheritance")` on `cider-test-run-test`.

* [#2946](https://github.com/clojure-emacs/cider/issues/2946): Add custom var `cider-merge-sessions` to allow combining sessions in two different ways: Setting `cider-merge-sessions` to `:host` will merge all sessions associated with the same host within a project. Setting it to `:project` will combine all sessions of a project irrespective of their host.

## 1.4.0 (2022-05-02)

## New features
Expand Down
61 changes: 58 additions & 3 deletions cider-connection.el
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ available) and the matching REPL buffer."
:safe #'booleanp
:package-version '(cider . "0.9.0"))

;;;###autoload
(defcustom cider-merge-sessions nil
"Controls session combination behaviour.
`:host' combines all sessions of a project associated with the same host.
`:project' combines all sessions of a project.
All other values do not combine any sessions."
:type 'keyword
:group 'cider
:safe #'keywordp
:package-version '(cider . "1.5"))

(defconst cider-required-nrepl-version "0.6.0"
"The minimum nREPL version that's known to work properly with CIDER.")

Expand Down Expand Up @@ -862,6 +875,33 @@ no linked session or there is no REPL of TYPE within the current session."
((listp type) (member buffer-repl-type type))
(t (string= type buffer-repl-type)))))

(defun cider--get-host-from-session (session)
"Returns the host associated with SESSION."
(plist-get (cider--gather-session-params session)
:host))

(defun cider--make-sessions-list-with-hosts (sessions)
"Makes a list of SESSIONS and their hosts.
Returns a list of the form ((session1 host1) (session2 host2) ...)."
(mapcar (lambda (session)
(list session (cider--get-host-from-session session)))
sessions))

(defun cider--get-sessions-with-same-host (session sessions)
"Returns a list of SESSIONS with the same host as SESSION."
(mapcar #'car
(seq-filter (lambda (x)
(string-equal (cadr x)
(cider--get-host-from-session session)))
(cider--make-sessions-list-with-hosts sessions))))

(defun cider--extract-connections (sessions)
"Returns a flattened list of all session buffers in SESSIONS."
(cl-reduce (lambda (x y)
(append x (cdr y)))
sessions
:initial-value '()))

(defun cider-repls (&optional type ensure)
"Return cider REPLs of TYPE from the current session.
If TYPE is nil or multi, return all REPLs. If TYPE is a list of types,
Expand All @@ -871,9 +911,24 @@ throw an error if no linked session exists."
((listp type)
(mapcar #'cider-maybe-intern type))
((cider-maybe-intern type))))
(repls (cdr (if ensure
(sesman-ensure-session 'CIDER)
(sesman-current-session 'CIDER)))))
(repls (pcase cider-merge-sessions
(:host
(if ensure
(or (cider--extract-connections (cider--get-sessions-with-same-host
(sesman-current-session 'CIDER)
(sesman-current-sessions 'CIDER)))
(user-error "No linked %s sessions" 'CIDER))
(cider--extract-connections (cider--get-sessions-with-same-host
(sesman-current-session 'CIDER)
(sesman-current-sessions 'CIDER)))))
(:project
(if ensure
(or (cider--extract-connections (sesman-current-sessions 'CIDER))
(user-error "No linked %s sessions" 'CIDER))
(cider--extract-connections (sesman-current-sessions 'CIDER))))
(_ (cdr (if ensure
(sesman-ensure-session 'CIDER)
(sesman-current-session 'CIDER)))))))
(or (seq-filter (lambda (b)
(cider--match-repl-type type b))
repls)
Expand Down
18 changes: 15 additions & 3 deletions doc/modules/ROOT/pages/usage/managing_connections.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,23 @@ You can add new REPLs to the current session with:

A very common use-case would be to run `cider-jack-in-clj` for some project and then follow up with `cider-connect-sibling-cljs`.

NOTE: Unless there are both Clojure and ClojureScript REPLs in the same session smart-dispatch commands (e.g. evaluate the code
in the right Clojure/ClojureScript REPL, toggle between Clojure and ClojureScript REPL) won't work. A very common problem
newcomers experience is to create a Clojure REPL and a ClojureScript REPL in separate sessions and wonder why those are not
[NOTE]
====
Unless there are both Clojure and ClojureScript REPLs in the same
session smart-dispatch commands (e.g. evaluate the code in the right
Clojure/ClojureScript REPL, toggle between Clojure and ClojureScript REPL) won't
work. A very common problem newcomers experience is to create a Clojure REPL and
a ClojureScript REPL in separate sessions and wonder why those are not
interacting properly with one another.
In the case of using separate config files for the clj and cljs dependencies
(e.g. clj dependencies in `deps.edn` and cljs dependencies in `shadow-cljs.edn`)
it is currently impossible to group those two repls in the same session.
However, this can be worked around with `cider-merge-sessions`. Setting it to
`:host` will combine all sessions associated with the same host within a
project. Setting it to `:project` will combine all sessions in the same project.
====

=== Session Life-Cycle Management

Session life-cycle management commands live on the https://github.com/vspinu/sesman[Sesman] keymap (kbd:[C-c C-s])
Expand Down
84 changes: 84 additions & 0 deletions test/cider-connection-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,90 @@
(expect (cider-repls) :to-equal (list bb2 bb1))
(expect (cider-repls 'cljs) :to-equal (list bb2)))))))))))))

(describe "when multiple sessions exist and cider-merge-sessions is set to :project"
(it "always returns all connections associated with a project"
(let ((proj-dir (expand-file-name "/tmp/proj-dir"))
(cider-merge-sessions :project))
(let ((default-directory proj-dir))
(with-repl-buffer ses-name 'clj bb1
(with-repl-buffer ses-name 'cljs bb2
(with-repl-buffer ses-name2 'clj b1
(with-repl-buffer ses-name2 'cljs b2

(expect (cider-repls) :to-have-same-items-as (list b2 b1 bb2 bb1))

(switch-to-buffer bb1)
(expect (cider-repls) :to-have-same-items-as (list b2 b1 bb2 bb1))

;; follows type arguments
(expect (cider-repls 'clj) :to-have-same-items-as (list b1 bb1))
(expect (cider-repls 'cljs) :to-have-same-items-as (list b2 bb2))

(switch-to-buffer bb2)
;; follows file type
(with-temp-buffer
(setq major-mode 'clojure-mode)
(expect (cider-repls) :to-have-same-items-as (list b2 b1 bb2 bb1))
(expect (cider-repls 'clj) :to-have-same-items-as (list b1 bb1)))

(with-temp-buffer
(setq major-mode 'clojurescript-mode)
(expect (cider-repls) :to-have-same-items-as (list b2 b1 bb2 bb1))
(expect (cider-repls 'cljs) :to-have-same-items-as (list b2 bb2))))))))))
(it "only returns the connections of the active project"
(let ((a-dir (expand-file-name "/tmp/a-dir"))
(b-dir (expand-file-name "/tmp/b-dir"))
(cider-merge-sessions :project))
(let ((default-directory a-dir))
(with-repl-buffer ses-name 'clj bb1
(with-repl-buffer ses-name 'cljs bb2
(let ((default-directory b-dir))
(with-repl-buffer ses-name2 'clj b1
(with-repl-buffer ses-name2 'cljs b2

(expect (cider-repls) :to-have-same-items-as (list b2 b1))

(switch-to-buffer bb1)
(expect (cider-repls) :to-have-same-items-as (list bb2 bb1))

;; follows type arguments
(expect (cider-repls 'clj) :to-have-same-items-as (list bb1))
(expect (cider-repls 'cljs) :to-have-same-items-as (list bb2))

(switch-to-buffer bb2)
;; follows file type
(let ((default-directory b-dir))
(with-temp-buffer
(setq major-mode 'clojure-mode)
(expect (cider-repls) :to-have-same-items-as (list b2 b1))
(expect (cider-repls 'clj) :to-have-same-items-as (list b1))))

(let ((default-directory a-dir))
(with-temp-buffer
(setq major-mode 'clojurescript-mode)
(expect (cider-repls) :to-have-same-items-as (list bb2 bb1))
(expect (cider-repls 'cljs) :to-have-same-items-as (list bb2)))))))))))))

(describe "when multiple sessions exist and cider-combine-merge-sessions is set to :host"
(before-each
(spy-on 'cider--gather-session-params :and-call-fake (lambda (session)
(if (string-equal (car session) "local")
'(:host "localhost")
'(:host "remotehost")))))
(it "returns only the sessions associated with the current session's host"
(let ((cider-merge-sessions :host)
(local-session "local")
(remote-session "remote")
(proj-dir (expand-file-name "/tmp/proj-dir")))
(let ((default-directory proj-dir))
(with-repl-buffer local-session 'clj l1
(with-repl-buffer local-session 'clj l2
(with-repl-buffer remote-session 'clj r1
(switch-to-buffer r1)
(expect (cider-repls) :to-have-same-items-as (list r1))
(switch-to-buffer l1)
(expect (cider-repls) :to-have-same-items-as (list l1 l2)))))))))

(describe "killed buffers"
(it "do not show up in it"
(let ((default-directory (expand-file-name "/tmp/some-dir")))
Expand Down

0 comments on commit 3ae7717

Please sign in to comment.