05be1de1 |
1 | /* Copyright 2015-2017 Christon DeWan |
2 | * |
3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | */ |
16 | |
17 | #include "xtonhasvim.h" |
18 | |
19 | /************************************ |
20 | * helper foo |
21 | ************************************/ |
22 | |
23 | #define PRESS(kc) register_code(kc) |
24 | #define RELEASE(kc) unregister_code(kc) |
25 | |
26 | static void TAP(uint16_t keycode) { |
27 | PRESS(keycode); |
28 | RELEASE(keycode); |
29 | } |
30 | |
31 | static void CMD(uint16_t keycode) { |
32 | PRESS(KC_LGUI); |
33 | TAP(keycode); |
34 | RELEASE(KC_LGUI); |
35 | } |
36 | |
37 | static void CTRL(uint16_t keycode) { |
38 | PRESS(KC_LCTRL); |
39 | TAP(keycode); |
40 | RELEASE(KC_LCTRL); |
41 | } |
42 | |
43 | static void SHIFT(uint16_t keycode) { |
44 | PRESS(KC_LSHIFT); |
45 | TAP(keycode); |
46 | RELEASE(KC_LSHIFT); |
47 | } |
48 | |
49 | static void ALT(uint16_t keycode) { |
50 | PRESS(KC_LALT); |
51 | TAP(keycode); |
52 | RELEASE(KC_LALT); |
53 | } |
54 | |
55 | |
975c48ef |
56 | static uint16_t vstate = VIM_START; |
57 | static bool yank_was_lines = false; |
58 | static bool SHIFTED = false; |
59 | static uint32_t mod_override_layer_state = 0; |
60 | static uint16_t mod_override_triggering_key = 0; |
05be1de1 |
61 | |
975c48ef |
62 | static void edit(void) { vstate = VIM_START; layer_on(_EDIT); layer_off(_CMD); } |
05be1de1 |
63 | #define EDIT edit() |
64 | |
65 | |
975c48ef |
66 | static void simple_movement(uint16_t keycode) { |
05be1de1 |
67 | switch(keycode) { |
68 | case VIM_B: |
69 | PRESS(KC_LALT); |
70 | SHIFT(KC_LEFT); // select to start of this word |
71 | RELEASE(KC_LALT); |
72 | break; |
73 | case VIM_E: |
74 | PRESS(KC_LALT); |
75 | SHIFT(KC_RIGHT); // select to end of this word |
76 | RELEASE(KC_LALT); |
77 | break; |
78 | case VIM_H: |
79 | SHIFT(KC_LEFT); |
80 | break; |
81 | case VIM_J: |
82 | CMD(KC_LEFT); |
83 | SHIFT(KC_DOWN); |
84 | SHIFT(KC_DOWN); |
85 | break; |
86 | case VIM_K: |
87 | CMD(KC_LEFT); |
88 | TAP(KC_DOWN); |
89 | SHIFT(KC_UP); |
90 | SHIFT(KC_UP); |
91 | break; |
92 | case VIM_L: |
93 | SHIFT(KC_RIGHT); |
94 | break; |
95 | case VIM_W: |
96 | PRESS(KC_LALT); |
97 | SHIFT(KC_RIGHT); // select to end of this word |
98 | SHIFT(KC_RIGHT); // select to end of next word |
99 | SHIFT(KC_LEFT); // select to start of next word |
100 | RELEASE(KC_LALT); |
101 | break; |
102 | } |
103 | } |
104 | |
975c48ef |
105 | __attribute__ ((weak)) |
106 | bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { |
107 | return true; |
108 | } |
109 | |
110 | #define PASS_THRU process_record_keymap(keycode, record) |
111 | |
112 | bool process_record_user(uint16_t keycode, keyrecord_t *record) { |
05be1de1 |
113 | if(record->event.pressed && layer_state_is(_CMD) && IS_MOD(keycode)) { |
114 | mod_override_layer_state = layer_state; |
115 | mod_override_triggering_key = keycode; |
116 | layer_clear(); |
975c48ef |
117 | return PASS_THRU; // let the event fall through... |
05be1de1 |
118 | } |
119 | if(mod_override_layer_state && !record->event.pressed && keycode == mod_override_triggering_key) { |
120 | layer_state_set(mod_override_layer_state); |
121 | mod_override_layer_state = 0; |
122 | mod_override_triggering_key = 0; |
975c48ef |
123 | return PASS_THRU; |
05be1de1 |
124 | } |
125 | |
126 | if (VIM_START <= keycode && keycode <= VIM_ESC) { |
127 | if(keycode == VIM_SHIFT) { |
128 | SHIFTED = record->event.pressed; |
129 | return false; |
130 | } |
131 | |
132 | if (record->event.pressed) { |
133 | if(keycode == VIM_START) { |
134 | // entry from anywhere |
135 | layer_on(_CMD); |
136 | vstate = VIM_START; |
975c48ef |
137 | |
138 | // reset state |
139 | yank_was_lines = false; |
140 | SHIFTED = false; |
141 | mod_override_layer_state = 0; |
142 | mod_override_triggering_key = 0; |
143 | |
05be1de1 |
144 | return false; |
145 | } |
146 | switch(vstate) { |
147 | case VIM_START: |
148 | switch(keycode){ |
149 | /***************************** |
150 | * ground state |
151 | *****************************/ |
152 | case VIM_A: |
153 | if(SHIFTED) { |
154 | // CMD(KC_RIGHT); |
155 | CTRL(KC_E); |
156 | } else { |
157 | TAP(KC_RIGHT); |
158 | } |
159 | EDIT; |
160 | break; |
161 | case VIM_B: |
162 | PRESS(KC_LALT); |
163 | PRESS(KC_LEFT); |
164 | break; |
165 | case VIM_C: |
166 | if(SHIFTED) { |
167 | PRESS(KC_LSHIFT); |
168 | CMD(KC_RIGHT); |
169 | RELEASE(KC_LSHIFT); |
170 | CMD(KC_X); |
171 | yank_was_lines = false; |
172 | EDIT; |
173 | } else { |
174 | vstate = VIM_C; |
175 | } |
176 | break; |
177 | case VIM_D: |
178 | if(SHIFTED) { |
179 | TAP(KC_K); |
180 | } else { |
181 | vstate = VIM_D; |
182 | } |
183 | break; |
184 | case VIM_E: |
185 | PRESS(KC_LALT); |
186 | PRESS(KC_RIGHT); |
187 | break; |
188 | case VIM_G: |
189 | if(SHIFTED) { |
190 | TAP(KC_END); |
191 | } else { |
192 | vstate = VIM_G; |
193 | } |
194 | break; |
195 | case VIM_H: |
196 | PRESS(KC_LEFT); |
197 | break; |
198 | case VIM_I: |
199 | if(SHIFTED){ |
200 | CTRL(KC_A); |
201 | } |
202 | EDIT; |
203 | break; |
204 | case VIM_J: |
205 | if(SHIFTED) { |
206 | CMD(KC_RIGHT); |
207 | TAP(KC_DEL); |
208 | } else { |
209 | PRESS(KC_DOWN); |
210 | } |
211 | break; |
212 | case VIM_K: |
213 | PRESS(KC_UP); |
214 | break; |
215 | case VIM_L: |
216 | PRESS(KC_RIGHT); |
217 | break; |
218 | case VIM_O: |
219 | if(SHIFTED) { |
220 | CMD(KC_LEFT); |
221 | TAP(KC_ENTER); |
222 | TAP(KC_UP); |
223 | EDIT; |
224 | } else { |
225 | CMD(KC_RIGHT); |
226 | TAP(KC_ENTER); |
227 | EDIT; |
228 | } |
229 | break; |
230 | case VIM_P: |
231 | if(SHIFTED) { |
232 | CMD(KC_LEFT); |
233 | CMD(KC_V); |
234 | } else { |
235 | if(yank_was_lines) { |
236 | CMD(KC_RIGHT); |
237 | TAP(KC_RIGHT); |
238 | CMD(KC_V); |
239 | } else { |
240 | CMD(KC_V); |
241 | } |
242 | } |
243 | break; |
244 | case VIM_S: |
245 | // s for substitute? |
246 | if(SHIFTED) { |
247 | CMD(KC_LEFT); |
248 | PRESS(KC_LSHIFT); |
249 | CMD(KC_RIGHT); |
250 | RELEASE(KC_LSHIFT); |
251 | CMD(KC_X); |
252 | yank_was_lines = false; |
253 | EDIT; |
254 | } else { |
255 | SHIFT(KC_RIGHT); |
256 | CMD(KC_X); |
257 | yank_was_lines = false; |
258 | EDIT; |
259 | } |
260 | break; |
261 | case VIM_U: |
262 | if(SHIFTED) { |
263 | PRESS(KC_LSFT); |
264 | CMD(KC_Z); |
265 | RELEASE(KC_LSHIFT); |
266 | } else { |
267 | CMD(KC_Z); |
268 | } |
269 | break; |
270 | case VIM_V: |
271 | if(SHIFTED) { |
272 | CMD(KC_LEFT); |
273 | SHIFT(KC_DOWN); |
274 | vstate = VIM_VS; |
275 | } else { |
276 | vstate = VIM_V; |
277 | } |
278 | break; |
279 | case VIM_W: |
280 | PRESS(KC_LALT); |
281 | TAP(KC_RIGHT); |
282 | TAP(KC_RIGHT); |
283 | TAP(KC_LEFT); |
284 | RELEASE(KC_LALT); |
285 | break; |
286 | case VIM_X: |
287 | // SHIFT(KC_RIGHT); |
288 | // CMD(KC_X); |
289 | PRESS(KC_DEL); |
290 | break; |
291 | case VIM_Y: |
292 | if(SHIFTED) { |
293 | CMD(KC_LEFT); |
294 | SHIFT(KC_DOWN); |
295 | CMD(KC_C); |
296 | TAP(KC_RIGHT); |
297 | yank_was_lines = true; |
298 | } else { |
299 | vstate = VIM_Y; |
300 | } |
301 | break; |
302 | case VIM_COMMA: |
303 | if(SHIFTED) { |
304 | // indent |
305 | CMD(KC_LBRACKET); |
306 | } else { |
307 | // toggle comment |
308 | CMD(KC_SLASH); |
309 | } |
310 | break; |
311 | case VIM_PERIOD: |
312 | if(SHIFTED) { |
313 | // outdent |
314 | CMD(KC_RBRACKET); |
315 | } |
316 | break; |
317 | } |
318 | break; |
319 | case VIM_C: |
320 | /***************************** |
321 | * c- ...for change. I never use this... |
322 | *****************************/ |
323 | switch(keycode) { |
324 | case VIM_B: |
325 | case VIM_E: |
326 | case VIM_H: |
327 | case VIM_J: |
328 | case VIM_K: |
329 | case VIM_L: |
330 | case VIM_W: |
331 | simple_movement(keycode); |
332 | CMD(KC_X); |
333 | yank_was_lines = false; |
334 | EDIT; |
335 | break; |
336 | |
337 | case VIM_C: |
338 | CMD(KC_LEFT); |
339 | PRESS(KC_LSHIFT); |
340 | CMD(KC_RIGHT); |
341 | RELEASE(KC_LSHIFT); |
342 | CMD(KC_X); |
343 | yank_was_lines = false; |
344 | EDIT; |
345 | break; |
346 | case VIM_I: |
347 | vstate = VIM_CI; |
348 | break; |
349 | default: |
350 | vstate = VIM_START; |
351 | break; |
352 | } |
353 | break; |
354 | case VIM_CI: |
355 | /***************************** |
356 | * ci- ...change inner word |
357 | *****************************/ |
358 | switch(keycode) { |
359 | case VIM_W: |
360 | ALT(KC_LEFT); |
361 | PRESS(KC_LSHIFT); |
362 | ALT(KC_RIGHT); |
363 | RELEASE(KC_LSHIFT); |
364 | CMD(KC_X); |
365 | yank_was_lines = false; |
366 | EDIT; |
367 | default: |
368 | vstate = VIM_START; |
369 | break; |
370 | } |
371 | break; |
372 | case VIM_D: |
373 | /***************************** |
374 | * d- ...delete stuff |
375 | *****************************/ |
376 | switch(keycode) { |
377 | case VIM_B: |
378 | case VIM_E: |
379 | case VIM_H: |
380 | case VIM_J: |
381 | case VIM_K: |
382 | case VIM_L: |
383 | case VIM_W: |
384 | simple_movement(keycode); |
385 | CMD(KC_X); |
386 | yank_was_lines = false; |
387 | break; |
388 | case VIM_D: |
389 | CMD(KC_LEFT); |
390 | SHIFT(KC_DOWN); |
391 | CMD(KC_X); |
392 | yank_was_lines = true; |
393 | vstate = VIM_START; |
394 | break; |
395 | case VIM_I: |
396 | vstate = VIM_DI; |
397 | break; |
398 | default: |
399 | vstate = VIM_START; |
400 | break; |
401 | } |
402 | break; |
403 | case VIM_DI: |
404 | /***************************** |
405 | * ci- ...delete a word... FROM THE INSIDE! |
406 | *****************************/ |
407 | switch(keycode) { |
408 | case VIM_W: |
409 | ALT(KC_LEFT); |
410 | PRESS(KC_LSHIFT); |
411 | ALT(KC_RIGHT); |
412 | RELEASE(KC_LSHIFT); |
413 | CMD(KC_X); |
414 | yank_was_lines = false; |
415 | vstate = VIM_START; |
416 | default: |
417 | vstate = VIM_START; |
418 | break; |
419 | } |
420 | break; |
421 | case VIM_V: |
422 | /***************************** |
423 | * visual! |
424 | *****************************/ |
425 | switch(keycode) { |
426 | case VIM_D: |
427 | case VIM_X: |
428 | CMD(KC_X); |
429 | yank_was_lines = false; |
430 | vstate = VIM_START; |
431 | break; |
432 | case VIM_B: |
433 | PRESS(KC_LALT); |
434 | PRESS(KC_LSHIFT); |
435 | PRESS(KC_LEFT); |
436 | // leave open for key repeat |
437 | break; |
438 | case VIM_E: |
439 | PRESS(KC_LALT); |
440 | PRESS(KC_LSHIFT); |
441 | PRESS(KC_RIGHT); |
442 | // leave open for key repeat |
443 | break; |
444 | case VIM_H: |
445 | PRESS(KC_LSHIFT); |
446 | PRESS(KC_LEFT); |
447 | break; |
448 | case VIM_I: |
449 | vstate = VIM_VI; |
450 | break; |
451 | case VIM_J: |
452 | PRESS(KC_LSHIFT); |
453 | PRESS(KC_DOWN); |
454 | break; |
455 | case VIM_K: |
456 | PRESS(KC_LSHIFT); |
457 | PRESS(KC_UP); |
458 | break; |
459 | case VIM_L: |
460 | PRESS(KC_LSHIFT); |
461 | PRESS(KC_RIGHT); |
462 | break; |
463 | case VIM_W: |
464 | PRESS(KC_LALT); |
465 | SHIFT(KC_RIGHT); // select to end of this word |
466 | SHIFT(KC_RIGHT); // select to end of next word |
467 | SHIFT(KC_LEFT); // select to start of next word |
468 | RELEASE(KC_LALT); |
469 | break; |
470 | case VIM_Y: |
471 | CMD(KC_C); |
472 | TAP(KC_RIGHT); |
473 | yank_was_lines = false; |
474 | vstate = VIM_START; |
475 | break; |
476 | case VIM_V: |
477 | case VIM_ESC: |
478 | TAP(KC_RIGHT); |
479 | vstate = VIM_START; |
480 | break; |
481 | default: |
482 | // do nothing |
483 | break; |
484 | } |
485 | break; |
486 | case VIM_VI: |
487 | /***************************** |
488 | * vi- ...select a word... FROM THE INSIDE! |
489 | *****************************/ |
490 | switch(keycode) { |
491 | case VIM_W: |
492 | ALT(KC_LEFT); |
493 | PRESS(KC_LSHIFT); |
494 | ALT(KC_RIGHT); |
495 | RELEASE(KC_LSHIFT); |
496 | vstate = VIM_V; |
497 | default: |
498 | // ignore |
499 | vstate = VIM_V; |
500 | break; |
501 | } |
502 | break; |
503 | case VIM_VS: |
504 | /***************************** |
505 | * visual line |
506 | *****************************/ |
507 | switch(keycode) { |
508 | case VIM_D: |
509 | case VIM_X: |
510 | CMD(KC_X); |
511 | yank_was_lines = true; |
512 | vstate = VIM_START; |
513 | break; |
514 | case VIM_J: |
515 | PRESS(KC_LSHIFT); |
516 | PRESS(KC_DOWN); |
517 | break; |
518 | case VIM_K: |
519 | PRESS(KC_LSHIFT); |
520 | PRESS(KC_UP); |
521 | break; |
522 | case VIM_Y: |
523 | CMD(KC_C); |
524 | yank_was_lines = true; |
525 | TAP(KC_RIGHT); |
526 | vstate = VIM_START; |
527 | break; |
528 | case VIM_V: |
529 | case VIM_ESC: |
530 | TAP(KC_RIGHT); |
531 | vstate = VIM_START; |
532 | break; |
533 | default: |
534 | // do nothing |
535 | break; |
536 | } |
537 | break; |
538 | case VIM_G: |
539 | /***************************** |
540 | * gg, and a grab-bag of other macros i find useful |
541 | *****************************/ |
542 | switch(keycode) { |
543 | case VIM_G: |
544 | TAP(KC_HOME); |
545 | break; |
546 | // codes b |
547 | case VIM_H: |
548 | CTRL(KC_A); |
549 | break; |
550 | case VIM_J: |
551 | PRESS(KC_PGDN); |
552 | break; |
553 | case VIM_K: |
554 | PRESS(KC_PGUP); |
555 | break; |
556 | case VIM_L: |
557 | CTRL(KC_E); |
558 | break; |
559 | default: |
560 | // do nothing |
561 | break; |
562 | } |
563 | vstate = VIM_START; |
564 | break; |
565 | case VIM_Y: |
566 | /***************************** |
567 | * yoink! |
568 | *****************************/ |
569 | switch(keycode) { |
570 | case VIM_B: |
571 | case VIM_E: |
572 | case VIM_H: |
573 | case VIM_J: |
574 | case VIM_K: |
575 | case VIM_L: |
576 | case VIM_W: |
577 | simple_movement(keycode); |
578 | CMD(KC_C); |
579 | TAP(KC_RIGHT); |
580 | yank_was_lines = false; |
581 | break; |
582 | case VIM_Y: |
583 | CMD(KC_LEFT); |
584 | SHIFT(KC_DOWN); |
585 | CMD(KC_C); |
586 | TAP(KC_RIGHT); |
587 | yank_was_lines = true; |
588 | break; |
589 | default: |
590 | // NOTHING |
591 | break; |
592 | } |
593 | vstate = VIM_START; |
594 | break; |
595 | } |
596 | } else { |
597 | /************************ |
598 | * key release events |
599 | ************************/ |
600 | clear_keyboard(); |
601 | } |
602 | return false; |
603 | } else { |
975c48ef |
604 | return PASS_THRU; |
05be1de1 |
605 | } |
606 | } |