|
54 | 54 | (defvar cider-clojure-cli-aliases) |
55 | 55 | (defvar cider-clojure-cli-global-aliases) |
56 | 56 | (defvar cider-enable-nrepl-jvmti-agent) |
| 57 | +(defvar cider-preferred-build-tool) |
| 58 | +(defvar cider-jack-in-default) |
57 | 59 | (declare-function cider--update-params "cider") |
58 | 60 | (declare-function cider-connect-sibling-clj "cider") |
59 | 61 | (declare-function cider-connect-sibling-cljs "cider") |
@@ -733,6 +735,120 @@ only when the ClojureScript dependencies are met." |
733 | 735 | (cider-connect-sibling-cljs params clj-repl)) |
734 | 736 | (cider-connect-sibling-cljs params clj-repl)))))))) |
735 | 737 |
|
| 738 | + |
| 739 | +;;; Project type detection and universal jack-in |
| 740 | + |
| 741 | +(defun cider--identify-buildtools-present (&optional project-dir) |
| 742 | + "Identify build systems present by their build files in PROJECT-DIR. |
| 743 | +PROJECT-DIR defaults to the current project. The set of recognized build |
| 744 | +files is derived from the :project-files entries in `cider-jack-in-tools'." |
| 745 | + (let ((default-directory (or project-dir (clojure-project-dir (cider-current-dir))))) |
| 746 | + (delq nil |
| 747 | + (mapcar (lambda (entry) |
| 748 | + (when (seq-some #'file-exists-p |
| 749 | + (plist-get (cdr entry) :project-files)) |
| 750 | + (car entry))) |
| 751 | + cider-jack-in-tools)))) |
| 752 | + |
| 753 | +(defun cider-project-type (&optional project-dir) |
| 754 | + "Determine the type of the project in PROJECT-DIR. |
| 755 | +When multiple project file markers are present, check for a preferred build |
| 756 | +tool in `cider-preferred-build-tool', otherwise prompt the user to choose. |
| 757 | +PROJECT-DIR defaults to the current project." |
| 758 | + (let* ((choices (cider--identify-buildtools-present project-dir)) |
| 759 | + (multiple-project-choices (> (length choices) 1)) |
| 760 | + ;; this needs to be a string to be used in `completing-read' |
| 761 | + (default (symbol-name (car choices))) |
| 762 | + ;; `cider-preferred-build-tool' used to be a string prior to CIDER |
| 763 | + ;; 0.18, therefore the need for `cider-maybe-intern' |
| 764 | + (preferred-build-tool (cider-maybe-intern cider-preferred-build-tool))) |
| 765 | + (cond ((and multiple-project-choices |
| 766 | + (member preferred-build-tool choices)) |
| 767 | + preferred-build-tool) |
| 768 | + (multiple-project-choices |
| 769 | + (intern |
| 770 | + (completing-read |
| 771 | + (format "Which command should be used (default %s): " default) |
| 772 | + choices nil t nil nil default))) |
| 773 | + (choices |
| 774 | + (car choices)) |
| 775 | + ;; If we're outside a project, fall back to the configured (or |
| 776 | + ;; auto-detected) default tool. `cider-jack-in-default' used to |
| 777 | + ;; be a string prior to CIDER 0.18, hence `cider-maybe-intern'. |
| 778 | + (t (cider--effective-jack-in-default))))) |
| 779 | + |
| 780 | +(defun cider--effective-jack-in-default () |
| 781 | + "Return `cider-jack-in-default', auto-detecting when nil. |
| 782 | +Auto-detect picks `clojure-cli' if \"clojure\" is on PATH at call time, |
| 783 | +otherwise `lein'." |
| 784 | + (or (cider-maybe-intern cider-jack-in-default) |
| 785 | + (if (and (not (file-remote-p default-directory)) |
| 786 | + (executable-find "clojure")) |
| 787 | + 'clojure-cli |
| 788 | + 'lein))) |
| 789 | + |
| 790 | +(defun cider--universal-jack-in-tools () |
| 791 | + "Return the subset of `cider-jack-in-tools' usable by `cider-jack-in-universal'. |
| 792 | +Each entry is a tool that has a :universal-prefix-arg." |
| 793 | + (seq-filter (lambda (entry) (plist-get (cdr entry) :universal-prefix-arg)) |
| 794 | + cider-jack-in-tools)) |
| 795 | + |
| 796 | +(defun cider--universal-jack-in-opts (project-type) |
| 797 | + "Build the params plist for `cider-jack-in-universal' for PROJECT-TYPE. |
| 798 | +The returned plist forces project dir editing and carries the cljs REPL |
| 799 | +type (when applicable) so the right entry point can dispatch." |
| 800 | + (let* ((spec (cider--jack-in-tool project-type)) |
| 801 | + (opts (list :project-type project-type :edit-project-dir t))) |
| 802 | + (when-let* ((cljs-type (plist-get spec :cljs-repl-type))) |
| 803 | + (setq opts (plist-put opts :cljs-repl-type cljs-type))) |
| 804 | + opts)) |
| 805 | + |
| 806 | +;;;###autoload |
| 807 | +(defun cider-jack-in-universal (arg) |
| 808 | + "Start and connect to an nREPL server for the current project or ARG project id. |
| 809 | +
|
| 810 | +If a project is found in current dir, call `cider-jack-in' passing ARG as |
| 811 | +first parameter, of which see. Otherwise, ask user which project type to |
| 812 | +start an nREPL server and connect to without a project. |
| 813 | +
|
| 814 | +But if invoked with a numeric prefix ARG, then start an nREPL server for |
| 815 | +the project type denoted by ARG number and connect to it, even if there is |
| 816 | +no project for it in the current dir. |
| 817 | +
|
| 818 | +The supported project tools are those in `cider-jack-in-tools' that have a |
| 819 | +:universal-prefix-arg key. |
| 820 | +
|
| 821 | +You can pass a numeric prefix argument n with `M-n` or `C-u n`. |
| 822 | +
|
| 823 | +For example, to jack in to leiningen which is assigned to prefix arg 2 type |
| 824 | +
|
| 825 | +M-2 \\[cider-jack-in-universal]." |
| 826 | + (interactive "P") |
| 827 | + (let ((cpt (clojure-project-dir (cider-current-dir)))) |
| 828 | + (if (or (integerp arg) (null cpt)) |
| 829 | + (let* ((tools (cider--universal-jack-in-tools)) |
| 830 | + (project-type |
| 831 | + (cond |
| 832 | + ((null arg) |
| 833 | + (intern (completing-read |
| 834 | + "No project found in current dir, select project type to jack in: " |
| 835 | + (mapcar #'car tools) nil t))) |
| 836 | + (t |
| 837 | + (or (car (seq-find (lambda (entry) |
| 838 | + (eql arg (plist-get (cdr entry) :universal-prefix-arg))) |
| 839 | + tools)) |
| 840 | + (error ":cider-jack-in-universal :unsupported-prefix-argument %S :no-such-project" |
| 841 | + arg))))) |
| 842 | + (opts (cider--universal-jack-in-opts project-type)) |
| 843 | + (jack-in-type (or (plist-get (cider--jack-in-tool project-type) :jack-in-type) |
| 844 | + 'clj))) |
| 845 | + (pcase jack-in-type |
| 846 | + ('clj (cider-jack-in-clj opts)) |
| 847 | + ('cljs (cider-jack-in-cljs opts)) |
| 848 | + (_ (error ":cider-jack-in-universal :jack-in-type-unsupported %S" jack-in-type)))) |
| 849 | + |
| 850 | + (cider-jack-in-clj arg)))) |
| 851 | + |
736 | 852 | (provide 'cider-jack-in) |
737 | 853 |
|
738 | 854 | ;;; cider-jack-in.el ends here |
0 commit comments