Browse Source

Merge branch 'master' into feat/custom-children-list-style

charlie 2 years ago
parent
commit
9367590d9b

+ 8 - 0
deps/common/src/logseq/common/path.cljs

@@ -309,3 +309,11 @@
                  (string/starts-with? p "/")
                  ;; is windows dir
                  (re-find #"^[a-zA-Z]:[/\\]" p)))))
+
+(defn protocol-url?
+  "Whether path `p` is a protocol URL.
+
+   This is a loose check, it only checks if there is a valid protocol prefix."
+  [p]
+  (boolean (and (re-find #"^[a-zA-Z0-9_+\-\.]{2,}:" p) ;; HACK: avoid matching windows drive
+                (not (string/includes? p " ")))))

+ 12 - 0
deps/common/test/logseq/common/path_test.cljs

@@ -45,3 +45,15 @@
     (is (false? (path/absolute? "test.md")))
     (is (false? (path/absolute? "test")))
     (is (false? (path/absolute? "D:test.md")))))
+
+(deftest protocol-url
+  (testing "protocol url"
+    (is (true? (path/protocol-url? "mailto:[email protected]")))
+    (is (true? (path/protocol-url? "https://logseq.com")))
+    (is (true? (path/protocol-url? "ftp://logseq.com")))
+    (is (true? (path/protocol-url? "file:///home/xxx/logseq/test.md")))
+    (is (true? (path/protocol-url? "assets:///home/xxx/logseq/test.md")))
+    (is (false? (path/protocol-url? "logseq/test.md")))
+    (is (false? (path/protocol-url? "test.md")))
+    (is (false? (path/protocol-url? "test")))
+    (is (false? (path/protocol-url? "D:test.md")))))

+ 3 - 0
deps/graph-parser/src/logseq/graph_parser/util.cljs

@@ -80,6 +80,9 @@
   (and (string? v) (>= (count v) 2) (= "\"" (first v) (last v))))
 
 (defn url?
+  "Test if it is a `protocol://`-style URL.
+
+   NOTE: Can not handle mailto: links, use this with caution."
   [s]
   (and (string? s)
        (try

+ 55 - 54
src/electron/electron/search.cljs

@@ -6,7 +6,8 @@
             [clojure.string :as string]
             ["electron" :refer [app]]
             [electron.logger :as logger]
-            [medley.core :as medley]))
+            [medley.core :as medley]
+            [electron.utils :as utils]))
 
 (defonce databases (atom nil))
 
@@ -28,14 +29,23 @@
   [repo]
   (get @databases (sanitize-db-name repo)))
 
