Ver Fonte

Tienson/feat/outliner core (#1672)

* refactor: perf tune wip

* fix: can't create block in new pages

* fix: perf improvement (temporally)
Tienson Qin há 4 anos atrás
pai
commit
0cfc4fed31

+ 71 - 18
src/main/frontend/handler/editor.cljs

@@ -456,7 +456,8 @@
 
 
 (defn outliner-insert-block!
 (defn outliner-insert-block!
   [current-block new-block child?]
   [current-block new-block child?]
-  (let [[current-node new-node]
+  (let [dummy? (:block/dummy? current-block)
+        [current-node new-node]
         (mapv outliner-core/block [current-block new-block])
         (mapv outliner-core/block [current-block new-block])
         has-children? (db/has-children? (state/get-current-repo)
         has-children? (db/has-children? (state/get-current-repo)
                                         (tree/-get-id current-node))
                                         (tree/-get-id current-node))
@@ -469,9 +470,14 @@
 
 
                    :else
                    :else
                    (not has-children?))]
                    (not has-children?))]
-    ;; perf: multiple file writes
-    (outliner-core/save-node current-node)
-    (outliner-core/insert-node new-node current-node sibling?)))
+    (let [*blocks (atom [current-node])
+          _ (outliner-core/insert-node new-node current-node sibling? {:blocks-atom *blocks
+                                                                       :skip-transact? true})
+          tx-f (fn []
+                 (outliner-core/save-node current-node)
+                 (outliner-core/insert-node new-node current-node sibling?))]
+      (if dummy? (tx-f) (state/add-tx! tx-f))
+      @*blocks)))
 
 
 (defn- block-self-alone-when-insert?
 (defn- block-self-alone-when-insert?
   [config uuid]
   [config uuid]
@@ -485,6 +491,52 @@
                        current-page))]
                        current-page))]
     (= uuid (and block-id (medley/uuid block-id)))))
     (= uuid (and block-id (medley/uuid block-id)))))
 
 
