enhance(plugin): support custom routes from the plugin sdk

pull/11055/head
charlie 2024-03-21 19:07:16 +08:00
parent bd26d0db0e
commit 53125d6315
11 changed files with 124 additions and 50 deletions

View File

@ -12,7 +12,7 @@
(def button base-core/button)
(def link base-core/link)
(def trigger-as base-core/trigger-as)
(def tabler-icon icon-v2/root)
(def ^:export tabler-icon icon-v2/root)
(def alert (util/lsui-wrap "Alert"))
(def alert-title (util/lsui-wrap "AlertTitle"))

View File

@ -44,7 +44,7 @@ export class LSPluginExperiments {
}
registerFencedCodeRenderer(
type: string,
lang: string,
opts: {
edit?: boolean
before?: () => Promise<void>
@ -54,7 +54,23 @@ export class LSPluginExperiments {
) {
return this.ensureHostScope().logseq.api.exper_register_fenced_code_renderer(
this.ctx.baseInfo.id,
type,
lang,
opts
)
}
registerRouteRenderer(
key: string,
opts: {
name?: string,
path: string,
render: (props: { content: string }) => any
subs?: Array<string>
}
) {
return this.ensureHostScope().logseq.api.exper_register_route_renderer(
this.ctx.baseInfo.id,
key,
opts
)
}
@ -83,7 +99,8 @@ export class LSPluginExperiments {
ensureHostScope(): any {
if (window === top) {
throw new Error('Can not access host scope!')
console.error('Can not access host scope!')
return {}
}
return top

View File

@ -3536,7 +3536,7 @@
(let [lang (util/safe-lower-case (:language options))]
[:div.cp__fenced-code-block
{:data-lang lang}
(if-let [opts (plugin-handler/hook-fenced-code-by-type lang)]
(if-let [opts (plugin-handler/hook-fenced-code-by-lang lang)]
[:div.ui-fenced-code-wrap
(src-cp config options html-export?)
(plugins/hook-ui-fenced-code (:block config) (string/join "" (:lines options)) opts)]

View File

@ -5,7 +5,7 @@
[frontend.ui :as ui]
[frontend.config :as config]
[frontend.state :as state]
[frontend.handler.plugin :refer [hook-extensions-enhancer-by-type]]
[frontend.handler.plugin :refer [hook-extensions-enhancer-by-key]]
[promesa.core :as p]))
;; TODO: Why does shadow fail when code is required
@ -23,7 +23,7 @@
(if-not @loaded?
(p/finally
(p/all (when-let [enhancers (and config/lsp-enabled?
(seq (hook-extensions-enhancer-by-type :codemirror)))]
(seq (hook-extensions-enhancer-by-key :codemirror)))]
(for [{f :enhancer} enhancers]
(when (fn? f) (f (. js/window -CodeMirror))))))
(fn []

View File

@ -12,6 +12,7 @@
[frontend.search :as search]
[frontend.util :as util]
[frontend.mixins :as mixins]
[frontend.config :as config]
[logseq.shui.ui :as shui]
[electron.ipc :as ipc]
[promesa.core :as p]
@ -1426,3 +1427,13 @@
(focused-settings-content title)])
{:label "plugin-settings-modal"
:id "ls-focused-settings-modal"}))
(defn hook-custom-routes
[routes]
(cond-> routes
config/lsp-enabled?
(concat (some->> (plugin-handler/hook-routes-renderer)
(mapv #(when-let [{:keys [name path render]} %]
(when (not (string/blank? path))
[path {:name name :view (fn [r] (render r %))}])))
(remove nil?)))))

View File

@ -5,6 +5,7 @@
[frontend.handler :as handler]
[frontend.handler.plugin :as plugin-handler]
[frontend.handler.route :as route-handler]
[frontend.components.plugins :as plugins]
[frontend.page :as page]
[frontend.routes :as routes]
[frontend.spec]
@ -19,7 +20,7 @@
(defn set-router!
[]
(rfe/start!
(rf/router routes/routes nil)
(rf/router (plugins/hook-custom-routes routes/routes) nil)
(fn [route]
(route-handler/set-route-match! route)
(plugin-handler/hook-plugin-app
@ -43,7 +44,7 @@
\\/ /_____/ \\/ \\/ |__|
"))
(defn start []
(defn ^:export start []
(when config/dev?
(md/start!))
(when-let [node (.getElementById js/document "root")]
@ -62,10 +63,14 @@
(plugin-handler/setup!
#(handler/start! start)))
(defn stop []
(defn ^:export stop []
;; stop is called before any code is reloaded
;; this is controlled by :before-load in the config
(handler/stop!)
(when config/dev?
(sync/<sync-stop))
(js/console.log "stop"))
(defn ^:export delay-remount
[delay]
(js/setTimeout #(start) delay))

View File

@ -4,7 +4,7 @@
[frontend.ui :as ui]
[frontend.config :as config]
[frontend.util :as util]
[frontend.handler.plugin :refer [hook-extensions-enhancer-by-type] :as plugin-handler]
[frontend.handler.plugin :refer [hook-extensions-enhancer-by-key] :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 config/lsp-enabled? (seq (hook-extensions-enhancer-by-type :katex)))]
(p/all (when-let [enhancers (and config/lsp-enabled? (seq (hook-extensions-enhancer-by-key :katex)))]
(for [{f :enhancer} enhancers]
(when (fn? f) (f js/window.katex)))))
(fn []

View File

@ -340,10 +340,11 @@
(when-let [pid (keyword pid)]
(when-let [type (and key (keyword type))]
(let [path [:plugin/installed-resources pid type]]
(when (contains? #{:error nil} (get-in @state/state (conj path key)))
(swap! state/state update-in path
(fnil assoc {}) key (merge opts {:pid pid}))
true)))))
;; TODO: conditions
;; (when (contains? #{:error nil} (get-in @state/state (conj path key))))
(swap! state/state update-in path
(fnil assoc {}) key (merge opts {:pid pid}))
true))))
(defn unregister-plugin-resources
[pid]
@ -380,39 +381,55 @@
(when-let [hook (and uuid (str "hook:db:block_" (string/replace (str uuid) "-" "_")))]
(boolean (seq (get (get-installed-hooks) hook)))))
(defn- create-local-renderer-register
[type *providers]
(fn [pid key {:keys [subs render] :as _opts}]
(when-let [key (and key (keyword key))]
(register-plugin-resources pid type
(merge _opts {:key key :subs subs :render render}))
(swap! *providers conj pid)
#(swap! *providers disj pid))))
(defn- create-local-renderer-getter
([type *providers] (create-local-renderer-getter type *providers false))
([type *providers many?]
(fn [key]
(when-let [key (or many? (and (seq @*providers) key (keyword key)))]
(when-let [rs (->> @*providers
(map #(if many?
(some-> (state/get-plugin-resources-with-type % type)
(vals))
(state/get-plugin-resource % type key)))
(remove nil?)
(flatten)
(seq))]
(if many? rs (first rs)))))))
(defonce *fenced-code-providers (atom #{}))
(defn register-fenced-code-renderer
[pid type {:keys [before subs render edit] :as _opts}]
(when-let [key (and type (keyword type))]
(register-plugin-resources pid :fenced-code-renderers
{:key key :edit edit :before before :subs subs :render render})
(swap! *fenced-code-providers conj pid)
#(swap! *fenced-code-providers disj pid)))
(defn hook-fenced-code-by-type
[type]
(when-let [key (and (seq @*fenced-code-providers) type (keyword type))]
(->> @*fenced-code-providers
(map #(state/get-plugin-resource % :fenced-code-renderers key))
(remove nil?)
(first))))
(def register-fenced-code-renderer
;; [pid key payload]
(create-local-renderer-register
:fenced-code-renderers *fenced-code-providers))
(def hook-fenced-code-by-lang
;; [key]
(create-local-renderer-getter
:fenced-code-renderers *fenced-code-providers))
(def *extensions-enhancer-providers (atom #{}))
(def register-extensions-enhancer
(create-local-renderer-register
:extensions-enhancers *extensions-enhancer-providers))
(def hook-extensions-enhancer-by-key
(create-local-renderer-getter
:extensions-enhancers *extensions-enhancer-providers))
(defn register-extensions-enhancer
[pid type {:keys [enhancer] :as _opts}]
(when-let [key (and type (keyword type))]
(register-plugin-resources pid :extensions-enhancers
{:key key :enhancer enhancer})
(swap! *extensions-enhancer-providers conj pid)
#(swap! *extensions-enhancer-providers disj pid)))
(defn hook-extensions-enhancer-by-type
[type]
(when-let [key (and type (keyword type))]
(map #(state/get-plugin-resource % :extensions-enhancers key)
@*extensions-enhancer-providers)))
(def *route-renderer-providers (atom #{}))
(def register-route-renderer
(create-local-renderer-register
:route-renderers *route-renderer-providers))
(def hook-routes-renderer
(create-local-renderer-getter
:route-renderers *route-renderer-providers true))
(defn select-a-plugin-theme
[pid]
@ -788,7 +805,8 @@
(p/then
(fn []
(state/set-state! :plugin/indicator-text "END")
(callback)))
;; wait for the plugin register async messages
(js/setTimeout #(callback) 64)))
(p/catch
(fn [^js e]
(log/error :setup-plugin-system-error e)

View File

@ -69,7 +69,12 @@
#?(:cljs (def string-join-path common-util/string-join-path))
#?(:cljs
(def safe-re-find common-util/safe-re-find))
(do
(def safe-re-find common-util/safe-re-find)
(defn safe-keyword
[s]
(when (string? s)
(keyword (string/replace s " " "_"))))))
#?(:cljs
(do

View File

@ -982,12 +982,25 @@
(keyword pid) type (reduce #(assoc %1 %2 (aget opts (name %2))) {}
[:edit :before :subs :render]))))
(defn ^:export exper_register_route_renderer
[pid key ^js opts]
(when-let [^js _pl (plugin-handler/get-plugin-inst pid)]
(let [key (util/safe-keyword key)]
(plugin-handler/register-route-renderer
(keyword pid) key
(reduce (fn [r k]
(assoc r k (cond-> (aget opts (name k))
(= :name k)
(#(if % (util/safe-keyword %) key)))))
{} [:v :name :path :subs :render])))))
(defn ^:export exper_register_extensions_enhancer
[pid type enhancer]
(when-let [^js _pl (and (fn? enhancer) (plugin-handler/get-plugin-inst pid))]
(plugin-handler/register-extensions-enhancer
(keyword pid) type {:enhancer enhancer})))
;; http request
(defonce *request-k (volatile! 0))
(defn ^:export exper_request
@ -1060,4 +1073,4 @@
[]
true)
(def ^:export set_blocks_id #(editor-handler/set-blocks-id! (map uuid %)))
(def ^:export set_blocks_id #(editor-handler/set-blocks-id! (map uuid %)))

View File

@ -1,7 +1,8 @@
(ns logseq.sdk.utils
(:require [clojure.walk :as walk]
[camel-snake-kebab.core :as csk]
[frontend.util :as util]))
[frontend.util :as util]
[cljs-bean.core :as bean]))
(defn normalize-keyword-for-json
([input] (normalize-keyword-for-json input true))
@ -28,4 +29,8 @@
(uuid s)
:else
(throw (js/Error. (str s " is not a valid UUID string.")))))
(throw (js/Error. (str s " is not a valid UUID string.")))))
(def ^:export to-clj bean/->clj)
(def ^:export to-keyword keyword)
(def ^:export to-symbol symbol)