浏览代码

Fix more bugs, move plugins.edn and add enabled

- Move plugins.edn to config/ as it is user configuration
- Add plugin-config enabled flag and moved plugin enabled
- Fixed bugs with manual install
- Refactored plugin-config component to have its own listener
- Split out shared plugin fns to a common ns - plugin-config shouldn't
  need to depend on a component like plugin-handler
- Bump rewrite-edn to include upstream fix and avoid tons of cljs
  warnings with earlier versions
- Fix react warning introduced outside this PR in ui/icon
Gabriel Horner 3 年之前
父节点
当前提交
0c570a0300

+ 3 - 0
.clj-kondo/config.edn

@@ -43,12 +43,15 @@
              frontend.handler.extract extract
              frontend.handler.common common-handler
              frontend.handler.common.file file-common-handler
+             frontend.handler.common.plugin plugin-common-handler
              frontend.handler.config config-handler
              frontend.handler.events events
              frontend.handler.global-config global-config-handler
              frontend.handler.ui ui-handler
              frontend.handler.notification notification
              frontend.handler.page page-handler
+             frontend.handler.plugin plugin-handler
+             frontend.handler.plugin-config plugin-config-handler
              frontend.handler.repo repo-handler
              frontend.handler.repo-config repo-config-handler
              frontend.handler.search search-handler

+ 3 - 1
deps.edn

@@ -4,7 +4,9 @@
   rum/rum                               {:mvn/version "0.12.9"}
   datascript/datascript                 {:mvn/version "1.3.8"}
   datascript-transit/datascript-transit {:mvn/version "0.3.0"}
-  borkdude/rewrite-edn                  {:mvn/version "0.1.0"}
+  ;; TODO: bump to mvn/version when released
+  borkdude/rewrite-edn                  {:git/url "https://github.com/borkdude/rewrite-edn"
+                                         :sha "80f246139b1a43b6f2cbab329521d060ee7c1b7b"}
   funcool/promesa                       {:mvn/version "4.0.2"}
   medley/medley                         {:mvn/version "1.4.0"}
   metosin/reitit-frontend               {:mvn/version "0.3.10"}

+ 1 - 1
src/main/frontend/components/block.cljs

@@ -1503,7 +1503,7 @@
       (= name "embed")
       (macro-embed-cp config arguments)
 
-      (and plugin-handler/lsp-enabled? (= name "renderer"))
+      (and config/lsp-enabled? (= name "renderer"))
       (when-let [block-uuid (str (:block/uuid config))]
         (plugins/hook-ui-slot :macro-renderer-slotted (assoc options :uuid block-uuid)))
 

+ 3 - 3
src/main/frontend/components/header.cljs

@@ -75,12 +75,12 @@
           :options {:on-click state/open-settings!}
           :icon (ui/icon "settings")})
 
