Please help me figure out how to attach custom metadata to the nodes using walk functions?
(->
(z/of-string "(1 2 3)" {:track-position? true})
(z/up)
(z/postwalk
(fn [zloc]
(z/subedit-node zloc #(vary-meta % merge {:foo/bar :baz}))))
(z/down)
(z/next)
(z/node)
(meta))
;; => {:row 1, :col 2, :end-row 1, :end-col 3}
I've been expecting to see my custom data here, but seems like either my approach is wrong or metadata was just ignored hereclojure postwalk is known to lose metadata in some cases, perhaps rewrite-clj calls the clojure one? can you check the source?
Seems like it have something to do with subedit-node, not the postwalk functionality:
(->
(z/of-string "(1 2 3)")
(z/subedit-node #(vary-meta % merge {:foo/bar :baz}))
(z/node)
(meta))
;; => {:row 1, :col 1, :end-row 1, :end-col 8}
What I've found so far:
• z/subedit-node and z/edit-node apply function to zloc, not the node
• z/edit applies function to the underlying data, i.e. literally things like 1, 2, 3 and (1 2 3)
• The only way I was able to find is zloc direct modification:
(->
"(1 2 3)"
(z/of-string)
(z/up)
(z/postwalk
(fn [zloc]
(assoc zloc
:changed? true
:node (vary-meta (:node zloc) merge {:foo (rand-int 100)}))))
(z/postwalk
(fn [zloc]
(prn (meta (z/node zloc)))
zloc)))
I don't like to rely on implementation details, but I think I'm okay with it as far as my code is tested 😊Ok here's maybe something cleaner:
(require '[rewrite-clj.zip :as z])
(-> "(1 2 3)"
(z/of-string {:track-position? true})
z/up
(z/postwalk
(fn [zloc]
(z/edit* zloc #(vary-meta % merge {:foo/bar :baz}))))
z/down
z/next
z/node
meta)
;; => {:row 1, :col 2, :end-row 1, :end-col 3, :foo/bar :baz}The z/edit* works directly on the node without attempting any coercion.
Here's me dumping all nodes, just to verify we seem all good with this approach:
(-> "(1 2 3)"
(z/of-string {:track-position? true})
z/up
(z/postwalk
(fn [zloc]
(z/edit* zloc #(vary-meta % merge {:foo/bar :baz}))))
(->> (iterate z/next)
(take-while identity)
(take-while (complement z/end?))
(map (fn [zloc]
[(z/string zloc)
(-> zloc z/node meta)]))))
;; => (["(1 2 3)" {:row 1, :col 1, :end-row 1, :end-col 8, :foo/bar :baz}]
;; ["(1 2 3)" {:row 1, :col 1, :end-row 1, :end-col 8, :foo/bar :baz}]
;; ["1" {:row 1, :col 2, :end-row 1, :end-col 3, :foo/bar :baz}]
;; ["2" {:row 1, :col 4, :end-row 1, :end-col 5, :foo/bar :baz}]
;; ["3" {:row 1, :col 6, :end-row 1, :end-col 7, :foo/bar :baz}])Does that work for your use case @s_zharinov?
This is exactly what I was looking for, thanks! 👍👍