Browse Source

feat(plguin): integration

charlie 4 years ago
parent
commit
6bd8f4847f

+ 2 - 0
resources/electron-dev.html

@@ -30,6 +30,7 @@
 </head>
 <body>
 <div id="root"></div>
+<script>window.__LSP__HOST__ = true</script>
 <script>window.user = null</script>
 <script src="./js/magic_portal.js"></script>
 <script>let worker = new Worker('./js/worker.js')
@@ -49,6 +50,7 @@ const portal = new MagicPortal(worker);
 </script>
 <script defer src="./js/highlight.min.js"></script>
 <script defer src="./js/interact.min.js"></script>
+<script defer src="./js/lsplugin.core.js"></script>
 <script defer src="./js/main.js"></script>
 <script defer src="./js/code-editor.js"></script>
 <script defer src="./js/age-encryption.js"></script>

+ 2 - 0
resources/electron.html

@@ -31,6 +31,7 @@
 </head>
 <body>
 <div id="root"></div>
+<script>window.__LSP__HOST__ = true</script>
 <script>window.user = null</script>
 <script src="./js/magic_portal.js"></script>
 <script>let worker = new Worker('./js/worker.js')
@@ -50,6 +51,7 @@ const portal = new MagicPortal(worker);
 </script>
 <script defer src="./js/highlight.min.js"></script>
 <script defer src="./js/interact.min.js"></script>
+<script defer src="./js/lsplugin.core.js"></script>
 <script defer src="./js/main.js"></script>
 <script defer src="./js/code-editor.js"></script>
 <script defer src="./js/age-encryption.js"></script>

+ 5 - 1
resources/js/preload.js

@@ -1,6 +1,6 @@
 const fs = require('fs')
 const path = require('path')
-const { ipcRenderer, contextBridge, shell, clipboard } = require('electron')
+const { ipcRenderer, contextBridge, shell, clipboard, webFrame } = require('electron')
 
 const IS_MAC = process.platform === 'darwin'
 const IS_WIN32 = process.platform === 'win32'
@@ -136,4 +136,8 @@ contextBridge.exposeInMainWorld('apis', {
 
   getFilePathFromClipboard,
   isClipboardHasImage,
+
+  setZoomFactor (factor) {
+    webFrame.setZoomFactor(factor)
+  }
 })

+ 31 - 0
src/electron/electron/handler.cljs

@@ -89,6 +89,25 @@
                 (remove nil?))]
     (vec (cons {:path (fix-win-path! path)} result))))
 
