diff --git a/.gitignore b/.gitignore index b79ff1f693..2514f5d3dc 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ node_modules/ /resources/static/js/publishing/main.js /resources/static/js/publishing/cljs-runtime /resources/static/js/publishing/manifest.edn +/resources/static/js/code-editor.js /resources/static/style.css tauri-release/ diff --git a/web/src/main/frontend/components/file.cljs b/web/src/main/frontend/components/file.cljs index 6d63d2775b..ede156cf4d 100644 --- a/web/src/main/frontend/components/file.cljs +++ b/web/src/main/frontend/components/file.cljs @@ -106,17 +106,24 @@ (when (and config? (state/logged?)) [:a.mb-8.block {:on-click (fn [_e] (project/sync-project-settings!))} (tongue :project/sync-settings)]) - (cond ;; image type (and format (contains? (config/img-formats) format)) [:img {:src path}] + (and format (contains? config/markup-formats format)) + (when-let [file-content (db/get-file path)] + (let [content (string/trim file-content)] + (content/content path {:config {:file? true + :file-path path} + :content content + :format format}))) + (and format (contains? (config/text-formats) format)) (when-let [file-content (db/get-file path)] (let [content (string/trim file-content)] (lazy-editor/editor {:file? true - :file-path path} path nil content))) + :file-path path} path nil content nil))) :else [:div (tongue :file/format-not-supported (name format))])]))) diff --git a/web/src/main/frontend/components/hiccup.cljs b/web/src/main/frontend/components/hiccup.cljs index babcde1eea..b7425d16b7 100644 --- a/web/src/main/frontend/components/hiccup.cljs +++ b/web/src/main/frontend/components/hiccup.cljs @@ -1451,7 +1451,7 @@ [:pre.pre-wrap-white-space (join-lines l)] ["Src" options] - (let [{:keys [language options lines]} options + (let [{:keys [language options lines pos_meta]} options attr (if language {:data-lang language}) code (join-lines lines)] @@ -1459,13 +1459,11 @@ html-export? (highlight/html-export attr code) - (and (= language "clojure") (contains? (set options) ":results")) - [:div - (lazy-editor/editor config (str (dc/squuid)) attr code) - (sci/eval-result code)] - :else - (lazy-editor/editor config (str (dc/squuid)) attr code))) + [:div + (lazy-editor/editor config (str (dc/squuid)) attr code pos_meta) + (when (and (= language "clojure") (contains? (set options) ":results")) + (sci/eval-result code))])) ["Quote" l] (->elem :blockquote diff --git a/web/src/main/frontend/components/lazy_editor.cljs b/web/src/main/frontend/components/lazy_editor.cljs index bc8851397a..94b244830e 100644 --- a/web/src/main/frontend/components/lazy_editor.cljs +++ b/web/src/main/frontend/components/lazy_editor.cljs @@ -13,8 +13,8 @@ (fn [] (reset! loaded? true))) state)} - [config id attr code] + [config id attr code pos_meta] (let [loaded? (rum/react loaded?)] (if loaded? - (@lazy-editor config id attr code) - (ui/loading "CodeMirror")))) + (@lazy-editor config id attr code pos_meta) + (ui/loading "CodeMirror")))) diff --git a/web/src/main/frontend/config.cljs b/web/src/main/frontend/config.cljs index 346a2e7d07..1fe5a82208 100644 --- a/web/src/main/frontend/config.cljs +++ b/web/src/main/frontend/config.cljs @@ -56,6 +56,9 @@ #{:json :org :md :yml :dat :asciidoc :rst :txt :markdown :adoc :html :js :ts :edn :clj :ml :rb :ex :erl :java :php :c :css :excalidraw}))) +(def markup-formats + #{:org :md :markdown :asciidoc :rst}) + (defn img-formats [] (let [config-formats (some->> (get-in @state/state [:config :image-formats]) @@ -227,6 +230,18 @@ (let [block-pattern (get-block-pattern format)] (apply str (repeat n block-pattern))))) +(defn with-code-wrapper + [format mode code] + (let [mode (if-not (string/blank? mode) + (str mode " ") + "")] + (case format + :markdown + (util/format "```%s\n%s\n```" mode code) + :org + (util/format "#+BEGIN_SRC%s\n%s\n#+END_SRC" mode code) + code))) + (defonce default-journals-directory "journals") (defonce default-pages-directory "pages") (defonce default-draw-directory "draws") diff --git a/web/src/main/frontend/extensions/code.cljs b/web/src/main/frontend/extensions/code.cljs index 8d3df45ee2..9e1508a97a 100644 --- a/web/src/main/frontend/extensions/code.cljs +++ b/web/src/main/frontend/extensions/code.cljs @@ -10,6 +10,7 @@ [frontend.handler.editor :as editor-handler] [frontend.handler.file :as file-handler] [clojure.string :as string] + [frontend.utf8 :as utf8] ["codemirror" :as cm] ["codemirror/addon/edit/matchbrackets"] ["codemirror/addon/edit/closebrackets"] @@ -45,8 +46,9 @@ (defn render! [state] - (let [[config id attr] (:rum/args state) - mode (get attr :data-lang "javascript") + (let [[config id attr code pos_meta] (:rum/args state) + original-mode (get attr :data-lang) + mode (or original-mode "javascript") clojure? (contains? #{"clojure" "clj"} mode) mode (if clojure? "clojure" mode) lisp? (contains? #{"clojure" "scheme" "racket" "lisp"} mode) @@ -64,10 +66,19 @@ (cond (:block/uuid config) (let [block (db/pull [:block/uuid (:block/uuid config)]) + format (:block/format block) + ;; Get newest state + pos-meta (::pos-meta state) + {:keys [start_pos end_pos]} @pos-meta + value (str (string/trimr value) "\n") content (:block/content block) - ;; FIXME: what if there're multiple same code blocks in the same block - ;; and we're editing the second code block instead of the first one? - content' (string/replace-first content default-value value)] + content' (utf8/insert! content + start_pos + end_pos + value)] + (reset! pos-meta {:start_pos start_pos + :end_pos (+ start_pos + (utf8/length (utf8/encode value)))}) (editor-handler/save-block-if-changed! block content')) (:file-path config) @@ -89,16 +100,26 @@ (.save editor) (.refresh editor) (when clojure? - (par-cm/init editor)))) + (par-cm/init editor)) + editor)) (defn- load-and-render! [state] - (render! state) - state) + (let [editor (render! state)] + (assoc state ::editor editor))) (rum/defcs editor < rum/reactive - {:did-mount load-and-render!} - [state config id attr code] + {:init (fn [state] + (assoc state ::pos-meta (atom (last (:rum/args state))))) + :did-mount (fn [state] + (load-and-render! state)) + :did-update (fn [state] + (when-let [editor (::editor state)] + (let [code (nth (:rum/args state) 3)] + (.setValue (.getDoc editor) code))) + (when-let [pos-meta (::pos-meta state)] + (reset! pos-meta (last (:rum/args state)))))} + [state config id attr code pos_meta] [:div.relative.fixed-width [:div.absolute.top-0.right-0.p-1.text-sm.text-gray-500 {:style {:z-index 1000 diff --git a/web/src/main/frontend/format/block.cljs b/web/src/main/frontend/format/block.cljs index 2269520472..8cdc36ce02 100644 --- a/web/src/main/frontend/format/block.cljs +++ b/web/src/main/frontend/format/block.cljs @@ -149,6 +149,22 @@ [:block/uuid (medley/uuid id)]) ref-blocks))))) +(defn update-src-pos-meta! + [{:keys [body] :as block}] + (let [body (walk/postwalk + (fn [form] + (if (and (vector? form) + (= (first form) "Src") + (map? (:pos_meta (second form)))) + (let [{:keys [start_pos end_pos]} (:pos_meta (second form)) + new_start_pos (- start_pos (get-in block [:meta :start-pos]))] + ["Src" (assoc (second form) + :pos_meta {:start_pos new_start_pos + :end_pos (+ new_start_pos (- end_pos start_pos))})]) + form)) + body)] + (assoc block :body body))) + (defn block-keywordize [block] (medley/map-keys @@ -224,6 +240,7 @@ block (collect-block-tags block) block (with-page-refs block) block (with-block-refs block) + block (update-src-pos-meta! block) block-refs (into block-refs (:ref-blocks block)) last-pos' (get-in block [:meta :start-pos])] (recur block-refs (conj headings block) [] (rest blocks) {} {} last-pos' (:level block) children))