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?
Couldn’t you sort the locations in reverse order, start from the bottom doing the replacements upwards?
Interesting idea, it might work if I use the location search to go from the last one to the top one and assuming that changes in the bottom aren’t affecting positions above it.
I saw on another thread that as long as “track position” is off, then it should not move the locations when replacing.
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.
Hi @alexander.minolta! 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}"
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..
Thanks for you help!
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.
I’m currently trying an approach that uses loop [zloc .. data ...] and z/find .
Also https://github.com/clj-kondo/clj-kondo/tree/master/analysis can be super useful for locating items of interest for some use cases.