-       (when plugin-handler/lsp-enabled?
+       (when config/lsp-enabled?
          {:title (t :plugins)
           :options {:on-click #(plugin-handler/goto-plugins-dashboard!)}
           :icon (ui/icon "apps")})
 
-       (when plugin-handler/lsp-enabled?
+       (when config/lsp-enabled?
          {:title (t :themes)
           :options {:on-click #(plugins/open-select-theme!)}
           :icon (ui/icon "palette")})
@@ -209,7 +209,7 @@
       (when sync-enabled?
         (login))
 
-      (when plugin-handler/lsp-enabled?
+      (when config/lsp-enabled?
         (plugins/hook-ui-items :toolbar))
 
       (when (util/electron?)

+ 1 - 2
src/main/frontend/components/page.cljs

@@ -23,7 +23,6 @@
             [frontend.handler.graph :as graph-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
-            [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.route :as route-handler]
             [frontend.mixins :as mixins]
             [frontend.mobile.util :as mobile-util]
@@ -425,7 +424,7 @@
                 [:h1.title.ls-page-title (page-title page-name icon title format fmt-journal?)]])
              (when (not config/publishing?)
                [:div.flex.flex-row
-                (when plugin-handler/lsp-enabled?
+                (when config/lsp-enabled?
                   (plugins/hook-ui-slot :page-head-actions-slotted nil)
                   (plugins/hook-ui-items :pagebar))])])
           [:div

+ 1 - 2
src/main/frontend/components/page_menu.cljs

@@ -12,7 +12,6 @@
             [frontend.util :as util]
             [frontend.util.url :as url-util]
             [frontend.handler.shell :as shell]
-            [frontend.handler.plugin :as plugin-handler]
             [frontend.mobile.util :as mobile-util]
             [electron.ipc :as ipc]
             [frontend.config :as config]
@@ -152,7 +151,7 @@
                        (fn []
                          (ipc/ipc "openFileBackupDir" (config/get-local-dir repo) file-path))}})
 
-          (when plugin-handler/lsp-enabled?
+          (when config/lsp-enabled?
             (for [[_ {:keys [label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
               {:title label
                :options {:on-click #(commands/exec-plugin-simple-command!

+ 7 - 6
src/main/frontend/components/plugins.cljs

@@ -5,7 +5,8 @@
             [frontend.context.i18n :refer [t]]
             [frontend.ui :as ui]
             [frontend.handler.ui :as ui-handler]
-            [frontend.handler.plugin-config :as plugin-config]
+            [frontend.handler.plugin-config :as plugin-config-handler]
+            [frontend.handler.common.plugin :as plugin-common-handler]
             [frontend.search :as search]
             [frontend.util :as util]
             [frontend.mixins :as mixins]
@@ -199,7 +200,7 @@
     [:a.btn
      {:class    (util/classnames [{:disabled   (or installed? installing-or-updating?)
                                    :installing installing-or-updating?}])
-      :on-click #(plugin-handler/install-marketplace-plugin item)}
+      :on-click #(plugin-common-handler/install-marketplace-plugin item)}
      (if installed?
        (t :plugin/installed)
        (if installing-or-updating?
@@ -224,8 +225,8 @@
                     {:title      (t :plugin/delete-alert name)
                      :on-confirm (fn [_ {:keys [close-fn]}]
                                    (close-fn)
-                                   (plugin-handler/unregister-plugin id)
-                                   (plugin-config/remove-plugin id))})]
+                                   (plugin-common-handler/unregister-plugin id)
+                                   (plugin-config-handler/remove-plugin id))})]
                (state/set-sub-modal! confirm-fn {:center? true}))}
        (t :plugin/uninstall)]]]
 
@@ -548,7 +549,7 @@
                  :options {:on-click #(state/pub-event! [:go/proxy-settings agent-opts])}}]
 
                [{:title   [:span.flex.items-center (ui/icon "arrow-down-circle") (t :plugin/install-from-file)]
-                 :options {:on-click plugin-config/open-sync-modal}}]
+                 :options {:on-click plugin-config-handler/open-sync-modal}}]
 
                (when (state/developer-mode?)
                  [{:hr true}
@@ -822,7 +823,7 @@
       [:div.pt-5
        (ui/button [:span "Install"]
                   :on-click #(do
-                               (plugin-config/update-plugins plugins)
+                               (plugin-config-handler/replace-plugins plugins)
                                (state/close-sub-modal! "ls-plugins-from-file-modal")))]]
      ;; all done
      [:div.py-4 [:strong.text-xl "\uD83C\uDF89 All synced!"]])])

+ 1 - 1
src/main/frontend/components/settings.cljs

@@ -726,7 +726,7 @@
   (let [current-repo (state/sub :git/current-repo)
         ;; enable-block-timestamps? (state/enable-block-timestamps?)
         _installed-plugins (state/sub :plugin/installed-plugins)
-        plugins-of-settings (and plugin-handler/lsp-enabled? (seq (plugin-handler/get-enabled-plugins-if-setting-schema)))
+        plugins-of-settings (and config/lsp-enabled? (seq (plugin-handler/get-enabled-plugins-if-setting-schema)))
         *active (::active state)]
 
     [:div#settings.cp__settings-main

+ 7 - 3
src/main/frontend/components/theme.cljs

@@ -1,7 +1,8 @@
 (ns frontend.components.theme
   (:require [frontend.extensions.pdf.highlights :as pdf]
             [frontend.config :as config]
-            [frontend.handler.plugin :refer [lsp-enabled?] :as plugin-handler]
+            [frontend.handler.plugin :as plugin-handler]
+            [frontend.handler.plugin-config :as plugin-config-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.ui :as ui]
@@ -41,9 +42,12 @@
      [sidebar-open? restored-sidebar? sidebar-blocks-len])
 
     (rum/use-effect!
-     #(when lsp-enabled?
+     #(when config/lsp-enabled?
         (plugin-handler/setup-install-listener!)
-        (plugin-handler/load-plugin-preferences))
+        (plugin-config-handler/setup-install-listener!)
+        (plugin-handler/load-plugin-preferences)
+        (fn []
+          (js/window.apis.removeAllListeners "lsp-installed")))
      [])
 
     (rum/use-effect!

+ 17 - 5
src/main/frontend/config.cljs

@@ -35,16 +35,32 @@
       (def API-DOMAIN "api-dev.logseq.com")
       (def WS-URL "wss://ws-dev.logseq.com/file-sync?graphuuid=%s")))
 
-;; feature flags
+;; Feature flags
+;; =============
 
 (goog-define ENABLE-PLUGINS true)
 (defonce enable-plugins? ENABLE-PLUGINS)
 
 (swap! state/state assoc :plugin/enabled enable-plugins?)
 
