Browse Source

enhance: import markdown quotes

Went ahead and implemented ast block to string
as regex version of this would've been to buggy
Gabriel Horner 8 months ago
parent
commit
8c6146a00d

+ 47 - 5
deps/graph-parser/src/logseq/graph_parser/exporter.cljs

@@ -974,12 +974,54 @@
           (assoc :asset-blocks-tx asset-blocks)))
       {:block block})))
 
+(defn- ast->text
+  "Given an ast block, convert it to text for use as a block title. This is a
+  slimmer version of handler.export.text/export-blocks-as-markdown"
+  [ast-block {:keys [log-fn]
+              :or {log-fn prn}}]
+  (let [extract
+        (fn extract [node]
+          (let [extract-emphasis
+                (fn extract-emphasis [node]
+                  (let [[[type'] coll'] node]
+                    (case type'
+                      "Bold"
+                      (vec (concat ["**"] (mapcat extract coll') ["**"]))
+                      "Italic"
+                      (vec (concat ["*"] (mapcat extract coll') ["*"]))
+                      "Strike_through"
+                      (vec (concat ["~~"] (mapcat extract coll') ["~~"]))
+                      "Highlight"
+                      (vec (concat ["^^"] (mapcat extract coll') ["^^"]))
+                      (throw (ex-info (str "Failed to wrap Emphasis AST block of type " (pr-str type')) {})))))]
+            (cond
+              (and (vector? node) (#{"Inline_Html" "Plain"} (first node)))
+              [(second node)]
+              (and (vector? node) (#{"Break_Line" "Hard_Break_Line"} (first node)))
+              ["\n"]
+              (and (vector? node) (= (first node) "Link"))
+              [(:full_text (second node))]
+              (and (vector? node) (#{"Paragraph" "Quote"} (first node)))
+              (mapcat extract (second node))
+              (and (vector? node) (= (first node) "Tag"))
+              (into ["#"] (mapcat extract (second node)))
+              (and (vector? node) (= (first node) "Emphasis"))
+              (extract-emphasis (second node))
+              :else
+              (do
+                (log-fn :ast->text "Ignored ast node" :node node)
+                []))))]
+    (->> (extract ast-block)
+        ;;  ((fn [x] (prn :X x) x))
+         (apply str)
+         string/trim)))
+
 (defn- handle-quote-in-block
-  [block]
-  ;; TODO: Use :block.temp/ast-blocks when there is a fn to convert them to text that user sees
-  (if-let [quote' (some->> (second (re-find #"(?s)#\+BEGIN_QUOTE(.*)#\+END_QUOTE" (:block/title block))) string/trim)]
+  "If a block contains a quote, convert block to #Quote node"
+  [block opts]
+  (if-let [ast-block (first (filter #(= "Quote" (first %)) (:block.temp/ast-blocks block)))]
     (merge block
-           {:block/title quote'
+           {:block/title (ast->text ast-block opts)
             :logseq.property.node/display-type :quote
             :block/tags [:logseq.class/Quote-block]})
     block))
@@ -1003,7 +1045,7 @@
                    (fix-block-name-lookup-ref page-names-to-uuids)
                    (update-block-refs page-names-to-uuids options)
                    (update-block-tags db (:user-options options) per-file-state (:all-idents import-state))
-                   handle-quote-in-block
+                   (handle-quote-in-block (select-keys options [:log-fn]))
                    (update-block-marker options)
                    (update-block-priority options)
                    add-missing-timestamps

+ 7 - 4
deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs

@@ -212,7 +212,7 @@
       (is (= 4 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Task]] @conn))))
       (is (= 4 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Query]] @conn))))
       (is (= 2 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Card]] @conn))))
-      (is (= 1 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Quote-block]] @conn))))
+      (is (= 3 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Quote-block]] @conn))))
 
       ;; Properties and tags aren't included in this count as they aren't a Page
       (is (= 10
@@ -421,9 +421,12 @@
       (is (= {:block/tags [:logseq.class/Quote-block]
               :logseq.property.node/display-type :quote}
              (db-test/readable-properties (db-test/find-block-by-content @conn #"Saito"))))
-      (is (= "Saito: Cobb? Impossible. We were young men together. I'm an old man.\n...\nCobb: I've come back for you... to remind you of something. Something you once knew..."
-             (:block/title (db-test/find-block-by-content @conn #"Saito")))
-          "Quote node imports full multi-line quote"))
+      (is (= "markdown quote\n[[wut]]\nline 3"
+             (:block/title (db-test/find-block-by-content @conn #"markdown quote")))
+          "Markdown quote imports as full multi-line quote")
+      (is (= "*Italic* ~~Strikethrough~~ ^^Highlight^^ #[[foo]]\n**Learn Datalog Today** is an interactive tutorial designed to teach you the [Datomic](http://datomic.com/) dialect of [Datalog](http://en.wikipedia.org/wiki/Datalog). Datalog is a declarative **database query language** with roots in logic programming. Datalog has similar expressive power as [SQL](http://en.wikipedia.org/wiki/Sql)."
+             (:block/title (db-test/find-block-by-content @conn #"Learn Datalog")))
+          "Imports full quote with various ast types"))
 
     (testing "tags convert to classes"
       (is (= :user.class/Quotes___life

+ 8 - 0
deps/graph-parser/test/resources/exporter-test-graph/journals/2025_06_12.md

@@ -8,4 +8,12 @@
   Saito: Cobb? Impossible. We were young men together. I'm an old man.
   ...
   Cobb: I've come back for you... to remind you of something. Something you once knew...
+  #+END_QUOTE
+- > markdown quote
+  [[wut]]
+  line 3
+- Test of various ast types:
+  #+BEGIN_QUOTE
+  *Italic* ~~Strikethrough~~ ^^Highlight^^ #[[foo]]
+  **Learn Datalog Today** is an interactive tutorial designed to teach you the [Datomic](http://datomic.com/) dialect of [Datalog](http://en.wikipedia.org/wiki/Datalog). Datalog is a declarative **database query language** with roots in logic programming. Datalog has similar expressive power as [SQL](http://en.wikipedia.org/wiki/Sql).
   #+END_QUOTE