xtonhasvim cleanup (#2947)
[jackhill/qmk/firmware.git] / users / xtonhasvim / xtonhasvim.c
CommitLineData
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
26static void TAP(uint16_t keycode) {
27 PRESS(keycode);
28 RELEASE(keycode);
29}
30
31static void CMD(uint16_t keycode) {
32 PRESS(KC_LGUI);
33 TAP(keycode);
34 RELEASE(KC_LGUI);
35}
36
37static void CTRL(uint16_t keycode) {
38 PRESS(KC_LCTRL);
39 TAP(keycode);
40 RELEASE(KC_LCTRL);
41}
42
43static void SHIFT(uint16_t keycode) {
44 PRESS(KC_LSHIFT);
45 TAP(keycode);
46 RELEASE(KC_LSHIFT);
47}
48
49static void ALT(uint16_t keycode) {
50 PRESS(KC_LALT);
51 TAP(keycode);
52 RELEASE(KC_LALT);
53}
54
55
975c48ef 56static uint16_t vstate = VIM_START;
57static bool yank_was_lines = false;
58static bool SHIFTED = false;
59static uint32_t mod_override_layer_state = 0;
60static uint16_t mod_override_triggering_key = 0;
05be1de1 61
975c48ef 62static void edit(void) { vstate = VIM_START; layer_on(_EDIT); layer_off(_CMD); }
05be1de1 63#define EDIT edit()
64
65
975c48ef 66static 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))
106bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
107 return true;
108}
109
110#define PASS_THRU process_record_keymap(keycode, record)
111
112bool 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}