Просмотр исходного кода

fix: node references do not appear on blocks that contain a tag

fixes https://github.com/logseq/db-test/issues/43
Tienson Qin 1 год назад
Родитель
Сommit
c23c15ca7e

+ 48 - 11
deps/db/src/logseq/db/frontend/content.cljs

@@ -76,17 +76,54 @@
        (map second)
        (map uuid)))
 
-(defn page-ref->special-id-ref
-  "Convert page ref to special id refs e.g. `[[page name]] -> [[~^...]].
-   TODO: Merge with db-editor-handler/replace-page-refs-with-ids when possible"
-  [content refs]
-  (reduce
-   (fn [content ref]
-     (-> content
-         (string/replace (str page-ref/left-brackets (:block/title ref) page-ref/right-brackets)
-                         (str page-ref/left-brackets page-ref-special-chars (:block/uuid ref) page-ref/right-brackets))))
-   content
-   refs))
+(defn- replace-tag-ref
+  [content page-name id]
+  (let [id' (str page-ref-special-chars id)
+        [page wrapped-id] (if (string/includes? page-name " ")
+                            (map page-ref/->page-ref [page-name id'])
+                            [page-name id'])
+        page-name (common-util/format "#%s" page)
+        r (common-util/format "#%s" wrapped-id)]
+    ;; hash tag parsing rules https://github.com/logseq/mldoc/blob/701243eaf9b4157348f235670718f6ad19ebe7f8/test/test_markdown.ml#L631
+    ;; Safari doesn't support look behind, don't use
+    ;; TODO: parse via mldoc
+    (string/replace content
+                    (re-pattern (str "(?i)(^|\\s)(" (common-util/escape-regex-chars page-name) ")(?=[,\\.]*($|\\s))"))
+                    ;;    case_insense^    ^lhs   ^_grp2                       look_ahead^         ^_grp3
+                    (fn [[_match lhs _grp2 _grp3]]
+                      (str lhs r)))))
+
+(defn- replace-page-ref
+  [content page-name id]
+  (let [id' (str page-ref-special-chars id)
+        [page wrapped-id] (map page-ref/->page-ref [page-name id'])]
+        (common-util/replace-ignore-case content page wrapped-id)))
+
+(defn- replace-page-ref-with-id
+  [content page-name id]
+  (let [page-name (str page-name)
+        id (str id)]
+    (-> content
+       (replace-page-ref page-name id)
+       (replace-tag-ref page-name id))))
+
+(defn refs->special-id-ref
+  "Convert ref to special id refs e.g. `[[page name]] -> [[~^...]]."
+  [db title refs]
+  (let [refs' (map
+               (fn [ref]
+                 (if (and (vector? ref) (= :block/uuid (first ref)))
+                   (d/entity db ref)
+                   ref))
+               refs)]
+    (if (some :block/title refs')
+      (reduce
+       (fn [content {:block/keys [title uuid]}]
+         (-> (replace-page-ref-with-id content title uuid)
+             (replace-page-ref-with-id uuid uuid)))
+       title
+       (filter :block/title refs'))
+      title)))
 
 (defn update-block-content
   "Replace `[[internal-id]]` with `[[page name]]`"

+ 11 - 11
deps/db/src/logseq/db/sqlite/build.cljs

@@ -107,7 +107,7 @@
     []
     (map second (re-seq page-ref/page-ref-re s))))
 
-(defn- ->block-tx [{:keys [build/properties] :as m} properties-config page-uuids all-idents page-id]
+(defn- ->block-tx [db {:keys [build/properties] :as m} properties-config page-uuids all-idents page-id]
   (let [new-block {:db/id (new-db-id)
                    :block/format :markdown
                    :block/page {:db/id page-id}
@@ -134,7 +134,7 @@
                                                            (throw (ex-info (str "No uuid for page ref name" (pr-str %)) {})))
                                                        :block/title %)
                                             ref-names)]
-                       {:block/title (db-content/page-ref->special-id-ref (:block/title m) block-refs)
+                       {:block/title (db-content/refs->special-id-ref db (:block/title m) block-refs)
                         :block/refs block-refs})))))))
 
 (defn- build-properties-tx [properties page-uuids all-idents]
@@ -332,8 +332,8 @@
     all-idents))
 
 (defn- build-pages-and-blocks-tx
-  [pages-and-blocks all-idents page-uuids {:keys [page-id-fn properties]
-                                           :or {page-id-fn :db/id}}]
+  [db pages-and-blocks all-idents page-uuids {:keys [page-id-fn properties]
+                                              :or {page-id-fn :db/id}}]
   (vec
    (mapcat
     (fn [{:keys [page blocks]}]
@@ -366,7 +366,7 @@
          ;; blocks tx
          (reduce (fn [acc m]
                    (into acc
-                         (->block-tx m properties page-uuids all-idents (page-id-fn new-page))))
+                         (->block-tx db m properties page-uuids all-idents (page-id-fn new-page))))
                  []
                  blocks))))
     pages-and-blocks)))
