浏览代码

fix: fs/write-file! is only for plain-text files

Tienson Qin 5 月之前
父节点
当前提交
4c298f9ae7
共有 2 个文件被更改,包括 147 次插入149 次删除
  1. 1 2
      src/main/frontend/fs.cljs
  2. 146 147
      src/main/frontend/handler/editor.cljs

+ 1 - 2
src/main/frontend/fs.cljs

@@ -90,6 +90,7 @@
 
 ;; TODO(andelf): distinguish from graph file writing and global file write
 (defn write-file!
+  "Use it only for plain-text files, not binary"
   [repo dir rpath content opts]
   (when content
     (let [path (gp-util/path-normalize rpath)
@@ -171,8 +172,6 @@
        (mkdir-if-not-exists new-dir)
        (protocol/copy! (get-fs old-path) repo old-path new-path)))))
 
-
-
 (defn open-dir
   [dir]
   (let [record (get-native-backend)]

+ 146 - 147
src/main/frontend/handler/editor.cljs

@@ -60,7 +60,8 @@
             [logseq.graph-parser.util.page-ref :as page-ref]
             [promesa.core :as p]
             [rum.core :as rum]
-            [frontend.fs.capacitor-fs :as capacitor-fs]))
+            [frontend.fs.capacitor-fs :as capacitor-fs]
+            [electron.ipc :as ipc]))
 
 ;; FIXME: should support multiple images concurrently uploading
 
@@ -447,11 +448,11 @@
     (outliner-tx/transact!
      {:outliner-op :insert-blocks}
      (save-current-block! {:current-block current-block})
-      (outliner-core/insert-blocks! [new-block] current-block
-        {:sibling?              sibling?
-         :keep-uuid?            keep-uuid?
-         :replace-empty-target? replace-empty-target?
-         :ordered-list? ordered-list?}))))
+     (outliner-core/insert-blocks! [new-block] current-block
+                                   {:sibling?              sibling?
+                                    :keep-uuid?            keep-uuid?
+                                    :replace-empty-target? replace-empty-target?
+                                    :ordered-list? ordered-list?}))))
 
 (defn- block-self-alone-when-insert?
   [config uuid]
@@ -630,10 +631,10 @@
                                    nil)]
           (when block-m
             (outliner-insert-block! {} block-m new-block
-              {:sibling?              sibling?
-               :keep-uuid?            true
-               :replace-empty-target? replace-empty-target?
-               :ordered-list? ordered-list?})
+                                    {:sibling?              sibling?
+                                     :keep-uuid?            true
+                                     :replace-empty-target? replace-empty-target?
+                                     :ordered-list? ordered-list?})
             (when edit-block?
               (if (and replace-empty-target?
                        (string/blank? (:block/content last-block)))
@@ -748,10 +749,10 @@
                                      (uuid id)) blocks))
                    (remove nil?))]
       (outliner-tx/transact! {:outliner-op :cycle-todos}
-        (doseq [id ids]
-          (let [block (db/pull [:block/uuid id])]
-            (when (not-empty (:block/content block))
-              (set-marker block))))))))
+                             (doseq [id ids]
+                               (let [block (db/pull [:block/uuid id])]
+                                 (when (not-empty (:block/content block))
+                                   (set-marker block))))))))
 
 (defn cycle-todo!
   []
@@ -851,9 +852,9 @@
                        concat-prev-block? (boolean (and prev-block new-content))
                        transact-opts (cond->
                                       {:outliner-op :delete-blocks}
-                                      concat-prev-block?
-                                      (assoc :concat-data
-                                             {:last-edit-block (:block/uuid block)}))]
+                                       concat-prev-block?
+                                       (assoc :concat-data
+                                              {:last-edit-block (:block/uuid block)}))]
                    (outliner-tx/transact! transact-opts
                                           (if concat-prev-block?
                                             (let [prev-block' (if (seq (:block/_refs block-e))
@@ -1082,8 +1083,8 @@
   (when-let [blocks (seq (get-selected-blocks))]
     ;; remove embeds, references and queries
     (let [dom-blocks (remove (fn [block]
-                              (or (= "true" (dom/attr block "data-transclude"))
-                                  (= "true" (dom/attr block "data-query")))) blocks)
+                               (or (= "true" (dom/attr block "data-transclude"))
+                                   (= "true" (dom/attr block "data-query")))) blocks)
           dom-blocks (if (seq dom-blocks) dom-blocks
                          (remove (fn [block]
                                    (= "true" (dom/attr block "data-transclude"))) blocks))]
@@ -1437,17 +1438,18 @@
             dir (or (:dir matched-alias) repo-dir)]
 
         (p/do! (js/console.debug "Debug: Writing Asset #" dir file-rpath)
-          (if (mobile-util/native-platform?)
+               (if (mobile-util/native-platform?)
             ;; capacitor fs accepts Blob, File implements Blob
-            (p/let [buffer (.arrayBuffer file)
-                    content (base64/encodeByteArray (js/Uint8Array. buffer))
-                    fpath (path/path-join dir file-rpath)]
-              (capacitor-fs/<write-file-with-base64 fpath content))
-            (p/let [content (if (util/electron?)
-                              (.arrayBuffer file)
-                              (.stream file))]
-              (fs/write-file! repo dir file-rpath content nil)))
-          [file-rpath file (path/path-join dir file-rpath) matched-alias]))))))
+                 (p/let [buffer (.arrayBuffer file)
+                         content (base64/encodeByteArray (js/Uint8Array. buffer))
+                         fpath (path/path-join dir file-rpath)]
+                   (capacitor-fs/<write-file-with-base64 fpath content))
+                 (p/let [content (if (util/electron?)
+                                   (.arrayBuffer file)
+                                   (.stream file))
+                         file-fpath (path/path-join dir file-rpath)]
+                   (ipc/ipc "writeFile" repo file-fpath content)))
+               [file-rpath file (path/path-join dir file-rpath) matched-alias]))))))
 
 (defonce *assets-url-cache (atom {}))
 
