-
Notifications
You must be signed in to change notification settings - Fork 120
/
rules.clj
269 lines (256 loc) · 12.5 KB
/
rules.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
(ns karabiner-configurator.rules
(:require
[clojure.tools.logging :as log]
[karabiner-configurator.conditions :as conditions]
[karabiner-configurator.keys :as keys]
[karabiner-configurator.froms :as froms]
[karabiner-configurator.tos :as tos]
[karabiner-configurator.data :refer :all]
[karabiner-configurator.misc :refer :all]))
;; <from> section
;; :a | normal key or predefined froms
;; :from-a | predefined froms
;; :!Ca | special modifier key
;; [:a :b] | simultaneous key
;; {...} | fallback to `froms` defination
(defn from-key
"generate normal from key config"
[des from]
(let [result nil
validate-from (assert (or (and (vector? from) (= 2 (count from)) (k? (first from)) (k? (second from)))
(and (keyword? from) (or (k? from) (special-modi-k? from) (nn? (from (:froms conf-data)))))
(map? from))
(str "invalid <from> in main section's " des))
result (if (vector? from)
{:from (froms/parse-from :tmp-from-defination-from-main {:sim from})}
result)
result (if (and (nil? result) (keyword? from) (or (k? from) (special-modi-k? from)))
{:from (froms/parse-from :tmp-from-defination-from-main {:key from})}
result)
result (if (and (nil? result) (contains? (:froms conf-data) from))
{:from (from (:froms conf-data))}
result)
result (if (and (map? from) (nil? result))
{:from (froms/parse-from :tmp-from-defination-from-main from)}
result)]
(assert (nn? result) (str "something wrong while parsing main rule " des))
result))
(defn parse-simple-set-variable
[des vec & [from-condition?]]
(first (tos/parse-to des [{:set vec}])))
(defn rule-parse-keyword [des to]
(cond (pointing-k? to)
(first (tos/parse-to des [{:pkey to}]))
(consumer-k? to)
(first (tos/parse-to des [{:ckey to}]))
(or (special-modi-k? to) (k? to))
(first (tos/parse-to des [{:key to}]))
(contains? (:tos conf-data) to)
(to (:tos conf-data))
:else
(assert false (str
"code shouldn't be here, something wrong while parsing <to> in main section's "
des
". Please check your data and contact the author, so that the author can improve the error message."))))
(defn to-key-vector
[des to prevresult]
(if (conditions/is-simple-set-variable? to)
[(parse-simple-set-variable des to)]
(into []
(flatten
(for [v to] ;; this for only return flatten vector
(do
(assert (or (contains? (:tos conf-data) v)
(k? v)
(special-modi-k? v)
(vector? v)
(string? v)
(map? v))
(str "invalid to defination in main section's " des))
(cond (keyword? v)
(rule-parse-keyword des v)
(and (vector? v) (conditions/is-simple-set-variable? v))
(parse-simple-set-variable des v)
(string? v)
(tos/parse-to des [{:shell v}])
(map? v)
(tos/parse-to des [v]))))))))
(defn process-to-shell-template-vector [to]
(into []
(for [x to]
(if (and (vector? x) (templates? x))
{:shell x}
x))))
;; <to> section
;; :a | normal key or predefined tos
;; :to-a | predefined tos
;; :!Ca | special modifier key
;; "ls" | shell command
;; [:a :b] | multiple normal key
;; ["vi-mode" 1] | set variable, second element in vector isn't keyword
;; ["vi-mode" :a] | shell command then insert a
;; [:launch-template "Mail"] | shell command then insert a
;; ["cd" "ls"] | multeple shell command
;; [["vi-mode" 1] :a] | set variable then insert a
;; [{...}] | fallback to `tos` defination
;; conflict
;; ["cd" "ls"]
;; set_variable to string or two shell_command
;; two shell_command cd & ls, cd && ls
;; ["cd" "ls"] | multeple shell command
;; [{:set ["variable name" "variable value"]}] | set variable's value to string (fallback to `tos` defination)
(defn to-key
"generate to config"
[des to]
(let [result nil
validate-to (assert (or (and (keyword? to) (or (k? to)
(special-modi-k? to)
(contains? (:tos conf-data) to)))
(string? to)
(vector? to)
(map? to))
(str "invalid <to> in main section's " des))
result (if (keyword? to)
(rule-parse-keyword des to))
result (if (nn? result)
(cond (vector? result)
result
:else
[result])
result)
to (if (vector? to) (process-to-shell-template-vector to) to)
result (cond (and (vector? to) (templates? to))
;; (tos/parse-to des [{:shell (apply format (flatten [((first to) (:templates conf-data)) [rest to]]))}])
(tos/parse-to des [{:shell to}])
(vector? to)
(to-key-vector des to result)
(string? to)
(into [] (tos/parse-to des [{:shell to}]))
(map? to)
(into [] (tos/parse-to des [to]))
:else result)]
result))
(defn merge-multiple-device-conditions
[vec]
(update-conf-data (assoc conf-data :devices (dissoc (:devices conf-data) :temp-device)))
(let [devices-list (for [item vec
:when (and (keyword? item) (devices? item))
:let [this-device-vec (item (:devices conf-data))
temp-device-vec (if (devices? :temp-device)
(into [] (concat (:temp-device (:devices conf-data)) this-device-vec))
this-device-vec)
update-temp-device-into-conf-data (update-conf-data (assoc-in conf-data [:devices :temp-device] temp-device-vec))]]
item)
use-temp-device? (> (count devices-list) 0)
new-conditions (if use-temp-device? (conj (into [] (reduce #(remove #{%2} %1) vec devices-list)) :temp-device)
vec)]
new-conditions))
;; <conditions>
;; :chrome
;; [:vi-mode :hhkb :!chrome]
;; ["vi-mode" 1]
;; ["vi-mode" 0]
;; [:vi-mode ["w mode" 1] :!chrome]
(defn conditions-key
[des conditions prev-result]
(let [conditions (merge-multiple-device-conditions conditions)]
(if (conditions/is-simple-set-variable? conditions)
{:conditions (conditions/parse-conditions [conditions] (:from prev-result) (:to prev-result))}
{:conditions (conditions/parse-conditions conditions (:from prev-result) (:to prev-result))})))
;; <other options> section
;; to_if_alone | :alone
;; to_if_held_down | :held
;; to_after_key_up | :afterup
;; to_delayed_action | :delayed
;; to_if_canceled | :cancled
;; to_if_invoked | :invoked
;; parameters | :params
;; basic.to_if_alone_timeout_milliseconds | :alone
;; basic.to_if_held_down_threshold_milliseconds | :held
;; to_delayed_action_delay_milliseconds | :delay FIXME should there be a "basic.", there's none on the spec page
(defn additional-key
"parse additional keys"
[des additional prevresult]
(let [result prevresult
{:keys [alone held afterup delayed params]} additional
{:keys [cancled invoked]} delayed
result (if alone (assoc result :to_if_alone (to-key des alone)) result)
result (if held (assoc result :to_if_held_down (to-key des held)) result)
result (if afterup (assoc result :to_after_key_up (to-key des afterup)) result)
result (if invoked (assoc-in result [:to_delayed_action :to_if_invoked] (to-key des invoked)) result)
result (if cancled (assoc-in result [:to_delayed_action :to_if_cancled] (to-key des cancled)) result)
{:keys [alone held delay]} params
result (if (number? alone) (assoc-in result [:parameters :basic.to_if_alone_timeout_milliseconds] alone) result)
result (if (number? held) (assoc-in result [:parameters :basic.to_if_held_down_threshold_milliseconds] held) result)
result (if (number? delay) (assoc-in result [:parameters :basic.to_delayed_action_delay_milliseconds] delay) result)]
result))
(defn parse-rule
"generate one manipulator"
([des from to]
(let [result {}
result (assoc result :from (:from (from-key des from)))
result (assoc result :to (to-key des to))
result (assoc result :type "basic")]
result))
([des from to conditions]
(let [result {}
result (assoc result :from (:from (from-key des from)))
result (assoc result :to (to-key des to))
result (if conditions
(if (vector? conditions)
(assoc result :conditions (:conditions (conditions-key des conditions result)))
(assoc result :conditions (:conditions (conditions-key des (into [] (flatten [conditions])) result))))
result)
result (assoc result :type "basic")
result (if conditions/used-simlayers-config
(let [insert-simlayer conditions/used-simlayers-config
insert-simlayer (assoc insert-simlayer :from
(froms/parse-from des (:from insert-simlayer)))
insert-simlayer (assoc insert-simlayer :to
(into [] (concat (tos/parse-to des (:to insert-simlayer)) (:to result))))
cleanup-used-simlayers-config (conditions/cleanup-used-simlayers-config)]
[result insert-simlayer])
result)]
result))
([des from to conditions additional]
(let [result {}
result (if additional
(additional-key des additional result)
{})
result (assoc result :from (:from (from-key des from)))
result (if to (assoc result :to (to-key des to)) result)
result (if conditions
(if (vector? conditions)
(assoc result :conditions (:conditions (conditions-key des conditions result)))
(assoc result :conditions (:conditions (conditions-key des (into [] (flatten [conditions])) result))))
result)
result (assoc result :type "basic")
result (if conditions/used-simlayers-config
(let [insert-simlayer conditions/used-simlayers-config
insert-simlayer (assoc insert-simlayer :from
(froms/parse-from des (:from insert-simlayer)))
insert-simlayer (assoc insert-simlayer :to
(into [] (concat (tos/parse-to des (:to insert-simlayer)) (:to result))))
cleanup-used-simlayers-config (conditions/cleanup-used-simlayers-config)]
[result insert-simlayer])
result)]
result)))
(defn generate
"generate one rule"
[mains]
(for [{:keys [des rules]} mains]
{:description des
:manipulators
(into []
(flatten
(for [rule rules]
(let [[from to condition other-options] rule]
(do
(assert (and (nn? from) (or (nn? other-options) (nn? to))) (str "invalid rule: " des ", <from> or <to> is nil"))
(cond (and (nil? other-options) (nil? condition)) (parse-rule des from to)
(and (nil? other-options) (nn? condition)) (parse-rule des from to condition)
(nn? other-options) (parse-rule des from to condition other-options)))))))}))
(defn parse-mains
"parse main section to final edn format, ready to convert to json"
[mains]
(into [] (generate mains)))