@@ -515,8 +515,8 @@
     {:classes classes' :properties properties'}))
 
 (defn- build-blocks-tx*
-  [{:keys [pages-and-blocks properties graph-namespace auto-create-ontology?]
-    :as options}]
+  [db {:keys [pages-and-blocks properties graph-namespace auto-create-ontology?]
+       :as options}]
   (let [pages-and-blocks' (pre-build-pages-and-blocks pages-and-blocks properties)
         page-uuids (create-page-uuids pages-and-blocks')
         {:keys [classes properties]} (if auto-create-ontology? (auto-create-ontology options) options)
@@ -534,7 +534,7 @@
                                                  cs)))
                                  m))
                              properties-tx)
-        pages-and-blocks-tx (build-pages-and-blocks-tx pages-and-blocks' all-idents page-uuids
+        pages-and-blocks-tx (build-pages-and-blocks-tx db pages-and-blocks' all-idents page-uuids
                                                        (assoc options :properties properties))]
     ;; Properties first b/c they have schema and are referenced by all. Then classes b/c they can be referenced by pages. Then pages
     (split-blocks-tx (concat properties-tx'
@@ -588,9 +588,9 @@
    supported: :default, :url, :checkbox, :number, :node and :date. :checkbox and
    :number values are written as booleans and integers/floats. :node references
    are written as vectors e.g. `[:page \"PAGE NAME\"]`"
-  [options]
+  [db options]
   (validate-options options)
-  (build-blocks-tx* options))
+  (build-blocks-tx* db options))
 
 (defn create-blocks
   "Builds txs with build-blocks-tx and transacts them. Also provides a shorthand
@@ -598,7 +598,7 @@
   [conn options]
   (let [options' (merge {:auto-create-ontology? true}
                         (if (vector? options) {:pages-and-blocks options} options))
-        {:keys [init-tx block-props-tx]} (build-blocks-tx options')]
+        {:keys [init-tx block-props-tx]} (build-blocks-tx @conn options')]
     (d/transact! conn init-tx)
     (when (seq block-props-tx)
       (d/transact! conn block-props-tx))))

+ 9 - 8
deps/graph-parser/src/logseq/graph_parser/exporter.cljs

@@ -580,7 +580,7 @@
 (defn- update-block-refs
   "Updates the attributes of a block ref as this is where a new page is defined. Also
    updates block content effected by refs"
-  [block page-names-to-uuids {:keys [whiteboard?]}]
+  [db block page-names-to-uuids {:keys [whiteboard?]}]
   (let [ref-to-ignore? (if whiteboard?
                          #(and (map? %) (:block/uuid %))
                          #(and (vector? %) (= :block/uuid (first %))))]
@@ -601,13 +601,14 @@
                  refs)))
         (:block/title block)
         (update :block/title
-                db-content/page-ref->special-id-ref
-                ;; TODO: Handle refs for whiteboard block which has none
-                (->> (:block/refs block)
-                     (remove #(or (ref-to-ignore? %)
+                (fn [title]
+                  ;; TODO: Handle refs for whiteboard block which has none
+                  (let [refs (->> (:block/refs block)
+                                  (remove #(or (ref-to-ignore? %)
                                   ;; ignore deadline related refs that don't affect content
-                                  (and (keyword? %) (db-malli-schema/internal-ident? %))))
-                     (map #(add-uuid-to-page-map % page-names-to-uuids)))))
+                                               (and (keyword? %) (db-malli-schema/internal-ident? %))))
+                                  (map #(add-uuid-to-page-map % page-names-to-uuids)))]
+                    (db-content/refs->special-id-ref db title refs)))))
       block)))
 
 (defn- fix-pre-block-references
@@ -637,7 +638,7 @@
         block' (-> block-after-built-in-props
                    (fix-pre-block-references pre-blocks page-names-to-uuids)
                    (fix-block-name-lookup-ref page-names-to-uuids)
-                   (update-block-refs page-names-to-uuids options)
+                   (update-block-refs db page-names-to-uuids options)
                    (update-block-tags db tag-classes page-names-to-uuids (:all-idents import-state))
                    (update-block-marker options)
                    (update-block-priority options)

+ 11 - 5
deps/outliner/src/logseq/outliner/core.cljs

@@ -241,12 +241,14 @@
   (cond
     (and (ldb/page? entity) (seq tags))
     (when-let [res (seq (d/q '[:find [?b ...]
-                               :in $ ?title [?tag-id ...]
+                               :in $ ?eid ?title [?tag-id ...]
                                :where
                                [?b :block/title ?title]
                                [?b :block/tags ?tag-id]
-                               [?b :block/type "page"]]
+                               [?b :block/type "page"]
+                               [(not= ?b ?eid)]]
                              db
+                             (:db/id entity)
                              new-title
                              (map :db/id tags)))]
       (throw (ex-info "Duplicate page by tag"
@@ -257,11 +259,13 @@
 
     (ldb/page? entity)
     (when-let [_res (seq (d/q '[:find [?b ...]
-                                :in $ ?title
+                                :in $ ?eid ?title
                                 :where
                                 [?b :block/title ?title]
-                                [?b :block/type "page"]]
+                                [?b :block/type "page"]
+                                [(not= ?b ?eid)]]
                               db
+                              (:db/id entity)
                               new-title))]
       (throw (ex-info "Duplicate page without tag"
                       {:type :notification
@@ -270,12 +274,14 @@
 
     (and (not (:block/type entity)) (seq tags))
     (when-let [res (seq (d/q '[:find [?b ...]
-                               :in $ ?title [?tag-id ...]
+                               :in $ ?eid ?title [?tag-id ...]
                                :where
                                [?b :block/title ?title]
                                [?b :block/tags ?tag-id]
+                               [(not= ?b ?eid)]
                                [(missing? $ ?b :block/type)]]
                              db
+                             (:db/id entity)
                              new-title
                              (map :db/id tags)))]
       (throw (ex-info "Duplicate block by tag"

+ 10 - 51
src/main/frontend/handler/db_based/editor.cljs

@@ -1,25 +1,24 @@
 (ns frontend.handler.db-based.editor
   "DB-based graph implementation"
   (:require [clojure.string :as string]
-            [frontend.config :as config]
             [frontend.commands :as commands]
+            [frontend.config :as config]
             [frontend.db :as db]
             [frontend.format.block :as block]
             [frontend.format.mldoc :as mldoc]
-            [frontend.util :as util]
-            [frontend.state :as state]
-            [logseq.common.util.page-ref :as page-ref]
-            [frontend.handler.ui :as ui-handler]
             [frontend.handler.common.config-edn :as config-edn-common-handler]
             [frontend.handler.property :as property-handler]
             [frontend.handler.property.util :as pu]
             [frontend.handler.repo-config :as repo-config-handler]
-            [frontend.modules.outliner.ui :as ui-outliner-tx]
+            [frontend.handler.ui :as ui-handler]
             [frontend.modules.outliner.op :as outliner-op]
+            [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.schema.handler.repo-config :as repo-config-schema]
-            [promesa.core :as p]
+            [frontend.state :as state]
+            [frontend.util :as util]
             [logseq.db.frontend.content :as db-content]
-            [logseq.outliner.op]))
+            [logseq.outliner.op]
+            [promesa.core :as p]))
 
 (defn- remove-non-existed-refs!
   [refs]
@@ -44,48 +43,6 @@
              x))
          refs)))
 
-(defn- replace-tag-ref
-  [content page-name id]
-  (let [id' (str db-content/page-ref-special-chars id)
-        [page wrapped-id] (if (string/includes? page-name " ")
-                            (map page-ref/->page-ref [page-name id'])
-                            [page-name id'])
-        page-name (util/format "#%s" page)
-        r (util/format "#%s" wrapped-id)]
-    ;; hash tag parsing rules https://github.com/logseq/mldoc/blob/701243eaf9b4157348f235670718f6ad19ebe7f8/test/test_markdown.ml#L631
-    ;; Safari doesn't support look behind, don't use
-    ;; TODO: parse via mldoc
-    (string/replace content
-                    (re-pattern (str "(?i)(^|\\s)(" (util/escape-regex-chars page-name) ")(?=[,\\.]*($|\\s))"))
-                    ;;    case_insense^    ^lhs   ^_grp2                       look_ahead^         ^_grp3
-                    (fn [[_match lhs _grp2 _grp3]]
-                      (str lhs r)))))
-
-(defn- replace-page-ref
-  [content page-name id]
-  (let [id' (str db-content/page-ref-special-chars id)
-        [page wrapped-id] (map page-ref/->page-ref [page-name id'])]
-        (util/replace-ignore-case content page wrapped-id)))
-
-(defn- replace-page-ref-with-id
-  [content page-name id]
-  (-> content
-      (replace-page-ref page-name id)
-      (replace-tag-ref page-name id)))
-
-
-(defn- replace-page-refs-with-ids
-  [block]
-  (let [content (:block/title block)
-        content' (if (some :block/title (:block/refs block))
-                   (reduce
-                    (fn [content {:block/keys [title uuid]}]
-                      (replace-page-ref-with-id content title uuid))
-                    content
-                    (filter :block/title (:block/refs block)))
-                   content)]
-    (assoc block :block/title content')))
-
 (defn wrap-parse-block
   [{:block/keys [title level] :as block}]
   (let [block (or (and (:db/id block) (db/entity (:db/id block))) block)
@@ -104,7 +61,9 @@
                                 (use-cached-refs! block))))))
         result (-> block
                    (merge (if level {:block/level level} {}))
-                   (replace-page-refs-with-ids))]
+                   (update :block/title
+                           (fn [title]
+                             (db-content/refs->special-id-ref (db/get-db) title (:block/refs block)))))]
     result))
 
 (defn save-file!

+ 3 - 2
src/main/frontend/handler/paste.cljs

@@ -37,8 +37,9 @@
                              (-> block
                                  (dissoc :block/tags)
                                  (update :block/title (fn [title]
-                                                        (-> (db-content/replace-tags-with-page-refs title refs)
-                                                            (db-content/page-ref->special-id-ref refs)))))))))]
+                                                        (let [title' (db-content/replace-tags-with-page-refs title refs)]
+                                                          (db-content/refs->special-id-ref (db/get-db) title' refs))
+                                                        )))))))]
       (editor-handler/paste-blocks blocks' {:keep-uuid? true}))))
 
 (defn- paste-segmented-text

+ 0 - 6
src/main/frontend/util.cljc

@@ -667,12 +667,6 @@
          (str prefix new-value)))
      s)))
 
-#?(:cljs
-   (def escape-regex-chars common-util/escape-regex-chars))
-
-#?(:cljs
-   (def replace-ignore-case common-util/replace-ignore-case))
-
 ;; copy from https://stackoverflow.com/questions/18735665/how-can-i-get-the-positions-of-regex-matches-in-clojurescript
 #?(:cljs
    (defn re-pos [re s]