Browse Source

feat: add defkeyword to define keyword

- add docstring for common used keywords
- support jump to definition in editors
- register malli-schema for keywords if provided
rcmerci 1 year ago
parent
commit
ef834cdaf7

+ 2 - 1
.clj-kondo/config.edn

@@ -182,6 +182,7 @@
            frontend.test.helper/deftest-async clojure.test/deftest
            frontend.test.helper/with-reset cljs.test/async
            frontend.worker.rtc.idb-keyval-mock/with-reset-idb-keyval-mock cljs.test/async
-           frontend.react/defc clojure.core/defn}
+           frontend.react/defc clojure.core/defn
+           frontend.schema-register/defkeyword cljs.spec.alpha/def}
  :skip-comments true
  :output {:progress true}}

+ 3 - 3
scripts/src/logseq/tasks/dev.clj

@@ -34,11 +34,11 @@
   (apply shell "yarn cljs:run-test" args))
 
 (defn lint-and-test
-  "Run all lint tasks, then run tests.
+  "Run all lint tasks, then run tests(exclude testcases taged by :long).
   pass args through to cmd 'yarn cljs:run-test'"
-  [& args]
+  []
   (lint)
-  (apply test args))
+  (test "-e" "long"))
 
 
 (defn gen-malli-kondo-config

+ 39 - 0
src/main/frontend/common_keywords.cljs

@@ -0,0 +1,39 @@
+(ns frontend.common-keywords
+  "There are some keywords scattered throughout the codebase."
+  (:require [frontend.schema-register :include-macros true :as sr]))
+
+
+(sr/defkeyword :block/uuid
+  "block's uuid"
+  :uuid)
+
+(sr/defkeyword :block/name
+  "block name, lowercase, only page-blocks have this attr"
+  :string)
+
+(sr/defkeyword :block/original-name
+  "like `:block/name`, but not unified into lowercase"
+  :string)
+
+(sr/defkeyword :block/type
+  "block type"
+  [:enum #{"property"} #{"class"} #{"whiteboard"} #{"hidden"}])
+
+(sr/defkeyword :block/parent
+  "page blocks don't have this attr")
+
+(sr/defkeyword :block/left
+  "
+- page blocks don't have this attr
+- some no-order blocks don't have this attr too,
+  TODO: list these types")
+
+(sr/defkeyword :block/content
+  "content string of the blocks.
+in db-version, page-references(e.g. [[page-name]]) are stored as [[~^uuid]]."
+  :string)
+
+(sr/defkeyword :block/raw-content
+  "like `:block/content`,
+but when eval `(:block/raw-content block-entity)`, return raw-content of this block"
+  :string)

+ 10 - 7
src/main/frontend/core.cljs

@@ -1,21 +1,23 @@
 (ns frontend.core
   "Entry ns for the mobile, browser and electron frontend apps"
   {:dev/always true}
-  (:require [rum.core :as rum]
+  (:require [frontend.common-keywords]
+            [frontend.components.plugins :as plugins]
+            [frontend.config :as config]
+            [frontend.fs.sync :as sync]
             [frontend.handler :as handler]
             [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.route :as route-handler]
-            [frontend.components.plugins :as plugins]
+            [frontend.log]
             [frontend.page :as page]
             [frontend.routes :as routes]
+            [frontend.schema-register :as sr]
             [frontend.spec]
-            [frontend.log]
+            [logseq.api]
+            [malli.dev.cljs :as md]
             [reitit.frontend :as rf]
             [reitit.frontend.easy :as rfe]
-            [logseq.api]
-            [frontend.fs.sync :as sync]
-            [frontend.config :as config]
-            [malli.dev.cljs :as md]))
+            [rum.core :as rum]))
 
 (defn set-router!
   []
@@ -47,6 +49,7 @@
 (defn ^:export start []
   (when config/dev?
     (md/start!))
+  (frontend.schema-register/init)
   (when-let [node (.getElementById js/document "root")]
     (set-router!)
     (rum/mount (page/current-page) node)

+ 15 - 0
src/main/frontend/schema_register.clj

@@ -0,0 +1,15 @@
+(ns frontend.schema-register
+  "Macro 'defkeyword' to def keyword with docstring and malli-schema")
+
+
+(defmacro defkeyword
+  "Define keyword with docstring and malli-schema"
+  [kw docstring & [optional-malli-schema]]
+  (assert (keyword? kw) "must be keyword")
+  (assert (some? docstring) "must have 'docstring' arg")
+  (let [register-schema (when optional-malli-schema
+                          `[(assert (frontend.schema-register/not-register-yet? ~kw) (str "Already registered: " ~kw))
+                            (frontend.schema-register/register! ~kw ~optional-malli-schema)])]
+    `(do
+       (cljs.spec.alpha/def ~kw any?)
+       ~@register-schema)))

+ 23 - 0
src/main/frontend/schema_register.cljs

@@ -0,0 +1,23 @@
+(ns frontend.schema-register
+  "Set malli default registry to a mutable one,
+  and use `register!` to add schemas dynamically."
+  (:require [malli.core :as m]
+            [malli.registry :as mr]))
+
+(def *malli-registry (atom {}))
+
+(defn register!
+  [type schema]
+  (swap! *malli-registry assoc type schema))
+
+(defn not-register-yet?
+  [type]
+  (boolean (nil? (@*malli-registry type))))
+
+(defn init
+  []
+  (reset! *malli-registry {})
+  (mr/set-default-registry!
+   (mr/composite-registry
+    (m/default-schemas)
+    (mr/mutable-registry *malli-registry))))

+ 43 - 35
src/main/frontend/worker/undo_redo.cljs

@@ -1,6 +1,7 @@
 (ns frontend.worker.undo-redo
   "undo/redo related fns and op-schema"
   (:require [datascript.core :as d]
+            [frontend.schema-register :include-macros true :as sr]
             [frontend.worker.db-listener :as db-listener]
             [frontend.worker.state :as worker-state]
             [logseq.common.config :as common-config]
@@ -9,22 +10,40 @@
             [malli.core :as m]
             [malli.util :as mu]))
 
+(sr/defkeyword ::boundary
+  "boundary of one or more undo-ops.
+when one undo/redo will operate on all ops between two ::boundary")
+
+(sr/defkeyword ::insert-block
+  "when a block is inserted, generate a ::insert-block undo-op.
+when undo this op, the related block will be removed.")
+
+(sr/defkeyword ::move-block
+  "when a block is moved, generate a ::move-block undo-op.")
+
+(sr/defkeyword ::remove-block
+  "when a block is removed, generate a ::remove-block undo-op.
+when undo this op, this original entity-map will be transacted back into db")
+
+(sr/defkeyword ::update-block
+  "when a block is updated, generate a ::update-block undo-op.")
+
 (def undo-op-schema
   (mu/closed-schema
    [:multi {:dispatch first}
-    [:boundary
+    [::boundary
      [:cat :keyword]]
-    [:insert-block
+    [::insert-block
      [:cat :keyword
       [:map
        [:block-uuid :uuid]]]]
-    [:move-block
+    [::move-block
      [:cat :keyword
       [:map
        [:block-uuid :uuid]
        [:block-origin-left :uuid]
        [:block-origin-parent :uuid]]]]
-    [:remove-block
+    [::remove-block
      [:cat :keyword
       [:map
        [:block-uuid :uuid]
@@ -38,7 +57,7 @@
          [:block/updated-at {:optional true} :int]
          [:block/format {:optional true} :any]
          [:block/tags {:optional true} [:sequential :uuid]]]]]]]
-    [:update-block
+    [::update-block
      [:cat :keyword
       [:map
        [:block-uuid :uuid]
@@ -70,31 +89,30 @@
   [db op]
   (let [block-uuid (:block-uuid (second op))]
     (case (first op)
-      :boundary op
+      ::boundary op
 
-      :insert-block
-      [:remove-block
+      ::insert-block
+      [::remove-block
        {:block-uuid block-uuid
         :block-entity-map (->block-entity-map db [:block/uuid block-uuid])}]
 
-      :move-block
+      ::move-block
       (let [b (d/entity db [:block/uuid block-uuid])]
-        [:move-block
+        [::move-block
          {:block-uuid block-uuid
           :block-origin-left (:block/uuid (:block/left b))
           :block-origin-parent (:block/uuid (:block/parent b))}])
 
-      :remove-block
-      [:insert-block {:block-uuid block-uuid}]
+      ::remove-block
+      [::insert-block {:block-uuid block-uuid}]
 
-      :update-block
+      ::update-block
       (let [block-origin-content (when (:block-origin-content (second op))
                                    (:block/content (d/entity db [:block/uuid block-uuid])))]
-        [:update-block
+        [::update-block
          (cond-> {:block-uuid block-uuid}
            block-origin-content (assoc :block-origin-content block-origin-content))]))))
 
-
 (def ^:private apply-conj-vec (partial apply (fnil conj [])))
 
 (defn- push-undo-ops
@@ -121,9 +139,8 @@
       (swap! repo->redo-stack update repo pop)
       peek-op)))
 
-
 (defmulti reverse-apply-op (fn [op _conn _repo] (first op)))
-(defmethod reverse-apply-op :remove-block
+(defmethod reverse-apply-op ::remove-block
   [op conn repo]
   (let [[_ {:keys [block-uuid block-entity-map]}] op]
     (when-let [left-entity (d/entity @conn [:block/uuid (:block/left block-entity-map)])]
@@ -147,10 +164,9 @@
                                           (assoc :block/tags (mapv (partial vector :block/uuid)
                                                                    (:block/tags block-entity-map))))]
                                        left-entity {:sibling? sibling? :keep-uuid? true}))
-        :push-undo-redo
-        ))))
+        :push-undo-redo))))
 
-(defmethod reverse-apply-op :insert-block
+(defmethod reverse-apply-op ::insert-block
   [op conn repo]
   (let [[_ {:keys [block-uuid]}] op]
     (when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
@@ -166,7 +182,7 @@
                                        {:children? false}))
         :push-undo-redo))))
 
-(defmethod reverse-apply-op :move-block
+(defmethod reverse-apply-op ::move-block
   [op conn repo]
   (let [[_ {:keys [block-uuid block-origin-left block-origin-parent]}] op]
     (when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
@@ -180,7 +196,7 @@
            (outliner-core/move-blocks! repo conn [block-entity] left-entity sibling?))
           :push-undo-redo)))))
 
-(defmethod reverse-apply-op :update-block
+(defmethod reverse-apply-op ::update-block
   [op conn repo]
   (let [[_ {:keys [block-uuid block-origin-content]}] op]
     (when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
@@ -195,7 +211,6 @@
                                     new-block))
         :push-undo-redo))))
 
-
 (defn undo
   [repo]
   (if-let [op (pop-undo-op repo)]
@@ -214,17 +229,13 @@
         (push-undo-ops repo [rev-op])))
     (prn "No further redo infomation")))
 
-
 ;;; listen db changes and push undo-ops
 
-
-
 (defn- normal-block?
   [entity]
   (and (:block/parent entity)
        (:block/left entity)))
 
-
 (defn- entity-datoms=>ops
   [db-before db-after id->attr->datom entity-datoms]
   (when-let [e (ffirst entity-datoms)]
@@ -239,28 +250,28 @@
           (cond
             (and (not add1?) block-uuid
                  (normal-block? entity-before))
-            [[:remove-block
+            [[::remove-block
               {:block-uuid (:block/uuid entity-before)
                :block-entity-map (->block-entity-map db-before e)}]]
 
             (and add1? block-uuid
                  (normal-block? entity-after))
-            [[:insert-block {:block-uuid (:block/uuid entity-after)}]]
+            [[::insert-block {:block-uuid (:block/uuid entity-after)}]]
 
             (and (or add3? add4?)
                  (normal-block? entity-after))
-            (cond-> [[:move-block
+            (cond-> [[::move-block
                       {:block-uuid (:block/uuid entity-after)
                        :block-origin-left (:block/uuid (:block/left entity-before))
                        :block-origin-parent (:block/uuid (:block/parent entity-before))}]]
               (and add2? block-content)
-              (conj [:update-block
+              (conj [::update-block
                      {:block-uuid (:block/uuid entity-after)
                       :block-origin-content (:block/content entity-before)}]))
 
             (and add2? block-content
                  (normal-block? entity-after))
-            [[:update-block
+            [[::update-block
               {:block-uuid (:block/uuid entity-after)
                :block-origin-content (:block/content entity-before)}]]))))))
 
@@ -270,7 +281,6 @@
     (when (seq ops)
       (push-undo-ops repo ops))))
 
-
 (defmethod db-listener/listen-db-changes :gen-undo-ops
   [_ {:keys [_tx-data tx-meta db-before db-after
              repo id->attr->datom same-entity-datoms-coll]}]
@@ -279,8 +289,6 @@
 
 ;;; listen db changes and push undo-ops (ends)
 
-
-
 (comment
   (defn- clear-undo-redo-stack
     []