feat(copy-as/export): add option: :newline-after-block

pull/8845/head
rcmerci 2023-03-13 23:17:39 +08:00 committed by Tienson Qin
parent 2cfe943169
commit bce6174b5a
5 changed files with 137 additions and 100 deletions

View File

@ -167,7 +167,19 @@
(reset! *content (export-helper root-block-uuids-or-page-name)))}) (reset! *content (export-helper root-block-uuids-or-page-name)))})
[:div {:style {:visibility (if (#{:text :html :opml} tp) "visible" "hidden")}} [:div {:style {:visibility (if (#{:text :html :opml} tp) "visible" "hidden")}}
"remove #tags"]] "remove #tags"]
(ui/checkbox {:style {:margin-right 6
:margin-left "1em"
:visibility (if (#{:text} tp) "visible" "hidden")}
:checked (boolean (:newline-after-block @*text-other-options))
:on-change (fn [e]
(state/update-export-block-text-other-options!
:newline-after-block (boolean (util/echecked? e)))
(reset! *text-other-options (state/get-export-block-text-other-options))
(reset! *content (export-helper root-block-uuids-or-page-name)))})
[:div {:style {:visibility (if (#{:text} tp) "visible" "hidden")}}
"newline after block"]]
[:div.flex.items-center [:div.flex.items-center
[:label.mr-2 {:style {:visibility (if (#{:text :html :opml} tp) "visible" "hidden")}} [:label.mr-2 {:style {:visibility (if (#{:text :html :opml} tp) "visible" "hidden")}}

View File

@ -38,6 +38,10 @@
:block-ref-replaced? false :block-ref-replaced? false
:block&page-embed-replaced? false} :block&page-embed-replaced? false}
;; submap for :newline-after-block internal state
:newline-after-block
{:current-block-is-first-heading-block? true}
;; export-options submap ;; export-options submap
:export-options :export-options
{;; dashes, spaces, no-indent {;; dashes, spaces, no-indent
@ -45,7 +49,8 @@
:remove-page-ref-brackets? false :remove-page-ref-brackets? false
:remove-emphasis? false :remove-emphasis? false
:remove-tags? false :remove-tags? false
:keep-only-level<=N :all}}) :keep-only-level<=N :all
:newline-after-block false}})
;;; internal utils ;;; internal utils
(defn- get-blocks-contents (defn- get-blocks-contents
@ -110,6 +115,10 @@
[level & {:keys [spaces] :or {spaces " "}}] [level & {:keys [spaces] :or {spaces " "}}]
["Plain" (str (reduce str (repeat (dec level) "\t")) spaces)]) ["Plain" (str (reduce str (repeat (dec level) "\t")) spaces)])
(defn- mk-paragraph-ast
[inline-coll meta]
(with-meta ["Paragraph" inline-coll] meta))
;;; internal utils (ends) ;;; internal utils (ends)
;;; utils ;;; utils
@ -291,7 +300,7 @@
[ast-type (replace-block-reference-in-heading ast-content)] [ast-type (replace-block-reference-in-heading ast-content)]
"Paragraph" "Paragraph"
[ast-type (replace-block-reference-in-paragraph ast-content)] (mk-paragraph-ast (replace-block-reference-in-paragraph ast-content) (meta block-ast))
"List" "List"
[ast-type (replace-block-reference-in-list ast-content)] [ast-type (replace-block-reference-in-list ast-content)]
@ -382,17 +391,20 @@
(recur other-inlines heading-exist? (conj current-paragraph-inlines* inline) r))))))) (recur other-inlines heading-exist? (conj current-paragraph-inlines* inline) r)))))))
(defn- replace-block&page-embeds-in-paragraph (defn- replace-block&page-embeds-in-paragraph
[inline-coll] [inline-coll meta]
(let [current-level (get-in *state* [:replace-ref-embed :current-level])] (let [current-level (get-in *state* [:replace-ref-embed :current-level])]
(loop [[inline & other-inlines] inline-coll (loop [[inline & other-inlines] inline-coll
current-paragraph-inlines [] current-paragraph-inlines []
just-after-embed? false just-after-embed? false
blocks (transient [])] blocks (transient [])]
(if-not inline (if-not inline
(persistent! (let [[first-block & other-blocks] (persistent!
(if (seq current-paragraph-inlines) (if (seq current-paragraph-inlines)
(conj! blocks ["Paragraph" current-paragraph-inlines]) (conj! blocks ["Paragraph" current-paragraph-inlines])
blocks)) blocks))]
(if first-block
(apply vector (with-meta first-block meta) other-blocks)
[]))
(match [inline] (match [inline]
[["Macro" {:name "embed" :arguments [block-uuid-or-page-name]}]] [["Macro" {:name "embed" :arguments [block-uuid-or-page-name]}]]
(cond (cond
@ -448,7 +460,7 @@
"Heading" "Heading"
(replace-block&page-embeds-in-heading ast-content) (replace-block&page-embeds-in-heading ast-content)
"Paragraph" "Paragraph"
(replace-block&page-embeds-in-paragraph ast-content) (replace-block&page-embeds-in-paragraph ast-content (meta block-ast))
"List" "List"
(replace-block&page-embeds-in-list ast-content) (replace-block&page-embeds-in-list ast-content)
"Quote" "Quote"
@ -514,6 +526,7 @@
[[tp _]] [[tp _]]
(= tp "Properties")) (= tp "Properties"))
(defn replace-Heading-with-Paragraph (defn replace-Heading-with-Paragraph
"works on block-ast "works on block-ast
replace all heading with paragraph when indent-style is no-indent" replace all heading with paragraph when indent-style is no-indent"
@ -526,7 +539,7 @@
marker (cons ["Plain" (str marker " ")]) marker (cons ["Plain" (str marker " ")])
size (cons ["Plain" (str (reduce str (repeat size "#")) " ")]) size (cons ["Plain" (str (reduce str (repeat size "#")) " ")])
true vec)] true vec)]
["Paragraph" inline-coll]) (mk-paragraph-ast inline-coll {:origin-ast heading-ast}))
heading-ast))) heading-ast)))
(defn keep-only-level<=n (defn keep-only-level<=n
@ -625,7 +638,7 @@
(let [[ast-type ast-content] block-ast] (let [[ast-type ast-content] block-ast]
(case ast-type (case ast-type
"Paragraph" "Paragraph"
["Paragraph" (walk-block-ast-helper ast-content map-fns-on-inline-ast mapcat-fns-on-inline-ast)] (mk-paragraph-ast (walk-block-ast-helper ast-content map-fns-on-inline-ast mapcat-fns-on-inline-ast) (meta block-ast))
"Heading" "Heading"
(let [{:keys [title]} ast-content] (let [{:keys [title]} ast-content]
["Heading" ["Heading"

View File

@ -1,17 +1,17 @@
(ns frontend.handler.export.html (ns frontend.handler.export.html
"export blocks/pages as html" "export blocks/pages as html"
(:require (:require [clojure.edn :as edn]
[clojure.edn :as edn] [clojure.string :as string]
[clojure.string :as string] [clojure.zip :as z]
[clojure.zip :as z] [frontend.db :as db]
[frontend.db :as db] [frontend.handler.export.common :as common :refer [*state*]]
[frontend.handler.export.common :as common :refer [*state*]] [frontend.handler.export.zip-helper :refer [get-level goto-last
[frontend.handler.export.zip-helper :refer [get-level goto-last goto-level]] goto-level]]
[frontend.state :as state] [frontend.state :as state]
[frontend.util :as util :refer [concatv mapcatv removev]] [frontend.util :as util :refer [concatv mapcatv removev]]
[hiccups.runtime :as h] [hiccups.runtime :as h]
[logseq.graph-parser.mldoc :as gp-mldoc] [logseq.graph-parser.mldoc :as gp-mldoc]
[malli.core :as m])) [malli.core :as m]))
(def ^:private hiccup-malli-schema (def ^:private hiccup-malli-schema
[:cat :keyword [:* :any]]) [:cat :keyword [:* :any]])

View File

@ -1,20 +1,20 @@
(ns frontend.handler.export.opml (ns frontend.handler.export.opml
"export blocks/pages as opml" "export blocks/pages as opml"
(:refer-clojure :exclude [map filter mapcat concat remove newline]) (:refer-clojure :exclude [map filter mapcat concat remove newline])
(:require (:require [clojure.string :as string]
[clojure.string :as string] [clojure.zip :as z]
[clojure.zip :as z] [frontend.db :as db]
[frontend.db :as db] [frontend.extensions.zip :as zip]
[frontend.extensions.zip :as zip] [frontend.handler.export.common :as common :refer
[frontend.handler.export.common :as common :refer
[*state* raw-text simple-asts->string space]] [*state* raw-text simple-asts->string space]]
[frontend.handler.export.zip-helper :refer [get-level goto-last goto-level]] [frontend.handler.export.zip-helper :refer [get-level goto-last
[frontend.state :as state] goto-level]]
[frontend.util :as util :refer [concatv mapcatv removev]] [frontend.state :as state]
[hiccups.runtime :as h] [frontend.util :as util :refer [concatv mapcatv removev]]
[logseq.graph-parser.mldoc :as gp-mldoc] [goog.dom :as gdom]
[promesa.core :as p] [hiccups.runtime :as h]
[goog.dom :as gdom])) [logseq.graph-parser.mldoc :as gp-mldoc]
[promesa.core :as p]))
;;; *opml-state* ;;; *opml-state*
(def ^:private ^:dynamic (def ^:private ^:dynamic

View File

@ -1,21 +1,18 @@
(ns frontend.handler.export.text (ns frontend.handler.export.text
"export blocks/pages as text" "export blocks/pages as text"
(:refer-clojure :exclude [map filter mapcat concat remove newline]) (:refer-clojure :exclude [map filter mapcat concat remove newline])
(:require (:require [clojure.string :as string]
[clojure.string :as string] [frontend.db :as db]
[frontend.db :as db] [frontend.extensions.zip :as zip]
[frontend.extensions.zip :as zip] [frontend.handler.export.common :as common :refer
[frontend.handler.export.common :as common :refer [*state* indent newline* raw-text simple-ast-malli-schema
[*state* simple-asts->string space]]
simple-ast-malli-schema [frontend.state :as state]
raw-text space newline* indent simple-asts->string]] [frontend.util :as util :refer [concatv mapcatv removev]]
[frontend.state :as state] [goog.dom :as gdom]
[frontend.util :as util :refer [mapcatv concatv removev]] [logseq.graph-parser.mldoc :as gp-mldoc]
[goog.dom :as gdom] [malli.core :as m]
[logseq.graph-parser.mldoc :as gp-mldoc] [promesa.core :as p]))
[malli.core :as m]
[promesa.core :as p]))
;;; block-ast, inline-ast -> simple-ast ;;; block-ast, inline-ast -> simple-ast
@ -41,10 +38,17 @@
size* (and size [space (raw-text (reduce str (repeat size "#")))]) size* (and size [space (raw-text (reduce str (repeat size "#")))])
marker* (and marker (raw-text marker))] marker* (and marker (raw-text marker))]
(set! *state* (assoc *state* :current-level level)) (set! *state* (assoc *state* :current-level level))
(removev nil? (concatv heading* size* (let [simple-asts
[space marker* space priority* space] (removev nil? (concatv
(mapcatv inline-ast->simple-ast title) (when (and (get-in *state* [:export-options :newline-after-block])
[(newline* 1)])))) (not (get-in *state* [:newline-after-block :current-block-is-first-heading-block?])))
[(newline* 2)])
heading* size*
[space marker* space priority* space]
(mapcatv inline-ast->simple-ast title)
[(newline* 1)]))]
(set! *state* (assoc-in *state* [:newline-after-block :current-block-is-first-heading-block?] false))
simple-asts)))
(declare block-list) (declare block-list)
(defn- block-list-item (defn- block-list-item
@ -309,52 +313,60 @@
(m/=> block-ast->simple-ast [:=> [:cat [:sequential :any]] [:sequential simple-ast-malli-schema]]) (m/=> block-ast->simple-ast [:=> [:cat [:sequential :any]] [:sequential simple-ast-malli-schema]])
(defn- block-ast->simple-ast (defn- block-ast->simple-ast
[block] [block]
(removev (let [newline-after-block? (get-in *state* [:export-options :newline-after-block])]
nil? (removev
(let [[ast-type ast-content] block] nil?
(case ast-type (let [[ast-type ast-content] block]
"Paragraph" (case ast-type
(concatv (mapcatv inline-ast->simple-ast ast-content) [(newline* 1)]) "Paragraph"
"Paragraph_line" (let [{:keys [origin-ast]} (meta block)
(assert false "Paragraph_line is mldoc internal ast") current-block-is-first-heading-block? (get-in *state* [:newline-after-block :current-block-is-first-heading-block?])]
"Paragraph_Sep" (set! *state* (assoc-in *state* [:newline-after-block :current-block-is-first-heading-block?] false))
[(newline* ast-content)] (concatv
"Heading" (when (and origin-ast newline-after-block? (not current-block-is-first-heading-block?))
(block-heading ast-content) [(newline* 2)])
"List" (mapcatv inline-ast->simple-ast ast-content)
(block-list ast-content) [(newline* 1)]))
("Directive" "Results" "Property_Drawer" "Export" "CommentBlock" "Custom") "Paragraph_line"
nil (assert false "Paragraph_line is mldoc internal ast")
"Example" "Paragraph_Sep"
(block-example ast-content) [(newline* ast-content)]
"Src" "Heading"
(block-src ast-content) (block-heading ast-content)
"Quote" "List"
(block-quote ast-content) (block-list ast-content)
"Latex_Fragment" ("Directive" "Results" "Property_Drawer" "Export" "CommentBlock" "Custom")
(block-latex-fragment ast-content) nil
"Latex_Environment" "Example"
(block-latex-env (rest block)) (block-example ast-content)
"Displayed_Math" "Src"
(block-displayed-math ast-content) (block-src ast-content)
"Drawer" "Quote"
(block-drawer (rest block)) (block-quote ast-content)
"Latex_Fragment"
(block-latex-fragment ast-content)
"Latex_Environment"
(block-latex-env (rest block))
"Displayed_Math"
(block-displayed-math ast-content)
"Drawer"
(block-drawer (rest block))
;; TODO: option: toggle Property_Drawer ;; TODO: option: toggle Property_Drawer
;; "Property_Drawer" ;; "Property_Drawer"
;; (block-property-drawer ast-content) ;; (block-property-drawer ast-content)
"Footnote_Definition" "Footnote_Definition"
(block-footnote-definition (rest block)) (block-footnote-definition (rest block))
"Horizontal_Rule" "Horizontal_Rule"
block-horizontal-rule block-horizontal-rule
"Table" "Table"
(block-table ast-content) (block-table ast-content)
"Comment" "Comment"
(block-comment ast-content) (block-comment ast-content)
"Raw_Html" "Raw_Html"
(block-raw-html ast-content) (block-raw-html ast-content)
"Hiccup" "Hiccup"
(block-hiccup ast-content) (block-hiccup ast-content)
(assert false (print-str :block-ast->simple-ast ast-type "not implemented yet")))))) (assert false (print-str :block-ast->simple-ast ast-type "not implemented yet")))))))
(defn- inline-ast->simple-ast (defn- inline-ast->simple-ast
[inline] [inline]
@ -410,7 +422,6 @@
;;; block-ast, inline-ast -> simple-ast (ends) ;;; block-ast, inline-ast -> simple-ast (ends)
;;; export fns ;;; export fns
(defn- export-helper (defn- export-helper
@ -423,7 +434,8 @@
:remove-emphasis? (contains? remove-options :emphasis) :remove-emphasis? (contains? remove-options :emphasis)
:remove-page-ref-brackets? (contains? remove-options :page-ref) :remove-page-ref-brackets? (contains? remove-options :page-ref)
:remove-tags? (contains? remove-options :tag) :remove-tags? (contains? remove-options :tag)
:keep-only-level<=N (:keep-only-level<=N other-options)}})] :keep-only-level<=N (:keep-only-level<=N other-options)
:newline-after-block (:newline-after-block other-options)}})]
(let [ast (gp-mldoc/->edn content (gp-mldoc/default-config format)) (let [ast (gp-mldoc/->edn content (gp-mldoc/default-config format))
ast (mapv common/remove-block-ast-pos ast) ast (mapv common/remove-block-ast-pos ast)
ast (removev common/Properties-block-ast? ast) ast (removev common/Properties-block-ast? ast)