fix: bind repeated marks to their own occurrence in their own context

A mark that repeats an earlier part produced bars for every occurrence of
that part, so all of an annotation's marks lit up at once inside it. In the
annotation's own context the local ranges are already the truth — merge those
instead of re-projecting the part across the parent's segments. Other contexts
still project, which is what makes a repeat visible from outside.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-09-17 15:54:11 -04:00
parent 839f4c51f1
commit 12ab7c4fca
2 changed files with 29 additions and 3 deletions

View file

@ -264,12 +264,16 @@
(defn- binding-bars [scene ctx segs annotations bound] (defn- binding-bars [scene ctx segs annotations bound]
(vec (vec
(mapcat (fn [gid] (mapcat (fn [gid]
(let [g (get-in scene [:groups gid])] (let [g (get-in scene [:groups gid])
segments (scene/resolve scene gid)
bars #(if (= gid ctx)
(scene/merge-bars (map :local %))
(scene/project-bars % segs))]
(concat (concat
(when (seq (bound g)) (when (seq (bound g))
[{:gids (bound g) :bars (scene/project-bars (scene/resolve scene gid) segs)}]) [{:gids (bound g) :bars (bars segments)}])
(for [m (:marks g) :when (seq (bound m))] (for [m (:marks g) :when (seq (bound m))]
{:gids (bound m) :bars (scene/mark-bars scene gid (:id m) segs)})))) {:gids (bound m) :bars (bars (filter #(= (:id m) (:mark %)) segments))}))))
(conj (set (map :id annotations)) ctx)))) (conj (set (map :id annotations)) ctx))))
(rf/reg-sub ::drawing-bars (rf/reg-sub ::drawing-bars

View file

@ -157,6 +157,28 @@
(is (= [:d] (mapv :id @(rf/subscribe [::subs/active-drawings])))) (is (= [:d] (mapv :id @(rf/subscribe [::subs/active-drawings]))))
(is (= #{:n} @(rf/subscribe [::subs/active-note-set]))))) (is (= #{:n} @(rf/subscribe [::subs/active-note-set])))))
(deftest repeated-marks-bind-to-own-occurrences-but-project-in-other-contexts
(rf-test/run-test-sync
(let [marks (mapv (fn [i [a b]]
(assoc (fixture/mark i (fixture/part :a a b))
:drawings [i] :notes [i]))
[:d1 :d2 :d3 :d4] [[12 72] [51 96] [22 77] [22 90]])
sc (reduce #(assoc-in %1 [:groups %2] {:type :drawing :strokes []})
(apply fixture/annotation fixture/base :repeat [:root] marks)
[:d1 :d2 :d3 :d4])]
(setup! sc [:root :repeat])
(doseq [[frame expected] [[0 #{:d1}] [55 #{:d1}] [59 #{:d1}]
[60 #{:d2}] [104 #{:d2}] [105 #{:d3}]
[159 #{:d3}] [160 #{:d4}] [227 #{:d4}] [228 #{}]]]
(rf/dispatch [::ev/set-playhead :repeat frame])
(is (= expected (set (map :id @(rf/subscribe [::subs/active-drawings])))))
(is (= expected @(rf/subscribe [::subs/active-note-set]))))
(setup! sc [:root])
(rf/dispatch [::ev/set-playhead :root 67])
(is (= #{:d1 :d2 :d3 :d4}
(set (map :id @(rf/subscribe [::subs/active-drawings])))))
(is (= #{:d1 :d2 :d3 :d4} @(rf/subscribe [::subs/active-note-set]))))))
(deftest nested-repeat-projection-is-shared-by-editor-and-lane (deftest nested-repeat-projection-is-shared-by-editor-and-lane
(rf-test/run-test-sync (rf-test/run-test-sync
(setup! fixture/base [:root]) (setup! fixture/base [:root])