]> git.donarmstrong.com Git - qmk_firmware.git/blob - users/xtonhasvim/xtonhasvim.c
Xton's first keymap! (#2941)
[qmk_firmware.git] / users / xtonhasvim / xtonhasvim.c
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
56 uint16_t vstate = VIM_START;
57 bool yank_was_lines = false;
58 bool SHIFTED = false;
59 uint32_t mod_override_layer_state = 0;
60 uint16_t mod_override_triggering_key = 0;
61 bool do_check_kb_clear = false;
62
63 void vim_reset(void) {
64   vstate = VIM_START;
65   SHIFTED = false;
66   yank_was_lines = false;
67 }
68
69 void edit(void) { vstate = VIM_START; layer_on(_EDIT); layer_off(_CMD); }
70 #define EDIT edit()
71
72
73 void simple_movement(uint16_t keycode) {
74   switch(keycode) {
75     case VIM_B:
76       PRESS(KC_LALT);
77         SHIFT(KC_LEFT); // select to start of this word
78       RELEASE(KC_LALT);
79       break;
80     case VIM_E:
81       PRESS(KC_LALT);
82         SHIFT(KC_RIGHT); // select to end of this word
83       RELEASE(KC_LALT);
84       break;
85     case VIM_H:
86       SHIFT(KC_LEFT);
87       break;
88     case VIM_J:
89       CMD(KC_LEFT);
90       SHIFT(KC_DOWN);
91       SHIFT(KC_DOWN);
92       break;
93     case VIM_K:
94       CMD(KC_LEFT);
95       TAP(KC_DOWN);
96       SHIFT(KC_UP);
97       SHIFT(KC_UP);
98       break;
99     case VIM_L:
100       SHIFT(KC_RIGHT);
101       break;
102     case VIM_W:
103       PRESS(KC_LALT);
104       SHIFT(KC_RIGHT); // select to end of this word
105       SHIFT(KC_RIGHT); // select to end of next word
106       SHIFT(KC_LEFT);  // select to start of next word
107       RELEASE(KC_LALT);
108       break;
109   }
110 }
111
112 bool process_record_xtonhasvim(uint16_t keycode, keyrecord_t *record) {
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();
117     return true; // let the event fall through...
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;
123     return true;
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;
137         return false;
138       }
139       switch(vstate) {
140         case VIM_START:
141           switch(keycode){
142             /*****************************
143              * ground state
144              *****************************/
145             case VIM_A:
146               if(SHIFTED) {
147                 // CMD(KC_RIGHT);
148                 CTRL(KC_E);
149               } else {
150                 TAP(KC_RIGHT);
151               }
152               EDIT;
153               break;
154             case VIM_B:
155               PRESS(KC_LALT);
156               PRESS(KC_LEFT);
157               break;
158             case VIM_C:
159               if(SHIFTED) {
160                 PRESS(KC_LSHIFT);
161                   CMD(KC_RIGHT);
162                 RELEASE(KC_LSHIFT);
163                 CMD(KC_X);
164                 yank_was_lines = false;
165                 EDIT;
166               } else {
167                 vstate = VIM_C;
168               }
169               break;
170             case VIM_D:
171               if(SHIFTED) {
172                 TAP(KC_K);
173               } else {
174                 vstate = VIM_D;
175               }
176               break;
177             case VIM_E:
178               PRESS(KC_LALT);
179               PRESS(KC_RIGHT);
180               break;
181             case VIM_G:
182               if(SHIFTED) {
183                 TAP(KC_END);
184               } else {
185                 vstate = VIM_G;
186               }
187               break;
188             case VIM_H:
189               PRESS(KC_LEFT);
190               break;
191             case VIM_I:
192               if(SHIFTED){
193                 CTRL(KC_A);
194               }
195               EDIT;
196               break;
197             case VIM_J:
198               if(SHIFTED) {
199                 CMD(KC_RIGHT);
200                 TAP(KC_DEL);
201               } else {
202                 PRESS(KC_DOWN);
203               }
204               break;
205             case VIM_K:
206               PRESS(KC_UP);
207               break;
208             case VIM_L:
209               PRESS(KC_RIGHT);
210               break;
211             case VIM_O:
212               if(SHIFTED) {
213                 CMD(KC_LEFT);
214                 TAP(KC_ENTER);
215                 TAP(KC_UP);
216                 EDIT;
217               } else {
218                 CMD(KC_RIGHT);
219                 TAP(KC_ENTER);
220                 EDIT;
221               }
222               break;
223             case VIM_P:
224               if(SHIFTED) {
225                 CMD(KC_LEFT);
226                 CMD(KC_V);
227               } else {
228                 if(yank_was_lines) {
229                   CMD(KC_RIGHT);
230                   TAP(KC_RIGHT);
231                   CMD(KC_V);
232                 } else {
233                   CMD(KC_V);
234                 }
235               }
236               break;
237             case VIM_S:
238               // s for substitute?
239               if(SHIFTED) {
240                 CMD(KC_LEFT);
241                 PRESS(KC_LSHIFT);
242                   CMD(KC_RIGHT);
243                 RELEASE(KC_LSHIFT);
244                 CMD(KC_X);
245                 yank_was_lines = false;
246                 EDIT;
247               } else {
248                 SHIFT(KC_RIGHT);
249                 CMD(KC_X);
250                 yank_was_lines = false;
251                 EDIT;
252               }
253               break;
254             case VIM_U:
255               if(SHIFTED) {
256                 PRESS(KC_LSFT);
257                   CMD(KC_Z);
258                 RELEASE(KC_LSHIFT);
259               } else {
260                 CMD(KC_Z);
261               }
262               break;
263             case VIM_V:
264               if(SHIFTED) {
265                 CMD(KC_LEFT);
266                 SHIFT(KC_DOWN);
267                 vstate = VIM_VS;
268               } else {
269                 vstate = VIM_V;
270               }
271               break;
272             case VIM_W:
273               PRESS(KC_LALT);
274                 TAP(KC_RIGHT);
275                 TAP(KC_RIGHT);
276                 TAP(KC_LEFT);
277               RELEASE(KC_LALT);
278               break;
279             case VIM_X:
280               // SHIFT(KC_RIGHT);
281               // CMD(KC_X);
282               PRESS(KC_DEL);
283               break;
284             case VIM_Y:
285               if(SHIFTED) {
286                 CMD(KC_LEFT);
287                 SHIFT(KC_DOWN);
288                 CMD(KC_C);
289                 TAP(KC_RIGHT);
290                 yank_was_lines = true;
291               } else {
292                 vstate = VIM_Y;
293               }
294               break;
295             case VIM_COMMA:
296               if(SHIFTED) {
297                 // indent
298                 CMD(KC_LBRACKET);
299               } else {
300                 // toggle comment
301                 CMD(KC_SLASH);
302               }
303               break;
304             case VIM_PERIOD:
305               if(SHIFTED) {
306                 // outdent
307                 CMD(KC_RBRACKET);
308               }
309               break;
310           }
311           break;
312         case VIM_C:
313           /*****************************
314            * c-  ...for change. I never use this...
315            *****************************/
316           switch(keycode) {
317           case VIM_B:
318           case VIM_E:
319           case VIM_H:
320           case VIM_J:
321           case VIM_K:
322           case VIM_L:
323           case VIM_W:
324             simple_movement(keycode);
325             CMD(KC_X);
326             yank_was_lines = false;
327             EDIT;
328             break;
329
330           case VIM_C:
331             CMD(KC_LEFT);
332             PRESS(KC_LSHIFT);
333               CMD(KC_RIGHT);
334             RELEASE(KC_LSHIFT);
335             CMD(KC_X);
336             yank_was_lines = false;
337             EDIT;
338             break;
339           case VIM_I:
340             vstate = VIM_CI;
341             break;
342           default:
343             vstate = VIM_START;
344             break;
345           }
346           break;
347         case VIM_CI:
348           /*****************************
349            * ci-  ...change inner word
350            *****************************/
351           switch(keycode) {
352             case VIM_W:
353               ALT(KC_LEFT);
354               PRESS(KC_LSHIFT);
355                 ALT(KC_RIGHT);
356               RELEASE(KC_LSHIFT);
357               CMD(KC_X);
358               yank_was_lines = false;
359               EDIT;
360             default:
361               vstate = VIM_START;
362               break;
363           }
364           break;
365         case VIM_D:
366           /*****************************
367            * d-  ...delete stuff
368            *****************************/
369           switch(keycode) {
370           case VIM_B:
371           case VIM_E:
372           case VIM_H:
373           case VIM_J:
374           case VIM_K:
375           case VIM_L:
376           case VIM_W:
377             simple_movement(keycode);
378             CMD(KC_X);
379             yank_was_lines = false;
380             break;
381           case VIM_D:
382             CMD(KC_LEFT);
383             SHIFT(KC_DOWN);
384             CMD(KC_X);
385             yank_was_lines = true;
386             vstate = VIM_START;
387             break;
388           case VIM_I:
389             vstate = VIM_DI;
390             break;
391           default:
392             vstate = VIM_START;
393             break;
394           }
395           break;
396         case VIM_DI:
397           /*****************************
398            * ci-  ...delete a word... FROM THE INSIDE!
399            *****************************/
400           switch(keycode) {
401             case VIM_W:
402               ALT(KC_LEFT);
403               PRESS(KC_LSHIFT);
404                 ALT(KC_RIGHT);
405               RELEASE(KC_LSHIFT);
406               CMD(KC_X);
407               yank_was_lines = false;
408               vstate = VIM_START;
409             default:
410               vstate = VIM_START;
411               break;
412           }
413           break;
414         case VIM_V:
415           /*****************************
416            * visual!
417            *****************************/
418           switch(keycode) {
419             case VIM_D:
420             case VIM_X:
421               CMD(KC_X);
422               yank_was_lines = false;
423               vstate = VIM_START;
424               break;
425             case VIM_B:
426               PRESS(KC_LALT);
427               PRESS(KC_LSHIFT);
428               PRESS(KC_LEFT);
429               // leave open for key repeat
430               break;
431             case VIM_E:
432               PRESS(KC_LALT);
433               PRESS(KC_LSHIFT);
434               PRESS(KC_RIGHT);
435               // leave open for key repeat
436               break;
437             case VIM_H:
438               PRESS(KC_LSHIFT);
439               PRESS(KC_LEFT);
440               break;
441             case VIM_I:
442               vstate = VIM_VI;
443               break;
444             case VIM_J:
445               PRESS(KC_LSHIFT);
446               PRESS(KC_DOWN);
447               break;
448             case VIM_K:
449               PRESS(KC_LSHIFT);
450               PRESS(KC_UP);
451               break;
452             case VIM_L:
453               PRESS(KC_LSHIFT);
454               PRESS(KC_RIGHT);
455               break;
456             case VIM_W:
457               PRESS(KC_LALT);
458               SHIFT(KC_RIGHT); // select to end of this word
459               SHIFT(KC_RIGHT); // select to end of next word
460               SHIFT(KC_LEFT);  // select to start of next word
461               RELEASE(KC_LALT);
462               break;
463             case VIM_Y:
464               CMD(KC_C);
465               TAP(KC_RIGHT);
466               yank_was_lines = false;
467               vstate = VIM_START;
468               break;
469             case VIM_V:
470             case VIM_ESC:
471               TAP(KC_RIGHT);
472               vstate = VIM_START;
473               break;
474             default:
475               // do nothing
476               break;
477           }
478           break;
479         case VIM_VI:
480           /*****************************
481            * vi-  ...select a word... FROM THE INSIDE!
482            *****************************/
483           switch(keycode) {
484             case VIM_W:
485               ALT(KC_LEFT);
486               PRESS(KC_LSHIFT);
487                 ALT(KC_RIGHT);
488               RELEASE(KC_LSHIFT);
489               vstate = VIM_V;
490             default:
491               // ignore
492               vstate = VIM_V;
493               break;
494           }
495           break;
496         case VIM_VS:
497           /*****************************
498            * visual line
499            *****************************/
500           switch(keycode) {
501             case VIM_D:
502             case VIM_X:
503               CMD(KC_X);
504               yank_was_lines = true;
505               vstate = VIM_START;
506               break;
507             case VIM_J:
508               PRESS(KC_LSHIFT);
509               PRESS(KC_DOWN);
510               break;
511             case VIM_K:
512               PRESS(KC_LSHIFT);
513               PRESS(KC_UP);
514               break;
515             case VIM_Y:
516               CMD(KC_C);
517               yank_was_lines = true;
518               TAP(KC_RIGHT);
519               vstate = VIM_START;
520               break;
521             case VIM_V:
522             case VIM_ESC:
523               TAP(KC_RIGHT);
524               vstate = VIM_START;
525               break;
526             default:
527               // do nothing
528               break;
529           }
530           break;
531         case VIM_G:
532           /*****************************
533            * gg, and a grab-bag of other macros i find useful
534            *****************************/
535           switch(keycode) {
536             case VIM_G:
537               TAP(KC_HOME);
538               break;
539             // codes b
540             case VIM_H:
541               CTRL(KC_A);
542               break;
543             case VIM_J:
544               PRESS(KC_PGDN);
545               break;
546             case VIM_K:
547               PRESS(KC_PGUP);
548               break;
549             case VIM_L:
550               CTRL(KC_E);
551               break;
552             default:
553               // do nothing
554               break;
555           }
556           vstate = VIM_START;
557           break;
558         case VIM_Y:
559           /*****************************
560            * yoink!
561            *****************************/
562           switch(keycode) {
563           case VIM_B:
564           case VIM_E:
565           case VIM_H:
566           case VIM_J:
567           case VIM_K:
568           case VIM_L:
569           case VIM_W:
570             simple_movement(keycode);
571             CMD(KC_C);
572             TAP(KC_RIGHT);
573             yank_was_lines = false;
574             break;
575           case VIM_Y:
576             CMD(KC_LEFT);
577             SHIFT(KC_DOWN);
578             CMD(KC_C);
579             TAP(KC_RIGHT);
580             yank_was_lines = true;
581             break;
582           default:
583             // NOTHING
584             break;
585           }
586           vstate = VIM_START;
587           break;
588         }
589     } else {
590       /************************
591        * key release events
592        ************************/
593       clear_keyboard();
594     }
595     return false;
596   } else {
597     return true;
598   }
599 }