suppose in ../clojure there is a checkout of clojure and rewrite-clj has been patched to include find-last-by-pos (https://github.com/lread/rewrite-cljs-playground/blob/master/src/rewrite_clj/zip/findz.cljc#L44_L57) (and may be some other things in rewrite-cljs-playground). consider the following:
(require '[rewrite-clj.zip :as rz])
(def set-str
(slurp "../clojure/src/clj/clojure/set.clj"))
;; nil
(-> (rz/of-string set-str
{:track-position? true})
(rz/find-last-by-pos [1 1]))
;; nil
(-> (rz/of-string set-str
{:track-position? true})
(rz/find-last-by-pos [178 1]))
the first of the thread-first forms gives nil because the position is before all top-level forms, iiuc. correspondingly, the second of the thread-first forms gives nil because the position is after all top-level forms.
to distinguish between these cases it appears that comparing the position (e.g. row 1 col 1 or row 178 col 1 in the code above) with the return value of:
(-> (rz/of-string set-str
{:track-position? true})
rz/position)
is one approach.
anyone know of a better or alternative method?Hi @sogaiu, I’ll study this and respond sometime soon
@lee thanks!
for some context, i'm doing this sort of thing:
(require '[rewrite-clj.zip :as rz])
(defn rcb? ; rich comment block
[zloc]
(and (rz/list? zloc)
(= "comment"
(-> zloc
rz/down
rz/string))))
(defn before?
[[r1 c1] [r2 c2]]
(cond (< r1 r2) true
;;
(> r1 r2) false
;;
:else (cond (< c1 c2)
true
;;
:else
false)))
;; before
(before? [1 1] [2 1])
;; not before, after
(before? [5 5] [1 2])
;; not before, the same
(before? [10 20] [10 20])
(defn expr-str-at
[src-str row col] ; XXX: consider [row col] as single parameter?
(let [zloc-0 (rz/of-string src-str
{:track-position? true})
_ (assert zloc-0 ; XXX: just return nil instead?
"of-string returned nil")
zloc (if-let [zloc (rz/find-last-by-pos zloc-0 [row col])]
zloc
;; before or after all top-level forms
(let [pos-0 (rz/position zloc-0)]
(when (before? pos-0 [row col])
(rz/rightmost zloc-0))))]
(when zloc
(loop [zloc zloc]
(if (or (contains? #{:comma :comment :newline :whitespace}
(rz/tag zloc))
(rcb? zloc))
(recur (rz/left zloc))
(rz/string zloc))))))
it's supposed to find the first non-comment-whitespace-etc expr string "at" row col (where "at" can look left if row col happens to refer to whitespace, newline, comment, comma nodes or (comment ...))
I moved this to git issue so I don't forget to answer sometime https://github.com/lread/rewrite-cljs-playground/issues/3
I'm not sure if I capture your entire question please feel free to add to it.
thanks -- added a comment
awesome, thanks!
although there's comment?
, list?
, and others, i don't see a forms?
-- is there a good way to check whether one has "gone up" all the way to the top apart from looking at the tag value?
edn
seems to check the tag value directly. is it a problem to have a predicate for this? or alternatively, are there reasons to not have such a predicate?
I'm not so familiar anymore with the zipper part of rewrite-clj so can't really help, sorry
np -- this is partly :duckie: ing 🙂 here's a use case for checking whether one is aleady at the top of the zipper:
(defn in-rcb?
[src-str row col]
(let [zloc-0 (rz/of-string src-str
{:track-position? true})
_ (assert zloc-0 ; XXX: just return nil instead?
"of-string returned nil")
zloc (rz/find-last-by-pos zloc-0 [row col])]
;; zloc nil means before or after all top-levels, so not in rcb
(when zloc
(loop [zloc zloc]
(cond (rcb? zloc)
zloc
;;
(= (rz/tag zloc) :forms)
nil?
;;
:else
(recur (-> zloc
rz/leftmost
rz/up)))))))