Skip to content

Commit fc0c0c0

Browse files
committed
Move jack-in dispatch and user-level commands to cider-jack-in.el
Pull the rest of the jack-in core out of cider.el so cider-jack-in.el owns the jack-in subsystem end to end: - registry + dispatch: cider-jack-in-tools, cider-register-jack-in-tool, cider--jack-in-tool, cider--jack-in-tool-command, cider-jack-in-command, cider-jack-in-resolve-command, cider-jack-in-params. - built-in tool registrations for clojure-cli/lein/babashka/shadow-cljs/ gradle/nbb/basilisp. - command resolution: cider--resolve-command, cider--resolve-project-command, cider--resolve-prefix-command. - the cljs jack-in helper macro cider--with-cljs-jack-in-deps (moved here from cider-cljs.el since it's jack-in machinery that only happens to be cljs-flavored - all the vars it let-binds live in cider-jack-in.el). - user-level commands: cider--start-nrepl-server, cider-jack-in-clj, cider-start-nrepl-server, cider-jack-in-cljs, cider-jack-in-clj&cljs. cider-jack-in.el and cider-cljs.el now have no cross-requires; each is required independently by cider.el. cider-jack-in.el forward-declares the few symbols it reaches into cider.el for (cider--update-params, cider-connect-sibling-clj, cider-connect-sibling-cljs) and into cider-cljs.el (cider--update-cljs-type, cider--check-cljs). All these are resolved at runtime once cider.el has loaded its dependencies. The ;;;###autoload cookies on cider-jack-in-{clj,cljs,clj&cljs} are preserved, so M-x dispatch keeps working without explicit require. cider.el drops from 1413 to 1181 lines.
1 parent 417eafa commit fc0c0c0

3 files changed

Lines changed: 273 additions & 251 deletions

File tree

lisp/cider-cljs.el

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
(require 'clojure-mode)
4343

4444
(require 'cider-client)
45-
(require 'cider-jack-in)
4645
(require 'nrepl-dict)
4746

4847
;; Defined in cider.el; used by `cider--update-cljs-type'.
@@ -425,22 +424,6 @@ instead of specifying the :cljs-repl-type key."
425424
(or inferred-type
426425
(cider-select-cljs-repl)))))))
427426

428-
(defmacro cider--with-cljs-jack-in-deps (&rest body)
429-
"Run BODY with the cljs jack-in deps appended to the regular ones.
430-
`cider--update-jack-in-cmd' picks up these dynamic vars indirectly when
431-
constructing the jack-in command, so they must be in effect for the
432-
duration of the param-update pipeline."
433-
(declare (indent 0) (debug t))
434-
`(let ((cider-jack-in-dependencies
435-
(append cider-jack-in-dependencies cider-jack-in-cljs-dependencies))
436-
(cider-jack-in-lein-plugins
437-
(append cider-jack-in-lein-plugins cider-jack-in-cljs-lein-plugins))
438-
(cider-jack-in-nrepl-middlewares
439-
(append cider-jack-in-nrepl-middlewares cider-jack-in-cljs-nrepl-middlewares)))
440-
,@body))
441-
442-
(put 'cider--with-cljs-jack-in-deps 'lisp-indent-function 0)
443-
444427
(provide 'cider-cljs)
445428

446429
;;; cider-cljs.el ends here

lisp/cider-jack-in.el

Lines changed: 273 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
(require 'seq)
4444
(require 'subr-x)
4545

46+
(require 'clojure-mode)
47+
(require 'nrepl-client)
48+
4649
(require 'cider-util)
4750

4851
;; Defined in cider.el; declared here to keep cider-jack-in.el free of a
@@ -51,8 +54,15 @@
5154
(defvar cider-clojure-cli-aliases)
5255
(defvar cider-clojure-cli-global-aliases)
5356
(defvar cider-enable-nrepl-jvmti-agent)
54-
(defvar cider-jack-in-tools)
55-
(declare-function cider--jack-in-tool "cider")
57+
(declare-function cider--update-params "cider")
58+
(declare-function cider-connect-sibling-clj "cider")
59+
(declare-function cider-connect-sibling-cljs "cider")
60+
61+
;; Defined in cider-cljs.el; declared here because cider-cljs.el and
62+
;; cider-jack-in.el deliberately don't require each other (both are required
63+
;; by cider.el). By the time these are called, cider.el has loaded both.
64+
(declare-function cider--update-cljs-type "cider-cljs")
65+
(declare-function cider--check-cljs "cider-cljs")
5666

5767
(defvar cider-jack-in-dependencies nil
5868
"List of dependencies where elements are lists of artifact name and version.")
@@ -462,6 +472,267 @@ with its nREPL middleware and dependencies."
462472
(funcall inject params project-type command)
463473
params)))
464474

475+
476+
;;; Command resolution
477+
478+
(defun cider--resolve-command (command)
479+
"Find COMMAND in `exec-path', or on the remote host's PATH over TRAMP.
480+
Return the (shell-quoted) absolute path if found, otherwise nil. When
481+
`default-directory' is remote, `executable-find' is asked to search on
482+
that host instead of the local one."
483+
(let ((remote (file-remote-p default-directory)))
484+
(when-let* ((found (or (executable-find command remote)
485+
(executable-find (concat command ".bat") remote))))
486+
(shell-quote-argument found))))
487+
488+
(defun cider--resolve-project-command (command)
489+
"Find COMMAND in project dir or exec path (see variable `exec-path').
490+
If COMMAND starts with ./ or ../ resolve relative to `clojure-project-dir',
491+
otherwise resolve via `cider--resolve-command'."
492+
(if (string-match-p "\\`\\.\\{1,2\\}/" command)
493+
(locate-file command (list (clojure-project-dir)) '("" ".bat") 'executable)
494+
(cider--resolve-command command)))
495+
496+
(defun cider--resolve-prefix-command (command)
497+
"Resolve COMMAND that may be a prefixed invocation like \"npx X\".
498+
Splits COMMAND on whitespace, resolves the first token via
499+
`cider--resolve-command', and rejoins it with the remaining tokens."
500+
(let ((parts (split-string command)))
501+
(when-let* ((resolved (cider--resolve-command (car parts))))
502+
(mapconcat #'identity (cons resolved (cdr parts)) " "))))
503+
504+
505+
;;; Jack-in tool registry
506+
507+
(defvar cider-jack-in-tools nil
508+
"Alist of project tools known to `cider-jack-in'.
509+
Each entry has the form (PROJECT-TYPE . PLIST), where PLIST may contain:
510+
511+
- :command-var symbol of the variable holding the executable name.
512+
513+
- :params-var symbol of the variable holding the params string used to
514+
start the nREPL server.
515+
516+
- :project-files list of project marker file names.
517+
518+
- :resolver function of one argument (the command string) returning the
519+
resolved invocation, or nil to use `cider--resolve-command'.
520+
521+
- :inject-fn function of three arguments (PARAMS PROJECT-TYPE COMMAND)
522+
returning PARAMS with REPL deps injected. When nil, no injection is
523+
performed and PARAMS is used as-is.
524+
525+
- :universal-prefix-arg numeric prefix arg for `cider-jack-in-universal'.
526+
Tools without this key cannot be invoked via that command.
527+
528+
- :jack-in-type `clj' (the default) or `cljs'; controls which jack-in
529+
entry point `cider-jack-in-universal' calls.
530+
531+
- :cljs-repl-type cljs REPL type symbol, used when :jack-in-type is `cljs'.
532+
533+
Use `cider-register-jack-in-tool' to add or replace entries.")
534+
535+
(defun cider-register-jack-in-tool (project-type &rest plist)
536+
"Register PROJECT-TYPE in `cider-jack-in-tools'.
537+
PLIST is the property list documented in `cider-jack-in-tools'. An
538+
existing entry for PROJECT-TYPE is replaced."
539+
(setf (alist-get project-type cider-jack-in-tools) plist))
540+
541+
(defun cider--jack-in-tool (project-type)
542+
"Return the plist registered for PROJECT-TYPE.
543+
Signal a `user-error' if PROJECT-TYPE is not registered."
544+
(or (alist-get project-type cider-jack-in-tools)
545+
(user-error "Unsupported project type `%S'" project-type)))
546+
547+
(defun cider--jack-in-tool-command (spec)
548+
"Return the command for tool SPEC.
549+
Prefers a non-nil value of the :command-var, falling back to the result
550+
of :default-command-fn when the var is nil or unset. Returns nil if
551+
neither produces a value."
552+
(or (when-let* ((var (plist-get spec :command-var))) (symbol-value var))
553+
(when-let* ((fn (plist-get spec :default-command-fn))) (funcall fn))))
554+
555+
(defun cider-jack-in-command (project-type)
556+
"Determine the command `cider-jack-in' needs to invoke for the PROJECT-TYPE."
557+
(or (cider--jack-in-tool-command (cider--jack-in-tool project-type))
558+
(user-error "No command configured for project type `%S'" project-type)))
559+
560+
(defun cider-jack-in-resolve-command (project-type)
561+
"Determine the resolved file path to `cider-jack-in-command'.
562+
Throws an error if PROJECT-TYPE is unknown."
563+
(let* ((spec (cider--jack-in-tool project-type))
564+
(command (cider--jack-in-tool-command spec))
565+
(resolver (or (plist-get spec :resolver) #'cider--resolve-command)))
566+
(when command
567+
(funcall resolver command))))
568+
569+
(defun cider-jack-in-params (project-type)
570+
"Determine the commands params for `cider-jack-in' for the PROJECT-TYPE."
571+
;; The format of these command-line strings must consider different shells,
572+
;; different values of IFS, and the possibility that they'll be run remotely
573+
;; (e.g. with TRAMP). Using `", "` causes problems with TRAMP, for example.
574+
;; Please be careful when changing them.
575+
(symbol-value (plist-get (cider--jack-in-tool project-type) :params-var)))
576+
577+
578+
;;; Built-in jack-in tool registrations
579+
580+
(cider-register-jack-in-tool 'clojure-cli
581+
:command-var 'cider-clojure-cli-command
582+
:default-command-fn #'cider--default-clojure-cli-command
583+
:params-var 'cider-clojure-cli-parameters
584+
:project-files '("deps.edn")
585+
:inject-fn #'cider--clojure-cli-inject-deps
586+
:universal-prefix-arg 1)
587+
588+
(cider-register-jack-in-tool 'lein
589+
:command-var 'cider-lein-command
590+
:params-var 'cider-lein-parameters
591+
:project-files '("project.clj")
592+
:inject-fn #'cider--lein-inject-deps
593+
:universal-prefix-arg 2)
594+
595+
(cider-register-jack-in-tool 'babashka
596+
:command-var 'cider-babashka-command
597+
:params-var 'cider-babashka-parameters
598+
:project-files '("bb.edn")
599+
:universal-prefix-arg 3)
600+
601+
(cider-register-jack-in-tool 'shadow-cljs
602+
:command-var 'cider-shadow-cljs-command
603+
:params-var 'cider-shadow-cljs-parameters
604+
:project-files '("shadow-cljs.edn")
605+
:resolver #'cider--resolve-prefix-command
606+
:inject-fn #'cider--shadow-cljs-inject-deps)
607+
608+
(cider-register-jack-in-tool 'gradle
609+
:command-var 'cider-gradle-command
610+
:params-var 'cider-gradle-parameters
611+
:project-files '("build.gradle" "build.gradle.kts")
612+
:resolver #'cider--resolve-project-command
613+
:inject-fn #'cider--gradle-inject-deps)
614+
615+
(cider-register-jack-in-tool 'nbb
616+
:command-var 'cider-nbb-command
617+
:params-var 'cider-nbb-parameters
618+
:project-files '("nbb.edn")
619+
:resolver #'cider--resolve-prefix-command
620+
:universal-prefix-arg 4
621+
:jack-in-type 'cljs
622+
:cljs-repl-type 'nbb)
623+
624+
(cider-register-jack-in-tool 'basilisp
625+
:command-var 'cider-basilisp-command
626+
:params-var 'cider-basilisp-parameters
627+
:project-files '("basilisp.edn")
628+
:universal-prefix-arg 5)
629+
630+
631+
;;; ClojureScript jack-in helpers
632+
633+
(defmacro cider--with-cljs-jack-in-deps (&rest body)
634+
"Run BODY with the cljs jack-in deps appended to the regular ones.
635+
`cider--update-jack-in-cmd' picks up these dynamic vars indirectly when
636+
constructing the jack-in command, so they must be in effect for the
637+
duration of the param-update pipeline."
638+
(declare (indent 0) (debug t))
639+
`(let ((cider-jack-in-dependencies
640+
(append cider-jack-in-dependencies cider-jack-in-cljs-dependencies))
641+
(cider-jack-in-lein-plugins
642+
(append cider-jack-in-lein-plugins cider-jack-in-cljs-lein-plugins))
643+
(cider-jack-in-nrepl-middlewares
644+
(append cider-jack-in-nrepl-middlewares cider-jack-in-cljs-nrepl-middlewares)))
645+
,@body))
646+
647+
(put 'cider--with-cljs-jack-in-deps 'lisp-indent-function 0)
648+
649+
650+
;;; User-level Jack-in commands
651+
652+
(defun cider--start-nrepl-server (params &optional on-port-callback)
653+
"Start an nREPL server.
654+
PARAMS is a plist optionally containing :project-dir and :jack-in-cmd.
655+
ON-PORT-CALLBACK (optional) is a function of one argument (server buffer)
656+
which is called by the process filter once the port of the connection has
657+
been determined. The callback runs in the buffer that was current at the
658+
time of this call, so that subsequent connect logic sees the correct
659+
project context even if the user has switched buffers in the meantime."
660+
(let ((orig-buffer (current-buffer)))
661+
(nrepl-start-server-process
662+
(plist-get params :project-dir)
663+
(plist-get params :jack-in-cmd)
664+
(when on-port-callback
665+
(lambda (server-buf)
666+
(if (buffer-live-p orig-buffer)
667+
(with-current-buffer orig-buffer
668+
(funcall on-port-callback server-buf))
669+
(funcall on-port-callback server-buf)))))))
670+
671+
;;;###autoload
672+
(defun cider-jack-in-clj (params)
673+
"Start an nREPL server for the current project and connect to it.
674+
PARAMS is a plist optionally containing :project-dir and :jack-in-cmd.
675+
With the prefix argument, allow editing of the jack in command; with a
676+
double prefix prompt for all these parameters."
677+
(interactive "P")
678+
(let ((params (cider--update-params params)))
679+
(cider--start-nrepl-server
680+
params
681+
(lambda (server-buf)
682+
(cider-connect-sibling-clj params server-buf)))))
683+
684+
(defun cider-start-nrepl-server (params)
685+
"Start an nREPL server for the current project, but don't connect to it.
686+
PARAMS is a plist optionally containing :project-dir and :jack-in-cmd.
687+
With the prefix argument, allow editing of the start server command; with a
688+
double prefix prompt for all these parameters."
689+
(interactive "P")
690+
(cider--start-nrepl-server (cider--update-params params)))
691+
692+
;;;###autoload
693+
(defun cider-jack-in-cljs (params)
694+
"Start an nREPL server for the current project and connect to it.
695+
PARAMS is a plist optionally containing :project-dir, :jack-in-cmd and
696+
:cljs-repl-type (e.g. `shadow', `node', `figwheel', etc).
697+
698+
With the prefix argument,
699+
allow editing of the jack in command; with a double prefix prompt for all
700+
these parameters."
701+
(interactive "P")
702+
(cider--with-cljs-jack-in-deps
703+
(let ((params (cider--update-params params)))
704+
(cider--start-nrepl-server
705+
params
706+
(lambda (server-buf)
707+
(cider-connect-sibling-cljs params server-buf))))))
708+
709+
;;;###autoload
710+
(defun cider-jack-in-clj&cljs (&optional params soft-cljs-start)
711+
"Start an nREPL server and connect with clj and cljs REPLs.
712+
PARAMS is a plist optionally containing :project-dir, :jack-in-cmd and
713+
:cljs-repl-type (e.g. `shadow', `node', `figwheel', etc).
714+
715+
With the prefix argument, allow for editing of the jack in command;
716+
with a double prefix prompt for all these parameters.
717+
718+
When SOFT-CLJS-START is non-nil, start cljs REPL
719+
only when the ClojureScript dependencies are met."
720+
(interactive "P")
721+
(cider--with-cljs-jack-in-deps
722+
(let ((params (thread-first params
723+
(cider--update-params)
724+
(cider--update-cljs-type)
725+
;; already asked, don't ask on sibling connect
726+
(plist-put :do-prompt nil))))
727+
(cider--start-nrepl-server
728+
params
729+
(lambda (server-buf)
730+
(let ((clj-repl (cider-connect-sibling-clj params server-buf)))
731+
(if soft-cljs-start
732+
(when (cider--check-cljs (plist-get params :cljs-repl-type) 'no-error)
733+
(cider-connect-sibling-cljs params clj-repl))
734+
(cider-connect-sibling-cljs params clj-repl))))))))
735+
465736
(provide 'cider-jack-in)
466737

467738
;;; cider-jack-in.el ends here

0 commit comments

Comments
 (0)