xtonhasvim.c 16 KB

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