Skip to content

Commit e8ff5fd

Browse files
authored
paredit/join fn fixes (#356)
* paredit/join fn fixes - rewritten to not use internal `global-find-by-node` (contributes to #256) - now takes type of left sequence (closes #321) - no longer removes comments between strings when joining 2 strings (closes #351) * docs: typos changelog [skip ci] * docs: changelog typo [skip ci]
1 parent 6999a8f commit e8ff5fd

File tree

3 files changed

+61
-30
lines changed

3 files changed

+61
-30
lines changed

CHANGELOG.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ A release with known breaking changes is marked with:
2929
* `rewrite.clj.paredit`
3030
** `pos` arguments now accept vector `[row col]` in addition to map `{:row :col}`
3131
{issue}344[#344] ({lread})
32+
** `join` now takes type of left sequence
33+
{issue}321[#321] ({lread}, thanks for the issue {person}openvest[@openvest]!)
34+
** `join` no longer removes comments that were between joined strings
35+
{issue}351[#351] ({lread})
3236

3337
=== v1.1.49 - 2024-11-18 [[v1.1.49]]
3438

src/rewrite_clj/paredit.cljc

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
(defn- empty-seq? [zloc]
1818
(and (z/seq? zloc) (not (seq (z/sexpr zloc)))))
1919

20-
;; helper
2120
(defn- move-n [loc f n]
2221
(if (= 0 n)
2322
loc
@@ -45,17 +44,25 @@
4544
(take-while p?)
4645
(map z/node))))
4746

47+
(defn- reduce-into-zipper
48+
"A thread-first-friendly reducer"
49+
[zloc f items]
50+
(reduce f zloc items))
51+
52+
(defn- linebreak-and-comment-nodes
53+
"Return vector of all linebreak and comment nodes from whitespace and comment nodes from `zloc` moving via `f` "
54+
[zloc f]
55+
(->> (-> zloc
56+
f
57+
(nodes-by-dir f ws/whitespace-or-comment?))
58+
(filterv #(or (nd/linebreak? %) (nd/comment? %)))))
59+
4860
(defn- remove-first-if-ws [nodes]
4961
(when (seq nodes)
5062
(if (nd/whitespace? (first nodes))
5163
(rest nodes)
5264
nodes)))
5365

54-
(defn- remove-ws-or-comment [zloc]
55-
(if-not (ws/whitespace-or-comment? zloc)
56-
zloc
57-
(recur (z/remove* zloc))))
58-
5966
(defn- create-seq-node
6067
"Creates a sequence node of given type `t` with node values of `v`"
6168
[t v]
@@ -457,33 +464,44 @@
457464
zloc))
458465

459466
(defn- join-seqs [left right]
460-
(let [lefts (-> left z/node nd/children)
467+
(let [rights (-> right z/node nd/children)
461468
ws-nodes (-> (z/right* left) (nodes-by-dir z/right* ws/whitespace-or-comment?))
462-
rights (-> right z/node nd/children)]
469+
ws-nodes (if (seq ws-nodes)
470+
ws-nodes
471+
[(nd/spaces 1)])
472+
zloc (-> left
473+
(reduce-into-zipper z/append-child* ws-nodes)
474+
(reduce-into-zipper z/append-child* rights))]
475+
(-> zloc
476+
(u/remove-right-while ws/whitespace-or-comment?)
477+
z/right*
478+
u/remove-and-move-left
479+
z/down
480+
z/rightmost*
481+
(move-n z/left* (dec (count rights))))))
463482

483+
(defn- join-strings [left right]
484+
(let [cmts-and-nls (linebreak-and-comment-nodes left z/right*)
485+
cmts-and-nls (when (seq cmts-and-nls)
486+
(into [(nd/spaces 1)] cmts-and-nls))]
464487
(-> right
465488
z/remove*
466-
remove-ws-or-comment
467-
z/up
468-
(z/insert-left (create-seq-node :vector
469-
(concat lefts
470-
ws-nodes
471-
rights)))
472-
z/remove
473-
(global-find-by-node (first rights)))))
474-
475-
(defn- join-strings [left right]
476-
(-> right
477-
z/remove*
478-
remove-ws-or-comment
479-
(z/replace (nd/string-node (str (-> left z/node nd/sexpr)
480-
(-> right z/node nd/sexpr))))))
489+
z/left
490+
(u/remove-right-while ws/whitespace-or-comment?)
491+
;; sexpr is safe on strings
492+
(z/replace (nd/string-node (str (-> left z/node nd/sexpr)
493+
(-> right z/node nd/sexpr))))
494+
(reduce-into-zipper z/insert-right* (reverse cmts-and-nls)))))
481495

482496
(defn join
483-
"Join S-expression to the left and right of current loc. Also works for strings.
484-
485-
- `[[1 2] |[3 4]] => [[1 2 3 4]]`
486-
- `[\"Hello \" | \"World\"] => [\"Hello World\"]`"
497+
"Returns `zloc` with sequence to the left joined to sequence to the right.
498+
Also works for strings.
499+
If sequence types differ, uses sequence type to the left.
500+
501+
- `[1 2] |[3 4] => [1 2 |3 4]`
502+
- `[1 2]| [3 4] => [1 2 |3 4]`
503+
- `{:a 1} |(:b 2) => `{:a 1 :b 2}`
504+
- `[\"Hello\" | \"World\"] => [|\"HelloWorld\"]`"
487505
[zloc]
488506
(let [left (some-> zloc z/left)
489507
right (if (some-> zloc z/node nd/whitespace?) (z/right zloc) zloc)]

test/rewrite_clj/paredit_test.cljc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@
214214
;; for this pos fn test, ⊚ in `s` represents character row/col the the `pos`
215215
;; ⊚ in `expected` is at zipper node granularity
216216
(doseq [[s expected]
217-
[["(\"Hello ⊚World\")" "(⊚\"Hello \" \"World\")" ]]]
217+
[["(\"Hello ⊚World\")" "(⊚\"Hello \" \"World\")"]]]
218218
(let [{:keys [pos s]} (th/pos-and-s s)
219219
zloc (z/of-string* s {:track-position? true})]
220220
(doseq [pos [pos [(:row pos) (:col pos)]]]
@@ -226,9 +226,18 @@
226226
(testing (zipper-opts-desc opts)
227227
(doseq [[s expected]
228228
[["[1 2]⊚ [3 4]" "[1 2 ⊚3 4]"]
229-
["\n[[1 2]⊚ ; the first stuff\n [3 4] ; the second stuff\n]" "\n[[1 2 ; the first stuff\n ⊚3 4]; the second stuff\n]"]
229+
["#{1 2} ⊚[3 4]" "#{1 2 ⊚3 4}"]
230+
["(1 2)⊚ {3 4}" "(1 2 ⊚3 4)"]
231+
["{:a 1} ⊚(:b 2)" "{:a 1 ⊚:b 2}"]
232+
["[foo]⊚[bar]" "[foo ⊚bar]"]
233+
["[foo] ⊚[bar]" "[foo ⊚bar]"]
234+
["\n[[1 2]⊚ ; the first stuff\n [3 4] ; the second stuff\n]" "\n[[1 2 ; the first stuff\n ⊚3 4] ; the second stuff\n]"]
230235
;; strings
231-
["(\"Hello \"\"World\")" "(⊚\"Hello World\")"]]]
236+
["(\"Hello \"\"World\")" "(⊚\"Hello World\")"]
237+
["(⊚\"Hello \" \"World\")" "(⊚\"Hello \" \"World\")"]
238+
["(\"Hello \" ;; comment\n;; comment2\n\"World\")"
239+
"(⊚\"Hello World\" ;; comment\n;; comment2\n)"]
240+
["\"foo\"\"bar\"" "\"foobar\""]]]
232241
(let [zloc (th/of-locmarked-string s opts)]
233242
(is (= s (th/root-locmarked-string zloc)) "(sanity) string before")
234243
(is (= expected (-> zloc pe/join th/root-locmarked-string)) "string after"))))))

0 commit comments

Comments
 (0)