+;; Desktop only as other platforms requires better understanding of their
+;; multi-graph workflows and optimal place for a "global" dir
+(def global-config-enabled? util/electron?)
+
+;; User level configuration for whether plugins are enabled
+(defonce lsp-enabled?
+         (and (util/electron?)
+              (state/lsp-enabled?-or-theme)))
+
+(defn plugin-config-enabled?
+  []
+  (and lsp-enabled? (global-config-enabled?)))
+
 ;; :TODO: How to do this?
 ;; (defonce desktop? ^boolean goog.DESKTOP)
 
+;; ============
+
 (def app-name "logseq")
 (def website
   (if dev?
@@ -289,10 +305,6 @@
 
 (def config-default-content (rc/inline "config.edn"))
 
-;; Desktop only as other platforms requires better understanding of their
-;; multi-graph workflows and optimal place for a "global" dir
-(def global-config-enabled? util/electron?)
-
 (defonce idb-db-prefix "logseq-db/")
 (defonce local-db-prefix "logseq_local_")
 (defonce local-handle "handle")

+ 2 - 2
src/main/frontend/extensions/latex.cljs

@@ -4,7 +4,7 @@
             [frontend.ui :as ui]
             [frontend.config :as config]
             [frontend.util :as util]
-            [frontend.handler.plugin :refer [lsp-enabled? hook-extensions-enhancer-by-type] :as plugin-handler]
+            [frontend.handler.plugin :refer [hook-extensions-enhancer-by-type] :as plugin-handler]
             [promesa.core :as p]
             [goog.dom :as gdom]))
 
