Skip to content

Commit 46d22bb

Browse files
rlbdvbbatsov
authored andcommitted
Mark put-clojure-indent safe for use in .dir-locals.el, etc.
Add a put-clojure-indent form validator and attach it as a safe-local-eval-function property so that safe invocations won't trigger open-file prompts when used in local variables, or when added to .dir-locals.el like this: ((clojure-mode (eval . (put-clojure-indent 'defrecord '(2 :form :form (1)))))) For now, only support specs specified as lists, not vectors.
1 parent a4c9b25 commit 46d22bb

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

clojure-mode.el

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,6 +1554,53 @@ This function also returns nil meaning don't specify the indentation."
15541554
"Instruct `clojure-indent-function' to indent the body of SYM by INDENT."
15551555
(put sym 'clojure-indent-function indent))
15561556

1557+
(defun clojure--maybe-quoted-symbol-p (x)
1558+
"Check that X is either a symbol or a quoted symbol like :foo or 'foo."
1559+
(or (symbolp x)
1560+
(and (listp x)
1561+
(= 2 (length x))
1562+
(eq 'quote (car x))
1563+
(symbolp (cadr x)))))
1564+
1565+
(defun clojure--valid-unquoted-indent-spec-p (spec)
1566+
"Check that the indentation SPEC is valid.
1567+
Validate it with respect to
1568+
https://docs.cider.mx/cider/indent_spec.html e.g. (2 :form
1569+
:form (1)))."
1570+
(or (integerp spec)
1571+
(memq spec '(:form :defn))
1572+
(and (listp spec)
1573+
(not (null spec))
1574+
(or (integerp (car spec))
1575+
(memq (car spec) '(:form :defn)))
1576+
(seq-every-p 'clojure--valid-unquoted-indent-spec-p (cdr spec)))))
1577+
1578+
(defun clojure--valid-indent-spec-p (spec)
1579+
"Check that the indentation SPEC (quoted if a list) is valid.
1580+
Validate it with respect to
1581+
https://docs.cider.mx/cider/indent_spec.html e.g. (2 :form
1582+
:form (1)))."
1583+
(or (integerp spec)
1584+
(and (keywordp spec) (memq spec '(:form :defn)))
1585+
(and (listp spec)
1586+
(= 2 (length spec))
1587+
(eq 'quote (car spec))
1588+
(clojure--valid-unquoted-indent-spec-p (cadr spec)))))
1589+
1590+
(defun clojure--valid-put-clojure-indent-call-p (exp)
1591+
"Check that EXP is a valid `put-clojure-indent' expression.
1592+
For example: (put-clojure-indent 'defrecord '(2 :form :form (1))."
1593+
(unless (and (listp exp)
1594+
(= 3 (length exp))
1595+
(eq 'put-clojure-indent (nth 0 exp))
1596+
(clojure--maybe-quoted-symbol-p (nth 1 exp))
1597+
(clojure--valid-indent-spec-p (nth 2 exp)))
1598+
(error "Unrecognized put-clojure-indent call: %s" exp))
1599+
t)
1600+
1601+
(put 'put-clojure-indent 'safe-local-eval-function
1602+
'clojure--valid-put-clojure-indent-call-p)
1603+
15571604
(defmacro define-clojure-indent (&rest kvs)
15581605
"Call `put-clojure-indent' on a series, KVS."
15591606
`(progn

test/clojure-mode-safe-eval-test.el

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
;;; clojure-mode-safe-eval-test.el --- Clojure Mode: safe eval test suite -*- lexical-binding: t; -*-
2+
3+
;; Copyright (C) 2014-2021 Bozhidar Batsov <bozhidar@batsov.com>
4+
;; Copyright (C) 2021 Rob Browning <rlb@defaultvalue.org>
5+
6+
;; This file is not part of GNU Emacs.
7+
8+
;; This program is free software; you can redistribute it and/or modify
9+
;; it under the terms of the GNU General Public License as published by
10+
;; the Free Software Foundation, either version 3 of the License, or
11+
;; (at your option) any later version.
12+
13+
;; This program is distributed in the hope that it will be useful,
14+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
;; GNU General Public License for more details.
17+
18+
;; You should have received a copy of the GNU General Public License
19+
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
21+
;;; Commentary:
22+
23+
;; The safe eval test suite of Clojure Mode
24+
25+
;;; Code:
26+
(require 'clojure-mode)
27+
(require 'buttercup)
28+
29+
(describe "put-clojure-indent safe-local-eval-function property"
30+
(it "should be set to clojure--valid-put-clojure-indent-call-p"
31+
(expect (get 'put-clojure-indent 'safe-local-eval-function)
32+
:to-be 'clojure--valid-put-clojure-indent-call-p)))
33+
34+
(describe "clojure--valid-put-clojure-indent-call-p"
35+
(it "should approve valid forms"
36+
(expect (clojure--valid-put-clojure-indent-call-p
37+
'(put-clojure-indent 'foo 1)))
38+
(expect (clojure--valid-put-clojure-indent-call-p
39+
'(put-clojure-indent 'foo :defn)))
40+
(expect (clojure--valid-put-clojure-indent-call-p
41+
'(put-clojure-indent 'foo :form)))
42+
(expect (clojure--valid-put-clojure-indent-call-p
43+
'(put-clojure-indent 'foo '(1))))
44+
(expect (clojure--valid-put-clojure-indent-call-p
45+
'(put-clojure-indent 'foo '(:defn))))
46+
(expect (clojure--valid-put-clojure-indent-call-p
47+
'(put-clojure-indent 'foo '(:form))))
48+
(expect (clojure--valid-put-clojure-indent-call-p
49+
'(put-clojure-indent 'foo '(1 1))))
50+
(expect (clojure--valid-put-clojure-indent-call-p
51+
'(put-clojure-indent 'foo '(2 :form :form (1))))))
52+
(it "should reject invalid forms"
53+
(expect (clojure--valid-put-clojure-indent-call-p
54+
'(put-clojure-indent 1 1))
55+
:to-throw 'error)
56+
(expect (clojure--valid-put-clojure-indent-call-p
57+
'(put-clojure-indent 'foo :foo))
58+
:to-throw 'error)
59+
(expect (clojure--valid-put-clojure-indent-call-p
60+
'(put-clojure-indent 'foo (:defn)))
61+
:to-throw 'error)
62+
(expect (clojure--valid-put-clojure-indent-call-p
63+
'(put-clojure-indent 'foo '(:foo)))
64+
:to-throw 'error)
65+
(expect (clojure--valid-put-clojure-indent-call-p
66+
'(put-clojure-indent 'foo '(1 :foo)))
67+
:to-throw 'error)
68+
(expect (clojure--valid-put-clojure-indent-call-p
69+
'(put-clojure-indent 'foo '(1 "foo")))
70+
:to-throw 'error)))
71+
72+
(provide 'clojure-mode-safe-eval-test)
73+
74+
;;; clojure-mode-safe-eval-test.el ends here

0 commit comments

Comments
 (0)