Compare commits
415 Commits
f/keyboard
...
main
Author | SHA1 | Date |
---|---|---|
Alpha Chen | 0bb3928aea | 2 years ago |
Alpha Chen | 7954cc8f25 | 2 years ago |
Alpha Chen | 9fb691f44a | 2 years ago |
Gergely Nagy | ff19f144f8 | 2 years ago |
Michael Richters | a0045f4d9e | 2 years ago |
Michael Richters | 51125f215b | 2 years ago |
Michael Richters | c84aa58470 | 2 years ago |
Michael Richters | 789cc218c6 | 2 years ago |
Michael Richters | adaa3b7a01 | 2 years ago |
Alpha Chen | a43b89ce51 | 2 years ago |
Alpha Chen | 02157d30c7 | 2 years ago |
Gergely Nagy | 2f1c96ab4e | 2 years ago |
Gergely Nagy | 49a691e0f9 | 2 years ago |
Norwin | 3655f9a517 | 2 years ago |
Norwin | e22773ab5b | 2 years ago |
Jesse Vincent | fefc6699ba | 2 years ago |
Taylor Yu | e233e96be7 | 2 years ago |
Jesse Vincent | 18d0292d64 | 2 years ago |
Taylor Yu | af69f6a72b | 2 years ago |
Taylor Yu | 0ac320baeb | 2 years ago |
Jesse Vincent | 95ea4e3175 | 2 years ago |
Gergely Nagy | d0f1a812b0 | 2 years ago |
Gergely Nagy | 6a12467b84 | 2 years ago |
Jesse Vincent | b949ca89b1 | 2 years ago |
Jesse Vincent | cf798497e2 | 2 years ago |
Gergely Nagy | ca9b4cb50c | 2 years ago |
Taylor Yu | 04d608c9f6 | 2 years ago |
Jesse Vincent | 9bf6eba010 | 2 years ago |
Gergely Nagy | f21dda9a51 | 2 years ago |
Gergely Nagy | 28d6d66e98 | 2 years ago |
Jesse Vincent | ae9e561028 | 2 years ago |
Jesse Vincent | f181d55124 | 2 years ago |
Jesse Vincent | be28b367ce | 2 years ago |
Taylor Yu | 45bd9d1a3d | 2 years ago |
Gergely Nagy | 75b911b27d | 2 years ago |
Gergely Nagy | a5afaf1eb4 | 2 years ago |
Gergely Nagy | 26340b7edb | 2 years ago |
Gergely Nagy | 8ac4d9f5c1 | 2 years ago |
Gergely Nagy | a9f4f16e31 | 2 years ago |
Jesse Vincent | 7b66d8dfb5 | 2 years ago |
Jesse Vincent | 8196adab6c | 2 years ago |
Gergely Nagy | 96fbfb0628 | 2 years ago |
Gergely Nagy | a4b84057b0 | 2 years ago |
Jesse Vincent | 62a0fae04d | 2 years ago |
Gergely Nagy | cd82afd50a | 2 years ago |
Gergely Nagy | 7f4090f126 | 2 years ago |
Jesse Vincent | 63bcf212f3 | 2 years ago |
Gergely Nagy | db7b0af730 | 2 years ago |
Jesse Vincent | f3fe7c9023 | 2 years ago |
Taylor Yu | 1301bebc09 | 2 years ago |
Taylor Yu | d16f2c93b8 | 2 years ago |
Jesse Vincent | becf816dbe | 2 years ago |
Taylor Yu | af3dc61710 | 2 years ago |
Jesse Vincent | 35aa03b63d | 2 years ago |
Taylor Yu | 4a030ae7e8 | 2 years ago |
Taylor Yu | cf66803288 | 2 years ago |
Jesse Vincent | 8f3fab579b | 2 years ago |
Gergely Nagy | b114110645 | 2 years ago |
Gergely Nagy | e52cf5c821 | 2 years ago |
Jesse Vincent | f5639dd5ba | 2 years ago |
Gergely Nagy | 9d0dddb79a | 2 years ago |
Jesse Vincent | 51b272e598 | 2 years ago |
Tatsuhiko Miyagawa | 1e36ab17a6 | 2 years ago |
Jesse Vincent | 9d374292ba | 2 years ago |
Gergely Nagy | 9b9911bdb5 | 2 years ago |
Gergely Nagy | dde7caeee9 | 2 years ago |
Gergely Polonkai | d794035f6c | 2 years ago |
Jesse Vincent | 4087f43534 | 2 years ago |
Gergely Nagy | 6fd2fa153b | 2 years ago |
Jesse Vincent | bc0466aa22 | 2 years ago |
Gergely Nagy | 2a902e9b74 | 2 years ago |
Jesse Vincent | d12515105f | 3 years ago |
Gergely Nagy | b243b0c1c5 | 3 years ago |
Gergely Nagy | da024d6bf9 | 3 years ago |
Gergely Nagy | b5f0fc5ec9 | 3 years ago |
Jesse Vincent | 65621738d2 | 3 years ago |
Gergely Nagy | 0e07331cbc | 3 years ago |
Gergely Nagy | e59a09e19e | 3 years ago |
Gergely Nagy | 0c6f608704 | 3 years ago |
Jesse Vincent | a61c211dee | 3 years ago |
Jesse Vincent | feca06d0c0 | 3 years ago |
Jesse Vincent | 633da94896 | 3 years ago |
Jesse Vincent | 727fd47b1f | 3 years ago |
Gergely Nagy | fc2670b99d | 3 years ago |
Michael Richters | b60ef9f0ab | 3 years ago |
Gergely Nagy | e02d446803 | 3 years ago |
Jesse Vincent | f10d5833f3 | 3 years ago |
Gergely Nagy | 5666e55d0a | 3 years ago |
Gergely Nagy | 657d33450c | 3 years ago |
Michael Richters | 0f27253f90 | 3 years ago |
Michael Richters | 7373882c88 | 3 years ago |
Michael Richters | 054dc9beb3 | 3 years ago |
Michael Richters | 3976e3dd5b | 3 years ago |
Jesse Vincent | cb9ad9f753 | 3 years ago |
Michael Richters | 274ff5eb76 | 3 years ago |
Michael Richters | 396b4220f2 | 3 years ago |
Michael Richters | d34f63e4eb | 3 years ago |
Michael Richters | 1f965da243 | 3 years ago |
Michael Richters | 2df20b1a5a | 3 years ago |
Michael Richters | 920be03cad | 3 years ago |
Michael Richters | bce72c4ddc | 3 years ago |
Michael Richters | 403ea4a8ec | 3 years ago |
Jesse Vincent | 4bcf4b85d6 | 3 years ago |
Michael Richters | 9c5df517ae | 3 years ago |
Michael Richters | f28a847329 | 3 years ago |
Michael Richters | 45c33c04f0 | 3 years ago |
Michael Richters | 041543a0b3 | 3 years ago |
Gergely Nagy | d476508e26 | 3 years ago |
Gergely Polonkai | 2923996650 | 3 years ago |
iliana etaoin | 3da0ad457a | 3 years ago |
iliana etaoin | 06aebb42b9 | 3 years ago |
iliana etaoin | a960f5a0cb | 3 years ago |
Jesse Vincent | 854f621703 | 3 years ago |
Gergely Nagy | 07dcf1dc9b | 3 years ago |
iliana etaoin | 0810321272 | 3 years ago |
iliana etaoin | 95b7a7b684 | 3 years ago |
Jesse Vincent | 6f11d89152 | 3 years ago |
Jesse Vincent | 21a67ae565 | 3 years ago |
Jesse Vincent | fe84a7afc7 | 3 years ago |
Michael Richters | 0a34e034d7 | 3 years ago |
Michael Richters | 919cb39ac9 | 3 years ago |
Michael Richters | ab52a6761d | 3 years ago |
Michael Richters | ba662f6ba1 | 3 years ago |
Jesse Vincent | 6be30469b9 | 3 years ago |
Michael Richters | ed40373986 | 3 years ago |
Gergely Nagy | 5f23dde558 | 3 years ago |
Jesse Vincent | daeb7bf2c6 | 3 years ago |
Jesse Vincent | 4fd12cd79c | 3 years ago |
Jesse Vincent | 8c15bb79ec | 3 years ago |
Jesse Vincent | 18bcebeb25 | 3 years ago |
Jesse Vincent | ceb361fa3c | 3 years ago |
Jesse Vincent | 6641fa5464 | 3 years ago |
Gergely Nagy | d29ffa72dc | 3 years ago |
Gergely Nagy | 39e607e7c7 | 3 years ago |
Gergely Nagy | 9e1c9e35f4 | 3 years ago |
Gergely Nagy | c0b99d763e | 3 years ago |
Gergely Nagy | 6106b9d6b2 | 3 years ago |
Gergely Nagy | 2dbf0f807b | 3 years ago |
Gergely Nagy | fd0795f375 | 3 years ago |
Jesse Vincent | 63df0c60b6 | 3 years ago |
Gergely Nagy | c15c895519 | 3 years ago |
Jesse Vincent | d3daeb5062 | 3 years ago |
Gergely Nagy | 40c7fa5fdb | 3 years ago |
Jesse Vincent | 4619f90297 | 3 years ago |
Gergely Nagy | be385e62c9 | 3 years ago |
Gergely Nagy | f834bd6079 | 3 years ago |
Michael Richters | 7279c073e0 | 3 years ago |
Michael Richters | 7dd8527aab | 3 years ago |
Michael Richters | f8237165c1 | 3 years ago |
Michael Richters | 7db4fca6c0 | 3 years ago |
Michael Richters | 9b04d6663c | 3 years ago |
Michael Richters | ee33b228f9 | 3 years ago |
Michael Richters | fa0bb377c7 | 3 years ago |
Michael Richters | a7e6f3f072 | 3 years ago |
Michael Richters | 21d78160f4 | 3 years ago |
Michael Richters | 4af5d6fc46 | 3 years ago |
Michael Richters | 5571c13c79 | 3 years ago |
Michael Richters | 5cee5d7d2a | 3 years ago |
Gergely Nagy | 7d08de5d23 | 3 years ago |
Michael Richters | 887eb6066e | 3 years ago |
Michael Richters | 79fc94839a | 3 years ago |
Michael Richters | 3035b7eb35 | 3 years ago |
Gergely Nagy | 1faa4e7c22 | 3 years ago |
Jesse Vincent | c92e0e4586 | 3 years ago |
Jesse Vincent | 23400122f9 | 3 years ago |
Jesse Vincent | 43f0a7e4cb | 3 years ago |
Michael Richters | b25a7d3322 | 3 years ago |
Jesse Vincent | ab72f25a39 | 3 years ago |
Michael Richters | 168cc40d59 | 3 years ago |
Michael Richters | f6cb00efad | 3 years ago |
Michael Richters | f635389b33 | 3 years ago |
Michael Richters | b6a8bb6dbd | 3 years ago |
Michael Richters | 674f6a0828 | 3 years ago |
Michael Richters | 6e53a6bbb3 | 3 years ago |
Michael Richters | 67d47d6904 | 3 years ago |
Michael Richters | 3de83322e5 | 3 years ago |
Michael Richters | cbf98fd70b | 3 years ago |
Michael Richters | e3d01d25cf | 3 years ago |
Jesse Vincent | 2c1f8913b4 | 3 years ago |
Michael Richters | 8477d8e0d2 | 3 years ago |
Jesse Vincent | 039818e482 | 3 years ago |
Jesse Vincent | 94a7131b1c | 3 years ago |
Michael Richters | 8af3584ea8 | 3 years ago |
Michael Richters | ca0f80d607 | 3 years ago |
Michael Richters | 418fdcad7e | 3 years ago |
Michael Richters | c28910a04d | 3 years ago |
Michael Richters | dee60b0fce | 3 years ago |
Michael Richters | 97b5de717a | 3 years ago |
Michael Richters | bccfad592c | 3 years ago |
Jesse Vincent | ea291858b2 | 3 years ago |
Jesse Vincent | 40ec622ba3 | 3 years ago |
Michael Richters | 5d5ad0871d | 3 years ago |
Michael Richters | f9697e25f3 | 3 years ago |
Michael Richters | 56c12996ad | 3 years ago |
Michael Richters | da03cbeccb | 3 years ago |
Michael Richters | 3d0482f0db | 3 years ago |
Michael Richters | 216fb72ce5 | 3 years ago |
Michael Richters | 5c0f20ca58 | 3 years ago |
Michael Richters | 5d1d7ae003 | 3 years ago |
Jesse Vincent | 3c3ff1efc8 | 3 years ago |
Gergely Nagy | 6ba52122e2 | 3 years ago |
Jesse Vincent | c208f02715 | 3 years ago |
Jesse Vincent | 80868274e5 | 3 years ago |
Gergely Nagy | 22a6c092fc | 3 years ago |
Jesse Vincent | 83f9dec385 | 3 years ago |
Gergely Nagy | e7e7fe75fe | 3 years ago |
Jesse Vincent | c978eb8133 | 3 years ago |
Gergely Nagy | 8ac8bb4a33 | 3 years ago |
Gergely Nagy | dc51a0cd61 | 3 years ago |
Jesse Vincent | cae997f59b | 3 years ago |
Jesse Vincent | faf132839d | 3 years ago |
Jesse Vincent | 50008ddd5a | 3 years ago |
Jesse Vincent | 4ca969092b | 3 years ago |
Jesse Vincent | cd41471643 | 3 years ago |
Jesse Vincent | 5805fb1117 | 3 years ago |
Jesse Vincent | fa6b6dc6bd | 3 years ago |
Jesse Vincent | 430b5bac53 | 3 years ago |
Jesse Vincent | 938536f553 | 3 years ago |
Jesse Vincent | fbbead928b | 3 years ago |
Jesse Vincent | 493528a556 | 3 years ago |
Jesse Vincent | 091419c919 | 3 years ago |
Jesse Vincent | b71ed0cdad | 3 years ago |
Jesse Vincent | 65dd53ba17 | 3 years ago |
Jesse Vincent | d132ad2446 | 3 years ago |
Jesse Vincent | 968f2cbb1a | 3 years ago |
Jesse Vincent | 784dd83167 | 3 years ago |
Jesse Vincent | 89678327a4 | 3 years ago |
Jesse Vincent | 7cb1e225b7 | 3 years ago |
Jesse Vincent | b83604d37e | 3 years ago |
Jesse Vincent | 5f03dbd245 | 3 years ago |
Jesse Vincent | 67155b84ad | 3 years ago |
Jesse Vincent | 72f3118c6b | 3 years ago |
Jesse Vincent | 572d772a8e | 3 years ago |
Jesse Vincent | 25eadfd0a6 | 3 years ago |
Jesse Vincent | 855ed3e9bc | 3 years ago |
Jesse Vincent | c3568c9d62 | 3 years ago |
Jesse Vincent | aba8c9ee66 | 3 years ago |
Michael Richters | e5d67efd58 | 3 years ago |
Michael Richters | dfd9bff7bd | 3 years ago |
Michael Richters | 69333badc9 | 3 years ago |
Michael Richters | 3252f9fb2b | 3 years ago |
Jesse Vincent | f195690dd4 | 3 years ago |
Gergely Nagy | b93b38da22 | 3 years ago |
Gergely Nagy | a7a29bb658 | 3 years ago |
Jesse Vincent | 7a9588e404 | 3 years ago |
Jesse Vincent | 69d14584b7 | 3 years ago |
Jesse Vincent | d1911c8395 | 3 years ago |
Jesse Vincent | 2a1fb9014d | 3 years ago |
Jesse Vincent | 1f49a16bf1 | 3 years ago |
Jesse Vincent | 372adb58c1 | 3 years ago |
Jesse Vincent | dbeed3c767 | 3 years ago |
Jesse Vincent | e2ca8ee815 | 3 years ago |
Jesse Vincent | 628117478e | 3 years ago |
Jesse Vincent | eeb6d00637 | 3 years ago |
Jesse Vincent | 0a3bff2df4 | 3 years ago |
Jesse Vincent | 0fc1cc89da | 3 years ago |
Jesse Vincent | a273b47ab2 | 3 years ago |
Michael Richters | cf5c19dd6c | 3 years ago |
Jesse Vincent | c260722937 | 3 years ago |
Michael Richters | cbc36724cd | 3 years ago |
Michael Richters | 98200b25b3 | 3 years ago |
Michael Richters | fd98ea2207 | 3 years ago |
Michael Richters | 80953368d1 | 3 years ago |
Michael Richters | 42b81bae96 | 3 years ago |
Jesse Vincent | dd44da41e4 | 3 years ago |
Gergely Nagy | 8f58179241 | 3 years ago |
Jesse Vincent | 68bbfd2b9f | 3 years ago |
Michael Richters | 8e29f3a705 | 3 years ago |
Michael Richters | e008b3240e | 3 years ago |
Michael Richters | 48ce259ae5 | 3 years ago |
Michael Richters | ec834f2fe5 | 3 years ago |
Michael Richters | 54ca31f959 | 3 years ago |
Michael Richters | c0da4643b3 | 3 years ago |
Michael Richters | ef7956a0a5 | 3 years ago |
Gergely Nagy | 93d6fa7dec | 3 years ago |
Gergely Nagy | eaca11af4a | 3 years ago |
Gergely Nagy | 9f69e430ea | 3 years ago |
Gergely Nagy | c4fcb7fc21 | 3 years ago |
Gergely Nagy | d33a93026a | 3 years ago |
Michael Richters | 23d22cc994 | 3 years ago |
SylvainJuge | 447ac1bb65 | 3 years ago |
Jesse Vincent | 275d45f479 | 3 years ago |
Jesse Vincent | 1b3362341b | 3 years ago |
Jesse Vincent | 84f0b3307f | 3 years ago |
Jesse Vincent | 7a2436f80b | 3 years ago |
Michael Richters | b3bf1ae421 | 3 years ago |
Michael Richters | 5a9025123e | 3 years ago |
Michael Richters | 3d3b531571 | 3 years ago |
Michael Richters | 06196fb20b | 3 years ago |
Jesse Vincent | 72ee63386e | 3 years ago |
Michael Richters | 85823f45f2 | 3 years ago |
Simon-Claudius | ec7db6a74d | 3 years ago |
Jesse Vincent | f5bbd61784 | 3 years ago |
Jesse Vincent | 77c8f394df | 3 years ago |
Michael Richters | a0751f25c8 | 3 years ago |
Michael Richters | f47c750681 | 3 years ago |
Jesse Vincent | da844e4a1e | 3 years ago |
Michael Richters | d87de66e04 | 3 years ago |
Jesse Vincent | dd54510431 | 3 years ago |
Jesse Vincent | 552790b21f | 3 years ago |
Michael Richters | 71a09389bf | 3 years ago |
Michael Richters | 535a4e8e90 | 3 years ago |
Michael Richters | 3204034089 | 3 years ago |
Michael Richters | a0c62ff0db | 3 years ago |
Michael Richters | a1c1fe6ba2 | 3 years ago |
Michael Richters | fd17553f1a | 3 years ago |
Michael Richters | 8aa9206a08 | 3 years ago |
Jesse Vincent | d898725725 | 3 years ago |
Jesse Vincent | 9357dcec8e | 3 years ago |
Jesse Vincent | 7844aeed5e | 3 years ago |
Jesse Vincent | 2370de647c | 3 years ago |
Michael Richters | 46311f0a64 | 3 years ago |
Michael Richters | f9b9c27852 | 3 years ago |
Michael Richters | 29ebffe099 | 3 years ago |
Michael Richters | 0670113b66 | 3 years ago |
Michael Richters | e87306144e | 3 years ago |
Michael Richters | e8c84a0e47 | 3 years ago |
Michael Richters | 72c2e0fe27 | 3 years ago |
Jesse Vincent | 48d43ae259 | 3 years ago |
Michael Richters | 419f317bbc | 3 years ago |
Michael Richters | ce31989a9c | 3 years ago |
Michael Richters | 2c40e908d5 | 3 years ago |
Michael Richters | f2d8e91332 | 3 years ago |
Michael Richters | 3152270585 | 3 years ago |
Michael Richters | 340d422a24 | 3 years ago |
Michael Richters | d0542ac6eb | 3 years ago |
Michael Richters | b57daf53a8 | 3 years ago |
Michael Richters | 6ee4539654 | 3 years ago |
Michael Richters | 7b1d45d1fb | 3 years ago |
Michael Richters | 7294317846 | 3 years ago |
Michael Richters | c8ab42103a | 3 years ago |
Michael Richters | f833b8f879 | 3 years ago |
Michael Richters | 07f65584d2 | 3 years ago |
Jesse Vincent | 1be7928480 | 3 years ago |
Jesse Vincent | 3f4f2dcedb | 3 years ago |
Jesse Vincent | e5977d0d4f | 3 years ago |
Jesse Vincent | ffb84e071e | 3 years ago |
Jesse Vincent | 953d97b0c7 | 3 years ago |
Gergely Nagy | d4f6430c66 | 3 years ago |
Michael Richters | 765ed7155c | 3 years ago |
Michael Richters | 6137ae3335 | 3 years ago |
Michael Richters | 1eb7949f90 | 3 years ago |
Michael Richters | 38988df273 | 3 years ago |
Jesse Vincent | a4f327df7a | 3 years ago |
Gergely Nagy | a5c11db084 | 3 years ago |
Jesse Vincent | 26c02a9a10 | 3 years ago |
Jesse Vincent | 23a98d64bc | 3 years ago |
Jesse Vincent | bd5e7b326a | 3 years ago |
Jesse Vincent | 258b03a45c | 3 years ago |
Jesse Vincent | 26a3034578 | 3 years ago |
Jesse Vincent | 4584210cda | 3 years ago |
Michael Richters | ebad8940fb | 3 years ago |
Michael Richters | 561907db57 | 3 years ago |
Gergely Nagy | ab4ee0babd | 3 years ago |
Jesse Vincent | fbfede3566 | 3 years ago |
Jesse Vincent | ec6248f92b | 3 years ago |
Michael Richters | e31fe2be10 | 3 years ago |
Michael Richters | b68ea18212 | 3 years ago |
Michael Richters | ca1e23093e | 3 years ago |
Jesse Vincent | 6a1506eeac | 3 years ago |
Jesse Vincent | 7b354403f8 | 3 years ago |
Michael Richters | c3ea0876c1 | 3 years ago |
Michael Richters | c1bb8b2545 | 3 years ago |
Michael Richters | 4480b08b2d | 3 years ago |
Jesse Vincent | 54fbb04eb6 | 3 years ago |
Michael Richters | 381b05e10f | 3 years ago |
Jesse Vincent | 46d9f06d77 | 3 years ago |
Jesse Vincent | 5c7ffe6383 | 3 years ago |
Jesse Vincent | 62f668fd25 | 3 years ago |
Jesse Vincent | c9943057f4 | 3 years ago |
Jesse Vincent | 34e630438b | 3 years ago |
Jesse Vincent | aa34c150d2 | 3 years ago |
Jesse Vincent | 80e7408e03 | 3 years ago |
Jesse Vincent | 1d3c7b3399 | 3 years ago |
Jesse Vincent | 5ca95d0deb | 3 years ago |
Gergely Nagy | d59604e98b | 3 years ago |
Jesse Vincent | 839effdfd5 | 3 years ago |
Michael Richters | 2c31dfec50 | 3 years ago |
Michael Richters | 99d47447ad | 3 years ago |
Jesse Vincent | b685729503 | 3 years ago |
Michael Richters | 543372d53a | 3 years ago |
Michael Richters | 14a2a645d6 | 3 years ago |
Jesse Vincent | 54573a9b8c | 3 years ago |
Joshua Hunt | 9e802112f0 | 3 years ago |
Jesse Vincent | fd834c2ffa | 3 years ago |
Jesse Vincent | 4fe8795bfe | 3 years ago |
Jesse Vincent | 5c9de2f58f | 3 years ago |
Gergely Nagy | 75acb8de40 | 3 years ago |
Jesse Vincent | d6b7d7d4c8 | 3 years ago |
Gergely Nagy | 4b1e122317 | 3 years ago |
Gergely Nagy | 32c175d51e | 3 years ago |
Jesse Vincent | 532253c234 | 3 years ago |
Jesse Vincent | b4bcdbd06d | 3 years ago |
Jesse Vincent | efdae81b3a | 3 years ago |
Gergely Nagy | ddad1305e2 | 3 years ago |
Gergely Nagy | f3604d3317 | 3 years ago |
Gergely Nagy | 4d1e59e769 | 3 years ago |
Jesse Vincent | 1d8eb6d2e2 | 3 years ago |
Jesse Vincent | d3216aed95 | 3 years ago |
Jesse Vincent | 1d70cf2dc8 | 3 years ago |
Jesse Vincent | 6b9496e2dc | 3 years ago |
Jesse Vincent | 2962f0f0c9 | 3 years ago |
Jesse Vincent | 40ce430861 | 3 years ago |
Jesse Vincent | da83001116 | 3 years ago |
Jesse Vincent | 5a566d6ecf | 3 years ago |
Jesse Vincent | 14f2ef8c3e | 3 years ago |
Jesse Vincent | addc341184 | 3 years ago |
Jesse Vincent | 4c84e8c093 | 3 years ago |
Jesse Vincent | 6a3e2d4eee | 3 years ago |
Michael Richters | c5bd030084 | 3 years ago |
Jesse Vincent | 15ee5573c1 | 3 years ago |
Michael Richters | 926a5f6f5e | 3 years ago |
Michael Richters | d3bcd45c29 | 3 years ago |
Jesse Vincent | 1ae48b9507 | 3 years ago |
Jesse Vincent | 14a2a5dea6 | 3 years ago |
@ -0,0 +1,47 @@
|
|||||||
|
# -*- mode: yaml -*-
|
||||||
|
---
|
||||||
|
BasedOnStyle: Google
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
|
||||||
|
AlignConsecutiveAssignments: Consecutive
|
||||||
|
## clang-format-15
|
||||||
|
# AlignConsecutiveAssignments:
|
||||||
|
# Enabled: true
|
||||||
|
# AlignCompound: true
|
||||||
|
# PadOperators: true
|
||||||
|
AlignConsecutiveDeclarations: None
|
||||||
|
AlignConsecutiveMacros: AcrossEmptyLines
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AttributeMacros:
|
||||||
|
- __attribute__((weak))
|
||||||
|
- __attribute__((always_inline))
|
||||||
|
- __attribute__((noinline))
|
||||||
|
- __attribute__((packed))
|
||||||
|
- __attribute__((optimize(3)))
|
||||||
|
- __attribute__((unused))
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
# BraceWrapping:
|
||||||
|
# SplitEmptyFunction: false
|
||||||
|
# SplitEmptyRecord: true
|
||||||
|
# SplitEmptyNamespace: true
|
||||||
|
# BreakBeforeBraces: Custom
|
||||||
|
ColumnLimit: 0
|
||||||
|
ConstructorInitializerIndentWidth: 2
|
||||||
|
ContinuationIndentWidth: 2
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
IndentCaseLabels: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
# PackConstructorInitializers: CurrentLine
|
||||||
|
PointerAlignment: Right
|
||||||
|
# ReferenceAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
@ -0,0 +1,9 @@
|
|||||||
|
set noparent
|
||||||
|
|
||||||
|
extensions=cpp,h,ino
|
||||||
|
|
||||||
|
filter=-build/include
|
||||||
|
filter=-legal/copyright
|
||||||
|
filter=-readability/namespace
|
||||||
|
filter=-runtime/references
|
||||||
|
filter=-whitespace
|
@ -0,0 +1,9 @@
|
|||||||
|
set noparent
|
||||||
|
|
||||||
|
extensions=cpp,h,ino
|
||||||
|
|
||||||
|
filter=-build/include
|
||||||
|
filter=-legal/copyright
|
||||||
|
filter=-readability/namespace
|
||||||
|
filter=-runtime/references
|
||||||
|
filter=-whitespace/line_length
|
@ -0,0 +1,14 @@
|
|||||||
|
examples
|
||||||
|
src/Kaleidoscope.h
|
||||||
|
src/Kaleidoscope-LEDControl.h
|
||||||
|
src/kaleidoscope/HIDTables.h
|
||||||
|
src/kaleidoscope/driver/bootloader/gd32/Base.h
|
||||||
|
src/kaleidoscope/driver/led/Base.h
|
||||||
|
src/kaleidoscope/driver/led/WS2812.h
|
||||||
|
src/kaleidoscope/driver/led/ws2812/config.h
|
||||||
|
src/kaleidoscope/driver/mcu/GD32.h
|
||||||
|
src/kaleidoscope/driver/storage/GD32Flash.h
|
||||||
|
plugins/Kaleidoscope-FirmwareDump/**
|
||||||
|
plugins/Kaleidoscope-HostOS/src/kaleidoscope/plugin/HostOS.h
|
||||||
|
plugins/Kaleidoscope-Hardware-EZ-ErgoDox/src/kaleidoscope/device/ez/ErgoDox/i2cmaster.h
|
||||||
|
testing/googletest
|
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
: "${KALEIDOSCOPE_DIR:=$(pwd)}"
|
||||||
|
cd "${KALEIDOSCOPE_DIR}" || exit 1
|
||||||
|
|
||||||
|
ERROR_COUNT=0
|
||||||
|
|
||||||
|
while read -r SCRIPT; do
|
||||||
|
shellcheck "${SCRIPT}"
|
||||||
|
(( ERROR_COUNT += $? ))
|
||||||
|
done < <(grep -E -n -r -l '(env (ba)?sh)|(/bin/(ba)?sh)' "${KALEIDOSCOPE_DIR}/bin")
|
||||||
|
|
||||||
|
exit $ERROR_COUNT
|
@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) 2022 Michael Richters <gedankenexperimenter@gmail.com>
|
||||||
|
|
||||||
|
# This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
# distribute this software, either in source code form or as a compiled
|
||||||
|
# binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
# means.
|
||||||
|
|
||||||
|
# In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
# of this software dedicate any and all copyright interest in the
|
||||||
|
# software to the public domain. We make this dedication for the benefit
|
||||||
|
# of the public at large and to the detriment of our heirs and
|
||||||
|
# successors. We intend this dedication to be an overt act of
|
||||||
|
# relinquishment in perpetuity of all present and future rights to this
|
||||||
|
# software under copyright law.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# For more information, please refer to <http://unlicense.org/>
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
"""Utilities shared by Kaleidoscope code maintenance tools."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
@contextmanager
|
||||||
|
def cwd(temp_wd):
|
||||||
|
"""Execute code in a different working directory
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
`temp_wd` (`str`): The name of a directory to (temporarily) change to
|
||||||
|
|
||||||
|
Change the current working directory, then automatically restore the previous working
|
||||||
|
directory when done. Invoke `cwd()` like this:
|
||||||
|
```py
|
||||||
|
with cwd(temp_wd):
|
||||||
|
...
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
old_wd = os.getcwd()
|
||||||
|
os.chdir(temp_wd)
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
os.chdir(old_wd)
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def split_on_newlines(string):
|
||||||
|
"""Split the string using newlines as the separator."""
|
||||||
|
return string.splitlines()
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
def split_on_nulls(string):
|
||||||
|
"""Split the input string using NULL characters as the separator."""
|
||||||
|
targets = [_ for _ in string.split('\0') if _ != '']
|
||||||
|
return targets or []
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def setup_logging(loglevel):
|
||||||
|
"""Set up basic logging."""
|
||||||
|
logformat = "%(message)s"
|
||||||
|
logging.basicConfig(
|
||||||
|
level=loglevel,
|
||||||
|
stream=sys.stdout,
|
||||||
|
format=logformat,
|
||||||
|
datefmt="",
|
||||||
|
)
|
||||||
|
return logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def check_git_diff():
|
||||||
|
"""Check for unstaged changes with `git diff`
|
||||||
|
|
||||||
|
Returns: a list of the names of files with unstaged changes
|
||||||
|
|
||||||
|
This check isn't perfect, because it can give false positives (if there are unrelated
|
||||||
|
unstaged changes).
|
||||||
|
"""
|
||||||
|
git_diff_cmd = ['git', 'diff', '-z', '--exit-code', '--name-only']
|
||||||
|
|
||||||
|
changed_files = []
|
||||||
|
proc = subprocess.run(git_diff_cmd, capture_output=True)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
changed_files = split_on_nulls(proc.stdout.decode('utf-8'))
|
||||||
|
return changed_files
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(1)
|
File diff suppressed because it is too large
Load Diff
@ -1,55 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# find-filename-conflicts - Finds cpp files with conflicting filenames
|
|
||||||
# Copyright (C) 2020 Keyboard.io, Inc.
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify it under
|
|
||||||
# the terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, version 3.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
## When building Kaleidoscope, the compiled object files are linked together
|
|
||||||
## into a static archive. This static archive has a very simple structure, and
|
|
||||||
## only stores filenames, not paths, not even relative ones. As such, we can't
|
|
||||||
## have files with the same name, because they will conflict, and one will
|
|
||||||
## override the other.
|
|
||||||
##
|
|
||||||
## To avoid this situation, this script will find all cpp source files (we don't
|
|
||||||
## need to care about header-only things, those do not result in an object
|
|
||||||
## file), and will comb through them to find conflicting filenames.
|
|
||||||
##
|
|
||||||
## If a conflict is found, it will print all files that share the name, and will
|
|
||||||
## exit with an error at the end. It does not exit at the first duplicate, but
|
|
||||||
## will find and print all of them.
|
|
||||||
##
|
|
||||||
## If no conflict is found, the script just prints its status message and exits
|
|
||||||
## with zero.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
FILE_LIST="$(find src -name '*.cpp' | sed -e 's,\(\(.*\)/\([^/]*\)\),\3 \1,')"
|
|
||||||
|
|
||||||
exit_code=0
|
|
||||||
|
|
||||||
echo -n "Looking for conflicting filenames... "
|
|
||||||
|
|
||||||
for f in $(echo "${FILE_LIST}" | cut -f1 -d" "); do
|
|
||||||
count=$(echo "${FILE_LIST}" | grep -c "^${f}")
|
|
||||||
if [ "$count" -gt 1 ]; then
|
|
||||||
echo >&2
|
|
||||||
echo " Conflict found for ${f}: " >&2
|
|
||||||
echo "${FILE_LIST}" | grep "${f}" | cut -d" " -f2 | sed -e 's,^, ,' >&2
|
|
||||||
exit_code=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "${exit_code}" -eq 0 ]; then
|
|
||||||
echo "done."
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit ${exit_code}
|
|
@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) 2022 Michael Richters <gedankenexperimenter@gmail.com>
|
||||||
|
|
||||||
|
# This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
# distribute this software, either in source code form or as a compiled
|
||||||
|
# binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
# means.
|
||||||
|
|
||||||
|
# In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
# of this software dedicate any and all copyright interest in the
|
||||||
|
# software to the public domain. We make this dedication for the benefit
|
||||||
|
# of the public at large and to the detriment of our heirs and
|
||||||
|
# successors. We intend this dedication to be an overt act of
|
||||||
|
# relinquishment in perpetuity of all present and future rights to this
|
||||||
|
# software under copyright law.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# For more information, please refer to <http://unlicense.org/>
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
"""When building Kaleidoscope, the compiled object files are linked together
|
||||||
|
into a static archive. This static archive has a very simple structure, and only
|
||||||
|
stores filenames, not paths, not even relative ones. As such, we can't have
|
||||||
|
files with the same name, because they will conflict, and one will override the
|
||||||
|
other.
|
||||||
|
|
||||||
|
To avoid this situation, this script will find all cpp source files (we don't
|
||||||
|
need to care about header-only things, those do not result in an object file),
|
||||||
|
and will comb through them to find conflicting filenames.
|
||||||
|
|
||||||
|
If a conflict is found, it will print all files that share the name, and will
|
||||||
|
exit with an error at the end. It does not exit at the first duplicate, but will
|
||||||
|
find and print all of them.
|
||||||
|
|
||||||
|
If no conflict is found, the script just prints its status message and exits
|
||||||
|
with zero."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
cpp_regex = re.compile('.*\.cpp')
|
||||||
|
|
||||||
|
|
||||||
|
def find_duplicates(root):
|
||||||
|
"""Search for files with the same basename, but in different directories in
|
||||||
|
the tree under <root>. Prints a message for each conflict found, and
|
||||||
|
returns a count of the number of non-unique basenames."""
|
||||||
|
|
||||||
|
# Search the specified tree for matching basenames:
|
||||||
|
basenames = {}
|
||||||
|
for dir_path, dirs, files in os.walk(root):
|
||||||
|
for file_name in files:
|
||||||
|
if cpp_regex.match(file_name):
|
||||||
|
if file_name not in basenames:
|
||||||
|
basenames[file_name] = []
|
||||||
|
basenames[file_name].append(dir_path)
|
||||||
|
|
||||||
|
conflict_count = 0
|
||||||
|
for file_name, dirs in basenames.items():
|
||||||
|
# Prune unique basenames from the dict:
|
||||||
|
if len(dirs) <= 1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
conflict_count += 1
|
||||||
|
# Print info about basenames with conflicts:
|
||||||
|
print(f"Conflict found for file name '{file_name}':")
|
||||||
|
for root in dirs:
|
||||||
|
path = os.path.join(root, file_name)
|
||||||
|
print(f' -> {path}')
|
||||||
|
|
||||||
|
return conflict_count
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
print('Searching for conflicting filenames...')
|
||||||
|
exit_code = 0
|
||||||
|
for path in args:
|
||||||
|
exit_code += find_duplicates(path)
|
||||||
|
if exit_code != 0:
|
||||||
|
sys.exit(exit_code)
|
||||||
|
print('No filename conflicts found.')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(sys.argv[1:])
|
@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# In case it hasn't been set, assume we're being run from the root of the local
|
||||||
|
# Kaleidoscope repository.
|
||||||
|
: "${KALEIDOSCOPE_DIR:=$(pwd)}"
|
||||||
|
|
||||||
|
# This variable is a git ref that should point to the current master branch of
|
||||||
|
# the primary Kaleidoscope repository. In most cases, this would be
|
||||||
|
# `origin/master`.
|
||||||
|
: "${KALEIDOSCOPE_MERGE_BASE:=origin/master}"
|
||||||
|
|
||||||
|
# Don't do anything if the working tree has unstaged changes, to avoid
|
||||||
|
# unintentional combining of contentful changes with formatting changes.
|
||||||
|
if ! git diff -z --exit-code --quiet; then
|
||||||
|
echo "Working tree has unstaged changes; aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run git-diff so we only run IWYU on files that differ from `master`. This
|
||||||
|
# isn't necessarily what we want, but if the current branch has been rebased, it
|
||||||
|
# shouldn't touch any extra files.
|
||||||
|
git diff -z --name-only "${KALEIDOSCOPE_MERGE_BASE}" -- src plugins \
|
||||||
|
| "${KALEIDOSCOPE_DIR}/bin/iwyu.py" -z -v
|
||||||
|
|
||||||
|
# After running it on Kaleidoscope source files, run it on the test simulator,
|
||||||
|
# which requires some additional include dirs.
|
||||||
|
git diff -z --name-only "${KALEIDOSCOPE_MERGE_BASE}" -- testing \
|
||||||
|
| "${KALEIDOSCOPE_DIR}/bin/iwyu.py" \
|
||||||
|
-z -v \
|
||||||
|
-I="${KALEIDOSCOPE_DIR}" \
|
||||||
|
-I="${KALEIDOSCOPE_DIR}/testing/googletest/googlemock/include" \
|
||||||
|
-I="${KALEIDOSCOPE_DIR}/testing/googletest/googletest/include"
|
||||||
|
|
||||||
|
# Always run clang-format after IWYU, because they have different indentation
|
||||||
|
# rules for comments added by IWYU.
|
||||||
|
git diff -z --name-only "${KALEIDOSCOPE_MERGE_BASE}" -- src plugins testing \
|
||||||
|
| "${KALEIDOSCOPE_DIR}/bin/format-code.py" \
|
||||||
|
-z -v \
|
||||||
|
--exclude-dir='testing/googletest' \
|
||||||
|
--exclude-file='generated-testcase.cpp' \
|
||||||
|
--force \
|
||||||
|
--check \
|
||||||
|
--verbose
|
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# focus-send - Trivial Focus testing tool
|
||||||
|
# Copyright (C) 2018-2022 Keyboard.io, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation, version 3.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OS=$(uname -s)
|
||||||
|
|
||||||
|
# igncr absorbs CR from Focus CRLF line endings
|
||||||
|
# -echo is needed because raw doesn't turn it off on Linux
|
||||||
|
STTY_ARGS="9600 raw igncr -echo"
|
||||||
|
|
||||||
|
case ${OS} in
|
||||||
|
Linux)
|
||||||
|
DEVICE="${DEVICE:-/dev/ttyACM0}"
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
# bash on macOS has a bug that randomly drops serial input
|
||||||
|
if [ -n "$BASH_VERSION" ] && [ -x /bin/dash ]; then
|
||||||
|
# Prevent loop in case someone exported it
|
||||||
|
export -n BASH_VERSION
|
||||||
|
exec /bin/dash "$0" "$@"
|
||||||
|
fi
|
||||||
|
DEVICE="${DEVICE:-/dev/cu.usbmodemCkbio01E}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Error Unknown OS : ${OS}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Redirect prior to running stty, because macOS sometimes resets termios
|
||||||
|
# state upon last close of a terminal device.
|
||||||
|
exec < "${DEVICE}"
|
||||||
|
# shellcheck disable=SC2086 # intentional word splitting
|
||||||
|
stty $STTY_ARGS
|
||||||
|
|
||||||
|
read_reply () {
|
||||||
|
while read -r line; do
|
||||||
|
if [ "${line}" = "." ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "${line}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Flush any invalid commands out of input buffer.
|
||||||
|
# This could happen after a failed upload.
|
||||||
|
echo ' ' > "${DEVICE}"
|
||||||
|
read_reply > /dev/null
|
||||||
|
echo "$@" >"${DEVICE}"
|
||||||
|
read_reply
|
@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# focus-test - Trivial Focus testing tool
|
|
||||||
# Copyright (C) 2018 Keyboard.io, Inc.
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify it under
|
|
||||||
# the terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, version 3.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
OS=$(uname -s)
|
|
||||||
|
|
||||||
case ${OS} in
|
|
||||||
Linux)
|
|
||||||
DEVICE="${DEVICE:-/dev/ttyACM0}"
|
|
||||||
stty -F "${DEVICE}" 9600 raw -echo
|
|
||||||
;;
|
|
||||||
Darwin)
|
|
||||||
DEVICE="${DEVICE:-/dev/cu.usbmodemCkbio01E}"
|
|
||||||
stty -f "${DEVICE}" 9600 raw -echo
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Error Unknown OS : ${OS}" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
|
|
||||||
exec 3<"${DEVICE}"
|
|
||||||
echo "$@" >"${DEVICE}"
|
|
||||||
|
|
||||||
while read -r line <&3; do
|
|
||||||
line="$(echo -n "${line}" | tr -d '\r')"
|
|
||||||
if [ "${line}" == "." ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
echo "${line}"
|
|
||||||
done
|
|
@ -0,0 +1,275 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) 2022 Michael Richters <gedankenexperimenter@gmail.com>
|
||||||
|
|
||||||
|
# This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
# distribute this software, either in source code form or as a compiled
|
||||||
|
# binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
# means.
|
||||||
|
|
||||||
|
# In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
# of this software dedicate any and all copyright interest in the
|
||||||
|
# software to the public domain. We make this dedication for the benefit
|
||||||
|
# of the public at large and to the detriment of our heirs and
|
||||||
|
# successors. We intend this dedication to be an overt act of
|
||||||
|
# relinquishment in perpetuity of all present and future rights to this
|
||||||
|
# software under copyright law.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# For more information, please refer to <http://unlicense.org/>
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
"""This script runs clang-format on a Kaleidoscope repository."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.dont_write_bytecode = True
|
||||||
|
|
||||||
|
from common import check_git_diff, setup_logging, split_on_newlines, split_on_nulls
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def parse_args(args):
|
||||||
|
"""Parse command line parameters
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args (list[str]): command line parameters as list of strings
|
||||||
|
(for example ``["--help"]``).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`argparse.Namespace`: command line parameters namespace
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="""
|
||||||
|
Recursively search specified directories and format source files with
|
||||||
|
clang-format. By default, it operates on Arduino C++ source files with
|
||||||
|
extensions: *.{cpp,h,hpp,inc,ino}.""")
|
||||||
|
parser.add_argument(
|
||||||
|
'-q',
|
||||||
|
'--quiet',
|
||||||
|
dest='loglevel',
|
||||||
|
action='store_const',
|
||||||
|
const=logging.ERROR,
|
||||||
|
default=logging.WARNING,
|
||||||
|
help="""
|
||||||
|
Suppress output except warnings and errors.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-v',
|
||||||
|
'--verbose',
|
||||||
|
action='store_const',
|
||||||
|
dest='loglevel',
|
||||||
|
const=logging.INFO,
|
||||||
|
help="""
|
||||||
|
Output verbose debugging information.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-d',
|
||||||
|
'--debug',
|
||||||
|
action='store_const',
|
||||||
|
dest='loglevel',
|
||||||
|
const=logging.DEBUG,
|
||||||
|
help="""
|
||||||
|
Save output from `include-what-you-use` for processed files beside the originals, with
|
||||||
|
a '.iwyu' suffix, for debugging purposes.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-X',
|
||||||
|
'--exclude-dir',
|
||||||
|
action='append',
|
||||||
|
dest='exclude_dirs',
|
||||||
|
default=[],
|
||||||
|
metavar="<path>",
|
||||||
|
help="""
|
||||||
|
Exclude dir from search (path relative to the pwd)""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-x',
|
||||||
|
'--exclude-file',
|
||||||
|
action='append',
|
||||||
|
dest='exclude_files',
|
||||||
|
default=[],
|
||||||
|
metavar="<file>",
|
||||||
|
help="""
|
||||||
|
Exclude <file> (base name only, not a full path) from formatting""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-r',
|
||||||
|
'--regex',
|
||||||
|
dest='regex',
|
||||||
|
default=r'\.(cpp|h|hpp|inc|ino)$',
|
||||||
|
metavar="<regex>",
|
||||||
|
help="""
|
||||||
|
Regular expression for matching source file names""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-z',
|
||||||
|
'-0',
|
||||||
|
action='store_const',
|
||||||
|
dest='input_splitter',
|
||||||
|
const=split_on_nulls,
|
||||||
|
default=split_on_newlines,
|
||||||
|
help="""
|
||||||
|
When reading target filenames from standard input, break on NULL characters instead
|
||||||
|
of newlines.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-f',
|
||||||
|
'--force',
|
||||||
|
action='store_true',
|
||||||
|
help="""
|
||||||
|
Format code even if there are unstaged changes""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--check',
|
||||||
|
action='store_true',
|
||||||
|
help="""
|
||||||
|
Check for changes after formatting by running `git diff --exit-code`. If there are any
|
||||||
|
changes after formatting, a non-zero exit code is returned.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'targets',
|
||||||
|
metavar="<search_dir>",
|
||||||
|
nargs='*',
|
||||||
|
help="""
|
||||||
|
A list of files and/or directories to search for source files to format.""",
|
||||||
|
)
|
||||||
|
return parser.parse_args(args)
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def main():
|
||||||
|
"""Parse command-line arguments and format source files.
|
||||||
|
"""
|
||||||
|
# Parse command-line argumets:
|
||||||
|
opts = parse_args(sys.argv[1:])
|
||||||
|
# Set up logging system:
|
||||||
|
setup_logging(opts.loglevel)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Unless we've been given the `--force` option, check for unstaged changes to avoid
|
||||||
|
# clobbering any work in progress:
|
||||||
|
exit_code = 0
|
||||||
|
if not opts.force:
|
||||||
|
changed_files = check_git_diff()
|
||||||
|
if len(changed_files) > 0:
|
||||||
|
logging.error("Working tree has unstaged changes; aborting")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Locate `clang-format` executable:
|
||||||
|
clang_format_exe = os.getenv('KALEIDOSCOPE_CODE_FORMATTER')
|
||||||
|
if clang_format_exe is None:
|
||||||
|
clang_format_exe = shutil.which('clang-format')
|
||||||
|
logging.debug("Found `clang-format` executable: %s", clang_format_exe)
|
||||||
|
clang_format_cmd = [clang_format_exe, '-i']
|
||||||
|
if opts.loglevel <= logging.INFO:
|
||||||
|
clang_format_cmd.append('--verbose')
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Read targets from command line:
|
||||||
|
targets = opts.targets
|
||||||
|
logging.debug("CLI target parameters: %s", targets)
|
||||||
|
|
||||||
|
# If stdin is a pipe, read target filenames from it:
|
||||||
|
if not sys.stdin.isatty():
|
||||||
|
targets += opts.input_splitter(sys.stdin.read())
|
||||||
|
logging.debug("All targets: %s", targets)
|
||||||
|
|
||||||
|
# Prepare exclusion lists. The file excludes are basenames only, and the dirs get
|
||||||
|
# converted to absolute path names.
|
||||||
|
exclude_files = set(opts.exclude_files)
|
||||||
|
exclude_dirs = set(os.path.abspath(_) for _ in opts.exclude_dirs)
|
||||||
|
|
||||||
|
# Convert target paths to absolute, and remove any that are excluded:
|
||||||
|
target_paths = set(os.path.abspath(_) for _ in targets if _ not in exclude_dirs)
|
||||||
|
logging.debug("Target paths: %s", target_paths)
|
||||||
|
|
||||||
|
# Build separate sets of target files and dirs. Later, we'll search target dirs and add
|
||||||
|
# matching target files to the files set.
|
||||||
|
target_files = set()
|
||||||
|
target_dirs = set()
|
||||||
|
for t in target_paths:
|
||||||
|
if os.path.isfile(t):
|
||||||
|
target_files.add(os.path.abspath(t))
|
||||||
|
elif os.path.isdir(t):
|
||||||
|
target_dirs.add(os.path.abspath(t))
|
||||||
|
logging.debug("Target files after separating: %s", target_files)
|
||||||
|
logging.debug("Target dirs after separating: %s", target_dirs)
|
||||||
|
|
||||||
|
# Remove excluded filenames:
|
||||||
|
target_files -= set(_ for _ in target_files if os.path.basename(_) in exclude_files)
|
||||||
|
|
||||||
|
# Remove files and dirs in excluded dirs:
|
||||||
|
target_files -= set(_ for _ in target_files for x in exclude_dirs if _.startswith(x))
|
||||||
|
target_dirs -= set(_ for _ in target_dirs for x in exclude_dirs if _.startswith(x))
|
||||||
|
|
||||||
|
# Compile regex for matching files to be formatted:
|
||||||
|
target_matcher = re.compile(opts.regex)
|
||||||
|
|
||||||
|
# Remove target files that don't match the regex:
|
||||||
|
logging.debug("Target files before matching regex: %s", target_files)
|
||||||
|
target_files = set(_ for _ in target_files if target_matcher.search(_))
|
||||||
|
logging.debug("Target files after matching regex: %s", target_files)
|
||||||
|
|
||||||
|
# Search target dirs for non-excluded files, and add them to `target_files`:
|
||||||
|
logging.debug("Searching target dirs: %s", target_dirs)
|
||||||
|
for path in target_dirs:
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
# Prune excluded dirs
|
||||||
|
for x in exclude_dirs:
|
||||||
|
if x in (os.path.join(root, _) for _ in dirs):
|
||||||
|
dirs.remove(os.path.basename(x))
|
||||||
|
# Add non-excluded files
|
||||||
|
for f in files:
|
||||||
|
if target_matcher.search(f) and f not in exclude_files:
|
||||||
|
target_files.add(os.path.join(root, f))
|
||||||
|
|
||||||
|
if len(target_files) == 0:
|
||||||
|
logging.error("No target files found; exiting.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Run clang-format on target files:
|
||||||
|
proc = subprocess.run(clang_format_cmd + sorted(target_files))
|
||||||
|
if proc.returncode != 0:
|
||||||
|
logging.error("Error: clang-format returned non-zero status: %s", proc.returncode)
|
||||||
|
return proc.returncode
|
||||||
|
else:
|
||||||
|
logging.info("Finished formatting target files.")
|
||||||
|
|
||||||
|
# If we've been asked to check for changes made by the formatter:
|
||||||
|
if opts.check:
|
||||||
|
logging.warning('Checking for changes made by the formatter...')
|
||||||
|
changed_files = check_git_diff()
|
||||||
|
if len(changed_files) == 0:
|
||||||
|
logging.warning("No files changed. Congratulations!")
|
||||||
|
else:
|
||||||
|
logging.warning("Found files with changes after formatting:")
|
||||||
|
exit_code = 1
|
||||||
|
for f in changed_files:
|
||||||
|
logging.warning(" %s", f)
|
||||||
|
|
||||||
|
return exit_code
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
sys.exit(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logging.info("Aborting")
|
||||||
|
sys.exit(1)
|
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
: "${KALEIDOSCOPE_DIR:=$(pwd)}"
|
||||||
|
cd "${KALEIDOSCOPE_DIR}" || exit 1
|
||||||
|
|
||||||
|
: "${VERBOSE:=}"
|
||||||
|
|
||||||
|
"${KALEIDOSCOPE_DIR}/bin/format-code.py" \
|
||||||
|
--exclude-dir 'testing/googletest' \
|
||||||
|
--exclude-file 'generated-testcase.cpp' \
|
||||||
|
--verbose \
|
||||||
|
src plugins testing
|
@ -0,0 +1,508 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) 2022 Michael Richters <gedankenexperimenter@gmail.com>
|
||||||
|
|
||||||
|
# This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
# distribute this software, either in source code form or as a compiled
|
||||||
|
# binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
# means.
|
||||||
|
|
||||||
|
# In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
# of this software dedicate any and all copyright interest in the
|
||||||
|
# software to the public domain. We make this dedication for the benefit
|
||||||
|
# of the public at large and to the detriment of our heirs and
|
||||||
|
# successors. We intend this dedication to be an overt act of
|
||||||
|
# relinquishment in perpetuity of all present and future rights to this
|
||||||
|
# software under copyright law.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# For more information, please refer to <http://unlicense.org/>
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
"""Run `include-what-you-use` on Kaleidoscope sources
|
||||||
|
|
||||||
|
This is a script for maintenance of the headers included in Kaleidoscope source
|
||||||
|
files. It is not currently possible to run this automatically on all
|
||||||
|
Kaleidoscope source files, because of the peculiarities therein. It uses
|
||||||
|
llvm/clang to determine which headers should be included in a given file, but
|
||||||
|
there's no avr-clang, so we're limited to using the virtual hardware device.
|
||||||
|
|
||||||
|
It takes any number of source files as its input, examines them and updates the
|
||||||
|
list of header `#include` directives.
|
||||||
|
|
||||||
|
It is safe to run on most Kaleidoscope source files, and a good idea to run it
|
||||||
|
on new ones (after staging them, so you can easily see what changes have been
|
||||||
|
made).
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Example invocation:
|
||||||
|
# $ git ls-files -m | grep '\.\(h\|cpp\)' | bin/iwyu.py
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import glob
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shlex
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.dont_write_bytecode = True
|
||||||
|
|
||||||
|
from common import cwd, setup_logging, split_on_newlines, split_on_nulls
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def parse_args(args):
|
||||||
|
"""Parse command line parameters
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args (list[str]): command line parameters as list of strings
|
||||||
|
(for example ``["--help"]``).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`argparse.Namespace`: command line parameters namespace
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="""
|
||||||
|
Run `include-what-you-use` on source files given as command-line arguments and/or read
|
||||||
|
from standard input. When reading target filenames from standard input, they should be
|
||||||
|
either absolute or relative to the current directory, and each line of input (minus the
|
||||||
|
line-ending character(s) is treated as a filename.""")
|
||||||
|
parser.add_argument(
|
||||||
|
'-q',
|
||||||
|
'--quiet',
|
||||||
|
dest='loglevel',
|
||||||
|
action='store_const',
|
||||||
|
const=logging.ERROR,
|
||||||
|
default=logging.WARNING,
|
||||||
|
help="""
|
||||||
|
Suppress output except warnings and errors.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-v',
|
||||||
|
'--verbose',
|
||||||
|
action='store_const',
|
||||||
|
dest='loglevel',
|
||||||
|
const=logging.INFO,
|
||||||
|
help="""
|
||||||
|
Output verbose debugging information.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-d',
|
||||||
|
'--debug',
|
||||||
|
action='store_const',
|
||||||
|
dest='loglevel',
|
||||||
|
const=logging.DEBUG,
|
||||||
|
help="""
|
||||||
|
Save output from `include-what-you-use` for processed files beside the originals, with
|
||||||
|
a '.iwyu' suffix, for debugging purposes.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-r',
|
||||||
|
'--regex',
|
||||||
|
action='store',
|
||||||
|
dest='regex',
|
||||||
|
default=r'\.(h|cpp)$',
|
||||||
|
help="""
|
||||||
|
A regular expression for matching filenames Only the basename of the file is
|
||||||
|
matched, and the regex is only used when searching a directory for files to process,
|
||||||
|
not on target filenames specified in arguments or read from standard input.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-i',
|
||||||
|
'--ignores_file',
|
||||||
|
action='store',
|
||||||
|
dest='ignores_file',
|
||||||
|
default='.iwyu_ignore',
|
||||||
|
metavar='<ignores_file>',
|
||||||
|
help="""
|
||||||
|
The name of a file (relative to KALEIDOSCOPE_DIR) that contains a list of glob patterns
|
||||||
|
that will be ignored when a target directory is searched for filenames that match
|
||||||
|
<regex>.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-I',
|
||||||
|
'--include',
|
||||||
|
action='append',
|
||||||
|
dest='include_dirs',
|
||||||
|
metavar='<dir>',
|
||||||
|
help="""
|
||||||
|
Add <dir> to the list of directories that will be searched for header files.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-z',
|
||||||
|
'-0',
|
||||||
|
action='store_const',
|
||||||
|
dest='input_splitter',
|
||||||
|
const=split_on_nulls,
|
||||||
|
default=split_on_newlines,
|
||||||
|
help="""
|
||||||
|
When reading target filenames from standard input, break on NULL characters instead
|
||||||
|
of newlines.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--update_comments',
|
||||||
|
action='store_true',
|
||||||
|
help="""
|
||||||
|
Call `include-what-you-use` with `--update_comments` to always rewrite its 'for'
|
||||||
|
comments regarding which symbols are used.""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'targets',
|
||||||
|
nargs='*',
|
||||||
|
metavar="<target>",
|
||||||
|
help="""
|
||||||
|
A list of target files and/or directories to search for source files to format. Any
|
||||||
|
target file will be processed, regardless of the filename. Any target directory will
|
||||||
|
be recursively searched for files matching the regular expression given by --regex.
|
||||||
|
Filenames and directories beginning with a '.' will always be excluded from the search,
|
||||||
|
but can still be processed if specified as a command-line target.""",
|
||||||
|
)
|
||||||
|
return parser.parse_args(args)
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def main():
|
||||||
|
"""Main entry point function."""
|
||||||
|
# Parse command-line arguments:
|
||||||
|
opts = parse_args(sys.argv[1:])
|
||||||
|
# Set up logging system:
|
||||||
|
setup_logging(opts.loglevel)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Find include-what-you-use:
|
||||||
|
iwyu = shutil.which('include-what-you-use')
|
||||||
|
logging.debug("Found `include-what-you-use` executable: %s", iwyu)
|
||||||
|
iwyu_opts = [
|
||||||
|
'--no_fwd_decls', # No forward declarations
|
||||||
|
'--max_line_length=100',
|
||||||
|
]
|
||||||
|
if opts.update_comments:
|
||||||
|
iwyu_opts.append('--update_comments')
|
||||||
|
# Prepend '-Xiwyu' to each `include-what-you-use` option:
|
||||||
|
iwyu_opts = [_ for opt in iwyu_opts for _ in ('-Xiwyu', opt)]
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Find fix_includes:
|
||||||
|
fix_includes = shutil.which('fix_includes.py')
|
||||||
|
logging.debug("Found `fix_includes` executable: %s", fix_includes)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Find clang (first checking environment variable):
|
||||||
|
clang = os.getenv('CLANG_COMPILER')
|
||||||
|
if clang is None:
|
||||||
|
clang = shutil.which('clang')
|
||||||
|
logging.debug("Found `clang` executable: %s", clang)
|
||||||
|
|
||||||
|
# Get system include dir from `clang`:
|
||||||
|
clang_cmd = [clang, '-print-resource-dir']
|
||||||
|
logging.debug("Running command: `%s`", shlex.join(clang_cmd))
|
||||||
|
result = subprocess.run(clang_cmd, capture_output=True, check=True)
|
||||||
|
clang_resource_dir = result.stdout.decode('utf-8').rstrip()
|
||||||
|
system_include_dir = os.path.join(clang_resource_dir, 'include')
|
||||||
|
logging.debug("Using system include dir: %s", system_include_dir)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Get $KALEIDOSCOPE_DIR from enironment, falling back on `pwd`:
|
||||||
|
kaleidoscope_dir = os.getenv('KALEIDOSCOPE_DIR')
|
||||||
|
if kaleidoscope_dir is None:
|
||||||
|
kaleidoscope_dir = os.getcwd()
|
||||||
|
logging.debug("Using Kaleidoscope dir: %s", kaleidoscope_dir)
|
||||||
|
kaleidoscope_src_dir = os.path.join(kaleidoscope_dir, 'src')
|
||||||
|
|
||||||
|
# Define locations of other dirs to find Arduino libraries:
|
||||||
|
virtual_hardware_dir = os.path.join(
|
||||||
|
kaleidoscope_dir, '.arduino', 'user', 'hardware', 'keyboardio', 'virtual')
|
||||||
|
logging.debug("Using virtual hardware dir: %s", virtual_hardware_dir)
|
||||||
|
|
||||||
|
virtual_arduino_core_dir = os.path.join(virtual_hardware_dir, 'cores', 'arduino')
|
||||||
|
logging.debug("Using virtual arduino core: %s", virtual_arduino_core_dir)
|
||||||
|
|
||||||
|
virtual_model01_dir = os.path.join(virtual_hardware_dir, 'variants', 'model01')
|
||||||
|
logging.debug("Using virtual Model01 dir: %s", virtual_model01_dir)
|
||||||
|
|
||||||
|
virtual_keyboardiohid_dir = os.path.join(
|
||||||
|
virtual_hardware_dir, 'libraries', 'KeyboardioHID', 'src')
|
||||||
|
logging.debug("Using virtual KeyboardioHID dir: %s", virtual_keyboardiohid_dir)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Create the long list of options passed to `clang` via `include-what-you-use`.
|
||||||
|
# First, we tell it we're using C++:
|
||||||
|
clang_opts = ['-x', 'c++']
|
||||||
|
# General compiler options:
|
||||||
|
clang_opts += [
|
||||||
|
'-c',
|
||||||
|
'-g',
|
||||||
|
'-Wall',
|
||||||
|
'-Wextra',
|
||||||
|
'-std=gnu++14', # Not `c++14`, because we're using clang, not gcc
|
||||||
|
'-ffunction-sections',
|
||||||
|
'-fdata-sections',
|
||||||
|
'-fno-threadsafe-statics',
|
||||||
|
'-MMD',
|
||||||
|
'-Woverloaded-virtual',
|
||||||
|
'-Wno-unused-parameter',
|
||||||
|
'-Wno-unused-variable',
|
||||||
|
'-Wno-ignored-qualifiers',
|
||||||
|
'-Wno-type-limits',
|
||||||
|
'-Wno-pragma-once-outside-header',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Variables we define to do a Kaleidoscope build:
|
||||||
|
defines = [
|
||||||
|
'KALEIDOSCOPE_VIRTUAL_BUILD=1',
|
||||||
|
'KEYBOARDIOHID_BUILD_WITHOUT_HID=1',
|
||||||
|
'USBCON=dummy',
|
||||||
|
'ARDUINO_ARCH_AVR=1',
|
||||||
|
'ARDUINO=10607',
|
||||||
|
'ARDUINO_AVR_MODEL01',
|
||||||
|
'ARDUINO_ARCH_VIRTUAL',
|
||||||
|
'USB_VID=0x1209',
|
||||||
|
'USB_PID=0x2301',
|
||||||
|
'USB_MANUFACTURER="Keyboardio"',
|
||||||
|
'USB_PRODUCT="Model 01"',
|
||||||
|
'KALEIDOSCOPE_HARDWARE_H="Kaleidoscope-Hardware-Keyboardio-Model01.h"',
|
||||||
|
'TWI_BUFFER_LENGTH=32',
|
||||||
|
]
|
||||||
|
clang_opts += ['-D' + _ for _ in defines]
|
||||||
|
|
||||||
|
# Directories to search for libraries to include:
|
||||||
|
includes = [
|
||||||
|
system_include_dir,
|
||||||
|
kaleidoscope_src_dir,
|
||||||
|
virtual_arduino_core_dir,
|
||||||
|
virtual_model01_dir,
|
||||||
|
virtual_keyboardiohid_dir,
|
||||||
|
]
|
||||||
|
# Include plugin source dirs for plugins that depend on other plugins:
|
||||||
|
includes += glob.glob(os.path.join(kaleidoscope_dir, 'plugins', '*', 'src'))
|
||||||
|
# Include dirs specified on the command line, if any:
|
||||||
|
if opts.include_dirs:
|
||||||
|
includes += [os.path.abspath(_) for _ in opts.include_dirs]
|
||||||
|
clang_opts += ['-I' + _ for _ in includes]
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Define the `include-what-you-use` command (sans target files)
|
||||||
|
iwyu_cmd = [iwyu] + iwyu_opts + clang_opts
|
||||||
|
logging.debug("Using IWYU command: %s", ' \\\n\t'.join(iwyu_cmd))
|
||||||
|
|
||||||
|
fix_includes_cmd = [
|
||||||
|
fix_includes,
|
||||||
|
'--nosafe_headers',
|
||||||
|
'--reorder',
|
||||||
|
'--separate_project_includes=' + kaleidoscope_src_dir, # Does this help?
|
||||||
|
]
|
||||||
|
if opts.update_comments:
|
||||||
|
fix_includes_cmd.append('--update_comments')
|
||||||
|
logging.debug("Using `fix_includes` command: %s", ' \\\n\t'.join(fix_includes_cmd))
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
targets = opts.targets
|
||||||
|
# If stdin is a pipe, read pathname targets, one per line. This allows us to connect the
|
||||||
|
# output of `find` to our input conveniently:
|
||||||
|
if not sys.stdin.isatty():
|
||||||
|
logging.debug("Reading targets from STDIN...")
|
||||||
|
targets += opts.input_splitter(sys.stdin.read())
|
||||||
|
for t in targets:
|
||||||
|
logging.debug(" Target path: %s", t)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
iwyu_ignores_file = os.path.join(kaleidoscope_dir, opts.ignores_file)
|
||||||
|
ignores = build_ignores_list(iwyu_ignores_file)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
regex = re.compile(opts.regex)
|
||||||
|
# Process source files first, then header files, because a source file might have been
|
||||||
|
# relying on a header included by its associated header, but which that header does not
|
||||||
|
# need on its own. In this case, if we process the header first, IWYU won't be able to
|
||||||
|
# parse the source file, and we'll get an error, but if we do them in the other order,
|
||||||
|
# the source file will get all the includes it needs before the header removes any of them.
|
||||||
|
source_files = []
|
||||||
|
header_files = []
|
||||||
|
for target_file in (_ for t in targets for _ in build_target_list(t, regex, ignores)):
|
||||||
|
if target_file.endswith('.cpp') or target_file.endswith('.ino'):
|
||||||
|
source_files.append(target_file)
|
||||||
|
else:
|
||||||
|
header_files.append(target_file)
|
||||||
|
|
||||||
|
# If there's an error processing any file, return an error code.
|
||||||
|
exit_code = 0
|
||||||
|
for target_file in source_files + header_files:
|
||||||
|
# Run IWYU and fix_headers:
|
||||||
|
if not run_iwyu(os.path.relpath(target_file), iwyu_cmd, fix_includes_cmd):
|
||||||
|
exit_code = 1
|
||||||
|
|
||||||
|
return exit_code
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def build_target_list(target, regex, ignores):
|
||||||
|
"""Build the list of target files, starting from a file or directory.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
target (str): The name of the file or directory to search
|
||||||
|
regex (Pattern): A compiled regular expression to match target file names
|
||||||
|
ignores (list): A list of (absolute) file names to be excluded from the target list
|
||||||
|
Returns:
|
||||||
|
targets (list): A list of (absolute) file names to be processed
|
||||||
|
|
||||||
|
Given a filename or directory (`path`), returns a list of target filenames to run IWYU
|
||||||
|
on. Target filenames will all be absolute, but `path` can be relative to the current
|
||||||
|
directory. All target filenames will match `regex`, and any items in `ignores` will be
|
||||||
|
excluded. If an element of the `ignores` list is a directory, all files and directories
|
||||||
|
beneath it will be excluded from the search.
|
||||||
|
"""
|
||||||
|
logging.debug("Searching target: %s", target)
|
||||||
|
|
||||||
|
# Convert all paths to absolute.
|
||||||
|
root = os.path.abspath(target)
|
||||||
|
|
||||||
|
# If `path` is a file, and it matches `regex`, add it to the target list.
|
||||||
|
if os.path.isfile(target) and regex.search(target) and root not in ignores:
|
||||||
|
return [root]
|
||||||
|
|
||||||
|
# If the specified path is not valid, just return an empty list.
|
||||||
|
if not os.path.isdir(target):
|
||||||
|
logging.error("Error: File not found: %s", target)
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Start with an empty list.
|
||||||
|
targets = []
|
||||||
|
|
||||||
|
# The specified path is a directory, so we search recursively for files
|
||||||
|
# contained therein that match the specified regular expression.
|
||||||
|
for path, dirs, files in os.walk(root):
|
||||||
|
logging.debug("Searching dir: %s", os.path.relpath(path))
|
||||||
|
# First, ignore all dotfiles (and directories).
|
||||||
|
for x in (os.path.basename(_)
|
||||||
|
for _ in ignores + glob.glob(os.path.join(path, '.*'))
|
||||||
|
if os.path.dirname(_) == path):
|
||||||
|
if x in dirs:
|
||||||
|
logging.info("Skipping ignored dir: %s", os.path.join(path, x))
|
||||||
|
dirs.remove(x)
|
||||||
|
if x in files:
|
||||||
|
logging.info("Skipping ignored file: %s", os.path.join(path, x))
|
||||||
|
files.remove(x)
|
||||||
|
|
||||||
|
logging.debug("Files found: %s", ', '.join(files))
|
||||||
|
# Add all matching files to the list of source files to be formatted.
|
||||||
|
for f in (_ for _ in files if regex.search(_)):
|
||||||
|
t = os.path.join(path, f)
|
||||||
|
logging.debug("Source file found: %s", t)
|
||||||
|
targets.append(t)
|
||||||
|
|
||||||
|
return targets
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def build_ignores_list(ignores_file_path):
|
||||||
|
"""Build a list of files and dirs to exclude from processing by IWYU
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
ignores_file_path (str): The name of the file to read ignores globs from
|
||||||
|
Returns:
|
||||||
|
ignores_list (list): A list of (absolute) file names to exclude from processing
|
||||||
|
|
||||||
|
Reads `ignores_file` and expands each line as a glob, returning a list of all the target
|
||||||
|
file names to be excluded from processing. Each path in the file is treated as a relative
|
||||||
|
pathname (unless it is already absolute), relative to the directory in which `ignores_file`
|
||||||
|
is located.
|
||||||
|
"""
|
||||||
|
logging.debug("Searching for ignores file: %s", ignores_file_path)
|
||||||
|
# If the ignores file doesn't exist, return an empty list:
|
||||||
|
if not os.path.isfile(ignores_file_path):
|
||||||
|
logging.debug("Ignores file not found")
|
||||||
|
return []
|
||||||
|
|
||||||
|
ignores_list = []
|
||||||
|
with open(ignores_file_path) as f:
|
||||||
|
for line in f.read().splitlines():
|
||||||
|
# Lines starting with `#` are treated as comments.
|
||||||
|
if line.startswith('#'):
|
||||||
|
continue
|
||||||
|
logging.debug("Ignoring files like: %s", line)
|
||||||
|
ignores_list += glob.glob(line, recursive=True)
|
||||||
|
|
||||||
|
# Get the dir of the ignores file so we can construct absolute pathnames.
|
||||||
|
ignores_file_dir = os.path.dirname(ignores_file_path)
|
||||||
|
with cwd(ignores_file_dir):
|
||||||
|
ignores_list[:] = [os.path.abspath(_) for _ in ignores_list]
|
||||||
|
|
||||||
|
logging.debug("Ignores list:\n\t%s", "\n\t".join(ignores_list))
|
||||||
|
return ignores_list
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
def run_iwyu(source_file, iwyu_cmd, fix_includes_cmd):
|
||||||
|
"""Run IWYU and fix_includes on a single source file
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
source_file (str): The name of a file to run IWYU on
|
||||||
|
iwyu_cmd (list): The command name and options list for `include-what-you-use`
|
||||||
|
fix_includes_cmd (list): The command name and options list for `fix_headers.py`
|
||||||
|
Returns:
|
||||||
|
True on success, False if either IWYU or fix_headers returns an error code
|
||||||
|
|
||||||
|
Run `include-what-you-use` on <source_file>, an update that file's header includes by
|
||||||
|
sending the output to `fix_includes.py`. If either command returns an error code, return
|
||||||
|
`False`, otherwise return `True`.
|
||||||
|
"""
|
||||||
|
logging.info("Fixing headers in file: %s", source_file)
|
||||||
|
|
||||||
|
# Run IWYU on <source_file>
|
||||||
|
iwyu_proc = subprocess.run(iwyu_cmd + [source_file], capture_output=True, check=False)
|
||||||
|
|
||||||
|
# If IWYU returns an error, report on it:
|
||||||
|
if iwyu_proc.returncode != 0:
|
||||||
|
logging.error("Error: failed to parse file: %s", source_file)
|
||||||
|
logging.debug("IWYU returned: %s", iwyu_proc.returncode)
|
||||||
|
logging.debug("STDOUT:\n%s", iwyu_proc.stdout.decode('utf-8'))
|
||||||
|
logging.debug("STDERR:\n%s", iwyu_proc.stderr.decode('utf-8'))
|
||||||
|
# In addition to reporting the error, save the output for analysis:
|
||||||
|
with open(source_file + '.iwyu', 'wb') as f:
|
||||||
|
f.write(iwyu_proc.stderr)
|
||||||
|
# Don't run fix_includes if there was an error (or if we've got an old version of IWYU
|
||||||
|
# that returns bogus exit codes):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# IWYU reports on the associated header of *.cpp files, but if we want to skip processing
|
||||||
|
# that header, we need to use only the part of the output for the *.cpp file. Fortunately,
|
||||||
|
# the header is listed first, so we only need to search for the start of the target file's
|
||||||
|
# section of the output.
|
||||||
|
n = iwyu_proc.stderr.find(f"\n{source_file} should".encode('utf-8'))
|
||||||
|
iwyu_stderr = iwyu_proc.stderr[n:]
|
||||||
|
|
||||||
|
# Run fix_includes.py, using the output (stderr) of IWYU:
|
||||||
|
fix_includes_proc = subprocess.run(
|
||||||
|
fix_includes_cmd, input=iwyu_stderr, capture_output=True, check=False)
|
||||||
|
|
||||||
|
# Report any errors returned by fix_includes.py:
|
||||||
|
if fix_includes_proc.returncode != 0:
|
||||||
|
logging.error("Error: failed to fix includes for file: %s", source_file)
|
||||||
|
logging.debug("fix_includes.py returned: %s", fix_includes_proc.returncode)
|
||||||
|
logging.debug("STDOUT:\n%s", fix_includes_proc.stdout.decode('utf-8'))
|
||||||
|
logging.debug("STDERR:\n%s", fix_includes_proc.stderr.decode('utf-8'))
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Return true on success, false otherwise:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
sys.exit(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logging.info("Aborting")
|
||||||
|
sys.exit(1)
|
@ -1,15 +0,0 @@
|
|||||||
#!/bin/bash -e
|
|
||||||
|
|
||||||
# This script sets all of the files inside src and example to have mtimes
|
|
||||||
# that match the times of the last git commit that touched each file
|
|
||||||
|
|
||||||
# This can be useful when build tools depend on file timestamps to
|
|
||||||
# make caching decisions
|
|
||||||
|
|
||||||
find src examples -type f -exec sh -c '
|
|
||||||
timestamp=$(git log --pretty=format:%ad --date=format:%Y%m%d%H%M.%S -n 1 HEAD "$1" 2> /dev/null)
|
|
||||||
if [ "x$timestamp" != "x" ]; then
|
|
||||||
touch -t "$timestamp" "$1"
|
|
||||||
fi
|
|
||||||
' sh {} \;
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
# Docker
|
||||||
|
|
||||||
|
It's possible to use Docker to run Kaleidoscope's test suite.
|
||||||
|
|
||||||
|
## Running tests in Docker
|
||||||
|
|
||||||
|
```
|
||||||
|
# make docker-simulator-tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cleaning out stale data in the Docker image:
|
||||||
|
|
||||||
|
```
|
||||||
|
# make docker-clean
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Removing the Kaleidoscope Docker image entirely:
|
||||||
|
|
||||||
|
```
|
||||||
|
# docker volume rm kaleidoscope-persist
|
||||||
|
# docker volume rm kaleidoscope-googletest-build
|
||||||
|
# docker volume rm kaleidoscope-build
|
||||||
|
# docker image rm kaleidoscope/docker
|
||||||
|
```
|
@ -0,0 +1,76 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Kaleidoscope - A Kaleidoscope example
|
||||||
|
* Copyright (C) 2016-2022 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DEBUG_SERIAL false
|
||||||
|
|
||||||
|
#include <Kaleidoscope.h>
|
||||||
|
#include <Kaleidoscope-MouseKeys.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PRIMARY,
|
||||||
|
MOUSEKEYS,
|
||||||
|
};
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
KEYMAPS(
|
||||||
|
[PRIMARY] = KEYMAP_STACKED
|
||||||
|
(Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
|
||||||
|
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
|
||||||
|
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
|
||||||
|
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
|
||||||
|
|
||||||
|
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
|
||||||
|
ShiftToLayer(MOUSEKEYS),
|
||||||
|
|
||||||
|
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
|
||||||
|
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
|
||||||
|
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
|
||||||
|
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
|
||||||
|
|
||||||
|
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
|
||||||
|
LockLayer(MOUSEKEYS)
|
||||||
|
),
|
||||||
|
|
||||||
|
[MOUSEKEYS] = KEYMAP_STACKED
|
||||||
|
(___, ___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, ___, Key_mouseWarpNW, Key_mouseWarpNE, ___,
|
||||||
|
___, ___, ___, ___, Key_mouseWarpSW, Key_mouseWarpSE,
|
||||||
|
___, ___, Key_mouseBtnL, Key_mouseBtnM, Key_mouseBtnR, ___, ___,
|
||||||
|
___, ___, ___, ___,
|
||||||
|
___,
|
||||||
|
|
||||||
|
___, ___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, Key_mouseUp, ___, ___, ___,
|
||||||
|
___, Key_mouseUp, Key_mouseDn, Key_mouseR, ___, ___,
|
||||||
|
___, ___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, ___,
|
||||||
|
___)
|
||||||
|
)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
|
||||||
|
KALEIDOSCOPE_INIT_PLUGINS(MouseKeys);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Kaleidoscope.setup();
|
||||||
|
MouseKeys.setSpeedLimit(100);
|
||||||
|
MouseKeys.setWarpGridSize(MOUSE_WARP_GRID_2X2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Kaleidoscope.loop();
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"cpu": {
|
||||||
|
"fqbn": "keyboardio:avr:model01",
|
||||||
|
"port": ""
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* ShiftBlocker -- A Kaleidoscope Example
|
||||||
|
* Copyright (C) 2016-2022 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Kaleidoscope.h"
|
||||||
|
#include "Kaleidoscope-Macros.h"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
KEYMAPS(
|
||||||
|
[0] = KEYMAP_STACKED
|
||||||
|
(
|
||||||
|
Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
|
||||||
|
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
|
||||||
|
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
|
||||||
|
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
|
||||||
|
|
||||||
|
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
|
||||||
|
M(0),
|
||||||
|
|
||||||
|
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
|
||||||
|
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
|
||||||
|
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
|
||||||
|
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
|
||||||
|
|
||||||
|
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
|
||||||
|
M(0)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace plugin {
|
||||||
|
|
||||||
|
// When activated, this plugin will suppress any `Shift` key (including modifier
|
||||||
|
// combos with `Shift`) before it's added to the HID report.
|
||||||
|
class ShiftBlocker : public Plugin {
|
||||||
|
|
||||||
|
public:
|
||||||
|
EventHandlerResult onAddToReport(Key key) {
|
||||||
|
if (active_ && key.isKeyboardShift())
|
||||||
|
return EventHandlerResult::ABORT;
|
||||||
|
return EventHandlerResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable() {
|
||||||
|
active_ = true;
|
||||||
|
}
|
||||||
|
void disable() {
|
||||||
|
active_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool active_{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace plugin
|
||||||
|
} // namespace kaleidoscope
|
||||||
|
|
||||||
|
kaleidoscope::plugin::ShiftBlocker ShiftBlocker;
|
||||||
|
|
||||||
|
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
|
||||||
|
if (keyToggledOn(event.state)) {
|
||||||
|
switch (macro_id) {
|
||||||
|
case 0:
|
||||||
|
// First, enable ShiftBlocker to suppress any held `Shift` key(s).
|
||||||
|
ShiftBlocker.enable();
|
||||||
|
// Tap `AltGr` + `7` to activate the grave accent dead key.
|
||||||
|
Macros.tap(RALT(Key_7));
|
||||||
|
// Disable ShiftBlocker so it won't affect the `E` event.
|
||||||
|
ShiftBlocker.disable();
|
||||||
|
// Change the Macros key into a plain `E` key before its press event is
|
||||||
|
// processed.
|
||||||
|
event.key = Key_E;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MACRO_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
KALEIDOSCOPE_INIT_PLUGINS(Macros,
|
||||||
|
ShiftBlocker);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Kaleidoscope.setup();
|
||||||
|
// Uncomment to manually set the OS, as Kaleidoscope will not autodetect it.
|
||||||
|
// (Possible values are in HostOS.h.)
|
||||||
|
// HostOS.os(kaleidoscope::hostos::LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Kaleidoscope.loop();
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"cpu": {
|
||||||
|
"fqbn": "keyboardio:avr:model01",
|
||||||
|
"port": ""
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
|
||||||
|
/* This example demonstrates the Model 01 / Model 100 butterfly logo key as a
|
||||||
|
* tmux prefix key. When the key is held, Ctrl-B is pressed prior to the key
|
||||||
|
* you pressed.
|
||||||
|
*
|
||||||
|
* This example also demonstrates the purpose of using an entire layer for this
|
||||||
|
* plugin: the h/j/k/l keys in the TMUX layer are swapped for arrow keys to
|
||||||
|
* make switching between panes easier.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Kaleidoscope.h>
|
||||||
|
#include <Kaleidoscope-PrefixLayer.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PRIMARY,
|
||||||
|
TMUX,
|
||||||
|
}; // layers
|
||||||
|
|
||||||
|
/* Used in setup() below. */
|
||||||
|
static const kaleidoscope::plugin::PrefixLayer::Entry prefix_layers[] PROGMEM = {
|
||||||
|
kaleidoscope::plugin::PrefixLayer::Entry(TMUX, LCTRL(Key_B)),
|
||||||
|
};
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
KEYMAPS(
|
||||||
|
[PRIMARY] = KEYMAP_STACKED
|
||||||
|
(XXX, Key_1, Key_2, Key_3, Key_4, Key_5, XXX,
|
||||||
|
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
|
||||||
|
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
|
||||||
|
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
|
||||||
|
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
|
||||||
|
XXX,
|
||||||
|
|
||||||
|
XXX, Key_6, Key_7, Key_8, Key_9, Key_0, XXX,
|
||||||
|
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
|
||||||
|
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
|
||||||
|
ShiftToLayer(TMUX), Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
|
||||||
|
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
|
||||||
|
XXX),
|
||||||
|
|
||||||
|
[TMUX] = KEYMAP_STACKED
|
||||||
|
(___, ___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, ___,
|
||||||
|
___,
|
||||||
|
|
||||||
|
___, ___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, ___, ___, ___, ___,
|
||||||
|
Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___, ___,
|
||||||
|
___, ___, ___, ___, ___, ___, ___,
|
||||||
|
___, ___, ___, ___,
|
||||||
|
___),
|
||||||
|
)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
KALEIDOSCOPE_INIT_PLUGINS(PrefixLayer);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Kaleidoscope.setup();
|
||||||
|
/* Configure the previously-defined prefix layers. */
|
||||||
|
PrefixLayer.setPrefixLayers(prefix_layers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Kaleidoscope.loop();
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"cpu": {
|
||||||
|
"fqbn": "keyboardio:avr:model01",
|
||||||
|
"port": ""
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue