rewrite-clj

Alexander Kouznetsov 2024-03-13T16:20:12.708269Z

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?

Joel 2024-06-24T15:15:54.813459Z

Couldn’t you sort the locations in reverse order, start from the bottom doing the replacements upwards?

Alexander Kouznetsov 2024-06-24T18:59:43.243719Z

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.

Joel 2024-06-24T19:00:48.912869Z

I saw on another thread that as long as “track position” is off, then it should not move the locations when replacing.

Alexander Kouznetsov 2024-03-13T17:08:01.363099Z

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.

lread 2024-03-13T17:16:31.346939Z

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}"

🙌 1
Alexander Kouznetsov 2024-03-13T17:37:16.057879Z

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 Kouznetsov 2024-03-13T17:37:49.951109Z

Thanks for you help!

lread 2024-03-13T17:51:01.975339Z

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 Kouznetsov 2024-03-13T18:08:24.935599Z

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

👍 1
lread 2024-03-13T20:21:47.016779Z

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