mirror of
https://github.com/logseq/logseq.git
synced 2026-04-30 08:56:29 +00:00
Simple query builder --------- Co-authored-by: Gabriel Horner <gabriel@logseq.com> Co-authored-by: charlie <xyhp915@qq.com>
115 lines
3.9 KiB
Clojure
115 lines
3.9 KiB
Clojure
(ns frontend.handler.command-palette
|
|
"System-component-like ns for command palette's functionality"
|
|
(:require [cljs.spec.alpha :as s]
|
|
[frontend.modules.shortcut.data-helper :as shortcut-helper]
|
|
[frontend.spec :as spec]
|
|
[frontend.state :as state]
|
|
[lambdaisland.glogi :as log]
|
|
[frontend.storage :as storage]))
|
|
|
|
(s/def :command/id keyword?)
|
|
(s/def :command/desc string?)
|
|
(s/def :command/action fn?)
|
|
(s/def :command/shortcut string?)
|
|
(s/def :command/tag vector?)
|
|
|
|
(s/def :command/command
|
|
(s/keys :req-un [:command/id :command/action]
|
|
;; :command/desc is optional for internal commands since view
|
|
;; checks translation ns first
|
|
:opt-un [:command/desc :command/shortcut :command/tag]))
|
|
|
|
(defn global-shortcut-commands []
|
|
(->> [:shortcut.handler/editor-global
|
|
:shortcut.handler/global-prevent-default
|
|
:shortcut.handler/global-non-editing-only]
|
|
(mapcat shortcut-helper/shortcuts->commands)))
|
|
|
|
(defn get-commands []
|
|
(->> (get @state/state :command-palette/commands)
|
|
(sort-by :id)))
|
|
|
|
(defn get-commands-unique []
|
|
(reduce #(assoc %1 (:id %2) %2) {}
|
|
(get @state/state :command-palette/commands)))
|
|
|
|
(defn history
|
|
([] (or (storage/get "commands-history") []))
|
|
([vals] (storage/set "commands-history" vals)))
|
|
|
|
(defn- assoc-invokes [cmds]
|
|
(let [invokes (->> (history)
|
|
(map :id)
|
|
(frequencies))]
|
|
(mapv (fn [{:keys [id] :as cmd}]
|
|
(if (contains? invokes id)
|
|
(assoc cmd :invokes-count (get invokes id))
|
|
cmd))
|
|
cmds)))
|
|
|
|
(defn add-history [{:keys [id]}]
|
|
(storage/set "commands-history" (conj (history) {:id id :timestamp (.getTime (js/Date.))})))
|
|
|
|
(defn invoke-command [{:keys [action] :as cmd}]
|
|
(add-history cmd)
|
|
(state/close-modal!)
|
|
(action))
|
|
|
|
(defn top-commands [limit]
|
|
(->> (get-commands)
|
|
(assoc-invokes)
|
|
(sort-by :invokes-count)
|
|
(reverse)
|
|
(take limit)))
|
|
|
|
(defn register
|
|
"Register a global command searchable by command palette.
|
|
`id` is defined as a global unique namespaced key :scope/command-name
|
|
`action` must be a zero arity function
|
|
|
|
Example:
|
|
```clojure
|
|
(register
|
|
{:id :document/open-logseq-doc
|
|
:desc \"Document: open Logseq documents\"
|
|
:action (fn [] (js/window.open \"https://docs.logseq.com/\"))})
|
|
```
|
|
|
|
To add i18n support, prefix `id` with command and put that item in dict.
|
|
Example: {:zh-CN {:command.document/open-logseq-doc \"打开文档\"}}"
|
|
[{:keys [id] :as command}]
|
|
(if (:command/shortcut command)
|
|
(log/error :shortcut/missing (str "Shortcut is missing for " (:id command)))
|
|
(try
|
|
(spec/validate :command/command command)
|
|
(let [cmds (get-commands)]
|
|
(if (some (fn [existing-cmd] (= (:id existing-cmd) id)) cmds)
|
|
(log/error :command/register {:msg "Failed to register command. Command with same id already exist"
|
|
:id id})
|
|
(state/set-state! :command-palette/commands (conj cmds command))))
|
|
;; Catch unexpected errors so that subsequent register calls pass
|
|
(catch :default e
|
|
(log/error :command/register {:msg "Unexpectedly failed to register command"
|
|
:id id
|
|
:error (str e)})))))
|
|
|
|
(defn unregister
|
|
[id]
|
|
(let [id (keyword id)
|
|
cmds (get-commands-unique)]
|
|
(when (contains? cmds id)
|
|
(state/set-state! :command-palette/commands (vals (dissoc cmds id)))
|
|
;; clear history
|
|
(history (filter #(not= (:id %) id) (history))))))
|
|
|
|
(defn register-global-shortcut-commands []
|
|
(let [cmds (global-shortcut-commands)]
|
|
(doseq [cmd cmds] (register cmd))))
|
|
|
|
(comment
|
|
;; register custom command example
|
|
(register
|
|
{:id :document/open-logseq-doc
|
|
:desc "Document: open Logseq documents"
|
|
:action (fn [] (js/window.open "https://docs.logseq.com/"))}))
|