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 223bf40
Show file tree
Hide file tree
Showing 4 changed files with 169 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-combine-sesman-sessions-per-project` to allow combining all sesman sessions associated with a project, therefore allowing for jacking-in a clojure-cli clj repl and a shadow-cljs cljs repl with separate dependency management and automatically using the correct repl even though the repls are in different sesman sessions. (CAUTION: If you are using two separate sessions for local and remote development setting this var to `true` will send all evaluated commands to *both* sessions. If this is functionality you need, use `cider-combine-sesman-sessions-per-project-per-host` instead which allows combining only those sessions which have the same host associated with them.)

## 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
28 changes: 25 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,33 @@ 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 by setting
`cider-combine-sesman-sessions-per-project` to a non-nil value. This has the
effect of dispatching to all relevant repls (i.e. all clj repls for a `.clj`
buffer) instead of just those associated with the current session. It is
recommended to set this as needed on a per-project basis in `.dir-locals.el`.
The downside of `cider-combine-sesman-sessions-per-project` is that dispatching
to separate local and remote sessions is no longer possible since all
project-associated sessions essentially become a single big session. Should this
behaviour be desired `cider-combine-sesman-sessions-per-project-per-host` can be
used instead. This var takes precedence over
`cider-combine-sesman-sessions-per-project` and only combines those sessions
which have the same host associated with them.
====

=== 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 223bf40

Please sign in to comment.