]> git.donarmstrong.com Git - qmk_firmware.git/blob - users/xtonhasvim/xtonhasvim.c
First pass at reorganizing docs
[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 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;
61
62 static void edit(void) { vstate = VIM_START; layer_on(_EDIT); layer_off(_CMD); }
63 #define EDIT edit()
64
65
66 static void simple_movement(uint16_t keycode) {
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
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) {
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 PASS_THRU; // 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 PASS_THRU;
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
138         // reset state
139         yank_was_lines = false;
140         SHIFTED = false;
141         mod_override_layer_state = 0;
142         mod_override_triggering_key = 0;
143
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             vstate = VIM_START;
388             break;
389           case VIM_D:
390             CMD(KC_LEFT);
391             SHIFT(KC_DOWN);
392             CMD(KC_X);
393             yank_was_lines = true;
394             vstate = VIM_START;
395             break;
396           case VIM_I:
397             vstate = VIM_DI;
398             break;
399           default:
400             vstate = VIM_START;
401             break;
402           }
403           break;
404         case VIM_DI:
405           /*****************************
406            * ci-  ...delete a word... FROM THE INSIDE!
407            *****************************/
408           switch(keycode) {
409             case VIM_W:
410               ALT(KC_LEFT);
411               PRESS(KC_LSHIFT);
412                 ALT(KC_RIGHT);
413               RELEASE(KC_LSHIFT);
414               CMD(KC_X);
415               yank_was_lines = false;
416               vstate = VIM_START;
417             default:
418               vstate = VIM_START;
419               break;
420           }
421           break;
422         case VIM_V:
423           /*****************************
424            * visual!
425            *****************************/
426           switch(keycode) {
427             case VIM_D:
428             case VIM_X:
429               CMD(KC_X);
430               yank_was_lines = false;
431               vstate = VIM_START;
432               break;
433             case VIM_B:
434               PRESS(KC_LALT);
435               PRESS(KC_LSHIFT);
436               PRESS(KC_LEFT);
437               // leave open for key repeat
438               break;
439             case VIM_E:
440               PRESS(KC_LALT);
441               PRESS(KC_LSHIFT);
442               PRESS(KC_RIGHT);
443               // leave open for key repeat
444               break;
445             case VIM_H:
446               PRESS(KC_LSHIFT);
447               PRESS(KC_LEFT);
448               break;
449             case VIM_I:
450               vstate = VIM_VI;
451               break;
452             case VIM_J:
453               PRESS(KC_LSHIFT);
454               PRESS(KC_DOWN);
455               break;
456             case VIM_K:
457               PRESS(KC_LSHIFT);
458               PRESS(KC_UP);
459               break;
460             case VIM_L:
461               PRESS(KC_LSHIFT);
462               PRESS(KC_RIGHT);
463               break;
464             case VIM_W:
465               PRESS(KC_LALT);
466               SHIFT(KC_RIGHT); // select to end of this word
467               SHIFT(KC_RIGHT); // select to end of next word
468               SHIFT(KC_LEFT);  // select to start of next word
469               RELEASE(KC_LALT);
470               break;
471             case VIM_P:
472               CMD(KC_V);
473               vstate = VIM_START;
474               break;
475             case VIM_Y:
476               CMD(KC_C);
477               TAP(KC_RIGHT);
478               yank_was_lines = false;
479               vstate = VIM_START;
480               break;
481             case VIM_V:
482             case VIM_ESC:
483               TAP(KC_RIGHT);
484               vstate = VIM_START;
485               break;
486             default:
487               // do nothing
488               break;
489           }
490           break;
491         case VIM_VI:
492           /*****************************
493            * vi-  ...select a word... FROM THE INSIDE!
494            *****************************/
495           switch(keycode) {
496             case VIM_W:
497               ALT(KC_LEFT);
498               PRESS(KC_LSHIFT);
499                 ALT(KC_RIGHT);
500               RELEASE(KC_LSHIFT);
501               vstate = VIM_V;
502             default:
503               // ignore
504               vstate = VIM_V;
505               break;
506           }
507           break;
508         case VIM_VS:
509           /*****************************
510            * visual line
511            *****************************/
512           switch(keycode) {
513             case VIM_D:
514             case VIM_X:
515               CMD(KC_X);
516               yank_was_lines = true;
517               vstate = VIM_START;
518               break;
519             case VIM_J:
520               PRESS(KC_LSHIFT);
521               PRESS(KC_DOWN);
522               break;
523             case VIM_K:
524               PRESS(KC_LSHIFT);
525               PRESS(KC_UP);
526               break;
527             case VIM_Y:
528               CMD(KC_C);
529               yank_was_lines = true;
530               TAP(KC_RIGHT);
531               vstate = VIM_START;
532               break;
533             case VIM_P:
534               CMD(KC_V);
535               vstate = VIM_START;
536               break;
537             case VIM_V:
538             case VIM_ESC:
539               TAP(KC_RIGHT);
540               vstate = VIM_START;
541               break;
542             default:
543               // do nothing
544               break;
545           }
546           break;
547         case VIM_G:
548           /*****************************
549            * gg, and a grab-bag of other macros i find useful
550            *****************************/
551           switch(keycode) {
552             case VIM_G:
553               TAP(KC_HOME);
554               break;
555             // codes b
556             case VIM_H:
557               CTRL(KC_A);
558               break;
559             case VIM_J:
560               PRESS(KC_PGDN);
561               break;
562             case VIM_K:
563               PRESS(KC_PGUP);
564               break;
565             case VIM_L:
566               CTRL(KC_E);
567               break;
568             default:
569               // do nothing
570               break;
571           }
572           vstate = VIM_START;
573           break;
574         case VIM_Y:
575           /*****************************
576            * yoink!
577            *****************************/
578           switch(keycode) {
579           case VIM_B:
580           case VIM_E:
581           case VIM_H:
582           case VIM_J:
583           case VIM_K:
584           case VIM_L:
585           case VIM_W:
586             simple_movement(keycode);
587             CMD(KC_C);
588             TAP(KC_RIGHT);
589             yank_was_lines = false;
590             break;
591           case VIM_Y:
592             CMD(KC_LEFT);
593             SHIFT(KC_DOWN);
594             CMD(KC_C);
595             TAP(KC_RIGHT);
596             yank_was_lines = true;
597             break;
598           default:
599             // NOTHING
600             break;
601           }
602           vstate = VIM_START;
603           break;
604         }
605     } else {
606       /************************
607        * key release events
608        ************************/
609       clear_keyboard();
610     }
611     return false;
612   } else {
613     return PASS_THRU;
614   }
615 }