+(defn- get-ls-dotdir-root
+  []
+  (let [lg-dir (str (.getPath app "home") "/.logseq")]
+    (if-not (fs/existsSync lg-dir)
+      (and (fs/mkdirSync lg-dir) lg-dir)
+      lg-dir)))
+
+(defn- get-ls-default-plugins
+  []
+  (let [plugins-root (path/join (get-ls-dotdir-root) "plugins")
+        _ (if-not (fs/existsSync plugins-root)
+            (fs/mkdirSync plugins-root))
+        dirs (js->clj (fs/readdirSync plugins-root #js{"withFileTypes" true}))
+        dirs (->> dirs
+                  (filter #(.isDirectory %))
+                  (filter #(not (string/starts-with? (.-name %) "_")))
+                  (map #(path/join plugins-root (.-name %))))]
+    dirs))
+
 (defmethod handle :openDir [^js window _messages]
   (let [result (.showOpenDialogSync dialog (bean/->js
                                             {:properties ["openDirectory" "createDirectory" "promptToCreate"]}))
@@ -178,6 +197,18 @@
   (when dir
     (watch-dir! window dir)))
 
+(defmethod handle :openDialogSync [^js window _messages]
+  (let [result (.showOpenDialogSync dialog (bean/->js
+                                             {:properties ["openDirectory"]}))
+        path (first result)]
+    path))
+
+(defmethod handle :getLogseqDotDirRoot []
+  (get-ls-dotdir-root))
+
+(defmethod handle :getUserDefaultPlugins []
+  (get-ls-default-plugins))
+
 (defmethod handle :default [args]
   (println "Error: no ipc handler for: " (bean/->js args)))
 

+ 10 - 0
src/main/frontend/components/header.cljs

@@ -15,6 +15,7 @@
             [frontend.components.repo :as repo]
             [frontend.components.search :as search]
             [frontend.components.export :as export]
+            [frontend.components.plugins :as plugins]
             [frontend.components.right-sidebar :as sidebar]
             [frontend.handler.page :as page-handler]
             [frontend.handler.web.nfs :as nfs]
@@ -71,6 +72,7 @@
 (rum/defc dropdown-menu < rum/reactive
   [{:keys [me current-repo t default-home]}]
   (let [projects (state/sub [:me :projects])
+        developer-mode? (state/sub [:ui/developer-mode?])
         logged? (state/logged?)]
     (ui/dropdown-with-links
      (fn [{:keys [toggle-fn]}]
@@ -114,6 +116,14 @@
           :options {:on-click #(ui-handler/toggle-settings-modal!)}
           :icon svg/settings-sm})
 
+       (when developer-mode?
+         {:title (t :plugins)
+          :options {:href (rfe/href :plugins)}})
+
+       (when developer-mode?
+         {:title (t :themes)
+          :options {:on-click #(plugins/open-select-theme!)}})
+
        (when current-repo
          {:title (t :export)
           :options {:on-click #(state/set-modal! export/export)}

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

@@ -81,7 +81,8 @@
        [:sup.inline-block.px-1.text-xs.opacity-30 version]]
       [:div.desc.text-xs.opacity-60
        [:p description]
-       [:small (js/JSON.stringify (bean/->js settings))]]
+       ;;[:small (js/JSON.stringify (bean/->js settings))]
+]
       [:div.flag
        [:p.text-xs.text-gray-300.pr-2.flex.justify-between.dark:opacity-40
         [:small author]
@@ -146,9 +147,9 @@
   ([type payload opts]
    (let [id (str "slot__" (util/rand-str 8))]
      (rum/use-effect!
-       (fn []
-         (plugin-handler/hook-plugin-app type {:slot id :payload payload} nil)
-         #())
-       [])
+      (fn []
+        (plugin-handler/hook-plugin-app type {:slot id :payload payload} nil)
+        #())
+      [])
      [:div.lsp-hook-ui-slot
       (merge opts {:id id})])))

+ 5 - 2
src/main/frontend/components/settings.cljs

@@ -244,7 +244,7 @@
                               (config-handler/set-config! :date-formatter format))))}
             (for [format (sort (date/journal-title-formatters))]
               [:option (cond->
-                           {:key format}
+                        {:key format}
                          (= format custom-date-format)
                          (assoc :selected "selected"))
                format])]]]]
@@ -352,7 +352,10 @@
          [:div.mt-1.sm:mt-0.sm:col-span-2
           [:div.rounded-md.sm:max-w-xs
            (ui/toggle developer-mode?
-                      #(state/set-developer-mode! (not developer-mode?))
+                      (fn []
+                        (let [mode (not developer-mode?)]
+                          (state/set-developer-mode! mode)
+                          (and mode (js/alert (t :developer-mode-alert)))))
                       true)]]]
         [:div.text-sm.opacity-50
          (t :settings-page/developer-mode-desc)]

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

@@ -2,6 +2,7 @@
   (:require [rum.core :as rum]
             [frontend.util :as util]
             [frontend.handler.route :as route-handler]
+            [frontend.handler.plugin :as plugin-handler]
             [frontend.components.svg :as svg]))
 
 (rum/defc container
@@ -12,7 +13,8 @@
       (.setAttribute doc "data-theme" (if (= theme "white") "light" theme))
       (if (= theme "dark")                                 ;; for tailwind dark mode
         (.add cls "dark")
-        (.remove cls "dark")))
+        (.remove cls "dark"))
+      (plugin-handler/hook-plugin-app :theme-mode-changed theme nil))
    [theme])
 
   (rum/use-effect!

+ 9 - 0
src/main/frontend/components/theme.css

@@ -214,3 +214,12 @@ html.is-resizing-buf {
     transition: none;
   }
 }
+
+body[data-page=plugins] {
+  .cp__sidebar-main-content {
+    max-width: 1280px;
+    width: 80%;
+    padding-left: 30px;
+    padding-right: 30px;
+  }
+}

+ 3 - 1
src/main/frontend/core.cljs

@@ -1,6 +1,7 @@
 (ns frontend.core
   (:require [rum.core :as rum]
             [frontend.handler :as handler]
+            [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.route :as route]
             [frontend.page :as page]
             [frontend.routes :as routes]
@@ -44,7 +45,8 @@
   ;; this is called in the index.html and must be exported
   ;; so it is available even in :advanced release builds
 
-  (handler/start! start)
+  (plugin-handler/setup!
+   #(handler/start! start))
 
   ;; popup to notify user, could be toggled in settings
   ;; (handler/request-notifications-if-not-asked)

+ 6 - 0
src/main/frontend/dicts.cljs

@@ -325,6 +325,9 @@ title: How to take dummy notes?
         :all-journals "All journals"
         :my-publishing "My publishing"
         :settings "Settings"
+        :plugins "Plugins"
+        :themes "Themes"
+        :developer-mode-alert "If you want enable plugin system just now, please restart app."
         :import "Import"
         :join-community "Join the community"
         :sponsor-us "Sponsor Us"
@@ -1048,6 +1051,9 @@ title: How to take dummy notes?
            :all-files "所有文件"
            :my-publishing "我的发布"
            :settings "设置"
+           :plugins "插件"
+           :themes "主题"
+           :developer-mode-alert "如果希望插件功能立刻生效, 请重启应用"
            :import "导入"
            :join-community "加入社区"
            :sponsor-us "赞助我们!"

+ 4 - 1
src/main/frontend/handler/plugin.cljs

@@ -4,6 +4,7 @@
             [frontend.util :as util]
             [frontend.fs :as fs]
             [frontend.handler.notification :as notifications]
+            [frontend.storage :as storage]
             [camel-snake-kebab.core :as csk]
             [frontend.state :as state]
             [medley.core :as md]
@@ -11,7 +12,9 @@
             [cljs-bean.core :as bean]
             [clojure.string :as string]))
 
-(defonce lsp-enabled? (util/electron?))
+(defonce lsp-enabled?
+  (and (util/electron?)
+       (= (storage/get "developer-mode") "true")))
 
 ;; state handlers
 (defn register-plugin

+ 6 - 0
src/main/frontend/handler/route.cljs

@@ -77,6 +77,11 @@
         title (get-title (:name data) path-params)]
     (util/set-title! title)))
 
+(defn update-page-label!
+  [route]
+  (let [{:keys [data]} route]
+    (set! (. js/document.body.dataset -page) (name (:name data)))))
+
 (defn jump-to-anchor!
   [anchor-text]
   (when anchor-text
@@ -87,6 +92,7 @@
   (let [route route]
     (swap! state/state assoc :route-match route)
     (update-page-title! route)
+    (update-page-label! route)
     (when-let [anchor (get-in route [:query-params :anchor])]
       (jump-to-anchor! anchor)
       (util/scroll-to-top))))

+ 2 - 0
src/main/frontend/page.cljs

@@ -3,6 +3,7 @@
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.components.sidebar :as sidebar]
+            [frontend.handler.plugin :as plugin-handler]
             [frontend.context.i18n :as i18n]))
 
 (rum/defc route-view
@@ -15,6 +16,7 @@
                    (state/setup-electron-updater!)
                    (ui/inject-document-devices-envs!)
                    (ui/inject-dynamic-style-node!)
+                   (plugin-handler/host-mounted!)
                    (let [teardown-fn (comp (ui/setup-patch-ios-fixed-bottom-position!))]
                      (assoc state ::teardown teardown-fn)))
    :will-unmount (fn [state]

+ 6 - 1
src/main/frontend/routes.cljs

@@ -4,6 +4,7 @@
             [frontend.components.file :as file]
             [frontend.components.page :as page]
             [frontend.components.diff :as diff]
+            [frontend.components.plugins :as plugins]
             [frontend.components.journal :as journal]
             [frontend.components.search :as search]
             [frontend.components.settings :as settings]
@@ -65,4 +66,8 @@
 
    ["/all-journals"
     {:name :all-journals
-     :view journal/all-journals}]])
+     :view journal/all-journals}]
+
+   ["/plugins"
+    {:name :plugins
+     :view plugins/installed-page}]])

+ 19 - 0
src/main/frontend/state.cljs

@@ -112,6 +112,16 @@
     :electron/updater-pending? false
     :electron/updater {}
 
+    ;; plugin
+    :plugin/indicator-text        nil
+    :plugin/installed-plugins     {}
+    :plugin/installed-themes      []
+    :plugin/installed-commands    {}
+    :plugin/simple-commands       {}
+    :plugin/selected-theme        nil
+    :plugin/selected-unpacked-pkg nil
+    :plugin/active-readme         nil
+
     ;; all notification contents as k-v pairs
     :notification/contents {}
     :graph/syncing? false
@@ -1030,6 +1040,15 @@
   []
   (:commands (get-config)))
 
+(defn get-plugins-commands
+  []
+  (mapcat seq (flatten (vals (:plugin/installed-commands @state)))))
+
+(defn get-plugins-commands-with-type
+  [type]
+  (filterv #(= (keyword (first %)) (keyword type))
+           (apply concat (vals (:plugin/simple-commands @state)))))
+
 (defn get-scheduled-future-days
   []
   (let [days (:scheduled/future-days (get-config))]