@@ -1538,13 +1540,13 @@
                  (insert-command!
                   id
                   (assets-handler/get-asset-file-link format
-                                       (if matched-alias
-                                         (str
-                                          (if image? "../assets/" "")
-                                          "@" (:name matched-alias) "/" asset-file-name)
-                                         (resolve-relative-path (or asset-file-fpath asset-file-name)))
-                                       (if file-obj (.-name file-obj) (if image? "image" "asset"))
-                                       image?)
+                                                      (if matched-alias
+                                                        (str
+                                                         (if image? "../assets/" "")
+                                                         "@" (:name matched-alias) "/" asset-file-name)
+                                                        (resolve-relative-path (or asset-file-fpath asset-file-name)))
+                                                      (if file-obj (.-name file-obj) (if image? "image" "asset"))
+                                                      image?)
                   format
                   {:last-pattern (if drop-or-paste? "" commands/command-trigger)
                    :restore?     true
@@ -1977,8 +1979,8 @@
           (:block/content block))
         new-content
         (cond->> new-content
-             (not keep-uuid?) (property/remove-property format "id")
-             true             (property/remove-property format "custom_id"))]
+          (not keep-uuid?) (property/remove-property format "id")
+          true             (property/remove-property format "custom_id"))]
     (merge (apply dissoc block (conj (when-not keep-uuid? [:block/_refs]) :block/pre-block? :block/meta))
            {:block/page {:db/id (:db/id page)}
             :block/format format
@@ -2031,7 +2033,7 @@
         page (if (:block/name block) block
                  (when target-block (:block/page (db/entity (:db/id target-block)))))
         empty-target? (if (true? skip-empty-target?) false
-                        (string/blank? (:block/content target-block)))
+                          (string/blank? (:block/content target-block)))
         paste-nested-blocks? (nested-blocks blocks)
         target-block-has-children? (db/has-children? (:block/uuid target-block))
         replace-empty-target? (and empty-target?
@@ -2056,23 +2058,23 @@
 
     (when has-unsaved-edits
       (outliner-tx/transact!
-        {:outliner-op :save-block}
-        (outliner-core/save-block! editing-block)))
+       {:outliner-op :save-block}
+       (outliner-core/save-block! editing-block)))
 
     (outliner-tx/transact!
-      {:outliner-op :insert-blocks
-       :additional-tx revert-cut-txs}
-      (when target-block'
-        (let [format (or (:block/format target-block') (state/get-preferred-format))
-              blocks' (map (fn [block]
-                             (paste-block-cleanup block page exclude-properties format content-update-fn keep-uuid?))
-                        blocks)
-              result (outliner-core/insert-blocks! blocks' target-block' {:sibling? sibling?
-                                                                          :outliner-op :paste
-                                                                          :replace-empty-target? replace-empty-target?
-                                                                          :keep-uuid? keep-uuid?})]
-          (state/set-block-op-type! nil)
-          (edit-last-block-after-inserted! result)))))
+     {:outliner-op :insert-blocks
+      :additional-tx revert-cut-txs}
+     (when target-block'
+       (let [format (or (:block/format target-block') (state/get-preferred-format))
+             blocks' (map (fn [block]
+                            (paste-block-cleanup block page exclude-properties format content-update-fn keep-uuid?))
+                          blocks)
+             result (outliner-core/insert-blocks! blocks' target-block' {:sibling? sibling?
+                                                                         :outliner-op :paste
+                                                                         :replace-empty-target? replace-empty-target?
+                                                                         :keep-uuid? keep-uuid?})]
+         (state/set-block-op-type! nil)
+         (edit-last-block-after-inserted! result)))))
   (state/set-editor-op! nil))
 
 (defn- block-tree->blocks
@@ -2115,10 +2117,10 @@
    A block element: {:content :properties :children [block-1, block-2, ...]}"
   [target-block-id sibling? tree-vec format keep-uuid?]
   (insert-block-tree tree-vec format
-    {:target-block       (db/pull target-block-id)
-     :keep-uuid?         keep-uuid?
-     :skip-empty-target? true
-     :sibling?           sibling?}))
+                     {:target-block       (db/pull target-block-id)
+                      :keep-uuid?         keep-uuid?
+                      :skip-empty-target? true
+                      :sibling?           sibling?}))
 
 (defn insert-template!
   ([element-id db-id]
@@ -2509,7 +2511,7 @@
             (profile
              "Insert block"
              (outliner-tx/transact! {:outliner-op :insert-blocks}
-               (insert-new-block! state)))))))))
+                                    (insert-new-block! state)))))))))
 
 (defn- inside-of-single-block
   "When we are in a single block wrapper, we should always insert a new line instead of new block"
@@ -2694,8 +2696,8 @@
                                  :block.temp/additional-properties (dissoc (:block/properties next-block) :block/uuid))
                           edit-block)]
         (outliner-tx/transact! transact-opts
-          (delete-block-aux! next-block false)
-          (save-block! repo edit-block' new-content {:editor/op :delete}))
+                               (delete-block-aux! next-block false)
+                               (save-block! repo edit-block' new-content {:editor/op :delete}))
         (let [block (if next-block-has-refs? next-block edit-block)]
           (edit-block! block current-pos (:block/uuid block)))))))
 
