data_helper.cljs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. (ns frontend.modules.shortcut.data-helper
  2. (:require [borkdude.rewrite-edn :as rewrite]
  3. [clojure.string :as str]
  4. [frontend.config :as cfg]
  5. [frontend.db :as db]
  6. [frontend.handler.file :as file]
  7. [frontend.modules.shortcut.config :as config]
  8. [frontend.state :as state]
  9. [frontend.util :as util]
  10. [lambdaisland.glogi :as log])
  11. (:import [goog.ui KeyboardShortcutHandler]))
  12. (defonce default-binding
  13. (->> (vals config/default-config)
  14. (into {})
  15. (map (fn [[k {:keys [binding]}]]
  16. {k binding}))
  17. (into {})))
  18. (defn- mod-key [shortcut]
  19. (str/replace shortcut #"(?i)mod"
  20. (if util/mac? "meta" "ctrl")))
  21. (defn shortcut-binding
  22. [id]
  23. (let [shortcut (get (state/shortcuts) id
  24. (get default-binding id))]
  25. (cond
  26. (nil? shortcut)
  27. (log/error :shortcut/binding-not-found {:id id})
  28. (false? shortcut)
  29. (do
  30. (log/debug :shortcut/disabled {:id id})
  31. false)
  32. :else
  33. (->>
  34. (if (string? shortcut)
  35. [shortcut]
  36. shortcut)
  37. (mapv mod-key)))))
  38. ;; returns a vector to preserve order
  39. (defn binding-by-category [name]
  40. (let [dict (->> (vals config/default-config)
  41. (apply merge)
  42. (map (fn [[k _]]
  43. {k {:binding (shortcut-binding k)}}))
  44. (into {}))]
  45. (->> (config/category name)
  46. (mapv (fn [k] [k (k dict)])))))
  47. (defn shortcut-map
  48. ([handler-id]
  49. (shortcut-map handler-id nil))
  50. ([handler-id state]
  51. (let [raw (get config/default-config handler-id)
  52. handler-m (->> raw
  53. (map (fn [[k {:keys [fn]}]]
  54. {k fn}))
  55. (into {}))
  56. before (-> raw meta :before)]
  57. (cond->> handler-m
  58. state (reduce-kv (fn [r k handle-fn]
  59. (assoc r k (partial handle-fn state)))
  60. {})
  61. before (reduce-kv (fn [r k v]
  62. (assoc r k (before v)))
  63. {})))))
  64. (defn decorate-namespace [k]
  65. (let [n (name k)
  66. ns (namespace k)]
  67. (keyword (str "shortcut." ns) n)))
  68. (defn desc-helper []
  69. (->> (vals config/default-config)
  70. (apply merge)
  71. (map (fn [[k {:keys [desc]}]]
  72. {(decorate-namespace k) desc}))
  73. (into {})))
  74. (defn category-helper []
  75. (->> config/category
  76. (map (fn [[k v]]
  77. {k (:doc (meta v))}))
  78. (into {})))
  79. (defn decorate-binding [binding]
  80. (-> binding
  81. (str/replace "mod" (if util/mac? "cmd" "ctrl"))
  82. (str/replace "alt" (if util/mac? "opt" "alt"))
  83. (str/replace "shift+/" "?")
  84. (str/lower-case)))
  85. (defn binding-for-display [k binding]
  86. (cond
  87. (false? binding)
  88. (cond
  89. (and util/mac? (= k :editor/kill-line-after))
  90. "disabled (system default: ctrl+k)"
  91. (and util/mac? (= k :editor/beginning-of-block))
  92. "disabled (system default: ctrl+a)"
  93. (and util/mac? (= k :editor/end-of-block))
  94. "disabled (system default: ctrl+e)"
  95. (and util/mac? (= k :editor/backward-kill-word))
  96. "disabled (system default: opt+delete)"
  97. :else
  98. "disabled")
  99. (string? binding)
  100. (decorate-binding binding)
  101. :else
  102. (->> binding
  103. (map decorate-binding)
  104. (str/join " | "))))
  105. (defn remove-shortcut [k]
  106. (let [repo (state/get-current-repo)
  107. path (cfg/get-config-path)]
  108. (when-let [content (db/get-file-no-sub path)]
  109. (let [result (try
  110. (rewrite/parse-string content)
  111. (catch js/Error e
  112. (println "Parsing config file failed: ")
  113. (js/console.dir e)
  114. {}))
  115. new-result (rewrite/update
  116. result
  117. :shortcuts
  118. #(dissoc (rewrite/sexpr %) k))]
  119. (state/set-config! repo new-result)
  120. (let [new-content (str new-result)]
  121. (file/set-file-content! repo path new-content))))))
  122. (defn get-group
  123. "Given shortcut key, return handler group
  124. eg: :editor/new-line -> :shortcut.handler/block-editing-only"
  125. [k]
  126. (->> config/default-config
  127. (filter (fn [[_ v]] (contains? v k)))
  128. (map key)
  129. (first)))
  130. (defn potential-confilct? [k]
  131. (if-not (shortcut-binding k)
  132. false
  133. (let [handler-id (get-group k)
  134. shortcut-m (shortcut-map handler-id)
  135. bindings (->> (shortcut-binding k)
  136. (map mod-key)
  137. (map KeyboardShortcutHandler/parseStringShortcut)
  138. (map js->clj))
  139. rest-bindings (->> (map key shortcut-m)
  140. (remove #{k})
  141. (map shortcut-binding)
  142. (filter vector?)
  143. (mapcat identity)
  144. (map mod-key)
  145. (map KeyboardShortcutHandler/parseStringShortcut)
  146. (map js->clj))]
  147. (some? (some (fn [b] (some #{b} rest-bindings)) bindings)))))