+;; FIXME: painful
+(defn update-cache-for-block-insert!
+  "Currently, this only affects current editor container to improve the performance."
+  [repo config {:block/keys [page uuid] :as block} blocks]
+  (let [blocks (map :data blocks)
+        [first-block last-block right-block] blocks
+        child? (= (first (:block/parent last-block))
+                  (:block/uuid first-block))
+        block-container-id (when-let [id (:id config)]
+                             (and (util/uuid-string? id) (medley/uuid id)))
+        new-last-block (let [first-block-id {:db/id (:db/id first-block)}]
+                         (assoc last-block
+                                :block/left first-block-id
+                                :block/parent (if child?
+                                                first-block-id
+                                                ;; sibling
+                                                (:block/parent first-block))))
+        blocks [first-block new-last-block]
+        page-blocks-atom (db/get-page-blocks-cache-atom repo (:db/id page))
+        [before-part after-part] (and page-blocks-atom
+                                      (split-with
+                                       #(not= uuid (:block/uuid %))
+                                       @page-blocks-atom))
+        after-part (rest after-part)
+        blocks (concat before-part blocks after-part)
+        blocks (if right-block
+                 (map (fn [block]
+                        (if (= (:block/uuid right-block) (:block/uuid block))
+                          (assoc block :block/left (:block/left right-block))
+                          block)) blocks)
+                 blocks)]
+    (when page-blocks-atom
+      (reset! page-blocks-atom blocks))
+
+    ;; update block children cache if exists
+    ;; (when blocks-container-id
+    ;;   (let [blocks-atom (db/get-block-blocks-cache-atom repo blocks-container-id)
+    ;;         [before-part after-part] (and blocks-atom
+    ;;                                       (split-with
+    ;;                                        #(not= uuid (:block/uuid %))
+    ;;                                        @blocks-atom))
+    ;;         after-part (rest after-part)]
+    ;;     (when blocks-atom
+    ;;          (reset! blocks-atom (concat before-part blocks after-part)))))
+    ))
+
 (defn insert-new-block-aux!
 (defn insert-new-block-aux!
   [config
   [config
    {:block/keys [uuid content repo format]
    {:block/keys [uuid content repo format]
@@ -500,21 +552,24 @@
         [fst-block-text snd-block-text] (compute-fst-snd-block-text value pos)
         [fst-block-text snd-block-text] (compute-fst-snd-block-text value pos)
         current-block (-> (assoc block :block/content fst-block-text)
         current-block (-> (assoc block :block/content fst-block-text)
                           (wrap-parse-block))
                           (wrap-parse-block))
+        dummy? (:block/dummy? current-block)
         new-m {:block/uuid (db/new-block-id)
         new-m {:block/uuid (db/new-block-id)
                :block/content snd-block-text}
                :block/content snd-block-text}
         next-block (-> (merge block new-m)
         next-block (-> (merge block new-m)
                        (dissoc :db/id :block/collapsed? :block/properties :block/pre-block? :block/meta)
                        (dissoc :db/id :block/collapsed? :block/properties :block/pre-block? :block/meta)
-                     (wrap-parse-block))]
+                       (wrap-parse-block))
+        blocks (profile
+                "outliner insert block"
+                (outliner-insert-block! current-block next-block block-self?))]
     (do
     (do
-      (profile
-       "outliner insert block"
-       (outliner-insert-block! current-block next-block block-self?))
-      (profile
-       "db refresh"
-       (let [opts {:key :block/insert
-                   :data [current-block next-block]}]
-         (db/refresh! repo opts)))
-      (ok-handler next-block)
+      (if dummy?
+        (profile
+         "db refresh"
+         (let [opts {:key :block/insert
+                     :data [current-block next-block]}]
+           (db/refresh! repo opts)))
+        (profile "update cache " (update-cache-for-block-insert! repo config block blocks)))
+      (profile "ok handler" (ok-handler next-block))
       (state/set-editor-op! nil))))
       (state/set-editor-op! nil))))
 
 
 (defn clear-when-saved!
 (defn clear-when-saved!
@@ -582,10 +637,8 @@
           value
           value
           {:ok-handler
           {:ok-handler
            (fn [last-block]
            (fn [last-block]
-             (let [last-id (:block/uuid last-block)]
-               ;; perf: improvement
-               (edit-block! last-block 0 format id)
-               (clear-when-saved!)))}))))))
+             (edit-block! last-block 0 format id)
+             (clear-when-saved!))}))))))
 
 
 (defn update-timestamps-content!
 (defn update-timestamps-content!
   [{:block/keys [repeated? marker] :as block} content]
   [{:block/keys [repeated? marker] :as block} content]

+ 30 - 20
src/main/frontend/modules/outliner/core.cljs

@@ -146,6 +146,7 @@
                                            [:db/retract id attribute])
                                            [:db/retract id attribute])
                                       db-schema/retract-attributes))))))
                                       db-schema/retract-attributes))))))
       (swap! txs-state conj (dissoc m :db/other-tx))
       (swap! txs-state conj (dissoc m :db/other-tx))
+      this
       ;; TODO: enable for the database-only version
       ;; TODO: enable for the database-only version
       ;; (let [[m page-tx] (with-timestamp (:data this))]
       ;; (let [[m page-tx] (with-timestamp (:data this))]
       ;;  (swap! txs-state conj m page-tx)
       ;;  (swap! txs-state conj m page-tx)
@@ -195,13 +196,14 @@
         node (-> (tree/-set-left-id new-node parent-id)
         node (-> (tree/-set-left-id new-node parent-id)
                (tree/-set-parent-id parent-id))
                (tree/-set-parent-id parent-id))
         right-node (tree/-get-down parent-node)]
         right-node (tree/-get-down parent-node)]
