branch: elpa/cider commit b2dd4a7d9def83d420424fcaf69fd791198a264b Author: lycheese <d...@lycheese.org> Commit: Bozhidar Batsov <bozhi...@batsov.dev>
Allow merging sesman sessions of a project - Makes cider-repls return the combination of all sesman sessions or those sessions with same host associated with a project - Adds a custom var for toggling the new functionality Closes clojure-emacs/cider#2946. --- CHANGELOG.md | 2 + cider-connection.el | 61 +++++++++++++++- .../ROOT/pages/usage/managing_connections.adoc | 18 ++++- test/cider-connection-tests.el | 84 ++++++++++++++++++++++ 4 files changed, 159 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d0d94ebee..7dc22ed4ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ JVM-specific code outside of JVM Clojure. * Do not always perform `undef-all`. Undef only with `C-u` prefix. * Fix extraction of namespace name. +* [#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 diff --git a/cider-connection.el b/cider-connection.el index 213c67f434..dace071292 100644 --- a/cider-connection.el +++ b/cider-connection.el @@ -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. + +Symbol `host' combines all sessions of a project associated with the same host. +Symbol `project' combines all sessions of a project. + +All other values do not combine any sessions." + :type 'symbol + :group 'cider + :safe #'symbolp + :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.") @@ -874,6 +887,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, @@ -883,9 +923,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) diff --git a/doc/modules/ROOT/pages/usage/managing_connections.adoc b/doc/modules/ROOT/pages/usage/managing_connections.adoc index 57d7c3699b..9b46b13401 100644 --- a/doc/modules/ROOT/pages/usage/managing_connections.adoc +++ b/doc/modules/ROOT/pages/usage/managing_connections.adoc @@ -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]) diff --git a/test/cider-connection-tests.el b/test/cider-connection-tests.el index bb0c3283e2..1ff79dd52c 100644 --- a/test/cider-connection-tests.el +++ b/test/cider-connection-tests.el @@ -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")))