Browse Source

Introduce keyword :fn to commands

Allows commands to invoke namespaces that previously caused circular
dependency issues
Gabriel Horner 2 years ago
parent
commit
bcaec408e6

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

@@ -58,6 +58,7 @@
              frontend.handler.common common-handler
              frontend.handler.common.file file-common-handler
              frontend.handler.common.plugin plugin-common-handler
+             frontend.handler.common.developer dev-common-handler
              frontend.handler.config config-handler
              frontend.handler.events events
              frontend.handler.global-config global-config-handler

+ 3 - 2
src/main/frontend/components/content.cljs

@@ -13,6 +13,7 @@
             [frontend.handler.image :as image-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
+            [frontend.handler.common.developer :as dev-common-handler]
             [frontend.mixins :as mixins]
             [frontend.state :as state]
             [frontend.ui :as ui]
@@ -293,7 +294,7 @@
            (ui/menu-link
             {:key      "(Dev) Show block data"
              :on-click (fn []
-                         (state/pub-event! [:dev/show-entity-data [:block/uuid block-id]]))}
+                         (dev-common-handler/show-entity-data [:block/uuid block-id]))}
             "(Dev) Show block data"
             nil))
 
@@ -302,7 +303,7 @@
             {:key      "(Dev) Show block AST"
              :on-click (fn []
                          (let [block (db/pull [:block/uuid block-id])]
-                           (state/pub-event! [:dev/show-content-ast (:block/content block) (:block/format block)])))}
+                           (dev-common-handler/show-content-ast (:block/content block) (:block/format block))))}
             "(Dev) Show block AST"
             nil))])))
 

+ 5 - 3
src/main/frontend/components/page_menu.cljs

@@ -6,6 +6,7 @@
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.route :as route-handler]
+            [frontend.handler.common.developer :as dev-common-handler]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.util :as util]
@@ -162,13 +163,14 @@
           (when developer-mode?
             {:title   "(Dev) Show page data"
              :options {:on-click (fn []
-                                   (state/pub-event! [:dev/show-entity-data (:db/id page)]))}})
+                                   (dev-common-handler/show-entity-data (:db/id page)))}})
 
           (when developer-mode?
             {:title   "(Dev) Show page AST"
              :options {:on-click (fn []
                                    (let [page (db/pull '[:block/format {:block/file [:file/content]}] (:db/id page))]
-                                     (state/pub-event! [:dev/show-content-ast (get-in page [:block/file :file/content])
-                                                        (:block/format page)])))}})]
+                                     (dev-common-handler/show-content-ast
+                                      (get-in page [:block/file :file/content])
+                                      (:block/format page))))}})]
          (flatten)
          (remove nil?))))))

+ 66 - 0
src/main/frontend/handler/common/developer.cljs

