Skip to content

Commit f296d08

Browse files
author
Yannick Scherer
committed
Rearranged edit-scope-limitation. TODO: fix removal.
1 parent c81e112 commit f296d08

File tree

5 files changed

+124
-29
lines changed

5 files changed

+124
-29
lines changed

src/rewrite_clj/zip.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
skip-whitespace skip-whitespace-left
3131
prepend-space append-space
3232
prepend-newline append-newline
33-
edit-> subzip]
33+
subzip
34+
edit->> edit->
35+
subedit-> subedit->>]
3436

3537
[rewrite-clj.zip.move
3638

src/rewrite_clj/zip/core.clj

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,24 @@
138138
(edn* (z/root zloc))
139139
path)))
140140

141+
(defn edit-node
142+
"Apply given function to the given zipper location. Afterwards move the resulting
143+
zipper to the same location as the original one."
144+
[zloc f]
145+
(if-let [eloc (f zloc)]
146+
(move-to-node eloc zloc)
147+
(throw (Exception. "Function supplied to edit-node did not return value!"))))
148+
149+
(defn edit-children
150+
"Apply given function to the given zipper location. It may only alter the node itself or
151+
its children. Afterwards, move the resulting zipper to the same location as the original one."
152+
[zloc f]
153+
(if-not (z/branch? zloc)
154+
(throw (Exception. "Zipper location supplied to edit-children is not a branch!"))
155+
(if-let [eloc (f (subzip zloc))]
156+
(z/replace zloc (z/root eloc))
157+
(throw (Exception. "Function supplied to edit-children did not return value!")))))
158+
141159
(defmacro edit->
142160
"Will pass arguments to `->`. Return value will be the state of the input node
143161
after all modifications have been performed. This means that the result is
@@ -146,9 +164,7 @@
146164
of the input node (modification can occur anywhere)."
147165
[zloc & body]
148166
`(let [zloc# ~zloc]
149-
(if-let [edit# (-> zloc# ~@body)]
150-
(move-to-node edit# zloc#)
151-
(throw (Exception. "Body of edit-> did not return value.")))))
167+
(edit-node zloc# (fn [zloc#] (-> zloc# ~@body)))))
152168

153169
(defmacro edit->>
154170
"Will pass arguments to `->>`. Return value will be the state of the input node
@@ -158,6 +174,22 @@
158174
of the input node (modification can occur anywhere)."
159175
[zloc & body]
160176
`(let [zloc# ~zloc]
161-
(if-let [edit# (->> zloc# ~@body)]
162-
(move-to-node edit# zloc#)
163-
(throw (Exception. "Body of edit->> did not return value.")))))
177+
(edit-node zloc# (fn [zloc#] (->> zloc# ~@body)))))
178+
179+
(defmacro subedit->
180+
"Will pass arguments to `->`. Return value will be the state of the input node after
181+
all modifications have been performed. This means that the result is automatically
182+
'zipped up' to represent the same location the macro was given. This only allows
183+
for modifications of the node itself or its children."
184+
[zloc & body]
185+
`(let [zloc# ~zloc]
186+
(edit-children zloc# (fn [zloc#] (-> zloc# ~@body)))))
187+
188+
(defmacro subedit->>
189+
"Will pass arguments to `->>`. Return value will be the state of the input node after
190+
all modifications have been performed. This means that the result is automatically
191+
'zipped up' to represent the same location the macro was given. This only allows
192+
for modifications of the node itself or its children."
193+
[zloc & body]
194+
`(let [zloc# ~zloc]
195+
(edit-children zloc# (fn [zloc#] (->> zloc# ~@body)))))

src/rewrite_clj/zip/edit.clj

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,22 @@
66
[rewrite-clj.convert :as conv]
77
[rewrite-clj.zip.core :as zc]))
88

9+
;; ## Helpers
10+
911
(def ^:private ^:const SPACE [:whitespace " "])
1012

13+
(defn- remove-trailing-space
14+
"Remove a single whitespace character after the given node."
15+
[zloc]
16+
(or
17+
(when-let [ws (z/right zloc)]
18+
(when (= (zc/tag ws) :whitespace)
19+
(let [w (dec (zc/length ws))]
20+
(-> ws
21+
(z/replace [:whitespace (apply str (repeat w \space))])
22+
z/left))))
23+
zloc))
24+
1125
;; ## Insert
1226

1327
(defn insert-right
@@ -62,18 +76,13 @@
6276
(defn remove
6377
"Remove value at the given zipper location. Returns the first non-whitespace node
6478
that would have preceded it in a depth-first walk. Will remove a single whitespace
65-
character following the current node."
79+
character following the current node and/or preceding it (if last element in branch)."
6680
[zloc]
67-
(let [ws (z/right zloc)
68-
zloc (or
69-
(when (= (zc/tag ws) :whitespace)
70-
(let [w (dec (zc/length ws))]
71-
(when-not (neg? w)
72-
(-> ws z/remove (zc/append-space w)))))
73-
zloc)]
74-
(->> zloc
75-
z/remove
76-
(zc/skip-whitespace z/prev))))
81+
(->> zloc
82+
remove-trailing-space
83+
;; TODO: Remove preceding space
84+
z/remove
85+
(zc/skip-whitespace z/prev)))
7786

7887
(defn splice
7988
"Add the current node's children to the parent branch (in place of the current node).

test/rewrite_clj/indent_test.clj

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
(z/tag rloc) => :token
4949
(z/value rloc) => 2
5050
(z/->root-string rloc) => "[1\n 2 \"abc\" [3\n 4]]")
51-
(let [rloc (-> (z/of-string "[1\n 2 [3\n 4]]") (z/find-value z/next 2) i/remove)]
52-
(z/tag rloc) => :token
53-
(z/value rloc) => 1
54-
(z/->root-string rloc) => "[1\n [3\n 4]]"))
51+
(future-fact "about correct preceding whitespace handling."
52+
(let [rloc (-> (z/of-string "[1\n 2 [3\n 4]]") (z/find-value z/next 2) i/remove)]
53+
(z/tag rloc) => :token
54+
(z/value rloc) => 1
55+
(z/->root-string rloc) => "[1\n [3\n 4]]")))

test/rewrite_clj/zip_test.clj

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
[b \"1.2.3\"]]
1616
:repositories { \"private\" \"http://private.com/repo\" })")
1717

18-
(def root (z/edn (p/parse-string data-string)))
18+
(def root (z/of-string data-string))
1919

2020
;; ## Tests
2121
;;
@@ -75,7 +75,7 @@
7575
(-> loc z/right z/node) => [:token 'defproject]))
7676

7777
(fact "about zipper modification"
78-
(let [root (z/edn (p/parse-string "[1\n 2\n 3]"))]
78+
(let [root (z/of-string "[1\n 2\n 3]")]
7979
(z/node root)
8080
=> [:vector
8181
[:token 1]
@@ -105,8 +105,24 @@
105105
[:newline "\n"] [:whitespace " "] [:token 2]
106106
[:newline "\n"] [:whitespace " "] [:token 8]]]))
107107

108+
(fact "about node removal (including trailing/preceding whitespace if necessary)"
109+
(let [root (z/of-string "[1 [2 3] 4]")]
110+
(z/sexpr root) => [1 [2 3] 4]
111+
(let [r0 (-> root z/down z/remove*)]
112+
(z/sexpr r0) => [[2 3] 4]
113+
(z/->root-string r0) => "[ [2 3] 4]")
114+
(let [r0 (-> root z/down z/remove)]
115+
(z/sexpr r0) => [[2 3] 4]
116+
(z/->root-string r0) => "[[2 3] 4]")
117+
(let [r0 (-> root z/down z/right z/right z/remove*)]
118+
(z/->root-string r0) => "[1 [2 3] ]")
119+
(future-fact "about removal of preceding spaces"
120+
(let [r0 (-> root z/down z/right z/right z/remove)]
121+
(z/sexpr r0) => 3
122+
(z/->root-string r0) => "[1 [2 3]]"))))
123+
108124
(fact "about zipper splice"
109-
(let [root (z/edn (p/parse-string "[1 [2 3] 4]"))]
125+
(let [root (z/of-string "[1 [2 3] 4]")]
110126
(z/sexpr root) => [1 [2 3] 4]
111127
(-> root z/down z/right z/splice z/up z/sexpr) => [1 2 3 4]))
112128

@@ -122,7 +138,7 @@
122138
=> [:repositories :dependencies "A project." :description "0.1.0-SNAPSHOT" 'my-project 'defproject])
123139

124140
(fact "about zipper seq operations"
125-
(let [root (z/edn (p/parse-string "[1 2 3]"))]
141+
(let [root (z/of-string "[1 2 3]")]
126142
root => z/seq?
127143
root => z/vector?
128144
(z/sexpr root) => [1 2 3]
@@ -132,7 +148,7 @@
132148
(-> root (z/assoc 2 5) z/sexpr) => [1 2 5]
133149
(-> root (z/assoc 5 8) z/sexpr) => (throws IndexOutOfBoundsException)
134150
(->> root (z/map #(z/edit % inc)) z/sexpr) => [2 3 4])
135-
(let [root (z/edn (p/parse-string "(1 2 3)"))]
151+
(let [root (z/of-string "(1 2 3)")]
136152
root => z/seq?
137153
root => z/list?
138154
(z/sexpr root) => '(1 2 3)
@@ -142,7 +158,7 @@
142158
(-> root (z/assoc 2 5) z/sexpr) => '(1 2 5)
143159
(-> root (z/assoc 5 8) z/sexpr) => (throws IndexOutOfBoundsException)
144160
(->> root (z/map #(z/edit % inc)) z/sexpr) => '(2 3 4))
145-
(let [root (z/edn (p/parse-string "#{1 2 3}"))]
161+
(let [root (z/of-string "#{1 2 3}")]
146162
root => z/seq?
147163
root => z/set?
148164
(z/sexpr root) => #{1 2 3}
@@ -152,7 +168,7 @@
152168
(-> root (z/assoc 2 5) z/sexpr) => #{1 2 5}
153169
(-> root (z/assoc 5 8) z/sexpr) => (throws IndexOutOfBoundsException)
154170
(->> root (z/map #(z/edit % inc)) z/sexpr) => #{2 3 4})
155-
(let [root (z/edn (p/parse-string "{:a 1 :b 2}"))]
171+
(let [root (z/of-string "{:a 1 :b 2}")]
156172
root => z/seq?
157173
root => z/map?
158174
(z/sexpr root) => {:a 1 :b 2}
@@ -162,3 +178,38 @@
162178
(-> root (z/assoc :c 7) z/sexpr) => {:a 1 :b 2 :c 7}
163179
(->> root (z/map #(z/edit % inc)) z/sexpr) => {:a 2 :b 3}
164180
(->> root (z/map-keys #(z/edit % name)) z/sexpr) => {"a" 1 "b" 2}))
181+
182+
(fact "about edit scope limitation/location memoization"
183+
(let [root (z/of-string "[0 [1 2 3] 4]")]
184+
(fact "about subedit->"
185+
(let [r0 (-> root z/down z/right z/down z/right (z/replace 5))
186+
r1 (z/subedit-> root z/down z/right z/down z/right (z/replace 5))]
187+
(z/->root-string r0) => (z/->root-string r1)
188+
(z/->string r0) => "5"
189+
(z/->string r1) => "[0 [1 5 3] 4]"
190+
(z/tag r0) => :token
191+
(z/tag r1) => :vector))
192+
(fact "about subedit->>"
193+
(let [r0 (->> root z/down z/right (z/map #(z/edit % inc)) z/down)
194+
r1 (z/subedit->> root z/down z/right (z/map #(z/edit % + 1)) z/down)]
195+
(z/->root-string r0) => (z/->root-string r1)
196+
(z/->string r0) => "2"
197+
(z/->string r1) => "[0 [2 3 4] 4]"
198+
(z/tag r0) => :token
199+
(z/tag r1) => :vector))
200+
(fact "about edit->"
201+
(let [v (-> root z/down z/right z/down)
202+
r0 (-> v z/up z/right z/remove)
203+
r1 (z/edit-> v z/up z/right z/remove)]
204+
(z/->root-string r0) => (z/->root-string r1)
205+
(z/->string v) => "1"
206+
(z/->string r0) => "3"
207+
(z/->string r1) => "1"))
208+
(fact "about edit->>"
209+
(let [v (-> root z/down)
210+
r0 (->> v z/right (z/map #(z/edit % inc)) z/right)
211+
r1 (z/edit->> v z/right (z/map #(z/edit % inc)) z/right)]
212+
(z/->root-string r0) => (z/->root-string r1)
213+
(z/->string v) => "0"
214+
(z/->string r0) => "4"
215+
(z/->string r1) => "0"))))

0 commit comments

Comments
 (0)