Skip to content

Commit ca3fb01

Browse files
author
Yannick Scherer
committed
make custom zipper identifiable; remove '*-positional-zipper' functions.
1 parent 5339453 commit ca3fb01

File tree

6 files changed

+162
-172
lines changed

6 files changed

+162
-172
lines changed

src/rewrite_clj/custom_zipper/core.clj

Lines changed: 29 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,60 +22,40 @@
2222
;; To not force users into using this custom zipper, the following flag
2323
;; is used to dispatch to `clojure.zip` when set to `false`.
2424

25-
(def ^:dynamic *active?*
26-
"Set this to true to activate the custom, position-tracking zipper
27-
implementation."
28-
false)
25+
(defn ^:no-doc custom-zipper
26+
[root]
27+
{::custom? true
28+
:node root
29+
:position [1 1]
30+
:parent nil
31+
:left []
32+
:right '()})
2933

30-
(defn use-positional-zipper!
31-
"Globally activate the position-tracking zipper. You can locally revert
32-
behaviour to `clojure.zip`'s by using `without-positional-zipper`."
33-
[]
34-
(alter-var-root #'*active?* (constantly true)))
34+
(defn ^:no-doc zipper
35+
[root]
36+
(clj-zip/zipper
37+
node/inner?
38+
(comp seq node/children)
39+
node/replace-children
40+
root))
41+
42+
(defn ^:no-doc custom-zipper?
43+
[value]
44+
(::custom? value))
3545

3646
(defmacro ^:private defn-switchable
3747
[sym docstring params & body]
3848
(let [placeholders (repeatedly (count params) gensym)]
3949
`(defn ~sym
4050
~docstring
4151
[~@placeholders]
42-
(if *active?*
52+
(if (custom-zipper? ~(first placeholders))
4353
(let [~@(interleave params placeholders)]
4454
~@body)
4555
(~(symbol "clojure.zip" (name sym)) ~@placeholders)))))
4656

47-
(defmacro with-positional-zipper
48-
"Do not use `clojure.zip` to evaluate any rewrite-clj zipper operations in
49-
`body` but a custom position-tracking zipper that offers the function
50-
`position` to return row and column of a node."
51-
[& body]
52-
`(binding [*active?* true]
53-
~@body))
54-
55-
(defmacro without-positional-zipper
56-
"Force usage of `clojure.zip` to evaluate any rewrite-clj zipper operations in
57-
`body` instead of a custom position-tracking zipper."
58-
[& body]
59-
`(binding [*active?* false]
60-
~@body))
61-
6257
;; ## Implementation
6358

64-
(defn ^:no-doc zipper
65-
"Creates a new zipper structure."
66-
[root]
67-
(if *active?*
68-
{:node root
69-
:position [1 1]
70-
:parent nil
71-
:left []
72-
:right '()}
73-
(clj-zip/zipper
74-
node/inner?
75-
(comp seq node/children)
76-
node/replace-children
77-
root)))
78-
7959
(defn-switchable node
8060
"Returns the node at loc"
8161
[{:keys [node]}]
@@ -102,13 +82,13 @@
10282
(defn position
10383
"Returns the ones-based [row col] of the start of the current node"
10484
[loc]
105-
(if *active?*
85+
(if (custom-zipper? loc)
10686
(:position loc)
10787
(throw
10888
(IllegalStateException.
10989
(str
110-
"to use the positional zipper functions, please wrap your rewrite-clj"
111-
" calls with `rewrite-clj.zip/with-positional-zipper`.")))))
90+
"to use the 'position' function, please construct your zipper with "
91+
"':track-position?' set to true.")))))
11292

11393
(defn-switchable lefts
11494
"Returns a seq of the left siblings of this loc"
@@ -123,11 +103,12 @@
123103
(let [{:keys [node path] [row col] :position} loc
124104
[c & cnext :as cs] (children loc)]
125105
(when cs
126-
{:node c
106+
{::custom? true
107+
:node c
127108
:position [row (+ col (node/leader-length node))]
128-
:parent loc
129-
:left []
130-
:right cnext}))))
109+
:parent loc
110+
:left []
111+
:right cnext}))))
131112

132113
(defn-switchable up
133114
"Returns the loc of the parent of the node at this loc, or nil if at
@@ -227,7 +208,7 @@
227208
(defn edit
228209
"Replaces the node at this loc with the value of (f node args)"
229210
[loc f & args]
230-
(if *active?*
211+
(if (custom-zipper? loc)
231212
(replace loc (apply f (node loc) args))
232213
(apply clj-zip/edit loc f args)))
233214

src/rewrite_clj/custom_zipper/utils.clj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
(defn remove-right
1616
"Remove right sibling of the current node (if there is one)."
1717
[loc]
18-
(if z/*active?*
18+
(if (z/custom-zipper? loc)
1919
(let [{[r & rs] :right} loc]
2020
(assoc loc
2121
:right rs
@@ -25,7 +25,7 @@
2525
(defn remove-left
2626
"Remove left sibling of the current node (if there is one)."
2727
[loc]
28-
(if z/*active?*
28+
(if (z/custom-zipper? loc)
2929
(let [{:keys [left]} loc]
3030
(if-let [[_ lpos] (peek left)]
3131
(assoc loc
@@ -63,7 +63,7 @@
6363
"Remove current node and move left. If current node is at the leftmost
6464
location, returns `nil`."
6565
[loc]
66-
(if z/*active?*
66+
(if (z/custom-zipper? loc)
6767
(let [{:keys [position left]} loc]
6868
(if (seq left)
6969
(let [[lnode lpos] (peek left)]
@@ -84,7 +84,7 @@
8484
"Remove current node and move right. If current node is at the rightmost
8585
location, returns `nil`."
8686
[loc]
87-
(if z/*active?*
87+
(if (z/custom-zipper? loc)
8888
(let [{:keys [position right]} loc]
8989
(if (seq right)
9090
(assoc loc

src/rewrite_clj/zip.clj

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323

2424
(import-vars
2525
[rewrite-clj.custom-zipper.core
26-
node position root
27-
use-positional-zipper!
28-
with-positional-zipper
29-
without-positional-zipper]
26+
node position root]
3027

3128
[rewrite-clj.zip.base
3229
child-sexprs

src/rewrite_clj/zip/base.clj

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,32 @@
99
;; ## Zipper
1010

1111
(defn edn*
12-
"Create zipper over the given Clojure/EDN node."
13-
[node]
14-
(z/zipper node))
12+
"Create zipper over the given Clojure/EDN node.
13+
14+
If `:track-position?` is set, this will create a custom zipper that will
15+
return the current row/column using `rewrite-clj.zip/position`. (Note that
16+
this custom zipper will be incompatible with `clojure.zip`'s functions.)"
17+
([node]
18+
(edn* node {}))
19+
([node {:keys [track-position?]}]
20+
(if track-position?
21+
(z/custom-zipper node)
22+
(z/zipper node))))
1523

1624
(defn edn
17-
"Create zipper over the given Clojure/EDN node and move
18-
to the first non-whitespace/non-comment child."
19-
[node]
20-
(if (= (node/tag node) :forms)
21-
(let [top (edn* node)]
22-
(or (-> top z/down ws/skip-whitespace)
23-
top))
24-
(recur (node/forms-node [node]))))
25+
"Create zipper over the given Clojure/EDN node and move to the first
26+
non-whitespace/non-comment child.
27+
28+
If `:track-position?` is set, this will create a custom zipper that will
29+
return the current row/column using `rewrite-clj.zip/position`. (Note that
30+
this custom zipper will be incompatible with `clojure.zip`'s functions.)"
31+
([node] (edn node {}))
32+
([node {:keys [track-position?] :as options}]
33+
(if (= (node/tag node) :forms)
34+
(let [top (edn* node options)]
35+
(or (-> top z/down ws/skip-whitespace)
36+
top))
37+
(recur (node/forms-node [node]) options))))
2538

2639
;; ## Inspection
2740

@@ -55,13 +68,15 @@
5568

5669
(defn of-string
5770
"Create zipper from String."
58-
[s]
59-
(some-> s p/parse-string-all edn))
71+
([s] (of-string s {}))
72+
([s options]
73+
(some-> s p/parse-string-all (edn options))))
6074

6175
(defn of-file
6276
"Create zipper from File."
63-
[f]
64-
(some-> f p/parse-file-all edn))
77+
([f] (of-file f {}))
78+
([f options]
79+
(some-> f p/parse-file-all (edn options))))
6580

6681
;; ## Write
6782

0 commit comments

Comments
 (0)