@@ -0,0 +1,66 @@
+(ns frontend.handler.common.developer
+  "Common fns for developer related functionality"
+  (:require [frontend.db :as db]
+            [cljs.pprint :as pprint]
+            [frontend.state :as state]
+            [frontend.handler.notification :as notification]
+            [frontend.ui :as ui]
+            [logseq.graph-parser.mldoc :as gp-mldoc]))
+
+;; Fns used between menus and commands
+(defn show-entity-data
+  [& pull-args]
+  (let [pull-data (with-out-str (pprint/pprint (apply db/pull pull-args)))]
+    (println pull-data)
+    (notification/show!
+     [:div
+      [:pre.code pull-data]
+      [:br]
+      (ui/button "Copy to clipboard"
+                 :on-click #(.writeText js/navigator.clipboard pull-data))]
+     :success
+     false)))
+
+(defn show-content-ast
+  [content format]
+  (let [ast-data (-> (gp-mldoc/->edn content (gp-mldoc/default-config format))
+                     pprint/pprint
+                     with-out-str)]
+    (println ast-data)
+    (notification/show!
+     [:div
+      ;; Show clipboard at top since content is really long for pages
+      (ui/button "Copy to clipboard"
+                 :on-click #(.writeText js/navigator.clipboard ast-data))
+      [:br]
+      [:pre.code ast-data]]
+     :success
+     false)))
+
+;; Public Commands
+(defn ^:export show-block-data []
+  ;; Use editor state to locate most recent block
+  (if-let [block-uuid (:block-id (first (state/get-editor-args)))]
+    (show-entity-data [:block/uuid block-uuid])
+    (notification/show! "No block found" :error)))
+
+(defn ^:export show-block-ast []
+  (if-let [{:block/keys [content format]} (:block (first (state/get-editor-args)))]
+    (show-content-ast content format)
+    (notification/show! "No block found" :error)))
+
+(defn ^:export show-page-data []
+  ;; Use editor state to locate most recent page.
+  ;; Consider replacing with navigation history if it's more useful
+  (if-let [page-id (get-in (first (state/get-editor-args))
+                           [:block :block/page :db/id])]
+    (show-entity-data page-id)
+    (notification/show! "No page found" :error)))
+
+(defn ^:export show-page-ast []
+  (let [page-data (db/pull '[:block/format {:block/file [:file/content]}]
+                           (get-in (first (state/get-editor-args))
+                                   [:block :block/page :db/id]))]
+    (if (get-in page-data [:block/file :file/content])
+      (show-content-ast (get-in page-data [:block/file :file/content]) (:block/format page-data))
+      (notification/show! "No page found" :error))))

+ 0 - 29
src/main/frontend/handler/events.cljs

@@ -8,7 +8,6 @@
             [clojure.core.async.interop :refer [p->c]]
             [clojure.set :as set]
             [clojure.string :as string]
-            [cljs.pprint :as pprint]
             [datascript.core :as d]
             [frontend.commands :as commands]
             [frontend.components.diff :as diff]
@@ -66,7 +65,6 @@
             [promesa.core :as p]
             [rum.core :as rum]
             [logseq.graph-parser.config :as gp-config]
-            [logseq.graph-parser.mldoc :as gp-mldoc]
             [cljs-bean.core :as bean]
             ["@sentry/react" :as Sentry]
             [frontend.modules.instrumentation.sentry :as sentry-event]))
@@ -921,33 +919,6 @@
   (when (and command (not (string/blank? content)))
     (shell-handler/run-cli-command-wrapper! command content)))
 