@@ -2721,7 +2723,7 @@
 
         :else
         (delete-and-update
-          input current-pos (util/safe-inc-current-pos-from-start (.-value input) current-pos))))))
+         input current-pos (util/safe-inc-current-pos-from-start (.-value input) current-pos))))))
 
 (defn keydown-backspace-handler
   [cut? e]
@@ -2824,10 +2826,9 @@
         :real-outliner-op :indent-outdent}
        (outliner-core/indent-outdent-blocks! [block] indent?))
       (edit-block!
-        (db/pull (:db/id block))
-        (cursor/pos (state/get-input))
-        (:block/uuid block))
-    )
+       (db/pull (:db/id block))
+       (cursor/pos (state/get-input))
+       (:block/uuid block)))
     (state/set-editor-op! :nil)))
 
 (defn keydown-tab-handler
@@ -2968,55 +2969,55 @@
         (commands/handle-step [:editor/search-page])
         (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}))
       (when (and (not editor-action) (not non-enter-processed?))
-       (cond
+        (cond
          ;; When you type text inside square brackets
-         (and (not (contains? #{"ArrowDown" "ArrowLeft" "ArrowRight" "ArrowUp" "Escape"} k))
-              (wrapped-by? input page-ref/left-brackets page-ref/right-brackets))
-         (let [orig-pos (cursor/get-caret-pos input)
-               value (gobj/get input "value")
-               square-pos (string/last-index-of (subs value 0 (:pos orig-pos)) page-ref/left-brackets)
-               pos (+ square-pos 2)
-               _ (state/set-editor-last-pos! pos)
-               pos (assoc orig-pos :pos pos)
-               command-step (if (= \# (util/nth-safe value (dec square-pos)))
-                              :editor/search-page-hashtag
-                              :editor/search-page)]
-           (commands/handle-step [command-step])
-           (state/set-editor-action-data! {:pos pos}))
+          (and (not (contains? #{"ArrowDown" "ArrowLeft" "ArrowRight" "ArrowUp" "Escape"} k))
+               (wrapped-by? input page-ref/left-brackets page-ref/right-brackets))
+          (let [orig-pos (cursor/get-caret-pos input)
+                value (gobj/get input "value")
+                square-pos (string/last-index-of (subs value 0 (:pos orig-pos)) page-ref/left-brackets)
+                pos (+ square-pos 2)
+                _ (state/set-editor-last-pos! pos)
+                pos (assoc orig-pos :pos pos)
+                command-step (if (= \# (util/nth-safe value (dec square-pos)))
+                               :editor/search-page-hashtag
+                               :editor/search-page)]
+            (commands/handle-step [command-step])
+            (state/set-editor-action-data! {:pos pos}))
 
          ;; Handle non-ascii square brackets
-         (and (input-page-ref? k current-pos blank-selected? last-key-code)
-              (not (wrapped-by? input page-ref/left-brackets page-ref/right-brackets)))
-         (do
-           (commands/handle-step [:editor/input page-ref/left-and-right-brackets {:backward-truncate-number 2
-                                                                                  :backward-pos 2}])
-           (commands/handle-step [:editor/search-page])
-           (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}))
+          (and (input-page-ref? k current-pos blank-selected? last-key-code)
+               (not (wrapped-by? input page-ref/left-brackets page-ref/right-brackets)))
+          (do
+            (commands/handle-step [:editor/input page-ref/left-and-right-brackets {:backward-truncate-number 2
+                                                                                   :backward-pos 2}])
+            (commands/handle-step [:editor/search-page])
+            (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}))
 
          ;; Handle non-ascii parentheses
-         (and blank-selected?
-              (contains? keycode/left-paren-keys k)
-              (= (:key last-key-code) k)
-              (> current-pos 0)
-              (not (wrapped-by? input block-ref/left-parens block-ref/right-parens)))
-         (do
-           (commands/handle-step [:editor/input block-ref/left-and-right-parens {:backward-truncate-number 2
-                                                                                 :backward-pos 2}])
-           (commands/handle-step [:editor/search-block :reference])
-           (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}))
+          (and blank-selected?
+               (contains? keycode/left-paren-keys k)
+               (= (:key last-key-code) k)
+               (> current-pos 0)
+               (not (wrapped-by? input block-ref/left-parens block-ref/right-parens)))
+          (do
+            (commands/handle-step [:editor/input block-ref/left-and-right-parens {:backward-truncate-number 2
+                                                                                  :backward-pos 2}])
+            (commands/handle-step [:editor/search-block :reference])
+            (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}))
 
          ;; Handle non-ascii angle brackets
-         (and (= "〈" c)
-              (= "《" (util/nth-safe (gobj/get input "value") (dec (dec current-pos))))
-              (> current-pos 0))
-         (do
-           (commands/handle-step [:editor/input commands/angle-bracket {:last-pattern "《〈"
-                                                                        :backward-pos 0}])
-           (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)})
-           (state/set-editor-show-block-commands!))
-
-         :else
-         nil)))))
+          (and (= "〈" c)
+               (= "《" (util/nth-safe (gobj/get input "value") (dec (dec current-pos))))
+               (> current-pos 0))
+          (do
+            (commands/handle-step [:editor/input commands/angle-bracket {:last-pattern "《〈"
+                                                                         :backward-pos 0}])
+            (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)})
+            (state/set-editor-show-block-commands!))
+
+          :else
+          nil)))))
 
 (defn keyup-handler
   [_state input input-id]
@@ -3146,8 +3147,8 @@
   (when-let [current-block (state/get-edit-block)]
     (when-let [block-id (:block/uuid current-block)]
       (if (= format "embed")
-       (copy-block-ref! block-id #(str "{{embed ((" % "))}}"))
-       (copy-block-ref! block-id block-ref/->block-ref)))))
+        (copy-block-ref! block-id #(str "{{embed ((" % "))}}"))
+        (copy-block-ref! block-id block-ref/->block-ref)))))
 
 (defn copy-current-block-embed []
   (copy-current-block-ref "embed"))
