mirror of
https://github.com/penpot/penpot.git
synced 2026-03-27 22:00:35 +01:00
♻️ Ensure a correct usage of concat/into operations.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
(ns app.common.data
|
||||
"Data manipulation and query helper functions."
|
||||
(:refer-clojure :exclude [concat read-string hash-map merge name])
|
||||
(:refer-clojure :exclude [read-string hash-map merge name])
|
||||
#?(:cljs
|
||||
(:require-macros [app.common.data]))
|
||||
(:require
|
||||
@@ -60,19 +60,37 @@
|
||||
m)
|
||||
(dissoc m k)))
|
||||
|
||||
(defn concat
|
||||
[& colls]
|
||||
(loop [result (transient (first colls))
|
||||
colls (next colls)]
|
||||
(defn- transient-concat
|
||||
[c1 colls]
|
||||
(loop [result (transient c1)
|
||||
colls colls]
|
||||
(if colls
|
||||
(recur (reduce conj! result (first colls))
|
||||
(next colls))
|
||||
(persistent! result))))
|
||||
|
||||
(defn concat-set
|
||||
([] #{})
|
||||
([c1]
|
||||
(if (set? c1) c1 (into #{} c1)))
|
||||
([c1 & more]
|
||||
(if (set? c1)
|
||||
(transient-concat c1 more)
|
||||
(transient-concat #{} (cons c1 more)))))
|
||||
|
||||
(defn concat-vec
|
||||
([] [])
|
||||
([c1]
|
||||
(if (vector? c1) c1 (into [] c1)))
|
||||
([c1 & more]
|
||||
(if (vector? c1)
|
||||
(transient-concat c1 more)
|
||||
(transient-concat [] (cons c1 more)))))
|
||||
|
||||
(defn preconj
|
||||
[coll elem]
|
||||
(assert (vector? coll))
|
||||
(concat [elem] coll))
|
||||
(into [elem] coll))
|
||||
|
||||
(defn enumerate
|
||||
([items] (enumerate items 0))
|
||||
@@ -144,10 +162,15 @@
|
||||
(reduce #(dissoc! %1 %2) (transient data) keys))))
|
||||
|
||||
(defn remove-at-index
|
||||
"Takes a vector and returns a vector with an element in the
|
||||
specified index removed."
|
||||
[v index]
|
||||
(vec (core/concat
|
||||
(subvec v 0 index)
|
||||
(subvec v (inc index)))))
|
||||
;; The subvec function returns a SubVector type that is an vector
|
||||
;; but does not have transient impl, because of this, we need to
|
||||
;; pass an explicit vector as first argument.
|
||||
(concat-vec []
|
||||
(subvec v 0 index)
|
||||
(subvec v (inc index))))
|
||||
|
||||
(defn zip [col1 col2]
|
||||
(map vector col1 col2))
|
||||
@@ -433,18 +456,18 @@
|
||||
(str maybe-keyword)))))
|
||||
|
||||
(defn with-next
|
||||
"Given a collectin will return a new collection where each element
|
||||
is paried with the next item in the collection
|
||||
(with-next (range 5)) => [[0 1] [1 2] [2 3] [3 4] [4 nil]"
|
||||
"Given a collection will return a new collection where each element
|
||||
is paired with the next item in the collection
|
||||
(with-next (range 5)) => [[0 1] [1 2] [2 3] [3 4] [4 nil]]"
|
||||
[coll]
|
||||
(map vector
|
||||
coll
|
||||
(concat [] (rest coll) [nil])))
|
||||
(concat (rest coll) [nil])))
|
||||
|
||||
(defn with-prev
|
||||
"Given a collectin will return a new collection where each element
|
||||
is paried with the previous item in the collection
|
||||
(with-prev (range 5)) => [[0 nil] [1 0] [2 1] [3 2] [4 3]"
|
||||
"Given a collection will return a new collection where each element
|
||||
is paired with the previous item in the collection
|
||||
(with-prev (range 5)) => [[0 nil] [1 0] [2 1] [3 2] [4 3]]"
|
||||
[coll]
|
||||
(map vector
|
||||
coll
|
||||
@@ -453,12 +476,12 @@
|
||||
(defn with-prev-next
|
||||
"Given a collection will return a new collection where every item is paired
|
||||
with the previous and the next item of a collection
|
||||
(with-prev-next (range 5)) => [[0 nil 1] [1 0 2] [2 1 3] [3 2 4] [4 3 nil]"
|
||||
(with-prev-next (range 5)) => [[0 nil 1] [1 0 2] [2 1 3] [3 2 4] [4 3 nil]]"
|
||||
[coll]
|
||||
(map vector
|
||||
coll
|
||||
(concat [nil] coll)
|
||||
(concat [] (rest coll) [nil])))
|
||||
(concat (rest coll) [nil])))
|
||||
|
||||
(defn prefix-keyword
|
||||
"Given a keyword and a prefix will return a new keyword with the prefix attached
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
(ns app.common.geom.align
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
@@ -16,11 +15,15 @@
|
||||
|
||||
(declare calc-align-pos)
|
||||
|
||||
;; TODO: revisit on how to reuse code and dont have this function
|
||||
;; duplicated because the implementation right now differs from the
|
||||
;; original function.
|
||||
|
||||
;; Duplicated from pages/helpers to remove cyclic dependencies
|
||||
(defn- get-children [id objects]
|
||||
(let [shapes (vec (get-in objects [id :shapes]))]
|
||||
(if shapes
|
||||
(d/concat shapes (mapcat #(get-children % objects) shapes))
|
||||
(into shapes (mapcat #(get-children % objects)) shapes)
|
||||
[])))
|
||||
|
||||
(defn- recursive-move
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
(defn curve-tangent
|
||||
"Retrieve the tangent vector to the curve in the point `t`"
|
||||
[[start end h1 h2] t]
|
||||
|
||||
|
||||
(let [coords [[(:x start) (:x h1) (:x h2) (:x end)]
|
||||
[(:y start) (:y h1) (:y h2) (:y end)]]
|
||||
|
||||
@@ -316,15 +316,13 @@
|
||||
:line-to [prev-point (command->point command)]
|
||||
|
||||
;; We return the bezier extremities
|
||||
:curve-to (d/concat
|
||||
[prev-point
|
||||
(command->point command)]
|
||||
(let [curve [prev-point
|
||||
(command->point command)
|
||||
(command->point command :c1)
|
||||
(command->point command :c2)]]
|
||||
(->> (curve-extremities curve)
|
||||
(mapv #(curve-values curve %)))))
|
||||
:curve-to (into [prev-point (command->point command)]
|
||||
(let [curve [prev-point
|
||||
(command->point command)
|
||||
(command->point command :c1)
|
||||
(command->point command :c2)]]
|
||||
(->> (curve-extremities curve)
|
||||
(map #(curve-values curve %)))))
|
||||
[])
|
||||
selrect (gpr/points->selrect points)]
|
||||
(-> selrect
|
||||
@@ -342,20 +340,19 @@
|
||||
(command->point command)]
|
||||
|
||||
;; We return the bezier extremities
|
||||
:curve-to (d/concat
|
||||
[(command->point prev)
|
||||
(command->point command)]
|
||||
(let [curve [(command->point prev)
|
||||
(command->point command)
|
||||
(command->point command :c1)
|
||||
(command->point command :c2)]]
|
||||
(->> (curve-extremities curve)
|
||||
(mapv #(curve-values curve %)))))
|
||||
:curve-to (into [(command->point prev)
|
||||
(command->point command)]
|
||||
(let [curve [(command->point prev)
|
||||
(command->point command)
|
||||
(command->point command :c1)
|
||||
(command->point command :c2)]]
|
||||
(->> (curve-extremities curve)
|
||||
(map #(curve-values curve %)))))
|
||||
[]))
|
||||
|
||||
extremities (mapcat calc-extremities
|
||||
content
|
||||
(d/concat [nil] content))
|
||||
(concat [nil] content))
|
||||
|
||||
selrect (gpr/points->selrect extremities)]
|
||||
|
||||
@@ -410,14 +407,16 @@
|
||||
(let [initial (first segments)
|
||||
lines (rest segments)]
|
||||
|
||||
(d/concat [{:command :move-to
|
||||
:params (select-keys initial [:x :y])}]
|
||||
(->> lines
|
||||
(mapv #(hash-map :command :line-to
|
||||
:params (select-keys % [:x :y]))))
|
||||
(d/concat-vec
|
||||
[{:command :move-to
|
||||
:params (select-keys initial [:x :y])}]
|
||||
|
||||
(when closed?
|
||||
[{:command :close-path}])))))
|
||||
(->> lines
|
||||
(map #(hash-map :command :line-to
|
||||
:params (select-keys % [:x :y]))))
|
||||
|
||||
(when closed?
|
||||
[{:command :close-path}])))))
|
||||
|
||||
(defonce num-segments 10)
|
||||
|
||||
@@ -770,7 +769,7 @@
|
||||
ts-3 (check-range c1-half c1-to c2-from c2-half)
|
||||
ts-4 (check-range c1-half c1-to c2-half c2-to)]
|
||||
|
||||
(d/concat [] ts-1 ts-2 ts-3 ts-4)))))))
|
||||
(d/concat-vec ts-1 ts-2 ts-3 ts-4)))))))
|
||||
|
||||
(remove-close-ts [{cp1 :p1 cp2 :p2}]
|
||||
(fn [{:keys [p1 p2]}]
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
not-mask-shapes (without-obj shapes mask-id)
|
||||
new-index (if (nil? index) nil (max (dec index) 0))
|
||||
new-shapes (insert-items other-ids new-index not-mask-shapes)]
|
||||
(d/concat [mask-id] new-shapes))))
|
||||
(into [mask-id] new-shapes))))
|
||||
|
||||
(add-to-parent [parent index shapes]
|
||||
(let [parent (-> parent
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
(let [old-obj (get objects id)
|
||||
new-obj (update-fn old-obj)
|
||||
|
||||
attrs (or attrs (d/concat #{} (keys old-obj) (keys new-obj)))
|
||||
attrs (or attrs (d/concat-set (keys old-obj) (keys new-obj)))
|
||||
|
||||
{rops :rops uops :uops}
|
||||
(reduce #(generate-operation %1 %2 old-obj new-obj ignore-geometry?)
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
"Retrieve all children ids recursively for a given object. The
|
||||
children's order will be breadth first."
|
||||
[id objects]
|
||||
|
||||
(loop [result (transient [])
|
||||
pending (transient [])
|
||||
next id]
|
||||
@@ -214,10 +213,10 @@
|
||||
[objects index ids]
|
||||
(let [[before after] (split-at index objects)
|
||||
p? (set ids)]
|
||||
(d/concat []
|
||||
(remove p? before)
|
||||
ids
|
||||
(remove p? after))))
|
||||
(d/concat-vec []
|
||||
(remove p? before)
|
||||
ids
|
||||
(remove p? after))))
|
||||
|
||||
(defn append-at-the-end
|
||||
[prev-ids ids]
|
||||
@@ -233,24 +232,25 @@
|
||||
([objects {:keys [include-frames? include-frame-children?]
|
||||
:or {include-frames? false
|
||||
include-frame-children? true}}]
|
||||
(let [lookup #(get objects %)
|
||||
root (lookup uuid/zero)
|
||||
|
||||
(let [lookup #(get objects %)
|
||||
root (lookup uuid/zero)
|
||||
root-children (:shapes root)
|
||||
|
||||
lookup-shapes
|
||||
(fn [result id]
|
||||
(if (nil? id)
|
||||
result
|
||||
(let [obj (lookup id)
|
||||
typ (:type obj)
|
||||
(let [obj (lookup id)
|
||||
typ (:type obj)
|
||||
children (:shapes obj)]
|
||||
|
||||
(cond-> result
|
||||
(or (not= :frame typ) include-frames?)
|
||||
(d/concat [obj])
|
||||
(conj obj)
|
||||
|
||||
(and (= :frame typ) include-frame-children?)
|
||||
(d/concat (map lookup children))))))]
|
||||
(into (map lookup) children)))))]
|
||||
|
||||
(reduce lookup-shapes [] root-children))))
|
||||
|
||||
@@ -299,15 +299,13 @@
|
||||
(some? (:shapes object))
|
||||
(assoc :shapes (mapv :id new-direct-children)))
|
||||
|
||||
new-object (update-new-object new-object object)
|
||||
|
||||
new-objects (d/concat [new-object] new-children)
|
||||
|
||||
updated-object (update-original-object object new-object)
|
||||
new-object (update-new-object new-object object)
|
||||
new-objects (into [new-object] new-children)
|
||||
|
||||
updated-object (update-original-object object new-object)
|
||||
updated-objects (if (identical? object updated-object)
|
||||
updated-children
|
||||
(d/concat [updated-object] updated-children))]
|
||||
(into [updated-object] updated-children))]
|
||||
|
||||
[new-object new-objects updated-objects])
|
||||
|
||||
@@ -320,9 +318,9 @@
|
||||
|
||||
(recur
|
||||
(next child-ids)
|
||||
(d/concat new-direct-children [new-child])
|
||||
(d/concat new-children new-child-objects)
|
||||
(d/concat updated-children updated-child-objects))))))))
|
||||
(into new-direct-children [new-child])
|
||||
(into new-children new-child-objects)
|
||||
(into updated-children updated-child-objects))))))))
|
||||
|
||||
(defn indexed-shapes
|
||||
"Retrieves a list with the indexes for each element in the layer tree.
|
||||
|
||||
@@ -12,28 +12,25 @@
|
||||
[clojure.set :as set]))
|
||||
|
||||
(defn calculate-frame-z-index [z-index frame-id objects]
|
||||
(let [is-frame? (fn [id] (= :frame (get-in objects [id :type])))
|
||||
(let [is-frame? (fn [id] (= :frame (get-in objects [id :type])))
|
||||
frame-shapes (->> objects (vals) (filterv #(= (:frame-id %) frame-id)))
|
||||
children (or (get-in objects [frame-id :shapes]) [])]
|
||||
children (or (get-in objects [frame-id :shapes]) [])]
|
||||
|
||||
(if (empty? children)
|
||||
z-index
|
||||
|
||||
(loop [current (peek children)
|
||||
pending (pop children)
|
||||
current-idx (count frame-shapes)
|
||||
z-index z-index]
|
||||
|
||||
(let [children (get-in objects [current :shapes])
|
||||
(let [children (get-in objects [current :shapes])
|
||||
is-frame? (is-frame? current)
|
||||
pending (if (not is-frame?)
|
||||
(d/concat pending children)
|
||||
pending)]
|
||||
pending (if (not is-frame?)
|
||||
(d/concat-vec pending children)
|
||||
pending)]
|
||||
|
||||
(if (empty? pending)
|
||||
(-> z-index
|
||||
(assoc current current-idx))
|
||||
|
||||
(assoc z-index current current-idx)
|
||||
(recur (peek pending)
|
||||
(pop pending)
|
||||
(dec current-idx)
|
||||
|
||||
@@ -213,26 +213,25 @@
|
||||
;; Pick all segments in content-a that are not inside content-b
|
||||
;; Pick all segments in content-b that are not inside content-a
|
||||
(let [content
|
||||
(d/concat
|
||||
[]
|
||||
(concat
|
||||
(->> content-a-split (filter #(not (contains-segment? % content-b))))
|
||||
(->> content-b-split (filter #(not (contains-segment? % content-a)))))
|
||||
|
||||
;; Overlapping segments should be added when they are part of the border
|
||||
border-content
|
||||
(->> content-b-split
|
||||
(filterv #(and (contains-segment? % content-a)
|
||||
(overlap-segment? % content-a-split)
|
||||
(not (inside-segment? % content)))))]
|
||||
(filter #(and (contains-segment? % content-a)
|
||||
(overlap-segment? % content-a-split)
|
||||
(not (inside-segment? % content)))))]
|
||||
|
||||
(d/concat content border-content)))
|
||||
;; Ensure that the output is always a vector
|
||||
(d/concat-vec content border-content)))
|
||||
|
||||
(defn create-difference [content-a content-a-split content-b content-b-split]
|
||||
;; Pick all segments in content-a that are not inside content-b
|
||||
;; Pick all segments in content b that are inside content-a
|
||||
;; removing overlapping
|
||||
(d/concat
|
||||
[]
|
||||
(d/concat-vec
|
||||
(->> content-a-split (filter #(not (contains-segment? % content-b))))
|
||||
|
||||
;; Reverse second content so we can have holes inside other shapes
|
||||
@@ -243,15 +242,14 @@
|
||||
(defn create-intersection [content-a content-a-split content-b content-b-split]
|
||||
;; Pick all segments in content-a that are inside content-b
|
||||
;; Pick all segments in content-b that are inside content-a
|
||||
(d/concat
|
||||
[]
|
||||
(d/concat-vec
|
||||
(->> content-a-split (filter #(contains-segment? % content-b)))
|
||||
(->> content-b-split (filter #(contains-segment? % content-a)))))
|
||||
|
||||
|
||||
(defn create-exclusion [content-a content-b]
|
||||
;; Pick all segments
|
||||
(d/concat [] content-a content-b))
|
||||
(d/concat-vec content-a content-b))
|
||||
|
||||
|
||||
(defn fix-move-to
|
||||
|
||||
@@ -31,23 +31,22 @@
|
||||
:blur])
|
||||
|
||||
(def style-properties
|
||||
(d/concat
|
||||
style-group-properties
|
||||
[:fill-color
|
||||
:fill-opacity
|
||||
:fill-color-gradient
|
||||
:fill-color-ref-file
|
||||
:fill-color-ref-id
|
||||
:fill-image
|
||||
:stroke-color
|
||||
:stroke-color-ref-file
|
||||
:stroke-color-ref-id
|
||||
:stroke-opacity
|
||||
:stroke-style
|
||||
:stroke-width
|
||||
:stroke-alignment
|
||||
:stroke-cap-start
|
||||
:stroke-cap-end]))
|
||||
(into style-group-properties
|
||||
[:fill-color
|
||||
:fill-opacity
|
||||
:fill-color-gradient
|
||||
:fill-color-ref-file
|
||||
:fill-color-ref-id
|
||||
:fill-image
|
||||
:stroke-color
|
||||
:stroke-color-ref-file
|
||||
:stroke-color-ref-id
|
||||
:stroke-opacity
|
||||
:stroke-style
|
||||
:stroke-width
|
||||
:stroke-alignment
|
||||
:stroke-cap-start
|
||||
:stroke-cap-end]))
|
||||
|
||||
(defn make-corner-arc
|
||||
"Creates a curvle corner for border radius"
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
[subpath other]
|
||||
(assert (pt= (:to subpath) (:from other)))
|
||||
(-> subpath
|
||||
(update :data d/concat (rest (:data other)))
|
||||
(update :data d/concat-vec (rest (:data other)))
|
||||
(assoc :to (:to other))))
|
||||
|
||||
(defn- merge-paths
|
||||
|
||||
Reference in New Issue
Block a user