Fork me on GitHub
#rewrite-clj
<
2024-03-13
>
Alexander Kouznetsov16:03:12

Hi! If I understand correctly, every change I make to a zloc is stored in that particular returned zloc object. Is there a way to merge changes done to different zlocs? For example, if I find several spots in the code where I want to apply changes and store separate zloc s for them. Can I then use those zloc s to apply changes and then combine the result? Otherwise, how can I get to the same zloc location if I have a zloc with changes and another zloc of another location before the change was made?

Alexander Kouznetsov17:03:01

Interesting, looks like clojure-lsp marks nodes by assigning them a custom ::markers field and then it can get back to the marked nodes easily.

lread17:03:31

Hi @UHS6PHL31! The typical usage is to make all your changes while navigating through the zipper. Sometimes, it can be convenient to make a change, reparse, and then make a subsequent change. Let's contrive a simple code snippet:

{:a 1 :b 2}
Let's imagine you want to change 1 to :foo and :b to :bar and add :c 3. Here's one way to do this in one pass
(require '[rewrite-clj.zip :as z])

(def s "{:a 1 :b 2}")

(-> s
    z/of-string
    z/down
    z/right
    (z/replace :foo) 
    z/right
    (z/replace :bar)
    z/up
    (z/append-child :c)
    (z/append-child 3)
    z/root-string)
;; => "{:a :foo :bar 2 :c 3}"
Here's the same result but with re-parsing:
(-> s
    z/of-string
    z/down
    z/right
    (z/replace :foo)
    z/root-string ;; take result
    z/of-string   ;; and reparse
    z/down
    z/right
    z/right
    (z/replace :bar)
    z/root-string  ;; take result
    z/of-string    ;; and reparse
    (z/append-child :c)
    (z/append-child 3)
    z/root-string)
;; => "{:a :foo :bar 2 :c 3}"

🙌 1
Alexander Kouznetsov17:03:16

When dealing with large source files, reparsing seems inefficient. Also navigating from one interesting spot to the next isn’t as trivial s calling z/right. But possibly I can change my code to something more zipper friendly as currently I’m using (->> z (iterate z/next) (filter …) … constructions which seems to only take original zloc value into account..

Alexander Kouznetsov17:03:49

Thanks for you help!

lread17:03:01

Yep, re-parsing is certainly not efficient enough for many use cases. But in a pinch, when you don't care about efficiency, it can be convenient. Sometimes the prewalk and postwalk zip fns can work out nicely. I guess you'll have to play around to see what works for you. When you land on something that does work, feel free to come back and share; It could help others, too.

Alexander Kouznetsov18:03:24

I’m currently trying an approach that uses loop [zloc .. data ...] and z/find .

👍 1
lread20:03:47

Also https://github.com/clj-kondo/clj-kondo/tree/master/analysis can be super useful for locating items of interest for some use cases.

🙌 1