@@ -3277,9 +3278,9 @@
           ;; if the move is to cross block boundary, select the whole block
          (or (and (= direction :up) (cursor/textarea-cursor-rect-first-row? cursor-rect))
              (and (= direction :down) (cursor/textarea-cursor-rect-last-row? cursor-rect)))
-         (select-block-up-down direction)
+          (select-block-up-down direction)
           ;; simulate text selection
-         (cursor/select-up-down input direction anchor cursor-rect)))
+          (cursor/select-up-down input direction anchor cursor-rect)))
       (select-block-up-down direction))))
 
 (defn open-selected-block!
@@ -3300,8 +3301,8 @@
                          (string/replace "ls-block" "edit-block"))
             left?    (= direction :left)]
         (edit-block! block
-                    (if left? 0 :max)
-                    block-id)))))
+                     (if left? 0 :max)
+                     block-id)))))
 
 (defn shortcut-left-right [direction]
   (fn [e]
@@ -3357,8 +3358,6 @@
     (util/forward-kill-word input)
     (state/set-edit-content! (state/get-edit-input-id) (.-value input))))
 
-
-
 (defn block-with-title?
   [format content semantic?]
   (and (string/includes? content "\n")
@@ -3488,14 +3487,14 @@
     (when repo
       (save-current-block!) ;; Save the input contents before collapsing
       (outliner-tx/transact! ;; Save the new collapsed state as an undo transaction (if it changed)
-        {:outliner-op :collapse-expand-blocks}
-        (doseq [block-id block-ids]
-          (when-let [block (db/entity [:block/uuid block-id])]
-            (let [current-value (boolean (:block/collapsed? block))]
-              (when-not (= current-value value)
-                (let [block {:block/uuid block-id
-                             :block/collapsed? value}]
-                  (outliner-core/save-block! block)))))))
+       {:outliner-op :collapse-expand-blocks}
+       (doseq [block-id block-ids]
+         (when-let [block (db/entity [:block/uuid block-id])]
+           (let [current-value (boolean (:block/collapsed? block))]
+             (when-not (= current-value value)
+               (let [block {:block/uuid block-id
+                            :block/collapsed? value}]
+                 (outliner-core/save-block! block)))))))
       (doseq [block-id block-ids]
         (state/set-collapsed-block! block-id value)))))
 
