/.emacs.d/lib/clojure-mode/clojure-mode.el
Emacs Lisp | 2357 lines | 1892 code | 231 blank | 234 comment | 47 complexity | 0337fbff3e1039ed402e7c604228c70d MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0
Large files files are truncated, but you can click here to view the full file
- ;;; clojure-mode.el --- Major mode for Clojure code -*- lexical-binding: t; -*-
- ;; Copyright © 2007-2016 Jeffrey Chu, Lennart Staflin, Phil Hagelberg
- ;; Copyright © 2013-2016 Bozhidar Batsov, Artur Malabarba
- ;;
- ;; Authors: Jeffrey Chu <jochu0@gmail.com>
- ;; Lennart Staflin <lenst@lysator.liu.se>
- ;; Phil Hagelberg <technomancy@gmail.com>
- ;; Bozhidar Batsov <bozhidar@batsov.com>
- ;; Artur Malabarba <bruce.connor.am@gmail.com>
- ;; URL: http://github.com/clojure-emacs/clojure-mode
- ;; Keywords: languages clojure clojurescript lisp
- ;; Version: 5.6.0
- ;; Package-Requires: ((emacs "24.4"))
- ;; This file is not part of GNU Emacs.
- ;;; Commentary:
- ;; Provides font-lock, indentation, navigation and basic refactoring for the
- ;; Clojure programming language (http://clojure.org).
- ;; Using clojure-mode with paredit or smartparens is highly recommended.
- ;; Here are some example configurations:
- ;; ;; require or autoload paredit-mode
- ;; (add-hook 'clojure-mode-hook #'paredit-mode)
- ;; ;; require or autoload smartparens
- ;; (add-hook 'clojure-mode-hook #'smartparens-strict-mode)
- ;; See inf-clojure (http://github.com/clojure-emacs/inf-clojure) for
- ;; basic interaction with Clojure subprocesses.
- ;; See CIDER (http://github.com/clojure-emacs/cider) for
- ;; better interaction with subprocesses via nREPL.
- ;;; License:
- ;; This program is free software; you can redistribute it and/or
- ;; modify it under the terms of the GNU General Public License
- ;; as published by the Free Software Foundation; either version 3
- ;; of the License, or (at your option) any later version.
- ;;
- ;; This program is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;;
- ;; You should have received a copy of the GNU General Public License
- ;; along with GNU Emacs; see the file COPYING. If not, write to the
- ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- ;; Boston, MA 02110-1301, USA.
- ;;; Code:
- (eval-when-compile
- (defvar calculate-lisp-indent-last-sexp)
- (defvar font-lock-beg)
- (defvar font-lock-end)
- (defvar paredit-space-for-delimiter-predicates)
- (defvar paredit-version)
- (defvar paredit-mode))
- (require 'cl-lib)
- (require 'imenu)
- (require 'newcomment)
- (require 'align)
- (require 'subr-x)
- (declare-function lisp-fill-paragraph "lisp-mode" (&optional justify))
- (defgroup clojure nil
- "Major mode for editing Clojure code."
- :prefix "clojure-"
- :group 'languages
- :link '(url-link :tag "Github" "https://github.com/clojure-emacs/clojure-mode")
- :link '(emacs-commentary-link :tag "Commentary" "clojure-mode"))
- (defconst clojure-mode-version "5.5.2"
- "The current version of `clojure-mode'.")
- (defface clojure-keyword-face
- '((t (:inherit font-lock-constant-face)))
- "Face used to font-lock Clojure keywords (:something)."
- :package-version '(clojure-mode . "3.0.0"))
- (defface clojure-character-face
- '((t (:inherit font-lock-string-face)))
- "Face used to font-lock Clojure character literals."
- :package-version '(clojure-mode . "3.0.0"))
- (defface clojure-interop-method-face
- '((t (:inherit font-lock-preprocessor-face)))
- "Face used to font-lock interop method names (camelCase)."
- :package-version '(clojure-mode . "3.0.0"))
- (defcustom clojure-indent-style :always-align
- "Indentation style to use for function forms and macro forms.
- There are two cases of interest configured by this variable.
- - Case (A) is when at least one function argument is on the same
- line as the function name.
- - Case (B) is the opposite (no arguments are on the same line as
- the function name). Note that the body of macros is not
- affected by this variable, it is always indented by
- `lisp-body-indent' (default 2) spaces.
- Note that this variable configures the indentation of function
- forms (and function-like macros), it does not affect macros that
- already use special indentation rules.
- The possible values for this variable are keywords indicating how
- to indent function forms.
- `:always-align' - Follow the same rules as `lisp-mode'. All
- args are vertically aligned with the first arg in case (A),
- and vertically aligned with the function name in case (B).
- For instance:
- (reduce merge
- some-coll)
- (reduce
- merge
- some-coll)
- `:always-indent' - All args are indented like a macro body.
- (reduce merge
- some-coll)
- (reduce
- merge
- some-coll)
- `:align-arguments' - Case (A) is indented like `lisp', and
- case (B) is indented like a macro body.
- (reduce merge
- some-coll)
- (reduce
- merge
- some-coll)"
- :safe #'keywordp
- :type '(choice (const :tag "Same as `lisp-mode'" :always-align)
- (const :tag "Indent like a macro body" :always-indent)
- (const :tag "Indent like a macro body unless first arg is on the same line"
- :align-arguments))
- :package-version '(clojure-mode . "5.2.0"))
- (define-obsolete-variable-alias 'clojure-defun-style-default-indent
- 'clojure-indent-style "5.2.0")
- (defcustom clojure-use-backtracking-indent t
- "When non-nil, enable context sensitive indentation."
- :type 'boolean
- :safe 'booleanp)
- (defcustom clojure-max-backtracking 3
- "Maximum amount to backtrack up a list to check for context."
- :type 'integer
- :safe 'integerp)
- (defcustom clojure-docstring-fill-column fill-column
- "Value of `fill-column' to use when filling a docstring."
- :type 'integer
- :safe 'integerp)
- (defcustom clojure-docstring-fill-prefix-width 2
- "Width of `fill-prefix' when filling a docstring.
- The default value conforms with the de facto convention for
- Clojure docstrings, aligning the second line with the opening
- double quotes on the third column."
- :type 'integer
- :safe 'integerp)
- (defcustom clojure-omit-space-between-tag-and-delimiters '(?\[ ?\{)
- "Allowed opening delimiter characters after a reader literal tag.
- For example, \[ is allowed in :db/id[:db.part/user]."
- :type '(set (const :tag "[" ?\[)
- (const :tag "{" ?\{)
- (const :tag "(" ?\()
- (const :tag "\"" ?\"))
- :safe (lambda (value)
- (and (listp value)
- (cl-every 'characterp value))))
- (defcustom clojure-build-tool-files '("project.clj" "build.boot" "build.gradle")
- "A list of files, which identify a Clojure project's root.
- Out-of-the box clojure-mode understands lein, boot and gradle."
- :type '(repeat string)
- :package-version '(clojure-mode . "5.0.0")
- :safe (lambda (value)
- (and (listp value)
- (cl-every 'stringp value))))
- (defcustom clojure-refactor-map-prefix (kbd "C-c C-r")
- "Clojure refactor keymap prefix."
- :group 'clojure
- :type 'string
- :package-version '(clojure-mode . "5.6.0"))
- (defvar clojure-refactor-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-t") #'clojure-thread)
- (define-key map (kbd "t") #'clojure-thread)
- (define-key map (kbd "C-u") #'clojure-unwind)
- (define-key map (kbd "u") #'clojure-unwind)
- (define-key map (kbd "C-f") #'clojure-thread-first-all)
- (define-key map (kbd "f") #'clojure-thread-first-all)
- (define-key map (kbd "C-l") #'clojure-thread-last-all)
- (define-key map (kbd "l") #'clojure-thread-last-all)
- (define-key map (kbd "C-a") #'clojure-unwind-all)
- (define-key map (kbd "a") #'clojure-unwind-all)
- (define-key map (kbd "C-p") #'clojure-cycle-privacy)
- (define-key map (kbd "p") #'clojure-cycle-privacy)
- (define-key map (kbd "C-(") #'clojure-convert-collection-to-list)
- (define-key map (kbd "(") #'clojure-convert-collection-to-list)
- (define-key map (kbd "C-'") #'clojure-convert-collection-to-quoted-list)
- (define-key map (kbd "'") #'clojure-convert-collection-to-quoted-list)
- (define-key map (kbd "C-{") #'clojure-convert-collection-to-map)
- (define-key map (kbd "{") #'clojure-convert-collection-to-map)
- (define-key map (kbd "C-[") #'clojure-convert-collection-to-vector)
- (define-key map (kbd "[") #'clojure-convert-collection-to-vector)
- (define-key map (kbd "C-#") #'clojure-convert-collection-to-set)
- (define-key map (kbd "#") #'clojure-convert-collection-to-set)
- (define-key map (kbd "C-i") #'clojure-cycle-if)
- (define-key map (kbd "i") #'clojure-cycle-if)
- (define-key map (kbd "n i") #'clojure-insert-ns-form)
- (define-key map (kbd "n h") #'clojure-insert-ns-form-at-point)
- (define-key map (kbd "n u") #'clojure-update-ns)
- (define-key map (kbd "n s") #'clojure-sort-ns)
- (define-key map (kbd "s i") #'clojure-introduce-let)
- (define-key map (kbd "s m") #'clojure-move-to-let)
- (define-key map (kbd "s f") #'clojure-let-forward-slurp-sexp)
- (define-key map (kbd "s b") #'clojure-let-backward-slurp-sexp)
- map)
- "Keymap for Clojure refactoring commands.")
- (fset 'clojure-refactor-map clojure-refactor-map)
- (defvar clojure-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-:") #'clojure-toggle-keyword-string)
- (define-key map (kbd "C-c SPC") #'clojure-align)
- (define-key map clojure-refactor-map-prefix 'clojure-refactor-map)
- (easy-menu-define clojure-mode-menu map "Clojure Mode Menu"
- '("Clojure"
- ["Toggle between string & keyword" clojure-toggle-keyword-string]
- ["Align expression" clojure-align]
- ["Cycle privacy" clojure-cycle-privacy]
- ["Cycle if, if-not" clojure-cycle-if]
- ("ns forms"
- ["Insert ns form at the top" clojure-insert-ns-form]
- ["Insert ns form here" clojure-insert-ns-form-at-point]
- ["Update ns form" clojure-update-ns]
- ["Sort ns form" clojure-sort-ns])
- ("Convert collection"
- ["Convert to list" clojure-convert-collection-to-list]
- ["Convert to quoted list" clojure-convert-collection-to-quoted-list]
- ["Convert to map" clojure-convert-collection-to-map]
- ["Convert to vector" clojure-convert-collection-to-vector]
- ["Convert to set" clojure-convert-collection-to-set])
- ("Refactor -> and ->>"
- ["Thread once more" clojure-thread]
- ["Fully thread a form with ->" clojure-thread-first-all]
- ["Fully thread a form with ->>" clojure-thread-last-all]
- "--"
- ["Unwind once" clojure-unwind]
- ["Fully unwind a threading macro" clojure-unwind-all])
- ("Let expression"
- ["Introduce let" clojure-introduce-let]
- ["Move to let" clojure-move-to-let]
- ["Forward slurp form into let" clojure-let-forward-slurp-sexp]
- ["Backward slurp form into let" clojure-let-backward-slurp-sexp])
- ("Documentation"
- ["View a Clojure guide" clojure-view-guide]
- ["View a Clojure reference section" clojure-view-reference-section]
- ["View the Clojure cheatsheet" clojure-view-cheatsheet]
- ["View the Clojure Grimoire" clojure-view-grimoire]
- ["View the Clojure style guide" clojure-view-style-guide])
- "--"
- ["Report a clojure-mode bug" clojure-mode-report-bug]
- ["Clojure-mode version" clojure-mode-display-version]))
- map)
- "Keymap for Clojure mode.")
- (defvar clojure-mode-syntax-table
- (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
- (modify-syntax-entry ?\{ "(}" table)
- (modify-syntax-entry ?\} "){" table)
- (modify-syntax-entry ?\[ "(]" table)
- (modify-syntax-entry ?\] ")[" table)
- (modify-syntax-entry ?? "_ p" table) ; ? is a prefix outside symbols
- (modify-syntax-entry ?# "_ p" table) ; # is allowed inside keywords (#399)
- (modify-syntax-entry ?~ "'" table)
- (modify-syntax-entry ?^ "'" table)
- (modify-syntax-entry ?@ "'" table)
- table)
- "Syntax table for Clojure mode.
- Inherits from `emacs-lisp-mode-syntax-table'.")
- (defconst clojure--prettify-symbols-alist
- '(("fn" . ?λ)))
- (defvar-local clojure-expected-ns-function nil
- "The function used to determine the expected namespace of a file.
- `clojure-mode' ships a basic function named `clojure-expected-ns'
- that does basic heuristics to figure this out.
- CIDER provides a more complex version which does classpath analysis.")
- (defun clojure-mode-display-version ()
- "Display the current `clojure-mode-version' in the minibuffer."
- (interactive)
- (message "clojure-mode (version %s)" clojure-mode-version))
- (defconst clojure-mode-report-bug-url "https://github.com/clojure-emacs/clojure-mode/issues/new"
- "The URL to report a clojure-mode issue.")
- (defun clojure-mode-report-bug ()
- "Report a bug in your default browser."
- (interactive)
- (browse-url clojure-mode-report-bug-url))
- (defconst clojure-guides-base-url "https://clojure.org/guides/"
- "The base URL for official Clojure guides.")
- (defconst clojure-guides '(("Getting Started" . "getting_started")
- ("FAQ" . "faq")
- ("spec" . "spec")
- ("Destructuring" . "destructuring")
- ("Threading Macros" . "threading_macros")
- ("Comparators" . "comparators")
- ("Reader Conditionals" . "reader_conditionals"))
- "A list of all official Clojure guides.")
- (defun clojure-view-guide ()
- "Open a Clojure guide in your default browser.
- The command will prompt you to select one of the available guides."
- (interactive)
- (let ((guide (completing-read "Select a guide: " (mapcar #'car clojure-guides))))
- (when guide
- (let ((guide-url (concat clojure-guides-base-url (cdr (assoc guide clojure-guides)))))
- (browse-url guide-url)))))
- (defconst clojure-reference-base-url "https://clojure.org/reference/"
- "The base URL for the official Clojure reference.")
- (defconst clojure-reference-sections '(("The Reader" . "reader")
- ("The REPL and main" . "repl_and_main")
- ("Evaluation" . "evaluation")
- ("Special Forms" . "special_forms")
- ("Macros" . "macros")
- ("Other Functions" . "other_functions")
- ("Data Structures" . "data_structures")
- ("Datatypes" . "datatypes")
- ("Sequences" . "sequences")
- ("Transients" . "transients")
- ("Transducers" . "transducers")
- ("Multimethods and Hierarchies" . "multimethods")
- ("Protocols" . "protocols")
- ("Metadata" . "metadata")
- ("Namespaces" . "namespaces")
- ("Libs" . "libs")
- ("Vars and Environments" . "vars")
- ("Refs and Transactions" . "refs")
- ("Agents" . "agents")
- ("Atoms" . "atoms")
- ("Reducers" . "reducers")
- ("Java Interop" . "java_interop")
- ("Compilation and Class Generation" . "compilation")
- ("Other Libraries" . "other_libraries")
- ("Differences with Lisps" . "lisps")))
- (defun clojure-view-reference-section ()
- "Open a Clojure reference section in your default browser.
- The command will prompt you to select one of the available sections."
- (interactive)
- (let ((section (completing-read "Select a reference section: " (mapcar #'car clojure-reference-sections))))
- (when section
- (let ((section-url (concat clojure-reference-base-url (cdr (assoc section clojure-reference-sections)))))
- (browse-url section-url)))))
- (defconst clojure-cheatsheet-url "http://clojure.org/api/cheatsheet"
- "The URL of the official Clojure cheatsheet.")
- (defun clojure-view-cheatsheet ()
- "Open the Clojure cheatsheet in your default browser."
- (interactive)
- (browse-url clojure-cheatsheet-url))
- (defconst clojure-grimoire-url "https://www.conj.io/"
- "The URL of the Grimoire community documentation site.")
- (defun clojure-view-grimoire ()
- "Open the Clojure Grimoire in your default browser."
- (interactive)
- (browse-url clojure-grimoire-url))
- (defconst clojure-style-guide-url "https://github.com/bbatsov/clojure-style-guide"
- "The URL of the Clojure style guide.")
- (defun clojure-view-style-guide ()
- "Open the Clojure style guide in your default browser."
- (interactive)
- (browse-url clojure-style-guide-url))
- (defun clojure-space-for-delimiter-p (endp delim)
- "Prevent paredit from inserting useless spaces.
- See `paredit-space-for-delimiter-predicates' for the meaning of
- ENDP and DELIM."
- (or endp
- (not (memq delim '(?\" ?{ ?\( )))
- (not (or (derived-mode-p 'clojure-mode)
- (derived-mode-p 'cider-repl-mode)))
- (save-excursion
- (backward-char)
- (cond ((eq (char-after) ?#)
- (and (not (bobp))
- (or (char-equal ?w (char-syntax (char-before)))
- (char-equal ?_ (char-syntax (char-before))))))
- ((and (eq delim ?\()
- (eq (char-after) ??)
- (eq (char-before) ?#))
- nil)
- (t)))))
- (defun clojure-no-space-after-tag (endp delimiter)
- "Prevent inserting a space after a reader-literal tag?
- When a reader-literal tag is followed be an opening delimiter
- listed in `clojure-omit-space-between-tag-and-delimiters', this
- function returns t.
- This allows you to write things like #db/id[:db.part/user]
- without inserting a space between the tag and the opening
- bracket.
- See `paredit-space-for-delimiter-predicates' for the meaning of
- ENDP and DELIMITER."
- (if endp
- t
- (or (not (member delimiter clojure-omit-space-between-tag-and-delimiters))
- (save-excursion
- (let ((orig-point (point)))
- (not (and (re-search-backward
- "#\\([a-zA-Z0-9._-]+/\\)?[a-zA-Z0-9._-]+"
- (line-beginning-position)
- t)
- (= orig-point (match-end 0)))))))))
- (declare-function paredit-open-curly "ext:paredit")
- (declare-function paredit-close-curly "ext:paredit")
- (declare-function paredit-convolute-sexp "ext:paredit")
- (defun clojure--replace-let-bindings-and-indent (orig-fun &rest args)
- "Advise `paredit-convolute-sexp' to replace s-expressions with their bound name if a let form was convoluted."
- (save-excursion
- (backward-sexp)
- (when (looking-back clojure--let-regexp)
- (clojure--replace-sexps-with-bindings-and-indent))))
- (defun clojure-paredit-setup (&optional keymap)
- "Make \"paredit-mode\" play nice with `clojure-mode'.
- If an optional KEYMAP is passed the changes are applied to it,
- instead of to `clojure-mode-map'.
- Also advice `paredit-convolute-sexp' when used on a let form as drop in
- replacement for `cljr-expand-let`."
- (when (>= paredit-version 21)
- (let ((keymap (or keymap clojure-mode-map)))
- (define-key keymap "{" #'paredit-open-curly)
- (define-key keymap "}" #'paredit-close-curly))
- (add-to-list 'paredit-space-for-delimiter-predicates
- #'clojure-space-for-delimiter-p)
- (add-to-list 'paredit-space-for-delimiter-predicates
- #'clojure-no-space-after-tag)
- (advice-add 'paredit-convolute-sexp :after #'clojure--replace-let-bindings-and-indent)))
- (defun clojure-mode-variables ()
- "Set up initial buffer-local variables for Clojure mode."
- (add-to-list 'imenu-generic-expression '(nil clojure-match-next-def 0))
- (setq-local indent-tabs-mode nil)
- (setq-local paragraph-ignore-fill-prefix t)
- (setq-local outline-regexp ";;;\\(;* [^ \t\n]\\)\\|(")
- (setq-local outline-level 'lisp-outline-level)
- (setq-local comment-start ";")
- (setq-local comment-start-skip ";+ *")
- (setq-local comment-add 1) ; default to `;;' in comment-region
- (setq-local comment-column 40)
- (setq-local comment-use-syntax t)
- (setq-local multibyte-syntax-as-symbol t)
- (setq-local electric-pair-skip-whitespace 'chomp)
- (setq-local electric-pair-open-newline-between-pairs nil)
- (setq-local fill-paragraph-function #'clojure-fill-paragraph)
- (setq-local adaptive-fill-function #'clojure-adaptive-fill-function)
- (setq-local normal-auto-fill-function #'clojure-auto-fill-function)
- (setq-local comment-start-skip
- "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")
- (setq-local indent-line-function #'clojure-indent-line)
- (setq-local indent-region-function #'clojure-indent-region)
- (setq-local lisp-indent-function #'clojure-indent-function)
- (setq-local lisp-doc-string-elt-property 'clojure-doc-string-elt)
- (setq-local clojure-expected-ns-function #'clojure-expected-ns)
- (setq-local parse-sexp-ignore-comments t)
- (setq-local prettify-symbols-alist clojure--prettify-symbols-alist)
- (setq-local open-paren-in-column-0-is-defun-start nil))
- ;;;###autoload
- (define-derived-mode clojure-mode prog-mode "Clojure"
- "Major mode for editing Clojure code.
- \\{clojure-mode-map}"
- (clojure-mode-variables)
- (clojure-font-lock-setup)
- (add-hook 'paredit-mode-hook #'clojure-paredit-setup))
- (defcustom clojure-verify-major-mode t
- "If non-nil, warn when activating the wrong major-mode."
- :type 'boolean
- :safe #'booleanp
- :package-version '(clojure-mode "5.3.0"))
- (defun clojure--check-wrong-major-mode ()
- "Check if the current major-mode matches the file extension.
- If it doesn't, issue a warning if `clojure-verify-major-mode' is
- non-nil."
- (when (and clojure-verify-major-mode
- (stringp (buffer-file-name)))
- (let* ((case-fold-search t)
- (problem (cond ((and (string-match "\\.clj\\'" (buffer-file-name))
- (not (eq major-mode 'clojure-mode)))
- 'clojure-mode)
- ((and (string-match "\\.cljs\\'" (buffer-file-name))
- (not (eq major-mode 'clojurescript-mode)))
- 'clojurescript-mode)
- ((and (string-match "\\.cljc\\'" (buffer-file-name))
- (not (eq major-mode 'clojurec-mode)))
- 'clojurec-mode)
- ((and (string-match "\\.cljx\\'" (buffer-file-name))
- (not (eq major-mode 'clojurex-mode)))
- 'clojurex-mode))))
- (when problem
- (message "[WARNING] %s activated `%s' instead of `%s' in this buffer.
- This could cause problems.
- \(See `clojure-verify-major-mode' to disable this message.)"
- (if (eq major-mode real-this-command)
- "You have"
- "Something in your configuration")
- major-mode
- problem)))))
- (add-hook 'clojure-mode-hook #'clojure--check-wrong-major-mode)
- (defsubst clojure-in-docstring-p ()
- "Check whether point is in a docstring."
- (eq (get-text-property (point) 'face) 'font-lock-doc-face))
- (defsubst clojure-docstring-fill-prefix ()
- "The prefix string used by `clojure-fill-paragraph'.
- It is simply `clojure-docstring-fill-prefix-width' number of spaces."
- (make-string clojure-docstring-fill-prefix-width ? ))
- (defun clojure-adaptive-fill-function ()
- "Clojure adaptive fill function.
- This only takes care of filling docstring correctly."
- (when (clojure-in-docstring-p)
- (clojure-docstring-fill-prefix)))
- (defun clojure-fill-paragraph (&optional justify)
- "Like `fill-paragraph', but can handle Clojure docstrings.
- If JUSTIFY is non-nil, justify as well as fill the paragraph."
- (if (clojure-in-docstring-p)
- (let ((paragraph-start
- (concat paragraph-start
- "\\|\\s-*\\([(;:\"[]\\|~@\\|`(\\|#'(\\)"))
- (paragraph-separate
- (concat paragraph-separate "\\|\\s-*\".*[,\\.]$"))
- (fill-column (or clojure-docstring-fill-column fill-column))
- (fill-prefix (clojure-docstring-fill-prefix)))
- (fill-paragraph justify))
- (let ((paragraph-start (concat paragraph-start
- "\\|\\s-*\\([(;:\"[]\\|`(\\|#'(\\)"))
- (paragraph-separate
- (concat paragraph-separate "\\|\\s-*\".*[,\\.[]$")))
- (or (fill-comment-paragraph justify)
- (fill-paragraph justify))
- ;; Always return `t'
- t)))
- (defun clojure-auto-fill-function ()
- "Clojure auto-fill function."
- ;; Check if auto-filling is meaningful.
- (let ((fc (current-fill-column)))
- (when (and fc (> (current-column) fc))
- (let ((fill-column (if (clojure-in-docstring-p)
- clojure-docstring-fill-column
- fill-column))
- (fill-prefix (clojure-adaptive-fill-function)))
- (do-auto-fill)))))
- ;;; #_ comments font-locking
- ;; Code heavily borrowed from Slime.
- ;; https://github.com/slime/slime/blob/master/contrib/slime-fontifying-fu.el#L186
- (defvar clojure--comment-macro-regexp
- (rx "#_" (* " ") (group-n 1 (not (any " "))))
- "Regexp matching the start of a comment sexp.
- The beginning of match-group 1 should be before the sexp to be
- marked as a comment. The end of sexp is found with
- `clojure-forward-logical-sexp'.
- By default, this only applies to code after the `#_' reader
- macro. In order to also font-lock the `(comment ...)' macro as a
- comment, you can set the value to:
- \"#_ *\\\\(?1:[^ ]\\\\)\\\\|\\\\(?1:(comment\\\\_>\\\\)\"")
- (defun clojure--search-comment-macro-internal (limit)
- (when (search-forward-regexp clojure--comment-macro-regexp limit t)
- (let* ((md (match-data))
- (start (match-beginning 1))
- (state (syntax-ppss start)))
- ;; inside string or comment?
- (if (or (nth 3 state)
- (nth 4 state))
- (clojure--search-comment-macro-internal limit)
- (goto-char start)
- (clojure-forward-logical-sexp 1)
- ;; Data for (match-end 1).
- (setf (elt md 3) (point))
- (set-match-data md)
- t))))
- (defun clojure--search-comment-macro (limit)
- "Find comment macros and set the match data.
- Search from point up to LIMIT. The region that should be
- considered a comment is between `(match-beginning 1)'
- and `(match-end 1)'."
- (let ((result 'retry))
- (while (and (eq result 'retry) (<= (point) limit))
- (condition-case nil
- (setq result (clojure--search-comment-macro-internal limit))
- (end-of-file (setq result nil))
- (scan-error (setq result 'retry))))
- result))
- ;;; General font-locking
- (defun clojure-match-next-def ()
- "Scans the buffer backwards for the next \"top-level\" definition.
- Called by `imenu--generic-function'."
- ;; we have to take into account namespace-definition forms
- ;; e.g. s/defn
- (when (re-search-backward "^(\\([a-z0-9.-]+/\\)?def\\sw*" nil t)
- (save-excursion
- (let (found?
- (start (point)))
- (down-list)
- (forward-sexp)
- (while (not found?)
- (forward-sexp)
- (or (if (char-equal ?[ (char-after (point)))
- (backward-sexp))
- (if (char-equal ?) (char-after (point)))
- (backward-sexp)))
- (cl-destructuring-bind (def-beg . def-end) (bounds-of-thing-at-point 'sexp)
- (if (char-equal ?^ (char-after def-beg))
- (progn (forward-sexp) (backward-sexp))
- (setq found? t)
- (set-match-data (list def-beg def-end)))))
- (goto-char start)))))
- (eval-and-compile
- (defconst clojure--sym-forbidden-rest-chars "][\";\'@\\^`~\(\)\{\}\\,\s\t\n\r"
- "A list of chars that a Clojure symbol cannot contain.
- See definition of 'macros': URL `http://git.io/vRGLD'.")
- (defconst clojure--sym-forbidden-1st-chars (concat clojure--sym-forbidden-rest-chars "0-9:")
- "A list of chars that a Clojure symbol cannot start with.
- See the for-loop: URL `http://git.io/vRGTj' lines: URL
- `http://git.io/vRGIh', URL `http://git.io/vRGLE' and value
- definition of 'macros': URL `http://git.io/vRGLD'.")
- (defconst clojure--sym-regexp
- (concat "[^" clojure--sym-forbidden-1st-chars "][^" clojure--sym-forbidden-rest-chars "]*")
- "A regexp matching a Clojure symbol or namespace alias.
- Matches the rule `clojure--sym-forbidden-1st-chars' followed by
- any number of matches of `clojure--sym-forbidden-rest-chars'."))
- (defconst clojure-font-lock-keywords
- (eval-when-compile
- `( ;; Top-level variable definition
- (,(concat "(\\(?:clojure.core/\\)?\\("
- (regexp-opt '("def" "defonce"))
- ;; variable declarations
- "\\)\\>"
- ;; Any whitespace
- "[ \r\n\t]*"
- ;; Possibly type or metadata
- "\\(?:#?^\\(?:{[^}]*}\\|\\sw+\\)[ \r\n\t]*\\)*"
- "\\(\\sw+\\)?")
- (1 font-lock-keyword-face)
- (2 font-lock-variable-name-face nil t))
- ;; Type definition
- (,(concat "(\\(?:clojure.core/\\)?\\("
- (regexp-opt '("defstruct" "deftype" "defprotocol"
- "defrecord"))
- ;; type declarations
- "\\)\\>"
- ;; Any whitespace
- "[ \r\n\t]*"
- ;; Possibly type or metadata
- "\\(?:#?^\\(?:{[^}]*}\\|\\sw+\\)[ \r\n\t]*\\)*"
- "\\(\\sw+\\)?")
- (1 font-lock-keyword-face)
- (2 font-lock-type-face nil t))
- ;; Function definition (anything that starts with def and is not
- ;; listed above)
- (,(concat "(\\(?:" clojure--sym-regexp "/\\)?"
- "\\(def[^ \r\n\t]*\\)"
- ;; Function declarations
- "\\>"
- ;; Any whitespace
- "[ \r\n\t]*"
- ;; Possibly type or metadata
- "\\(?:#?^\\(?:{[^}]*}\\|\\sw+\\)[ \r\n\t]*\\)*"
- "\\(\\sw+\\)?")
- (1 font-lock-keyword-face)
- (2 font-lock-function-name-face nil t))
- ;; (fn name? args ...)
- (,(concat "(\\(?:clojure.core/\\)?\\(fn\\)[ \t]+"
- ;; Possibly type
- "\\(?:#?^\\sw+[ \t]*\\)?"
- ;; Possibly name
- "\\(\\sw+\\)?" )
- (1 font-lock-keyword-face)
- (2 font-lock-function-name-face nil t))
- ;; lambda arguments - %, %&, %1, %2, etc
- ("\\<%[&1-9]?" (0 font-lock-variable-name-face))
- ;; Special forms
- (,(concat
- "("
- (regexp-opt
- '("def" "do" "if" "let" "let*" "var" "fn" "fn*" "loop" "loop*"
- "recur" "throw" "try" "catch" "finally"
- "set!" "new" "."
- "monitor-enter" "monitor-exit" "quote") t)
- "\\>")
- 1 font-lock-keyword-face)
- ;; Built-in binding and flow of control forms
- (,(concat
- "(\\(?:clojure.core/\\)?"
- (regexp-opt
- '("letfn" "case" "cond" "cond->" "cond->>" "condp"
- "for" "when" "when-not" "when-let" "when-first" "when-some"
- "if-let" "if-not" "if-some"
- ".." "->" "->>" "as->" "doto" "and" "or"
- "dosync" "doseq" "dotimes" "dorun" "doall"
- "ns" "in-ns"
- "with-open" "with-local-vars" "binding"
- "with-redefs" "with-redefs-fn"
- "declare") t)
- "\\>")
- 1 font-lock-keyword-face)
- ;; Macros similar to let, when, and while
- (,(rx symbol-start
- (or "let" "when" "while") "-"
- (1+ (or (syntax word) (syntax symbol)))
- symbol-end)
- 0 font-lock-keyword-face)
- (,(concat
- "\\<"
- (regexp-opt
- '("*1" "*2" "*3" "*agent*"
- "*allow-unresolved-vars*" "*assert*" "*clojure-version*"
- "*command-line-args*" "*compile-files*"
- "*compile-path*" "*data-readers*" "*default-data-reader-fn*"
- "*e" "*err*" "*file*" "*flush-on-newline*"
- "*in*" "*macro-meta*" "*math-context*" "*ns*" "*out*"
- "*print-dup*" "*print-length*" "*print-level*"
- "*print-meta*" "*print-readably*"
- "*read-eval*" "*source-path*"
- "*unchecked-math*"
- "*use-context-classloader*" "*warn-on-reflection*")
- t)
- "\\>")
- 0 font-lock-builtin-face)
- ;; Dynamic variables - *something* or @*something*
- ("\\(?:\\<\\|/\\)@?\\(\\*[a-z-]*\\*\\)\\>" 1 font-lock-variable-name-face)
- ;; Global constants - nil, true, false
- (,(concat
- "\\<"
- (regexp-opt
- '("true" "false" "nil") t)
- "\\>")
- 0 font-lock-constant-face)
- ;; Character literals - \1, \a, \newline, \u0000
- ("\\\\\\([[:punct:]]\\|[a-z0-9]+\\>\\)" 0 'clojure-character-face)
- ;; foo/ Foo/ @Foo/ /FooBar
- (,(concat "\\(?:\\<:?\\|\\.\\)@?\\(" clojure--sym-regexp "\\)\\(/\\)")
- (1 font-lock-type-face) (2 'default))
- ;; Constant values (keywords), including as metadata e.g. ^:static
- ("\\<^?\\(:\\(\\sw\\|\\s_\\)+\\(\\>\\|\\_>\\)\\)" 1 'clojure-keyword-face append)
- ;; Java interop highlighting
- ;; CONST SOME_CONST (optionally prefixed by /)
- ("\\(?:\\<\\|/\\)\\([A-Z]+\\|\\([A-Z]+_[A-Z1-9_]+\\)\\)\\>" 1 font-lock-constant-face)
- ;; .foo .barBaz .qux01 .-flibble .-flibbleWobble
- ("\\<\\.-?[a-z][a-zA-Z0-9]*\\>" 0 'clojure-interop-method-face)
- ;; Foo Bar$Baz Qux_ World_OpenUDP Foo. Babylon15.
- ("\\(?:\\<\\|\\.\\|/\\|#?^\\)\\([A-Z][a-zA-Z0-9_]*[a-zA-Z0-9$_]+\\.?\\>\\)" 1 font-lock-type-face)
- ;; foo.bar.baz
- ("\\<^?\\([a-z][a-z0-9_-]+\\.\\([a-z][a-z0-9_-]*\\.?\\)+\\)" 1 font-lock-type-face)
- ;; (ns namespace) - special handling for single segment namespaces
- (,(concat "(\\<ns\\>[ \r\n\t]*"
- ;; Possibly metadata
- "\\(?:\\^?{[^}]+}[ \r\n\t]*\\)*"
- ;; namespace
- "\\([a-z0-9-]+\\)")
- (1 font-lock-type-face nil t))
- ;; fooBar
- ("\\(?:\\<\\|/\\)\\([a-z]+[A-Z]+[a-zA-Z0-9$]*\\>\\)" 1 'clojure-interop-method-face)
- ;; #_ and (comment ...) macros.
- (clojure--search-comment-macro 1 font-lock-comment-face t)
- ;; Highlight `code` marks, just like `elisp'.
- (,(rx "`" (group-n 1 (optional "#'")
- (+ (or (syntax symbol) (syntax word)))) "`")
- (1 'font-lock-constant-face prepend))
- ;; Highlight escaped characters in strings.
- (clojure-font-lock-escaped-chars 0 'bold prepend)
- ;; Highlight grouping constructs in regular expressions
- (clojure-font-lock-regexp-groups
- (1 'font-lock-regexp-grouping-construct prepend))))
- "Default expressions to highlight in Clojure mode.")
- (defun clojure-font-lock-syntactic-face-function (state)
- "Find and highlight text with a Clojure-friendly syntax table.
- This function is passed to `font-lock-syntactic-face-function',
- which is called with a single parameter, STATE (which is, in
- turn, returned by `parse-partial-sexp' at the beginning of the
- highlighted region)."
- (if (nth 3 state)
- ;; This might be a (doc)string or a |...| symbol.
- (let ((startpos (nth 8 state)))
- (if (eq (char-after startpos) ?|)
- ;; This is not a string, but a |...| symbol.
- nil
- (let* ((listbeg (nth 1 state))
- (firstsym (and listbeg
- (save-excursion
- (goto-char listbeg)
- (and (looking-at "([ \t\n]*\\(\\(\\sw\\|\\s_\\)+\\)")
- (match-string 1)))))
- (docelt (and firstsym
- (function-get (intern-soft firstsym)
- lisp-doc-string-elt-property))))
- (if (and docelt
- ;; It's a string in a form that can have a docstring.
- ;; Check whether it's in docstring position.
- (save-excursion
- (when (functionp docelt)
- (goto-char (match-end 1))
- (setq docelt (funcall docelt)))
- (goto-char listbeg)
- (forward-char 1)
- (condition-case nil
- (while (and (> docelt 0) (< (point) startpos)
- (progn (forward-sexp 1) t))
- ;; ignore metadata and type hints
- (unless (looking-at "[ \n\t]*\\(\\^[A-Z:].+\\|\\^?{.+\\)")
- (setq docelt (1- docelt))))
- (error nil))
- (and (zerop docelt) (<= (point) startpos)
- (progn (forward-comment (point-max)) t)
- (= (point) (nth 8 state)))))
- font-lock-doc-face
- font-lock-string-face))))
- font-lock-comment-face))
- (defun clojure-font-lock-setup ()
- "Configures font-lock for editing Clojure code."
- (setq-local font-lock-multiline t)
- (add-to-list 'font-lock-extend-region-functions
- #'clojure-font-lock-extend-region-def t)
- (setq font-lock-defaults
- '(clojure-font-lock-keywords ; keywords
- nil nil
- (("+-*/.<>=!?$%_&:" . "w")) ; syntax alist
- nil
- (font-lock-mark-block-function . mark-defun)
- (font-lock-syntactic-face-function
- . clojure-font-lock-syntactic-face-function))))
- (defun clojure-font-lock-def-at-point (point)
- "Range between the top-most def* and the fourth element after POINT.
- Note that this means that there is no guarantee of proper font
- locking in def* forms that are not at top level."
- (goto-char point)
- (condition-case nil
- (beginning-of-defun)
- (error nil))
- (let ((beg-def (point)))
- (when (and (not (= point beg-def))
- (looking-at "(def"))
- (condition-case nil
- (progn
- ;; move forward as much as possible until failure (or success)
- (forward-char)
- (dotimes (_ 4)
- (forward-sexp)))
- (error nil))
- (cons beg-def (point)))))
- (defun clojure-font-lock-extend-region-def ()
- "Set region boundaries to include the first four elements of def* forms."
- (let ((changed nil))
- (let ((def (clojure-font-lock-def-at-point font-lock-beg)))
- (when def
- (cl-destructuring-bind (def-beg . def-end) def
- (when (and (< def-beg font-lock-beg)
- (< font-lock-beg def-end))
- (setq font-lock-beg def-beg
- changed t)))))
- (let ((def (clojure-font-lock-def-at-point font-lock-end)))
- (when def
- (cl-destructuring-bind (def-beg . def-end) def
- (when (and (< def-beg font-lock-end)
- (< font-lock-end def-end))
- (setq font-lock-end def-end
- changed t)))))
- changed))
- (defun clojure--font-locked-as-string-p (&optional regexp)
- "Non-nil if the char before point is font-locked as a string.
- If REGEXP is non-nil, also check whether current string is
- preceeded by a #."
- (let ((face (get-text-property (1- (point)) 'face)))
- (and (or (and (listp face)
- (memq 'font-lock-string-face face))
- (eq 'font-lock-string-face face))
- (or (clojure-string-start t)
- (unless regexp
- (clojure-string-start nil))))))
- (defun clojure-font-lock-escaped-chars (bound)
- "Highlight \escaped chars in strings.
- BOUND denotes a buffer position to limit the search."
- (let ((found nil))
- (while (and (not found)
- (re-search-forward "\\\\." bound t))
- (setq found (clojure--font-locked-as-string-p)))
- found))
- (defun clojure-font-lock-regexp-groups (bound)
- "Highlight grouping constructs in regular expression.
- BOUND denotes the maximum number of characters (relative to the
- point) to check."
- (let ((found nil))
- (while (and (not found)
- (re-search-forward (eval-when-compile
- (concat
- ;; A group may start using several alternatives:
- "\\(\\(?:"
- ;; 1. (? special groups
- "(\\?\\(?:"
- ;; a) non-capturing group (?:X)
- ;; b) independent non-capturing group (?>X)
- ;; c) zero-width positive lookahead (?=X)
- ;; d) zero-width negative lookahead (?!X)
- "[:=!>]\\|"
- ;; e) zero-width positive lookbehind (?<=X)
- ;; f) zero-width negative lookbehind (?<!X)
- "<[=!]\\|"
- ;; g) named capturing group (?<name>X)
- "<[[:alnum:]]+>"
- "\\)\\|" ;; end of special groups
- ;; 2. normal capturing groups (
- ;; 3. we also highlight alternative
- ;; separarators |, and closing parens )
- "[|()]"
- "\\)\\)"))
- bound t))
- (setq found (clojure--font-locked-as-string-p 'regexp)))
- found))
- ;; Docstring positions
- (put 'ns 'clojure-doc-string-elt 2)
- (put 'def 'clojure-doc-string-elt 2)
- (put 'defn 'clojure-doc-string-elt 2)
- (put 'defn- 'clojure-doc-string-elt 2)
- (put 'defmulti 'clojure-doc-string-elt 2)
- (put 'defmacro 'clojure-doc-string-elt 2)
- (put 'definline 'clojure-doc-string-elt 2)
- (put 'defprotocol 'clojure-doc-string-elt 2)
- ;;; Vertical alignment
- (defcustom clojure-align-forms-automatically nil
- "If non-nil, vertically align some forms automatically.
- Automatically means it is done as part of indenting code. This
- applies to binding forms (`clojure-align-binding-forms'), to cond
- forms (`clojure-align-cond-forms') and to map literals. For
- instance, selecting a map a hitting \\<clojure-mode-map>`\\[indent-for-tab-command]'
- will align the values like this:
- {:some-key 10
- :key2 20}"
- :package-version '(clojure-mode . "5.1")
- :safe #'booleanp
- :type 'boolean)
- (defcustom clojure-align-binding-forms
- '("let" "when-let" "when-some" "if-let" "if-some" "binding" "loop"
- "doseq" "for" "with-open" "with-local-vars" "with-redefs")
- "List of strings matching forms that have binding forms."
- :package-version '(clojure-mode . "5.1")
- :safe #'listp
- :type '(repeat string))
- (defcustom clojure-align-cond-forms '("condp" "cond" "cond->" "cond->>" "case" "are")
- "List of strings identifying cond-like forms."
- :package-version '(clojure-mode . "5.1")
- :safe #'listp
- :type '(repeat string))
- (defun clojure--position-for-alignment ()
- "Non-nil if the sexp around point should be automatically aligned.
- This function expects to be called immediately after an
- open-brace or after the function symbol in a function call.
- First check if the sexp around point is a map literal, or is a
- call to one of the vars listed in `clojure-align-cond-forms'. If
- it isn't, return nil. If it is, return non-nil and place point
- immediately before the forms that should be aligned.
- For instance, in a map literal point is left immediately before
- the first key; while, in a let-binding, point is left inside the
- binding vector and immediately before the first binding
- construct."
- ;; Are we in a map?
- (or (and (eq (char-before) ?{)
- (not (eq (char-before (1- (point))) ?\#)))
- ;; Are we in a cond form?
- (let* ((fun (car (member (thing-at-point 'symbol) clojure-align-cond-forms)))
- (method (and fun (clojure--get-indent-method fun)))
- ;; The number of special arguments in the cond form is
- ;; the number of sexps we skip before aligning.
- (skip (cond ((numberp method) method)
- ((null method) 0)
- ((sequencep method) (elt method 0)))))
- (when (and fun (numberp skip))
- (clojure-forward-logical-sexp skip)
- (comment-forward (point-max))
- fun)) ; Return non-nil (the var name).
- ;; Are we in a let-like form?
- (when (member (thing-at-point 'symbol)
- clojure-align-binding-forms)
- ;; Position inside the binding vector.
- (clojure-forward-logical-sexp)
- (backward-sexp)
- (when (eq (char-after) ?\[)
- (forward-char 1)
- (comment-forward (point-max))
- ;; Return non-nil.
- t))))
- (defun clojure--find-sexp-to-align (end)
- "Non-nil if there's a sexp ahead to be aligned before END.
- Place point as in `clojure--position-for-alignment'."
- ;; Look for a relevant sexp.
- (let ((found))
- (while (and (not found)
- (search-forward-regexp
- (concat "{\\|(" (regexp-opt
- (append clojure-align-binding-forms
- clojure-align-cond-forms)
- 'symbols))
- end 'noerror))
- (let ((ppss (syntax-ppss)))
- ;; If we're in a string or comment.
- (unless (or (elt ppss 3)
- (elt ppss 4))
- ;; Only stop looking if we successfully position
- ;; the point.
- (setq found (clojure--position-for-alignment)))))
- found))
- (defun clojure--search-whitespace-after-next-sexp (&optional bound _noerror)
- "Move point after all whitespace after the next sexp.
- Set the match data group 1 to be this region of whitespace and
- return point."
- (unwind-protect
- (ignore-errors
- (clojure-forward-logical-sexp 1)
- (search-forward-regexp "\\([,\s\t]*\\)" bound)
- (pcase (syntax-after (point))
- ;; End-of-line, try again on next line.
- (`(12) (clojure--search-whitespace-after-next-sexp bound))
- ;; Closing paren, stop here.
- (`(5 . ,_) nil)
- ;; Anything else is something to align.
- (_ (point))))
- (when (and bound (> (point) bound))
- (goto-char bound))))
- (defun clojure-align (beg end)
- "Vertically align the contents of the sexp around point.
- If region is active, align it. Otherwise, align everything in the
- current \"top-level\" sexp.
- When called from lisp code align everything between BEG and END."
- (interactive (if (use-region-p)
- (list (region-beginning) (region-end))
- (save-excursion
- (let ((end (progn (end-of-defun)
- (point))))
- (clojure-backward-logical-sexp)
- (list (point) end)))))
- (setq end (copy-marker end))
- (save-excursion
- (goto-char beg)
- (while (clojure--find-sexp-to-align end)
- (let ((sexp-end (save-excursion
- (backward-up-list)
- (forward-sexp 1)
- (point-marker)))
- (clojure-align-forms-automatically nil)
- (count 1))
- ;; For some bizarre reason, we need to `align-region' once for each
- ;; group.
- (save-excursion
- (while (search-forward-regexp "^ *\n" sexp-end 'noerror)
- (cl-incf count)))
- (dotimes (_ count)
- (align-region (point) sexp-end nil
- '((clojure-align (regexp . clojure--search-whitespace-after-next-sexp)
- (group . 1)
- (separate . "^ *$")
- (repeat . t)))
- nil))
- ;; Reindent after aligning because of #360.
- (indent-region (point) sexp-end)))))
- ;;; Indentation
- (defun clojure-indent-region (beg end)
- "Like `indent-region', but also maybe align forms.
- Forms between BEG and END are aligned according to
- `clojure-align-forms-automatically'."
- (prog1 (let ((indent-region-function nil))
- (indent-region beg end))
- (when clojure-align-forms-automatically
- (condition-case nil
- (clojure-align beg end)
- (scan-error nil)))))
- (defun clojure-indent-line ()
- "Indent current line as Clojure code."
- (if (clojure-in-docstring-p)
- (save-excursion
- (beginning-of-line)
- (when (and (looking-at "^\\s-*")
- (<= (string-width (match-string-no-properties 0))
- (string-width (clojure-docstring-fill-prefix))))
- (replace-match (clojure-docstring-fill-prefix))))
- (lisp-indent-line)))
- (defvar clojure-get-indent-function nil
- "Function to get the indent spec of a symbol.
- This function should take one argument, the name of the symbol as
- a string. This name will be exactly as it appears in the buffer,
- so it might start with a namespace alias.
- This function is analogous to the `clojure-indent-function'
- symbol property, and its return value should match one of the
- allowed values of this property. See `clojure-indent-function'
- for more information.")
- (defun clojure--get-indent-method (function-name)
- "Return the indent spec for the symbol named FUNCTION-NAME.
- FUNCTION-NAME is a string. If it contains a `/', also try only
- the part after the `/'.
- Look for a spec using `clojure-get-indent-function', then try the
- `clojure-indent-function' and `clojure-backtracking-indent'
- symbol properties."
- (or (when (functionp clojure-get-indent-function)
- …
Large files files are truncated, but you can click here to view the full file