+(declare delete-db!)
+
 (defn prepare
-  [^object db sql]
+  [^object db sql db-name]
   (when db
-    (.prepare db sql)))
+    (try
+      (.prepare db sql)
+      (catch :default e
+        (logger/error (str "SQLite prepare failed: " e ": " db-name))
+        ;; case 1: vtable constructor failed: blocks_fts https://github.com/logseq/logseq/issues/7467
+        (delete-db! db-name)
+        (utils/send-to-renderer "rebuildSearchIndice" {})
+        (throw e)))))
 
 (defn add-blocks-fts-triggers!
   "Table bindings of blocks tables and the blocks FTS virtual tables"
-  [db]
+  [db db-name]
   (let [triggers [;; add
                   "CREATE TRIGGER IF NOT EXISTS blocks_ad AFTER DELETE ON blocks
                   BEGIN
@@ -55,12 +65,12 @@
                       VALUES (new.id, new.uuid, new.content, new.page);
                   END;"]]
     (doseq [trigger triggers]
-      (let [stmt (prepare db trigger)]
+      (let [stmt (prepare db trigger db-name)]
         (.run ^object stmt)))))
 
 (defn add-pages-fts-triggers!
   "Table bindings of pages tables and the pages FTS virtual tables"
-  [db]
+  [db db-name]
   (let [triggers [;; add
                   "CREATE TRIGGER IF NOT EXISTS pages_ad AFTER DELETE ON pages
                   BEGIN
@@ -80,34 +90,36 @@
                       VALUES (new.id, new.uuid, new.content);
                   END;"]]
     (doseq [trigger triggers]
-      (let [stmt (prepare db trigger)]
+      (let [stmt (prepare db trigger db-name)]
         (.run ^object stmt)))))
 
 (defn create-blocks-table!
-  [db]
+  [db db-name]
   (let [stmt (prepare db "CREATE TABLE IF NOT EXISTS blocks (
                         id INTEGER PRIMARY KEY,
                         uuid TEXT NOT NULL,
                         content TEXT NOT NULL,
-                        page INTEGER)")]
+                        page INTEGER)"
+                      db-name)]
     (.run ^object stmt)))
 
 (defn create-blocks-fts-table!
-  [db]
-  (let [stmt (prepare db "CREATE VIRTUAL TABLE IF NOT EXISTS blocks_fts USING fts5(uuid, content, page)")]
+  [db db-name]
+  (let [stmt (prepare db "CREATE VIRTUAL TABLE IF NOT EXISTS blocks_fts USING fts5(uuid, content, page)" db-name)]
     (.run ^object stmt)))
 
 (defn create-pages-table!
-  [db]
+  [db db-name]
   (let [stmt (prepare db "CREATE TABLE IF NOT EXISTS pages (
                         id INTEGER PRIMARY KEY,
                         uuid TEXT NOT NULL,
-                        content TEXT NOT NULL)")]
+                        content TEXT NOT NULL)"
+                      db-name)]
     (.run ^object stmt)))
 
 (defn create-pages-fts-table!
-  [db]
-  (let [stmt (prepare db "CREATE VIRTUAL TABLE IF NOT EXISTS pages_fts USING fts5(uuid, content)")]
+  [db db-name]
+  (let [stmt (prepare db "CREATE VIRTUAL TABLE IF NOT EXISTS pages_fts USING fts5(uuid, content)" db-name)]
     (.run ^object stmt)))
 
 (defn get-search-dir
@@ -136,12 +148,12 @@
   [db-name]
   (let [[db-sanitized-name db-full-path] (get-db-full-path db-name)]
     (try (let [db (sqlite3 db-full-path nil)]
-           (create-blocks-table! db)
-           (create-blocks-fts-table! db)
-           (create-pages-table! db)
-           (create-pages-fts-table! db)
-           (add-blocks-fts-triggers! db)
-           (add-pages-fts-triggers! db)
+           (create-blocks-table! db db-name)
+           (create-blocks-fts-table! db db-name)
+           (create-pages-table! db db-name)
+           (create-pages-fts-table! db db-name)
+           (add-blocks-fts-triggers! db db-name)
+           (add-pages-fts-triggers! db db-name)
            (swap! databases assoc db-sanitized-name db))
          (catch :default e
            (logger/error (str e ": " db-name))
@@ -170,7 +182,7 @@
   (if-let [db (get-db repo)]
     ;; TODO: what if a CONFLICT on uuid
     ;; Should update all values on id conflict
-    (let [insert (prepare db "INSERT INTO pages (id, uuid, content) VALUES (@id, @uuid, @content) ON CONFLICT (id) DO UPDATE SET (uuid, content) = (@uuid, @content)")
+    (let [insert (prepare db "INSERT INTO pages (id, uuid, content) VALUES (@id, @uuid, @content) ON CONFLICT (id) DO UPDATE SET (uuid, content) = (@uuid, @content)" repo)
           insert-many (.transaction ^object db
                                     (fn [pages]
                                       (doseq [page pages]
@@ -184,7 +196,7 @@
   [repo ids]
   (when-let [db (get-db repo)]
     (let [sql (str "DELETE from pages WHERE id IN " (clj-list->sql ids))
-          stmt (prepare db sql)]
+          stmt (prepare db sql repo)]
       (.run ^object stmt))))
 
 (defn upsert-blocks!
@@ -192,7 +204,7 @@
   (if-let [db (get-db repo)]
     ;; TODO: what if a CONFLICT on uuid
     ;; Should update all values on id conflict
-    (let [insert (prepare db "INSERT INTO blocks (id, uuid, content, page) VALUES (@id, @uuid, @content, @page) ON CONFLICT (id) DO UPDATE SET (uuid, content, page) = (@uuid, @content, @page)")
+    (let [insert (prepare db "INSERT INTO blocks (id, uuid, content, page) VALUES (@id, @uuid, @content, @page) ON CONFLICT (id) DO UPDATE SET (uuid, content, page) = (@uuid, @content, @page)" repo)
           insert-many (.transaction ^object db
                                     (fn [blocks]
                                       (doseq [block blocks]
@@ -206,20 +218,13 @@
   [repo ids]
   (when-let [db (get-db repo)]
     (let [sql (str "DELETE from blocks WHERE id IN " (clj-list->sql ids))
-          stmt (prepare db sql)]
+          stmt (prepare db sql repo)]
       (.run ^object stmt))))
 
-;; (defn search-blocks-fts
-;;   [q]
-;;   (when-not (string/blank? q)
-;;     (let [stmt (prepare @database
-;;                          "select id, uuid, content from blocks_fts where content match ? ORDER BY rank")]
-;;       (js->clj (.all ^object stmt q) :keywordize-keys true))))
-
 (defn- search-blocks-aux
-  [database sql input page limit]
+  [repo database sql input page limit]
   (try
-    (let [stmt (prepare database sql)]
+    (let [stmt (prepare database sql repo)]
       (js->clj
        (if page
          (.all ^object stmt (int page) input limit)
@@ -264,12 +269,12 @@
             matched-result (->>
                             (map
                              (fn [match-input]
-                               (search-blocks-aux database match-sql match-input page limit))
+                               (search-blocks-aux repo database match-sql match-input page limit))
                              match-inputs)
                             (apply concat))]
         (->>
          (concat matched-result
-                 (search-blocks-aux database non-match-sql non-match-input page limit))
+                 (search-blocks-aux repo database non-match-sql non-match-input page limit))
          (distinct-by :rowid)
          (take limit)
          (vec))))))
@@ -299,8 +304,8 @@
                 snippet)}))
 
 (defn- search-pages-aux
-  [database sql input limit]
-  (let [stmt (prepare database sql)]
+  [repo database sql input limit]
+  (let [stmt (prepare database sql repo)]
     (try
       (doall
        (map search-pages-res-unpack (-> (.raw ^object stmt)
@@ -329,12 +334,12 @@
             matched-result (->>
                             (map
                              (fn [match-input]
-                               (search-pages-aux database match-sql match-input limit))
+                               (search-pages-aux repo database match-sql match-input limit))
                              match-inputs)
                             (apply concat))]
         (->>
          (concat matched-result
-                 (search-pages-aux database non-match-sql non-match-input limit))
+                 (search-pages-aux repo database non-match-sql non-match-input limit))
          (distinct-by :id)
          (take limit)
          (vec))))))
@@ -342,23 +347,25 @@
 (defn truncate-blocks-table!
   [repo]
   (when-let [database (get-db repo)]
-    (let [stmt (prepare database
-                        "delete from blocks;")
+    (let [stmt (prepare database "delete from blocks;" repo)
           _ (.run ^object stmt)
-          stmt (prepare database
-                        "delete from blocks_fts;")]
+          stmt (prepare database "delete from blocks_fts;" repo)]
       (.run ^object stmt))))
 
 (defn truncate-pages-table!
   [repo]
   (when-let [database (get-db repo)]
-    (let [stmt (prepare database
-                        "delete from pages;")
+    (let [stmt (prepare database "delete from pages;" repo)
           _ (.run ^object stmt)
-          stmt (prepare database
-                        "delete from pages_fts;")]
+          stmt (prepare database "delete from pages_fts;" repo)]
       (.run ^object stmt))))
 
+(defn query
+  [repo sql]
+  (when-let [database (get-db repo)]
+    (let [stmt (prepare database sql repo)]
+      (.all ^object stmt))))
+
 (defn delete-db!
   [repo]
   (when-let [database (get-db repo)]
@@ -367,9 +374,3 @@
       (logger/info "Delete search indice: " db-full-path)
       (fs/unlinkSync db-full-path)
       (swap! databases dissoc db-name))))
-
-(defn query
-  [repo sql]
-  (when-let [database (get-db repo)]
-    (let [stmt (prepare database sql)]
-      (.all ^object stmt))))

+ 6 - 0
src/main/electron/listener.cljs

@@ -17,6 +17,7 @@
             [frontend.handler.route :as route-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.user :as user]
+            [frontend.handler.search :as search-handler]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [logseq.common.path :as path]
@@ -76,6 +77,11 @@
                    (let [repo (bean/->clj data)]
                      (repo-handler/remove-repo! repo))))
 
+  (safe-api-call "rebuildSearchIndice"
+                 (fn [_data]
+                   (prn "Rebuild search indices")
+                   (search-handler/rebuild-indices!)))
+
   (safe-api-call "setGitUsernameAndEmail"
                  (fn []
                    (state/pub-event! [:modal/set-git-username-and-email])))

+ 6 - 4
src/main/frontend/components/block.cljs

@@ -998,7 +998,9 @@
 
 (defn- relative-assets-path->absolute-path
   [path]
-  (if (path/absolute? path)
+  (when (path/protocol-url? path)
+    (js/console.error "BUG: relative-assets-path->absolute-path called with protocol url" path))
+  (if (or (path/absolute? path) (path/protocol-url? path))
     path
     (.. util/node-path
         (join (config/get-repo-dir (state/get-current-repo))
@@ -1080,7 +1082,7 @@
     (not (string/includes? s "."))
     (page-reference (:html-export? config) s config label)
 
-    (gp-util/url? s)
+    (path/protocol-url? s)
     (->elem :a {:href s
                 :data-href s
                 :target "_blank"}
@@ -1102,7 +1104,7 @@
       (->elem
        :a
        (cond->
-        {:href      (str "file://" path)
+        {:href      (path/path-join "file://" path)
          :data-href path
          :target    "_blank"}
          title
@@ -1184,7 +1186,7 @@
                               href)]
                   (->elem
                    :a
-                   (cond-> {:href      (str "file://" href*)
+                   (cond-> {:href      (path/path-join "file://" href*)
                             :data-href href*
                             :target    "_blank"}
                      title (assoc :title title))

+ 22 - 4
src/main/frontend/components/plugins.cljs

@@ -23,6 +23,12 @@
 (declare open-waiting-updates-modal!)
 (defonce PER-PAGE-SIZE 15)
 
+(def *dirties-toggle-items (atom {}))
+
+(defn- clear-dirties-states!
+  []
+  (reset! *dirties-toggle-items {}))
+
 (rum/defcs installed-themes
   <
   (rum/local [] ::themes)
@@ -272,7 +278,9 @@
 
     (ui/toggle (not disabled?)
                (fn []
-                 (js-invoke js/LSPluginCore (if disabled? "enable" "disable") id))
+                 (js-invoke js/LSPluginCore (if disabled? "enable" "disable") id)
+                 (when (nil? (get @*dirties-toggle-items (keyword id)))
+                   (swap! *dirties-toggle-items assoc (keyword id) (not disabled?))))
                true)]])
 
 (defn get-open-plugin-readme-handler
@@ -796,11 +804,15 @@
                                 filtered-plugins)
         sorted-plugins        (if default-filter-by?
                                 (->> filtered-plugins
-                                     (reduce #(let [k (if (get-in %2 [:settings :disabled]) 1 0)]
+                                     (reduce #(let [disabled? (get-in %2 [:settings :disabled])
+                                                    old-dirty (get @*dirties-toggle-items (keyword (:id %2)))
+                                                    k         (if (if (boolean? old-dirty) (not old-dirty) disabled?) 1 0)]
                                                 (update %1 k conj %2)) [[] []])
                                      (#(update % 0 (fn [coll] (sort-by :iir coll))))
                                      (flatten))
-                                filtered-plugins)
+                                (do
+                                  (clear-dirties-states!)
+                                  filtered-plugins))
 
         fn-query-flag         (fn [] (string/join "_" (map #(str @%) [*filter-by *sort-by *search-key *category])))
         str-query-flag        (fn-query-flag)
@@ -1120,9 +1132,15 @@
         *el-ref (rum/create-ref)]
 
     (rum/use-effect!
-      #(state/load-app-user-cfgs)
+      (fn []
+        (state/load-app-user-cfgs)
+        #(clear-dirties-states!))
       [])
 
+    (rum/use-effect!
+      #(clear-dirties-states!)
+      [market?])
+
     [:div.cp__plugins-page
      {:ref       *el-ref
       :tab-index "-1"}

+ 2 - 2
src/main/frontend/components/server.cljs

@@ -87,12 +87,12 @@
                        (swap! *configs assoc :host value))}]]
 
       [:label
-       [:strong "Port (0 ~ 65536)"]
+       [:strong "Port (1 ~ 65535)"]
        [:input.form-input
         {:auto-focus true
          :value      port
          :min        "1"
-         :max        "65536"
+         :max        "65535"
          :type       "number"
          :on-change  #(let [value (.-value (.-target %))]
                         (swap! *configs assoc :port value))}]]]

+ 6 - 8
src/main/frontend/fs.cljs

@@ -194,14 +194,12 @@
 
 (defn mkdir-if-not-exists
   [dir]
-  (->
-   (when dir
-     (util/p-handle
-      (stat dir)
-      (fn [_stat])
-      (fn [_error]
-        (mkdir! dir))))
-   (p/catch (fn [error] (js/console.error error)))))
+  (when dir
+    (util/p-handle
+     (stat dir)
+     (fn [_stat])
+     (fn [_error]
+       (mkdir! dir)))))
 
 ;; FIXME: counterintuitive return value
 (defn create-if-not-exists

+ 17 - 2
src/main/frontend/fs/node.cljs

@@ -80,24 +80,33 @@
 (defrecord Node []
   protocol/Fs
   (mkdir! [_this dir]
-    (ipc/ipc "mkdir" dir))
+    (-> (ipc/ipc "mkdir" dir)
+        (p/then (fn [_] (js/console.log (str "Directory created: " dir))))
+        (p/catch (fn [error]
+                   (when (not= (.-code error) "EEXIST")
+                     (js/console.error (str "Error creating directory: " dir) error))))))
+
   (mkdir-recur! [_this dir]
     (ipc/ipc "mkdir-recur" dir))
+
   (readdir [_this dir]                   ; recursive
     (p/then (ipc/ipc "readdir" dir)
             bean/->clj))
+
   (unlink! [_this repo path _opts]
     (ipc/ipc "unlink"
              (config/get-repo-dir repo)
              path))
   (rmdir! [_this _dir]
-    ;; Too dangerious!!! We'll never implement this.
+    ;; !Too dangerous! We'll never implement this.
     nil)
+
   (read-file [_this dir path _options]
     (let [path (if (nil? dir)
                  path
                  (path/path-join dir path))]
       (ipc/ipc "readFile" path)))
+
   (write-file! [this repo dir path content opts]
     (p/let [fpath (path/path-join dir path)
             stat (p/catch
@@ -106,18 +115,24 @@
             parent-dir (path/parent fpath)
             _ (protocol/mkdir-recur! this parent-dir)]
       (write-file-impl! repo dir path content opts stat)))
+
   (rename! [_this _repo old-path new-path]
     (ipc/ipc "rename" old-path new-path))
+
   (stat [_this fpath]
     (-> (ipc/ipc "stat" fpath)
         (p/then bean/->clj)))
+
   (open-dir [_this dir]
     (open-dir dir))
+
   (get-files [_this dir]
     (-> (ipc/ipc "getFiles" dir)
         (p/then (fn [result]
                   (:files (bean/->clj result))))))
+
   (watch-dir! [_this dir options]
     (ipc/ipc "addDirWatcher" dir options))
+
   (unwatch-dir! [_this dir]
     (ipc/ipc "unwatchDir" dir)))

+ 1 - 1
src/main/frontend/handler/whiteboard.cljs

@@ -182,7 +182,7 @@
 
 (defn get-default-new-whiteboard-tx
   [page-name id]
-  [#:block{:name page-name,
+  [#:block{:name (util/page-name-sanity-lc page-name),
            :type "whiteboard",
            :properties
            {:ls-type :whiteboard-page,

+ 4 - 4
src/main/frontend/ui.cljs

@@ -234,15 +234,15 @@
           (if (keyword? status)
             (case status
               :success
-              (icon "circle-check" {:class "text-success" :size "32"})
+              (icon "circle-check" {:class "text-success" :size "20"})
 
               :warning
-              (icon "alert-circle" {:class "text-warning" :size "32"})
+              (icon "alert-circle" {:class "text-warning" :size "20"})
 
               :error
-              (icon "circle-x" {:class "text-error" :size "32"})
+              (icon "circle-x" {:class "text-error" :size "20"})
 
-              (icon "info-circle" {:class "text-indigo-500" :size "32"}))
+              (icon "info-circle" {:class "text-indigo-500" :size "20"}))
             status)]
       [:div.ui__notifications-content
        {:style