config.cljs 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. (ns frontend.modules.shortcut.config
  2. (:require [clojure.data :as data]
  3. [clojure.string :as string]
  4. [electron.ipc :as ipc]
  5. [frontend.commands :as commands]
  6. [frontend.components.commit :as commit]
  7. [frontend.config :as config]
  8. [frontend.dicts :as dicts]
  9. [frontend.extensions.pdf.utils :as pdf-utils]
  10. [frontend.extensions.srs.handler :as srs]
  11. [frontend.handler.config :as config-handler]
  12. [frontend.handler.editor :as editor-handler]
  13. [frontend.handler.export :as export-handler]
  14. [frontend.handler.history :as history]
  15. [frontend.handler.journal :as journal-handler]
  16. [frontend.handler.jump :as jump-handler]
  17. [frontend.handler.notification :as notification]
  18. [frontend.handler.page :as page-handler]
  19. [frontend.handler.paste :as paste-handler]
  20. [frontend.handler.plugin :as plugin-handler]
  21. [frontend.handler.plugin-config :as plugin-config-handler]
  22. [frontend.handler.repo :as repo-handler]
  23. [frontend.handler.route :as route-handler]
  24. [frontend.handler.search :as search-handler]
  25. [frontend.handler.ui :as ui-handler]
  26. [frontend.handler.whiteboard :as whiteboard-handler]
  27. [frontend.handler.window :as window-handler]
  28. [frontend.modules.shortcut.before :as m]
  29. [frontend.state :as state]
  30. [frontend.util :refer [mac?] :as util]
  31. [medley.core :as medley]
  32. [promesa.core :as p]))
  33. (defn- search
  34. [mode]
  35. (editor-handler/escape-editing {:select? true})
  36. (if (state/get-search-mode)
  37. (js/setTimeout #(route-handler/go-to-search! mode) 128)
  38. (route-handler/go-to-search! mode)))
  39. ;; TODO: Namespace all-default-keyboard-shortcuts keys with `:command` e.g.
  40. ;; `:command.date-picker/complete`. They are namespaced in translation but
  41. ;; almost everywhere else they are not which could cause needless conflicts
  42. ;; with other config keys
  43. ;; To add a new entry to this map, first add it here and then a description for
  44. ;; it under :commands keys of frontend.dicts.en/dicts
  45. ;; A shortcut is a map with the following keys:
  46. ;; * :binding - A string representing a keybinding. Avoid using single letter
  47. ;; shortcuts to allow chords that start with those characters
  48. ;; * :fn - Fn or a qualified keyword that represents a fn
  49. ;; * :inactive - Optional boolean to disable a shortcut for certain conditions
  50. ;; e.g. a given platform or feature condition
  51. ;; * :file-graph? - Optional boolean to identify a command to only be run in file graphs
  52. ;; and warned gracefully in db graphs
  53. (def ^:large-vars/data-var all-built-in-keyboard-shortcuts
  54. {:pdf/previous-page {:binding "alt+p"
  55. :fn pdf-utils/prev-page}
  56. :pdf/next-page {:binding "alt+n"
  57. :fn pdf-utils/next-page}
  58. :pdf/close {:binding "alt+x"
  59. :fn #(state/set-state! :pdf/current nil)}
  60. :pdf/find {:binding "alt+f"
  61. :fn pdf-utils/open-finder}
  62. :whiteboard/select {:binding ["1" "w s"]
  63. :fn #(.selectTool ^js (state/active-tldraw-app) "select")}
  64. :whiteboard/pan {:binding ["2" "w p"]
  65. :fn #(.selectTool ^js (state/active-tldraw-app) "move")}
  66. :whiteboard/portal {:binding ["3" "w b"]
  67. :fn #(.selectTool ^js (state/active-tldraw-app) "logseq-portal")}
  68. :whiteboard/pencil {:binding ["4" "w d"]
  69. :fn #(.selectTool ^js (state/active-tldraw-app) "pencil")}
  70. :whiteboard/highlighter {:binding ["5" "w h"]
  71. :fn #(.selectTool ^js (state/active-tldraw-app) "highlighter")}
  72. :whiteboard/eraser {:binding ["6" "w e"]
  73. :fn #(.selectTool ^js (state/active-tldraw-app) "erase")}
  74. :whiteboard/connector {:binding ["7" "w c"]
  75. :fn #(.selectTool ^js (state/active-tldraw-app) "line")}
  76. :whiteboard/text {:binding ["8" "w t"]
  77. :fn #(.selectTool ^js (state/active-tldraw-app) "text")}
  78. :whiteboard/rectangle {:binding ["9" "w r"]
  79. :fn #(.selectTool ^js (state/active-tldraw-app) "box")}
  80. :whiteboard/ellipse {:binding ["o" "w o"]
  81. :fn #(.selectTool ^js (state/active-tldraw-app) "ellipse")}
  82. :whiteboard/reset-zoom {:binding "shift+0"
  83. :fn #(.resetZoom (.-api ^js (state/active-tldraw-app)))}
  84. :whiteboard/zoom-to-fit {:binding "shift+1"
  85. :fn #(.zoomToFit (.-api ^js (state/active-tldraw-app)))}
  86. :whiteboard/zoom-to-selection {:binding "shift+2"
  87. :fn #(.zoomToSelection (.-api ^js (state/active-tldraw-app)))}
  88. :whiteboard/zoom-out {:binding "shift+dash"
  89. :fn #(.zoomOut (.-api ^js (state/active-tldraw-app)) false)}
  90. :whiteboard/zoom-in {:binding "shift+equals"
  91. :fn #(.zoomIn (.-api ^js (state/active-tldraw-app)) false)}
  92. :whiteboard/send-backward {:binding "open-square-bracket"
  93. :fn #(.sendBackward ^js (state/active-tldraw-app))}
  94. :whiteboard/send-to-back {:binding "shift+open-square-bracket"
  95. :fn #(.sendToBack ^js (state/active-tldraw-app))}
  96. :whiteboard/bring-forward {:binding "close-square-bracket"
  97. :fn #(.bringForward ^js (state/active-tldraw-app))}
  98. :whiteboard/bring-to-front {:binding "shift+close-square-bracket"
  99. :fn #(.bringToFront ^js (state/active-tldraw-app))}
  100. :whiteboard/lock {:binding "mod+l"
  101. :fn #(.setLocked ^js (state/active-tldraw-app) true)}
  102. :whiteboard/unlock {:binding "mod+shift+l"
  103. :fn #(.setLocked ^js (state/active-tldraw-app) false)}
  104. :whiteboard/group {:binding "mod+g"
  105. :fn #(.doGroup (.-api ^js (state/active-tldraw-app)))}
  106. :whiteboard/ungroup {:binding "mod+shift+g"
  107. :fn #(.unGroup (.-api ^js (state/active-tldraw-app)))}
  108. :whiteboard/toggle-grid {:binding "t g"
  109. :fn #(.toggleGrid (.-api ^js (state/active-tldraw-app)))}
  110. :whiteboard/clone-right {:binding (if mac? "ctrl+shift+right" "alt+right")
  111. :fn #(.clone (.-api ^js (state/active-tldraw-app)) "right")}
  112. :whiteboard/clone-left {:binding (if mac? "ctrl+shift+left" "alt+left")
  113. :fn #(.clone (.-api ^js (state/active-tldraw-app)) "left")}
  114. :whiteboard/clone-up {:binding (if mac? "ctrl+shift+up" "alt+up")
  115. :fn #(.clone (.-api ^js (state/active-tldraw-app)) "up")}
  116. :whiteboard/clone-down {:binding (if mac? "ctrl+shift+down" "alt+down")
  117. :fn #(.clone (.-api ^js (state/active-tldraw-app)) "down")}
  118. :auto-complete/complete {:binding "enter"
  119. :fn ui-handler/auto-complete-complete}
  120. :auto-complete/prev {:binding ["up" "ctrl+p"]
  121. :fn ui-handler/auto-complete-prev}
  122. :auto-complete/next {:binding ["down" "ctrl+n"]
  123. :fn ui-handler/auto-complete-next}
  124. :auto-complete/shift-complete {:binding "shift+enter"
  125. :fn ui-handler/auto-complete-shift-complete}
  126. :auto-complete/meta-complete {:binding "mod+enter"
  127. :fn (fn [state e]
  128. (ui-handler/auto-complete-complete state e))}
  129. :cards/toggle-answers {:binding "s"
  130. :fn srs/toggle-answers}
  131. :cards/next-card {:binding "n"
  132. :fn srs/next-card}
  133. :cards/forgotten {:binding "f"
  134. :fn srs/forgotten}
  135. :cards/remembered {:binding "r"
  136. :fn srs/remembered}
  137. :cards/recall {:binding "t"
  138. :fn srs/recall}
  139. :cards/again {:binding "1"
  140. :fn srs/card-again}
  141. :cards/hard {:binding "2"
  142. :fn srs/card-hard}
  143. :cards/good {:binding "3"
  144. :fn srs/card-good}
  145. :cards/easy {:binding "4"
  146. :fn srs/card-easy}
  147. :editor/escape-editing {:binding []
  148. :fn (fn [_ _]
  149. (editor-handler/escape-editing))}
  150. :editor/backspace {:binding "backspace"
  151. :fn editor-handler/editor-backspace}
  152. :editor/delete {:binding "delete"
  153. :fn editor-handler/editor-delete}
  154. :editor/new-block {:binding "enter"
  155. :fn editor-handler/keydown-new-block-handler}
  156. :editor/new-line {:binding "shift+enter"
  157. :fn editor-handler/keydown-new-line-handler}
  158. :editor/new-whiteboard {:binding "n w"
  159. :fn (fn []
  160. (when-not (config/db-based-graph? (state/get-current-repo))
  161. (whiteboard-handler/<create-new-whiteboard-and-redirect!)))}
  162. :editor/follow-link {:binding "mod+o"
  163. :fn editor-handler/follow-link-under-cursor!}
  164. :editor/open-link-in-sidebar {:binding "mod+shift+o"
  165. :fn editor-handler/open-link-in-sidebar!}
  166. :editor/bold {:binding "mod+b"
  167. :fn editor-handler/bold-format!}
  168. :editor/italics {:binding "mod+i"
  169. :fn editor-handler/italics-format!}
  170. :editor/highlight {:binding "mod+shift+h"
  171. :fn editor-handler/highlight-format!}
  172. :editor/strike-through {:binding "mod+shift+s"
  173. :fn editor-handler/strike-through-format!}
  174. :editor/clear-block {:binding (if mac? "ctrl+l" "alt+l")
  175. :fn editor-handler/clear-block-content!}
  176. :editor/kill-line-before {:binding (if mac? "ctrl+u" "alt+u")
  177. :fn editor-handler/kill-line-before!}
  178. :editor/kill-line-after {:binding (if mac? false "alt+k")
  179. :fn editor-handler/kill-line-after!}
  180. :editor/beginning-of-block {:binding (if mac? false "alt+a")
  181. :fn editor-handler/beginning-of-block}
  182. :editor/end-of-block {:binding (if mac? false "alt+e")
  183. :fn editor-handler/end-of-block}
  184. :editor/forward-word {:binding (if mac? "ctrl+shift+f" "alt+f")
  185. :fn editor-handler/cursor-forward-word}
  186. :editor/backward-word {:binding (if mac? "ctrl+shift+b" "alt+b")
  187. :fn editor-handler/cursor-backward-word}
  188. :editor/forward-kill-word {:binding (if mac? "ctrl+w" "alt+d")
  189. :fn editor-handler/forward-kill-word}
  190. :editor/backward-kill-word {:binding (if mac? false "alt+w")
  191. :fn editor-handler/backward-kill-word}
  192. :editor/replace-block-reference-at-point {:binding "mod+shift+r"
  193. :fn editor-handler/replace-block-reference-with-content-at-point}
  194. :editor/copy-embed {:binding "mod+e"
  195. :fn editor-handler/copy-current-block-embed}
  196. :editor/paste-text-in-one-block-at-point {:binding "mod+shift+v"
  197. :fn paste-handler/editor-on-paste-raw!}
  198. :editor/insert-youtube-timestamp {:binding "mod+shift+y"
  199. :fn commands/insert-youtube-timestamp}
  200. :editor/cycle-todo {:binding "mod+enter"
  201. :fn editor-handler/cycle-todo!}
  202. :editor/up {:binding ["up" "ctrl+p"]
  203. :fn (editor-handler/shortcut-up-down :up)}
  204. :editor/down {:binding ["down" "ctrl+n"]
  205. :fn (editor-handler/shortcut-up-down :down)}
  206. :editor/left {:binding "left"
  207. :fn (editor-handler/shortcut-left-right :left)}
  208. :editor/right {:binding "right"
  209. :fn (editor-handler/shortcut-left-right :right)}
  210. :editor/move-block-up {:binding (if mac? "mod+shift+up" "alt+shift+up")
  211. :fn (editor-handler/move-up-down true)}
  212. :editor/move-block-down {:binding (if mac? "mod+shift+down" "alt+shift+down")
  213. :fn (editor-handler/move-up-down false)}
  214. :editor/open-edit {:binding "enter"
  215. :fn (fn [e]
  216. (editor-handler/open-selected-block! :right e))}
  217. :editor/open-selected-blocks-in-sidebar {:binding "shift+enter"
  218. :fn editor-handler/open-selected-blocks-in-sidebar!}
  219. :editor/select-block-up {:binding "alt+up"
  220. :fn (editor-handler/on-select-block :up)}
  221. :editor/select-block-down {:binding "alt+down"
  222. :fn (editor-handler/on-select-block :down)}
  223. :editor/select-up {:binding "shift+up"
  224. :fn (editor-handler/shortcut-select-up-down :up)}
  225. :editor/select-down {:binding "shift+down"
  226. :fn (editor-handler/shortcut-select-up-down :down)}
  227. :editor/delete-selection {:binding ["backspace" "delete"]
  228. :fn editor-handler/delete-selection}
  229. :editor/expand-block-children {:binding "mod+down"
  230. :fn editor-handler/expand!}
  231. :editor/collapse-block-children {:binding "mod+up"
  232. :fn editor-handler/collapse!}
  233. :editor/toggle-block-children {:binding "mod+;"
  234. :fn editor-handler/toggle-collapse!}
  235. :editor/indent {:binding "tab"
  236. :fn (editor-handler/keydown-tab-handler :right)}
  237. :editor/outdent {:binding "shift+tab"
  238. :fn (editor-handler/keydown-tab-handler :left)}
  239. :editor/copy {:binding "mod+c"
  240. :fn editor-handler/shortcut-copy}
  241. :editor/copy-text {:binding "mod+shift+c"
  242. :fn editor-handler/shortcut-copy-text}
  243. :editor/cut {:binding "mod+x"
  244. :fn editor-handler/shortcut-cut}
  245. :editor/undo {:binding "mod+z"
  246. :fn history/undo!}
  247. :editor/redo {:binding ["mod+shift+z" "mod+y"]
  248. :fn history/redo!}
  249. :editor/insert-link {:binding "mod+l"
  250. :fn #(editor-handler/html-link-format!)}
  251. :editor/select-all-blocks {:binding "mod+shift+a"
  252. :fn editor-handler/select-all-blocks!}
  253. :editor/select-parent {:binding "mod+a"
  254. :fn editor-handler/select-parent}
  255. :editor/zoom-in {:binding (if mac? ["mod+." "mod+shift+."] "alt+right") ; FIXME: mod+. not works on Chrome
  256. :fn editor-handler/zoom-in!}
  257. :editor/zoom-out {:binding (if mac? "mod+," "alt+left")
  258. :fn editor-handler/zoom-out!}
  259. :editor/toggle-number-list {:binding "t n"
  260. :fn #(state/pub-event! [:editor/toggle-own-number-list (state/get-selection-block-ids)])}
  261. :editor/add-property {:binding (if mac? "mod+p" "ctrl+alt+p")
  262. :db-graph? true
  263. :fn (fn [e]
  264. (when e (util/stop e))
  265. (state/pub-event! [:editor/new-property {}]))}
  266. :editor/add-property-deadline {:binding "p d"
  267. :db-graph? true
  268. :selection? true
  269. :fn (fn []
  270. (state/pub-event! [:editor/new-property {:property-key "Deadline"}]))}
  271. :editor/add-property-status {:binding "p s"
  272. :db-graph? true
  273. :selection? true
  274. :fn (fn []
  275. (state/pub-event! [:editor/new-property {:property-key "Status"}]))}
  276. :editor/add-property-priority {:binding "p p"
  277. :db-graph? true
  278. :selection? true
  279. :fn (fn []
  280. (state/pub-event! [:editor/new-property {:property-key "Priority"}]))}
  281. :editor/add-property-icon {:binding "p i"
  282. :db-graph? true
  283. :selection? true
  284. :fn (fn []
  285. (state/pub-event! [:editor/new-property {:property-key "Icon"}]))}
  286. :editor/toggle-display-all-properties {:binding "p t"
  287. :db-graph? true
  288. :fn ui-handler/toggle-show-empty-hidden-properties!}
  289. :ui/toggle-brackets {:binding "t b"
  290. :fn config-handler/toggle-ui-show-brackets!}
  291. :go/search {:binding "mod+k"
  292. :fn #(search :global)}
  293. :go/search-themes {:binding "mod+shift+i"
  294. :fn #(search :themes)}
  295. :command-palette/toggle {:binding "mod+shift+p"
  296. :fn #(search :commands)}
  297. :go/search-in-page {:binding "mod+shift+k"
  298. :fn #(search :current-page)}
  299. :go/electron-find-in-page {:binding "mod+f"
  300. :inactive (not (util/electron?))
  301. :fn #(search-handler/open-find-in-page!)}
  302. :go/electron-jump-to-the-next {:binding ["enter" "mod+g"]
  303. :inactive (not (util/electron?))
  304. :fn #(search-handler/loop-find-in-page! false)}
  305. :go/electron-jump-to-the-previous {:binding ["shift+enter" "mod+shift+g"]
  306. :inactive (not (util/electron?))
  307. :fn #(search-handler/loop-find-in-page! true)}
  308. :go/journals {:binding "g j"
  309. :fn route-handler/go-to-journals!}
  310. :go/backward {:binding "mod+open-square-bracket"
  311. :fn (fn [_] (js/window.history.back))}
  312. :go/forward {:binding "mod+close-square-bracket"
  313. :fn (fn [_] (js/window.history.forward))}
  314. :search/re-index {:binding "mod+c mod+s"
  315. :fn (fn [_] (search-handler/rebuild-indices! true))}
  316. :sidebar/open-today-page {:binding (if mac? "mod+shift+j" "alt+shift+j")
  317. :fn page-handler/open-today-in-sidebar}
  318. :sidebar/close-top {:binding "c t"
  319. :fn #(state/sidebar-remove-block! 0)}
  320. :sidebar/clear {:binding "mod+c mod+c"
  321. :fn #(do
  322. (state/clear-sidebar-blocks!)
  323. (state/hide-right-sidebar!))}
  324. :misc/copy {:binding "mod+c"
  325. :fn (fn [] (js/document.execCommand "copy"))}
  326. :graph/export-as-html {:fn #(export-handler/download-repo-as-html!
  327. (state/get-current-repo))
  328. :binding []}
  329. :graph/open {:fn #(do
  330. (editor-handler/escape-editing)
  331. (state/pub-event! [:dialog-select/graph-open]))
  332. :binding "alt+shift+g"}
  333. :graph/remove {:fn #(do
  334. (editor-handler/escape-editing)
  335. (state/pub-event! [:dialog-select/graph-remove]))
  336. :binding []}
  337. :graph/add {:fn (fn [] (route-handler/redirect! {:to :graphs}))
  338. :binding []}
  339. :graph/db-add {:fn #(state/pub-event! [:graph/new-db-graph])
  340. :binding false}
  341. :graph/db-save {:fn #(state/pub-event! [:graph/save-db-to-disk])
  342. :inactive (not (util/electron?))
  343. :binding "mod+s"}
  344. :graph/re-index {:fn (fn []
  345. (p/let [multiple-windows? (ipc/ipc "graphHasMultipleWindows" (state/get-current-repo))]
  346. (state/pub-event! [:graph/ask-for-re-index (atom multiple-windows?) nil])))
  347. :file-graph? true
  348. :binding []}
  349. :command/run {:binding "mod+shift+1"
  350. :inactive (not (util/electron?))
  351. :fn #(do
  352. (editor-handler/escape-editing {:select? true})
  353. (state/pub-event! [:command/run]))}
  354. :go/home {:binding "g h"
  355. :fn #(route-handler/redirect-to-home!)}
  356. :go/all-pages {:binding "g a"
  357. :fn route-handler/redirect-to-all-pages!}
  358. :go/graph-view {:binding "g g"
  359. :fn route-handler/redirect-to-graph-view!}
  360. :go/all-graphs {:binding "g shift+g"
  361. :fn route-handler/redirect-to-all-graphs}
  362. :go/whiteboards {:binding "g w"
  363. :fn route-handler/redirect-to-whiteboard-dashboard!}
  364. :go/keyboard-shortcuts {:binding "g s"
  365. :fn #(state/pub-event! [:modal/keymap])}
  366. :go/tomorrow {:binding "g t"
  367. :fn journal-handler/go-to-tomorrow!}
  368. :go/next-journal {:binding "g n"
  369. :fn journal-handler/go-to-next-journal!}
  370. :go/prev-journal {:binding "g p"
  371. :fn journal-handler/go-to-prev-journal!}
  372. :go/flashcards {:binding ["g f" "t c"]
  373. :fn ui-handler/toggle-cards!}
  374. :ui/toggle-document-mode {:binding "t d"
  375. :fn state/toggle-document-mode!}
  376. :ui/highlight-recent-blocks {:fn state/toggle-highlight-recent-blocks!}
  377. :ui/toggle-settings {:binding (if mac? ["t s" "mod+,"] "t s")
  378. :fn ui-handler/toggle-settings-modal!}
  379. :ui/toggle-right-sidebar {:binding "t r"
  380. :fn ui-handler/toggle-right-sidebar!}
  381. :ui/toggle-left-sidebar {:binding "t l"
  382. :fn state/toggle-left-sidebar!}
  383. :ui/toggle-help {:binding "shift+/"
  384. :fn ui-handler/toggle-help!}
  385. :ui/toggle-theme {:binding "t t"
  386. :fn state/toggle-theme!}
  387. :ui/toggle-contents {:binding "alt+shift+c"
  388. :fn ui-handler/toggle-contents!}
  389. :command/toggle-favorite {:binding "mod+shift+f"
  390. :fn page-handler/toggle-favorite!}
  391. :editor/jump {:binding "mod+j"
  392. :fn jump-handler/jump-to}
  393. :editor/open-file-in-default-app {:binding "mod+d mod+a"
  394. :inactive (not (util/electron?))
  395. :file-graph? true
  396. :fn page-handler/open-file-in-default-app}
  397. :editor/open-file-in-directory {:binding "mod+d mod+i"
  398. :inactive (not (util/electron?))
  399. :file-graph? true
  400. :fn page-handler/open-file-in-directory}
  401. :editor/copy-current-file {:binding false
  402. :inactive (not (util/electron?))
  403. :file-graph? true
  404. :fn page-handler/copy-current-file}
  405. :editor/copy-page-url {:binding []
  406. :inactive (not (util/electron?))
  407. :fn #(page-handler/copy-page-url)}
  408. :window/close {:binding "mod+w"
  409. :inactive (not (util/electron?))
  410. :fn window-handler/close!}
  411. :ui/toggle-wide-mode {:binding "t w"
  412. :fn ui-handler/toggle-wide-mode!}
  413. :ui/select-theme-color {:binding "t i"
  414. :fn #(plugin-handler/show-themes-modal! true)}
  415. :ui/goto-plugins {:binding "t p"
  416. :inactive (not config/lsp-enabled?)
  417. :fn plugin-handler/goto-plugins-dashboard!}
  418. :ui/install-plugins-from-file {:binding []
  419. :inactive (not (config/plugin-config-enabled?))
  420. :fn plugin-config-handler/open-replace-plugins-modal}
  421. :ui/install-plugin-from-github {:binding []
  422. :inactive (or (not config/lsp-enabled?) (not (util/electron?)))
  423. :fn plugin-config-handler/open-install-plugin-from-github-modal}
  424. :ui/clear-all-notifications {:binding []
  425. :fn :frontend.handler.notification/clear-all!}
  426. :editor/toggle-open-blocks {:binding "t o"
  427. :fn editor-handler/toggle-open!}
  428. :ui/customize-appearance {:binding "c c"
  429. :fn #(state/pub-event! [:ui/toggle-appearance])}
  430. :git/commit {:binding "mod+g c"
  431. :inactive (not (util/electron?))
  432. :fn commit/show-commit-modal!}
  433. :dev/fix-broken-graph {:binding []
  434. :db-graph? true
  435. :fn #(repo-handler/fix-broken-graph! (state/get-current-repo))}
  436. :dev/gc-graph {:binding []
  437. :inactive (not (state/developer-mode?))
  438. :fn #(repo-handler/gc-graph! (state/get-current-repo))}
  439. :dev/replace-graph-with-db-file {:binding []
  440. :inactive (or (not (util/electron?)) (not (state/developer-mode?)))
  441. :fn :frontend.handler.common.developer/replace-graph-with-db-file}
  442. :dev/show-block-data {:binding []
  443. :inactive (not (state/developer-mode?))
  444. :fn :frontend.handler.common.developer/show-block-data}
  445. :dev/show-block-ast {:binding []
  446. :inactive (not (state/developer-mode?))
  447. :fn :frontend.handler.common.developer/show-block-ast}
  448. :dev/show-page-data {:binding []
  449. :inactive (not (state/developer-mode?))
  450. :fn :frontend.handler.common.developer/show-page-data}
  451. :dev/show-page-ast {:binding []
  452. :inactive (not (state/developer-mode?))
  453. :fn :frontend.handler.common.developer/show-page-ast}
  454. :misc/export-block-data {:binding []
  455. :db-graph? true
  456. :fn :frontend.handler.db-based.export/export-block-data}
  457. :misc/export-page-data {:binding []
  458. :db-graph? true
  459. :fn :frontend.handler.db-based.export/export-page-data}
  460. :misc/export-graph-ontology-data {:binding []
  461. :db-graph? true
  462. :fn :frontend.handler.db-based.export/export-graph-ontology-data}
  463. :misc/import-edn-data {:binding []
  464. :db-graph? true
  465. :fn :frontend.handler.db-based.import/import-edn-data-dialog}
  466. :dev/validate-db {:binding []
  467. :db-graph? true
  468. :inactive (not (state/developer-mode?))
  469. :fn :frontend.handler.common.developer/validate-db}
  470. :dev/rtc-stop {:binding []
  471. :db-graph? true
  472. :inactive (not (state/developer-mode?))
  473. :fn :frontend.handler.common.developer/rtc-stop}
  474. :dev/rtc-start {:binding []
  475. :db-graph? true
  476. :inactive (not (state/developer-mode?))
  477. :fn :frontend.handler.common.developer/rtc-start}})
  478. (let [keyboard-commands
  479. {::commands (set (keys all-built-in-keyboard-shortcuts))
  480. ::dicts/commands dicts/abbreviated-commands}]
  481. (assert (= (::commands keyboard-commands) (::dicts/commands keyboard-commands))
  482. (str "Keyboard commands must have an english label"
  483. (data/diff (::commands keyboard-commands) (::commands keyboard-commands)))))
  484. (defn- resolve-fn
  485. "Converts a keyword fn to the actual fn. The fn to be resolved needs to be
  486. marked as ^:export for advanced mode"
  487. [keyword-fn]
  488. (fn []
  489. (if-let [resolved-fn (some-> (namespace keyword-fn)
  490. ;; handle reserved words
  491. (string/replace-first ".export" ".export$")
  492. (string/replace-first ".import" ".import$")
  493. find-ns-obj
  494. (aget (munge (name keyword-fn))))]
  495. (resolved-fn)
  496. (throw (ex-info (str "Unable to resolve " keyword-fn " to a fn") {})))))
  497. (defn- wrap-fn-with-db-graph-only-warning
  498. "Wraps DB graph only commands so they are only run in DB graphs and warned
  499. when in file graphs"
  500. [f]
  501. (fn []
  502. (if (config/db-based-graph? (state/get-current-repo))
  503. (f)
  504. (notification/show! "This command is only for DB graphs." :warning true nil 3000))))
  505. (defn- wrap-fn-with-file-graph-only-warning
  506. "Wraps file graph only commands so they are only run in file graphs and warned
  507. when in DB graphs"
  508. [f]
  509. (fn []
  510. (if (config/db-based-graph? (state/get-current-repo))
  511. (notification/show! "This command is only for file graphs." :warning true nil 3000)
  512. (f))))
  513. (defn build-category-map [ks]
  514. (->> (if (sequential? ks)
  515. ks (let [{:keys [ns includes excludes]} ks]
  516. (->> (keys all-built-in-keyboard-shortcuts)
  517. (filter (fn [k]
  518. (and (or (and ns (keyword? k)
  519. (contains? (->> (if (seqable? ns) (seq ns) [ns]) (map #(name %)) (set))
  520. (namespace k)))
  521. (and includes (contains? (set includes) k)))
  522. (if (not (seq excludes)) true (not (contains? (set excludes) k)))))))))
  523. (select-keys all-built-in-keyboard-shortcuts)
  524. (remove (comp :inactive val))
  525. ;; Convert keyword fns to real fns
  526. (map (fn [[k v]]
  527. [k (if (keyword? (:fn v))
  528. (assoc v :fn (resolve-fn (:fn v)))
  529. v)]))
  530. (map (fn [[k v]]
  531. [k (cond (:file-graph? v)
  532. (update v :fn wrap-fn-with-file-graph-only-warning)
  533. (:db-graph? v)
  534. (update v :fn wrap-fn-with-db-graph-only-warning)
  535. :else
  536. v)]))
  537. (into {})))
  538. ;; This is the only var that should be publicly expose :fn functionality
  539. (defonce ^:large-vars/data-var *config
  540. (atom
  541. {:shortcut.handler/date-picker
  542. (build-category-map {:ns :date-picker})
  543. :shortcut.handler/pdf
  544. (-> (build-category-map {:ns :pdf})
  545. (with-meta {:before m/enable-when-not-editing-mode!}))
  546. :shortcut.handler/whiteboard
  547. (-> (build-category-map {:ns :whiteboard})
  548. (with-meta {:before m/enable-when-not-editing-mode!}))
  549. :shortcut.handler/auto-complete
  550. (build-category-map {:ns :auto-complete})
  551. :shortcut.handler/cards
  552. (-> (build-category-map {:ns :cards})
  553. (with-meta {:before m/enable-when-not-editing-mode!}))
  554. :shortcut.handler/block-editing-only
  555. (-> (build-category-map
  556. [:editor/escape-editing
  557. :editor/backspace
  558. :editor/delete
  559. :editor/zoom-in
  560. :editor/zoom-out
  561. :editor/new-block
  562. :editor/new-line
  563. :editor/follow-link
  564. :editor/open-link-in-sidebar
  565. :editor/bold
  566. :editor/italics
  567. :editor/highlight
  568. :editor/strike-through
  569. :editor/clear-block
  570. :editor/kill-line-before
  571. :editor/kill-line-after
  572. :editor/beginning-of-block
  573. :editor/end-of-block
  574. :editor/forward-word
  575. :editor/backward-word
  576. :editor/forward-kill-word
  577. :editor/backward-kill-word
  578. :editor/replace-block-reference-at-point
  579. :editor/copy-embed
  580. :editor/paste-text-in-one-block-at-point
  581. :editor/insert-youtube-timestamp])
  582. (with-meta {:before m/enable-when-editing-mode!}))
  583. :shortcut.handler/editor-global
  584. (-> (build-category-map
  585. [:graph/export-as-html
  586. :graph/open
  587. :graph/remove
  588. :graph/add
  589. :graph/db-add
  590. :graph/db-save
  591. :graph/re-index
  592. :editor/cycle-todo
  593. :editor/up
  594. :editor/down
  595. :editor/left
  596. :editor/right
  597. :editor/select-up
  598. :editor/select-down
  599. :editor/move-block-up
  600. :editor/move-block-down
  601. :editor/open-edit
  602. :editor/open-selected-blocks-in-sidebar
  603. :editor/select-block-up
  604. :editor/select-block-down
  605. :editor/select-parent
  606. :editor/delete-selection
  607. :editor/expand-block-children
  608. :editor/collapse-block-children
  609. :editor/toggle-block-children
  610. :editor/indent
  611. :editor/outdent
  612. :editor/copy
  613. :editor/copy-text
  614. :editor/cut
  615. :command/toggle-favorite
  616. :editor/jump])
  617. (with-meta {:before m/enable-when-not-component-editing!}))
  618. :shortcut.handler/global-prevent-default
  619. (-> (build-category-map
  620. [:editor/insert-link
  621. :editor/select-all-blocks
  622. :editor/toggle-number-list
  623. :editor/undo
  624. :editor/redo
  625. :ui/toggle-brackets
  626. :go/search-in-page
  627. :go/search
  628. :go/search-themes
  629. :go/electron-find-in-page
  630. :go/electron-jump-to-the-next
  631. :go/electron-jump-to-the-previous
  632. :go/backward
  633. :go/forward
  634. :search/re-index
  635. :sidebar/open-today-page
  636. :sidebar/clear
  637. :command/run
  638. :command-palette/toggle
  639. :editor/add-property
  640. :window/close])
  641. (with-meta {:before m/prevent-default-behavior}))
  642. :shortcut.handler/global-non-editing-only
  643. (-> (build-category-map
  644. [:go/home
  645. :go/journals
  646. :go/all-pages
  647. :go/flashcards
  648. :go/graph-view
  649. :go/all-graphs
  650. :go/whiteboards
  651. :go/keyboard-shortcuts
  652. :go/tomorrow
  653. :go/next-journal
  654. :go/prev-journal
  655. :ui/toggle-document-mode
  656. :ui/highlight-recent-blocks
  657. :ui/toggle-settings
  658. :ui/toggle-right-sidebar
  659. :ui/toggle-left-sidebar
  660. :ui/toggle-help
  661. :ui/toggle-theme
  662. :ui/toggle-contents
  663. :editor/open-file-in-default-app
  664. :editor/open-file-in-directory
  665. :editor/copy-current-file
  666. :editor/copy-page-url
  667. :editor/new-whiteboard
  668. :editor/add-property-deadline
  669. :editor/add-property-status
  670. :editor/add-property-priority
  671. :editor/add-property-icon
  672. :editor/toggle-display-all-properties
  673. :ui/toggle-wide-mode
  674. :ui/select-theme-color
  675. :ui/goto-plugins
  676. :ui/install-plugins-from-file
  677. :ui/install-plugin-from-github
  678. :editor/toggle-open-blocks
  679. :ui/clear-all-notifications
  680. :git/commit
  681. :sidebar/close-top
  682. :misc/export-block-data
  683. :misc/export-page-data
  684. :misc/export-graph-ontology-data
  685. :misc/import-edn-data
  686. :dev/show-block-data
  687. :dev/show-block-ast
  688. :dev/show-page-data
  689. :dev/show-page-ast
  690. :dev/replace-graph-with-db-file
  691. :dev/validate-db
  692. :dev/fix-broken-graph
  693. :dev/gc-graph
  694. :dev/rtc-stop
  695. :dev/rtc-start
  696. :ui/customize-appearance])
  697. (with-meta {:before m/enable-when-not-editing-mode!}))
  698. :shortcut.handler/misc
  699. ;; always overrides the copy due to "mod+c mod+s"
  700. {:misc/copy (:misc/copy all-built-in-keyboard-shortcuts)}}))
  701. ;; To add a new entry to this map, first add it here and then
  702. ;; a description for it in frontend.dicts.en/dicts
  703. ;; Full list of categories for docs purpose
  704. (defonce ^:large-vars/data-var *category
  705. (atom
  706. {:shortcut.category/basics
  707. [:go/search
  708. :go/search-themes
  709. :editor/new-block
  710. :editor/new-line
  711. :editor/indent
  712. :editor/outdent
  713. :editor/select-all-blocks
  714. :editor/select-parent
  715. :go/search-in-page
  716. :command-palette/toggle
  717. :go/electron-find-in-page
  718. :go/electron-jump-to-the-next
  719. :go/electron-jump-to-the-previous
  720. :editor/undo
  721. :editor/redo
  722. :editor/copy
  723. :editor/copy-text
  724. :editor/cut]
  725. :shortcut.category/formatting
  726. [:editor/bold
  727. :editor/insert-link
  728. :editor/italics
  729. :editor/strike-through
  730. :editor/highlight]
  731. :shortcut.category/navigating
  732. [:editor/up
  733. :editor/down
  734. :editor/left
  735. :editor/right
  736. :editor/collapse-block-children
  737. :editor/expand-block-children
  738. :editor/toggle-block-children
  739. :editor/toggle-open-blocks
  740. :editor/jump
  741. :go/backward
  742. :go/forward
  743. :go/home
  744. :go/journals
  745. :go/all-pages
  746. :go/graph-view
  747. :go/all-graphs
  748. :go/whiteboards
  749. :go/flashcards
  750. :go/tomorrow
  751. :go/next-journal
  752. :go/prev-journal
  753. :go/keyboard-shortcuts]
  754. :shortcut.category/block-editing
  755. [:editor/backspace
  756. :editor/delete
  757. :editor/indent
  758. :editor/outdent
  759. :editor/new-block
  760. :editor/new-line
  761. :editor/zoom-in
  762. :editor/zoom-out
  763. :editor/cycle-todo
  764. :editor/follow-link
  765. :editor/open-link-in-sidebar
  766. :editor/move-block-up
  767. :editor/move-block-down
  768. :editor/escape-editing]
  769. :shortcut.category/block-command-editing
  770. [:editor/backspace
  771. :editor/clear-block
  772. :editor/kill-line-before
  773. :editor/kill-line-after
  774. :editor/beginning-of-block
  775. :editor/end-of-block
  776. :editor/forward-word
  777. :editor/backward-word
  778. :editor/forward-kill-word
  779. :editor/backward-kill-word
  780. :editor/replace-block-reference-at-point
  781. :editor/copy-embed
  782. :editor/paste-text-in-one-block-at-point
  783. :editor/select-up
  784. :editor/select-down]
  785. :shortcut.category/block-selection
  786. [:editor/open-edit
  787. :editor/open-selected-blocks-in-sidebar
  788. :editor/select-all-blocks
  789. :editor/select-parent
  790. :editor/select-block-up
  791. :editor/select-block-down
  792. :editor/delete-selection
  793. :editor/add-property
  794. :editor/add-property-deadline
  795. :editor/add-property-status
  796. :editor/add-property-priority
  797. :editor/add-property-icon
  798. :editor/toggle-display-all-properties]
  799. :shortcut.category/toggle
  800. [:ui/toggle-help
  801. :editor/toggle-open-blocks
  802. :editor/toggle-number-list
  803. :ui/toggle-wide-mode
  804. :ui/highlight-recent-blocks
  805. :ui/toggle-brackets
  806. :ui/toggle-theme
  807. :ui/toggle-left-sidebar
  808. :ui/toggle-right-sidebar
  809. :ui/toggle-settings
  810. :ui/toggle-contents
  811. :ui/customize-appearance]
  812. :shortcut.category/whiteboard
  813. [:editor/new-whiteboard
  814. :whiteboard/select
  815. :whiteboard/pan
  816. :whiteboard/portal
  817. :whiteboard/pencil
  818. :whiteboard/highlighter
  819. :whiteboard/eraser
  820. :whiteboard/connector
  821. :whiteboard/text
  822. :whiteboard/rectangle
  823. :whiteboard/ellipse
  824. :whiteboard/reset-zoom
  825. :whiteboard/zoom-to-fit
  826. :whiteboard/zoom-to-selection
  827. :whiteboard/zoom-out
  828. :whiteboard/zoom-in
  829. :whiteboard/send-backward
  830. :whiteboard/send-to-back
  831. :whiteboard/bring-forward
  832. :whiteboard/bring-to-front
  833. :whiteboard/lock
  834. :whiteboard/unlock
  835. :whiteboard/group
  836. :whiteboard/ungroup
  837. :whiteboard/toggle-grid
  838. :whiteboard/clone-left
  839. :whiteboard/clone-right
  840. :whiteboard/clone-top
  841. :whiteboard/clone-bottom]
  842. :shortcut.category/others
  843. [:pdf/previous-page
  844. :pdf/next-page
  845. :pdf/close
  846. :pdf/find
  847. :command/toggle-favorite
  848. :command/run
  849. :graph/export-as-html
  850. :graph/open
  851. :graph/remove
  852. :graph/add
  853. :graph/re-index
  854. :sidebar/close-top
  855. :sidebar/clear
  856. :sidebar/open-today-page
  857. :search/re-index
  858. :editor/insert-youtube-timestamp
  859. :editor/open-file-in-default-app
  860. :editor/open-file-in-directory
  861. :editor/copy-page-url
  862. :window/close
  863. :auto-complete/prev
  864. :auto-complete/next
  865. :auto-complete/complete
  866. :auto-complete/shift-complete
  867. :auto-complete/meta-complete
  868. :git/commit
  869. :misc/export-block-data
  870. :misc/export-page-data
  871. :misc/export-graph-ontology-data
  872. :misc/import-edn-data
  873. :dev/show-block-data
  874. :dev/show-block-ast
  875. :dev/show-page-data
  876. :dev/show-page-ast
  877. :dev/replace-graph-with-db-file
  878. :dev/validate-db
  879. :dev/fix-broken-graph
  880. :dev/gc-graph
  881. :dev/rtc-stop
  882. :dev/rtc-start
  883. :ui/clear-all-notifications]
  884. :shortcut.category/plugins
  885. []}))
  886. (let [category-maps {::category (set (keys @*category))
  887. ::dicts/category dicts/categories}]
  888. (assert (= (::category category-maps) (::dicts/category category-maps))
  889. (str "Keys for category maps must have an english label "
  890. (data/diff (::category category-maps) (::dicts/category category-maps)))))
  891. (defn get-category-shortcuts
  892. "Active list of categories for docs purpose"
  893. [name]
  894. (get @*category name))
  895. (def *shortcut-cmds (atom {}))
  896. (defn add-shortcut!
  897. ([handler-id id shortcut-map] (add-shortcut! handler-id id shortcut-map false))
  898. ([handler-id id shortcut-map config-only?]
  899. (swap! *config assoc-in [handler-id id] shortcut-map)
  900. (when-not config-only?
  901. (swap! *shortcut-cmds assoc id (:cmd shortcut-map))
  902. (let [plugin? (string/starts-with? (str id) ":plugin.")
  903. category (or (:category shortcut-map)
  904. (if plugin?
  905. :shortcut.category/plugins
  906. :shortcut.category/others))]
  907. (swap! *category update category #(conj % id))))))
  908. (defn remove-shortcut!
  909. [handler-id id]
  910. (swap! *config medley/dissoc-in [handler-id id])
  911. (swap! *shortcut-cmds dissoc id)
  912. (doseq [category (keys @*category)]
  913. (swap! *category update category (fn [ids] (remove #(= % id) ids)))))