mk / clerk-render-repl

2 stars 1 forks source link

Doc: Problems and Suggestions #1

Open benjamin-asdf opened 1 month ago

benjamin-asdf commented 1 month ago

The problem:

Cider connections (~= 'repl buffer') are either 'clj or cljs' connections. Cider needs to decide between them for each connection.

General approach 1: Specify up front whether it is cljs. General approach 2: Let cider discover whether clojurescript is present itself.

Suggested fix 1: Specify 'cljs' up front (approach 1)

  1. Config:

    (cider-register-cljs-repl-type 'sci-browser-nrepl)

  2. Run cider-jack-in-clj

  3. Run cider-connect-cljs, select host: localhost and port: 1339, and cljs repl type sci-browser-nrepl.

Or evaluate:

(cider-connect-cljs
 '(:host "localhost"
   :port 1339
   :cljs-repl-type sci-browser-nrepl))

Suggested fix 2: Discover cljs capability (approach 2)

  1. Config (as temp version, as long as it is not part of cider):
    (add-hook
     'cider-connected-hook
     (defun cider-sometimes-discover-cljs-capability (&optional conn-buffer)
       "Add clojurescript to `cider-connection-capabilities', if present.
    This is meant to be run together with `cider-connected-hook'
    and is a setup step for a cider connection.

    This way cider knows your repl has clojurescript capabilities, and it
    will be 'connected' to .cljs file buffers.

    "
       (with-current-buffer
           (or conn-buffer
               (current-buffer))
         (unless
             ;; ------------
             ;; Skip as optimization:
             ;; Making an eval request triggers load for cljs repls like shadow,
             ;; it's not needed to trigger it at this point.
             ;; ------------
             (or (eq cider-repl-type 'cljs)
                 (memq
                  'cljs
                  cider-connection-capabilities))
           (setf
            cider-connection-capabilities
            (append
             cider-connection-capabilities
             (pcase
                 (cider-runtime)
               ('clojure '())
               ('babashka '())
               ('nbb '())
               ('scittle '(cljs))
               (_
                ;; this is fast for sci / scittle kind of repls
                (when (cider-clojurescript-present-p)
                  '(cljs))))))))))
  1. Run cider-jack-in-clj (with dev alias)
  2. When the repl and browser are started, Run cider-connect-clj, enter 1339 when prompted for the port.

Note you use cider-connect-clj, not cider-connect-cljs, this is because we skip cljs setup flow and still mark the resulting connection as having clojurescript.

As a future step, this could be part of cider proper.

More background

Approach 2 is implemented in cider to some degree, but tied to 'nrepl version' (comes from the output of :describe ob). A few known repls are listed, but not sci nrepl.

Questions

Could things become more seamless by nesting having only one nREPL port like shadow-cljs does?

(but cider doesn't handle it automatically so well atm - visible by the 'listening on port' issue).

Potential future work:

benjamin-asdf commented 1 month ago

I looked into having a command as nice as 'jack in clj&cljs'.

Video of current state: https://github.com/user-attachments/assets/1f3298cc-89fb-4788-8037-c592a5f87d53

Current v1 is a bespoke command:

;; -*- lexical-binding: t; -*-

(defun clerk-render-repl-cider-jack-in-clj&cljs (&optional params)
  "A bespoke cider jack in for clerk-render-repl.
This waits for both nrepl servers to run and then jacks in a clj and a cljs nrepl."
  (interactive "P")
  (let* ((params (thread-first
                   params
                   (plist-put
                    :project-type 'clojure-cli)
                   (plist-put
                    :cljs-repl-type 'sci-browser-nrepl)))
         (cljs-endpoint '(:host "localhost" :port 1339))
         (params (cider--update-params params))
         (orig-buffer (current-buffer)))
    (nrepl-start-server-process
     (plist-get params :project-dir)
     (plist-get params :jack-in-cmd)
     (let ((clj-endpoint nil)
           (clj-endpoint-ready nil)
           (cljs-endpoint-ready nil))
       (lambda (server-buffer)
         (cond ((equal cljs-endpoint
                       nrepl-endpoint)
                (setf cljs-endpoint-ready t))
               (t
                (progn
                  (setf
                   clj-endpoint
                   nrepl-endpoint)
                  (setf clj-endpoint-ready t))))
         ;; ----------------------
         ;; signal that we are not done waiting,
         (setf nrepl-endpoint nil)
         ;; -----------------------
         (when (and cljs-endpoint-ready
                    clj-endpoint-ready)
           ;; ... until we are done waiting
           (setf nrepl-endpoint clj-endpoint)
           (with-current-buffer
               orig-buffer
             (let ((clj-repl (cider-connect-sibling-clj
                              params
                              server-buffer)))
               (cider-register-cljs-repl-type 'sci-browser-nrepl)
               ;; I think it first needed to open the browser or something,
               ;; it's possible you need to increase this
               ;; (symptom was that cider timed out with sync request 'describe op')
               (sit-for 1)
               (cider-connect-sibling-cljs
                (thread-first
                  params
                  (plist-put
                   :port (plist-get cljs-endpoint :port))
                  (plist-put
                   :host (plist-get cljs-endpoint :host)))
                clj-repl)))))))))
(let ((cider-clojure-cli-aliases ":dev"))
  (clerk-render-repl-cider-jack-in-clj&cljs))

This get's rid of the delay: https://github.com/benjamin-asdf/clerk-render-repl/blob/9f25b822411ffdb066e9bfa58ba94b25c1064590/dev/user.clj#L11

Idea: Make this part of cider, something line 'single process clj&cljs jack-in'

Idea: Connect with nrepl port files

repl

Does editor specify the connections (file names?) up front? doess editor wait for files to appear in 'nrepl/' and try to connect?
Should the file then contain additional info of how to connect?