-(defmethod handle :dev/show-entity-data [[_ & pull-args]]
-  (let [pull-data (with-out-str (pprint/pprint (apply db/pull pull-args)))]
-    (println pull-data)
-    (notification/show!
-     [:div
-      [:pre.code pull-data]
-      [:br]
-      (ui/button "Copy to clipboard"
-                 :on-click #(.writeText js/navigator.clipboard pull-data))]
-     :success
-     false)))
-
-(defmethod handle :dev/show-content-ast [[_ content format]]
-  (let [ast-data (-> (gp-mldoc/->edn content (gp-mldoc/default-config format))
-                       pprint/pprint
-                       with-out-str)]
-    (println ast-data)
-    (notification/show!
-     [:div
-      ;; Show clipboard at top since content is really long for pages
-      (ui/button "Copy to clipboard"
-                 :on-click #(.writeText js/navigator.clipboard ast-data))
-      [:br]
-      [:pre.code ast-data]]
-     :success
-     false)))
-
 (defn run!
   []
   (let [chan (state/get-events-chan)]

+ 29 - 30
src/main/frontend/modules/shortcut/config.cljs

@@ -1,6 +1,5 @@
 (ns frontend.modules.shortcut.config
   (:require [frontend.components.commit :as commit]
-            [frontend.handler.notification :as notification]
             [frontend.extensions.srs.handler :as srs]
             [frontend.extensions.pdf.utils :as pdf-utils]
             [frontend.handler.config :as config-handler]
@@ -19,7 +18,6 @@
             [frontend.modules.shortcut.dicts :as dicts]
             [frontend.modules.shortcut.before :as m]
             [frontend.state :as state]
-            [frontend.db :as db]
             [frontend.util :refer [mac?] :as util]
             [frontend.commands :as commands]
             [frontend.config :as config]
@@ -33,10 +31,14 @@
 ;; almost everywhere else they are not which could cause needless conflicts
 ;; with other config keys
 
-;; To add a new entry to this map, first add it here and then
-;; a description for it in frontend.modules.shortcut.dicts/all-default-keyboard-shortcuts.
-;; :inactive key is for commands that are not active for a given platform or feature condition
-;; Avoid using single letter shortcuts to allow chords that start with those characters
+;; To add a new entry to this map, first add it here and then a description for
+;; it in frontend.modules.shortcut.dicts/all-default-keyboard-shortcuts.
+;; A shortcut is a map with the following keys:
+;;  * :binding - A string representing a keybinding. Avoid using single letter
+;;    shortcuts to allow chords that start with those characters
+;;  * :fn - Fn or a qualified keyword that represents a fn
+;;  * :inactive - Optional boolean to disable a shortcut for certain conditions
+;;    e.g. a given platform or feature condition
 (def ^:large-vars/data-var all-default-keyboard-shortcuts
   ;; BUG: Actually, "enter" is registered by mixin behind a "when inputing" guard
   ;; So this setting item does not cover all cases.
@@ -426,7 +428,7 @@
                                      :fn       plugin-config-handler/open-replace-plugins-modal}
 
    :ui/clear-all-notifications      {:binding false
-                                     :fn       notification/clear-all!}
+                                     :fn      :frontend.handler.notification/clear-all!}
 
    :editor/toggle-open-blocks       {:binding "t o"
                                      :fn      editor-handler/toggle-open!}
@@ -439,38 +441,19 @@
 
    :dev/show-block-data            {:binding false
                                     :inactive (not (state/developer-mode?))
-                                    :fn (fn []
-                                          ;; Use editor state to locate most recent block
-                                          (if-let [block-uuid (:block-id (first (state/get-editor-args)))]
-                                            (state/pub-event! [:dev/show-entity-data [:block/uuid block-uuid]])
-                                            (notification/show! "No block found" :error)))}
+                                    :fn :frontend.handler.common.developer/show-block-data}
 
    :dev/show-block-ast             {:binding false
                                     :inactive (not (state/developer-mode?))
-                                    :fn (fn []
-                                          (if-let [{:block/keys [content format]} (:block (first (state/get-editor-args)))]
-                                            (state/pub-event! [:dev/show-content-ast content format])
-                                            (notification/show! "No block found" :error)))}
+                                    :fn :frontend.handler.common.developer/show-block-ast}
 
    :dev/show-page-data             {:binding false
                                     :inactive (not (state/developer-mode?))
-                                    :fn (fn []
-                                          ;; Use editor state to locate most recent page.
-                                          ;; Consider replacing with navigation history if it's more useful
-                                          (if-let [page-id (get-in (first (state/get-editor-args))
-                                                                   [:block :block/page :db/id])]
-                                            (state/pub-event! [:dev/show-entity-data page-id])
-                                            (notification/show! "No page found" :error)))}
+                                    :fn :frontend.handler.common.developer/show-page-data}
 
    :dev/show-page-ast              {:binding false
                                     :inactive (not (state/developer-mode?))
-                                    :fn (fn []
-                                          (let [page-data (db/pull '[:block/format {:block/file [:file/content]}]
-                                                                   (get-in (first (state/get-editor-args))
-                                                                           [:block :block/page :db/id]))]
-                                            (if (seq page-data)
-                                              (state/pub-event! [:dev/show-content-ast (get-in page-data [:block/file :file/content]) (:block/format page-data)])
-                                              (notification/show! "No page found" :error))))}})
+                                    :fn :frontend.handler.common.developer/show-page-ast}})
 
 (let [keyboard-shortcuts
       {::keyboard-shortcuts (set (keys all-default-keyboard-shortcuts))
@@ -479,11 +462,27 @@
           (str "Keys for keyboard shortcuts must be the same "
                (data/diff (::keyboard-shortcuts keyboard-shortcuts) (::dicts/keyboard-shortcuts keyboard-shortcuts)))))
 
+(defn- resolve-fn
+  "Converts a keyword fn to the actual fn. The fn to be resolved needs to be
+  marked as ^:export for advanced mode"
+  [keyword-fn]
+  (fn []
+    (if-let [resolved-fn (some-> (find-ns-obj (namespace keyword-fn))
+                                 (aget (munge (name keyword-fn))))]
+      (resolved-fn)
+      (throw (ex-info (str "Unable to resolve " keyword-fn " to a fn") {})))))
+
 (defn build-category-map [ks]
   (->> (select-keys all-default-keyboard-shortcuts ks)
        (remove (comp :inactive val))
+       ;; Convert keyword fns to real fns
+       (map (fn [[k v]]
+              [k (if (keyword? (:fn v))
+                   (assoc v :fn (resolve-fn (:fn v)))
+                   v)]))
        (into {})))
 
+;; This is the only var that should be publicly expose :fn functionality
 (defonce ^:large-vars/data-var config
   (atom
    {:shortcut.handler/date-picker