1310 lines
55 KiB
EmacsLisp
1310 lines
55 KiB
EmacsLisp
|
;;; cider.el --- Clojure Interactive Development Environment that Rocks -*- lexical-binding: t -*-
|
|||
|
|
|||
|
;; Copyright © 2012-2013 Tim King, Phil Hagelberg, Bozhidar Batsov
|
|||
|
;; Copyright © 2013-2018 Bozhidar Batsov, Artur Malabarba and CIDER contributors
|
|||
|
;;
|
|||
|
;; Author: Tim King <kingtim@gmail.com>
|
|||
|
;; Phil Hagelberg <technomancy@gmail.com>
|
|||
|
;; Bozhidar Batsov <bozhidar@batsov.com>
|
|||
|
;; Artur Malabarba <bruce.connor.am@gmail.com>
|
|||
|
;; Hugo Duncan <hugo@hugoduncan.org>
|
|||
|
;; Steve Purcell <steve@sanityinc.com>
|
|||
|
;; Maintainer: Bozhidar Batsov <bozhidar@batsov.com>
|
|||
|
;; URL: http://www.github.com/clojure-emacs/cider
|
|||
|
;; Version: 0.18.0-snapshot
|
|||
|
;; Package-Requires: ((emacs "25") (clojure-mode "5.7.0") (pkg-info "0.4") (queue "0.1.1") (spinner "1.7") (seq "2.16") (sesman "0.1.1"))
|
|||
|
;; Keywords: languages, clojure, cider
|
|||
|
|
|||
|
;; This program is free software: you can redistribute it and/or modify
|
|||
|
;; it under the terms of the GNU General Public License as published by
|
|||
|
;; the Free Software Foundation, either version 3 of the License, or
|
|||
|
;; (at your option) any later version.
|
|||
|
|
|||
|
;; This program is distributed in the hope that it will be useful,
|
|||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
;; GNU General Public License for more details.
|
|||
|
|
|||
|
;; You should have received a copy of the GNU General Public License
|
|||
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|
|||
|
;; This file is not part of GNU Emacs.
|
|||
|
|
|||
|
;;; Commentary:
|
|||
|
|
|||
|
;; Provides a Clojure interactive development environment for Emacs, built on
|
|||
|
;; top of nREPL.
|
|||
|
|
|||
|
;;; Installation:
|
|||
|
|
|||
|
;; Available as a package in melpa.org and stable.melpa.org
|
|||
|
|
|||
|
;; (add-to-list 'package-archives
|
|||
|
;; '("melpa" . "https://melpa.org/packages/"))
|
|||
|
;;
|
|||
|
;; or
|
|||
|
;;
|
|||
|
;; (add-to-list 'package-archives
|
|||
|
;; '("melpa-stable" . "https://stable.melpa.org/packages/") t)
|
|||
|
;;
|
|||
|
;; M-x package-install cider
|
|||
|
|
|||
|
;;; Usage:
|
|||
|
|
|||
|
;; M-x cider-jack-in-clj
|
|||
|
;; M-x cider-jack-in-cljs
|
|||
|
;;
|
|||
|
;; M-x cider-connect-sibling-clj
|
|||
|
;; M-x cider-connect-sibling-cljs
|
|||
|
;;
|
|||
|
;; M-x cider-connect-clj
|
|||
|
;; M-x cider-connect-cljs
|
|||
|
|
|||
|
;;; Code:
|
|||
|
|
|||
|
(defgroup cider nil
|
|||
|
"Clojure Interactive Development Environment that Rocks."
|
|||
|
:prefix "cider-"
|
|||
|
:group 'applications
|
|||
|
:link '(url-link :tag "GitHub" "https://github.com/clojure-emacs/cider")
|
|||
|
:link '(url-link :tag "Online Manual" "http://docs.cider.mx")
|
|||
|
:link '(emacs-commentary-link :tag "Commentary" "cider"))
|
|||
|
|
|||
|
(require 'cider-client)
|
|||
|
(require 'cider-eldoc)
|
|||
|
(require 'cider-repl)
|
|||
|
(require 'cider-repl-history)
|
|||
|
(require 'cider-connection)
|
|||
|
(require 'cider-mode)
|
|||
|
(require 'cider-common)
|
|||
|
(require 'cider-compat)
|
|||
|
(require 'cider-debug)
|
|||
|
|
|||
|
(require 'tramp-sh)
|
|||
|
(require 'subr-x)
|
|||
|
(require 'seq)
|
|||
|
(require 'sesman)
|
|||
|
|
|||
|
(defconst cider-version "0.18.0-snapshot"
|
|||
|
"Fallback version used when it cannot be extracted automatically.
|
|||
|
Normally it won't be used, unless `pkg-info' fails to extract the
|
|||
|
version from the CIDER package or library.")
|
|||
|
|
|||
|
(defconst cider-codename "Saigon"
|
|||
|
"Codename used to denote stable releases.")
|
|||
|
|
|||
|
(defcustom cider-lein-command
|
|||
|
"lein"
|
|||
|
"The command used to execute Leiningen."
|
|||
|
:type 'string
|
|||
|
:group 'cider)
|
|||
|
|
|||
|
(defcustom cider-lein-global-options
|
|||
|
nil
|
|||
|
"Command global options used to execute Leiningen (e.g.: -o for offline)."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp)
|
|||
|
|
|||
|
(defcustom cider-lein-parameters
|
|||
|
"repl :headless :host ::"
|
|||
|
"Params passed to Leiningen to start an nREPL server via `cider-jack-in'."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp)
|
|||
|
|
|||
|
(defcustom cider-boot-command
|
|||
|
"boot"
|
|||
|
"The command used to execute Boot."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:package-version '(cider . "0.9.0"))
|
|||
|
|
|||
|
(defcustom cider-boot-global-options
|
|||
|
nil
|
|||
|
"Command global options used to execute Boot (e.g.: -c for checkouts)."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.14.0"))
|
|||
|
|
|||
|
(defcustom cider-boot-parameters
|
|||
|
"repl -s -H :: wait"
|
|||
|
"Params passed to boot to start an nREPL server via `cider-jack-in'."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.9.0"))
|
|||
|
|
|||
|
(defcustom cider-clojure-cli-command
|
|||
|
"clojure"
|
|||
|
"The command used to execute clojure with tools.deps (requires Clojure 1.9+).
|
|||
|
Don't use clj here, as it doesn't work when spawned from Emacs due to
|
|||
|
it using rlwrap."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.17.0"))
|
|||
|
|
|||
|
(defcustom cider-clojure-cli-global-options
|
|||
|
nil
|
|||
|
"Command line options used to execute clojure with tools.deps."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.17.0"))
|
|||
|
|
|||
|
(defcustom cider-clojure-cli-parameters
|
|||
|
"-e '(require (quote cider-nrepl.main)) (cider-nrepl.main/init %s)'"
|
|||
|
"Params passed to clojure to start an nREPL server via `cider-jack-in'.
|
|||
|
This is evaluated using `format', with the first argument being the Clojure
|
|||
|
vector of middleware variables as a string."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.17.0"))
|
|||
|
|
|||
|
(defcustom cider-shadow-cljs-command
|
|||
|
"npx shadow-cljs"
|
|||
|
"The command used to execute shadow-cljs.
|
|||
|
|
|||
|
By default we favor the project-specific shadow-cljs over the system-wide."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.17.0"))
|
|||
|
|
|||
|
(defcustom cider-shadow-cljs-global-options
|
|||
|
""
|
|||
|
"Command line options used to execute shadow-cljs (e.g.: -v for verbose mode)."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.17.0"))
|
|||
|
|
|||
|
(defcustom cider-shadow-cljs-parameters
|
|||
|
"server"
|
|||
|
"Params passed to shadow-cljs to start an nREPL server via `cider-jack-in'."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.17.0"))
|
|||
|
|
|||
|
(defcustom cider-gradle-command
|
|||
|
"gradle"
|
|||
|
"The command used to execute Gradle."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.10.0"))
|
|||
|
|
|||
|
(defcustom cider-gradle-global-options
|
|||
|
"--no-daemon"
|
|||
|
"Command line options used to execute Gradle (e.g.: -m for dry run)."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.14.0"))
|
|||
|
|
|||
|
(defcustom cider-gradle-parameters
|
|||
|
"clojureRepl"
|
|||
|
"Params passed to gradle to start an nREPL server via `cider-jack-in'."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.10.0"))
|
|||
|
|
|||
|
(defcustom cider-default-repl-command "clojure-cli"
|
|||
|
"The default command and parameters to use when connecting to nREPL.
|
|||
|
This value will only be consulted when no identifying file types, i.e.
|
|||
|
project.clj for leiningen or build.boot for boot, could be found.
|
|||
|
|
|||
|
As tools.deps is bundled with Clojure itself, it's the default REPL command."
|
|||
|
:type 'string
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.9.0"))
|
|||
|
|
|||
|
(defcustom cider-preferred-build-tool
|
|||
|
nil
|
|||
|
"Allow choosing a build system when there are many.
|
|||
|
When there are artifacts from multiple build systems (\"lein\", \"boot\",
|
|||
|
\"gradle\") the user is prompted to select one of them. When non-nil, this
|
|||
|
variable will suppress this behavior and will select whatever build system
|
|||
|
is indicated by the variable if present. Note, this is only when CIDER
|
|||
|
cannot decide which of many build systems to use and will never override a
|
|||
|
command when there is no ambiguity."
|
|||
|
:type '(choice (const "lein")
|
|||
|
(const "boot")
|
|||
|
(const "clojure-cli")
|
|||
|
(const "shadow-cljs")
|
|||
|
(const "gradle")
|
|||
|
(const :tag "Always ask" nil))
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.13.0"))
|
|||
|
|
|||
|
(defcustom cider-allow-jack-in-without-project 'warn
|
|||
|
"Controls what happens when doing `cider-jack-in' outside a project.
|
|||
|
When set to 'warn you'd prompted to confirm the command.
|
|||
|
When set to t `cider-jack-in' will quietly continue.
|
|||
|
When set to nil `cider-jack-in' will fail."
|
|||
|
:type '(choice (const :tag "always" t)
|
|||
|
(const 'warn)
|
|||
|
(const :tag "never" nil))
|
|||
|
:group 'cider
|
|||
|
:safe #'stringp
|
|||
|
:package-version '(cider . "0.15.0"))
|
|||
|
|
|||
|
(defcustom cider-known-endpoints nil
|
|||
|
"A list of connection endpoints where each endpoint is a list.
|
|||
|
For example: \\='((\"label\" \"host\" \"port\")).
|
|||
|
The label is optional so that \\='(\"host\" \"port\") will suffice.
|
|||
|
This variable is used by `cider-connect'."
|
|||
|
:type '(repeat (list (string :tag "label")
|
|||
|
(string :tag "host")
|
|||
|
(string :tag "port")))
|
|||
|
:group 'cider)
|
|||
|
|
|||
|
(defcustom cider-connected-hook nil
|
|||
|
"List of functions to call when connected to Clojure nREPL server."
|
|||
|
:type 'hook
|
|||
|
:group 'cider
|
|||
|
:package-version '(cider . "0.9.0"))
|
|||
|
|
|||
|
(defcustom cider-disconnected-hook nil
|
|||
|
"List of functions to call when disconnected from the Clojure nREPL server."
|
|||
|
:type 'hook
|
|||
|
:group 'cider
|
|||
|
:package-version '(cider . "0.9.0"))
|
|||
|
|
|||
|
(defcustom cider-inject-dependencies-at-jack-in t
|
|||
|
"When nil, do not inject repl dependencies (most likely nREPL middlewares) at `cider-jack-in' time."
|
|||
|
:type 'boolean
|
|||
|
:safe #'booleanp
|
|||
|
:version '(cider . "0.11.0"))
|
|||
|
|
|||
|
(defcustom cider-offer-to-open-cljs-app-in-browser t
|
|||
|
"When nil, do not offer to open ClojureScript apps in a browser on connect."
|
|||
|
:type 'boolean
|
|||
|
:safe #'booleanp
|
|||
|
:version '(cider . "0.15.0"))
|
|||
|
|
|||
|
(defvar cider-ps-running-nrepls-command "ps u | grep leiningen"
|
|||
|
"Process snapshot command used in `cider-locate-running-nrepl-ports'.")
|
|||
|
|
|||
|
(defvar cider-ps-running-nrepl-path-regexp-list
|
|||
|
'("\\(?:leiningen.original.pwd=\\)\\(.+?\\) -D"
|
|||
|
"\\(?:-classpath +:?\\(.+?\\)/self-installs\\)")
|
|||
|
"Regexp list to get project paths.
|
|||
|
Extract project paths from output of `cider-ps-running-nrepls-command'.
|
|||
|
Sub-match 1 must be the project path.")
|
|||
|
|
|||
|
(defvar cider-host-history nil
|
|||
|
"Completion history for connection hosts.")
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-version ()
|
|||
|
"Display CIDER's version."
|
|||
|
(interactive)
|
|||
|
(message "CIDER %s" (cider--version)))
|
|||
|
|
|||
|
(defun cider-jack-in-command (project-type)
|
|||
|
"Determine the command `cider-jack-in' needs to invoke for the PROJECT-TYPE."
|
|||
|
(pcase project-type
|
|||
|
("lein" cider-lein-command)
|
|||
|
("boot" cider-boot-command)
|
|||
|
("clojure-cli" cider-clojure-cli-command)
|
|||
|
("shadow-cljs" cider-shadow-cljs-command)
|
|||
|
("gradle" cider-gradle-command)
|
|||
|
(_ (user-error "Unsupported project type `%s'" project-type))))
|
|||
|
|
|||
|
(defun cider-jack-in-resolve-command (project-type)
|
|||
|
"Determine the resolved file path to `cider-jack-in-command'.
|
|||
|
Throws an error if PROJECT-TYPE is unknown. Known types are
|
|||
|
\"lein\", \"boot\", and \"gradle\"."
|
|||
|
(pcase project-type
|
|||
|
("lein" (cider--resolve-command cider-lein-command))
|
|||
|
("boot" (cider--resolve-command cider-boot-command))
|
|||
|
("clojure-cli" (cider--resolve-command cider-clojure-cli-command))
|
|||
|
;; here we have to account for the possibility that the command is either
|
|||
|
;; "npx shadow-cljs" or just "shadow-cljs"
|
|||
|
("shadow-cljs" (let ((parts (split-string cider-shadow-cljs-command)))
|
|||
|
(when-let* ((command (cider--resolve-command (car parts))))
|
|||
|
(mapconcat #'identity (cons command (cdr parts)) " "))))
|
|||
|
("gradle" (cider--resolve-command cider-gradle-command))
|
|||
|
(_ (user-error "Unsupported project type `%s'" project-type))))
|
|||
|
|
|||
|
(defun cider-jack-in-global-options (project-type)
|
|||
|
"Determine the command line options for `cider-jack-in' for the PROJECT-TYPE."
|
|||
|
(pcase project-type
|
|||
|
("lein" cider-lein-global-options)
|
|||
|
("boot" cider-boot-global-options)
|
|||
|
("clojure-cli" cider-clojure-cli-global-options)
|
|||
|
("shadow-cljs" cider-shadow-cljs-global-options)
|
|||
|
("gradle" cider-gradle-global-options)
|
|||
|
(_ (user-error "Unsupported project type `%s'" project-type))))
|
|||
|
|
|||
|
(defun cider-jack-in-params (project-type)
|
|||
|
"Determine the commands params for `cider-jack-in' for the PROJECT-TYPE."
|
|||
|
(pcase project-type
|
|||
|
("lein" cider-lein-parameters)
|
|||
|
("boot" cider-boot-parameters)
|
|||
|
("clojure-cli" (format cider-clojure-cli-parameters
|
|||
|
(concat
|
|||
|
"["
|
|||
|
(mapconcat
|
|||
|
(apply-partially #'format "\"%s\"")
|
|||
|
(cider-jack-in-normalized-nrepl-middlewares)
|
|||
|
", ")
|
|||
|
"]")))
|
|||
|
("shadow-cljs" cider-shadow-cljs-parameters)
|
|||
|
("gradle" cider-gradle-parameters)
|
|||
|
(_ (user-error "Unsupported project type `%s'" project-type))))
|
|||
|
|
|||
|
|
|||
|
;;; Jack-in dependencies injection
|
|||
|
(defvar cider-jack-in-dependencies nil
|
|||
|
"List of dependencies where elements are lists of artifact name and version.")
|
|||
|
(put 'cider-jack-in-dependencies 'risky-local-variable t)
|
|||
|
(cider-add-to-alist 'cider-jack-in-dependencies
|
|||
|
"org.clojure/tools.nrepl" "0.2.13")
|
|||
|
|
|||
|
(defvar cider-jack-in-cljs-dependencies nil
|
|||
|
"List of dependencies where elements are lists of artifact name and version.
|
|||
|
Added to `cider-jack-in-dependencies' when doing `cider-jack-in-cljs'.")
|
|||
|
(put 'cider-jack-in-cljs-dependencies 'risky-local-variable t)
|
|||
|
(cider-add-to-alist 'cider-jack-in-cljs-dependencies "cider/piggieback" "0.3.5")
|
|||
|
|
|||
|
(defvar cider-jack-in-dependencies-exclusions nil
|
|||
|
"List of exclusions for jack in dependencies.
|
|||
|
Elements of the list are artifact name and list of exclusions to apply for the artifact.")
|
|||
|
(put 'cider-jack-in-dependencies-exclusions 'risky-local-variable t)
|
|||
|
(cider-add-to-alist 'cider-jack-in-dependencies-exclusions
|
|||
|
"org.clojure/tools.nrepl" '("org.clojure/clojure"))
|
|||
|
|
|||
|
(defconst cider-clojure-artifact-id "org.clojure/clojure"
|
|||
|
"Artifact identifier for Clojure.")
|
|||
|
|
|||
|
(defconst cider-minimum-clojure-version "1.8.0"
|
|||
|
"Minimum supported version of Clojure.")
|
|||
|
|
|||
|
(defconst cider-latest-clojure-version "1.10.0"
|
|||
|
"Latest supported version of Clojure.")
|
|||
|
|
|||
|
(defcustom cider-jack-in-auto-inject-clojure nil
|
|||
|
"Version of clojure to auto-inject into REPL.
|
|||
|
If nil, do not inject Clojure into the REPL. If `latest', inject
|
|||
|
`cider-latest-clojure-version', which should approximate to the most recent
|
|||
|
version of Clojure. If `minimal', inject `cider-minimum-clojure-version',
|
|||
|
which will be the lowest version CIDER supports. If a string, use this as
|
|||
|
the version number. If it is a list, the first element should be a string,
|
|||
|
specifying the artifact ID, and the second element the version number."
|
|||
|
:type '(choice (const :tag "None" nil)
|
|||
|
(const :tag "Latest" 'latest)
|
|||
|
(const :tag "Minimal" 'minimal)
|
|||
|
(string :tag "Specific Version")
|
|||
|
(list :tag "Artifact ID and Version"
|
|||
|
(string :tag "Artifact ID")
|
|||
|
(string :tag "Version"))))
|
|||
|
|
|||
|
(defvar cider-jack-in-lein-plugins nil
|
|||
|
"List of Leiningen plugins to be injected at jack-in.
|
|||
|
Each element is a list of artifact name and version, followed optionally by
|
|||
|
keyword arguments. The only keyword argument currently accepted is
|
|||
|
`:predicate', which should be given a function that takes the list (name,
|
|||
|
version, and keyword arguments) and returns non-nil to indicate that the
|
|||
|
plugin should actually be injected. (This is useful primarily for packages
|
|||
|
that extend CIDER, not for users. For example, a refactoring package might
|
|||
|
want to inject some middleware only when within a project context.)")
|
|||
|
(put 'cider-jack-in-lein-plugins 'risky-local-variable t)
|
|||
|
(cider-add-to-alist 'cider-jack-in-lein-plugins
|
|||
|
"cider/cider-nrepl" (upcase cider-version))
|
|||
|
|
|||
|
(defvar cider-jack-in-cljs-lein-plugins nil
|
|||
|
"List of Leiningen plugins to be injected at jack-in.
|
|||
|
Added to `cider-jack-in-lein-plugins' (which see) when doing
|
|||
|
`cider-jack-in-cljs'.")
|
|||
|
(put 'cider-jack-in-cljs-lein-plugins 'risky-local-variable t)
|
|||
|
|
|||
|
(defun cider-jack-in-normalized-lein-plugins ()
|
|||
|
"Return a normalized list of Leiningen plugins to be injected.
|
|||
|
See `cider-jack-in-lein-plugins' for the format, except that the list
|
|||
|
returned by this function does not include keyword arguments."
|
|||
|
(thread-last cider-jack-in-lein-plugins
|
|||
|
(seq-filter
|
|||
|
(lambda (spec)
|
|||
|
(if-let* ((pred (plist-get (seq-drop spec 2) :predicate)))
|
|||
|
(funcall pred spec)
|
|||
|
t)))
|
|||
|
(mapcar
|
|||
|
(lambda (spec)
|
|||
|
(seq-take spec 2)))))
|
|||
|
|
|||
|
(defvar cider-jack-in-nrepl-middlewares nil
|
|||
|
"List of Clojure variable names.
|
|||
|
Each of these Clojure variables should hold a vector of nREPL middlewares.
|
|||
|
Instead of a string, an element can be a list containing a string followed
|
|||
|
by optional keyword arguments. The only keyword argument currently
|
|||
|
accepted is `:predicate', which should be given a function that takes the
|
|||
|
list (string and keyword arguments) and returns non-nil to indicate that
|
|||
|
the middlewares should actually be injected.")
|
|||
|
(put 'cider-jack-in-nrepl-middlewares 'risky-local-variable t)
|
|||
|
(add-to-list 'cider-jack-in-nrepl-middlewares "cider.nrepl/cider-middleware")
|
|||
|
|
|||
|
(defvar cider-jack-in-cljs-nrepl-middlewares nil
|
|||
|
"List of Clojure variable names.
|
|||
|
Added to `cider-jack-in-nrepl-middlewares' (which see) when doing
|
|||
|
`cider-jack-in-cljs'.")
|
|||
|
(put 'cider-jack-in-cljs-nrepl-middlewares 'risky-local-variable t)
|
|||
|
(add-to-list 'cider-jack-in-cljs-nrepl-middlewares "cider.piggieback/wrap-cljs-repl")
|
|||
|
|
|||
|
(defun cider-jack-in-normalized-nrepl-middlewares ()
|
|||
|
"Return a normalized list of middleware variable names.
|
|||
|
See `cider-jack-in-nrepl-middlewares' for the format, except that the list
|
|||
|
returned by this function only contains strings."
|
|||
|
(thread-last cider-jack-in-nrepl-middlewares
|
|||
|
(seq-filter
|
|||
|
(lambda (spec)
|
|||
|
(or (not (listp spec))
|
|||
|
(if-let* ((pred (plist-get (cdr spec) :predicate)))
|
|||
|
(funcall pred spec)
|
|||
|
t))))
|
|||
|
(mapcar
|
|||
|
(lambda (spec)
|
|||
|
(if (listp spec)
|
|||
|
(car spec)
|
|||
|
spec)))))
|
|||
|
|
|||
|
(defun cider--list-as-boot-artifact (list)
|
|||
|
"Return a boot artifact string described by the elements of LIST.
|
|||
|
LIST should have the form (ARTIFACT-NAME ARTIFACT-VERSION). The returned
|
|||
|
string is quoted for passing as argument to an inferior shell."
|
|||
|
(concat "-d " (shell-quote-argument (format "%s:%s" (car list) (cadr list)))))
|
|||
|
|
|||
|
(defun cider-boot-dependencies (dependencies)
|
|||
|
"Return a list of boot artifact strings created from DEPENDENCIES."
|
|||
|
(concat (mapconcat #'cider--list-as-boot-artifact dependencies " ")
|
|||
|
(unless (seq-empty-p dependencies) " ")))
|
|||
|
|
|||
|
(defun cider-boot-middleware-task (params middlewares)
|
|||
|
"Create a command to add MIDDLEWARES with corresponding PARAMS."
|
|||
|
(concat "cider.tasks/add-middleware "
|
|||
|
(mapconcat (lambda (middleware)
|
|||
|
(format "-m %s" (shell-quote-argument middleware)))
|
|||
|
middlewares
|
|||
|
" ")
|
|||
|
" " params))
|
|||
|
|
|||
|
(defun cider-boot-jack-in-dependencies (global-opts params dependencies plugins middlewares)
|
|||
|
"Create boot jack-in dependencies.
|
|||
|
Does so by concatenating GLOBAL-OPTS, DEPENDENCIES,
|
|||
|
PLUGINS and MIDDLEWARES. PARAMS and MIDDLEWARES are passed on to
|
|||
|
`cider-boot-middleware-task` before concatenating and DEPENDENCIES and PLUGINS
|
|||
|
are passed on to `cider-boot-dependencies`."
|
|||
|
(concat global-opts
|
|||
|
(unless (seq-empty-p global-opts) " ")
|
|||
|
"-i \"(require 'cider.tasks)\" " ;; Note the space at the end here
|
|||
|
(cider-boot-dependencies (append dependencies plugins))
|
|||
|
(cider-boot-middleware-task params middlewares)))
|
|||
|
|
|||
|
(defun cider--lein-artifact-exclusions (exclusions)
|
|||
|
"Return an exclusions vector described by the elements of EXCLUSIONS."
|
|||
|
(if exclusions
|
|||
|
(format " :exclusions [%s]" (mapconcat #'identity exclusions " "))
|
|||
|
""))
|
|||
|
|
|||
|
(defun cider--list-as-lein-artifact (list &optional exclusions)
|
|||
|
"Return an artifact string described by the elements of LIST.
|
|||
|
LIST should have the form (ARTIFACT-NAME ARTIFACT-VERSION). Optionally a list
|
|||
|
of EXCLUSIONS can be provided as well. The returned
|
|||
|
string is quoted for passing as argument to an inferior shell."
|
|||
|
(shell-quote-argument (format "[%s %S%s]" (car list) (cadr list) (cider--lein-artifact-exclusions exclusions))))
|
|||
|
|
|||
|
(defun cider-lein-jack-in-dependencies (global-opts params dependencies dependencies-exclusions lein-plugins)
|
|||
|
"Create lein jack-in dependencies.
|
|||
|
Does so by concatenating GLOBAL-OPTS, DEPENDENCIES, with DEPENDENCIES-EXCLUSIONS
|
|||
|
removed, LEIN-PLUGINS, and finally PARAMS."
|
|||
|
(concat
|
|||
|
global-opts
|
|||
|
(unless (seq-empty-p global-opts) " ")
|
|||
|
(mapconcat #'identity
|
|||
|
(append (seq-map (lambda (dep)
|
|||
|
(let ((exclusions (cadr (assoc (car dep) dependencies-exclusions))))
|
|||
|
(concat "update-in :dependencies conj "
|
|||
|
(cider--list-as-lein-artifact dep exclusions))))
|
|||
|
dependencies)
|
|||
|
(seq-map (lambda (plugin)
|
|||
|
(concat "update-in :plugins conj "
|
|||
|
(cider--list-as-lein-artifact plugin)))
|
|||
|
lein-plugins))
|
|||
|
" -- ")
|
|||
|
" -- "
|
|||
|
params))
|
|||
|
|
|||
|
(defun cider-clojure-cli-jack-in-dependencies (global-opts params dependencies)
|
|||
|
"Create Clojure tools.deps jack-in dependencies.
|
|||
|
Does so by concatenating GLOBAL-OPTS, DEPENDENCIES finally PARAMS."
|
|||
|
(let ((dependencies (append dependencies cider-jack-in-lein-plugins)))
|
|||
|
(concat
|
|||
|
global-opts
|
|||
|
(unless (seq-empty-p global-opts) " ")
|
|||
|
"-Sdeps '{:deps {"
|
|||
|
(mapconcat #'identity
|
|||
|
(seq-map (lambda (dep) (format "%s {:mvn/version \"%s\"}" (car dep) (cadr dep))) dependencies)
|
|||
|
" ")
|
|||
|
"}}' "
|
|||
|
params)))
|
|||
|
|
|||
|
(defun cider-shadow-cljs-jack-in-dependencies (global-opts params dependencies)
|
|||
|
"Create shadow-cljs jack-in deps.
|
|||
|
Does so by concatenating GLOBAL-OPTS, DEPENDENCIES finally PARAMS."
|
|||
|
(let ((dependencies (append dependencies cider-jack-in-lein-plugins)))
|
|||
|
(concat
|
|||
|
global-opts
|
|||
|
(unless (seq-empty-p global-opts) " ")
|
|||
|
(mapconcat #'identity
|
|||
|
(seq-map (lambda (dep) (format "-d %s:%s" (car dep) (cadr dep))) dependencies)
|
|||
|
" ")
|
|||
|
" "
|
|||
|
params)))
|
|||
|
|
|||
|
(defun cider-add-clojure-dependencies-maybe (dependencies)
|
|||
|
"Return DEPENDENCIES with an added Clojure dependency if requested.
|
|||
|
See also `cider-jack-in-auto-inject-clojure'."
|
|||
|
(if cider-jack-in-auto-inject-clojure
|
|||
|
(if (consp cider-jack-in-auto-inject-clojure)
|
|||
|
(cons cider-jack-in-auto-inject-clojure dependencies)
|
|||
|
(cons (list cider-clojure-artifact-id
|
|||
|
(cond
|
|||
|
((stringp cider-jack-in-auto-inject-clojure)
|
|||
|
cider-jack-in-auto-inject-clojure)
|
|||
|
((eq cider-jack-in-auto-inject-clojure 'minimal)
|
|||
|
cider-minimum-clojure-version)
|
|||
|
((eq cider-jack-in-auto-inject-clojure 'latest)
|
|||
|
cider-latest-clojure-version)))
|
|||
|
dependencies))
|
|||
|
dependencies))
|
|||
|
|
|||
|
(defun cider-inject-jack-in-dependencies (global-opts params project-type)
|
|||
|
"Return GLOBAL-OPTS and PARAMS with injected REPL dependencies.
|
|||
|
These are set in `cider-jack-in-dependencies', `cider-jack-in-lein-plugins' and
|
|||
|
`cider-jack-in-nrepl-middlewares' are injected from the CLI according to
|
|||
|
the used PROJECT-TYPE. Eliminates the need for hacking profiles.clj or the
|
|||
|
boot script for supporting cider with its nREPL middleware and
|
|||
|
dependencies."
|
|||
|
(pcase project-type
|
|||
|
("lein" (cider-lein-jack-in-dependencies
|
|||
|
global-opts
|
|||
|
params
|
|||
|
(cider-add-clojure-dependencies-maybe
|
|||
|
cider-jack-in-dependencies)
|
|||
|
cider-jack-in-dependencies-exclusions
|
|||
|
(cider-jack-in-normalized-lein-plugins)))
|
|||
|
("boot" (cider-boot-jack-in-dependencies
|
|||
|
global-opts
|
|||
|
params
|
|||
|
(cider-add-clojure-dependencies-maybe
|
|||
|
cider-jack-in-dependencies)
|
|||
|
(cider-jack-in-normalized-lein-plugins)
|
|||
|
(cider-jack-in-normalized-nrepl-middlewares)))
|
|||
|
("clojure-cli" (cider-clojure-cli-jack-in-dependencies
|
|||
|
global-opts
|
|||
|
params
|
|||
|
(cider-add-clojure-dependencies-maybe
|
|||
|
cider-jack-in-dependencies)))
|
|||
|
("shadow-cljs" (cider-shadow-cljs-jack-in-dependencies
|
|||
|
global-opts
|
|||
|
params
|
|||
|
(cider-add-clojure-dependencies-maybe
|
|||
|
cider-jack-in-dependencies)))
|
|||
|
("gradle" (concat
|
|||
|
global-opts
|
|||
|
(unless (seq-empty-p global-opts) " ")
|
|||
|
params))
|
|||
|
(_ (error "Unsupported project type `%s'" project-type))))
|
|||
|
|
|||
|
|
|||
|
;;; ClojureScript REPL creation
|
|||
|
|
|||
|
(defcustom cider-check-cljs-repl-requirements t
|
|||
|
"When non-nil will run the requirement checks for the different cljs repls.
|
|||
|
Generally you should not disable this unless you run into some faulty check."
|
|||
|
:type 'boolean
|
|||
|
:safe #'booleanp
|
|||
|
:version '(cider . "0.17.0"))
|
|||
|
|
|||
|
(defun cider-verify-clojurescript-is-present ()
|
|||
|
"Check whether ClojureScript is present."
|
|||
|
(unless (cider-library-present-p "clojure/clojurescript")
|
|||
|
(user-error "ClojureScript is not available. See http://docs.cider.mx/en/latest/clojurescript for details")))
|
|||
|
|
|||
|
(defun cider-verify-piggieback-is-present ()
|
|||
|
"Check whether the piggieback middleware is present."
|
|||
|
(unless (cider-library-present-p "cider/piggieback")
|
|||
|
(user-error "Piggieback is not available. See http://docs.cider.mx/en/latest/clojurescript for details")))
|
|||
|
|
|||
|
(defun cider-check-nashorn-requirements ()
|
|||
|
"Check whether we can start a Nashorn ClojureScript REPL."
|
|||
|
(cider-verify-piggieback-is-present)
|
|||
|
(when (string-prefix-p "1.7" (cider--java-version))
|
|||
|
(user-error "Nashorn is supported only on Java 8 or newer")))
|
|||
|
|
|||
|
(defun cider-check-node-requirements ()
|
|||
|
"Check whether we can start a Node ClojureScript REPL."
|
|||
|
(cider-verify-piggieback-is-present)
|
|||
|
(unless (executable-find "node")
|
|||
|
(user-error "Node.js is not present on the exec-path. Make sure you've installed it and your exec-path is properly set")))
|
|||
|
|
|||
|
(defun cider-check-figwheel-requirements ()
|
|||
|
"Check whether we can start a Figwheel ClojureScript REPL."
|
|||
|
(cider-verify-piggieback-is-present)
|
|||
|
(unless (cider-library-present-p "figwheel-sidecar/figwheel-sidecar")
|
|||
|
(user-error "Figwheel-sidecar is not available. Please check http://docs.cider.mx/en/latest/clojurescript")))
|
|||
|
|
|||
|
(defun cider-check-figwheel-main-requirements ()
|
|||
|
"Check whether we can start a Figwheel ClojureScript REPL."
|
|||
|
(cider-verify-piggieback-is-present)
|
|||
|
(unless (cider-library-present-p "bhauman/figwheel-main")
|
|||
|
(user-error "Figwheel-main is not available. Please check http://docs.cider.mx/en/latest/clojurescript")))
|
|||
|
|
|||
|
(defun cider-check-weasel-requirements ()
|
|||
|
"Check whether we can start a Weasel ClojureScript REPL."
|
|||
|
(cider-verify-piggieback-is-present)
|
|||
|
(unless (cider-library-present-p "weasel/weasel")
|
|||
|
(user-error "Weasel in not available. Please check http://docs.cider.mx/en/latest/clojurescript/#browser-connected-clojurescript-repl")))
|
|||
|
|
|||
|
(defun cider-check-boot-requirements ()
|
|||
|
"Check whether we can start a Boot ClojureScript REPL."
|
|||
|
(cider-verify-piggieback-is-present)
|
|||
|
(unless (cider-library-present-p "adzerk/boot-cljs-repl")
|
|||
|
(user-error "The Boot ClojureScript REPL is not available. Please check https://github.com/adzerk-oss/boot-cljs-repl/blob/master/README.md")))
|
|||
|
|
|||
|
(defun cider-check-shadow-cljs-requirements ()
|
|||
|
"Check whether we can start a shadow-cljs REPL."
|
|||
|
(unless (cider-library-present-p "thheller/shadow-cljs")
|
|||
|
(user-error "The shadow-cljs ClojureScript REPL is not available")))
|
|||
|
|
|||
|
(defun cider-shadow-cljs-init-form ()
|
|||
|
"Generate the init form for a shadow-cljs REPL.
|
|||
|
We have to prompt the user to select a build, that's why
|
|||
|
this is a command, not just a string."
|
|||
|
(let ((form "(do (require '[shadow.cljs.devtools.api :as shadow]) (shadow/watch :%s) (shadow/nrepl-select :%s))")
|
|||
|
(build (string-remove-prefix ":" (read-from-minibuffer "Select shadow-cljs build: "))))
|
|||
|
(format form build build)))
|
|||
|
|
|||
|
(defcustom cider-figwheel-main-default-options nil
|
|||
|
"Defines the `figwheel.main/start' options.
|
|||
|
|
|||
|
Note that figwheel-main/start can also accept a map of options, refer to
|
|||
|
Figwheel for details."
|
|||
|
:type 'string
|
|||
|
:safe (lambda (s) (or (null s) (stringp s)))
|
|||
|
:package-version '(cider . "0.18.0"))
|
|||
|
|
|||
|
(defun cider-figwheel-main-init-form ()
|
|||
|
"Produce the figwheel-main ClojureScript init form."
|
|||
|
(let ((form "(do (require 'figwheel.main) (figwheel.main/start %s))")
|
|||
|
(options (or cider-figwheel-main-default-options
|
|||
|
(read-from-minibuffer "Select figwheel-main build: "))))
|
|||
|
(format form options)))
|
|||
|
|
|||
|
(defun cider-custom-cljs-repl-init-form ()
|
|||
|
"Prompt for a form that would start a ClojureScript REPL.
|
|||
|
The supplied string will be wrapped in a do form if needed."
|
|||
|
(let ((form (read-from-minibuffer "Please, provide a form to start a ClojureScript REPL: ")))
|
|||
|
;; TODO: We should probably make this more robust (e.g. by using a regexp or
|
|||
|
;; parsing the form).
|
|||
|
(if (string-prefix-p "(do" form)
|
|||
|
form
|
|||
|
(format "(do %s)" form))))
|
|||
|
|
|||
|
(defvar cider-cljs-repl-types
|
|||
|
'((nashorn "(do (require 'cljs.repl.nashorn) (cider.piggieback/cljs-repl (cljs.repl.nashorn/repl-env)))"
|
|||
|
cider-check-nashorn-requirements)
|
|||
|
(figwheel "(do (require 'figwheel-sidecar.repl-api) (figwheel-sidecar.repl-api/start-figwheel!) (figwheel-sidecar.repl-api/cljs-repl))"
|
|||
|
cider-check-figwheel-requirements)
|
|||
|
(figwheel-main cider-figwheel-main-init-form cider-check-figwheel-main-requirements)
|
|||
|
(node "(do (require 'cljs.repl.node) (cider.piggieback/cljs-repl (cljs.repl.node/repl-env)))"
|
|||
|
cider-check-node-requirements)
|
|||
|
(weasel "(do (require 'weasel.repl.websocket) (cider.piggieback/cljs-repl (weasel.repl.websocket/repl-env :ip \"127.0.0.1\" :port 9001)))"
|
|||
|
cider-check-weasel-requirements)
|
|||
|
(boot "(do (require 'adzerk.boot-cljs-repl) (adzerk.boot-cljs-repl/start-repl))"
|
|||
|
cider-check-boot-requirements)
|
|||
|
(shadow cider-shadow-cljs-init-form cider-check-shadow-cljs-requirements)
|
|||
|
(custom cider-custom-cljs-repl-init-form nil))
|
|||
|
"A list of supported ClojureScript REPLs.
|
|||
|
|
|||
|
For each one we have its name, the form we need to evaluate in a Clojure
|
|||
|
REPL to start the ClojureScript REPL and functions to very their requirements.
|
|||
|
|
|||
|
The form should be either a string or a function producing a string.")
|
|||
|
|
|||
|
(defun cider-register-cljs-repl-type (type init-form &optional requirements-fn)
|
|||
|
"Register a new ClojureScript REPL type.
|
|||
|
|
|||
|
Types are defined by the following:
|
|||
|
|
|||
|
- TYPE - symbol identifier that will be used to refer to the REPL type
|
|||
|
- INIT-FORM - string or function (symbol) producing string
|
|||
|
- REQUIREMENTS-FN - function to check whether the REPL can be started.
|
|||
|
This param is optional.
|
|||
|
|
|||
|
All this function does is modifying `cider-cljs-repl-types'.
|
|||
|
It's intended to be used in your Emacs config."
|
|||
|
(unless (symbolp type)
|
|||
|
(user-error "The REPL type must be a symbol"))
|
|||
|
(unless (or (stringp init-form) (symbolp init-form))
|
|||
|
(user-error "The init form must be a string or a symbol referring to a function"))
|
|||
|
(unless (or (null requirements-fn) (symbolp requirements-fn))
|
|||
|
(user-error "The requirements-fn must be a symbol referring to a function"))
|
|||
|
(add-to-list 'cider-cljs-repl-types (list type init-form requirements-fn)))
|
|||
|
|
|||
|
(defcustom cider-default-cljs-repl nil
|
|||
|
"The default ClojureScript REPL to start.
|
|||
|
This affects commands like `cider-jack-in-cljs'. Generally it's
|
|||
|
intended to be set via .dir-locals.el for individual projects, as its
|
|||
|
relatively unlikely you'd like to use the same type of REPL in each project
|
|||
|
you're working on."
|
|||
|
:type '(choice (const :tag "Nashorn" nashorn)
|
|||
|
(const :tag "Figwheel" figwheel)
|
|||
|
(const :tag "Node" node)
|
|||
|
(const :tag "Weasel" weasel)
|
|||
|
(const :tag "Boot" boot)
|
|||
|
(const :tag "Shadow" shadow)
|
|||
|
(const :tag "Custom" custom))
|
|||
|
:group 'cider
|
|||
|
:safe #'symbolp
|
|||
|
:package-version '(cider . "0.17.0"))
|
|||
|
|
|||
|
(make-obsolete-variable 'cider-cljs-lein-repl 'cider-default-cljs-repl "0.17")
|
|||
|
(make-obsolete-variable 'cider-cljs-boot-repl 'cider-default-cljs-repl "0.17")
|
|||
|
(make-obsolete-variable 'cider-cljs-gradle-repl 'cider-default-cljs-repl "0.17")
|
|||
|
|
|||
|
(defun cider-select-cljs-repl ()
|
|||
|
"Select the ClojureScript REPL to use with `cider-jack-in-cljs'."
|
|||
|
(let ((repl-types (mapcar #'car cider-cljs-repl-types)))
|
|||
|
(intern (completing-read "Select ClojureScript REPL type: " repl-types))))
|
|||
|
|
|||
|
(defun cider-cljs-repl-form (repl-type)
|
|||
|
"Get the cljs REPL form for REPL-TYPE."
|
|||
|
(if-let* ((repl-form (cadr (seq-find
|
|||
|
(lambda (entry)
|
|||
|
(eq (car entry) repl-type))
|
|||
|
cider-cljs-repl-types))))
|
|||
|
;; repl-form can be either a string or a function producing a string
|
|||
|
(if (symbolp repl-form)
|
|||
|
(funcall repl-form)
|
|||
|
repl-form)
|
|||
|
(user-error "No ClojureScript REPL type %s found. Please make sure that `cider-cljs-repl-types' has an entry for it" repl-type)))
|
|||
|
|
|||
|
(defun cider-verify-cljs-repl-requirements (&optional repl-type)
|
|||
|
"Verify that the requirements for REPL-TYPE are met.
|
|||
|
Return REPL-TYPE if requirements are met."
|
|||
|
(let ((repl-type (or repl-type
|
|||
|
cider-default-cljs-repl
|
|||
|
(cider-select-cljs-repl))))
|
|||
|
(when-let* ((fun (nth 2 (seq-find
|
|||
|
(lambda (entry)
|
|||
|
(eq (car entry) repl-type))
|
|||
|
cider-cljs-repl-types))))
|
|||
|
(funcall fun))
|
|||
|
repl-type))
|
|||
|
|
|||
|
(defun cider--check-cljs (&optional cljs-type no-error)
|
|||
|
"Verify that all cljs requirements are met for CLJS-TYPE connection.
|
|||
|
Return REPL-TYPE of requirement are met, and throw an ‘user-error’ otherwise.
|
|||
|
When NO-ERROR is non-nil, don't throw an error, issue a message and return
|
|||
|
nil."
|
|||
|
(if no-error
|
|||
|
(condition-case ex
|
|||
|
(progn
|
|||
|
(cider-verify-clojurescript-is-present)
|
|||
|
(cider-verify-cljs-repl-requirements cljs-type))
|
|||
|
(error
|
|||
|
(message "Invalid CLJS dependency: %S" ex)
|
|||
|
nil))
|
|||
|
(cider-verify-clojurescript-is-present)
|
|||
|
(cider-verify-cljs-repl-requirements cljs-type)))
|
|||
|
|
|||
|
(defun cider--offer-to-open-app-in-browser (server-buffer)
|
|||
|
"Look for a server address in SERVER-BUFFER and offer to open it."
|
|||
|
(when (buffer-live-p server-buffer)
|
|||
|
(with-current-buffer server-buffer
|
|||
|
(save-excursion
|
|||
|
(goto-char (point-min))
|
|||
|
(when-let* ((url (and (search-forward-regexp "http://localhost:[0-9]+" nil 'noerror)
|
|||
|
(match-string 0))))
|
|||
|
(when (y-or-n-p (format "Visit ‘%s’ in a browser? " url))
|
|||
|
(browse-url url)))))))
|
|||
|
|
|||
|
|
|||
|
;;; User Level Connectors
|
|||
|
|
|||
|
(defvar cider-start-map
|
|||
|
(let ((map (define-prefix-command 'cider-start-map)))
|
|||
|
(define-key map (kbd "j j") #'cider-jack-in-clj)
|
|||
|
(define-key map (kbd "j s") #'cider-jack-in-cljs)
|
|||
|
(define-key map (kbd "j m") #'cider-jack-in-clj&cljs)
|
|||
|
(define-key map (kbd "C-j j") #'cider-jack-in-clj)
|
|||
|
(define-key map (kbd "C-j s") #'cider-jack-in-cljs)
|
|||
|
(define-key map (kbd "C-j m") #'cider-jack-in-clj&cljs)
|
|||
|
(define-key map (kbd "C-j C-j") #'cider-jack-in-clj)
|
|||
|
(define-key map (kbd "C-j C-s") #'cider-jack-in-cljs)
|
|||
|
(define-key map (kbd "C-j C-m") #'cider-jack-in-clj&cljs)
|
|||
|
(define-key map (kbd "c j") #'cider-connect-clj)
|
|||
|
(define-key map (kbd "c s") #'cider-connect-cljs)
|
|||
|
(define-key map (kbd "c m") #'cider-connect-clj&cljs)
|
|||
|
(define-key map (kbd "C-c j") #'cider-connect-clj)
|
|||
|
(define-key map (kbd "C-c s") #'cider-connect-cljs)
|
|||
|
(define-key map (kbd "C-c m") #'cider-connect-clj&cljs)
|
|||
|
(define-key map (kbd "C-c C-j") #'cider-connect-clj)
|
|||
|
(define-key map (kbd "C-c C-s") #'cider-connect-cljs)
|
|||
|
(define-key map (kbd "C-c C-m") #'cider-connect-clj&cljs)
|
|||
|
(define-key map (kbd "s j") #'cider-connect-sibling-clj)
|
|||
|
(define-key map (kbd "s s") #'cider-connect-sibling-cljs)
|
|||
|
(define-key map (kbd "C-s j") #'cider-connect-sibling-clj)
|
|||
|
(define-key map (kbd "C-s s") #'cider-connect-sibling-cljs)
|
|||
|
(define-key map (kbd "C-s C-j") #'cider-connect-sibling-clj)
|
|||
|
(define-key map (kbd "C-s C-s") #'cider-connect-sibling-cljs)
|
|||
|
map)
|
|||
|
"CIDER jack-in and connect keymap.")
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-jack-in-clj (params)
|
|||
|
"Start an nREPL server for the current project and connect to it.
|
|||
|
PARAMS is a plist optionally containing :project-dir and :jack-in-cmd.
|
|||
|
With the prefix argument, prompt for all these parameters."
|
|||
|
(interactive "P")
|
|||
|
(let ((params (thread-first params
|
|||
|
(cider--update-project-dir)
|
|||
|
(cider--update-jack-in-cmd))))
|
|||
|
(nrepl-start-server-process
|
|||
|
(plist-get params :project-dir)
|
|||
|
(plist-get params :jack-in-cmd)
|
|||
|
(lambda (server-buffer)
|
|||
|
(cider-connect-sibling-clj params server-buffer)))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-jack-in-cljs (params)
|
|||
|
"Start an nREPL server for the current project and connect to it.
|
|||
|
PARAMS is a plist optionally containing :project-dir, :jack-in-cmd and
|
|||
|
:cljs-repl-type (e.g. Node, Figwheel, etc). With the prefix argument,
|
|||
|
prompt for all these parameters."
|
|||
|
(interactive "P")
|
|||
|
(let ((cider-jack-in-dependencies (append cider-jack-in-dependencies cider-jack-in-cljs-dependencies))
|
|||
|
(cider-jack-in-lein-plugins (append cider-jack-in-lein-plugins cider-jack-in-cljs-lein-plugins))
|
|||
|
(cider-jack-in-nrepl-middlewares (append cider-jack-in-nrepl-middlewares cider-jack-in-cljs-nrepl-middlewares))
|
|||
|
(params (thread-first params
|
|||
|
(cider--update-project-dir)
|
|||
|
(cider--update-jack-in-cmd))))
|
|||
|
(nrepl-start-server-process
|
|||
|
(plist-get params :project-dir)
|
|||
|
(plist-get params :jack-in-cmd)
|
|||
|
(lambda (server-buffer)
|
|||
|
(cider-connect-sibling-cljs params server-buffer)))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-jack-in-clj&cljs (&optional params soft-cljs-start)
|
|||
|
"Start an nREPL server and connect with clj and cljs REPLs.
|
|||
|
PARAMS is a plist optionally containing :project-dir, :jack-in-cmd and
|
|||
|
:cljs-repl-type (e.g. Node, Figwheel, etc). With the prefix argument,
|
|||
|
prompt for all these parameters. When SOFT-CLJS-START is non-nil, start
|
|||
|
cljs REPL only when the ClojureScript dependencies are met."
|
|||
|
(interactive "P")
|
|||
|
(let ((cider-jack-in-dependencies (append cider-jack-in-dependencies cider-jack-in-cljs-dependencies))
|
|||
|
(cider-jack-in-lein-plugins (append cider-jack-in-lein-plugins cider-jack-in-cljs-lein-plugins))
|
|||
|
(cider-jack-in-nrepl-middlewares (append cider-jack-in-nrepl-middlewares cider-jack-in-cljs-nrepl-middlewares))
|
|||
|
(params (thread-first params
|
|||
|
(cider--update-project-dir)
|
|||
|
(cider--update-jack-in-cmd)
|
|||
|
(cider--update-cljs-type)
|
|||
|
(plist-put :do-prompt nil))))
|
|||
|
(nrepl-start-server-process
|
|||
|
(plist-get params :project-dir)
|
|||
|
(plist-get params :jack-in-cmd)
|
|||
|
(lambda (server-buffer)
|
|||
|
(let ((clj-repl (cider-connect-sibling-clj params server-buffer)))
|
|||
|
(if soft-cljs-start
|
|||
|
(when (cider--check-cljs (plist-get params :cljs-repl-type) 'no-error)
|
|||
|
(cider-connect-sibling-cljs params clj-repl))
|
|||
|
(cider-connect-sibling-cljs params clj-repl)))))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-connect-sibling-clj (params &optional other-repl)
|
|||
|
"Create a Clojure REPL with the same server as OTHER-REPL.
|
|||
|
PARAMS is for consistency with other connection commands and is currently
|
|||
|
ignored. OTHER-REPL defaults to `cider-current-repl' and in programs can
|
|||
|
also be a server buffer, in which case a new session with a REPL for that
|
|||
|
server is created."
|
|||
|
(interactive "P")
|
|||
|
(cider-nrepl-connect
|
|||
|
(let* ((other-repl (or other-repl (cider-current-repl nil 'ensure)))
|
|||
|
(ses-name (unless (nrepl-server-p other-repl)
|
|||
|
(sesman-session-name-for-object 'CIDER other-repl))))
|
|||
|
(thread-first params
|
|||
|
(cider--update-do-prompt)
|
|||
|
(cider--gather-connect-params other-repl)
|
|||
|
(plist-put :repl-init-function nil)
|
|||
|
(plist-put :repl-type "clj")
|
|||
|
(plist-put :session-name ses-name)))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-connect-sibling-cljs (params &optional other-repl)
|
|||
|
"Create a ClojureScript REPL with the same server as OTHER-REPL.
|
|||
|
PARAMS is a plist optionally containing :cljs-repl-type (e.g. Node,
|
|||
|
Figwheel, etc). All other parameters are inferred from the OTHER-REPL.
|
|||
|
OTHER-REPL defaults to `cider-current-repl' but in programs can also be a
|
|||
|
server buffer, in which case a new session for that server is created."
|
|||
|
(interactive "P")
|
|||
|
(let* ((other-repl (or other-repl (cider-current-repl nil 'ensure)))
|
|||
|
(ses-name (unless (nrepl-server-p other-repl)
|
|||
|
(sesman-session-name-for-object 'CIDER other-repl))))
|
|||
|
(cider-nrepl-connect
|
|||
|
(thread-first params
|
|||
|
(cider--update-do-prompt)
|
|||
|
(cider--gather-connect-params other-repl)
|
|||
|
(cider--update-cljs-type)
|
|||
|
(cider--update-cljs-init-function)
|
|||
|
(plist-put :session-name ses-name)
|
|||
|
(plist-put :repl-type "cljs")))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-connect-clj (&optional params)
|
|||
|
"Initialize a CLJ connection to an nREPL server.
|
|||
|
PARAMS is a plist optionally containing :host, :port and :project-dir. On
|
|||
|
prefix argument, prompt for all the parameters."
|
|||
|
(interactive "P")
|
|||
|
(cider-nrepl-connect
|
|||
|
(thread-first params
|
|||
|
(cider--update-project-dir)
|
|||
|
(cider--update-host-port)
|
|||
|
(plist-put :repl-init-function nil)
|
|||
|
(plist-put :session-name nil)
|
|||
|
(plist-put :repl-type "clj"))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-connect-cljs (&optional params)
|
|||
|
"Initialize a CLJS connection to an nREPL server.
|
|||
|
PARAMS is a plist optionally containing :host, :port, :project-dir and
|
|||
|
:cljs-repl-type (e.g. Node, Figwheel, etc). On prefix, prompt for all the
|
|||
|
parameters regardless of their supplied or default values."
|
|||
|
(interactive "P")
|
|||
|
(cider-nrepl-connect
|
|||
|
(thread-first params
|
|||
|
(cider--update-project-dir)
|
|||
|
(cider--update-host-port)
|
|||
|
(cider--update-cljs-type)
|
|||
|
(cider--update-cljs-init-function)
|
|||
|
(plist-put :session-name nil)
|
|||
|
(plist-put :repl-type "cljs"))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider-connect-clj&cljs (params &optional soft-cljs-start)
|
|||
|
"Initialize a CLJ and CLJS connection to an nREPL server..
|
|||
|
PARAMS is a plist optionally containing :host, :port, :project-dir and
|
|||
|
:cljs-repl-type (e.g. Node, Figwheel, etc). When SOFT-CLJS-START is
|
|||
|
non-nil, don't start if ClojureScript requirements are not met."
|
|||
|
(interactive "P")
|
|||
|
(let* ((params (thread-first params
|
|||
|
(cider--update-project-dir)
|
|||
|
(cider--update-host-port)
|
|||
|
(cider--update-cljs-type)))
|
|||
|
(clj-repl (cider-connect-clj params)))
|
|||
|
(if soft-cljs-start
|
|||
|
(when (cider--check-cljs (plist-get params :cljs-repl-type) 'no-error)
|
|||
|
(cider-connect-sibling-cljs params clj-repl))
|
|||
|
(cider-connect-sibling-cljs params clj-repl))))
|
|||
|
|
|||
|
(defvar cider-connection-init-commands
|
|||
|
'(cider-jack-in-clj
|
|||
|
cider-jack-in-cljs
|
|||
|
cider-jack-in-clj&cljs
|
|||
|
cider-connect-clj
|
|||
|
cider-connect-cljs
|
|||
|
cider-connect-clj&cljs
|
|||
|
cider-connect-sibling-clj
|
|||
|
cider-connect-sibling-cljs)
|
|||
|
"A list of all user-level connection init commands in CIDER.")
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun cider ()
|
|||
|
"Start a connection of any type interactively."
|
|||
|
(interactive)
|
|||
|
(when-let* ((command (intern (completing-read "Select command: " cider-connection-init-commands))))
|
|||
|
(call-interactively command)))
|
|||
|
|
|||
|
|
|||
|
;;; PARAMS updating
|
|||
|
|
|||
|
(defun cider--update-do-prompt (params)
|
|||
|
"Update :do-prompt in PARAMS."
|
|||
|
(if (equal params '(4))
|
|||
|
(list :do-prompt t)
|
|||
|
params))
|
|||
|
|
|||
|
(defun cider--update-project-dir (params)
|
|||
|
"Update :project-dir in PARAMS."
|
|||
|
(let ((params (cider--update-do-prompt params)))
|
|||
|
(plist-put params :project-dir
|
|||
|
(if (plist-get params :do-prompt)
|
|||
|
(read-directory-name "Project: "
|
|||
|
(clojure-project-dir (cider-current-dir)))
|
|||
|
(or (plist-get params :project-dir)
|
|||
|
(clojure-project-dir (cider-current-dir)))))))
|
|||
|
|
|||
|
(defun cider--update-cljs-type (params)
|
|||
|
"Update :cljs-repl-type in PARAMS."
|
|||
|
(let ((params (cider--update-do-prompt params)))
|
|||
|
(plist-put params :cljs-repl-type
|
|||
|
(if (plist-get params :do-prompt)
|
|||
|
(cider-select-cljs-repl)
|
|||
|
(or (plist-get params :cljs-repl-type)
|
|||
|
cider-default-cljs-repl
|
|||
|
(cider-select-cljs-repl))))))
|
|||
|
|
|||
|
(defun cider--update-jack-in-cmd (params)
|
|||
|
"Update :jack-in-cmd key in PARAMS."
|
|||
|
(let* ((params (cider--update-do-prompt params))
|
|||
|
(project-dir (plist-get params :project-dir))
|
|||
|
(project-type (cider-project-type project-dir))
|
|||
|
(command (cider-jack-in-command project-type))
|
|||
|
(command-resolved (cider-jack-in-resolve-command project-type))
|
|||
|
(command-global-opts (cider-jack-in-global-options project-type))
|
|||
|
(command-params (cider-jack-in-params project-type)))
|
|||
|
(if command-resolved
|
|||
|
(let* ((command-params (if (plist-get params :do-prompt)
|
|||
|
(read-string (format "nREPL server command: %s " command-params)
|
|||
|
command-params)
|
|||
|
command-params))
|
|||
|
(cmd-params (if cider-inject-dependencies-at-jack-in
|
|||
|
(cider-inject-jack-in-dependencies command-global-opts command-params project-type)
|
|||
|
command-params)))
|
|||
|
(if (or project-dir cider-allow-jack-in-without-project)
|
|||
|
(when (or project-dir
|
|||
|
(eq cider-allow-jack-in-without-project t)
|
|||
|
(and (null project-dir)
|
|||
|
(eq cider-allow-jack-in-without-project 'warn)
|
|||
|
(y-or-n-p "Are you sure you want to run `cider-jack-in' without a Clojure project? ")))
|
|||
|
(let* ((cmd (format "%s %s" command-resolved cmd-params)))
|
|||
|
(plist-put params :jack-in-cmd cmd)))
|
|||
|
(user-error "`cider-jack-in' is not allowed without a Clojure project")))
|
|||
|
(user-error "The %s executable isn't on your `exec-path'" command))))
|
|||
|
|
|||
|
(defun cider--update-host-port (params)
|
|||
|
"Update :host and :port in PARAMS."
|
|||
|
(let* ((params (cider--update-do-prompt params))
|
|||
|
(host (plist-get params :host))
|
|||
|
(port (plist-get params :port))
|
|||
|
(endpoint (if (plist-get params :do-prompt)
|
|||
|
(cider-select-endpoint)
|
|||
|
(if (and host port)
|
|||
|
(cons host port)
|
|||
|
(cider-select-endpoint)))))
|
|||
|
(thread-first params
|
|||
|
(plist-put :host (car endpoint))
|
|||
|
(plist-put :port (cdr endpoint)))))
|
|||
|
|
|||
|
(defun cider--update-cljs-init-function (params)
|
|||
|
"Update PARAMS :repl-init-function for cljs connections."
|
|||
|
(let ((cljs-type (plist-get params :cljs-repl-type)))
|
|||
|
(plist-put params :repl-init-function
|
|||
|
(lambda ()
|
|||
|
(cider--check-cljs cljs-type)
|
|||
|
(cider-nrepl-send-request
|
|||
|
(list "op" "eval"
|
|||
|
"ns" (cider-current-ns)
|
|||
|
"code" (cider-cljs-repl-form cljs-type))
|
|||
|
(cider-repl-handler (current-buffer)))
|
|||
|
(when (and (buffer-live-p nrepl-server-buffer)
|
|||
|
cider-offer-to-open-cljs-app-in-browser)
|
|||
|
(cider--offer-to-open-app-in-browser nrepl-server-buffer))))))
|
|||
|
|
|||
|
|
|||
|
;;; Aliases
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defalias 'cider-jack-in #'cider-jack-in-clj)
|
|||
|
;;;###autoload
|
|||
|
(defalias 'cider-jack-in-clojure #'cider-jack-in-clj)
|
|||
|
;;;###autoload
|
|||
|
(defalias 'cider-jack-in-clojurescript #'cider-jack-in-cljs)
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defalias 'cider-connect #'cider-connect-clj)
|
|||
|
;;;###autoload
|
|||
|
(defalias 'cider-connect-clojure #'cider-connect-clj)
|
|||
|
;;;###autoload
|
|||
|
(defalias 'cider-connect-clojurescript #'cider-connect-cljs)
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defalias 'cider-connect-sibling-clojure #'cider-connect-sibling-clj)
|
|||
|
;;;###autoload
|
|||
|
(defalias 'cider-connect-sibling-clojurescript #'cider-connect-sibling-cljs)
|
|||
|
|
|||
|
|
|||
|
;;; Helpers
|
|||
|
|
|||
|
(defun cider-current-host ()
|
|||
|
"Retrieve the current host."
|
|||
|
(if (stringp buffer-file-name)
|
|||
|
(file-remote-p buffer-file-name 'host)
|
|||
|
"localhost"))
|
|||
|
|
|||
|
(defun cider-select-endpoint ()
|
|||
|
"Interactively select the host and port to connect to."
|
|||
|
(dolist (endpoint cider-known-endpoints)
|
|||
|
(unless (stringp (or (nth 2 endpoint)
|
|||
|
(nth 1 endpoint)))
|
|||
|
(user-error "The port for %s in `cider-known-endpoints' should be a string"
|
|||
|
(nth 0 endpoint))))
|
|||
|
(let* ((ssh-hosts (cider--ssh-hosts))
|
|||
|
(hosts (seq-uniq (append (when cider-host-history
|
|||
|
;; history elements are strings of the form "host:port"
|
|||
|
(list (split-string (car cider-host-history) ":")))
|
|||
|
(list (list (cider-current-host)))
|
|||
|
cider-known-endpoints
|
|||
|
ssh-hosts
|
|||
|
(when (file-remote-p default-directory)
|
|||
|
;; add localhost even in remote buffers
|
|||
|
'(("localhost"))))))
|
|||
|
(sel-host (cider--completing-read-host hosts))
|
|||
|
(host (car sel-host))
|
|||
|
(port (or (cadr sel-host)
|
|||
|
(cider--completing-read-port host (cider--infer-ports host ssh-hosts)))))
|
|||
|
(cons host port)))
|
|||
|
|
|||
|
(defun cider--ssh-hosts ()
|
|||
|
"Retrieve all ssh host from local configuration files."
|
|||
|
(seq-map (lambda (s) (list (replace-regexp-in-string ":$" "" s)))
|
|||
|
;; `tramp-completion-mode' is obsoleted in 26
|
|||
|
(cl-progv (if (version< emacs-version "26")
|
|||
|
'(tramp-completion-mode)
|
|||
|
'(non-essential)) '(t)
|
|||
|
(tramp-completion-handle-file-name-all-completions "" "/ssh:"))))
|
|||
|
|
|||
|
(defun cider--completing-read-host (hosts)
|
|||
|
"Interactively select host from HOSTS.
|
|||
|
Each element in HOSTS is one of: (host), (host port) or (label host port).
|
|||
|
Return a list of the form (HOST PORT), where PORT can be nil."
|
|||
|
(let* ((hosts (cider-join-into-alist hosts))
|
|||
|
(sel-host (completing-read "Host: " hosts nil nil nil
|
|||
|
'cider-host-history (caar hosts)))
|
|||
|
(host (or (cdr (assoc sel-host hosts)) (list sel-host))))
|
|||
|
;; remove the label
|
|||
|
(if (= 3 (length host)) (cdr host) host)))
|
|||
|
|
|||
|
(defun cider--infer-ports (host ssh-hosts)
|
|||
|
"Infer nREPL ports on HOST.
|
|||
|
Return a list of elements of the form (directory port). SSH-HOSTS is a list
|
|||
|
of remote SSH hosts."
|
|||
|
(let ((localp (or (nrepl-local-host-p host)
|
|||
|
(not (assoc-string host ssh-hosts)))))
|
|||
|
(if localp
|
|||
|
;; change dir: current file might be remote
|
|||
|
(let* ((change-dir-p (file-remote-p default-directory))
|
|||
|
(default-directory (if change-dir-p "~/" default-directory)))
|
|||
|
(cider-locate-running-nrepl-ports (unless change-dir-p default-directory)))
|
|||
|
(let ((vec (vector "sshx" nil host "" nil))
|
|||
|
;; change dir: user might want to connect to a different remote
|
|||
|
(dir (when (file-remote-p default-directory)
|
|||
|
(with-parsed-tramp-file-name default-directory cur
|
|||
|
(when (string= cur-host host) default-directory)))))
|
|||
|
(tramp-maybe-open-connection vec)
|
|||
|
(with-current-buffer (tramp-get-connection-buffer vec)
|
|||
|
(cider-locate-running-nrepl-ports dir))))))
|
|||
|
|
|||
|
(defun cider--completing-read-port (host ports)
|
|||
|
"Interactively select port for HOST from PORTS."
|
|||
|
(let* ((ports (cider-join-into-alist ports))
|
|||
|
(sel-port (completing-read (format "Port for %s: " host) ports
|
|||
|
nil nil nil nil (caar ports)))
|
|||
|
(port (or (cdr (assoc sel-port ports)) sel-port))
|
|||
|
(port (if (listp port) (cadr port) port)))
|
|||
|
(if (stringp port) (string-to-number port) port)))
|
|||
|
|
|||
|
(defun cider-locate-running-nrepl-ports (&optional dir)
|
|||
|
"Locate ports of running nREPL servers.
|
|||
|
When DIR is non-nil also look for nREPL port files in DIR. Return a list
|
|||
|
of list of the form (project-dir port)."
|
|||
|
(let* ((paths (cider--running-nrepl-paths))
|
|||
|
(proj-ports (mapcar (lambda (d)
|
|||
|
(when-let* ((port (and d (nrepl-extract-port (cider--file-path d)))))
|
|||
|
(list (file-name-nondirectory (directory-file-name d)) port)))
|
|||
|
(cons (clojure-project-dir dir) paths))))
|
|||
|
(seq-uniq (delq nil proj-ports))))
|
|||
|
|
|||
|
(defun cider--running-nrepl-paths ()
|
|||
|
"Retrieve project paths of running nREPL servers.
|
|||
|
Use `cider-ps-running-nrepls-command' and `cider-ps-running-nrepl-path-regexp-list'."
|
|||
|
(let (paths)
|
|||
|
(with-temp-buffer
|
|||
|
(insert (shell-command-to-string cider-ps-running-nrepls-command))
|
|||
|
(dolist (regexp cider-ps-running-nrepl-path-regexp-list)
|
|||
|
(goto-char 1)
|
|||
|
(while (re-search-forward regexp nil t)
|
|||
|
(setq paths (cons (match-string 1) paths)))))
|
|||
|
(seq-uniq paths)))
|
|||
|
|
|||
|
(defun cider--identify-buildtools-present (&optional project-dir)
|
|||
|
"Identify build systems present by their build files in PROJECT-DIR.
|
|||
|
PROJECT-DIR defaults to current project."
|
|||
|
(let* ((default-directory (or project-dir (clojure-project-dir (cider-current-dir))))
|
|||
|
(build-files '(("lein" . "project.clj")
|
|||
|
("boot" . "build.boot")
|
|||
|
("clojure-cli" . "deps.edn")
|
|||
|
("shadow-cljs" . "shadow-cljs.edn")
|
|||
|
("gradle" . "build.gradle"))))
|
|||
|
(delq nil
|
|||
|
(mapcar (lambda (candidate)
|
|||
|
(when (file-exists-p (cdr candidate))
|
|||
|
(car candidate)))
|
|||
|
build-files))))
|
|||
|
|
|||
|
(defun cider-project-type (&optional project-dir)
|
|||
|
"Determine the type of the project in PROJECT-DIR.
|
|||
|
When multiple project file markers are present, check for a preferred build
|
|||
|
tool in `cider-preferred-build-tool', otherwise prompt the user to choose.
|
|||
|
PROJECT-DIR defaults to the current project."
|
|||
|
(let* ((choices (cider--identify-buildtools-present project-dir))
|
|||
|
(multiple-project-choices (> (length choices) 1))
|
|||
|
(default (car choices)))
|
|||
|
(cond ((and multiple-project-choices
|
|||
|
(member cider-preferred-build-tool choices))
|
|||
|
cider-preferred-build-tool)
|
|||
|
(multiple-project-choices
|
|||
|
(completing-read (format "Which command should be used (default %s): " default)
|
|||
|
choices nil t nil nil default))
|
|||
|
(choices
|
|||
|
(car choices))
|
|||
|
(t cider-default-repl-command))))
|
|||
|
|
|||
|
|
|||
|
;; TODO: Implement a check for command presence over tramp
|
|||
|
(defun cider--resolve-command (command)
|
|||
|
"Find COMMAND in exec path (see variable `exec-path').
|
|||
|
Return nil if not found. In case `default-directory' is non-local we
|
|||
|
assume the command is available."
|
|||
|
(when-let* ((command (or (and (file-remote-p default-directory) command)
|
|||
|
(executable-find command)
|
|||
|
(executable-find (concat command ".bat")))))
|
|||
|
(shell-quote-argument command)))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(eval-after-load 'clojure-mode
|
|||
|
'(progn
|
|||
|
(define-key clojure-mode-map (kbd "C-c M-x") #'cider)
|
|||
|
(define-key clojure-mode-map (kbd "C-c M-j") #'cider-jack-in-clj)
|
|||
|
(define-key clojure-mode-map (kbd "C-c M-J") #'cider-jack-in-cljs)
|
|||
|
(define-key clojure-mode-map (kbd "C-c M-c") #'cider-connect-clj)
|
|||
|
(define-key clojure-mode-map (kbd "C-c M-C") #'cider-connect-cljs)
|
|||
|
(define-key clojure-mode-map (kbd "C-c C-x") 'cider-start-map)
|
|||
|
(define-key clojure-mode-map (kbd "C-c C-s") 'sesman-map)
|
|||
|
(require 'sesman)
|
|||
|
(sesman-install-menu clojure-mode-map)
|
|||
|
(add-hook 'clojure-mode-hook (lambda () (setq-local sesman-system 'CIDER)))))
|
|||
|
|
|||
|
(provide 'cider)
|
|||
|
|
|||
|
;;; cider.el ends here
|