-
Notifications
You must be signed in to change notification settings - Fork 40
/
fn.clj
114 lines (90 loc) · 3.2 KB
/
fn.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
(ns cljfmt.format.fn
(:require
[cljfmt.format.zloc :as zl]
[clojure.zip :as zip]
[rewrite-clj.zip :as z]))
(defn- unwrap-meta
"If this location is a metadata node, recursively unwrap it and return the
location of the nested value form. Otherwise returns the location unchanged."
[zloc]
(if (= :meta (z/tag zloc))
(recur (z/next (z/down zloc)))
zloc))
(defn- vector-node?
"True if the node at this location is a vector node."
[zloc]
(= :vector (z/tag (unwrap-meta zloc))))
(defn- no-prev?
"True if no prior location in this form matches the predicate."
[zloc p?]
(nil? (z/find-next zloc zip/left p?)))
(defn- fn-form?
"True if the node at this location is a function form."
[zloc]
(and (= :list (z/tag zloc))
(let [form-sym (zl/form-symbol (z/down zloc))]
(and (symbol? form-sym)
(or (= "fn" (name form-sym))
(= "defn" (name form-sym))
(and (vector-node? (z/up zloc))
(no-prev? zloc vector-node?)
(= 'letfn (zl/form-symbol (z/up zloc)))))))))
(defn- arg-vector?
"True if the node at this location is an argument vector to a function."
[zloc]
(and (vector-node? zloc)
(no-prev? zloc vector-node?)
(or (fn-form? (z/up zloc))
(and (= :list (z/tag (z/up zloc)))
(fn-form? (z/up (z/up zloc)))))))
(defn- preceeding-symbols
"Return a vector of all the symbols to the left of this location at the
current level."
[zloc]
(into []
(comp (take-while some?)
(keep (comp zl/token-value unwrap-meta))
(filter symbol?))
(iterate z/left (z/left zloc))))
(defn- fn-name?
"True if this location is a function name symbol."
[zloc]
(let [unwrapped (unwrap-meta zloc)]
(and (fn-form? (z/up zloc))
(zl/token? unwrapped)
(no-prev? zloc arg-vector?)
(symbol? (z/sexpr unwrapped))
(not (contains? #{"fn" "defn"} (name (z/sexpr unwrapped))))
(contains? #{[] ["fn"] ["defn"]} (map name (preceeding-symbols zloc))))))
(defn fn-to-name-or-args-space?
"True if the node at this location is whitespace between a function's header
and the name or argument vector."
[zloc]
(and (zl/zwhitespace? zloc)
(fn-form? (z/up zloc))
(no-prev? zloc (some-fn fn-name? arg-vector?))))
(defn post-name-space?
"True if the node at this location is whitespace immediately following a
function name."
[zloc]
(and (zl/zwhitespace? zloc)
(fn-name? (z/left zloc))))
(defn post-doc-space?
"True if the node at this location is whitespace immediately following a
function docstring."
[zloc]
(and (zl/zwhitespace? zloc)
(fn-name? (z/left (z/left zloc)))
(string? (zl/token-value (z/left zloc)))))
(defn post-args-space?
"True if the node at this location is whitespace immediately following a
function argument vector."
[zloc]
(and (zl/zwhitespace? zloc)
(arg-vector? (z/left zloc))))
(defn defn-or-multiline?
"True if this location is inside a `defn` or a multi-line form."
[zloc]
(or (when-let [fsym (zl/form-symbol zloc)]
(and (symbol? fsym) (= "defn" (name fsym))))
(zl/multiline? (z/up zloc))))