-    (do
-      (if (tree/satisfied-inode? right-node)
-        (let [new-right-node (tree/-set-left-id right-node (tree/-get-id new-node))
-              saved-new-node (tree/-save node txs-state)]
-          (tree/-save new-right-node txs-state)
-          saved-new-node)
-        (tree/-save node txs-state)))))
+    (if (tree/satisfied-inode? right-node)
+      (let [new-right-node (tree/-set-left-id right-node (tree/-get-id new-node))
+            saved-new-node (tree/-save node txs-state)]
+        (tree/-save new-right-node txs-state)
+        [saved-new-node new-right-node])
+      (do
+        (tree/-save node txs-state)
+        [node]))))
 
 
 (defn insert-node-as-sibling
 (defn insert-node-as-sibling
   "Insert a node as sibling."
   "Insert a node as sibling."
@@ -210,21 +212,29 @@
   (let [node (-> (tree/-set-left-id new-node (tree/-get-id left-node))
   (let [node (-> (tree/-set-left-id new-node (tree/-get-id left-node))
                (tree/-set-parent-id (tree/-get-parent-id left-node)))
                (tree/-set-parent-id (tree/-get-parent-id left-node)))
         right-node (tree/-get-right left-node)]
         right-node (tree/-get-right left-node)]
-    (do
-      (if (tree/satisfied-inode? right-node)
-        (let [new-right-node (tree/-set-left-id right-node (tree/-get-id new-node))
-              saved-new-node (tree/-save node txs-state)]
-          (tree/-save new-right-node txs-state)
-          saved-new-node)
-        (tree/-save node txs-state)))))
+    (if (tree/satisfied-inode? right-node)
+      (let [new-right-node (tree/-set-left-id right-node (tree/-get-id new-node))
+            saved-new-node (tree/-save node txs-state)]
+        (tree/-save new-right-node txs-state)
+        [saved-new-node new-right-node])
+      (do
+        (tree/-save node txs-state)
+        [node]))))
 
 
 (defn insert-node
 (defn insert-node
-  [new-node target-node sibling?]
-  (ds/auto-transact!
-    [txs-state (ds/new-outliner-txs-state)] {:outliner-op :insert-node}
-    (if sibling?
-      (insert-node-as-sibling txs-state new-node target-node)
-      (insert-node-as-first-child txs-state new-node target-node))))
+  ([new-node target-node sibling?]
+   (insert-node new-node target-node sibling? nil))
+  ([new-node target-node sibling? {:keys [blocks-atom skip-transact?]
+                                   :or {skip-transact? false}}]
+   (ds/auto-transact!
+    [txs-state (ds/new-outliner-txs-state)] {:outliner-op :insert-node
+                                             :skip-transact? skip-transact?}
+    (let [result (if sibling?
+                   (insert-node-as-sibling txs-state new-node target-node)
+                   (insert-node-as-first-child txs-state new-node target-node))]
+      (when blocks-atom
+        (swap! blocks-atom concat result))
+      (first result)))))
 
 
 
 
 (defn- walk-&-insert-nodes
 (defn- walk-&-insert-nodes

+ 2 - 1
src/main/frontend/modules/outliner/datascript.cljc

@@ -37,7 +37,8 @@
 #?(:cljs
 #?(:cljs
    (defn transact!
    (defn transact!
      [txs opts]
      [txs opts]
-     (when (seq txs)
+     (when (and (seq txs)
+                (not (:skip-transact? opts)))
        (let [conn (conn/get-conn false)
        (let [conn (conn/get-conn false)
              editor-cursor (state/get-last-edit-block)
              editor-cursor (state/get-last-edit-block)
              meta (merge opts {:editor-cursor editor-cursor})
              meta (merge opts {:editor-cursor editor-cursor})

+ 1 - 1
src/main/frontend/modules/shortcut/mixin.cljs

@@ -14,7 +14,7 @@
      (js/setTimeout
      (js/setTimeout
       (fn []
       (fn []
         (swap! state-store assoc k state))
         (swap! state-store assoc k state))
-      100)
+      5)
      state)
      state)
 
 
    :did-remount
    :did-remount

+ 6 - 5
src/main/frontend/state.cljs

@@ -709,11 +709,12 @@
                      :editor/last-edit-block-id edit-input-id
                      :editor/last-edit-block-id edit-input-id
                      :cursor-range cursor-range))))
                      :cursor-range cursor-range))))
 
 
-       (let [input (gdom/getElement edit-input-id)
-             pos (count cursor-range)]
-         (set! (.-value input) (string/trim content))
-         (when move-cursor?
-           (util/move-cursor-to input pos)))))))
+       (when-let [input (gdom/getElement edit-input-id)]
+         (let [pos (count cursor-range)]
+           (when content
+             (set! (.-value input) (string/trim content)))
+           (when move-cursor?
+             (util/move-cursor-to input pos))))))))
 
 
 (defn clear-edit!
 (defn clear-edit!
   []
   []