Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2856 lines
107 KiB

4 years ago
  1. ;;; clojure-mode.el --- Major mode for Clojure code -*- lexical-binding: t; -*-
  2. ;; Copyright © 2007-2019 Jeffrey Chu, Lennart Staflin, Phil Hagelberg
  3. ;; Copyright © 2013-2019 Bozhidar Batsov, Artur Malabarba
  4. ;;
  5. ;; Authors: Jeffrey Chu <jochu0@gmail.com>
  6. ;; Lennart Staflin <lenst@lysator.liu.se>
  7. ;; Phil Hagelberg <technomancy@gmail.com>
  8. ;; Bozhidar Batsov <bozhidar@batsov.com>
  9. ;; Artur Malabarba <bruce.connor.am@gmail.com>
  10. ;; URL: http://github.com/clojure-emacs/clojure-mode
  11. ;; Package-Version: 20190725.654
  12. ;; Keywords: languages clojure clojurescript lisp
  13. ;; Version: 5.11.0
  14. ;; Package-Requires: ((emacs "25.1"))
  15. ;; This file is not part of GNU Emacs.
  16. ;;; Commentary:
  17. ;; Provides font-lock, indentation, navigation and basic refactoring for the
  18. ;; Clojure programming language (http://clojure.org).
  19. ;; Using clojure-mode with paredit or smartparens is highly recommended.
  20. ;; Here are some example configurations:
  21. ;; ;; require or autoload paredit-mode
  22. ;; (add-hook 'clojure-mode-hook #'paredit-mode)
  23. ;; ;; require or autoload smartparens
  24. ;; (add-hook 'clojure-mode-hook #'smartparens-strict-mode)
  25. ;; See inf-clojure (http://github.com/clojure-emacs/inf-clojure) for
  26. ;; basic interaction with Clojure subprocesses.
  27. ;; See CIDER (http://github.com/clojure-emacs/cider) for
  28. ;; better interaction with subprocesses via nREPL.
  29. ;;; License:
  30. ;; This program is free software; you can redistribute it and/or
  31. ;; modify it under the terms of the GNU General Public License
  32. ;; as published by the Free Software Foundation; either version 3
  33. ;; of the License, or (at your option) any later version.
  34. ;;
  35. ;; This program is distributed in the hope that it will be useful,
  36. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  37. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  38. ;; GNU General Public License for more details.
  39. ;;
  40. ;; You should have received a copy of the GNU General Public License
  41. ;; along with GNU Emacs; see the file COPYING. If not, write to the
  42. ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  43. ;; Boston, MA 02110-1301, USA.
  44. ;;; Code:
  45. (eval-when-compile
  46. (defvar calculate-lisp-indent-last-sexp)
  47. (defvar font-lock-beg)
  48. (defvar font-lock-end)
  49. (defvar paredit-space-for-delimiter-predicates)
  50. (defvar paredit-version)
  51. (defvar paredit-mode))
  52. (require 'cl-lib)
  53. (require 'imenu)
  54. (require 'newcomment)
  55. (require 'align)
  56. (require 'subr-x)
  57. (require 'lisp-mnt)
  58. (require 'project)
  59. (declare-function lisp-fill-paragraph "lisp-mode" (&optional justify))
  60. (defgroup clojure nil
  61. "Major mode for editing Clojure code."
  62. :prefix "clojure-"
  63. :group 'languages
  64. :link '(url-link :tag "GitHub" "https://github.com/clojure-emacs/clojure-mode")
  65. :link '(emacs-commentary-link :tag "Commentary" "clojure-mode"))
  66. (defconst clojure-mode-version
  67. (eval-when-compile
  68. (lm-version (or load-file-name buffer-file-name)))
  69. "The current version of `clojure-mode'.")
  70. (defface clojure-keyword-face
  71. '((t (:inherit font-lock-constant-face)))
  72. "Face used to font-lock Clojure keywords (:something)."
  73. :package-version '(clojure-mode . "3.0.0"))
  74. (defface clojure-character-face
  75. '((t (:inherit font-lock-string-face)))
  76. "Face used to font-lock Clojure character literals."
  77. :package-version '(clojure-mode . "3.0.0"))
  78. (defcustom clojure-indent-style 'always-align
  79. "Indentation style to use for function forms and macro forms.
  80. There are two cases of interest configured by this variable.
  81. - Case (A) is when at least one function argument is on the same
  82. line as the function name.
  83. - Case (B) is the opposite (no arguments are on the same line as
  84. the function name). Note that the body of macros is not
  85. affected by this variable, it is always indented by
  86. `lisp-body-indent' (default 2) spaces.
  87. Note that this variable configures the indentation of function
  88. forms (and function-like macros), it does not affect macros that
  89. already use special indentation rules.
  90. The possible values for this variable are keywords indicating how
  91. to indent function forms.
  92. `always-align' - Follow the same rules as `lisp-mode'. All
  93. args are vertically aligned with the first arg in case (A),
  94. and vertically aligned with the function name in case (B).
  95. For instance:
  96. (reduce merge
  97. some-coll)
  98. (reduce
  99. merge
  100. some-coll)
  101. `always-indent' - All args are indented like a macro body.
  102. (reduce merge
  103. some-coll)
  104. (reduce
  105. merge
  106. some-coll)
  107. `align-arguments' - Case (A) is indented like `lisp', and
  108. case (B) is indented like a macro body.
  109. (reduce merge
  110. some-coll)
  111. (reduce
  112. merge
  113. some-coll)"
  114. :safe #'symbolp
  115. :type '(choice (const :tag "Same as `lisp-mode'" 'always-align)
  116. (const :tag "Indent like a macro body" 'always-indent)
  117. (const :tag "Indent like a macro body unless first arg is on the same line"
  118. 'align-arguments))
  119. :package-version '(clojure-mode . "5.2.0"))
  120. (defcustom clojure-use-backtracking-indent t
  121. "When non-nil, enable context sensitive indentation."
  122. :type 'boolean
  123. :safe 'booleanp)
  124. (defcustom clojure-max-backtracking 3
  125. "Maximum amount to backtrack up a list to check for context."
  126. :type 'integer
  127. :safe 'integerp)
  128. (defcustom clojure-docstring-fill-column fill-column
  129. "Value of `fill-column' to use when filling a docstring."
  130. :type 'integer
  131. :safe 'integerp)
  132. (defcustom clojure-docstring-fill-prefix-width 2
  133. "Width of `fill-prefix' when filling a docstring.
  134. The default value conforms with the de facto convention for
  135. Clojure docstrings, aligning the second line with the opening
  136. double quotes on the third column."
  137. :type 'integer
  138. :safe 'integerp)
  139. (defcustom clojure-omit-space-between-tag-and-delimiters '(?\[ ?\{ ?\()
  140. "Allowed opening delimiter characters after a reader literal tag.
  141. For example, \[ is allowed in :db/id[:db.part/user]."
  142. :type '(set (const :tag "[" ?\[)
  143. (const :tag "{" ?\{)
  144. (const :tag "(" ?\()
  145. (const :tag "\"" ?\"))
  146. :safe (lambda (value)
  147. (and (listp value)
  148. (cl-every 'characterp value))))
  149. (defcustom clojure-build-tool-files
  150. '("project.clj" ; Leiningen
  151. "build.boot" ; Boot
  152. "build.gradle" ; Gradle
  153. "build.gradle.kts" ; Gradle
  154. "deps.edn" ; Clojure CLI (a.k.a. tools.deps)
  155. "shadow-cljs.edn" ; shadow-cljs
  156. )
  157. "A list of files, which identify a Clojure project's root.
  158. Out-of-the box `clojure-mode' understands lein, boot, gradle,
  159. shadow-cljs and tools.deps."
  160. :type '(repeat string)
  161. :package-version '(clojure-mode . "5.0.0")
  162. :safe (lambda (value)
  163. (and (listp value)
  164. (cl-every 'stringp value))))
  165. (defcustom clojure-project-root-function #'clojure-project-root-path
  166. "Function to locate clojure project root directory."
  167. :type 'function
  168. :risky t
  169. :package-version '(clojure-mode . "5.7.0"))
  170. (defcustom clojure-refactor-map-prefix (kbd "C-c C-r")
  171. "Clojure refactor keymap prefix."
  172. :type 'string
  173. :package-version '(clojure-mode . "5.6.0"))
  174. (defvar clojure-refactor-map
  175. (let ((map (make-sparse-keymap)))
  176. (define-key map (kbd "C-t") #'clojure-thread)
  177. (define-key map (kbd "t") #'clojure-thread)
  178. (define-key map (kbd "C-u") #'clojure-unwind)
  179. (define-key map (kbd "u") #'clojure-unwind)
  180. (define-key map (kbd "C-f") #'clojure-thread-first-all)
  181. (define-key map (kbd "f") #'clojure-thread-first-all)
  182. (define-key map (kbd "C-l") #'clojure-thread-last-all)
  183. (define-key map (kbd "l") #'clojure-thread-last-all)
  184. (define-key map (kbd "C-p") #'clojure-cycle-privacy)
  185. (define-key map (kbd "p") #'clojure-cycle-privacy)
  186. (define-key map (kbd "C-(") #'clojure-convert-collection-to-list)
  187. (define-key map (kbd "(") #'clojure-convert-collection-to-list)
  188. (define-key map (kbd "C-'") #'clojure-convert-collection-to-quoted-list)
  189. (define-key map (kbd "'") #'clojure-convert-collection-to-quoted-list)
  190. (define-key map (kbd "C-{") #'clojure-convert-collection-to-map)
  191. (define-key map (kbd "{") #'clojure-convert-collection-to-map)
  192. (define-key map (kbd "C-[") #'clojure-convert-collection-to-vector)
  193. (define-key map (kbd "[") #'clojure-convert-collection-to-vector)
  194. (define-key map (kbd "C-#") #'clojure-convert-collection-to-set)
  195. (define-key map (kbd "#") #'clojure-convert-collection-to-set)
  196. (define-key map (kbd "C-i") #'clojure-cycle-if)
  197. (define-key map (kbd "i") #'clojure-cycle-if)
  198. (define-key map (kbd "C-w") #'clojure-cycle-when)
  199. (define-key map (kbd "w") #'clojure-cycle-when)
  200. (define-key map (kbd "C-o") #'clojure-cycle-not)
  201. (define-key map (kbd "o") #'clojure-cycle-not)
  202. (define-key map (kbd "n i") #'clojure-insert-ns-form)
  203. (define-key map (kbd "n h") #'clojure-insert-ns-form-at-point)
  204. (define-key map (kbd "n u") #'clojure-update-ns)
  205. (define-key map (kbd "n s") #'clojure-sort-ns)
  206. (define-key map (kbd "n r") #'clojure-rename-ns-alias)
  207. (define-key map (kbd "s i") #'clojure-introduce-let)
  208. (define-key map (kbd "s m") #'clojure-move-to-let)
  209. (define-key map (kbd "s f") #'clojure-let-forward-slurp-sexp)
  210. (define-key map (kbd "s b") #'clojure-let-backward-slurp-sexp)
  211. (define-key map (kbd "C-a") #'clojure-add-arity)
  212. (define-key map (kbd "a") #'clojure-add-arity)
  213. map)
  214. "Keymap for Clojure refactoring commands.")
  215. (fset 'clojure-refactor-map clojure-refactor-map)
  216. (defvar clojure-mode-map
  217. (let ((map (make-sparse-keymap)))
  218. (set-keymap-parent map prog-mode-map)
  219. (define-key map (kbd "C-:") #'clojure-toggle-keyword-string)
  220. (define-key map (kbd "C-c SPC") #'clojure-align)
  221. (define-key map clojure-refactor-map-prefix 'clojure-refactor-map)
  222. (easy-menu-define clojure-mode-menu map "Clojure Mode Menu"
  223. '("Clojure"
  224. ["Toggle between string & keyword" clojure-toggle-keyword-string]
  225. ["Align expression" clojure-align]
  226. ["Cycle privacy" clojure-cycle-privacy]
  227. ["Cycle if, if-not" clojure-cycle-if]
  228. ["Cycle when, when-not" clojure-cycle-when]
  229. ["Cycle not" clojure-cycle-not]
  230. ["Add function arity" clojure-add-arity]
  231. ("ns forms"
  232. ["Insert ns form at the top" clojure-insert-ns-form]
  233. ["Insert ns form here" clojure-insert-ns-form-at-point]
  234. ["Update ns form" clojure-update-ns]
  235. ["Sort ns form" clojure-sort-ns]
  236. ["Rename ns alias" clojure-rename-ns-alias])
  237. ("Convert collection"
  238. ["Convert to list" clojure-convert-collection-to-list]
  239. ["Convert to quoted list" clojure-convert-collection-to-quoted-list]
  240. ["Convert to map" clojure-convert-collection-to-map]
  241. ["Convert to vector" clojure-convert-collection-to-vector]
  242. ["Convert to set" clojure-convert-collection-to-set])
  243. ("Refactor -> and ->>"
  244. ["Thread once more" clojure-thread]
  245. ["Fully thread a form with ->" clojure-thread-first-all]
  246. ["Fully thread a form with ->>" clojure-thread-last-all]
  247. "--"
  248. ["Unwind once" clojure-unwind]
  249. ["Fully unwind a threading macro" clojure-unwind-all])
  250. ("Let expression"
  251. ["Introduce let" clojure-introduce-let]
  252. ["Move to let" clojure-move-to-let]
  253. ["Forward slurp form into let" clojure-let-forward-slurp-sexp]
  254. ["Backward slurp form into let" clojure-let-backward-slurp-sexp])
  255. ("Documentation"
  256. ["View a Clojure guide" clojure-view-guide]
  257. ["View a Clojure reference section" clojure-view-reference-section]
  258. ["View the Clojure cheatsheet" clojure-view-cheatsheet]
  259. ["View the Clojure Grimoire" clojure-view-grimoire]
  260. ["View the Clojure style guide" clojure-view-style-guide])
  261. "--"
  262. ["Report a clojure-mode bug" clojure-mode-report-bug]
  263. ["Clojure-mode version" clojure-mode-display-version]))
  264. map)
  265. "Keymap for Clojure mode.")
  266. (defvar clojure-mode-syntax-table
  267. (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
  268. (modify-syntax-entry ?\{ "(}" table)
  269. (modify-syntax-entry ?\} "){" table)
  270. (modify-syntax-entry ?\[ "(]" table)
  271. (modify-syntax-entry ?\] ")[" table)
  272. (modify-syntax-entry ?? "_ p" table) ; ? is a prefix outside symbols
  273. (modify-syntax-entry ?# "_ p" table) ; # is allowed inside keywords (#399)
  274. (modify-syntax-entry ?~ "'" table)
  275. (modify-syntax-entry ?^ "'" table)
  276. (modify-syntax-entry ?@ "'" table)
  277. table)
  278. "Syntax table for Clojure mode.
  279. Inherits from `emacs-lisp-mode-syntax-table'.")
  280. (defconst clojure--prettify-symbols-alist
  281. '(("fn" . )))
  282. (defvar-local clojure-expected-ns-function nil
  283. "The function used to determine the expected namespace of a file.
  284. `clojure-mode' ships a basic function named `clojure-expected-ns'
  285. that does basic heuristics to figure this out.
  286. CIDER provides a more complex version which does classpath analysis.")
  287. (defun clojure-mode-display-version ()
  288. "Display the current `clojure-mode-version' in the minibuffer."
  289. (interactive)
  290. (message "clojure-mode (version %s)" clojure-mode-version))
  291. (defconst clojure-mode-report-bug-url "https://github.com/clojure-emacs/clojure-mode/issues/new"
  292. "The URL to report a `clojure-mode' issue.")
  293. (defun clojure-mode-report-bug ()
  294. "Report a bug in your default browser."
  295. (interactive)
  296. (browse-url clojure-mode-report-bug-url))
  297. (defconst clojure-guides-base-url "https://clojure.org/guides/"
  298. "The base URL for official Clojure guides.")
  299. (defconst clojure-guides '(("Getting Started" . "getting_started")
  300. ("FAQ" . "faq")
  301. ("spec" . "spec")
  302. ("Destructuring" . "destructuring")
  303. ("Threading Macros" . "threading_macros")
  304. ("Comparators" . "comparators")
  305. ("Reader Conditionals" . "reader_conditionals"))
  306. "A list of all official Clojure guides.")
  307. (defun clojure-view-guide ()
  308. "Open a Clojure guide in your default browser.
  309. The command will prompt you to select one of the available guides."
  310. (interactive)
  311. (let ((guide (completing-read "Select a guide: " (mapcar #'car clojure-guides))))
  312. (when guide
  313. (let ((guide-url (concat clojure-guides-base-url (cdr (assoc guide clojure-guides)))))
  314. (browse-url guide-url)))))
  315. (defconst clojure-reference-base-url "https://clojure.org/reference/"
  316. "The base URL for the official Clojure reference.")
  317. (defconst clojure-reference-sections '(("The Reader" . "reader")
  318. ("The REPL and main" . "repl_and_main")
  319. ("Evaluation" . "evaluation")
  320. ("Special Forms" . "special_forms")
  321. ("Macros" . "macros")
  322. ("Other Functions" . "other_functions")
  323. ("Data Structures" . "data_structures")
  324. ("Datatypes" . "datatypes")
  325. ("Sequences" . "sequences")
  326. ("Transients" . "transients")
  327. ("Transducers" . "transducers")
  328. ("Multimethods and Hierarchies" . "multimethods")
  329. ("Protocols" . "protocols")
  330. ("Metadata" . "metadata")
  331. ("Namespaces" . "namespaces")
  332. ("Libs" . "libs")
  333. ("Vars and Environments" . "vars")
  334. ("Refs and Transactions" . "refs")
  335. ("Agents" . "agents")
  336. ("Atoms" . "atoms")
  337. ("Reducers" . "reducers")
  338. ("Java Interop" . "java_interop")
  339. ("Compilation and Class Generation" . "compilation")
  340. ("Other Libraries" . "other_libraries")
  341. ("Differences with Lisps" . "lisps")))
  342. (defun clojure-view-reference-section ()
  343. "Open a Clojure reference section in your default browser.
  344. The command will prompt you to select one of the available sections."
  345. (interactive)
  346. (let ((section (completing-read "Select a reference section: " (mapcar #'car clojure-reference-sections))))
  347. (when section
  348. (let ((section-url (concat clojure-reference-base-url (cdr (assoc section clojure-reference-sections)))))
  349. (browse-url section-url)))))
  350. (defconst clojure-cheatsheet-url "https://clojure.org/api/cheatsheet"
  351. "The URL of the official Clojure cheatsheet.")
  352. (defun clojure-view-cheatsheet ()
  353. "Open the Clojure cheatsheet in your default browser."
  354. (interactive)
  355. (browse-url clojure-cheatsheet-url))
  356. (defconst clojure-grimoire-url "https://www.conj.io/"
  357. "The URL of the Grimoire community documentation site.")
  358. (defun clojure-view-grimoire ()
  359. "Open the Clojure Grimoire in your default browser."
  360. (interactive)
  361. (browse-url clojure-grimoire-url))
  362. (defconst clojure-style-guide-url "https://github.com/bbatsov/clojure-style-guide"
  363. "The URL of the Clojure style guide.")
  364. (defun clojure-view-style-guide ()
  365. "Open the Clojure style guide in your default browser."
  366. (interactive)
  367. (browse-url clojure-style-guide-url))
  368. (defun clojure-space-for-delimiter-p (endp delim)
  369. "Prevent paredit from inserting useless spaces.
  370. See `paredit-space-for-delimiter-predicates' for the meaning of
  371. ENDP and DELIM."
  372. (or endp
  373. (not (memq delim '(?\" ?{ ?\( )))
  374. (not (or (derived-mode-p 'clojure-mode)
  375. (derived-mode-p 'cider-repl-mode)))
  376. (save-excursion
  377. (backward-char)
  378. (cond ((eq (char-after) ?#)
  379. (and (not (bobp))
  380. (or (char-equal ?w (char-syntax (char-before)))
  381. (char-equal ?_ (char-syntax (char-before))))))
  382. ((and (eq delim ?\()
  383. (eq (char-after) ??)
  384. (eq (char-before) ?#))
  385. nil)
  386. (t)))))
  387. (defconst clojure--collection-tag-regexp "#\\(::[a-zA-Z0-9._-]*\\|:?\\([a-zA-Z0-9._-]+/\\)?[a-zA-Z0-9._-]+\\)"
  388. "Collection reader macro tag regexp.
  389. It is intended to check for allowed strings that can come before a
  390. collection literal (e.g. '[]' or '{}'), as reader macro tags.
  391. This includes #fully.qualified/my-ns[:kw val] and #::my-ns{:kw
  392. val} as of Clojure 1.9.")
  393. (defun clojure-no-space-after-tag (endp delimiter)
  394. "Prevent inserting a space after a reader-literal tag.
  395. When a reader-literal tag is followed be an opening delimiter
  396. listed in `clojure-omit-space-between-tag-and-delimiters', this
  397. function returns t.
  398. This allows you to write things like #db/id[:db.part/user]
  399. and #::my-ns{:some \"map\"} without inserting a space between
  400. the tag and the opening bracket.
  401. See `paredit-space-for-delimiter-predicates' for the meaning of
  402. ENDP and DELIMITER."
  403. (if endp
  404. t
  405. (or (not (member delimiter clojure-omit-space-between-tag-and-delimiters))
  406. (save-excursion
  407. (let ((orig-point (point)))
  408. (not (and (re-search-backward
  409. clojure--collection-tag-regexp
  410. (line-beginning-position)
  411. t)
  412. (= orig-point (match-end 0)))))))))
  413. (declare-function paredit-open-curly "ext:paredit" t t)
  414. (declare-function paredit-close-curly "ext:paredit" t t)
  415. (declare-function paredit-convolute-sexp "ext:paredit")
  416. (defun clojure--replace-let-bindings-and-indent ()
  417. "Replace let bindings and indent."
  418. (save-excursion
  419. (backward-sexp)
  420. (when (looking-back clojure--let-regexp nil)
  421. (clojure--replace-sexps-with-bindings-and-indent))))
  422. (defun clojure-paredit-setup (&optional keymap)
  423. "Make \"paredit-mode\" play nice with `clojure-mode'.
  424. If an optional KEYMAP is passed the changes are applied to it,
  425. instead of to `clojure-mode-map'.
  426. Also advice `paredit-convolute-sexp' when used on a let form as drop in
  427. replacement for `cljr-expand-let`."
  428. (when (>= paredit-version 21)
  429. (let ((keymap (or keymap clojure-mode-map)))
  430. (define-key keymap "{" #'paredit-open-curly)
  431. (define-key keymap "}" #'paredit-close-curly))
  432. (add-to-list 'paredit-space-for-delimiter-predicates
  433. #'clojure-space-for-delimiter-p)
  434. (add-to-list 'paredit-space-for-delimiter-predicates
  435. #'clojure-no-space-after-tag)
  436. (advice-add 'paredit-convolute-sexp :after #'clojure--replace-let-bindings-and-indent)))
  437. (defun clojure-mode-variables ()
  438. "Set up initial buffer-local variables for Clojure mode."
  439. (add-to-list 'imenu-generic-expression '(nil clojure-match-next-def 0))
  440. (setq-local indent-tabs-mode nil)
  441. (setq-local paragraph-ignore-fill-prefix t)
  442. (setq-local outline-regexp ";;;\\(;* [^ \t\n]\\)\\|(")
  443. (setq-local outline-level 'lisp-outline-level)
  444. (setq-local comment-start ";")
  445. (setq-local comment-start-skip ";+ *")
  446. (setq-local comment-add 1) ; default to `;;' in comment-region
  447. (setq-local comment-column 40)
  448. (setq-local comment-use-syntax t)
  449. (setq-local multibyte-syntax-as-symbol t)
  450. (setq-local electric-pair-skip-whitespace 'chomp)
  451. (setq-local electric-pair-open-newline-between-pairs nil)
  452. (setq-local fill-paragraph-function #'clojure-fill-paragraph)
  453. (setq-local adaptive-fill-function #'clojure-adaptive-fill-function)
  454. (setq-local normal-auto-fill-function #'clojure-auto-fill-function)
  455. (setq-local comment-start-skip
  456. "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")
  457. (setq-local indent-line-function #'clojure-indent-line)
  458. (setq-local indent-region-function #'clojure-indent-region)
  459. (setq-local lisp-indent-function #'clojure-indent-function)
  460. (setq-local lisp-doc-string-elt-property 'clojure-doc-string-elt)
  461. (setq-local clojure-expected-ns-function #'clojure-expected-ns)
  462. (setq-local parse-sexp-ignore-comments t)
  463. (setq-local prettify-symbols-alist clojure--prettify-symbols-alist)
  464. (setq-local open-paren-in-column-0-is-defun-start nil)
  465. (setq-local beginning-of-defun-function #'clojure-beginning-of-defun-function))
  466. (defsubst clojure-in-docstring-p ()
  467. "Check whether point is in a docstring."
  468. (let ((ppss (syntax-ppss)))
  469. ;; are we in a string?
  470. (when (nth 3 ppss)
  471. ;; check font lock at the start of the string
  472. (eq (get-text-property (nth 8 ppss) 'face)
  473. 'font-lock-doc-face))))
  474. ;;;###autoload
  475. (define-derived-mode clojure-mode prog-mode "Clojure"
  476. "Major mode for editing Clojure code.
  477. \\{clojure-mode-map}"
  478. (clojure-mode-variables)
  479. (clojure-font-lock-setup)
  480. (add-hook 'paredit-mode-hook #'clojure-paredit-setup)
  481. ;; `electric-layout-post-self-insert-function' prevents indentation in strings
  482. ;; and comments, force indentation of non-inlined docstrings:
  483. (add-hook 'electric-indent-functions
  484. (lambda (_char) (if (and (clojure-in-docstring-p)
  485. ;; make sure we're not dealing with an inline docstring
  486. ;; e.g. (def foo "inline docstring" bar)
  487. (save-excursion
  488. (beginning-of-line-text)
  489. (eq (get-text-property (point) 'face)
  490. 'font-lock-doc-face)))
  491. 'do-indent)))
  492. ;; integration with project.el
  493. (add-hook 'project-find-functions #'clojure-current-project))
  494. (defcustom clojure-verify-major-mode t
  495. "If non-nil, warn when activating the wrong `major-mode'."
  496. :type 'boolean
  497. :safe #'booleanp
  498. :package-version '(clojure-mode "5.3.0"))
  499. (defun clojure--check-wrong-major-mode ()
  500. "Check if the current `major-mode' matches the file extension.
  501. If it doesn't, issue a warning if `clojure-verify-major-mode' is
  502. non-nil."
  503. (when (and clojure-verify-major-mode
  504. (stringp (buffer-file-name)))
  505. (let* ((case-fold-search t)
  506. (problem (cond ((and (string-match "\\.clj\\'" (buffer-file-name))
  507. (not (eq major-mode 'clojure-mode)))
  508. 'clojure-mode)
  509. ((and (string-match "\\.cljs\\'" (buffer-file-name))
  510. (not (eq major-mode 'clojurescript-mode)))
  511. 'clojurescript-mode)
  512. ((and (string-match "\\.cljc\\'" (buffer-file-name))
  513. (not (eq major-mode 'clojurec-mode)))
  514. 'clojurec-mode))))
  515. (when problem
  516. (message "[WARNING] %s activated `%s' instead of `%s' in this buffer.
  517. This could cause problems.
  518. \(See `clojure-verify-major-mode' to disable this message.)"
  519. (if (eq major-mode real-this-command)
  520. "You have"
  521. "Something in your configuration")
  522. major-mode
  523. problem)))))
  524. (add-hook 'clojure-mode-hook #'clojure--check-wrong-major-mode)
  525. (defsubst clojure-docstring-fill-prefix ()
  526. "The prefix string used by `clojure-fill-paragraph'.
  527. It is simply `clojure-docstring-fill-prefix-width' number of spaces."
  528. (make-string clojure-docstring-fill-prefix-width ? ))
  529. (defun clojure-adaptive-fill-function ()
  530. "Clojure adaptive fill function.
  531. This only takes care of filling docstring correctly."
  532. (when (clojure-in-docstring-p)
  533. (clojure-docstring-fill-prefix)))
  534. (defun clojure-fill-paragraph (&optional justify)
  535. "Like `fill-paragraph', but can handle Clojure docstrings.
  536. If JUSTIFY is non-nil, justify as well as fill the paragraph."
  537. (if (clojure-in-docstring-p)
  538. (let ((paragraph-start
  539. (concat paragraph-start
  540. "\\|\\s-*\\([(:\"[]\\|~@\\|`(\\|#'(\\)"))
  541. (paragraph-separate
  542. (concat paragraph-separate "\\|\\s-*\".*[,\\.]$"))
  543. (fill-column (or clojure-docstring-fill-column fill-column))
  544. (fill-prefix (clojure-docstring-fill-prefix)))
  545. ;; we are in a string and string start pos (8th element) is non-nil
  546. (let* ((beg-doc (nth 8 (syntax-ppss)))
  547. (end-doc (save-excursion
  548. (goto-char beg-doc)
  549. (or (ignore-errors (forward-sexp) (point))
  550. (point-max)))))
  551. (save-restriction
  552. (narrow-to-region beg-doc end-doc)
  553. (fill-paragraph justify))))
  554. (let ((paragraph-start (concat paragraph-start
  555. "\\|\\s-*\\([(:\"[]\\|`(\\|#'(\\)"))
  556. (paragraph-separate
  557. (concat paragraph-separate "\\|\\s-*\".*[,\\.[]$")))
  558. (or (fill-comment-paragraph justify)
  559. (fill-paragraph justify))
  560. ;; Always return `t'
  561. t)))
  562. (defun clojure-auto-fill-function ()
  563. "Clojure auto-fill function."
  564. ;; Check if auto-filling is meaningful.
  565. (let ((fc (current-fill-column)))
  566. (when (and fc (> (current-column) fc))
  567. (let ((fill-column (if (clojure-in-docstring-p)
  568. clojure-docstring-fill-column
  569. fill-column))
  570. (fill-prefix (clojure-adaptive-fill-function)))
  571. (do-auto-fill)))))
  572. ;;; #_ comments font-locking
  573. ;; Code heavily borrowed from Slime.
  574. ;; https://github.com/slime/slime/blob/master/contrib/slime-fontifying-fu.el#L186
  575. (defvar clojure--comment-macro-regexp
  576. (rx "#_" (* " ") (group-n 1 (not (any " "))))
  577. "Regexp matching the start of a comment sexp.
  578. The beginning of match-group 1 should be before the sexp to be
  579. marked as a comment. The end of sexp is found with
  580. `clojure-forward-logical-sexp'.")
  581. (defvar clojure--reader-and-comment-regexp
  582. "#_ *\\(?1:[^ ]\\)\\|\\(?1:(comment\\_>\\)"
  583. "Regexp matching both `#_' macro and a comment sexp." )
  584. (defcustom clojure-comment-regexp clojure--comment-macro-regexp
  585. "Comment mode.
  586. The possible values for this variable are keywords indicating
  587. what is considered a comment (affecting font locking).
  588. - Reader macro `#_' only - the default
  589. - Reader macro `#_' and `(comment)'"
  590. :type '(choice (const :tag "Reader macro `#_' and `(comment)'" clojure--reader-and-comment-regexp)
  591. (other :tag "Reader macro `#_' only" clojure--comment-macro-regexp))
  592. :package-version '(clojure-mode . "5.7.0"))
  593. (defun clojure--search-comment-macro-internal (limit)
  594. "Search for a comment forward stopping at LIMIT."
  595. (when (search-forward-regexp clojure-comment-regexp limit t)
  596. (let* ((md (match-data))
  597. (start (match-beginning 1))
  598. (state (syntax-ppss start)))
  599. ;; inside string or comment?
  600. (if (or (nth 3 state)
  601. (nth 4 state))
  602. (clojure--search-comment-macro-internal limit)
  603. (goto-char start)
  604. (clojure-forward-logical-sexp 1)
  605. ;; Data for (match-end 1).
  606. (setf (elt md 3) (point))
  607. (set-match-data md)
  608. t))))
  609. (defun clojure--search-comment-macro (limit)
  610. "Find comment macros and set the match data.
  611. Search from point up to LIMIT. The region that should be
  612. considered a comment is between `(match-beginning 1)'
  613. and `(match-end 1)'."
  614. (let ((result 'retry))
  615. (while (and (eq result 'retry) (<= (point) limit))
  616. (condition-case nil
  617. (setq result (clojure--search-comment-macro-internal limit))
  618. (end-of-file (setq result nil))
  619. (scan-error (setq result 'retry))))
  620. result))
  621. ;;; General font-locking
  622. (defun clojure-match-next-def ()
  623. "Scans the buffer backwards for the next \"top-level\" definition.
  624. Called by `imenu--generic-function'."
  625. ;; we have to take into account namespace-definition forms
  626. ;; e.g. s/defn
  627. (when (re-search-backward "^[ \t]*(\\([a-z0-9.-]+/\\)?\\(def\\sw*\\)" nil t)
  628. (save-excursion
  629. (let (found?
  630. (deftype (match-string 2))
  631. (start (point)))
  632. (down-list)
  633. (forward-sexp)
  634. (while (not found?)
  635. (ignore-errors
  636. (forward-sexp))
  637. (or (when (char-equal ?\[ (char-after (point)))
  638. (backward-sexp))
  639. (when (char-equal ?\) (char-after (point)))
  640. (backward-sexp)))
  641. (cl-destructuring-bind (def-beg . def-end) (bounds-of-thing-at-point 'sexp)
  642. (if (char-equal ?^ (char-after def-beg))
  643. (progn (forward-sexp) (backward-sexp))
  644. (setq found? t)
  645. (when (string= deftype "defmethod")
  646. (setq def-end (progn (goto-char def-end)
  647. (forward-sexp)
  648. (point))))
  649. (set-match-data (list def-beg def-end)))))
  650. (goto-char start)))))
  651. (eval-and-compile
  652. (defconst clojure--sym-forbidden-rest-chars "][\";\'@\\^`~\(\)\{\}\\,\s\t\n\r"
  653. "A list of chars that a Clojure symbol cannot contain.
  654. See definition of 'macros': URL `http://git.io/vRGLD'.")
  655. (defconst clojure--sym-forbidden-1st-chars (concat clojure--sym-forbidden-rest-chars "0-9:")
  656. "A list of chars that a Clojure symbol cannot start with.
  657. See the for-loop: URL `http://git.io/vRGTj' lines: URL
  658. `http://git.io/vRGIh', URL `http://git.io/vRGLE' and value
  659. definition of 'macros': URL `http://git.io/vRGLD'.")
  660. (defconst clojure--sym-regexp
  661. (concat "[^" clojure--sym-forbidden-1st-chars "][^" clojure--sym-forbidden-rest-chars "]*")
  662. "A regexp matching a Clojure symbol or namespace alias.
  663. Matches the rule `clojure--sym-forbidden-1st-chars' followed by
  664. any number of matches of `clojure--sym-forbidden-rest-chars'."))
  665. (defconst clojure-font-lock-keywords
  666. (eval-when-compile
  667. `( ;; Top-level variable definition
  668. (,(concat "(\\(?:clojure.core/\\)?\\("
  669. (regexp-opt '("def" "defonce"))
  670. ;; variable declarations
  671. "\\)\\>"
  672. ;; Any whitespace
  673. "[ \r\n\t]*"
  674. ;; Possibly type or metadata
  675. "\\(?:#?^\\(?:{[^}]*}\\|\\sw+\\)[ \r\n\t]*\\)*"
  676. "\\(\\sw+\\)?")
  677. (1 font-lock-keyword-face)
  678. (2 font-lock-variable-name-face nil t))
  679. ;; Type definition
  680. (,(concat "(\\(?:clojure.core/\\)?\\("
  681. (regexp-opt '("defstruct" "deftype" "defprotocol"
  682. "defrecord"))
  683. ;; type declarations
  684. "\\)\\>"
  685. ;; Any whitespace
  686. "[ \r\n\t]*"
  687. ;; Possibly type or metadata
  688. "\\(?:#?^\\(?:{[^}]*}\\|\\sw+\\)[ \r\n\t]*\\)*"
  689. "\\(\\sw+\\)?")
  690. (1 font-lock-keyword-face)
  691. (2 font-lock-type-face nil t))
  692. ;; Function definition (anything that starts with def and is not
  693. ;; listed above)
  694. (,(concat "(\\(?:" clojure--sym-regexp "/\\)?"
  695. "\\(def[^ \r\n\t]*\\)"
  696. ;; Function declarations
  697. "\\>"
  698. ;; Any whitespace
  699. "[ \r\n\t]*"
  700. ;; Possibly type or metadata
  701. "\\(?:#?^\\(?:{[^}]*}\\|\\sw+\\)[ \r\n\t]*\\)*"
  702. (concat "\\(" clojure--sym-regexp "\\)?"))
  703. (1 font-lock-keyword-face)
  704. (2 font-lock-function-name-face nil t))
  705. ;; (fn name? args ...)
  706. (,(concat "(\\(?:clojure.core/\\)?\\(fn\\)[ \t]+"
  707. ;; Possibly type
  708. "\\(?:#?^\\sw+[ \t]*\\)?"
  709. ;; Possibly name
  710. "\\(\\sw+\\)?" )
  711. (1 font-lock-keyword-face)
  712. (2 font-lock-function-name-face nil t))
  713. ;; lambda arguments - %, %&, %1, %2, etc
  714. ("\\<%[&1-9]?" (0 font-lock-variable-name-face))
  715. ;; Special forms
  716. (,(concat
  717. "("
  718. (regexp-opt
  719. '("def" "do" "if" "let" "let*" "var" "fn" "fn*" "loop" "loop*"
  720. "recur" "throw" "try" "catch" "finally"
  721. "set!" "new" "."
  722. "monitor-enter" "monitor-exit" "quote") t)
  723. "\\>")
  724. 1 font-lock-keyword-face)
  725. ;; Built-in binding and flow of control forms
  726. (,(concat
  727. "(\\(?:clojure.core/\\)?"
  728. (regexp-opt
  729. '("letfn" "case" "cond" "cond->" "cond->>" "condp"
  730. "for" "when" "when-not" "when-let" "when-first" "when-some"
  731. "if-let" "if-not" "if-some"
  732. ".." "->" "->>" "as->" "doto" "and" "or"
  733. "dosync" "doseq" "dotimes" "dorun" "doall"
  734. "ns" "in-ns"
  735. "with-open" "with-local-vars" "binding"
  736. "with-redefs" "with-redefs-fn"
  737. "declare") t)
  738. "\\>")
  739. 1 font-lock-keyword-face)
  740. ;; Macros similar to let, when, and while
  741. (,(rx symbol-start
  742. (or "let" "when" "while") "-"
  743. (1+ (or (syntax word) (syntax symbol)))
  744. symbol-end)
  745. 0 font-lock-keyword-face)
  746. (,(concat
  747. "\\<"
  748. (regexp-opt
  749. '("*1" "*2" "*3" "*agent*"
  750. "*allow-unresolved-vars*" "*assert*" "*clojure-version*"
  751. "*command-line-args*" "*compile-files*"
  752. "*compile-path*" "*data-readers*" "*default-data-reader-fn*"
  753. "*e" "*err*" "*file*" "*flush-on-newline*"
  754. "*in*" "*macro-meta*" "*math-context*" "*ns*" "*out*"
  755. "*print-dup*" "*print-length*" "*print-level*"
  756. "*print-meta*" "*print-readably*"
  757. "*read-eval*" "*source-path*"
  758. "*unchecked-math*"
  759. "*use-context-classloader*" "*warn-on-reflection*")
  760. t)
  761. "\\>")
  762. 0 font-lock-builtin-face)
  763. ;; Dynamic variables - *something* or @*something*
  764. (,(concat "\\(?:\\<\\|/\\)@?\\(\\*" clojure--sym-regexp "\\*\\)\\>")
  765. 1 font-lock-variable-name-face)
  766. ;; Global constants - nil, true, false
  767. (,(concat
  768. "\\<"
  769. (regexp-opt
  770. '("true" "false" "nil") t)
  771. "\\>")
  772. 0 font-lock-constant-face)
  773. ;; Character literals - \1, \a, \newline, \u0000
  774. ("\\\\\\([[:punct:]]\\|[a-z0-9]+\\>\\)" 0 'clojure-character-face)
  775. ;; namespace definitions: (ns foo.bar)
  776. (,(concat "(\\<ns\\>[ \r\n\t]*"
  777. ;; Possibly metadata, shorthand and/or longhand
  778. "\\(?:\\^?\\(?:{[^}]+}\\|:[^ \r\n\t]+[ \r\n\t]\\)[ \r\n\t]*\\)*"
  779. ;; namespace
  780. "\\(" clojure--sym-regexp "\\)")
  781. (1 font-lock-type-face))
  782. ;; TODO dedupe the code for matching of keywords, type-hints and unmatched symbols
  783. ;; keywords: {:oneword/ve/yCom|pLex.stu-ff 0}
  784. (,(concat "\\(:\\{1,2\\}\\)\\(" clojure--sym-regexp "?\\)\\(/\\)\\(" clojure--sym-regexp "\\)")
  785. (1 'clojure-keyword-face)
  786. (2 font-lock-type-face)
  787. ;; (2 'clojure-keyword-face)
  788. (3 'default)
  789. (4 'clojure-keyword-face))
  790. (,(concat "\\(:\\{1,2\\}\\)\\(" clojure--sym-regexp "\\)")
  791. (1 'clojure-keyword-face)
  792. (2 'clojure-keyword-face))
  793. ;; type-hints: #^oneword
  794. (,(concat "\\(#?\\^\\)\\(" clojure--sym-regexp "?\\)\\(/\\)\\(" clojure--sym-regexp "\\)")
  795. (1 'default)
  796. (2 font-lock-type-face)
  797. (3 'default)
  798. (4 'default))
  799. (,(concat "\\(#?\\^\\)\\(" clojure--sym-regexp "\\)")
  800. (1 'default)
  801. (2 font-lock-type-face))
  802. ;; clojure symbols not matched by the previous regexps; influences CIDER's
  803. ;; dynamic syntax highlighting (CDSH). See https://git.io/vxEEA:
  804. (,(concat "\\(" clojure--sym-regexp "?\\)\\(/\\)\\(" clojure--sym-regexp "\\)")
  805. (1 font-lock-type-face)
  806. ;; 2nd and 3th matching groups can be font-locked to `nil' or `default'.
  807. ;; CDSH seems to kick in only for functions and variables referenced w/o
  808. ;; writing their namespaces.
  809. (2 nil)
  810. (3 nil))
  811. (,(concat "\\(" clojure--sym-regexp "\\)")
  812. ;; this matching group must be font-locked to `nil' otherwise CDSH breaks.
  813. (1 nil))
  814. ;; #_ and (comment ...) macros.
  815. (clojure--search-comment-macro 1 font-lock-comment-face t)
  816. ;; Highlight `code` marks, just like `elisp'.
  817. (,(rx "`" (group-n 1 (optional "#'")
  818. (+ (or (syntax symbol) (syntax word)))) "`")
  819. (1 'font-lock-constant-face prepend))
  820. ;; Highlight [[var]] comments
  821. (,(rx "[[" (group-n 1 (optional "#'")
  822. (+ (or (syntax symbol) (syntax word)))) "]]")
  823. (1 'font-lock-constant-face prepend))
  824. ;; Highlight escaped characters in strings.
  825. (clojure-font-lock-escaped-chars 0 'bold prepend)
  826. ;; Highlight grouping constructs in regular expressions
  827. (clojure-font-lock-regexp-groups
  828. (1 'font-lock-regexp-grouping-construct prepend))))
  829. "Default expressions to highlight in Clojure mode.")
  830. (defun clojure-font-lock-syntactic-face-function (state)
  831. "Find and highlight text with a Clojure-friendly syntax table.
  832. This function is passed to `font-lock-syntactic-face-function',
  833. which is called with a single parameter, STATE (which is, in
  834. turn, returned by `parse-partial-sexp' at the beginning of the
  835. highlighted region)."
  836. (if (nth 3 state)
  837. ;; This might be a (doc)string or a |...| symbol.
  838. (let ((startpos (nth 8 state)))
  839. (if (eq (char-after startpos) ?|)
  840. ;; This is not a string, but a |...| symbol.
  841. nil
  842. (let* ((listbeg (nth 1 state))
  843. (firstsym (and listbeg
  844. (save-excursion
  845. (goto-char listbeg)
  846. (and (looking-at "([ \t\n]*\\(\\(\\sw\\|\\s_\\)+\\)")
  847. (match-string 1)))))
  848. (docelt (and firstsym
  849. (function-get (intern-soft firstsym)
  850. lisp-doc-string-elt-property))))
  851. (if (and docelt
  852. ;; It's a string in a form that can have a docstring.
  853. ;; Check whether it's in docstring position.
  854. (save-excursion
  855. (when (functionp docelt)
  856. (goto-char (match-end 1))
  857. (setq docelt (funcall docelt)))
  858. (goto-char listbeg)
  859. (forward-char 1)
  860. (ignore-errors
  861. (while (and (> docelt 0) (< (point) startpos)
  862. (progn (forward-sexp 1) t))
  863. ;; ignore metadata and type hints
  864. (unless (looking-at "[ \n\t]*\\(\\^[A-Z:].+\\|\\^?{.+\\)")
  865. (setq docelt (1- docelt)))))
  866. (and (zerop docelt) (<= (point) startpos)
  867. (progn (forward-comment (point-max)) t)
  868. (= (point) (nth 8 state))))
  869. ;; In a def, at last position is not a docstring
  870. (not (and (string= "def" firstsym)
  871. (save-excursion
  872. (goto-char startpos)
  873. (goto-char (+ startpos (length (sexp-at-point)) 2))
  874. (looking-at "[ \r\n\t]*\)")))))
  875. font-lock-doc-face
  876. font-lock-string-face))))
  877. font-lock-comment-face))
  878. (defun clojure-font-lock-setup ()
  879. "Configures font-lock for editing Clojure code."
  880. (setq-local font-lock-multiline t)
  881. (add-to-list 'font-lock-extend-region-functions
  882. #'clojure-font-lock-extend-region-def t)
  883. (setq font-lock-defaults
  884. '(clojure-font-lock-keywords ; keywords
  885. nil nil
  886. (("+-*/.<>=!?$%_&:" . "w")) ; syntax alist
  887. nil
  888. (font-lock-mark-block-function . mark-defun)
  889. (font-lock-syntactic-face-function
  890. . clojure-font-lock-syntactic-face-function))))
  891. (defun clojure-font-lock-def-at-point (point)
  892. "Range between the top-most def* and the fourth element after POINT.
  893. Note that this means that there is no guarantee of proper font
  894. locking in def* forms that are not at top level."
  895. (goto-char point)
  896. (ignore-errors
  897. (beginning-of-defun))
  898. (let ((beg-def (point)))
  899. (when (and (not (= point beg-def))
  900. (looking-at "(def"))
  901. (ignore-errors
  902. ;; move forward as much as possible until failure (or success)
  903. (forward-char)
  904. (dotimes (_ 4)
  905. (forward-sexp)))
  906. (cons beg-def (point)))))
  907. (defun clojure-font-lock-extend-region-def ()
  908. "Set region boundaries to include the first four elements of def* forms."
  909. (let ((changed nil))
  910. (let ((def (clojure-font-lock-def-at-point font-lock-beg)))
  911. (when def
  912. (cl-destructuring-bind (def-beg . def-end) def
  913. (when (and (< def-beg font-lock-beg)
  914. (< font-lock-beg def-end))
  915. (setq font-lock-beg def-beg
  916. changed t)))))
  917. (let ((def (clojure-font-lock-def-at-point font-lock-end)))
  918. (when def
  919. (cl-destructuring-bind (def-beg . def-end) def
  920. (when (and (< def-beg font-lock-end)
  921. (< font-lock-end def-end))
  922. (setq font-lock-end def-end
  923. changed t)))))
  924. changed))
  925. (defun clojure--font-locked-as-string-p (&optional regexp)
  926. "Non-nil if the char before point is font-locked as a string.
  927. If REGEXP is non-nil, also check whether current string is
  928. preceeded by a #."
  929. (let ((face (get-text-property (1- (point)) 'face)))
  930. (and (or (and (listp face)
  931. (memq 'font-lock-string-face face))
  932. (eq 'font-lock-string-face face))
  933. (or (clojure-string-start t)
  934. (unless regexp
  935. (clojure-string-start nil))))))
  936. (defun clojure-font-lock-escaped-chars (bound)
  937. "Highlight \escaped chars in strings.
  938. BOUND denotes a buffer position to limit the search."
  939. (let ((found nil))
  940. (while (and (not found)
  941. (re-search-forward "\\\\." bound t))
  942. (setq found (clojure--font-locked-as-string-p)))
  943. found))
  944. (defun clojure-font-lock-regexp-groups (bound)
  945. "Highlight grouping constructs in regular expression.
  946. BOUND denotes the maximum number of characters (relative to the
  947. point) to check."
  948. (let ((found nil))
  949. (while (and (not found)
  950. (re-search-forward (eval-when-compile
  951. (concat
  952. ;; A group may start using several alternatives:
  953. "\\(\\(?:"
  954. ;; 1. (? special groups
  955. "(\\?\\(?:"
  956. ;; a) non-capturing group (?:X)
  957. ;; b) independent non-capturing group (?>X)
  958. ;; c) zero-width positive lookahead (?=X)
  959. ;; d) zero-width negative lookahead (?!X)
  960. "[:=!>]\\|"
  961. ;; e) zero-width positive lookbehind (?<=X)
  962. ;; f) zero-width negative lookbehind (?<!X)
  963. "<[=!]\\|"
  964. ;; g) named capturing group (?<name>X)
  965. "<[[:alnum:]]+>"
  966. "\\)\\|" ;; end of special groups
  967. ;; 2. normal capturing groups (
  968. ;; 3. we also highlight alternative
  969. ;; separarators |, and closing parens )
  970. "[|()]"
  971. "\\)\\)"))
  972. bound t))
  973. (setq found (clojure--font-locked-as-string-p 'regexp)))
  974. found))
  975. ;; Docstring positions
  976. (put 'ns 'clojure-doc-string-elt 2)
  977. (put 'def 'clojure-doc-string-elt 2)
  978. (put 'defn 'clojure-doc-string-elt 2)
  979. (put 'defn- 'clojure-doc-string-elt 2)
  980. (put 'defmulti 'clojure-doc-string-elt 2)
  981. (put 'defmacro 'clojure-doc-string-elt 2)
  982. (put 'definline 'clojure-doc-string-elt 2)
  983. (put 'defprotocol 'clojure-doc-string-elt 2)
  984. (put 'deftask 'clojure-doc-string-eld 2) ;; common Boot macro
  985. ;;; Vertical alignment
  986. (defcustom clojure-align-forms-automatically nil
  987. "If non-nil, vertically align some forms automatically.
  988. Automatically means it is done as part of indenting code. This
  989. applies to binding forms (`clojure-align-binding-forms'), to cond
  990. forms (`clojure-align-cond-forms') and to map literals. For
  991. instance, selecting a map a hitting \\<clojure-mode-map>`\\[indent-for-tab-command]'
  992. will align the values like this:
  993. {:some-key 10
  994. :key2 20}"
  995. :package-version '(clojure-mode . "5.1")
  996. :safe #'booleanp
  997. :type 'boolean)
  998. (defconst clojure--align-separator-newline-regexp "^ *$")
  999. (defcustom clojure-align-separator clojure--align-separator-newline-regexp
  1000. "The separator that will be passed to `align-region' when performing vertical alignment."
  1001. :package-version '(clojure-mode . "5.10")
  1002. :type `(choice (const :tag "Make blank lines prevent vertical alignment from happening."
  1003. ,clojure--align-separator-newline-regexp)
  1004. (other :tag "Allow blank lines to happen within a vertically-aligned expression."
  1005. 'entire)))
  1006. (defcustom clojure-align-reader-conditionals nil
  1007. "Whether to align reader conditionals, as if they were maps."
  1008. :package-version '(clojure-mode . "5.10")
  1009. :safe #'booleanp
  1010. :type 'boolean)
  1011. (defcustom clojure-align-binding-forms
  1012. '("let" "when-let" "when-some" "if-let" "if-some" "binding" "loop"
  1013. "doseq" "for" "with-open" "with-local-vars" "with-redefs")
  1014. "List of strings matching forms that have binding forms."
  1015. :package-version '(clojure-mode . "5.1")
  1016. :safe #'listp
  1017. :type '(repeat string))
  1018. (defcustom clojure-align-cond-forms '("condp" "cond" "cond->" "cond->>" "case" "are"
  1019. "clojure.core/condp" "clojure.core/cond" "clojure.core/cond->"
  1020. "clojure.core/cond->>" "clojure.core/case" "clojure.test/are")
  1021. "List of strings identifying cond-like forms."
  1022. :package-version '(clojure-mode . "5.1")
  1023. :safe #'listp
  1024. :type '(repeat string))
  1025. (defvar clojure--beginning-of-reader-conditional-regexp
  1026. "#\\?@(\\|#\\?("
  1027. "Regexp denoting the beginning of a reader conditional.")
  1028. (defun clojure--position-for-alignment ()
  1029. "Non-nil if the sexp around point should be automatically aligned.
  1030. This function expects to be called immediately after an
  1031. open-brace or after the function symbol in a function call.
  1032. First check if the sexp around point is a map literal, or is a
  1033. call to one of the vars listed in `clojure-align-cond-forms'. If
  1034. it isn't, return nil. If it is, return non-nil and place point
  1035. immediately before the forms that should be aligned.
  1036. For instance, in a map literal point is left immediately before
  1037. the first key; while, in a let-binding, point is left inside the
  1038. binding vector and immediately before the first binding
  1039. construct."
  1040. (let ((point (point)))
  1041. ;; Are we in a map?
  1042. (or (and (eq (char-before) ?{)
  1043. (not (eq (char-before (1- point)) ?\#)))
  1044. ;; Are we in a reader conditional?
  1045. (and clojure-align-reader-conditionals
  1046. (looking-back clojure--beginning-of-reader-conditional-regexp (- (point) 4)))
  1047. ;; Are we in a cond form?
  1048. (let* ((fun (car (member (thing-at-point 'symbol) clojure-align-cond-forms)))
  1049. (method (and fun (clojure--get-indent-method fun)))
  1050. ;; The number of special arguments in the cond form is
  1051. ;; the number of sexps we skip before aligning.
  1052. (skip (cond ((numberp method) method)
  1053. ((null method) 0)
  1054. ((sequencep method) (elt method 0)))))
  1055. (when (and fun (numberp skip))
  1056. (clojure-forward-logical-sexp skip)
  1057. (comment-forward (point-max))
  1058. fun)) ; Return non-nil (the var name).
  1059. ;; Are we in a let-like form?
  1060. (when (member (thing-at-point 'symbol)
  1061. clojure-align-binding-forms)
  1062. ;; Position inside the binding vector.
  1063. (clojure-forward-logical-sexp)
  1064. (backward-sexp)
  1065. (when (eq (char-after) ?\[)
  1066. (forward-char 1)
  1067. (comment-forward (point-max))
  1068. ;; Return non-nil.
  1069. t)))))
  1070. (defun clojure--find-sexp-to-align (end)
  1071. "Non-nil if there's a sexp ahead to be aligned before END.
  1072. Place point as in `clojure--position-for-alignment'."
  1073. ;; Look for a relevant sexp.
  1074. (let ((found))
  1075. (while (and (not found)
  1076. (search-forward-regexp
  1077. (concat (when clojure-align-reader-conditionals
  1078. (concat clojure--beginning-of-reader-conditional-regexp
  1079. "\\|"))
  1080. "{\\|("
  1081. (regexp-opt
  1082. (append clojure-align-binding-forms
  1083. clojure-align-cond-forms)
  1084. 'symbols))
  1085. end 'noerror))
  1086. (let ((ppss (syntax-ppss)))
  1087. ;; If we're in a string or comment.
  1088. (unless (or (elt ppss 3)
  1089. (elt ppss 4))
  1090. ;; Only stop looking if we successfully position
  1091. ;; the point.
  1092. (setq found (clojure--position-for-alignment)))))
  1093. found))
  1094. (defun clojure--search-whitespace-after-next-sexp (&optional bound _noerror)
  1095. "Move point after all whitespace after the next sexp.
  1096. Set the match data group 1 to be this region of whitespace and
  1097. return point.
  1098. BOUND is bounds the whitespace search."
  1099. (unwind-protect
  1100. (ignore-errors
  1101. (clojure-forward-logical-sexp 1)
  1102. (search-forward-regexp "\\([,\s\t]*\\)" bound)
  1103. (pcase (syntax-after (point))
  1104. ;; End-of-line, try again on next line.
  1105. (`(12) (clojure--search-whitespace-after-next-sexp bound))
  1106. ;; Closing paren, stop here.
  1107. (`(5 . ,_) nil)
  1108. ;; Anything else is something to align.
  1109. (_ (point))))
  1110. (when (and bound (> (point) bound))
  1111. (goto-char bound))))
  1112. (defun clojure-align (beg end)
  1113. "Vertically align the contents of the sexp around point.
  1114. If region is active, align it. Otherwise, align everything in the
  1115. current \"top-level\" sexp.
  1116. When called from lisp code align everything between BEG and END."
  1117. (interactive (if (use-region-p)
  1118. (list (region-beginning) (region-end))
  1119. (save-excursion
  1120. (let ((end (progn (end-of-defun)
  1121. (point))))
  1122. (clojure-backward-logical-sexp)
  1123. (list (point) end)))))
  1124. (setq end (copy-marker end))
  1125. (save-excursion
  1126. (goto-char beg)
  1127. (while (clojure--find-sexp-to-align end)
  1128. (let ((sexp-end (save-excursion
  1129. (backward-up-list)
  1130. (forward-sexp 1)
  1131. (point-marker)))
  1132. (clojure-align-forms-automatically nil)
  1133. (count 1))
  1134. ;; For some bizarre reason, we need to `align-region' once for each
  1135. ;; group.
  1136. (save-excursion
  1137. (while (search-forward-regexp "^ *\n" sexp-end 'noerror)
  1138. (cl-incf count)))
  1139. (dotimes (_ count)
  1140. (align-region (point) sexp-end nil
  1141. `((clojure-align (regexp . clojure--search-whitespace-after-next-sexp)
  1142. (group . 1)
  1143. (separate . ,clojure-align-separator)
  1144. (repeat . t)))
  1145. nil))
  1146. ;; Reindent after aligning because of #360.
  1147. (indent-region (point) sexp-end)))))
  1148. ;;; Indentation
  1149. (defun clojure-indent-region (beg end)
  1150. "Like `indent-region', but also maybe align forms.
  1151. Forms between BEG and END are aligned according to
  1152. `clojure-align-forms-automatically'."
  1153. (prog1 (let ((indent-region-function nil))
  1154. (indent-region beg end))
  1155. (when clojure-align-forms-automatically
  1156. (condition-case nil
  1157. (clojure-align beg end)
  1158. (scan-error nil)))))
  1159. (defun clojure-indent-line ()
  1160. "Indent current line as Clojure code."
  1161. (if (clojure-in-docstring-p)
  1162. (save-excursion
  1163. (beginning-of-line)
  1164. (when (and (looking-at "^\\s-*")
  1165. (<= (string-width (match-string-no-properties 0))
  1166. (string-width (clojure-docstring-fill-prefix))))
  1167. (replace-match (clojure-docstring-fill-prefix))))
  1168. (lisp-indent-line)))
  1169. (defvar clojure-get-indent-function nil
  1170. "Function to get the indent spec of a symbol.
  1171. This function should take one argument, the name of the symbol as
  1172. a string. This name will be exactly as it appears in the buffer,
  1173. so it might start with a namespace alias.
  1174. This function is analogous to the `clojure-indent-function'
  1175. symbol property, and its return value should match one of the
  1176. allowed values of this property. See `clojure-indent-function'
  1177. for more information.")
  1178. (defun clojure--get-indent-method (function-name)
  1179. "Return the indent spec for the symbol named FUNCTION-NAME.
  1180. FUNCTION-NAME is a string. If it contains a `/', also try only
  1181. the part after the `/'.
  1182. Look for a spec using `clojure-get-indent-function', then try the
  1183. `clojure-indent-function' and `clojure-backtracking-indent'
  1184. symbol properties."
  1185. (or (when (functionp clojure-get-indent-function)
  1186. (funcall clojure-get-indent-function function-name))
  1187. (get (intern-soft function-name) 'clojure-indent-function)
  1188. (get (intern-soft function-name) 'clojure-backtracking-indent)
  1189. (when (string-match "/\\([^/]+\\)\\'" function-name)
  1190. (or (get (intern-soft (match-string 1 function-name))
  1191. 'clojure-indent-function)
  1192. (get (intern-soft (match-string 1 function-name))
  1193. 'clojure-backtracking-indent)))
  1194. ;; indent symbols starting with if, when, ...
  1195. ;; such as if-let, when-let, ...
  1196. ;; like if, when, ...
  1197. (when (string-match (rx string-start (or "if" "when" "let" "while") (syntax symbol))
  1198. function-name)
  1199. (clojure--get-indent-method (substring (match-string 0 function-name) 0 -1)))))
  1200. (defvar clojure--current-backtracking-depth 0)
  1201. (defun clojure--find-indent-spec-backtracking ()
  1202. "Return the indent sexp that applies to the sexp at point.
  1203. Implementation function for `clojure--find-indent-spec'."
  1204. (when (and (>= clojure-max-backtracking clojure--current-backtracking-depth)
  1205. (not (looking-at "^")))
  1206. (let ((clojure--current-backtracking-depth (1+ clojure--current-backtracking-depth))
  1207. (pos 0))
  1208. ;; Count how far we are from the start of the sexp.
  1209. (while (ignore-errors (clojure-backward-logical-sexp 1)
  1210. (not (or (bobp)
  1211. (eq (char-before) ?\n))))
  1212. (cl-incf pos))
  1213. (let* ((function (thing-at-point 'symbol))
  1214. (method (or (when function ;; Is there a spec here?
  1215. (clojure--get-indent-method function))
  1216. (ignore-errors
  1217. ;; Otherwise look higher up.
  1218. (pcase (syntax-ppss)
  1219. (`(,(pred (< 0)) ,start . ,_)
  1220. (goto-char start)
  1221. (clojure--find-indent-spec-backtracking)))))))
  1222. (when (numberp method)
  1223. (setq method (list method)))
  1224. (pcase method
  1225. ((pred functionp)
  1226. (when (= pos 0)
  1227. method))
  1228. ((pred sequencep)
  1229. (pcase (length method)
  1230. (`0 nil)
  1231. (`1 (let ((head (elt method 0)))
  1232. (when (or (= pos 0) (sequencep head))
  1233. head)))
  1234. (l (if (>= pos l)
  1235. (elt method (1- l))
  1236. (elt method pos)))))
  1237. ((or `defun `:defn)
  1238. (when (= pos 0)
  1239. :defn))
  1240. (_
  1241. (message "Invalid indent spec for `%s': %s" function method)
  1242. nil))))))
  1243. (defun clojure--find-indent-spec ()
  1244. "Return the indent spec that applies to current sexp.
  1245. If `clojure-use-backtracking-indent' is non-nil, also do
  1246. backtracking up to a higher-level sexp in order to find the
  1247. spec."
  1248. (if clojure-use-backtracking-indent
  1249. (save-excursion
  1250. (clojure--find-indent-spec-backtracking))
  1251. (let ((function (thing-at-point 'symbol)))
  1252. (clojure--get-indent-method function))))
  1253. (defun clojure--keyword-to-symbol (keyword)
  1254. "Convert KEYWORD to symbol."
  1255. (intern (substring (symbol-name keyword) 1)))
  1256. (defun clojure--normal-indent (last-sexp indent-mode)
  1257. "Return the normal indentation column for a sexp.
  1258. Point should be after the open paren of the _enclosing_ sexp, and
  1259. LAST-SEXP is the start of the previous sexp (immediately before
  1260. the sexp being indented). INDENT-MODE is any of the values
  1261. accepted by `clojure-indent-style'."
  1262. (goto-char last-sexp)
  1263. (forward-sexp 1)
  1264. (clojure-backward-logical-sexp 1)
  1265. (let ((last-sexp-start nil))
  1266. (if (ignore-errors
  1267. ;; `backward-sexp' until we reach the start of a sexp that is the
  1268. ;; first of its line (the start of the enclosing sexp).
  1269. (while (string-match
  1270. "[^[:blank:]]"
  1271. (buffer-substring (line-beginning-position) (point)))
  1272. (setq last-sexp-start (prog1 (point)
  1273. (forward-sexp -1))))
  1274. t)
  1275. ;; Here we have found an arg before the arg we're indenting which is at
  1276. ;; the start of a line. Every mode simply aligns on this case.
  1277. (current-column)
  1278. ;; Here we have reached the start of the enclosing sexp (point is now at
  1279. ;; the function name), so the behaviour depends on INDENT-MODE and on
  1280. ;; whether there's also an argument on this line (case A or B).
  1281. (let ((indent-mode (if (keywordp indent-mode)
  1282. ;; needed for backwards compatibility
  1283. ;; as before clojure-mode 5.10 indent-mode was a keyword
  1284. (clojure--keyword-to-symbol indent-mode)
  1285. indent-mode))
  1286. (case-a ; The meaning of case-a is explained in `clojure-indent-style'.
  1287. (and last-sexp-start
  1288. (< last-sexp-start (line-end-position)))))
  1289. (cond
  1290. ((eq indent-mode 'always-indent)
  1291. (+ (current-column) lisp-body-indent -1))
  1292. ;; There's an arg after the function name, so align with it.
  1293. (case-a (goto-char last-sexp-start)
  1294. (current-column))
  1295. ;; Not same line.
  1296. ((eq indent-mode 'align-arguments)
  1297. (+ (current-column) lisp-body-indent -1))
  1298. ;; Finally, just align with the function name.
  1299. (t (current-column)))))))
  1300. (defun clojure--not-function-form-p ()
  1301. "Non-nil if form at point doesn't represent a function call."
  1302. (or (member (char-after) '(?\[ ?\{))
  1303. (save-excursion ;; Catch #?@ (:cljs ...)
  1304. (skip-chars-backward "\r\n[:blank:]")
  1305. (when (eq (char-before) ?@)
  1306. (forward-char -1))
  1307. (and (eq (char-before) ?\?)
  1308. (eq (char-before (1- (point))) ?\#)))
  1309. ;; Car of form is not a symbol.
  1310. (not (looking-at ".\\(?:\\sw\\|\\s_\\)"))))
  1311. ;; Check the general context, and provide indentation for data structures and
  1312. ;; special macros. If current form is a function (or non-special macro),
  1313. ;; delegate indentation to `clojure--normal-indent'.
  1314. (defun clojure-indent-function (indent-point state)
  1315. "When indenting a line within a function call, indent properly.
  1316. INDENT-POINT is the position where the user typed TAB, or equivalent.
  1317. Point is located at the point to indent under (for default indentation);
  1318. STATE is the `parse-partial-sexp' state for that position.
  1319. If the current line is in a call to a Clojure function with a
  1320. non-nil property `clojure-indent-function', that specifies how to do
  1321. the indentation.
  1322. The property value can be
  1323. - `defun', meaning indent `defun'-style;
  1324. - an integer N, meaning indent the first N arguments specially
  1325. like ordinary function arguments and then indent any further
  1326. arguments like a body;
  1327. - a function to call just as this function was called.
  1328. If that function returns nil, that means it doesn't specify
  1329. the indentation.
  1330. - a list, which is used by `clojure-backtracking-indent'.
  1331. This function also returns nil meaning don't specify the indentation."
  1332. ;; Goto to the open-paren.
  1333. (goto-char (elt state 1))
  1334. ;; Maps, sets, vectors and reader conditionals.
  1335. (if (clojure--not-function-form-p)
  1336. (1+ (current-column))
  1337. ;; Function or macro call.
  1338. (forward-char 1)
  1339. (let ((method (clojure--find-indent-spec))
  1340. (last-sexp calculate-lisp-indent-last-sexp)
  1341. (containing-form-column (1- (current-column))))
  1342. (pcase method
  1343. ((or (pred integerp) `(,method))
  1344. (let ((pos -1))
  1345. (condition-case nil
  1346. (while (and (<= (point) indent-point)
  1347. (not (eobp)))
  1348. (clojure-forward-logical-sexp 1)
  1349. (cl-incf pos))
  1350. ;; If indent-point is _after_ the last sexp in the
  1351. ;; current sexp, we detect that by catching the
  1352. ;; `scan-error'. In that case, we should return the
  1353. ;; indentation as if there were an extra sexp at point.
  1354. (scan-error (cl-incf pos)))
  1355. (cond
  1356. ;; The first non-special arg. Rigidly reduce indentation.
  1357. ((= pos (1+ method))
  1358. (+ lisp-body-indent containing-form-column))
  1359. ;; Further non-special args, align with the arg above.
  1360. ((> pos (1+ method))
  1361. (clojure--normal-indent last-sexp 'always-align))
  1362. ;; Special arg. Rigidly indent with a large indentation.
  1363. (t
  1364. (+ (* 2 lisp-body-indent) containing-form-column)))))
  1365. (`:defn
  1366. (+ lisp-body-indent containing-form-column))
  1367. ((pred functionp)
  1368. (funcall method indent-point state))
  1369. ;; No indent spec, do the default.
  1370. (`nil
  1371. (let ((function (thing-at-point 'symbol)))
  1372. (cond
  1373. ;; Preserve useful alignment of :require (and friends) in `ns' forms.
  1374. ((and function (string-match "^:" function))
  1375. (clojure--normal-indent last-sexp 'always-align))
  1376. ;; This should be identical to the :defn above.
  1377. ((and function
  1378. (string-match "\\`\\(?:\\S +/\\)?\\(def[a-z]*\\|with-\\)"
  1379. function)
  1380. (not (string-match "\\`default" (match-string 1 function))))
  1381. (+ lisp-body-indent containing-form-column))
  1382. ;; Finally, nothing special here, just respect the user's
  1383. ;; preference.
  1384. (t (clojure--normal-indent last-sexp clojure-indent-style)))))))))
  1385. ;;; Setting indentation
  1386. (defun put-clojure-indent (sym indent)
  1387. "Instruct `clojure-indent-function' to indent the body of SYM by INDENT."
  1388. (put sym 'clojure-indent-function indent))
  1389. (defmacro define-clojure-indent (&rest kvs)
  1390. "Call `put-clojure-indent' on a series, KVS."
  1391. `(progn
  1392. ,@(mapcar (lambda (x) `(put-clojure-indent
  1393. (quote ,(car x)) ,(cadr x)))
  1394. kvs)))
  1395. (defun add-custom-clojure-indents (name value)
  1396. "Allow `clojure-defun-indents' to indent user-specified macros.
  1397. Requires the macro's NAME and a VALUE."
  1398. (custom-set-default name value)
  1399. (mapcar (lambda (x)
  1400. (put-clojure-indent x 'defun))
  1401. value))
  1402. (defcustom clojure-defun-indents nil
  1403. "List of additional symbols with defun-style indentation in Clojure.
  1404. You can use this to let Emacs indent your own macros the same way
  1405. that it indents built-in macros like with-open. This variable
  1406. only works when set via the customize interface (`setq' won't
  1407. work). To set it from Lisp code, use
  1408. (put-clojure-indent \\='some-symbol :defn)."
  1409. :type '(repeat symbol)
  1410. :set 'add-custom-clojure-indents)
  1411. (define-clojure-indent
  1412. ;; built-ins
  1413. (ns 1)
  1414. (fn :defn)
  1415. (def :defn)
  1416. (defn :defn)
  1417. (bound-fn :defn)
  1418. (if 1)
  1419. (if-not 1)
  1420. (case 1)
  1421. (cond 0)
  1422. (condp 2)
  1423. (cond-> 1)
  1424. (cond->> 1)
  1425. (when 1)
  1426. (while 1)
  1427. (when-not 1)
  1428. (when-first 1)
  1429. (do 0)
  1430. (delay 0)
  1431. (future 0)
  1432. (comment 0)
  1433. (doto 1)
  1434. (locking 1)
  1435. (proxy '(2 nil nil (:defn)))
  1436. (as-> 2)
  1437. (fdef 1)
  1438. (reify '(:defn (1)))
  1439. (deftype '(2 nil nil (:defn)))
  1440. (defrecord '(2 nil nil (:defn)))
  1441. (defprotocol '(1 (:defn)))
  1442. (definterface '(1 (:defn)))
  1443. (extend 1)
  1444. (extend-protocol '(1 :defn))
  1445. (extend-type '(1 :defn))
  1446. ;; specify and specify! are from ClojureScript
  1447. (specify '(1 :defn))
  1448. (specify! '(1 :defn))
  1449. (try 0)
  1450. (catch 2)
  1451. (finally 0)
  1452. ;; binding forms
  1453. (let 1)
  1454. (letfn '(1 ((:defn)) nil))
  1455. (binding 1)
  1456. (loop 1)
  1457. (for 1)
  1458. (doseq 1)
  1459. (dotimes 1)
  1460. (when-let 1)
  1461. (if-let 1)
  1462. (when-some 1)
  1463. (if-some 1)
  1464. (this-as 1) ; ClojureScript
  1465. (defmethod :defn)
  1466. ;; clojure.test
  1467. (testing 1)
  1468. (deftest :defn)
  1469. (are 2)
  1470. (use-fixtures :defn)
  1471. ;; core.logic
  1472. (run :defn)
  1473. (run* :defn)
  1474. (fresh :defn)
  1475. ;; core.async
  1476. (alt! 0)
  1477. (alt!! 0)
  1478. (go 0)
  1479. (go-loop 1)
  1480. (thread 0))
  1481. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1482. ;;
  1483. ;; Better docstring filling for clojure-mode
  1484. ;;
  1485. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1486. (defun clojure-string-start (&optional regex)
  1487. "Return the position of the \" that begins the string at point.
  1488. If REGEX is non-nil, return the position of the # that begins the
  1489. regex at point. If point is not inside a string or regex, return
  1490. nil."
  1491. (when (nth 3 (syntax-ppss)) ;; Are we really in a string?
  1492. (save-excursion
  1493. (save-match-data
  1494. ;; Find a quote that appears immediately after whitespace,
  1495. ;; beginning of line, hash, or an open paren, brace, or bracket
  1496. (re-search-backward "\\(\\s-\\|^\\|#\\|(\\|\\[\\|{\\)\\(\"\\)")
  1497. (let ((beg (match-beginning 2)))
  1498. (when beg
  1499. (if regex
  1500. (and (char-before beg) (eq ?# (char-before beg)) (1- beg))
  1501. (when (not (eq ?# (char-before beg)))
  1502. beg))))))))
  1503. (defun clojure-char-at-point ()
  1504. "Return the char at point or nil if at buffer end."
  1505. (when (not (= (point) (point-max)))
  1506. (buffer-substring-no-properties (point) (1+ (point)))))
  1507. (defun clojure-char-before-point ()
  1508. "Return the char before point or nil if at buffer beginning."
  1509. (when (not (= (point) (point-min)))
  1510. (buffer-substring-no-properties (point) (1- (point)))))
  1511. (defun clojure-toggle-keyword-string ()
  1512. "Convert the string or keyword at point to keyword or string."
  1513. (interactive)
  1514. (let ((original-point (point)))
  1515. (while (and (> (point) 1)
  1516. (not (equal "\"" (buffer-substring-no-properties (point) (+ 1 (point)))))
  1517. (not (equal ":" (buffer-substring-no-properties (point) (+ 1 (point))))))
  1518. (backward-char))
  1519. (cond
  1520. ((equal 1 (point))
  1521. (error "Beginning of file reached, this was probably a mistake"))
  1522. ((equal "\"" (buffer-substring-no-properties (point) (+ 1 (point))))
  1523. (insert ":" (substring (clojure-delete-and-extract-sexp) 1 -1)))
  1524. ((equal ":" (buffer-substring-no-properties (point) (+ 1 (point))))
  1525. (insert "\"" (substring (clojure-delete-and-extract-sexp) 1) "\"")))
  1526. (goto-char original-point)))
  1527. (defun clojure-delete-and-extract-sexp ()
  1528. "Delete the surrounding sexp and return it."
  1529. (let ((begin (point)))
  1530. (forward-sexp)
  1531. (let ((result (buffer-substring begin (point))))
  1532. (delete-region begin (point))
  1533. result)))
  1534. (defcustom clojure-cache-project-dir t
  1535. "Whether to cache the results of `clojure-project-dir'."
  1536. :type 'boolean
  1537. :safe #'booleanp
  1538. :package-version '(clojure-mode . "5.8.0"))
  1539. (defvar-local clojure-cached-project-dir nil
  1540. "A project dir cache used to speed up related operations.")
  1541. (defun clojure-project-dir (&optional dir-name)
  1542. "Return the absolute path to the project's root directory.
  1543. Call is delegated down to `clojure-project-root-function' with
  1544. optional DIR-NAME as argument.
  1545. When `clojure-cache-project-dir' is t the results of the command
  1546. are cached in a buffer local variable (`clojure-cached-project-dir')."
  1547. (let ((project-dir (or clojure-cached-project-dir
  1548. (funcall clojure-project-root-function dir-name))))
  1549. (when (and clojure-cache-project-dir
  1550. (derived-mode-p 'clojure-mode)
  1551. (not clojure-cached-project-dir))
  1552. (setq clojure-cached-project-dir project-dir))
  1553. project-dir))
  1554. (defun clojure-current-project (&optional dir-name)
  1555. "Return the current project as a cons cell usable by project.el.
  1556. Call is delegated down to `clojure-clojure-dir' with
  1557. optional DIR-NAME as argument."
  1558. (let ((project-dir (clojure-project-dir dir-name)))
  1559. (if project-dir
  1560. (cons 'clojure project-dir)
  1561. nil)))
  1562. (defun clojure-project-root-path (&optional dir-name)
  1563. "Return the absolute path to the project's root directory.
  1564. Use `default-directory' if DIR-NAME is nil.
  1565. Return nil if not inside a project."
  1566. (let* ((dir-name (or dir-name default-directory))
  1567. (choices (delq nil
  1568. (mapcar (lambda (fname)
  1569. (locate-dominating-file dir-name fname))
  1570. clojure-build-tool-files))))
  1571. (when (> (length choices) 0)
  1572. (car (sort choices #'file-in-directory-p)))))
  1573. ;; project.el integration
  1574. (cl-defmethod project-roots ((project (head clojure)))
  1575. (list (cdr project)))
  1576. (defun clojure-project-relative-path (path)
  1577. "Denormalize PATH by making it relative to the project root."
  1578. (file-relative-name path (clojure-project-dir)))
  1579. ;;; ns manipulation
  1580. (defun clojure-expected-ns (&optional path)
  1581. "Return the namespace matching PATH.
  1582. PATH is expected to be an absolute file path.
  1583. If PATH is nil, use the path to the file backing the current buffer."
  1584. (let* ((path (or path (file-truename (buffer-file-name))))
  1585. (relative (clojure-project-relative-path path))
  1586. (sans-file-type (substring relative 0 (- (length (file-name-extension path t)))))
  1587. (sans-file-sep (mapconcat 'identity (cdr (split-string sans-file-type "/")) "."))
  1588. (sans-underscores (replace-regexp-in-string "_" "-" sans-file-sep)))
  1589. ;; Drop prefix from ns for projects with structure src/{clj,cljs,cljc}
  1590. (replace-regexp-in-string "\\`clj[scx]?\\." "" sans-underscores)))
  1591. (defun clojure-insert-ns-form-at-point ()
  1592. "Insert a namespace form at point."
  1593. (interactive)
  1594. (insert (format "(ns %s)" (funcall clojure-expected-ns-function))))
  1595. (defun clojure-insert-ns-form ()
  1596. "Insert a namespace form at the beginning of the buffer."
  1597. (interactive)
  1598. (widen)
  1599. (goto-char (point-min))
  1600. (clojure-insert-ns-form-at-point))
  1601. (defun clojure-update-ns ()
  1602. "Update the namespace of the current buffer.
  1603. Useful if a file has been renamed."
  1604. (interactive)
  1605. (let ((nsname (funcall clojure-expected-ns-function)))
  1606. (when nsname
  1607. (save-excursion
  1608. (save-match-data
  1609. (if (clojure-find-ns)
  1610. (progn
  1611. (replace-match nsname nil nil nil 4)
  1612. (message "ns form updated to `%s'" nsname)
  1613. (setq clojure-cached-ns nsname))
  1614. (user-error "Can't find ns form")))))))
  1615. (defun clojure--sort-following-sexps ()
  1616. "Sort sexps between point and end of current sexp.
  1617. Comments at the start of a line are considered part of the
  1618. following sexp. Comments at the end of a line (after some other
  1619. content) are considered part of the preceding sexp."
  1620. ;; Here we're after the :require/:import symbol.
  1621. (save-restriction
  1622. (narrow-to-region (point) (save-excursion
  1623. (up-list)
  1624. (1- (point))))
  1625. (skip-chars-forward "\r\n[:blank:]")
  1626. (sort-subr nil
  1627. (lambda () (skip-chars-forward "\r\n[:blank:]"))
  1628. ;; Move to end of current top-level thing.
  1629. (lambda ()
  1630. (condition-case nil
  1631. (while t (up-list))
  1632. (scan-error nil))
  1633. ;; We could be inside a symbol instead of a sexp.
  1634. (unless (looking-at "\\s-\\|$")
  1635. (clojure-forward-logical-sexp))
  1636. ;; move past comments at the end of the line.
  1637. (search-forward-regexp "$"))
  1638. ;; Move to start of ns name.
  1639. (lambda ()
  1640. (comment-forward)
  1641. (skip-chars-forward "[:blank:]\n\r[(")
  1642. (clojure-forward-logical-sexp)
  1643. (forward-sexp -1)
  1644. nil)
  1645. ;; Move to end of ns name.
  1646. (lambda ()
  1647. (clojure-forward-logical-sexp)))
  1648. (goto-char (point-max))
  1649. ;; Does the last line now end in a comment?
  1650. (when (nth 4 (parse-partial-sexp (point-min) (point)))
  1651. (insert "\n"))))
  1652. (defun clojure-sort-ns ()
  1653. "Internally sort each sexp inside the ns form."
  1654. (interactive)
  1655. (comment-normalize-vars)
  1656. (if (clojure-find-ns)
  1657. (save-excursion
  1658. (goto-char (match-beginning 0))
  1659. (redisplay)
  1660. (let ((beg (point))
  1661. (ns))
  1662. (forward-sexp 1)
  1663. (setq ns (buffer-substring beg (point)))
  1664. (forward-char -1)
  1665. (while (progn (forward-sexp -1)
  1666. (looking-at "(:[a-z]"))
  1667. (save-excursion
  1668. (forward-char 1)
  1669. (forward-sexp 1)
  1670. (clojure--sort-following-sexps)))
  1671. (goto-char beg)
  1672. (if (looking-at (regexp-quote ns))
  1673. (message "ns form is already sorted")
  1674. (sleep-for 0.1)
  1675. (redisplay)
  1676. (message "ns form has been sorted")
  1677. (sleep-for 0.1))))
  1678. (user-error "Can't find ns form")))
  1679. (defconst clojure-namespace-name-regex
  1680. (rx line-start
  1681. "("
  1682. (zero-or-one (group (regexp "clojure.core/")))
  1683. (zero-or-one (submatch "in-"))
  1684. "ns"
  1685. (zero-or-one "+")
  1686. (one-or-more (any whitespace "\n"))
  1687. (zero-or-more (or (submatch (zero-or-one "#")
  1688. "^{"
  1689. (zero-or-more (not (any "}")))
  1690. "}")
  1691. (zero-or-more "^:"
  1692. (one-or-more (not (any whitespace)))))
  1693. (one-or-more (any whitespace "\n")))
  1694. (zero-or-one (any ":'")) ;; (in-ns 'foo) or (ns+ :user)
  1695. (group (one-or-more (not (any "()\"" whitespace))) symbol-end)))
  1696. (defcustom clojure-cache-ns nil
  1697. "Whether to cache the results of `clojure-find-ns'.
  1698. Note that this won't work well in buffers with multiple namespace
  1699. declarations (which rarely occur in practice) and you'll
  1700. have to invalidate this manually after changing the ns for
  1701. a buffer. If you update the ns using `clojure-update-ns'
  1702. the cached value will be updated automatically."
  1703. :type 'boolean
  1704. :safe #'booleanp
  1705. :package-version '(clojure-mode . "5.8.0"))
  1706. (defvar-local clojure-cached-ns nil
  1707. "A buffer ns cache used to speed up ns-related operations.")
  1708. (defun clojure--find-ns-in-direction (direction)
  1709. "Return the nearest namespace in a specific DIRECTION.
  1710. DIRECTION is `forward' or `backward'."
  1711. (let ((candidate)
  1712. (fn (if (eq direction 'forward)
  1713. #'search-forward-regexp
  1714. #'search-backward-regexp)))
  1715. (while (and (not candidate)
  1716. (funcall fn clojure-namespace-name-regex nil t))
  1717. (unless (or (clojure--in-string-p) (clojure--in-comment-p))
  1718. (setq candidate (match-string-no-properties 4))))
  1719. candidate))
  1720. (defun clojure-find-ns ()
  1721. "Return the namespace of the current Clojure buffer.
  1722. Return the namespace closest to point and above it. If there are
  1723. no namespaces above point, return the first one in the buffer.
  1724. The results will be cached if `clojure-cache-ns' is set to t."
  1725. (if (and clojure-cache-ns clojure-cached-ns)
  1726. clojure-cached-ns
  1727. (let ((ns (save-excursion
  1728. (save-restriction
  1729. (widen)
  1730. ;; Move to top-level to avoid searching from inside ns
  1731. (ignore-errors (while t (up-list nil t t)))
  1732. (or (clojure--find-ns-in-direction 'backward)
  1733. (clojure--find-ns-in-direction 'forward))))))
  1734. (setq clojure-cached-ns ns)
  1735. ns)))
  1736. (defun clojure-show-cache ()
  1737. "Display cached values if present.
  1738. Useful for debugging."
  1739. (interactive)
  1740. (message "Cached Project: %s, Cached Namespace: %s" clojure-cached-project-dir clojure-cached-ns))
  1741. (defun clojure-clear-cache ()
  1742. "Clear all buffer-local cached values.
  1743. Normally you'd need to do this very infrequently - e.g.
  1744. after renaming the root folder of project or after
  1745. renaming a namespace."
  1746. (interactive)
  1747. (setq clojure-cached-project-dir nil
  1748. clojure-cached-ns nil)
  1749. (message "Buffer-local clojure-mode cache cleared"))
  1750. (defconst clojure-def-type-and-name-regex
  1751. (concat "(\\(?:\\(?:\\sw\\|\\s_\\)+/\\)?"
  1752. ;; Declaration
  1753. "\\(def\\(?:\\sw\\|\\s_\\)*\\)\\>"
  1754. ;; Any whitespace
  1755. "[ \r\n\t]*"
  1756. ;; Possibly type or metadata
  1757. "\\(?:#?^\\(?:{[^}]*}\\|\\(?:\\sw\\|\\s_\\)+\\)[ \r\n\t]*\\)*"
  1758. ;; Symbol name
  1759. "\\(\\(?:\\sw\\|\\s_\\)+\\)"))
  1760. (defun clojure-find-def ()
  1761. "Find the var declaration macro and symbol name of the current form.
  1762. Returns a list pair, e.g. (\"defn\" \"abc\") or (\"deftest\" \"some-test\")."
  1763. (save-excursion
  1764. (unless (looking-at clojure-def-type-and-name-regex)
  1765. (beginning-of-defun))
  1766. (when (search-forward-regexp clojure-def-type-and-name-regex nil t)
  1767. (list (match-string-no-properties 1)
  1768. (match-string-no-properties 2)))))
  1769. ;;; Sexp navigation
  1770. (defun clojure--looking-at-non-logical-sexp ()
  1771. "Return non-nil if text after point is \"non-logical\" sexp.
  1772. \"Non-logical\" sexp are ^metadata and #reader.macros."
  1773. (comment-normalize-vars)
  1774. (comment-forward (point-max))
  1775. (looking-at-p "\\^\\|#:?:?[[:alpha:]]"))
  1776. (defun clojure-forward-logical-sexp (&optional n)
  1777. "Move forward N logical sexps.
  1778. This will skip over sexps that don't represent objects, so that ^hints and
  1779. #reader.macros are considered part of the following sexp."
  1780. (interactive "p")
  1781. (unless n (setq n 1))
  1782. (if (< n 0)
  1783. (clojure-backward-logical-sexp (- n))
  1784. (let ((forward-sexp-function nil))
  1785. (while (> n 0)
  1786. (while (clojure--looking-at-non-logical-sexp)
  1787. (forward-sexp 1))
  1788. ;; The actual sexp
  1789. (forward-sexp 1)
  1790. (skip-chars-forward ",")
  1791. (setq n (1- n))))))
  1792. (defun clojure-backward-logical-sexp (&optional n)
  1793. "Move backward N logical sexps.
  1794. This will skip over sexps that don't represent objects, so that ^hints and
  1795. #reader.macros are considered part of the following sexp."
  1796. (interactive "p")
  1797. (unless n (setq n 1))
  1798. (if (< n 0)
  1799. (clojure-forward-logical-sexp (- n))
  1800. (let ((forward-sexp-function nil))
  1801. (while (> n 0)
  1802. ;; The actual sexp
  1803. (backward-sexp 1)
  1804. ;; Non-logical sexps.
  1805. (while (and (not (bobp))
  1806. (ignore-errors
  1807. (save-excursion
  1808. (backward-sexp 1)
  1809. (clojure--looking-at-non-logical-sexp))))
  1810. (backward-sexp 1))
  1811. (setq n (1- n))))))
  1812. (defun clojure-top-level-form-p (first-form)
  1813. "Return truthy if the first form matches FIRST-FORM."
  1814. (condition-case nil
  1815. (save-excursion
  1816. (beginning-of-defun)
  1817. (forward-char 1)
  1818. (clojure-forward-logical-sexp 1)
  1819. (clojure-backward-logical-sexp 1)
  1820. (looking-at-p first-form))
  1821. (scan-error nil)
  1822. (end-of-buffer nil)))
  1823. (defun clojure-sexp-starts-until-position (position)
  1824. "Return the starting points for forms before POSITION.
  1825. Positions are in descending order to aide in finding the first starting
  1826. position before the current position."
  1827. (save-excursion
  1828. (let (sexp-positions)
  1829. (condition-case nil
  1830. (while (< (point) position)
  1831. (clojure-forward-logical-sexp 1)
  1832. (clojure-backward-logical-sexp 1)
  1833. (push (point) sexp-positions)
  1834. (clojure-forward-logical-sexp 1))
  1835. (scan-error nil))
  1836. sexp-positions)))
  1837. (defcustom clojure-toplevel-inside-comment-form nil
  1838. "Eval top level forms inside comment forms instead of the comment form itself.
  1839. Experimental. Function `cider-defun-at-point' is used extensively so if we
  1840. change this heuristic it needs to be bullet-proof and desired. While
  1841. testing, give an easy way to turn this new behavior off."
  1842. :type 'boolean
  1843. :safe #'booleanp
  1844. :package-version '(clojure-mode . "5.9.0"))
  1845. (defun clojure-find-first (pred coll)
  1846. "Find first element of COLL for which PRED return truthy."
  1847. (let ((found)
  1848. (haystack coll))
  1849. (while (and (not found)
  1850. haystack)
  1851. (if (funcall pred (car haystack))
  1852. (setq found (car haystack))
  1853. (setq haystack (cdr haystack))))
  1854. found))
  1855. (defun clojure-beginning-of-defun-function (&optional n)
  1856. "Go to top level form.
  1857. Set as `beginning-of-defun-function' so that these generic
  1858. operators can be used. Given a positive N it will do it that
  1859. many times."
  1860. (let ((beginning-of-defun-function nil))
  1861. (if (and clojure-toplevel-inside-comment-form
  1862. (clojure-top-level-form-p "comment"))
  1863. (condition-case nil
  1864. (save-match-data
  1865. (let ((original-position (point))
  1866. clojure-comment-end)
  1867. (beginning-of-defun)
  1868. (end-of-defun)
  1869. (setq clojure-comment-end (point))
  1870. (beginning-of-defun)
  1871. (forward-char 1) ;; skip paren so we start at comment
  1872. (clojure-forward-logical-sexp) ;; skip past the comment form itself
  1873. (if-let ((sexp-start (clojure-find-first (lambda (beg-pos)
  1874. (< beg-pos original-position))
  1875. (clojure-sexp-starts-until-position
  1876. clojure-comment-end))))
  1877. (progn (goto-char sexp-start) t)
  1878. (beginning-of-defun n))))
  1879. (scan-error (beginning-of-defun n)))
  1880. (beginning-of-defun n))))
  1881. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1882. ;;
  1883. ;; Refactoring support
  1884. ;;
  1885. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1886. ;;; Threading macros related
  1887. (defcustom clojure-thread-all-but-last nil
  1888. "Non-nil means do not thread the last expression.
  1889. This means that `clojure-thread-first-all' and
  1890. `clojure-thread-last-all' not thread the deepest sexp inside the
  1891. current sexp."
  1892. :package-version '(clojure-mode . "5.4.0")
  1893. :safe #'booleanp
  1894. :type 'boolean)
  1895. (defun clojure--point-after (&rest actions)
  1896. "Return POINT after performing ACTIONS.
  1897. An action is either the symbol of a function or a two element
  1898. list of (fn args) to pass to `apply''"
  1899. (save-excursion
  1900. (dolist (fn-and-args actions)
  1901. (let ((f (if (listp fn-and-args) (car fn-and-args) fn-and-args))
  1902. (args (if (listp fn-and-args) (cdr fn-and-args) nil)))
  1903. (apply f args)))
  1904. (point)))
  1905. (defun clojure--maybe-unjoin-line ()
  1906. "Undo a `join-line' done by a threading command."
  1907. (when (get-text-property (point) 'clojure-thread-line-joined)
  1908. (remove-text-properties (point) (1+ (point)) '(clojure-thread-line-joined t))
  1909. (insert "\n")))
  1910. (defun clojure--unwind-last ()
  1911. "Unwind a thread last macro once.
  1912. Point must be between the opening paren and the ->> symbol."
  1913. (forward-sexp)
  1914. (save-excursion
  1915. (let ((contents (clojure-delete-and-extract-sexp)))
  1916. (when (looking-at " *\n")
  1917. (join-line 'following))
  1918. (clojure--ensure-parens-around-function-names)
  1919. (let* ((sexp-beg-line (line-number-at-pos))
  1920. (sexp-end-line (progn (forward-sexp)
  1921. (line-number-at-pos)))
  1922. (multiline-sexp-p (not (= sexp-beg-line sexp-end-line))))
  1923. (down-list -1)
  1924. (if multiline-sexp-p
  1925. (insert "\n")
  1926. ;; `clojure--maybe-unjoin-line' only works when unwinding sexps that were
  1927. ;; threaded in the same Emacs session, but it also catches cases that
  1928. ;; `multiline-sexp-p' doesn't.
  1929. (clojure--maybe-unjoin-line))
  1930. (insert contents))))
  1931. (forward-char))
  1932. (defun clojure--ensure-parens-around-function-names ()
  1933. "Insert parens around function names if necessary."
  1934. (clojure--looking-at-non-logical-sexp)
  1935. (unless (looking-at "(")
  1936. (insert-parentheses 1)
  1937. (backward-up-list)))
  1938. (defun clojure--unwind-first ()
  1939. "Unwind a thread first macro once.
  1940. Point must be between the opening paren and the -> symbol."
  1941. (forward-sexp)
  1942. (save-excursion
  1943. (let ((contents (clojure-delete-and-extract-sexp)))
  1944. (when (looking-at " *\n")
  1945. (join-line 'following))
  1946. (clojure--ensure-parens-around-function-names)
  1947. (down-list)
  1948. (forward-sexp)
  1949. (insert contents)
  1950. (forward-sexp -1)
  1951. (clojure--maybe-unjoin-line)))
  1952. (forward-char))
  1953. (defun clojure--pop-out-of-threading ()
  1954. "Raise a sexp up a level to unwind a threading form."
  1955. (save-excursion
  1956. (down-list 2)
  1957. (backward-up-list)
  1958. (raise-sexp)))
  1959. (defun clojure--nothing-more-to-unwind ()
  1960. "Return non-nil if a threaded form cannot be unwound further."
  1961. (save-excursion
  1962. (let ((beg (point)))
  1963. (forward-sexp)
  1964. (down-list -1)
  1965. (backward-sexp 2) ;; the last sexp, the threading macro
  1966. (when (looking-back "(\\s-*" (line-beginning-position))
  1967. (backward-up-list)) ;; and the paren
  1968. (= beg (point)))))
  1969. (defun clojure--fix-sexp-whitespace (&optional move-out)
  1970. "Fix whitespace after unwinding a threading form.
  1971. Optional argument MOVE-OUT, if non-nil, means moves up a list
  1972. before fixing whitespace."
  1973. (save-excursion
  1974. (when move-out (backward-up-list))
  1975. (let ((sexp (bounds-of-thing-at-point 'sexp)))
  1976. (clojure-indent-region (car sexp) (cdr sexp))
  1977. (delete-trailing-whitespace (car sexp) (cdr sexp)))))
  1978. ;;;###autoload
  1979. (defun clojure-unwind (&optional n)
  1980. "Unwind thread at point or above point by N levels.
  1981. With universal argument \\[universal-argument], fully unwind thread."
  1982. (interactive "P")
  1983. (setq n (cond ((equal n '(4)) 999)
  1984. (n) (1)))
  1985. (save-excursion
  1986. (let ((limit (save-excursion
  1987. (beginning-of-defun)
  1988. (point))))
  1989. (ignore-errors
  1990. (when (looking-at "(")
  1991. (forward-char 1)
  1992. (forward-sexp 1)))
  1993. (while (> n 0)
  1994. (search-backward-regexp "([^-]*->" limit)
  1995. (if (clojure--nothing-more-to-unwind)
  1996. (progn (clojure--pop-out-of-threading)
  1997. (clojure--fix-sexp-whitespace)
  1998. (setq n 0)) ;; break out of loop
  1999. (down-list)
  2000. (cond
  2001. ((looking-at "[^-]*->\\_>") (clojure--unwind-first))
  2002. ((looking-at "[^-]*->>\\_>") (clojure--unwind-last)))
  2003. (clojure--fix-sexp-whitespace 'move-out)
  2004. (setq n (1- n)))))))
  2005. ;;;###autoload
  2006. (defun clojure-unwind-all ()
  2007. "Fully unwind thread at point or above point."
  2008. (interactive)
  2009. (clojure-unwind '(4)))
  2010. (defun clojure--remove-superfluous-parens ()
  2011. "Remove extra parens from a form."
  2012. (when (looking-at "([^ )]+)")
  2013. (delete-pair)))
  2014. (defun clojure--thread-first ()
  2015. "Thread a nested sexp using ->."
  2016. (down-list)
  2017. (forward-symbol 1)
  2018. (unless (looking-at ")")
  2019. (let ((contents (clojure-delete-and-extract-sexp)))
  2020. (backward-up-list)
  2021. (just-one-space 0)
  2022. (save-excursion
  2023. (insert contents "\n")
  2024. (clojure--remove-superfluous-parens))
  2025. (when (looking-at "\\s-*\n")
  2026. (join-line 'following)
  2027. (forward-char 1)
  2028. (put-text-property (point) (1+ (point))
  2029. 'clojure-thread-line-joined t))
  2030. t)))
  2031. (defun clojure--thread-last ()
  2032. "Thread a nested sexp using ->>."
  2033. (forward-sexp 2)
  2034. (down-list -1)
  2035. (backward-sexp)
  2036. (unless (eq (char-before) ?\()
  2037. (let ((contents (clojure-delete-and-extract-sexp)))
  2038. (just-one-space 0)
  2039. (backward-up-list)
  2040. (insert contents "\n")
  2041. (clojure--remove-superfluous-parens)
  2042. ;; cljr #255 Fix dangling parens
  2043. (forward-sexp)
  2044. (when (looking-back "^\\s-*\\()+\\)\\s-*" (line-beginning-position))
  2045. (let ((pos (match-beginning 1)))
  2046. (put-text-property pos (1+ pos) 'clojure-thread-line-joined t))
  2047. (join-line))
  2048. t)))
  2049. (defun clojure--threadable-p ()
  2050. "Return non-nil if a form can be threaded."
  2051. (save-excursion
  2052. (forward-symbol 1)
  2053. (looking-at "[\n\r\t ]*(")))
  2054. ;;;###autoload
  2055. (defun clojure-thread ()
  2056. "Thread by one more level an existing threading macro."
  2057. (interactive)
  2058. (ignore-errors
  2059. (when (looking-at "(")
  2060. (forward-char 1)
  2061. (forward-sexp 1)))
  2062. (search-backward-regexp "([^-]*->")
  2063. (down-list)
  2064. (when (clojure--threadable-p)
  2065. (prog1 (cond
  2066. ((looking-at "[^-]*->\\_>") (clojure--thread-first))
  2067. ((looking-at "[^-]*->>\\_>") (clojure--thread-last)))
  2068. (clojure--fix-sexp-whitespace 'move-out))))
  2069. (defun clojure--thread-all (first-or-last-thread but-last)
  2070. "Fully thread the form at point.
  2071. FIRST-OR-LAST-THREAD is \"->\" or \"->>\".
  2072. When BUT-LAST is non-nil, the last expression is not threaded.
  2073. Default value is `clojure-thread-all-but-last'."
  2074. (save-excursion
  2075. (insert-parentheses 1)
  2076. (insert first-or-last-thread))
  2077. (while (save-excursion (clojure-thread)))
  2078. (when (or but-last clojure-thread-all-but-last)
  2079. (clojure-unwind)))
  2080. ;;;###autoload
  2081. (defun clojure-thread-first-all (but-last)
  2082. "Fully thread the form at point using ->.
  2083. When BUT-LAST is non-nil, the last expression is not threaded.
  2084. Default value is `clojure-thread-all-but-last'."
  2085. (interactive "P")
  2086. (clojure--thread-all "-> " but-last))
  2087. ;;;###autoload
  2088. (defun clojure-thread-last-all (but-last)
  2089. "Fully thread the form at point using ->>.
  2090. When BUT-LAST is non-nil, the last expression is not threaded.
  2091. Default value is `clojure-thread-all-but-last'."
  2092. (interactive "P")
  2093. (clojure--thread-all "->> " but-last))
  2094. ;;; Cycling stuff
  2095. (defcustom clojure-use-metadata-for-privacy nil
  2096. "If nil, `clojure-cycle-privacy' will use (defn- f []).
  2097. If t, it will use (defn ^:private f [])."
  2098. :package-version '(clojure-mode . "5.5.0")
  2099. :safe #'booleanp
  2100. :type 'boolean)
  2101. ;;;###autoload
  2102. (defun clojure-cycle-privacy ()
  2103. "Make public the current private def, or vice-versa.
  2104. See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-cycle-privacy"
  2105. (interactive)
  2106. (save-excursion
  2107. (ignore-errors (forward-char 7))
  2108. (search-backward-regexp "(defn?\\(-\\| ^:private\\)?\\_>")
  2109. (if (match-string 1)
  2110. (replace-match "" nil nil nil 1)
  2111. (goto-char (match-end 0))
  2112. (insert (if (or clojure-use-metadata-for-privacy
  2113. (equal (match-string 0) "(def"))
  2114. " ^:private"
  2115. "-")))))
  2116. (defun clojure--convert-collection (coll-open coll-close)
  2117. "Convert the collection at (point) by unwrapping it an wrapping it between COLL-OPEN and COLL-CLOSE."
  2118. (save-excursion
  2119. (while (and
  2120. (not (bobp))
  2121. (not (looking-at "(\\|{\\|\\[")))
  2122. (backward-char))
  2123. (when (or (eq ?\# (char-before))
  2124. (eq ?\' (char-before)))
  2125. (delete-char -1))
  2126. (when (and (bobp)
  2127. (not (memq (char-after) '(?\{ ?\( ?\[))))
  2128. (user-error "Beginning of file reached, collection is not found"))
  2129. (insert coll-open (substring (clojure-delete-and-extract-sexp) 1 -1) coll-close)))
  2130. ;;;###autoload
  2131. (defun clojure-convert-collection-to-list ()
  2132. "Convert collection at (point) to list."
  2133. (interactive)
  2134. (clojure--convert-collection "(" ")"))
  2135. ;;;###autoload
  2136. (defun clojure-convert-collection-to-quoted-list ()
  2137. "Convert collection at (point) to quoted list."
  2138. (interactive)
  2139. (clojure--convert-collection "'(" ")"))
  2140. ;;;###autoload
  2141. (defun clojure-convert-collection-to-map ()
  2142. "Convert collection at (point) to map."
  2143. (interactive)
  2144. (clojure--convert-collection "{" "}"))
  2145. ;;;###autoload
  2146. (defun clojure-convert-collection-to-vector ()
  2147. "Convert collection at (point) to vector."
  2148. (interactive)
  2149. (clojure--convert-collection "[" "]"))
  2150. ;;;###autoload
  2151. (defun clojure-convert-collection-to-set ()
  2152. "Convert collection at (point) to set."
  2153. (interactive)
  2154. (clojure--convert-collection "#{" "}"))
  2155. (defun clojure--in-string-p ()
  2156. "Check whether the point is currently in a string."
  2157. (nth 3 (syntax-ppss)))
  2158. (defun clojure--in-comment-p ()
  2159. "Check whether the point is currently in a comment."
  2160. (nth 4 (syntax-ppss)))
  2161. (defun clojure--goto-if ()
  2162. "Find the first surrounding if or if-not expression."
  2163. (when (clojure--in-string-p)
  2164. (while (or (not (looking-at "("))
  2165. (clojure--in-string-p))
  2166. (backward-char)))
  2167. (while (not (looking-at "\\((if \\)\\|\\((if-not \\)"))
  2168. (condition-case nil
  2169. (backward-up-list)
  2170. (scan-error (user-error "No if or if-not found")))))
  2171. ;;;###autoload
  2172. (defun clojure-cycle-if ()
  2173. "Change a surrounding if to if-not, or vice-versa.
  2174. See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-cycle-if"
  2175. (interactive)
  2176. (save-excursion
  2177. (clojure--goto-if)
  2178. (cond
  2179. ((looking-at "(if-not")
  2180. (forward-char 3)
  2181. (delete-char 4)
  2182. (forward-sexp 2)
  2183. (transpose-sexps 1))
  2184. ((looking-at "(if")
  2185. (forward-char 3)
  2186. (insert "-not")
  2187. (forward-sexp 2)
  2188. (transpose-sexps 1)))))
  2189. ;; TODO: Remove code duplication with `clojure--goto-if'.
  2190. (defun clojure--goto-when ()
  2191. "Find the first surrounding when or when-not expression."
  2192. (when (clojure--in-string-p)
  2193. (while (or (not (looking-at "("))
  2194. (clojure--in-string-p))
  2195. (backward-char)))
  2196. (while (not (looking-at "\\((when \\)\\|\\((when-not \\)"))
  2197. (condition-case nil
  2198. (backward-up-list)
  2199. (scan-error (user-error "No when or when-not found")))))
  2200. ;;;###autoload
  2201. (defun clojure-cycle-when ()
  2202. "Change a surrounding when to when-not, or vice-versa."
  2203. (interactive)
  2204. (save-excursion
  2205. (clojure--goto-when)
  2206. (cond
  2207. ((looking-at "(when-not")
  2208. (forward-char 9)
  2209. (delete-char -4))
  2210. ((looking-at "(when")
  2211. (forward-char 5)
  2212. (insert "-not")))))
  2213. (defun clojure-cycle-not ()
  2214. "Add or remove a not form around the current form."
  2215. (interactive)
  2216. (save-excursion
  2217. (condition-case nil
  2218. (backward-up-list)
  2219. (scan-error (user-error "`clojure-cycle-not' must be invoked inside a list")))
  2220. (if (looking-back "(not " nil)
  2221. (progn
  2222. (delete-char -5)
  2223. (forward-sexp)
  2224. (delete-char 1))
  2225. (insert "(not ")
  2226. (forward-sexp)
  2227. (insert ")"))))
  2228. ;;; let related stuff
  2229. (defvar clojure--let-regexp
  2230. "\(\\(when-let\\|if-let\\|let\\)\\(\\s-*\\|\\[\\)"
  2231. "Regexp matching let like expressions, i.e. \"let\", \"when-let\", \"if-let\".
  2232. The first match-group is the let expression.
  2233. The second match-group is the whitespace or the opening square
  2234. bracket if no whitespace between the let expression and the
  2235. bracket.")
  2236. (defun clojure--goto-let ()
  2237. "Go to the beginning of the nearest let form."
  2238. (when (clojure--in-string-p)
  2239. (while (or (not (looking-at "("))
  2240. (clojure--in-string-p))
  2241. (backward-char)))
  2242. (ignore-errors
  2243. (while (not (looking-at clojure--let-regexp))
  2244. (backward-up-list)))
  2245. (looking-at clojure--let-regexp))
  2246. (defun clojure--inside-let-binding-p ()
  2247. "Return non-nil if point is inside a let binding."
  2248. (ignore-errors
  2249. (save-excursion
  2250. (let ((pos (point)))
  2251. (clojure--goto-let)
  2252. (re-search-forward "\\[")
  2253. (if (< pos (point))
  2254. nil
  2255. (forward-sexp)
  2256. (up-list)
  2257. (< pos (point)))))))
  2258. (defun clojure--beginning-of-current-let-binding ()
  2259. "Move before the bound name of the current binding.
  2260. Assume that point is in the binding form of a let."
  2261. (let ((current-point (point)))
  2262. (clojure--goto-let)
  2263. (search-forward "[")
  2264. (forward-char)
  2265. (while (> current-point (point))
  2266. (forward-sexp))
  2267. (backward-sexp 2)))
  2268. (defun clojure--previous-line ()
  2269. "Keep the column position while go the previous line."
  2270. (let ((col (current-column)))
  2271. (forward-line -1)
  2272. (move-to-column col)))
  2273. (defun clojure--prepare-to-insert-new-let-binding ()
  2274. "Move to right place in the let form to insert a new binding and indent."
  2275. (if (clojure--inside-let-binding-p)
  2276. (progn
  2277. (clojure--beginning-of-current-let-binding)
  2278. (newline-and-indent)
  2279. (clojure--previous-line)
  2280. (indent-for-tab-command))
  2281. (clojure--goto-let)
  2282. (search-forward "[")
  2283. (backward-up-list)
  2284. (forward-sexp)
  2285. (down-list -1)
  2286. (backward-char)
  2287. (if (looking-at "\\[\\s-*\\]")
  2288. (forward-char)
  2289. (forward-char)
  2290. (newline-and-indent))))
  2291. (defun clojure--sexp-regexp (sexp)
  2292. "Return a regexp for matching SEXP."
  2293. (concat "\\([^[:word:]^-]\\)"
  2294. (mapconcat #'identity (mapcar 'regexp-quote (split-string sexp))
  2295. "[[:space:]\n\r]+")
  2296. "\\([^[:word:]^-]\\)"))
  2297. (defun clojure--replace-sexp-with-binding (bound-name init-expr)
  2298. "Replace a binding with its bound name in the let form.
  2299. BOUND-NAME is the name (left-hand side) of a binding.
  2300. INIT-EXPR is the value (right-hand side) of a binding."
  2301. (save-excursion
  2302. (while (re-search-forward
  2303. (clojure--sexp-regexp init-expr)
  2304. (clojure--point-after 'clojure--goto-let 'forward-sexp)
  2305. t)
  2306. (replace-match (concat "\\1" bound-name "\\2")))))
  2307. (defun clojure--replace-sexps-with-bindings (bindings)
  2308. "Replace bindings with their respective bound names in the let form.
  2309. BINDINGS is the list of bound names and init expressions."
  2310. (let ((bound-name (pop bindings))
  2311. (init-expr (pop bindings)))
  2312. (when bound-name
  2313. (clojure--replace-sexp-with-binding bound-name init-expr)
  2314. (clojure--replace-sexps-with-bindings bindings))))
  2315. (defun clojure--replace-sexps-with-bindings-and-indent ()
  2316. "Replace sexps with bindings."
  2317. (clojure--replace-sexps-with-bindings
  2318. (clojure--read-let-bindings))
  2319. (clojure-indent-region
  2320. (clojure--point-after 'clojure--goto-let)
  2321. (clojure--point-after 'clojure--goto-let 'forward-sexp)))
  2322. (defun clojure--read-let-bindings ()
  2323. "Read the bound-name and init expression pairs in the binding form.
  2324. Return a list: odd elements are bound names, even elements init expressions."
  2325. (clojure--goto-let)
  2326. (down-list 2)
  2327. (let* ((start (point))
  2328. (sexp-start start)
  2329. (end (save-excursion
  2330. (backward-char)
  2331. (forward-sexp)
  2332. (down-list -1)
  2333. (point)))
  2334. bindings)
  2335. (while (/= sexp-start end)
  2336. (forward-sexp)
  2337. (push
  2338. (string-trim (buffer-substring-no-properties sexp-start (point)))
  2339. bindings)
  2340. (skip-chars-forward "\r\n\t[:blank:]")
  2341. (setq sexp-start (point)))
  2342. (nreverse bindings)))
  2343. (defun clojure--introduce-let-internal (name &optional n)
  2344. "Create a let form, binding the form at point with NAME.
  2345. Optional numeric argument N, if non-nil, introduces the let N
  2346. lists up."
  2347. (if (numberp n)
  2348. (let ((init-expr-sexp (clojure-delete-and-extract-sexp)))
  2349. (insert name)
  2350. (ignore-errors (backward-up-list n))
  2351. (insert "(let" (clojure-delete-and-extract-sexp) ")")
  2352. (backward-sexp)
  2353. (down-list)
  2354. (forward-sexp)
  2355. (insert " [" name " " init-expr-sexp "]\n")
  2356. (clojure--replace-sexps-with-bindings-and-indent))
  2357. (insert "[ " (clojure-delete-and-extract-sexp) "]")
  2358. (backward-sexp)
  2359. (insert "(let " (clojure-delete-and-extract-sexp) ")")
  2360. (backward-sexp)
  2361. (down-list 2)
  2362. (insert name)
  2363. (forward-sexp)
  2364. (up-list)
  2365. (newline-and-indent)
  2366. (insert name)))
  2367. (defun clojure--move-to-let-internal (name)
  2368. "Bind the form at point to NAME in the nearest let."
  2369. (if (not (save-excursion (clojure--goto-let)))
  2370. (clojure--introduce-let-internal name)
  2371. (let ((contents (clojure-delete-and-extract-sexp)))
  2372. (insert name)
  2373. (clojure--prepare-to-insert-new-let-binding)
  2374. (insert contents)
  2375. (backward-sexp)
  2376. (insert " ")
  2377. (backward-char)
  2378. (insert name)
  2379. (clojure--replace-sexps-with-bindings-and-indent))))
  2380. (defun clojure--let-backward-slurp-sexp-internal ()
  2381. "Slurp the s-expression before the let form into the let form."
  2382. (clojure--goto-let)
  2383. (backward-sexp)
  2384. (let ((sexp (string-trim (clojure-delete-and-extract-sexp))))
  2385. (delete-blank-lines)
  2386. (down-list)
  2387. (forward-sexp 2)
  2388. (newline-and-indent)
  2389. (insert sexp)
  2390. (clojure--replace-sexps-with-bindings-and-indent)))
  2391. (defun clojure--rename-ns-alias-internal (current-alias new-alias)
  2392. "Rename a namespace alias CURRENT-ALIAS to NEW-ALIAS."
  2393. (clojure--find-ns-in-direction 'backward)
  2394. (let ((rgx (concat ":as +" current-alias))
  2395. (bound (save-excursion (forward-list 1) (point))))
  2396. (when (search-forward-regexp rgx bound t)
  2397. (replace-match (concat ":as " new-alias))
  2398. (save-excursion
  2399. (while (re-search-forward (concat current-alias "/") nil t)
  2400. (when (not (nth 3 (syntax-ppss)))
  2401. (replace-match (concat new-alias "/")))))
  2402. (save-excursion
  2403. (while (re-search-forward (concat "#::" current-alias "{") nil t)
  2404. (replace-match (concat "#::" new-alias "{"))))
  2405. (message "Successfully renamed alias '%s' to '%s'" current-alias new-alias))))
  2406. ;;;###autoload
  2407. (defun clojure-let-backward-slurp-sexp (&optional n)
  2408. "Slurp the s-expression before the let form into the let form.
  2409. With a numeric prefix argument slurp the previous N s-expressions
  2410. into the let form."
  2411. (interactive "p")
  2412. (let ((n (or n 1)))
  2413. (dotimes (_ n)
  2414. (save-excursion (clojure--let-backward-slurp-sexp-internal)))))
  2415. (defun clojure--let-forward-slurp-sexp-internal ()
  2416. "Slurp the next s-expression after the let form into the let form."
  2417. (clojure--goto-let)
  2418. (forward-sexp)
  2419. (let ((sexp (string-trim (clojure-delete-and-extract-sexp))))
  2420. (down-list -1)
  2421. (newline-and-indent)
  2422. (insert sexp)
  2423. (clojure--replace-sexps-with-bindings-and-indent)))
  2424. ;;;###autoload
  2425. (defun clojure-let-forward-slurp-sexp (&optional n)
  2426. "Slurp the next s-expression after the let form into the let form.
  2427. With a numeric prefix argument slurp the next N s-expressions
  2428. into the let form."
  2429. (interactive "p")
  2430. (unless n (setq n 1))
  2431. (dotimes (_ n)
  2432. (save-excursion (clojure--let-forward-slurp-sexp-internal))))
  2433. ;;;###autoload
  2434. (defun clojure-introduce-let (&optional n)
  2435. "Create a let form, binding the form at point.
  2436. With a numeric prefix argument the let is introduced N lists up."
  2437. (interactive "P")
  2438. (clojure--introduce-let-internal (read-from-minibuffer "Name of bound symbol: ") n))
  2439. ;;;###autoload
  2440. (defun clojure-move-to-let ()
  2441. "Move the form at point to a binding in the nearest let."
  2442. (interactive)
  2443. (clojure--move-to-let-internal (read-from-minibuffer "Name of bound symbol: ")))
  2444. ;;;###autoload
  2445. (defun clojure-rename-ns-alias ()
  2446. "Rename a namespace alias."
  2447. (interactive)
  2448. (let ((current-alias (read-from-minibuffer "Current alias: ")))
  2449. (save-excursion
  2450. (clojure--find-ns-in-direction 'backward)
  2451. (let ((rgx (concat ":as +" current-alias))
  2452. (bound (save-excursion (forward-list 1) (point))))
  2453. (if (save-excursion (search-forward-regexp rgx bound t))
  2454. (let ((new-alias (read-from-minibuffer "New alias: ")))
  2455. (clojure--rename-ns-alias-internal current-alias new-alias))
  2456. (message "Cannot find namespace alias: '%s'" current-alias))))))
  2457. (defun clojure--add-arity-defprotocol-internal ()
  2458. "Add an arity to a signature inside a defprotocol.
  2459. Assumes cursor is at beginning of signature."
  2460. (re-search-forward "\\[")
  2461. (save-excursion (insert "] [")))
  2462. (defun clojure--add-arity-reify-internal ()
  2463. "Add an arity to a function inside a reify.
  2464. Assumes cursor is at beginning of function."
  2465. (re-search-forward "\\(\\w+ \\)")
  2466. (insert "[")
  2467. (save-excursion (insert "])\n(" (match-string 0))))
  2468. (defun clojure--add-arity-internal ()
  2469. "Add an arity to a function.
  2470. Assumes cursor is at beginning of function."
  2471. (let ((beg-line (what-line))
  2472. (end (save-excursion (forward-sexp)
  2473. (point))))
  2474. (down-list 2)
  2475. (when (looking-back "{" 1) ;; skip metadata if present
  2476. (up-list)
  2477. (down-list))
  2478. (cond
  2479. ((looking-back "(" 1) ;; multi-arity fn
  2480. (insert "[")
  2481. (save-excursion (insert "])\n(")))
  2482. ((looking-back "\\[" 1) ;; single-arity fn
  2483. (let* ((same-line (string= beg-line (what-line)))
  2484. (new-arity-text (concat (when same-line "\n") "([")))
  2485. (save-excursion
  2486. (goto-char end)
  2487. (insert ")"))
  2488. (re-search-backward " +\\[")
  2489. (replace-match new-arity-text)
  2490. (save-excursion (insert "])\n([")))))))
  2491. ;;;###autoload
  2492. (defun clojure-add-arity ()
  2493. "Add an arity to a function."
  2494. (interactive)
  2495. (let ((original-pos (point))
  2496. (n 0))
  2497. (while (not (looking-at-p "(\\(defn\\|letfn\\|fn\\|defmacro\\|defmethod\\|defprotocol\\|reify\\|proxy\\)"))
  2498. (setq n (1+ n))
  2499. (backward-up-list 1 t))
  2500. (let ((beg (point))
  2501. (end-marker (make-marker))
  2502. (end (save-excursion (forward-sexp)
  2503. (point)))
  2504. (jump-up (lambda (x)
  2505. (goto-char original-pos)
  2506. (backward-up-list x t))))
  2507. (set-marker end-marker end)
  2508. (cond
  2509. ((looking-at-p "(\\(defn\\|fn\\|defmethod\\|defmacro\\)")
  2510. (clojure--add-arity-internal))
  2511. ((looking-at-p "(letfn")
  2512. (funcall jump-up (- n 2))
  2513. (clojure--add-arity-internal))
  2514. ((looking-at-p "(proxy")
  2515. (funcall jump-up (- n 1))
  2516. (clojure--add-arity-internal))
  2517. ((looking-at-p "(defprotocol")
  2518. (funcall jump-up (- n 1))
  2519. (clojure--add-arity-defprotocol-internal))
  2520. ((looking-at-p "(reify")
  2521. (funcall jump-up (- n 1))
  2522. (clojure--add-arity-reify-internal)))
  2523. (indent-region beg end-marker))))
  2524. ;;; ClojureScript
  2525. (defconst clojurescript-font-lock-keywords
  2526. (eval-when-compile
  2527. `(;; ClojureScript built-ins
  2528. (,(concat "(\\(?:\.*/\\)?"
  2529. (regexp-opt '("js-obj" "js-delete" "clj->js" "js->clj"))
  2530. "\\>")
  2531. 0 font-lock-builtin-face)))
  2532. "Additional font-locking for `clojurescript-mode'.")
  2533. ;;;###autoload
  2534. (define-derived-mode clojurescript-mode clojure-mode "ClojureScript"
  2535. "Major mode for editing ClojureScript code.
  2536. \\{clojurescript-mode-map}"
  2537. (font-lock-add-keywords nil clojurescript-font-lock-keywords))
  2538. ;;;###autoload
  2539. (define-derived-mode clojurec-mode clojure-mode "ClojureC"
  2540. "Major mode for editing ClojureC code.
  2541. \\{clojurec-mode-map}")
  2542. ;;;###autoload
  2543. (progn
  2544. (add-to-list 'auto-mode-alist
  2545. '("\\.\\(clj\\|dtm\\|edn\\)\\'" . clojure-mode))
  2546. (add-to-list 'auto-mode-alist '("\\.cljc\\'" . clojurec-mode))
  2547. (add-to-list 'auto-mode-alist '("\\.cljs\\'" . clojurescript-mode))
  2548. ;; boot build scripts are Clojure source files
  2549. (add-to-list 'auto-mode-alist '("\\(?:build\\|profile\\)\\.boot\\'" . clojure-mode)))
  2550. (provide 'clojure-mode)
  2551. ;; Local Variables:
  2552. ;; coding: utf-8
  2553. ;; End:
  2554. ;;; clojure-mode.el ends here