block.cljs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. (ns frontend.format.block
  2. "Block code needed by app but not graph-parser"
  3. (:require [clojure.string :as string]
  4. [logseq.graph-parser.block :as gp-block]
  5. [frontend.config :as config]
  6. [frontend.db :as db]
  7. [frontend.format :as format]
  8. [frontend.state :as state]
  9. [frontend.handler.notification :as notification]
  10. ["@sentry/react" :as Sentry]
  11. [logseq.graph-parser.config :as gp-config]
  12. [logseq.graph-parser.property :as gp-property]
  13. [logseq.graph-parser.mldoc :as gp-mldoc]
  14. [lambdaisland.glogi :as log]))
  15. (defn extract-blocks
  16. "Wrapper around logseq.graph-parser.block/extract-blocks that adds in system state
  17. and handles unexpected failure."
  18. [blocks content format {:keys [with-id?]
  19. :or {with-id? true}}]
  20. (try
  21. (gp-block/extract-blocks blocks content with-id? format
  22. {:user-config (state/get-config)
  23. :block-pattern (config/get-block-pattern format)
  24. :supported-formats (gp-config/supported-formats)
  25. :db (db/get-db (state/get-current-repo))
  26. :date-formatter (state/get-date-formatter)})
  27. (catch :default e
  28. (log/error :exception e)
  29. (Sentry/captureException e)
  30. (notification/show! "An unexpected error occurred during block extraction." :error)
  31. [])))
  32. (defn page-name->map
  33. "Wrapper around logseq.graph-parser.block/page-name->map that adds in db"
  34. ([original-page-name with-id?]
  35. (page-name->map original-page-name with-id? true))
  36. ([original-page-name with-id? with-timestamp?]
  37. (gp-block/page-name->map original-page-name with-id? (db/get-db (state/get-current-repo)) with-timestamp? (state/get-date-formatter))))
  38. (defn parse-block
  39. ([block]
  40. (parse-block block nil))
  41. ([{:block/keys [uuid content format] :as block} {:keys [with-id?]
  42. :or {with-id? true}}]
  43. (when-not (string/blank? content)
  44. (let [block (dissoc block :block/pre-block?)
  45. ast (format/to-edn content format nil)
  46. blocks (extract-blocks ast content format {:with-id? with-id?})
  47. new-block (first blocks)
  48. block (cond->
  49. (merge block new-block)
  50. (> (count blocks) 1)
  51. (assoc :block/warning :multiple-blocks))
  52. block (dissoc block :block/title :block/body :block/level)]
  53. (if uuid (assoc block :block/uuid uuid) block)))))
  54. (defn parse-title-and-body
  55. ([block]
  56. (when (map? block)
  57. (merge block
  58. (parse-title-and-body (:block/uuid block)
  59. (:block/format block)
  60. (:block/pre-block? block)
  61. (:block/content block)))))
  62. ([block-uuid format pre-block? content]
  63. (when-not (string/blank? content)
  64. (let [content (if pre-block? content
  65. (str (config/get-block-pattern format) " " (string/triml content)))]
  66. (if-let [result (state/get-block-ast block-uuid content)]
  67. result
  68. (let [ast (->> (format/to-edn content format (gp-mldoc/default-config format))
  69. (map first))
  70. title (when (gp-block/heading-block? (first ast))
  71. (:title (second (first ast))))
  72. body (vec (if title (rest ast) ast))
  73. body (drop-while gp-property/properties-ast? body)
  74. result (cond->
  75. (if (seq body) {:block/body body} {})
  76. title
  77. (assoc :block/title title))]
  78. (state/add-block-ast-cache! block-uuid content result)
  79. result))))))
  80. (defn macro-subs
  81. [macro-content arguments]
  82. (loop [s macro-content
  83. args arguments
  84. n 1]
  85. (if (seq args)
  86. (recur
  87. (string/replace s (str "$" n) (first args))
  88. (rest args)
  89. (inc n))
  90. s)))
  91. (defn break-line-paragraph?
  92. [[typ break-lines]]
  93. (and (= typ "Paragraph")
  94. (every? #(= % ["Break_Line"]) break-lines)))
  95. (defn trim-paragraph-special-break-lines
  96. [ast]
  97. (let [[typ paras] ast]
  98. (if (= typ "Paragraph")
  99. (let [indexed-paras (map-indexed vector paras)]
  100. [typ (->> (filter
  101. #(let [[index value] %]
  102. (not (and (> index 0)
  103. (= value ["Break_Line"])
  104. (contains? #{"Timestamp" "Macro"}
  105. (first (nth paras (dec index)))))))
  106. indexed-paras)
  107. (map #(last %)))])
  108. ast)))
  109. (defn trim-break-lines!
  110. [ast]
  111. (drop-while break-line-paragraph?
  112. (map trim-paragraph-special-break-lines ast)))