@@ -42,7 +42,7 @@
           (config/asset-uri "/static/js/mhchem.min.js")
           (fn []
             (p/finally
-              (p/all (when-let [enhancers (and lsp-enabled? (seq (hook-extensions-enhancer-by-type :katex)))]
+              (p/all (when-let [enhancers (and config/lsp-enabled? (seq (hook-extensions-enhancer-by-type :katex)))]
                        (for [{f :enhancer} enhancers]
                          (when (fn? f) (f js/window.katex)))))
               (fn []

+ 2 - 2
src/main/frontend/extensions/pdf/highlights.cljs

@@ -7,7 +7,7 @@
             [frontend.extensions.pdf.utils :as pdf-utils]
             [frontend.extensions.pdf.toolbar :refer [pdf-toolbar *area-dashed? *area-mode? *highlight-mode? *highlights-ctx*]]
             [frontend.handler.notification :as notification]
-            [frontend.handler.plugin :as plugin-handler]
+            [frontend.config :as config]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.commands :as commands]
             [frontend.rum :refer [use-atom]]
@@ -193,7 +193,7 @@
 
      (and id [:li.item {:data-action "del"} (t :delete)])
 
-     (when (and plugin-handler/lsp-enabled? text?)
+     (when (and config/lsp-enabled? text?)
        (for [[_ {:keys [key label extras] :as _cmd} action pid]
              (state/get-plugins-commands-with-type :highlight-context-menu-item)]
          [:li.item {:key         key

+ 2 - 3
src/main/frontend/handler.cljs

@@ -28,7 +28,7 @@
             [frontend.handler.user :as user-handler]
             [frontend.handler.repo-config :as repo-config-handler]
             [frontend.handler.global-config :as global-config-handler]
-            [frontend.handler.plugin-config :as plugin-config]
+            [frontend.handler.plugin-config :as plugin-config-handler]
             [frontend.handler.metadata :as metadata-handler]
             [frontend.idb :as idb]
             [frontend.mobile.util :as mobile-util]
@@ -93,8 +93,7 @@
             (p/do! (repo-config-handler/start {:repo repo})
                    (when (config/global-config-enabled?)
                      (global-config-handler/start {:repo repo}))
-                   ;; TODO: Is there a better place for this setup?
-                   (plugin-config/start))
+                   (when (config/plugin-config-enabled?) (plugin-config-handler/start)))
             (p/finally
               (fn []
                 ;; install after config is restored

+ 27 - 0
src/main/frontend/handler/common/plugin.cljs

@@ -0,0 +1,27 @@
+(ns frontend.handler.common.plugin
+  "Common plugin related fns for handlers and api"
+  (:require [frontend.state :as state]
+            [promesa.core :as p]
+            [electron.ipc :as ipc]))
+
+(defn installed?
+  "For the given plugin id, returns boolean indicating if it is installed"
+  [id]
+  (and (contains? (:plugin/installed-plugins @state/state) (keyword id))
+       (get-in @state/state [:plugin/installed-plugins (keyword id) :iir])))
+
+(defn install-marketplace-plugin
+  "Installs plugin given plugin map with id"
+  [{:keys [id] :as mft}]
+  (when-not (and (:plugin/installing @state/state)
+                 (installed? id))
+    (p/create
+     (fn [resolve]
+       (state/set-state! :plugin/installing mft)
+       (ipc/ipc :installMarketPlugin mft)
+       (resolve id)))))
+
+(defn unregister-plugin
+  "Unregister and uninstall plugin given plugin id"
+  [id]
+  (js/LSPluginCore.unregister id))

+ 8 - 38
src/main/frontend/handler/plugin.cljs

@@ -6,7 +6,7 @@
             [clojure.walk :as walk]
             [logseq.graph-parser.mldoc :as gp-mldoc]
             [frontend.handler.notification :as notification]
-            [frontend.handler.plugin-config :as plugin-config]
+            [frontend.handler.common.plugin :as plugin-common-handler]
             [camel-snake-kebab.core :as csk]
             [frontend.state :as state]
             [medley.core :as medley]
@@ -17,12 +17,9 @@
             [lambdaisland.glogi :as log]
             [frontend.components.svg :as svg]
             [frontend.context.i18n :refer [t]]
+            [frontend.config :as config]
             [frontend.format :as format]))
 
-(defonce lsp-enabled?
-         (and (util/electron?)
-              (state/lsp-enabled?-or-theme)))
-
 (defn- normalize-keyword-for-json
   [input]
   (when input
@@ -112,25 +109,10 @@
             (util/fetch stats-url on-ok reject)))))
     (p/resolved nil)))
 
-(defn installed?
-  [id]
-  (and (contains? (:plugin/installed-plugins @state/state) (keyword id))
-       (get-in @state/state [:plugin/installed-plugins (keyword id) :iir])))
-
-(defn install-marketplace-plugin
-  [{:keys [id] :as mft}]
-  (when-not (and (:plugin/installing @state/state)
-                 (installed? id))
-    (p/create
-      (fn [resolve]
-        (state/set-state! :plugin/installing mft)
-        (ipc/ipc :installMarketPlugin mft)
-        (resolve id)))))
-
 (defn check-or-update-marketplace-plugin
   [{:keys [id] :as pkg} error-handler]
   (when-not (and (:plugin/installing @state/state)
-                 (not (installed? id)))
+                 (not (plugin-common-handler/installed? id)))
     (p/catch
       (p/then
         (do (state/set-state! :plugin/installing pkg)
@@ -198,7 +180,7 @@
                              name (or title name "Untitled")]
                          (if only-check
                            (state/consume-updates-coming-plugin payload false)
-                           (if (installed? id)
+                           (if (plugin-common-handler/installed? id)
                              (when-let [^js pl (get-plugin-inst id)] ;; update
                                (p/then
                                 (.reload pl)
@@ -212,10 +194,6 @@
                                (p/then
                                 (js/LSPluginCore.register (bean/->js {:key id :url dst}))
                                 (fn [] (when theme (js/setTimeout #(select-a-plugin-theme id) 300))))
-                               (plugin-config/add-or-update-plugin
-                                (assoc payload
-                                       :version (:installed-version payload)
-                                       :name name))
                                (notification/show!
                                 (str (t :plugin/installed) (t :plugins) ": " name) :success)))))
 
@@ -252,23 +230,15 @@
                    (js/setTimeout #(state/set-state! :plugin/installing nil) 512)
                    true)]
 
-    (js/window.apis.addListener channel listener)
-
-    ;; clear
-    (fn []
-      (js/window.apis.removeAllListeners channel))))
+    (js/window.apis.addListener channel listener)))
 
 (defn register-plugin
   [pl]
   (swap! state/state update-in [:plugin/installed-plugins] assoc (keyword (:id pl)) pl))
 
-(defn unregister-plugin
-  [id]
-  (js/LSPluginCore.unregister id))
-
 (defn host-mounted!
   []
-  (and lsp-enabled? (js/LSPluginCore.hostMounted)))
+  (and config/lsp-enabled? (js/LSPluginCore.hostMounted)))
 
 (defn register-plugin-slash-command
   [pid [cmd actions]]
@@ -469,7 +439,7 @@
 
 (defn hook-plugin
   [tag type payload plugin-id]
-  (when lsp-enabled?
+  (when config/lsp-enabled?
     (try
       (js-invoke js/LSPluginCore
                  (str "hook" (string/capitalize (name tag)))
@@ -706,6 +676,6 @@
 (defn setup!
   "setup plugin core handler"
   [callback]
-  (if (not lsp-enabled?)
+  (if (not config/lsp-enabled?)
     (callback)
     (init-plugins! callback)))

+ 41 - 30
src/main/frontend/handler/plugin_config.cljs

@@ -1,6 +1,7 @@
 (ns frontend.handler.plugin-config
-  "This ns is a system component that encapsulate the global plugin.edn.
-This component depends on TODO"
+  "This system component encapsulates the global plugin.edn and depends on the
+  global-config component. This component is only enabled? if both the
+  global-config and plugin components are enabled"
   (:require [frontend.handler.global-config :as global-config-handler]
             ["path" :as path]
             [promesa.core :as p]
@@ -8,24 +9,26 @@ This component depends on TODO"
             [frontend.fs :as fs]
             [frontend.state :as state]
             [frontend.handler.notification :as notification]
-            [electron.ipc :as ipc]
+            [frontend.handler.common.plugin :as plugin-common-handler]
             [clojure.edn :as edn]
             [clojure.set :as set]
             [clojure.pprint :as pprint]
             [malli.core :as m]
             [malli.error :as me]
             [frontend.schema.handler.plugin-config :as plugin-config-schema]
+            [cljs-bean.core :as bean]
             [lambdaisland.glogi :as log]))
 
-(defn- plugin-config-path
+(defn plugin-config-path
   []
-  (path/join @global-config-handler/root-dir "plugins.edn"))
+  (path/join (global-config-handler/global-config-dir) "plugins.edn"))
 
 (def common-plugin-keys
   "Vec of plugin keys to store in plugins.edn and to compare with installed-plugins state"
   (->> plugin-config-schema/Plugin rest (mapv first)))
 
 (defn add-or-update-plugin
+  "Adds or updates a plugin from plugin.edn"
   [{:keys [id] :as plugin}]
   (p/let [content (fs/read-file "" (plugin-config-path))
           updated-content (-> content
@@ -37,6 +40,7 @@ This component depends on TODO"
          (fs/write-file! nil "" (plugin-config-path) updated-content {:skip-compare? true})))
 
 (defn remove-plugin
+  "Removes a plugin from plugin.edn"
   [plugin-id]
   (p/let [content (fs/read-file "" (plugin-config-path))
           updated-content (-> content rewrite/parse-string (rewrite/dissoc (keyword plugin-id)) str)]
@@ -54,13 +58,18 @@ This component depends on TODO"
   "Given installed plugins state and plugins from plugins.edn,
 returns map of plugins to install and uninstall"
   [installed-plugins edn-plugins]
+  ;; :name is removed from comparison because it isn't used for reproducible builds
+  ;; and is just for display purposes
   (let [installed-plugins-set (->> installed-plugins
                                    vals
-                                   (map #(assoc (select-keys % common-plugin-keys)
-                                                :id (keyword (:id %))))
+                                   (map #(-> (select-keys % common-plugin-keys)
+                                             (assoc :id (keyword (:id %)))
+                                             (dissoc :name)))
                                    set)
         edn-plugins-set (->> edn-plugins
-                             (map (fn [[k v]] (assoc v :id k)))
+                             (map (fn [[k v]] (-> v
+                                                  (assoc :id k)
+                                                  (dissoc :name))))
                              set)]
     (if (= installed-plugins-set edn-plugins-set)
       {}
@@ -89,34 +98,36 @@ returns map of plugins to install and uninstall"
                            :error)
        (log/error :unexpected-error e)))))
 
-;; TODO: Extract from handler.plugin
-(defn installed?
-  [id]
-  (and (contains? (:plugin/installed-plugins @state/state) (keyword id))
-       (get-in @state/state [:plugin/installed-plugins (keyword id) :iir])))
-
-(defn install-marketplace-plugin
-  [{:keys [id] :as mft}]
-  ; (prn :IN {:k1 (:plugin/installing @state/state)
-  ;           :k2 (installed? id)})
-  ;; TODO:
-  (when-not (and (:plugin/installing @state/state)
-                 (installed? id))
-    (p/create
-     (fn [resolve]
-       (state/set-state! :plugin/installing mft)
-       (ipc/ipc :installMarketPlugin mft)
-       (resolve id)))))
-
-(defn update-plugins
+(defn replace-plugins
+  "Replaces current plugins given plugins to install and uninstall"
   [plugins]
   (log/info :uninstall-plugins (:uninstall plugins))
   (doseq [plugin (:uninstall plugins)]
-    (js/LSPluginCore.unregister (name (:id plugin))))
+    (plugin-common-handler/unregister-plugin (name (:id plugin))))
   (log/info :install-plugins (:install plugins))
   (doseq [plugin (:install plugins)]
-    (install-marketplace-plugin plugin)))
+    (plugin-common-handler/install-marketplace-plugin plugin)))
+
+(defn setup-install-listener!
+  "Sets up a listener for the lsp-installed event to update plugins.edn"
+  []
+  (let [listener (fn listener [_ e]
+                   (when-let [{:keys [status payload only-check]} (bean/->clj e)]
+                     (when (and (= status "completed") (not only-check))
+                       (let [{:keys [name title theme]} payload
+                             ;; Same defaults as plugin/setup-install-listener!
+                             name (or title name "Untitled")]
+                         (add-or-update-plugin
+                          (assoc payload
+                                 :version (:installed-version payload)
+                                 ;; Manual install doesn't have theme field but
+                                 ;; plugin.edn requires this field
+                                 :theme (if (some? theme) theme false)
+                                 :name name))))))]
+    (js/window.apis.addListener "lsp-installed" listener)))
 
 (defn start
+  "This component has just one reponsibility on start, to create a plugins.edn
+  if none exists"
   []
   (create-plugin-config-file-if-not-exists))

+ 5 - 4
src/main/frontend/modules/shortcut/config.cljs

@@ -14,12 +14,13 @@
             [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.export :as export-handler]
             [frontend.handler.whiteboard :as whiteboard-handler]
-            [frontend.handler.plugin-config :as plugin-config]
+            [frontend.handler.plugin-config :as plugin-config-handler]
             [frontend.modules.shortcut.dicts :as dicts]
             [frontend.modules.shortcut.before :as m]
             [frontend.state :as state]
             [frontend.util :refer [mac?] :as util]
             [frontend.commands :as commands]
+            [frontend.config :as config]
             [electron.ipc :as ipc]
             [promesa.core :as p]
             [clojure.data :as data]
@@ -406,13 +407,13 @@
                                      :fn      plugin-handler/show-themes-modal!}
 
    :ui/goto-plugins                 {:binding "t p"
-                                     :inactive (not plugin-handler/lsp-enabled?)
+                                     :inactive (not config/lsp-enabled?)
                                      :fn      plugin-handler/goto-plugins-dashboard!}
 
    :ui/install-plugins-from-file    {:binding false
-                                     :inactive (not plugin-handler/lsp-enabled?)
+                                     :inactive (not (config/plugin-config-enabled?))
                                      ;; TODO: Remove dev convenience
-                                     :fn      (fn [] (plugin-config/open-sync-modal))}
+                                     :fn      (fn [] (plugin-config-handler/open-sync-modal))}
 
    :editor/toggle-open-blocks       {:binding "t o"
                                      :fn      editor-handler/toggle-open!}

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

@@ -12,6 +12,7 @@
             [datascript.core :as d]
             [electron.ipc :as ipc]
             [frontend.components.svg :as svg]
+            [frontend.config :as config]
             [frontend.context.i18n :refer [t]]
             [frontend.db-mixins :as db-mixins]
             [frontend.handler.notification :as notification]
@@ -32,7 +33,6 @@
             [goog.object :as gobj]
             [lambdaisland.glogi :as log]
             [medley.core :as medley]
-            [frontend.config :as config]
             [promesa.core :as p]
             [rum.core :as rum]))
 
@@ -361,7 +361,7 @@
       style)))
 
 (defn apply-custom-theme-effect! [theme]
-  (when plugin-handler/lsp-enabled?
+  (when config/lsp-enabled?
     (when-let [custom-theme (state/sub [:ui/custom-theme (keyword theme)])]
       (when-let [url (:url custom-theme)]
         (js/LSPluginCore.selectTheme (bean/->js custom-theme)
@@ -939,7 +939,7 @@
                            (when (:class opts)
                              (str " " (string/trim (:class opts)))))
                       (if extension? "tie tie" "ti ti"))}
-                    (dissoc opts :class :extension?))]
+                    (dissoc opts :class :extension? :font?))]
 
          ;; tabler svg react
          (when-let [klass (gobj/get js/tablerIcons (str "Icon" (csk/->PascalCase class)))]

+ 2 - 1
src/main/logseq/api.cljs

@@ -21,6 +21,7 @@
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.plugin :as plugin-handler]
+            [frontend.handler.common.plugin :as plugin-common-handler]
             [frontend.modules.outliner.core :as outliner]
             [frontend.modules.outliner.tree :as outliner-tree]
             [frontend.handler.command-palette :as palette-handler]
@@ -776,7 +777,7 @@
     (when-let [{:keys [repo id] :as mft} (bean/->clj manifest)]
       (if-not (and repo id)
         (throw (js/Error. "[required] :repo :id"))
-        (plugin-handler/install-marketplace-plugin mft)))))
+        (plugin-common-handler/install-marketplace-plugin mft)))))
 
 ;; db
 (defn ^:export q

+ 44 - 51
src/test/frontend/handler/plugin_config_test.cljs

@@ -2,7 +2,7 @@
   (:require [clojure.test :refer [is use-fixtures testing deftest]]
             [frontend.test.helper :as test-helper :include-macros true :refer [deftest-async]]
             [frontend.test.fixtures :as fixtures]
-            [frontend.handler.plugin-config :as plugin-config]
+            [frontend.handler.plugin-config :as plugin-config-handler]
             [frontend.handler.global-config :as global-config-handler]
             [frontend.schema.handler.plugin-config :as plugin-config-schema]
             ["fs" :as fs-node]
@@ -15,88 +15,81 @@
 
 (use-fixtures :once fixtures/redef-get-fs)
 
+(defn- create-global-config-dir
+  []
+  (let [dir (test-helper/create-tmp-dir "config")
+        root-dir (path/dirname dir)]
+    (reset! global-config-handler/root-dir root-dir)
+    dir))
+
+(defn- delete-global-config-dir
+  [config-dir]
+  (doseq [relative-file (fs-node/readdirSync config-dir)]
+    (fs-node/unlinkSync (path/join config-dir relative-file)))
+  (reset! global-config-handler/root-dir nil)
+  (fs-node/rmdirSync config-dir)
+  (fs-node/rmdirSync (path/dirname config-dir)))
+
 (deftest-async add-or-update-plugin
-  (let [dir (test-helper/create-tmp-dir)
-        plugins-file (path/join dir "plugins.edn")
+  (let [dir (create-global-config-dir)
         plugin-to-add {:id :foo :name "Foo" :repo "some-user/foo" :version "v0.9.0"}
         body (pr-str (mg/generate plugin-config-schema/Plugins-edn {:size 10}))]
-    (fs-node/writeFileSync plugins-file body)
-    (reset! global-config-handler/root-dir dir)
+    (fs-node/writeFileSync (plugin-config-handler/plugin-config-path) body)
 
     (->
      (p/do!
-      (plugin-config/add-or-update-plugin plugin-to-add)
+      (plugin-config-handler/add-or-update-plugin plugin-to-add)
       (is (= (dissoc plugin-to-add :id)
-             (:foo (edn/read-string (str (fs-node/readFileSync plugins-file)))))))
+             (:foo (edn/read-string (str (fs-node/readFileSync (plugin-config-handler/plugin-config-path))))))))
 
-     (.finally
-      (fn []
-        (reset! global-config-handler/root-dir nil)
-        (fs-node/unlinkSync plugins-file)
-        (fs-node/rmdirSync dir))))))
+     (p/finally #(delete-global-config-dir dir)))))
 
 (deftest-async remove-plugin
-  (let [dir (test-helper/create-tmp-dir)
-        plugins-file (path/join dir "plugins.edn")
+  (let [dir (create-global-config-dir)
         ;; use seed to consistently generate 5 plugins
         ;; if we want more randomness we could look into gen/such-that
         plugins (mg/generate plugin-config-schema/Plugins-edn {:size 5 :seed 1})
         some-plugin-id (first (keys plugins))]
-    (fs-node/writeFileSync plugins-file (pr-str plugins))
-    (reset! global-config-handler/root-dir dir)
+    (fs-node/writeFileSync (plugin-config-handler/plugin-config-path) (pr-str plugins))
 
     (->
      (p/do!
-      (plugin-config/remove-plugin some-plugin-id)
+      (plugin-config-handler/remove-plugin some-plugin-id)
       (is (= nil
-             (get (edn/read-string (str (fs-node/readFileSync plugins-file)))
+             (get (edn/read-string (str (fs-node/readFileSync (plugin-config-handler/plugin-config-path))))
                   some-plugin-id))))
 
-     (.finally
-      (fn []
-        (reset! global-config-handler/root-dir nil)
-        (fs-node/unlinkSync plugins-file)
-        (fs-node/rmdirSync dir))))))
+     (p/finally #(delete-global-config-dir dir)))))
 
 (deftest-async open-sync-modal-malformed-edn
-  (let [dir (test-helper/create-tmp-dir)
-        plugins-file (path/join dir "plugins.edn")
+  (let [dir (create-global-config-dir)
         error-message (atom nil)]
-    (fs-node/writeFileSync plugins-file "{:id {}")
-    (reset! global-config-handler/root-dir dir)
+    (fs-node/writeFileSync (plugin-config-handler/plugin-config-path) "{:id {}")
 
     (test-helper/with-reset reset
       [notification/show! (fn [msg _] (reset! error-message msg))]
       (->
        (p/do!
-        (plugin-config/open-sync-modal)
+        (plugin-config-handler/open-sync-modal)
         (is (string/starts-with? @error-message "Malformed plugins.edn")
             "User sees correct notification"))
-       (p/finally (fn []
-                    (reset)
-                    (reset! global-config-handler/root-dir nil)
-                    (fs-node/unlinkSync plugins-file)
-                    (fs-node/rmdirSync dir)))))))
+       (p/finally #(delete-global-config-dir dir))))))
 
 (deftest-async open-sync-modal-invalid-edn
-  (let [dir (test-helper/create-tmp-dir)
-        plugins-file (path/join dir "plugins.edn")
+  (let [dir (create-global-config-dir)
         error-message (atom nil)]
     ;; Missing a couple plugin keys
-    (fs-node/writeFileSync plugins-file (pr-str {:id {:theme true :repo "user/repo"}}))
-    (reset! global-config-handler/root-dir dir)
+    (fs-node/writeFileSync (plugin-config-handler/plugin-config-path)
+                           (pr-str {:id {:theme true :repo "user/repo"}}))
 
     (test-helper/with-reset reset
       [notification/show! (fn [msg _] (reset! error-message msg))]
       (->
        (p/do!
-        (plugin-config/open-sync-modal)
+        (plugin-config-handler/open-sync-modal)
         (is (string/starts-with? @error-message "Invalid plugins.edn")
             "User sees correct notification"))
-       (p/finally (fn []
-                    (reset)
-                    (fs-node/unlinkSync plugins-file)
-                    (fs-node/rmdirSync dir)))))))
+       (p/finally #(delete-global-config-dir dir))))))
 
 (defn- installed-plugins->edn-plugins
   "Converts installed plugins state to edn.plugins format"
@@ -107,26 +100,26 @@
 ;; install and uninstall
 (deftest determine-plugins-to-change
   (testing "no changes to make"
-    (let [plugins {:foo {:id :foo :name "Foo" :repo "some-user/foo" :version "v0.9.0"}
-                   :bar {:id :bar :name "Bar" :repo "some-user/bar" :version "v0.1.0"}}]
-      (is (= {} (#'plugin-config/determine-plugins-to-change
+    (let [plugins {:foo {:id :foo :repo "some-user/foo" :version "v0.9.0"}
+                   :bar {:id :bar :repo "some-user/bar" :version "v0.1.0"}}]
+      (is (= {} (#'plugin-config-handler/determine-plugins-to-change
                   plugins
                   (installed-plugins->edn-plugins plugins))))))
 
   (testing "differing versions are uninstalled and installed"
-    (let [plugins {:bar {:id :bar :name "Bar" :repo "some-user/bar" :version "v0.1.0"}}]
+    (let [plugins {:bar {:id :bar :repo "some-user/bar" :version "v0.1.0"}}]
       (is (= {:uninstall [(:bar plugins)]
               :install [(assoc (:bar plugins) :version "v1.0.0" :plugin-action "install")]}
-             (#'plugin-config/determine-plugins-to-change
+             (#'plugin-config-handler/determine-plugins-to-change
                plugins
                (installed-plugins->edn-plugins (assoc-in plugins [:bar :version] "v1.0.0")))))))
 
   (testing "replaced plugins are uninstalled and new plugins are installed"
-    (let [plugins {:foo {:id :foo :name "Foo" :repo "some-user/foo" :version "v0.9.0"}
-                   :bar {:id :bar :name "Bar" :repo "some-user/bar" :version "v0.1.0"}}
-          new-plugin {:id :baz :name "Baz" :repo "some-user/baz" :version "v0.5.0"}]
+    (let [plugins {:foo {:id :foo :repo "some-user/foo" :version "v0.9.0"}
+                   :bar {:id :bar :repo "some-user/bar" :version "v0.1.0"}}
+          new-plugin {:id :baz :repo "some-user/baz" :version "v0.5.0"}]
       (is (= {:uninstall [(:foo plugins)]
               :install [(assoc new-plugin :plugin-action "install")]}
-             (#'plugin-config/determine-plugins-to-change
+             (#'plugin-config-handler/determine-plugins-to-change
                plugins
                (-> plugins (dissoc :foo) (assoc :baz new-plugin) installed-plugins->edn-plugins)))))))

+ 3 - 2
src/test/frontend/handler/repo_conversion_test.cljs

@@ -121,8 +121,9 @@
         ;; only test file name parsing, don't consider title prop overriding
         rename-target (:target (#'conversion-handler/calc-rename-target-impl :legacy :triple-lowbar original-body nil))]
     (if rename-target
-      (do (prn "conversion triple-lowbar: " original-body " -> " rename-target)
-          (#'page-handler/compute-new-file-path path rename-target))
+      #_:clj-kondo/ignore
+      (do #_(prn "conversion triple-lowbar: " original-body " -> " rename-target)
+        (#'page-handler/compute-new-file-path path rename-target))
       path)))
 
 (defn- convert-graph-files-path

+ 13 - 3
src/test/frontend/test/helper.cljs

@@ -16,6 +16,8 @@
   (conn/destroy-all!))
 
 (defn load-test-files
+  "Given a collection of file maps, loads them into the current test-db.
+This can be called in synchronous contexts as no async fns should be invoked"
   [files]
   (repo-handler/parse-files-and-load-to-db!
    test-db
@@ -24,6 +26,14 @@
    {:re-render? false :verbose false :refresh? true}))
 
 (defn create-tmp-dir
-  []
-  (when-not (fs-node/existsSync "tmp") (fs-node/mkdirSync "tmp"))
-  (fs-node/mkdtempSync (path/join "tmp" "unit-test-")))
+  "Creates a temporary directory under tmp/. If a subdir is given, creates an
+  additional subdirectory under the newly created temp directory."
+  ([] (create-tmp-dir nil))
+  ([subdir]
+   (when-not (fs-node/existsSync "tmp") (fs-node/mkdirSync "tmp"))
+   (let [dir (fs-node/mkdtempSync (path/join "tmp" "unit-test-"))]
+     (if subdir
+       (do
+         (fs-node/mkdirSync (path/join dir subdir))
+         (path/join dir subdir))
+       dir))))