@@ -3587,39 +3586,39 @@
 (defn toggle-collapse!
   ([e] (toggle-collapse! e false))
   ([e clear-selection?]
-    (when e (util/stop e))
-    (cond
-      (state/editing?)
-      (when-let [block (state/get-edit-block)]
+   (when e (util/stop e))
+   (cond
+     (state/editing?)
+     (when-let [block (state/get-edit-block)]
         ;; get-edit-block doesn't track the latest collapsed state, so we need to reload from db.
-        (let [block-id (:block/uuid block)
-              block (db/pull [:block/uuid block-id])]
-          (if (:block/collapsed? block)
-            (expand! e clear-selection?)
-            (collapse! e clear-selection?))))
+       (let [block-id (:block/uuid block)
+             block (db/pull [:block/uuid block-id])]
+         (if (:block/collapsed? block)
+           (expand! e clear-selection?)
+           (collapse! e clear-selection?))))
 
-      (state/selection?)
-      (do
-        (let [block-ids (map #(-> % (dom/attr "blockid") uuid) (get-selected-blocks))
-              first-block-id (first block-ids)]
-          (when first-block-id
+     (state/selection?)
+     (do
+       (let [block-ids (map #(-> % (dom/attr "blockid") uuid) (get-selected-blocks))
+             first-block-id (first block-ids)]
+         (when first-block-id
             ;; If multiple blocks are selected, they may not have all the same collapsed state.
             ;; For simplicity, use the first block's state to decide whether to collapse/expand all.
-            (let [first-block (db/pull [:block/uuid first-block-id])]
-              (if (:block/collapsed? first-block)
-                (doseq [block-id block-ids] (expand-block! block-id))
-                (doseq [block-id block-ids] (collapse-block! block-id))))))
-        (and clear-selection? (clear-selection!)))
+           (let [first-block (db/pull [:block/uuid first-block-id])]
+             (if (:block/collapsed? first-block)
+               (doseq [block-id block-ids] (expand-block! block-id))
+               (doseq [block-id block-ids] (collapse-block! block-id))))))
+       (and clear-selection? (clear-selection!)))
 
-      (whiteboard?)
+     (whiteboard?)
       ;; TODO: Looks like detecting the whiteboard selection's collapse state will take more work.
       ;; Leaving unimplemented for now.
-      nil
+     nil
 
-      :else
+     :else
       ;; If no block is being edited or selected, the "toggle" action doesn't make sense,
       ;; so we no-op here, unlike in the expand! & collapse! functions.
-      nil)))
+     nil)))
 
 (defn collapse-all!
   ([]