mirror of https://github.com/junegunn/fzf
Compare commits
835 Commits
Author | SHA1 | Date |
---|---|---|
|
db01e7dab6 | 18 hours ago |
|
2326c74eb2 | 18 hours ago |
|
b9d15569e8 | 1 day ago |
|
c3cc378d89 | 1 day ago |
|
27d1f5e0a8 | 1 day ago |
|
540632bb9e | 1 day ago |
|
d9c028c934 | 2 days ago |
|
c54ad82e8d | 2 days ago |
|
295b89631b | 2 days ago |
|
6179faf778 | 2 days ago |
|
16dc236a25 | 2 days ago |
|
61ae9d75b6 | 2 days ago |
|
e2401aca68 | 4 days ago |
|
59943cbb48 | 4 days ago |
|
02634d404d | 4 days ago |
|
ed12925f7d | 4 days ago |
|
e0ddb97ab4 | 4 days ago |
|
b8c01af0fc | 5 days ago |
|
6de0a7ddc1 | 6 days ago |
|
79196c025d | 6 days ago |
|
94c33ac020 | 6 days ago |
|
b2ecb6352c | 7 days ago |
|
9dc3ed638a | 1 week ago |
|
0acace1ace | 1 week ago |
|
1a2d37e1e6 | 1 week ago |
|
22adb6494f | 1 week ago |
|
e023736c30 | 1 week ago |
|
dca2262fe6 | 1 week ago |
|
0684a20ea3 | 1 week ago |
|
a1a72bb8d1 | 1 week ago |
|
144d55a5be | 1 week ago |
|
7fc13c5cfd | 2 weeks ago |
|
dfee7af57b | 2 weeks ago |
|
9b0e2daf02 | 2 weeks ago |
|
590060a16b | 2 weeks ago |
|
368294edf6 | 2 weeks ago |
|
c4a9ccd6af | 2 weeks ago |
|
cbf91f2ed3 | 2 weeks ago |
|
b1460d4787 | 2 weeks ago |
|
7dc9e14874 | 2 weeks ago |
|
1616ed543d | 2 weeks ago |
|
dc73fba188 | 2 weeks ago |
|
ef148dfd37 | 2 weeks ago |
|
93bbb3032d | 2 weeks ago |
|
4c83d8596d | 3 weeks ago |
|
d453e6d7db | 3 weeks ago |
|
c29533994f | 3 weeks ago |
|
1afe13b5b5 | 3 weeks ago |
|
36600eaaa9 | 3 weeks ago |
|
3ee1fc2034 | 3 weeks ago |
|
e2f93e5a2d | 3 weeks ago |
|
cfdf2f1153 | 3 weeks ago |
|
e042143e3f | 3 weeks ago |
|
7c613d0d9b | 3 weeks ago |
|
b00d46bc14 | 3 weeks ago |
|
555b0d235b | 3 weeks ago |
|
564daf9a7d | 3 weeks ago |
|
41bcbe342f | 3 weeks ago |
|
dbe8dc344e | 3 weeks ago |
|
e33fb59da1 | 3 weeks ago |
|
7aa88aa115 | 3 weeks ago |
|
2b6d600879 | 3 weeks ago |
|
05c765d442 | 3 weeks ago |
|
49b496269c | 3 weeks ago |
|
7405925952 | 3 weeks ago |
|
3afd543a7e | 3 weeks ago |
|
b4f2cde5ac | 3 weeks ago |
|
ed53ef7cee | 3 weeks ago |
|
12630b124d | 3 weeks ago |
|
1d59ac09d2 | 3 weeks ago |
|
a8f3a0dd59 | 3 weeks ago |
|
124cd70710 | 3 weeks ago |
|
782de139c8 | 3 weeks ago |
|
32eb32ee5e | 4 weeks ago |
|
2f51eb2b41 | 4 weeks ago |
|
0ccbd79e10 | 4 weeks ago |
|
99bd6de541 | 4 weeks ago |
|
1fef36e4bc | 4 weeks ago |
|
89375005b5 | 4 weeks ago |
|
88e78c9193 | 4 weeks ago |
|
29a19ad080 | 4 weeks ago |
|
2a039ab746 | 4 weeks ago |
|
7e9a0fcdbd | 4 weeks ago |
|
7a97532547 | 4 weeks ago |
|
996abb2831 | 4 weeks ago |
|
da500a358f | 4 weeks ago |
|
c36b846acc | 4 weeks ago |
|
d9b5c9b2be | 4 weeks ago |
|
3dee8778d0 | 4 weeks ago |
|
d4216b0dcc | 4 weeks ago |
|
bfe2bf4dce | 4 weeks ago |
|
561f9291fd | 4 weeks ago |
|
b5b0d6b3ea | 4 weeks ago |
|
a90426b7ca | 4 weeks ago |
|
303c3bae7f | 4 weeks ago |
|
6b4358f641 | 4 weeks ago |
|
552158f3ad | 4 weeks ago |
|
7205203dc8 | 1 month ago |
|
0cadf70072 | 1 month ago |
|
076b3d0a9a | 1 month ago |
|
7b0c9e04d3 | 1 month ago |
|
573df524fe | 1 month ago |
|
aee417c46a | 1 month ago |
|
04db44067d | 1 month ago |
|
5b204c54f9 | 1 month ago |
|
daa602422d | 1 month ago |
|
04dfb14e32 | 1 month ago |
|
c24256cba3 | 1 month ago |
|
685fb71d89 | 1 month ago |
|
83b6033906 | 1 month ago |
|
01e7668915 | 1 month ago |
|
0994d9c881 | 1 month ago |
|
030428ba43 | 1 month ago |
|
8a110e02b9 | 1 month ago |
|
86d92c17c4 | 1 month ago |
|
c4cc7891b4 | 1 month ago |
|
218843b9f1 | 1 month ago |
|
d274d093af | 1 month ago |
|
6432f00f0d | 1 month ago |
|
4e9e842aa4 | 1 month ago |
|
07880ca441 | 1 month ago |
|
bcda25a513 | 1 month ago |
|
8256fcde15 | 1 month ago |
|
af65aa298a | 1 month ago |
|
6834d17844 | 1 month ago |
|
ed511d7867 | 1 month ago |
|
cd8d736a9f | 1 month ago |
|
0952b2dfd4 | 1 month ago |
|
4bedd33c59 | 1 month ago |
|
c5fb0c43f9 | 2 months ago |
|
9e4780510e | 2 months ago |
|
e8405f40fe | 2 months ago |
|
065b9e6fb2 | 2 months ago |
|
98141ca7d8 | 2 months ago |
|
501577ab28 | 2 months ago |
|
5669f48343 | 2 months ago |
|
24ff66d4a9 | 2 months ago |
|
bf184449bc | 2 months ago |
|
7b98c2c653 | 2 months ago |
|
b6add2a257 | 2 months ago |
|
2bd41f1330 | 2 months ago |
|
c37cd11ca5 | 2 months ago |
|
9dee8edc0c | 2 months ago |
|
f6aa28c380 | 2 months ago |
|
dba1644518 | 2 months ago |
|
260a65b0fb | 2 months ago |
|
835d2fb98c | 2 months ago |
|
a9811addaa | 2 months ago |
|
ee9d88b637 | 2 months ago |
|
194a763c46 | 2 months ago |
|
8d74446bef | 2 months ago |
|
7ed6c7905c | 2 months ago |
|
159a37fa37 | 2 months ago |
|
f39ae0e7c1 | 2 months ago |
|
4a68eac99b | 2 months ago |
|
2665580120 | 2 months ago |
|
a4391aeedd | 2 months ago |
|
b86a967ee2 | 2 months ago |
|
608232568b | 2 months ago |
|
7f85beccb5 | 2 months ago |
|
767f1255ab | 2 months ago |
|
fddbfe7b0e | 2 months ago |
|
4ab7fdc28e | 2 months ago |
|
e352b68878 | 2 months ago |
|
207deeadba | 2 months ago |
|
d18d92f925 | 2 months ago |
|
af3ce47c44 | 2 months ago |
|
d8bfb6712d | 2 months ago |
|
f864f8b5f7 | 2 months ago |
|
31d72efba7 | 2 months ago |
|
d169c951f3 | 2 months ago |
|
90d7e38909 | 2 months ago |
|
938f23e429 | 2 months ago |
|
f97d275413 | 2 months ago |
|
3acb4ca90e | 2 months ago |
|
e86b81bbf5 | 2 months ago |
|
a5447b8b75 | 2 months ago |
|
7ce6452d83 | 2 months ago |
|
5643a306bd | 2 months ago |
|
3c877c504b | 2 months ago |
|
892d1acccb | 2 months ago |
|
1a9c282f76 | 2 months ago |
|
fd1ba46f77 | 2 months ago |
|
a4745626dd | 2 months ago |
|
17bb7ad278 | 2 months ago |
|
152988c17b | 2 months ago |
|
4cd37fc02b | 2 months ago |
|
69b9d674a3 | 3 months ago |
|
bad8061547 | 3 months ago |
|
62963dcefd | 3 months ago |
|
68a35e4735 | 3 months ago |
|
9b9ad77e1c | 3 months ago |
|
118b4d4a01 | 3 months ago |
|
da14ab6f16 | 3 months ago |
|
09a4ca6ab5 | 3 months ago |
|
8a2df79711 | 3 months ago |
|
c30e486b64 | 3 months ago |
|
a575c0c54b | 3 months ago |
|
77fe96ac0d | 3 months ago |
|
5234c3759a | 3 months ago |
|
41b3511ad9 | 3 months ago |
|
128e4a2e8d | 3 months ago |
|
07ac90d798 | 3 months ago |
|
7de87a9b2c | 3 months ago |
|
dff865239a | 3 months ago |
|
07f8f70c5b | 3 months ago |
|
f625c5aabe | 3 months ago |
|
8a74976c1f | 3 months ago |
|
b6bfd4a5cb | 3 months ago |
|
008fb9d258 | 3 months ago |
|
db6db49ed6 | 3 months ago |
|
05453881c3 | 3 months ago |
|
5e47ab9431 | 3 months ago |
|
ec70acd0b9 | 3 months ago |
|
25e61056b6 | 3 months ago |
|
d579e335b5 | 3 months ago |
|
7e344ceb85 | 3 months ago |
|
0145b82ea0 | 3 months ago |
|
b4efe7aab7 | 3 months ago |
|
9ffe951f6d | 3 months ago |
|
a5ea4f57bd | 3 months ago |
|
88f4c16755 | 3 months ago |
|
c7ee071efa | 3 months ago |
|
0740ef7ceb | 3 months ago |
|
b29bd809ac | 3 months ago |
|
8977c9257a | 3 months ago |
|
091b7eacba | 3 months ago |
|
e74b1251c0 | 3 months ago |
|
d282a1649d | 3 months ago |
|
6ce8d49d1b | 3 months ago |
|
c5b197078a | 3 months ago |
|
0494f20d62 | 3 months ago |
|
73aff476dd | 3 months ago |
|
98ee5e651a | 3 months ago |
|
01871ea383 | 3 months ago |
|
1dbdb9438f | 3 months ago |
|
c70f0eadb8 | 3 months ago |
|
26244ad8c2 | 3 months ago |
|
fa0aa5510d | 3 months ago |
|
eec557b6aa | 3 months ago |
|
0cc27c3cc1 | 4 months ago |
|
507089d7b2 | 4 months ago |
|
a6b3517b75 | 4 months ago |
|
2d6beb7813 | 4 months ago |
|
61bc129e1d | 4 months ago |
|
52210a57f0 | 4 months ago |
|
8061a2f108 | 4 months ago |
|
7444eff6d4 | 4 months ago |
|
f35a9da99a | 4 months ago |
|
c3098e9ab2 | 4 months ago |
|
686f9288fc | 4 months ago |
|
1833670fb9 | 4 months ago |
|
3dd42f5aa2 | 4 months ago |
|
99a7beba57 | 4 months ago |
|
edee2b753c | 4 months ago |
|
545d5770be | 4 months ago |
|
ca747a2b54 | 4 months ago |
|
17da165cfe | 4 months ago |
|
5e6788c679 | 4 months ago |
|
425deadca9 | 4 months ago |
|
2c8e9dd3a5 | 4 months ago |
|
7a72f1a253 | 4 months ago |
|
208e556332 | 4 months ago |
|
c65d11bfb5 | 4 months ago |
|
3b5b52d89a | 4 months ago |
|
a4f6c8f990 | 4 months ago |
|
670c329852 | 4 months ago |
|
f3551c8422 | 4 months ago |
|
90b8187882 | 5 months ago |
|
1a43259989 | 5 months ago |
|
3c0a630475 | 5 months ago |
|
2a1e5a9729 | 5 months ago |
|
413c66beba | 5 months ago |
|
1416e696b1 | 5 months ago |
|
d373cf89c7 | 5 months ago |
|
dd886d22f0 | 5 months ago |
|
472569a27c | 5 months ago |
|
76cf6559cc | 5 months ago |
|
a34e8dcdc9 | 5 months ago |
|
da752fc9a4 | 5 months ago |
|
beb2de2dd9 | 5 months ago |
|
2a8b65e105 | 5 months ago |
|
62a916bc24 | 5 months ago |
|
c47b833e7b | 5 months ago |
|
09b0958b5f | 5 months ago |
|
3a4c3d3e58 | 5 months ago |
|
7484292e63 | 5 months ago |
|
687c2741b8 | 5 months ago |
|
2fb285e530 | 5 months ago |
|
16f6473938 | 5 months ago |
|
66546208b2 | 5 months ago |
|
532274045e | 5 months ago |
|
9347c72fb6 | 5 months ago |
|
e90bb7169c | 5 months ago |
|
8a2c41e183 | 5 months ago |
|
59fb65293a | 5 months ago |
|
e7718b92b7 | 5 months ago |
|
cdfaf761df | 5 months ago |
|
1a9ea6f738 | 5 months ago |
|
945c1c8597 | 5 months ago |
|
e4d0f7acd5 | 5 months ago |
|
250496c953 | 6 months ago |
|
e47dc758c9 | 6 months ago |
|
b92a843c5f | 6 months ago |
|
91bea9c5b3 | 6 months ago |
|
d75bb5cbe1 | 6 months ago |
|
2671259fdb | 6 months ago |
|
2024010119 | 6 months ago |
|
412040f77e | 6 months ago |
|
d210660ce8 | 6 months ago |
|
863a12562b | 6 months ago |
|
5da606a9ac | 6 months ago |
|
8d20f3d5c4 | 6 months ago |
|
5d360180af | 6 months ago |
|
f0fbed6007 | 6 months ago |
|
519de7c833 | 6 months ago |
|
97ccef1a04 | 6 months ago |
|
c4df0dd06e | 6 months ago |
|
cd114c6818 | 6 months ago |
|
1707b8cdba | 6 months ago |
|
41d4d70b98 | 6 months ago |
|
0e999482cb | 6 months ago |
|
65b2c06027 | 6 months ago |
|
d7b61ede07 | 6 months ago |
|
87fc1c84b8 | 6 months ago |
|
d4b5f12383 | 6 months ago |
|
eb62b0d665 | 6 months ago |
|
91387a741b | 6 months ago |
|
e8b34cb00d | 6 months ago |
|
82954258c1 | 6 months ago |
|
50f092551b | 6 months ago |
|
c36a64be68 | 6 months ago |
|
a343b20775 | 6 months ago |
|
a714e76ae1 | 6 months ago |
|
d21d5c9510 | 7 months ago |
|
cd6788a2bb | 7 months ago |
|
6b99399c41 | 7 months ago |
|
952b6af445 | 7 months ago |
|
7c674ad7fa | 7 months ago |
|
d7d2ac3951 | 7 months ago |
|
29e67d307a | 7 months ago |
|
7320b7df62 | 7 months ago |
|
11fb4233f7 | 7 months ago |
|
84bb350b14 | 7 months ago |
|
38e3694d1c | 7 months ago |
|
1084935241 | 8 months ago |
|
f5f0b9ecaa | 8 months ago |
|
230fc49ae2 | 8 months ago |
|
250d507bdf | 8 months ago |
|
a818653174 | 8 months ago |
|
5c3b044740 | 8 months ago |
|
c5aa8729a1 | 8 months ago |
|
3f78d76da1 | 8 months ago |
|
70c19ccf16 | 8 months ago |
|
68db9cb499 | 8 months ago |
|
d0466fa777 | 8 months ago |
|
21ab64e962 | 8 months ago |
|
a0145cebf2 | 8 months ago |
|
69176fc5f4 | 8 months ago |
|
278dce9ba6 | 8 months ago |
|
1cfa3ee4c7 | 8 months ago |
|
9a95cd5794 | 8 months ago |
|
a62fe3df6f | 8 months ago |
|
7701244a08 | 8 months ago |
|
96e31e4b78 | 8 months ago |
|
ec208af474 | 8 months ago |
|
242641264d | 8 months ago |
|
d3a9a0615b | 8 months ago |
|
3277e8c89c | 8 months ago |
|
d02b9442a5 | 8 months ago |
|
bac385b59c | 8 months ago |
|
b1a0ab8086 | 8 months ago |
|
a33749eb71 | 8 months ago |
|
f5e4ee90e4 | 8 months ago |
|
690d5e6dbd | 8 months ago |
|
a76c055b63 | 8 months ago |
|
70c461c60b | 8 months ago |
|
d51b71ee80 | 8 months ago |
|
3666448ca6 | 8 months ago |
|
d3311d9f43 | 8 months ago |
|
3e1735b06e | 8 months ago |
|
de7ef7eace | 8 months ago |
|
7e89458a3b | 8 months ago |
|
f212bafe46 | 8 months ago |
|
86fe40708b | 8 months ago |
|
d718747c5b | 8 months ago |
|
46ee9ac41c | 8 months ago |
|
f1d306feab | 8 months ago |
|
2d0db98e83 | 8 months ago |
|
3df06a1c68 | 8 months ago |
|
a8f9432a3a | 8 months ago |
|
561e0b04a8 | 8 months ago |
|
404b6a864b | 8 months ago |
|
4feaf31225 | 8 months ago |
|
391aa14845 | 8 months ago |
|
a0d61b4c37 | 9 months ago |
|
2952737755 | 9 months ago |
|
f103aa4753 | 9 months ago |
|
884856023a | 9 months ago |
|
d8188fce7b | 9 months ago |
|
0f15f1ab73 | 9 months ago |
|
488a236b7a | 9 months ago |
|
e833823e15 | 9 months ago |
|
ee4ba104e7 | 9 months ago |
|
4fdc08295b | 9 months ago |
|
a3ff49aaf1 | 9 months ago |
|
76364ea767 | 9 months ago |
|
8eec50d764 | 9 months ago |
|
32b659b346 | 9 months ago |
|
00809909ae | 9 months ago |
|
9f7684f6fe | 9 months ago |
|
2bed7d370e | 9 months ago |
|
d2b852f7cb | 9 months ago |
|
901939bd96 | 9 months ago |
|
edfdcc8cee | 9 months ago |
|
3982c9a552 | 9 months ago |
|
4490b2d209 | 9 months ago |
|
eb4bbf3294 | 9 months ago |
|
dc97d48491 | 10 months ago |
|
0f50dc848e | 10 months ago |
|
c5e4b83de3 | 10 months ago |
|
a08ab46713 | 10 months ago |
|
f50a7058d6 | 10 months ago |
|
2c74f0a040 | 10 months ago |
|
58835e40f3 | 10 months ago |
|
8befa5918a | 10 months ago |
|
df80f7ff2a | 10 months ago |
|
5f66786ef1 | 10 months ago |
|
3a965856a5 | 10 months ago |
|
03df609d77 | 10 months ago |
|
178581b560 | 10 months ago |
|
ffd2314120 | 10 months ago |
|
815b595d2f | 10 months ago |
|
11e56403dd | 10 months ago |
|
4baadecda5 | 10 months ago |
|
cf552b5f3b | 10 months ago |
|
1894304d33 | 10 months ago |
|
9d5392fb02 | 10 months ago |
|
c280645671 | 10 months ago |
|
45f92e6b38 | 10 months ago |
|
6509f09961 | 10 months ago |
|
3c279a6f0e | 10 months ago |
|
9ec3f03871 | 10 months ago |
|
84a9c2c112 | 11 months ago |
|
af368119cb | 11 months ago |
|
89b9189efa | 11 months ago |
|
dd59b8c7b9 | 11 months ago |
|
f83491274f | 11 months ago |
|
c0435fdff4 | 11 months ago |
|
3c09c77269 | 11 months ago |
|
547e101f1d | 11 months ago |
|
0130f64934 | 12 months ago |
|
361e0543ee | 12 months ago |
|
63aa5d3b4e | 12 months ago |
|
01302d097c | 1 year ago |
|
e6095cb7e8 | 1 year ago |
|
b876b8af11 | 1 year ago |
|
a7c41f3fcd | 1 year ago |
|
4772bd8d4c | 1 year ago |
|
d471067e3f | 1 year ago |
|
d0b7780239 | 1 year ago |
|
e627ca6bd7 | 1 year ago |
|
c97172bdd4 | 1 year ago |
|
ce8a745fb4 | 1 year ago |
|
3e9efd1401 | 1 year ago |
|
20340190b5 | 1 year ago |
|
265040a78c | 1 year ago |
|
448d7e0c5a | 1 year ago |
|
6eb1874c5a | 1 year ago |
|
4c70745cc1 | 1 year ago |
|
7795748a3f | 1 year ago |
|
098ef4d7cf | 1 year ago |
|
e3f91bfe1b | 1 year ago |
|
7374fe73a3 | 1 year ago |
|
d2bde205f0 | 1 year ago |
|
5620f70f9a | 1 year ago |
|
37f258b1bf | 1 year ago |
|
e2dd2a133e | 1 year ago |
|
7514644e07 | 1 year ago |
|
16b0aeda7d | 1 year ago |
|
86e4f4a841 | 1 year ago |
|
607eacf8c7 | 1 year ago |
|
7a049644a8 | 1 year ago |
|
17a13f00f8 | 1 year ago |
|
43436e48e0 | 1 year ago |
|
5a39102405 | 1 year ago |
|
94999101e3 | 1 year ago |
|
e619b7c4f4 | 1 year ago |
|
b7c2e8cb67 | 1 year ago |
|
fb76893e18 | 1 year ago |
|
88d812fe82 | 1 year ago |
|
77f9f4664a | 1 year ago |
|
5c2f85c39e | 1 year ago |
|
ac4d22cd12 | 1 year ago |
|
cf95e44cb4 | 1 year ago |
|
65dd2bb429 | 1 year ago |
|
6be855be6a | 1 year ago |
|
b6e3f4423b | 1 year ago |
|
0c61d81713 | 1 year ago |
|
7c6f5dba63 | 1 year ago |
|
44cfc7e62a | 1 year ago |
|
96670d5f16 | 1 year ago |
|
36b971ee4e | 1 year ago |
|
f1a9629652 | 1 year ago |
|
20230402d0 | 1 year ago |
|
5c2c3a6c88 | 1 year ago |
|
fb019d43bf | 1 year ago |
|
025aa33773 | 1 year ago |
|
302e21fd58 | 1 year ago |
|
211512ae64 | 1 year ago |
|
8ec917b1c3 | 1 year ago |
|
1c7534f009 | 1 year ago |
|
ae745d9397 | 1 year ago |
|
60f37aae2f | 1 year ago |
|
d7daf5f724 | 1 year ago |
|
e5103d9429 | 1 year ago |
|
8fecb29848 | 1 year ago |
|
290ea6179d | 1 year ago |
|
9695a40fc9 | 1 year ago |
|
1913b95227 | 1 year ago |
|
a874aea692 | 1 year ago |
|
69c52099e7 | 1 year ago |
|
cfc0747d5d | 1 year ago |
|
fcd7e8768d | 1 year ago |
|
3c34dd8275 | 1 year ago |
|
1116e481be | 1 year ago |
|
63cf9d04de | 1 year ago |
|
3364d4d147 | 1 year ago |
|
57ad21e4bd | 1 year ago |
|
414f87981f | 1 year ago |
|
b1459c79cf | 1 year ago |
|
352ea07226 | 1 year ago |
|
27018787af | 1 year ago |
|
4e305eca26 | 1 year ago |
|
9e9c0ceaf4 | 1 year ago |
|
b3bf18b1c0 | 1 year ago |
|
b1619f675f | 1 year ago |
|
96c3de12eb | 1 year ago |
|
719dbb8bae | 1 year ago |
|
f38a7f7f8f | 1 year ago |
|
6ea38b4438 | 1 year ago |
|
f7447aece1 | 1 year ago |
|
aa2b9ec476 | 1 year ago |
|
3ee00f8bc2 | 1 year ago |
|
fccab60a5c | 1 year ago |
|
0f4af38457 | 1 year ago |
|
aef39f1160 | 1 year ago |
|
2023012408 | 1 year ago |
|
95a7661bb1 | 1 year ago |
|
618d317803 | 1 year ago |
|
ae897c8cdb | 1 year ago |
|
d0a0f3c052 | 1 year ago |
|
91b9591b10 | 1 year ago |
|
aa7361337d | 1 year ago |
|
284d77fe2e | 1 year ago |
|
826178f1e2 | 1 year ago |
|
acccf8a9b8 | 1 year ago |
|
57c066f0be | 1 year ago |
|
e44f64ae92 | 1 year ago |
|
d51980a3f5 | 1 year ago |
|
c3d73e7ecb | 1 year ago |
|
b077f6821d | 1 year ago |
|
a79de11af7 | 1 year ago |
|
2023011763 | 1 year ago |
|
b46e40e86b | 1 year ago |
|
a6d6cdd165 | 1 year ago |
|
dc8da605f9 | 1 year ago |
|
8b299a29c7 | 1 year ago |
|
3109b865d2 | 1 year ago |
|
0c5956c43c | 1 year ago |
|
1c83b39691 | 1 year ago |
|
77874b473c | 1 year ago |
|
b7cce7be15 | 1 year ago |
|
3cd3362417 | 1 year ago |
|
e97e925efb | 1 year ago |
|
0f032235cf | 1 year ago |
|
e0f0984da7 | 1 year ago |
|
4d22b5aaef | 1 year ago |
|
80b8846318 | 1 year ago |
|
bf641faafa | 1 year ago |
|
23d8b78ce1 | 1 year ago |
|
3b2244077d | 1 year ago |
|
ee5cdb9713 | 1 year ago |
|
03d02d67f7 | 1 year ago |
|
5798145581 | 1 year ago |
|
51ef0b7f66 | 1 year ago |
|
97b4542c73 | 1 year ago |
|
c1cd0c09a2 | 1 year ago |
|
1fc1f47d80 | 1 year ago |
|
ec471a5bc2 | 1 year ago |
|
a893fc0ca2 | 1 year ago |
|
3761dc0433 | 1 year ago |
|
aa71a07fbe | 1 year ago |
|
088293f5e7 | 1 year ago |
|
7c660aa86e | 1 year ago |
|
435d8fa0a2 | 1 year ago |
|
5cd6f1d064 | 1 year ago |
|
ec20dfe312 | 1 year ago |
|
924ffb5a35 | 1 year ago |
|
62c7f59b94 | 1 year ago |
|
e97176b1d7 | 1 year ago |
|
d649f5d826 | 1 year ago |
|
6c37177cf5 | 1 year ago |
|
14775aa975 | 1 year ago |
|
44b6336372 | 2 years ago |
|
36d2bb332b | 2 years ago |
|
4dbe45640a | 2 years ago |
|
4b3f0b9f08 | 2 years ago |
|
12af069dca | 2 years ago |
|
d42e708d31 | 2 years ago |
|
b7bb973118 | 2 years ago |
|
750b2a6313 | 2 years ago |
|
de0da86bd7 | 2 years ago |
|
8e283f512a | 2 years ago |
|
73162a4bc3 | 2 years ago |
|
1a9761736e | 2 years ago |
|
fd1f7665a7 | 2 years ago |
|
6d14573fd0 | 2 years ago |
|
cf69b836ac | 2 years ago |
|
a7a771b92b | 2 years ago |
|
def011c029 | 2 years ago |
|
4b055bf260 | 2 years ago |
|
1ba7484d60 | 2 years ago |
|
51c518da1e | 2 years ago |
|
a3b6b03dfb | 2 years ago |
|
18e3b38c69 | 2 years ago |
|
0ad30063ff | 2 years ago |
|
7812c64a31 | 2 years ago |
|
3d2376ab52 | 2 years ago |
|
6b207bbf2b | 2 years ago |
|
3f079ba7c6 | 2 years ago |
|
8f4c89f50e | 2 years ago |
|
6b7a543c82 | 2 years ago |
|
2ba68d24f2 | 2 years ago |
|
46877e0a92 | 2 years ago |
|
b55f555487 | 2 years ago |
|
a38b63be18 | 2 years ago |
|
1bebd6f4f5 | 2 years ago |
|
3da63f394d | 2 years ago |
|
2a54e3d770 | 2 years ago |
|
06b02ba46e | 2 years ago |
|
d01ae55109 | 2 years ago |
|
8868d7d188 | 2 years ago |
|
2eec9892be | 2 years ago |
|
01ae621f11 | 2 years ago |
|
f984aa0d2c | 2 years ago |
|
0881a6bc17 | 2 years ago |
|
2c6a73546d | 2 years ago |
|
a29944660e | 2 years ago |
|
f6ce624c6f | 2 years ago |
|
c09ec8e4d1 | 2 years ago |
|
31bbaad06e | 2 years ago |
|
b9ca1fe830 | 2 years ago |
|
e61585f2f3 | 2 years ago |
|
0de1aacb0c | 2 years ago |
|
168829b555 | 2 years ago |
|
170fc517d0 | 2 years ago |
|
0fbf1c7c71 | 2 years ago |
|
694be39c71 | 2 years ago |
|
dad26d81df | 2 years ago |
|
bcaea097ea | 2 years ago |
|
d56fe74e24 | 2 years ago |
|
4603d540c3 | 2 years ago |
|
f9d53303bb | 2 years ago |
|
d04faa6505 | 2 years ago |
|
07da058eae | 2 years ago |
|
cefa6b9878 | 2 years ago |
|
04d0b0223f | 2 years ago |
|
78ad6d2d88 | 2 years ago |
|
22cbd9fa58 | 2 years ago |
|
984049586a | 2 years ago |
|
cdfc2b92e3 | 2 years ago |
|
4530abe8df | 2 years ago |
|
586020b8b6 | 2 years ago |
|
3a8626fd04 | 2 years ago |
|
a6e483a434 | 2 years ago |
|
6a942e56b1 | 2 years ago |
|
87c91550ad | 2 years ago |
|
731daf0f37 | 2 years ago |
|
f931e53890 | 2 years ago |
|
b5efc68737 | 2 years ago |
|
b9e6e7926c | 2 years ago |
|
845034c81c | 2 years ago |
|
54d42e3f40 | 2 years ago |
|
e03ac3136e | 2 years ago |
|
6fb41a202a | 2 years ago |
|
4bef330ce1 | 2 years ago |
|
8a5f719964 | 2 years ago |
|
209d5e8e90 | 2 years ago |
|
9d041aa582 | 2 years ago |
|
6532b3e655 | 2 years ago |
|
c1c355160d | 2 years ago |
|
83515d5610 | 2 years ago |
|
aa10dccf90 | 2 years ago |
|
f4fd53211a | 2 years ago |
|
4993d19466 | 2 years ago |
|
19f9bbca0d | 2 years ago |
|
779d8e1627 | 2 years ago |
|
bb07410448 | 2 years ago |
|
d826f9e72f | 2 years ago |
|
6a6130615d | 2 years ago |
|
a8e7021be2 | 2 years ago |
|
38259d0382 | 2 years ago |
|
f7e7259910 | 2 years ago |
|
f0bfeba733 | 2 years ago |
|
c3a7a24eea | 2 years ago |
|
bbbcd780c9 | 2 years ago |
|
475469a2e7 | 2 years ago |
|
3a7447dcb6 | 2 years ago |
|
e5d8cbd383 | 2 years ago |
|
3c08dca7e7 | 2 years ago |
|
d083f01d22 | 2 years ago |
|
68cf393644 | 2 years ago |
|
18f7230662 | 2 years ago |
|
728f735281 | 2 years ago |
|
ecc418ba77 | 2 years ago |
|
3af5b7f2ac | 2 years ago |
|
7a7cfcacbe | 2 years ago |
|
52594355bf | 2 years ago |
|
0d06c28b19 | 2 years ago |
|
ccc4677252 | 2 years ago |
|
821fc9feed | 2 years ago |
|
82b46726fc | 2 years ago |
|
8df872a482 | 2 years ago |
|
c79c306adb | 2 years ago |
|
51fdaad002 | 2 years ago |
|
885cd8ff04 | 2 years ago |
|
2707af403a | 2 years ago |
|
2d227e5222 | 2 years ago |
|
70529878e2 | 2 years ago |
|
3b7a962dc6 | 2 years ago |
|
6dcf5c3d7d | 2 years ago |
|
b089bb5e7b | 2 years ago |
|
a91a67668e | 2 years ago |
|
220a908118 | 2 years ago |
|
54841248e7 | 2 years ago |
|
a0b42e6538 | 2 years ago |
|
3312cf525d | 2 years ago |
|
2093667548 | 2 years ago |
|
3c868d7961 | 2 years ago |
|
707f4f5816 | 2 years ago |
|
b3ab6311c5 | 2 years ago |
|
d56f605b63 | 2 years ago |
|
f8b713f425 | 2 years ago |
|
5209e95bc7 | 2 years ago |
|
ef67a45702 | 2 years ago |
|
b88eb72ac2 | 2 years ago |
|
32847f7254 | 2 years ago |
|
71df93b534 | 2 years ago |
|
bb028191f8 | 2 years ago |
|
19af8fc7d8 | 2 years ago |
|
a06671b47f | 2 years ago |
|
5f385d88e0 | 2 years ago |
|
9cb7a364a3 | 2 years ago |
|
f68cbc577d | 2 years ago |
|
dc975e8974 | 3 years ago |
|
4311ade535 | 3 years ago |
|
cd23401411 | 3 years ago |
|
176ee6910f | 3 years ago |
|
13c8f3d3aa | 3 years ago |
|
ce9af687bc | 3 years ago |
|
43f0d0cacd | 3 years ago |
|
20b4e6953e | 3 years ago |
|
7da287e3aa | 3 years ago |
|
205f885d69 | 3 years ago |
|
3715cd349d | 3 years ago |
|
e4c3ecc57e | 3 years ago |
|
673c5d886d | 3 years ago |
|
f799b568d1 | 3 years ago |
|
7bff4661f6 | 3 years ago |
|
ffd8bef808 | 3 years ago |
|
02cee2234d | 3 years ago |
|
e0dd2be3fb | 3 years ago |
|
a33c011c21 | 3 years ago |
|
7c3f42bbba | 3 years ago |
|
edac9820b5 | 3 years ago |
|
84a47f7102 | 3 years ago |
|
97ae8afb6f | 3 years ago |
|
4138333f5c | 3 years ago |
|
61339a8ae2 | 3 years ago |
|
50eb2e3855 | 3 years ago |
|
5fc78e4584 | 3 years ago |
|
2736a2f69e | 3 years ago |
|
179993f0cd | 3 years ago |
|
b734f657f9 | 3 years ago |
|
c29d7d02c2 | 3 years ago |
|
3df6b2a58c | 3 years ago |
|
b8aa2d2c32 | 3 years ago |
|
0ff885461b | 3 years ago |
|
ca43f95fb1 | 3 years ago |
|
09700f676b | 3 years ago |
|
4271e9cffa | 3 years ago |
|
f3dc8a10d5 | 3 years ago |
|
00fb486f6a | 3 years ago |
|
4173e94c6f | 3 years ago |
|
261d3d3340 | 3 years ago |
|
15e20fcae1 | 3 years ago |
|
f4f47f5fe3 | 3 years ago |
|
71d11de7ca | 3 years ago |
|
88d74a15aa | 3 years ago |
|
0f02fc0c77 | 3 years ago |
|
3f90fb42d8 | 3 years ago |
|
9bd8988300 | 3 years ago |
|
3c804bcfec | 3 years ago |
|
cca4cdc4f1 | 3 years ago |
|
8f899aaf8a | 3 years ago |
|
e53b4bb439 | 3 years ago |
|
ab247a1309 | 3 years ago |
|
c21e9edad4 | 3 years ago |
|
9c21a20f8b | 3 years ago |
|
7191ebb615 | 3 years ago |
|
a74731d7f5 | 3 years ago |
|
e086f0b3fe | 3 years ago |
|
8255aa23f4 | 3 years ago |
|
a4bc08f5a3 | 3 years ago |
|
7e5aa1e2a5 | 3 years ago |
|
0818dbc36a | 3 years ago |
|
347c4b2625 | 3 years ago |
|
34f0d4d0c4 | 3 years ago |
|
cbedb57511 | 3 years ago |
|
9ef825d2fd | 3 years ago |
|
85ae745910 | 3 years ago |
|
7411da8d5a | 3 years ago |
|
3f75a8369f | 3 years ago |
|
4cd621e877 | 3 years ago |
|
6e3a2fe0bf | 3 years ago |
|
8b0e1f941a | 3 years ago |
|
c7c5e7670a | 3 years ago |
|
f6c621ef1b | 3 years ago |
|
faf32d451d | 3 years ago |
|
252fd7ecb1 | 3 years ago |
|
7fa89dddb4 | 3 years ago |
|
fefdb8c84e | 3 years ago |
|
a6cc05936e | 3 years ago |
|
b209843545 | 3 years ago |
@ -1 +1 @@
|
||||
custom: ["https://paypal.me/junegunn", "https://www.buymeacoffee.com/junegunn"]
|
||||
github: junegunn
|
||||
|
@ -1,22 +0,0 @@
|
||||
<!-- ISSUES NOT FOLLOWING THIS TEMPLATE WILL BE CLOSED AND DELETED -->
|
||||
|
||||
<!-- Check all that apply [x] -->
|
||||
|
||||
- [ ] I have read through the manual page (`man fzf`)
|
||||
- [ ] I have the latest version of fzf
|
||||
- [ ] I have searched through the existing issues
|
||||
|
||||
## Info
|
||||
|
||||
- OS
|
||||
- [ ] Linux
|
||||
- [ ] Mac OS X
|
||||
- [ ] Windows
|
||||
- [ ] Etc.
|
||||
- Shell
|
||||
- [ ] bash
|
||||
- [ ] zsh
|
||||
- [ ] fish
|
||||
|
||||
## Problem / Steps to reproduce
|
||||
|
@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Issue Template
|
||||
description: Report a problem or bug related to fzf to help us improve
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: ISSUES NOT FOLLOWING THIS TEMPLATE WILL BE CLOSED AND DELETED
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: I have read through the manual page (`man fzf`)
|
||||
required: true
|
||||
- label: I have searched through the existing issues
|
||||
required: true
|
||||
- label: For bug reports, I have checked if the bug is reproducible in the latest version of fzf
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Output of `fzf --version`
|
||||
placeholder: e.g. 0.48.1 (d579e33)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: OS
|
||||
options:
|
||||
- label: Linux
|
||||
- label: macOS
|
||||
- label: Windows
|
||||
- label: Etc.
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Shell
|
||||
options:
|
||||
- label: bash
|
||||
- label: zsh
|
||||
- label: fish
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem / Steps to reproduce
|
||||
validations:
|
||||
required: true
|
@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
@ -0,0 +1,14 @@
|
||||
name: 'Dependency Review'
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v4
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v4
|
@ -0,0 +1,24 @@
|
||||
---
|
||||
name: Generate Sponsors README
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: 0 0 * * 0
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate Sponsors 💖
|
||||
uses: JamesIves/github-sponsors-readme-action@v1
|
||||
with:
|
||||
token: ${{ secrets.SPONSORS_TOKEN }}
|
||||
file: 'README.md'
|
||||
|
||||
- name: Deploy to GitHub Pages 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
branch: master
|
||||
folder: '.'
|
@ -0,0 +1,10 @@
|
||||
name: "Spell Check"
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
typos:
|
||||
name: Spell Check with Typos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: crate-ci/typos@v1.22.7
|
@ -0,0 +1,15 @@
|
||||
name: Publish to Winget
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: vedantmgoyal2009/winget-releaser@v2
|
||||
with:
|
||||
identifier: junegunn.fzf
|
||||
version: ${{ github.event.release.tag_name }}
|
||||
installers-regex: '-windows_(armv7|arm64|amd64)\.zip$'
|
||||
token: ${{ secrets.WINGET_TOKEN }}
|
@ -0,0 +1 @@
|
||||
golang 1.20.13
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# The purpose of this script is to demonstrate how to preview a file or an
|
||||
# image in the preview window of fzf.
|
||||
#
|
||||
# Dependencies:
|
||||
# - https://github.com/sharkdp/bat
|
||||
# - https://github.com/hpjansson/chafa
|
||||
# - https://iterm2.com/utilities/imgcat
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
>&2 echo "usage: $0 FILENAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file=${1/#\~\//$HOME/}
|
||||
type=$(file --dereference --mime -- "$file")
|
||||
|
||||
if [[ ! $type =~ image/ ]]; then
|
||||
if [[ $type =~ =binary ]]; then
|
||||
file "$1"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Sometimes bat is installed as batcat.
|
||||
if command -v batcat > /dev/null; then
|
||||
batname="batcat"
|
||||
elif command -v bat > /dev/null; then
|
||||
batname="bat"
|
||||
else
|
||||
cat "$1"
|
||||
exit
|
||||
fi
|
||||
|
||||
${batname} --style="${BAT_STYLE:-numbers}" --color=always --pager=never -- "$file"
|
||||
exit
|
||||
fi
|
||||
|
||||
dim=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}
|
||||
if [[ $dim = x ]]; then
|
||||
dim=$(stty size < /dev/tty | awk '{print $2 "x" $1}')
|
||||
elif ! [[ $KITTY_WINDOW_ID ]] && (( FZF_PREVIEW_TOP + FZF_PREVIEW_LINES == $(stty size < /dev/tty | awk '{print $1}') )); then
|
||||
# Avoid scrolling issue when the Sixel image touches the bottom of the screen
|
||||
# * https://github.com/junegunn/fzf/issues/2544
|
||||
dim=${FZF_PREVIEW_COLUMNS}x$((FZF_PREVIEW_LINES - 1))
|
||||
fi
|
||||
|
||||
# 1. Use kitty icat on kitty terminal
|
||||
if [[ $KITTY_WINDOW_ID ]]; then
|
||||
# 1. 'memory' is the fastest option but if you want the image to be scrollable,
|
||||
# you have to use 'stream'.
|
||||
#
|
||||
# 2. The last line of the output is the ANSI reset code without newline.
|
||||
# This confuses fzf and makes it render scroll offset indicator.
|
||||
# So we remove the last line and append the reset code to its previous line.
|
||||
kitty icat --clear --transfer-mode=memory --unicode-placeholder --stdin=no --place="$dim@0x0" "$file" | sed '$d' | sed $'$s/$/\e[m/'
|
||||
|
||||
# 2. Use chafa with Sixel output
|
||||
elif command -v chafa > /dev/null; then
|
||||
chafa -s "$dim" "$file"
|
||||
# Add a new line character so that fzf can display multiple images in the preview window
|
||||
echo
|
||||
|
||||
# 3. If chafa is not found but imgcat is available, use it on iTerm2
|
||||
elif command -v imgcat > /dev/null; then
|
||||
# NOTE: We should use https://iterm2.com/utilities/it2check to check if the
|
||||
# user is running iTerm2. But for the sake of simplicity, we just assume
|
||||
# that's the case here.
|
||||
imgcat -W "${dim%%x*}" -H "${dim##*x}" "$file"
|
||||
|
||||
# 4. Cannot find any suitable method to preview the image
|
||||
else
|
||||
file "$file"
|
||||
fi
|
@ -1,17 +1,20 @@
|
||||
module github.com/junegunn/fzf
|
||||
|
||||
require (
|
||||
github.com/gdamore/tcell v1.4.0
|
||||
github.com/charlievieth/fastwalk v1.0.4
|
||||
github.com/gdamore/tcell/v2 v2.7.4
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mattn/go-shellwords v1.0.12
|
||||
github.com/rivo/uniseg v0.4.7
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.org/x/term v0.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/mattn/go-runewidth v0.0.12
|
||||
github.com/mattn/go-shellwords v1.0.11
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/saracen/walker v0.1.2
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
|
||||
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
||||
go 1.20
|
||||
|
@ -1,33 +1,57 @@
|
||||
github.com/charlievieth/fastwalk v1.0.4 h1:EG3y5L1XBa8VftvpONuQlfe5sNuf1xzGpm59bdgCDwo=
|
||||
github.com/charlievieth/fastwalk v1.0.4/go.mod h1:JSfglY/gmL/rqsUS1NCsJTocB5n6sSl9ApAqif4CUbs=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
|
||||
github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
|
||||
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-shellwords v1.0.11 h1:vCoR9VPpsk/TZFW2JwK5I9S0xdrtUq2bph6/YjEPnaw=
|
||||
github.com/mattn/go-shellwords v1.0.11/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/saracen/walker v0.1.2 h1:/o1TxP82n8thLvmL4GpJXduYaRmJ7qXp8u9dSlV0zmo=
|
||||
github.com/saracen/walker v0.1.2/go.mod h1:0oKYMsKVhSJ+ful4p/XbjvXbMgLEkLITZaxozsl4CGE=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 h1:EC6+IGYTjPpRfv9a2b/6Puw0W+hLtAhkV1tPsXhutqs=
|
||||
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -1,14 +1,101 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/junegunn/fzf/src"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
fzf "github.com/junegunn/fzf/src"
|
||||
"github.com/junegunn/fzf/src/protector"
|
||||
)
|
||||
|
||||
var version string = "0.27"
|
||||
var revision string = "devel"
|
||||
var version = "0.53"
|
||||
var revision = "devel"
|
||||
|
||||
//go:embed shell/key-bindings.bash
|
||||
var bashKeyBindings []byte
|
||||
|
||||
//go:embed shell/completion.bash
|
||||
var bashCompletion []byte
|
||||
|
||||
//go:embed shell/key-bindings.zsh
|
||||
var zshKeyBindings []byte
|
||||
|
||||
//go:embed shell/completion.zsh
|
||||
var zshCompletion []byte
|
||||
|
||||
//go:embed shell/key-bindings.fish
|
||||
var fishKeyBindings []byte
|
||||
|
||||
//go:embed man/man1/fzf.1
|
||||
var manPage []byte
|
||||
|
||||
func printScript(label string, content []byte) {
|
||||
fmt.Println("### " + label + " ###")
|
||||
fmt.Println(strings.TrimSpace(string(content)))
|
||||
fmt.Println("### end: " + label + " ###")
|
||||
}
|
||||
|
||||
func exit(code int, err error) {
|
||||
if code == fzf.ExitError && err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func main() {
|
||||
protector.Protect()
|
||||
fzf.Run(fzf.ParseOptions(), version, revision)
|
||||
|
||||
options, err := fzf.ParseOptions(true, os.Args[1:])
|
||||
if err != nil {
|
||||
exit(fzf.ExitError, err)
|
||||
return
|
||||
}
|
||||
if options.Bash {
|
||||
printScript("key-bindings.bash", bashKeyBindings)
|
||||
printScript("completion.bash", bashCompletion)
|
||||
return
|
||||
}
|
||||
if options.Zsh {
|
||||
printScript("key-bindings.zsh", zshKeyBindings)
|
||||
printScript("completion.zsh", zshCompletion)
|
||||
return
|
||||
}
|
||||
if options.Fish {
|
||||
printScript("key-bindings.fish", fishKeyBindings)
|
||||
fmt.Println("fzf_key_bindings")
|
||||
return
|
||||
}
|
||||
if options.Help {
|
||||
fmt.Print(fzf.Usage)
|
||||
return
|
||||
}
|
||||
if options.Version {
|
||||
if len(revision) > 0 {
|
||||
fmt.Printf("%s (%s)\n", version, revision)
|
||||
} else {
|
||||
fmt.Println(version)
|
||||
}
|
||||
return
|
||||
}
|
||||
if options.Man {
|
||||
file := fzf.WriteTemporaryFile([]string{string(manPage)}, "\n")
|
||||
if len(file) == 0 {
|
||||
fmt.Print(string(manPage))
|
||||
return
|
||||
}
|
||||
defer os.Remove(file)
|
||||
cmd := exec.Command("man", file)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Print(string(manPage))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
code, err := fzf.Run(options)
|
||||
exit(code, err)
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,134 @@
|
||||
// Code generated by "stringer -type=actionType"; DO NOT EDIT.
|
||||
|
||||
package fzf
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[actIgnore-0]
|
||||
_ = x[actStart-1]
|
||||
_ = x[actClick-2]
|
||||
_ = x[actInvalid-3]
|
||||
_ = x[actChar-4]
|
||||
_ = x[actMouse-5]
|
||||
_ = x[actBeginningOfLine-6]
|
||||
_ = x[actAbort-7]
|
||||
_ = x[actAccept-8]
|
||||
_ = x[actAcceptNonEmpty-9]
|
||||
_ = x[actAcceptOrPrintQuery-10]
|
||||
_ = x[actBackwardChar-11]
|
||||
_ = x[actBackwardDeleteChar-12]
|
||||
_ = x[actBackwardDeleteCharEof-13]
|
||||
_ = x[actBackwardWord-14]
|
||||
_ = x[actCancel-15]
|
||||
_ = x[actChangeBorderLabel-16]
|
||||
_ = x[actChangeHeader-17]
|
||||
_ = x[actChangeMulti-18]
|
||||
_ = x[actChangePreviewLabel-19]
|
||||
_ = x[actChangePrompt-20]
|
||||
_ = x[actChangeQuery-21]
|
||||
_ = x[actClearScreen-22]
|
||||
_ = x[actClearQuery-23]
|
||||
_ = x[actClearSelection-24]
|
||||
_ = x[actClose-25]
|
||||
_ = x[actDeleteChar-26]
|
||||
_ = x[actDeleteCharEof-27]
|
||||
_ = x[actEndOfLine-28]
|
||||
_ = x[actFatal-29]
|
||||
_ = x[actForwardChar-30]
|
||||
_ = x[actForwardWord-31]
|
||||
_ = x[actKillLine-32]
|
||||
_ = x[actKillWord-33]
|
||||
_ = x[actUnixLineDiscard-34]
|
||||
_ = x[actUnixWordRubout-35]
|
||||
_ = x[actYank-36]
|
||||
_ = x[actBackwardKillWord-37]
|
||||
_ = x[actSelectAll-38]
|
||||
_ = x[actDeselectAll-39]
|
||||
_ = x[actToggle-40]
|
||||
_ = x[actToggleSearch-41]
|
||||
_ = x[actToggleAll-42]
|
||||
_ = x[actToggleDown-43]
|
||||
_ = x[actToggleUp-44]
|
||||
_ = x[actToggleIn-45]
|
||||
_ = x[actToggleOut-46]
|
||||
_ = x[actToggleTrack-47]
|
||||
_ = x[actToggleTrackCurrent-48]
|
||||
_ = x[actToggleHeader-49]
|
||||
_ = x[actTrackCurrent-50]
|
||||
_ = x[actUntrackCurrent-51]
|
||||
_ = x[actDown-52]
|
||||
_ = x[actUp-53]
|
||||
_ = x[actPageUp-54]
|
||||
_ = x[actPageDown-55]
|
||||
_ = x[actPosition-56]
|
||||
_ = x[actHalfPageUp-57]
|
||||
_ = x[actHalfPageDown-58]
|
||||
_ = x[actOffsetUp-59]
|
||||
_ = x[actOffsetDown-60]
|
||||
_ = x[actOffsetMiddle-61]
|
||||
_ = x[actJump-62]
|
||||
_ = x[actJumpAccept-63]
|
||||
_ = x[actPrintQuery-64]
|
||||
_ = x[actRefreshPreview-65]
|
||||
_ = x[actReplaceQuery-66]
|
||||
_ = x[actToggleSort-67]
|
||||
_ = x[actShowPreview-68]
|
||||
_ = x[actHidePreview-69]
|
||||
_ = x[actTogglePreview-70]
|
||||
_ = x[actTogglePreviewWrap-71]
|
||||
_ = x[actTransform-72]
|
||||
_ = x[actTransformBorderLabel-73]
|
||||
_ = x[actTransformHeader-74]
|
||||
_ = x[actTransformPreviewLabel-75]
|
||||
_ = x[actTransformPrompt-76]
|
||||
_ = x[actTransformQuery-77]
|
||||
_ = x[actPreview-78]
|
||||
_ = x[actChangePreview-79]
|
||||
_ = x[actChangePreviewWindow-80]
|
||||
_ = x[actPreviewTop-81]
|
||||
_ = x[actPreviewBottom-82]
|
||||
_ = x[actPreviewUp-83]
|
||||
_ = x[actPreviewDown-84]
|
||||
_ = x[actPreviewPageUp-85]
|
||||
_ = x[actPreviewPageDown-86]
|
||||
_ = x[actPreviewHalfPageUp-87]
|
||||
_ = x[actPreviewHalfPageDown-88]
|
||||
_ = x[actPrevHistory-89]
|
||||
_ = x[actPrevSelected-90]
|
||||
_ = x[actPrint-91]
|
||||
_ = x[actPut-92]
|
||||
_ = x[actNextHistory-93]
|
||||
_ = x[actNextSelected-94]
|
||||
_ = x[actExecute-95]
|
||||
_ = x[actExecuteSilent-96]
|
||||
_ = x[actExecuteMulti-97]
|
||||
_ = x[actSigStop-98]
|
||||
_ = x[actFirst-99]
|
||||
_ = x[actLast-100]
|
||||
_ = x[actReload-101]
|
||||
_ = x[actReloadSync-102]
|
||||
_ = x[actDisableSearch-103]
|
||||
_ = x[actEnableSearch-104]
|
||||
_ = x[actSelect-105]
|
||||
_ = x[actDeselect-106]
|
||||
_ = x[actUnbind-107]
|
||||
_ = x[actRebind-108]
|
||||
_ = x[actBecome-109]
|
||||
_ = x[actShowHeader-110]
|
||||
_ = x[actHideHeader-111]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeHeaderactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformHeaderactTransformPreviewLabelactTransformPromptactTransformQueryactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeader"
|
||||
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 242, 256, 277, 292, 306, 320, 333, 350, 358, 371, 387, 399, 407, 421, 435, 446, 457, 475, 492, 499, 518, 530, 544, 553, 568, 580, 593, 604, 615, 627, 641, 662, 677, 692, 709, 716, 721, 730, 741, 752, 765, 780, 791, 804, 819, 826, 839, 852, 869, 884, 897, 911, 925, 941, 961, 973, 996, 1014, 1038, 1056, 1073, 1083, 1099, 1121, 1134, 1150, 1162, 1176, 1192, 1210, 1230, 1252, 1266, 1281, 1289, 1295, 1309, 1324, 1334, 1350, 1365, 1375, 1383, 1390, 1399, 1412, 1428, 1443, 1452, 1463, 1472, 1481, 1490, 1503, 1516}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
return "actionType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _actionType_name[_actionType_index[i]:_actionType_index[i+1]]
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func WriteTemporaryFile(data []string, printSep string) string {
|
||||
f, err := os.CreateTemp("", "fzf-temp-*")
|
||||
if err != nil {
|
||||
// Unable to create temporary file
|
||||
// FIXME: Should we terminate the program?
|
||||
return ""
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
f.WriteString(strings.Join(data, printSep))
|
||||
f.WriteString(printSep)
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
func removeFiles(files []string) {
|
||||
for _, filename := range files {
|
||||
os.Remove(filename)
|
||||
}
|
||||
}
|
||||
|
||||
func stringBytes(data string) []byte {
|
||||
return unsafe.Slice(unsafe.StringData(data), len(data))
|
||||
}
|
||||
|
||||
func byteString(data []byte) string {
|
||||
return unsafe.String(unsafe.SliceData(data), len(data))
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@
|
||||
//go:build !pprof
|
||||
// +build !pprof
|
||||
|
||||
package fzf
|
||||
|
||||
import "errors"
|
||||
|
||||
func (o *Options) initProfiling() error {
|
||||
if o.CPUProfile != "" || o.MEMProfile != "" || o.BlockProfile != "" || o.MutexProfile != "" {
|
||||
return errors.New("error: profiling not supported: FZF must be built with '-tags=pprof' to enable profiling")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
//go:build pprof
|
||||
// +build pprof
|
||||
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
func (o *Options) initProfiling() error {
|
||||
if o.CPUProfile != "" {
|
||||
f, err := os.Create(o.CPUProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create CPU profile: %w", err)
|
||||
}
|
||||
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
return fmt.Errorf("could not start CPU profile: %w", err)
|
||||
}
|
||||
|
||||
util.AtExit(func() {
|
||||
pprof.StopCPUProfile()
|
||||
if err := f.Close(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Error: closing cpu profile:", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
stopProfile := func(name string, f *os.File) {
|
||||
if err := pprof.Lookup(name).WriteTo(f, 0); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: could not write %s profile: %v\n", name, err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: closing %s profile: %v\n", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if o.MEMProfile != "" {
|
||||
f, err := os.Create(o.MEMProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create MEM profile: %w", err)
|
||||
}
|
||||
util.AtExit(func() {
|
||||
runtime.GC()
|
||||
stopProfile("allocs", f)
|
||||
})
|
||||
}
|
||||
|
||||
if o.BlockProfile != "" {
|
||||
runtime.SetBlockProfileRate(1)
|
||||
f, err := os.Create(o.BlockProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create BLOCK profile: %w", err)
|
||||
}
|
||||
util.AtExit(func() { stopProfile("block", f) })
|
||||
}
|
||||
|
||||
if o.MutexProfile != "" {
|
||||
runtime.SetMutexProfileFraction(1)
|
||||
f, err := os.Create(o.MutexProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create MUTEX profile: %w", err)
|
||||
}
|
||||
util.AtExit(func() { stopProfile("mutex", f) })
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
//go:build pprof
|
||||
// +build pprof
|
||||
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
// runInitProfileTests is an internal flag used TestInitProfiling
|
||||
var runInitProfileTests = flag.Bool("test-init-profile", false, "run init profile tests")
|
||||
|
||||
func TestInitProfiling(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("short test")
|
||||
}
|
||||
|
||||
// Run this test in a separate process since it interferes with
|
||||
// profiling and modifies the global atexit state. Without this
|
||||
// running `go test -bench . -cpuprofile cpu.out` will fail.
|
||||
if !*runInitProfileTests {
|
||||
t.Parallel()
|
||||
|
||||
// Make sure we are not the child process.
|
||||
if os.Getenv("_FZF_CHILD_PROC") != "" {
|
||||
t.Fatal("already running as child process!")
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0],
|
||||
"-test.timeout", "30s",
|
||||
"-test.run", "^"+t.Name()+"$",
|
||||
"-test-init-profile",
|
||||
)
|
||||
cmd.Env = append(os.Environ(), "_FZF_CHILD_PROC=1")
|
||||
|
||||
out, err := cmd.CombinedOutput()
|
||||
out = bytes.TrimSpace(out)
|
||||
if err != nil {
|
||||
t.Fatalf("Child test process failed: %v:\n%s", err, out)
|
||||
}
|
||||
// Make sure the test actually ran
|
||||
if bytes.Contains(out, []byte("no tests to run")) {
|
||||
t.Fatalf("Failed to run test %q:\n%s", t.Name(), out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Child process
|
||||
|
||||
tempdir := t.TempDir()
|
||||
t.Cleanup(util.RunAtExitFuncs)
|
||||
|
||||
o := Options{
|
||||
CPUProfile: filepath.Join(tempdir, "cpu.prof"),
|
||||
MEMProfile: filepath.Join(tempdir, "mem.prof"),
|
||||
BlockProfile: filepath.Join(tempdir, "block.prof"),
|
||||
MutexProfile: filepath.Join(tempdir, "mutex.prof"),
|
||||
}
|
||||
if err := o.initProfiling(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
profiles := []string{
|
||||
o.CPUProfile,
|
||||
o.MEMProfile,
|
||||
o.BlockProfile,
|
||||
o.MutexProfile,
|
||||
}
|
||||
for _, name := range profiles {
|
||||
if _, err := os.Stat(name); err != nil {
|
||||
t.Errorf("Failed to create profile %s: %v", filepath.Base(name), err)
|
||||
}
|
||||
}
|
||||
|
||||
util.RunAtExitFuncs()
|
||||
|
||||
for _, name := range profiles {
|
||||
if _, err := os.Stat(name); err != nil {
|
||||
t.Errorf("Failed to write profile %s: %v", filepath.Base(name), err)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
// +build !openbsd
|
||||
//go:build !openbsd
|
||||
|
||||
package protector
|
||||
|
||||
// Protect calls OS specific protections like pledge on OpenBSD
|
||||
func Protect() {
|
||||
return
|
||||
}
|
||||
func Protect() {}
|
||||
|
@ -0,0 +1,146 @@
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/junegunn/fzf/src/tui"
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
const becomeSuffix = ".become"
|
||||
|
||||
func escapeSingleQuote(str string) string {
|
||||
return "'" + strings.ReplaceAll(str, "'", "'\\''") + "'"
|
||||
}
|
||||
|
||||
func fifo(name string) (string, error) {
|
||||
ns := time.Now().UnixNano()
|
||||
output := filepath.Join(os.TempDir(), fmt.Sprintf("fzf-%s-%d", name, ns))
|
||||
output, err := mkfifo(output, 0600)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func runProxy(commandPrefix string, cmdBuilder func(temp string) *exec.Cmd, opts *Options, withExports bool) (int, error) {
|
||||
output, err := fifo("proxy-output")
|
||||
if err != nil {
|
||||
return ExitError, err
|
||||
}
|
||||
defer os.Remove(output)
|
||||
|
||||
// Take the output
|
||||
go func() {
|
||||
withOutputPipe(output, func(outputFile io.ReadCloser) {
|
||||
if opts.Output == nil {
|
||||
io.Copy(os.Stdout, outputFile)
|
||||
} else {
|
||||
reader := bufio.NewReader(outputFile)
|
||||
sep := opts.PrintSep[0]
|
||||
for {
|
||||
item, err := reader.ReadString(sep)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
opts.Output <- item
|
||||
}
|
||||
}
|
||||
})
|
||||
}()
|
||||
|
||||
var command string
|
||||
commandPrefix += ` --no-force-tty-in --proxy-script "$0"`
|
||||
if opts.Input == nil && (opts.ForceTtyIn || util.IsTty(os.Stdin)) {
|
||||
command = fmt.Sprintf(`%s > %q`, commandPrefix, output)
|
||||
} else {
|
||||
input, err := fifo("proxy-input")
|
||||
if err != nil {
|
||||
return ExitError, err
|
||||
}
|
||||
defer os.Remove(input)
|
||||
|
||||
go func() {
|
||||
withInputPipe(input, func(inputFile io.WriteCloser) {
|
||||
if opts.Input == nil {
|
||||
io.Copy(inputFile, os.Stdin)
|
||||
} else {
|
||||
for item := range opts.Input {
|
||||
fmt.Fprint(inputFile, item+opts.PrintSep)
|
||||
}
|
||||
}
|
||||
})
|
||||
}()
|
||||
|
||||
if withExports {
|
||||
command = fmt.Sprintf(`%s < %q > %q`, commandPrefix, input, output)
|
||||
} else {
|
||||
// For mintty: cannot directly read named pipe from Go code
|
||||
command = fmt.Sprintf(`command cat %q | %s > %q`, input, commandPrefix, output)
|
||||
}
|
||||
}
|
||||
|
||||
// To ensure that the options are processed by a POSIX-compliant shell,
|
||||
// we need to write the command to a temporary file and execute it with sh.
|
||||
var exports []string
|
||||
if withExports {
|
||||
exports = os.Environ()
|
||||
for idx, pairStr := range exports {
|
||||
pair := strings.SplitN(pairStr, "=", 2)
|
||||
exports[idx] = fmt.Sprintf("export %s=%s", pair[0], escapeSingleQuote(pair[1]))
|
||||
}
|
||||
}
|
||||
temp := WriteTemporaryFile(append(exports, command), "\n")
|
||||
defer os.Remove(temp)
|
||||
|
||||
cmd := cmdBuilder(temp)
|
||||
cmd.Stderr = os.Stderr
|
||||
intChan := make(chan os.Signal, 1)
|
||||
defer close(intChan)
|
||||
go func() {
|
||||
if sig, valid := <-intChan; valid {
|
||||
cmd.Process.Signal(sig)
|
||||
}
|
||||
}()
|
||||
signal.Notify(intChan, os.Interrupt)
|
||||
if err := cmd.Run(); err != nil {
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
code := exitError.ExitCode()
|
||||
if code == ExitBecome {
|
||||
becomeFile := temp + becomeSuffix
|
||||
data, err := os.ReadFile(becomeFile)
|
||||
os.Remove(becomeFile)
|
||||
if err != nil {
|
||||
return ExitError, err
|
||||
}
|
||||
elems := strings.Split(string(data), "\x00")
|
||||
if len(elems) < 1 {
|
||||
return ExitError, errors.New("invalid become command")
|
||||
}
|
||||
command := elems[0]
|
||||
env := []string{}
|
||||
if len(elems) > 1 {
|
||||
env = elems[1:]
|
||||
}
|
||||
executor := util.NewExecutor(opts.WithShell)
|
||||
ttyin, err := tui.TtyIn()
|
||||
if err != nil {
|
||||
return ExitError, err
|
||||
}
|
||||
executor.Become(ttyin, env, command)
|
||||
}
|
||||
return code, err
|
||||
}
|
||||
}
|
||||
|
||||
return ExitOk, nil
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
//go:build !windows
|
||||
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func sh() (string, error) {
|
||||
return "sh", nil
|
||||
}
|
||||
|
||||
func mkfifo(path string, mode uint32) (string, error) {
|
||||
return path, unix.Mkfifo(path, mode)
|
||||
}
|
||||
|
||||
func withOutputPipe(output string, task func(io.ReadCloser)) error {
|
||||
outputFile, err := os.OpenFile(output, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task(outputFile)
|
||||
outputFile.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func withInputPipe(input string, task func(io.WriteCloser)) error {
|
||||
inputFile, err := os.OpenFile(input, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task(inputFile)
|
||||
inputFile.Close()
|
||||
return nil
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
//go:build windows
|
||||
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var shPath atomic.Value
|
||||
|
||||
func sh() (string, error) {
|
||||
if cached := shPath.Load(); cached != nil {
|
||||
return cached.(string), nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("cygpath", "-w", "/usr/bin/sh")
|
||||
bytes, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sh := strings.TrimSpace(string(bytes))
|
||||
shPath.Store(sh)
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
func mkfifo(path string, mode uint32) (string, error) {
|
||||
m := strconv.FormatUint(uint64(mode), 8)
|
||||
sh, err := sh()
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
cmd := exec.Command(sh, "-c", fmt.Sprintf(`command mkfifo -m %s %q`, m, path))
|
||||
if err := cmd.Run(); err != nil {
|
||||
return path, err
|
||||
}
|
||||
return path + ".lnk", nil
|
||||
}
|
||||
|
||||
func withOutputPipe(output string, task func(io.ReadCloser)) error {
|
||||
sh, err := sh()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command(sh, "-c", fmt.Sprintf(`command cat %q`, output))
|
||||
outputFile, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
task(outputFile)
|
||||
cmd.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func withInputPipe(input string, task func(io.WriteCloser)) error {
|
||||
sh, err := sh()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command(sh, "-c", fmt.Sprintf(`command cat - > %q`, input))
|
||||
inputFile, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
task(inputFile)
|
||||
inputFile.Close()
|
||||
cmd.Wait()
|
||||
return nil
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var getRegex *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
getRegex = regexp.MustCompile(`^GET /(?:\?([a-z0-9=&]+))? HTTP`)
|
||||
}
|
||||
|
||||
type getParams struct {
|
||||
limit int
|
||||
offset int
|
||||
}
|
||||
|
||||
const (
|
||||
crlf = "\r\n"
|
||||
httpOk = "HTTP/1.1 200 OK" + crlf
|
||||
httpBadRequest = "HTTP/1.1 400 Bad Request" + crlf
|
||||
httpUnauthorized = "HTTP/1.1 401 Unauthorized" + crlf
|
||||
httpUnavailable = "HTTP/1.1 503 Service Unavailable" + crlf
|
||||
httpReadTimeout = 10 * time.Second
|
||||
channelTimeout = 2 * time.Second
|
||||
jsonContentType = "Content-Type: application/json" + crlf
|
||||
maxContentLength = 1024 * 1024
|
||||
)
|
||||
|
||||
type httpServer struct {
|
||||
apiKey []byte
|
||||
actionChannel chan []*action
|
||||
getHandler func(getParams) string
|
||||
}
|
||||
|
||||
type listenAddress struct {
|
||||
host string
|
||||
port int
|
||||
}
|
||||
|
||||
func (addr listenAddress) IsLocal() bool {
|
||||
return addr.host == "localhost" || addr.host == "127.0.0.1"
|
||||
}
|
||||
|
||||
var defaultListenAddr = listenAddress{"localhost", 0}
|
||||
|
||||
func parseListenAddress(address string) (listenAddress, error) {
|
||||
parts := strings.SplitN(address, ":", 3)
|
||||
if len(parts) == 1 {
|
||||
parts = []string{"localhost", parts[0]}
|
||||
}
|
||||
if len(parts) != 2 {
|
||||
return defaultListenAddr, fmt.Errorf("invalid listen address: %s", address)
|
||||
}
|
||||
portStr := parts[len(parts)-1]
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil || port < 0 || port > 65535 {
|
||||
return defaultListenAddr, fmt.Errorf("invalid listen port: %s", portStr)
|
||||
}
|
||||
if len(parts[0]) == 0 {
|
||||
parts[0] = "localhost"
|
||||
}
|
||||
return listenAddress{parts[0], port}, nil
|
||||
}
|
||||
|
||||
func startHttpServer(address listenAddress, actionChannel chan []*action, getHandler func(getParams) string) (net.Listener, int, error) {
|
||||
host := address.host
|
||||
port := address.port
|
||||
apiKey := os.Getenv("FZF_API_KEY")
|
||||
if !address.IsLocal() && len(apiKey) == 0 {
|
||||
return nil, port, errors.New("FZF_API_KEY is required to allow remote access")
|
||||
}
|
||||
addrStr := fmt.Sprintf("%s:%d", host, port)
|
||||
listener, err := net.Listen("tcp", addrStr)
|
||||
if err != nil {
|
||||
return nil, port, fmt.Errorf("failed to listen on %s", addrStr)
|
||||
}
|
||||
if port == 0 {
|
||||
addr := listener.Addr().String()
|
||||
parts := strings.Split(addr, ":")
|
||||
if len(parts) < 2 {
|
||||
return nil, port, fmt.Errorf("cannot extract port: %s", addr)
|
||||
}
|
||||
var err error
|
||||
port, err = strconv.Atoi(parts[len(parts)-1])
|
||||
if err != nil {
|
||||
return nil, port, err
|
||||
}
|
||||
}
|
||||
|
||||
server := httpServer{
|
||||
apiKey: []byte(apiKey),
|
||||
actionChannel: actionChannel,
|
||||
getHandler: getHandler,
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
if errors.Is(err, net.ErrClosed) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
conn.Write([]byte(server.handleHttpRequest(conn)))
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
return listener, port, nil
|
||||
}
|
||||
|
||||
// Here we are writing a simplistic HTTP server without using net/http
|
||||
// package to reduce the size of the binary.
|
||||
//
|
||||
// * No --listen: 2.8MB
|
||||
// * --listen with net/http: 5.7MB
|
||||
// * --listen w/o net/http: 3.3MB
|
||||
func (server *httpServer) handleHttpRequest(conn net.Conn) string {
|
||||
contentLength := 0
|
||||
apiKey := ""
|
||||
body := ""
|
||||
answer := func(code string, message string) string {
|
||||
message += "\n"
|
||||
return code + fmt.Sprintf("Content-Length: %d%s", len(message), crlf+crlf+message)
|
||||
}
|
||||
unauthorized := func(message string) string {
|
||||
return answer(httpUnauthorized, message)
|
||||
}
|
||||
bad := func(message string) string {
|
||||
return answer(httpBadRequest, message)
|
||||
}
|
||||
good := func(message string) string {
|
||||
return answer(httpOk+jsonContentType, message)
|
||||
}
|
||||
conn.SetReadDeadline(time.Now().Add(httpReadTimeout))
|
||||
scanner := bufio.NewScanner(conn)
|
||||
scanner.Split(func(data []byte, atEOF bool) (int, []byte, error) {
|
||||
found := bytes.Index(data, []byte(crlf))
|
||||
if found >= 0 {
|
||||
token := data[:found+len(crlf)]
|
||||
return len(token), token, nil
|
||||
}
|
||||
if atEOF || len(body)+len(data) >= contentLength {
|
||||
return 0, data, bufio.ErrFinalToken
|
||||
}
|
||||
return 0, nil, nil
|
||||
})
|
||||
|
||||
section := 0
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
switch section {
|
||||
case 0:
|
||||
getMatch := getRegex.FindStringSubmatch(text)
|
||||
if len(getMatch) > 0 {
|
||||
response := server.getHandler(parseGetParams(getMatch[1]))
|
||||
if len(response) > 0 {
|
||||
return good(response)
|
||||
}
|
||||
return answer(httpUnavailable+jsonContentType, `{"error":"timeout"}`)
|
||||
} else if !strings.HasPrefix(text, "POST / HTTP") {
|
||||
return bad("invalid request method")
|
||||
}
|
||||
section++
|
||||
case 1:
|
||||
if text == crlf {
|
||||
if contentLength == 0 {
|
||||
return bad("content-length header missing")
|
||||
}
|
||||
section++
|
||||
continue
|
||||
}
|
||||
pair := strings.SplitN(text, ":", 2)
|
||||
if len(pair) == 2 {
|
||||
switch strings.ToLower(pair[0]) {
|
||||
case "content-length":
|
||||
length, err := strconv.Atoi(strings.TrimSpace(pair[1]))
|
||||
if err != nil || length <= 0 || length > maxContentLength {
|
||||
return bad("invalid content length")
|
||||
}
|
||||
contentLength = length
|
||||
case "x-api-key":
|
||||
apiKey = strings.TrimSpace(pair[1])
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
body += text
|
||||
}
|
||||
}
|
||||
|
||||
if len(server.apiKey) != 0 && subtle.ConstantTimeCompare([]byte(apiKey), server.apiKey) != 1 {
|
||||
return unauthorized("invalid api key")
|
||||
}
|
||||
|
||||
if len(body) < contentLength {
|
||||
return bad("incomplete request")
|
||||
}
|
||||
body = body[:contentLength]
|
||||
|
||||
actions, err := parseSingleActionList(strings.Trim(string(body), "\r\n"))
|
||||
if err != nil {
|
||||
return bad(err.Error())
|
||||
}
|
||||
if len(actions) == 0 {
|
||||
return bad("no action specified")
|
||||
}
|
||||
|
||||
select {
|
||||
case server.actionChannel <- actions:
|
||||
case <-time.After(channelTimeout):
|
||||
return httpUnavailable + crlf
|
||||
}
|
||||
return httpOk + crlf
|
||||
}
|
||||
|
||||
func parseGetParams(query string) getParams {
|
||||
params := getParams{limit: 100, offset: 0}
|
||||
for _, pair := range strings.Split(query, "&") {
|
||||
parts := strings.SplitN(pair, "=", 2)
|
||||
if len(parts) == 2 {
|
||||
switch parts[0] {
|
||||
case "limit", "offset":
|
||||
if val, err := strconv.Atoi(parts[1]); err == nil {
|
||||
if parts[0] == "limit" {
|
||||
params.limit = val
|
||||
} else {
|
||||
params.offset = val
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,57 @@
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/junegunn/fzf/src/tui"
|
||||
)
|
||||
|
||||
func runTmux(args []string, opts *Options) (int, error) {
|
||||
// Prepare arguments
|
||||
fzf := args[0]
|
||||
args = append([]string{"--bind=ctrl-z:ignore"}, args[1:]...)
|
||||
if opts.BorderShape == tui.BorderUndefined {
|
||||
args = append(args, "--border")
|
||||
}
|
||||
argStr := escapeSingleQuote(fzf)
|
||||
for _, arg := range args {
|
||||
argStr += " " + escapeSingleQuote(arg)
|
||||
}
|
||||
argStr += ` --no-tmux --no-height`
|
||||
|
||||
// Get current directory
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
dir = "."
|
||||
}
|
||||
|
||||
// Set tmux options for popup placement
|
||||
// C Both The centre of the terminal
|
||||
// R -x The right side of the terminal
|
||||
// P Both The bottom left of the pane
|
||||
// M Both The mouse position
|
||||
// W Both The window position on the status line
|
||||
// S -y The line above or below the status line
|
||||
tmuxArgs := []string{"display-popup", "-E", "-B", "-d", dir}
|
||||
switch opts.Tmux.position {
|
||||
case posUp:
|
||||
tmuxArgs = append(tmuxArgs, "-xC", "-y0")
|
||||
case posDown:
|
||||
tmuxArgs = append(tmuxArgs, "-xC", "-yS")
|
||||
case posLeft:
|
||||
tmuxArgs = append(tmuxArgs, "-x0", "-yC")
|
||||
case posRight:
|
||||
tmuxArgs = append(tmuxArgs, "-xR", "-yC")
|
||||
case posCenter:
|
||||
tmuxArgs = append(tmuxArgs, "-xC", "-yC")
|
||||
}
|
||||
tmuxArgs = append(tmuxArgs, "-w"+opts.Tmux.width.String())
|
||||
tmuxArgs = append(tmuxArgs, "-h"+opts.Tmux.height.String())
|
||||
|
||||
return runProxy(argStr, func(temp string) *exec.Cmd {
|
||||
sh, _ := sh()
|
||||
tmuxArgs = append(tmuxArgs, sh, temp)
|
||||
return exec.Command("tmux", tmuxArgs...)
|
||||
}, opts, true)
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
// Code generated by "stringer -type=EventType"; DO NOT EDIT.
|
||||
|
||||
package tui
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Rune-0]
|
||||
_ = x[CtrlA-1]
|
||||
_ = x[CtrlB-2]
|
||||
_ = x[CtrlC-3]
|
||||
_ = x[CtrlD-4]
|
||||
_ = x[CtrlE-5]
|
||||
_ = x[CtrlF-6]
|
||||
_ = x[CtrlG-7]
|
||||
_ = x[CtrlH-8]
|
||||
_ = x[Tab-9]
|
||||
_ = x[CtrlJ-10]
|
||||
_ = x[CtrlK-11]
|
||||
_ = x[CtrlL-12]
|
||||
_ = x[CtrlM-13]
|
||||
_ = x[CtrlN-14]
|
||||
_ = x[CtrlO-15]
|
||||
_ = x[CtrlP-16]
|
||||
_ = x[CtrlQ-17]
|
||||
_ = x[CtrlR-18]
|
||||
_ = x[CtrlS-19]
|
||||
_ = x[CtrlT-20]
|
||||
_ = x[CtrlU-21]
|
||||
_ = x[CtrlV-22]
|
||||
_ = x[CtrlW-23]
|
||||
_ = x[CtrlX-24]
|
||||
_ = x[CtrlY-25]
|
||||
_ = x[CtrlZ-26]
|
||||
_ = x[Esc-27]
|
||||
_ = x[CtrlSpace-28]
|
||||
_ = x[CtrlDelete-29]
|
||||
_ = x[CtrlBackSlash-30]
|
||||
_ = x[CtrlRightBracket-31]
|
||||
_ = x[CtrlCaret-32]
|
||||
_ = x[CtrlSlash-33]
|
||||
_ = x[ShiftTab-34]
|
||||
_ = x[Backspace-35]
|
||||
_ = x[Delete-36]
|
||||
_ = x[PageUp-37]
|
||||
_ = x[PageDown-38]
|
||||
_ = x[Up-39]
|
||||
_ = x[Down-40]
|
||||
_ = x[Left-41]
|
||||
_ = x[Right-42]
|
||||
_ = x[Home-43]
|
||||
_ = x[End-44]
|
||||
_ = x[Insert-45]
|
||||
_ = x[ShiftUp-46]
|
||||
_ = x[ShiftDown-47]
|
||||
_ = x[ShiftLeft-48]
|
||||
_ = x[ShiftRight-49]
|
||||
_ = x[ShiftDelete-50]
|
||||
_ = x[F1-51]
|
||||
_ = x[F2-52]
|
||||
_ = x[F3-53]
|
||||
_ = x[F4-54]
|
||||
_ = x[F5-55]
|
||||
_ = x[F6-56]
|
||||
_ = x[F7-57]
|
||||
_ = x[F8-58]
|
||||
_ = x[F9-59]
|
||||
_ = x[F10-60]
|
||||
_ = x[F11-61]
|
||||
_ = x[F12-62]
|
||||
_ = x[AltBackspace-63]
|
||||
_ = x[AltUp-64]
|
||||
_ = x[AltDown-65]
|
||||
_ = x[AltLeft-66]
|
||||
_ = x[AltRight-67]
|
||||
_ = x[AltShiftUp-68]
|
||||
_ = x[AltShiftDown-69]
|
||||
_ = x[AltShiftLeft-70]
|
||||
_ = x[AltShiftRight-71]
|
||||
_ = x[Alt-72]
|
||||
_ = x[CtrlAlt-73]
|
||||
_ = x[Invalid-74]
|
||||
_ = x[Fatal-75]
|
||||
_ = x[Mouse-76]
|
||||
_ = x[DoubleClick-77]
|
||||
_ = x[LeftClick-78]
|
||||
_ = x[RightClick-79]
|
||||
_ = x[SLeftClick-80]
|
||||
_ = x[SRightClick-81]
|
||||
_ = x[ScrollUp-82]
|
||||
_ = x[ScrollDown-83]
|
||||
_ = x[SScrollUp-84]
|
||||
_ = x[SScrollDown-85]
|
||||
_ = x[PreviewScrollUp-86]
|
||||
_ = x[PreviewScrollDown-87]
|
||||
_ = x[Resize-88]
|
||||
_ = x[Change-89]
|
||||
_ = x[BackwardEOF-90]
|
||||
_ = x[Start-91]
|
||||
_ = x[Load-92]
|
||||
_ = x[Focus-93]
|
||||
_ = x[One-94]
|
||||
_ = x[Zero-95]
|
||||
_ = x[Result-96]
|
||||
_ = x[Jump-97]
|
||||
_ = x[JumpCancel-98]
|
||||
_ = x[ClickHeader-99]
|
||||
}
|
||||
|
||||
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLCtrlMCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidFatalMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeader"
|
||||
|
||||
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 452, 463, 472, 482, 492, 503, 511, 521, 530, 541, 556, 573, 579, 585, 596, 601, 605, 610, 613, 617, 623, 627, 637, 648}
|
||||
|
||||
func (i EventType) String() string {
|
||||
if i < 0 || i >= EventType(len(_EventType_index)-1) {
|
||||
return "EventType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _EventType_name[_EventType_index[i]:_EventType_index[i+1]]
|
||||
}
|
@ -0,0 +1,395 @@
|
||||
//go:build tcell || windows
|
||||
|
||||
package tui
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
func assert(t *testing.T, context string, got interface{}, want interface{}) bool {
|
||||
if got == want {
|
||||
return true
|
||||
} else {
|
||||
t.Errorf("%s = (%T)%v, want (%T)%v", context, got, got, want, want)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Test the handling of the tcell keyboard events.
|
||||
func TestGetCharEventKey(t *testing.T) {
|
||||
if util.IsTty(os.Stdout) {
|
||||
// This test is skipped when output goes to terminal, because it causes
|
||||
// some glitches:
|
||||
// - output lines may not start at the beginning of a row which makes
|
||||
// the output unreadable
|
||||
// - terminal may get cleared which prevents you from seeing results of
|
||||
// previous tests
|
||||
// Good ways to prevent the glitches are piping the output to a pager
|
||||
// or redirecting to a file. I've found `less +G` to be trouble-free.
|
||||
t.Skip("Skipped because this test misbehaves in terminal, pipe to a pager or redirect output to a file to run it safely.")
|
||||
} else if testing.Verbose() {
|
||||
// I have observed a behaviour when this test outputted more than 8192
|
||||
// bytes (32*256) into the 'less' pager, both the go's test executable
|
||||
// and the pager hanged. The go's executable was blocking on printing.
|
||||
// I was able to create minimal working example of that behaviour, but
|
||||
// that example hanged after 12256 bytes (32*(256+127)).
|
||||
t.Log("If you are piping this test to a pager and it hangs, make the pager greedy for input, e.g. 'less +G'.")
|
||||
}
|
||||
|
||||
if !HasFullscreenRenderer() {
|
||||
t.Skip("Can't test FullscreenRenderer.")
|
||||
}
|
||||
|
||||
// construct test cases
|
||||
type giveKey struct {
|
||||
Type tcell.Key
|
||||
Char rune
|
||||
Mods tcell.ModMask
|
||||
}
|
||||
type wantKey = Event
|
||||
type testCase struct {
|
||||
giveKey
|
||||
wantKey
|
||||
}
|
||||
/*
|
||||
Some test cases are marked "fabricated". It means that giveKey value
|
||||
is valid, but it is not what you get when you press the keys. For
|
||||
example Ctrl+C will NOT give you tcell.KeyCtrlC, but tcell.KeyETX
|
||||
(End-Of-Text character, causing SIGINT).
|
||||
I was trying to accompany the fabricated test cases with real ones.
|
||||
|
||||
Some test cases are marked "unhandled". It means that giveKey.Type
|
||||
is not present in tcell.go source code. It can still be handled via
|
||||
implicit or explicit alias.
|
||||
|
||||
If not said otherwise, test cases are for US keyboard.
|
||||
|
||||
(tabstop=44)
|
||||
*/
|
||||
tests := []testCase{
|
||||
|
||||
// section 1: Ctrl+(Alt)+[a-z]
|
||||
{giveKey{tcell.KeyCtrlA, rune(tcell.KeyCtrlA), tcell.ModCtrl}, wantKey{CtrlA, 0, nil}},
|
||||
{giveKey{tcell.KeyCtrlC, rune(tcell.KeyCtrlC), tcell.ModCtrl}, wantKey{CtrlC, 0, nil}}, // fabricated
|
||||
{giveKey{tcell.KeyETX, rune(tcell.KeyETX), tcell.ModCtrl}, wantKey{CtrlC, 0, nil}}, // this is SIGINT (Ctrl+C)
|
||||
{giveKey{tcell.KeyCtrlZ, rune(tcell.KeyCtrlZ), tcell.ModCtrl}, wantKey{CtrlZ, 0, nil}}, // fabricated
|
||||
// KeyTab is alias for KeyTAB
|
||||
{giveKey{tcell.KeyCtrlI, rune(tcell.KeyCtrlI), tcell.ModCtrl}, wantKey{Tab, 0, nil}}, // fabricated
|
||||
{giveKey{tcell.KeyTab, rune(tcell.KeyTab), tcell.ModNone}, wantKey{Tab, 0, nil}}, // unhandled, actual "Tab" keystroke
|
||||
{giveKey{tcell.KeyTAB, rune(tcell.KeyTAB), tcell.ModNone}, wantKey{Tab, 0, nil}}, // fabricated, unhandled
|
||||
// KeyEnter is alias for KeyCR
|
||||
{giveKey{tcell.KeyCtrlM, rune(tcell.KeyCtrlM), tcell.ModNone}, wantKey{CtrlM, 0, nil}}, // actual "Enter" keystroke
|
||||
{giveKey{tcell.KeyCR, rune(tcell.KeyCR), tcell.ModNone}, wantKey{CtrlM, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone}, wantKey{CtrlM, 0, nil}}, // fabricated, unhandled
|
||||
// Ctrl+Alt keys
|
||||
{giveKey{tcell.KeyCtrlA, rune(tcell.KeyCtrlA), tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAlt, 'a', nil}}, // fabricated
|
||||
{giveKey{tcell.KeyCtrlA, rune(tcell.KeyCtrlA), tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAlt, 'a', nil}}, // fabricated
|
||||
|
||||
// section 2: Ctrl+[ \]_]
|
||||
{giveKey{tcell.KeyCtrlSpace, rune(tcell.KeyCtrlSpace), tcell.ModCtrl}, wantKey{CtrlSpace, 0, nil}}, // fabricated
|
||||
{giveKey{tcell.KeyNUL, rune(tcell.KeyNUL), tcell.ModNone}, wantKey{CtrlSpace, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyRune, ' ', tcell.ModCtrl}, wantKey{CtrlSpace, 0, nil}}, // actual Ctrl+' '
|
||||
{giveKey{tcell.KeyCtrlBackslash, rune(tcell.KeyCtrlBackslash), tcell.ModCtrl}, wantKey{CtrlBackSlash, 0, nil}},
|
||||
{giveKey{tcell.KeyCtrlRightSq, rune(tcell.KeyCtrlRightSq), tcell.ModCtrl}, wantKey{CtrlRightBracket, 0, nil}},
|
||||
{giveKey{tcell.KeyCtrlCarat, rune(tcell.KeyCtrlCarat), tcell.ModShift | tcell.ModCtrl}, wantKey{CtrlCaret, 0, nil}}, // fabricated
|
||||
{giveKey{tcell.KeyRS, rune(tcell.KeyRS), tcell.ModShift | tcell.ModCtrl}, wantKey{CtrlCaret, 0, nil}}, // actual Ctrl+Shift+6 (i.e. Ctrl+^) keystroke
|
||||
{giveKey{tcell.KeyCtrlUnderscore, rune(tcell.KeyCtrlUnderscore), tcell.ModShift | tcell.ModCtrl}, wantKey{CtrlSlash, 0, nil}},
|
||||
|
||||
// section 3: (Alt)+Backspace2
|
||||
// KeyBackspace2 is alias for KeyDEL = 0x7F (ASCII) (allegedly unused by Windows)
|
||||
// KeyDelete = 0x2E (VK_DELETE constant in Windows)
|
||||
// KeyBackspace is alias for KeyBS = 0x08 (ASCII) (implicit alias with KeyCtrlH)
|
||||
{giveKey{tcell.KeyBackspace2, 0, tcell.ModNone}, wantKey{Backspace, 0, nil}}, // fabricated
|
||||
{giveKey{tcell.KeyBackspace2, 0, tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // fabricated
|
||||
{giveKey{tcell.KeyDEL, 0, tcell.ModNone}, wantKey{Backspace, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyDelete, 0, tcell.ModNone}, wantKey{Delete, 0, nil}},
|
||||
{giveKey{tcell.KeyDelete, 0, tcell.ModAlt}, wantKey{Delete, 0, nil}},
|
||||
{giveKey{tcell.KeyBackspace, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyBS, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyCtrlH, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModNone}, wantKey{Backspace, 0, nil}}, // actual "Backspace" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Alt+Backspace" keystroke
|
||||
{giveKey{tcell.KeyDEL, rune(tcell.KeyDEL), tcell.ModCtrl}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Backspace" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Shift+Backspace" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Alt+Backspace" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Shift+Backspace" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift | tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Shift+Alt+Backspace" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Shift+Alt+Backspace" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+H" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAlt, 'h', nil}}, // fabricated "Ctrl+Alt+H" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+Shift+H" keystroke
|
||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAlt, 'h', nil}}, // fabricated "Ctrl+Shift+Alt+H" keystroke
|
||||
|
||||
// section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
|
||||
{giveKey{tcell.KeyUp, 0, tcell.ModNone}, wantKey{Up, 0, nil}},
|
||||
{giveKey{tcell.KeyDown, 0, tcell.ModAlt}, wantKey{AltDown, 0, nil}},
|
||||
{giveKey{tcell.KeyLeft, 0, tcell.ModShift}, wantKey{ShiftLeft, 0, nil}},
|
||||
{giveKey{tcell.KeyRight, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftRight, 0, nil}},
|
||||
{giveKey{tcell.KeyUpLeft, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyUpRight, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyDownLeft, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyDownRight, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyCenter, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
// section 5: (Insert|Home|Delete|End|PgUp|PgDn|BackTab|F1-F12)
|
||||
{giveKey{tcell.KeyInsert, 0, tcell.ModNone}, wantKey{Insert, 0, nil}},
|
||||
{giveKey{tcell.KeyF1, 0, tcell.ModNone}, wantKey{F1, 0, nil}},
|
||||
// section 6: (Ctrl+Alt)+'rune'
|
||||
{giveKey{tcell.KeyRune, 'a', tcell.ModNone}, wantKey{Rune, 'a', nil}},
|
||||
{giveKey{tcell.KeyRune, 'a', tcell.ModCtrl}, wantKey{Rune, 'a', nil}}, // fabricated
|
||||
{giveKey{tcell.KeyRune, 'a', tcell.ModAlt}, wantKey{Alt, 'a', nil}},
|
||||
{giveKey{tcell.KeyRune, 'A', tcell.ModAlt}, wantKey{Alt, 'A', nil}},
|
||||
{giveKey{tcell.KeyRune, '`', tcell.ModAlt}, wantKey{Alt, '`', nil}},
|
||||
/*
|
||||
"Input method" in Windows Language options:
|
||||
US: "US Keyboard" does not generate any characters (and thus any events) in Ctrl+Alt+[a-z] range
|
||||
CS: "Czech keyboard"
|
||||
DE: "German keyboard"
|
||||
|
||||
Note that right Alt is not just `tcell.ModAlt` on foreign language keyboards, but it is the AltGr `tcell.ModCtrl|tcell.ModAlt`.
|
||||
*/
|
||||
{giveKey{tcell.KeyRune, '{', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '{', nil}}, // CS: Ctrl+Alt+b = "{" // Note that this does not interfere with CtrlB, since the "b" is replaced with "{" on OS level
|
||||
{giveKey{tcell.KeyRune, '$', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '$', nil}}, // CS: Ctrl+Alt+ů = "$"
|
||||
{giveKey{tcell.KeyRune, '~', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '~', nil}}, // CS: Ctrl+Alt++ = "~"
|
||||
{giveKey{tcell.KeyRune, '`', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '`', nil}}, // CS: Ctrl+Alt+ý,Space = "`" // this is dead key, space is required to emit the char
|
||||
|
||||
{giveKey{tcell.KeyRune, '{', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '{', nil}}, // DE: Ctrl+Alt+7 = "{"
|
||||
{giveKey{tcell.KeyRune, '@', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '@', nil}}, // DE: Ctrl+Alt+q = "@"
|
||||
{giveKey{tcell.KeyRune, 'µ', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, 'µ', nil}}, // DE: Ctrl+Alt+m = "µ"
|
||||
|
||||
// section 7: Esc
|
||||
// KeyEsc and KeyEscape are aliases for KeyESC
|
||||
{giveKey{tcell.KeyEsc, rune(tcell.KeyEsc), tcell.ModNone}, wantKey{Esc, 0, nil}}, // fabricated
|
||||
{giveKey{tcell.KeyESC, rune(tcell.KeyESC), tcell.ModNone}, wantKey{Esc, 0, nil}}, // unhandled
|
||||
{giveKey{tcell.KeyEscape, rune(tcell.KeyEscape), tcell.ModNone}, wantKey{Esc, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyESC, rune(tcell.KeyESC), tcell.ModCtrl}, wantKey{Esc, 0, nil}}, // actual Ctrl+[ keystroke
|
||||
{giveKey{tcell.KeyCtrlLeftSq, rune(tcell.KeyCtrlLeftSq), tcell.ModCtrl}, wantKey{Esc, 0, nil}}, // fabricated, unhandled
|
||||
|
||||
// section 8: Invalid
|
||||
{giveKey{tcell.KeyRune, 'a', tcell.ModMeta}, wantKey{Rune, 'a', nil}}, // fabricated
|
||||
{giveKey{tcell.KeyF24, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}},
|
||||
{giveKey{tcell.KeyHelp, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyExit, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyClear, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // unhandled, actual keystroke Numpad_5 with Numlock OFF
|
||||
{giveKey{tcell.KeyCancel, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyPrint, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||
{giveKey{tcell.KeyPause, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // unhandled
|
||||
|
||||
}
|
||||
r := NewFullscreenRenderer(&ColorTheme{}, false, false)
|
||||
r.Init()
|
||||
|
||||
// run and evaluate the tests
|
||||
initialResizeAsInvalid := true
|
||||
for _, test := range tests {
|
||||
// generate key event
|
||||
giveEvent := tcell.NewEventKey(test.giveKey.Type, test.giveKey.Char, test.giveKey.Mods)
|
||||
_screen.PostEventWait(giveEvent)
|
||||
t.Logf("giveEvent = %T{key: %v, ch: %q (%[3]v), mod: %#04b}\n", giveEvent, giveEvent.Key(), giveEvent.Rune(), giveEvent.Modifiers())
|
||||
|
||||
// process the event in fzf and evaluate the test
|
||||
gotEvent := r.GetChar()
|
||||
// skip Resize events, those are sometimes put in the buffer outside of this test
|
||||
if initialResizeAsInvalid && gotEvent.Type == Invalid {
|
||||
t.Logf("Resize as Invalid swallowed")
|
||||
initialResizeAsInvalid = false
|
||||
gotEvent = r.GetChar()
|
||||
}
|
||||
t.Logf("wantEvent = %T{Type: %v, Char: %q (%[3]v)}\n", test.wantKey, test.wantKey.Type, test.wantKey.Char)
|
||||
t.Logf("gotEvent = %T{Type: %v, Char: %q (%[3]v)}\n", gotEvent, gotEvent.Type, gotEvent.Char)
|
||||
|
||||
assert(t, "r.GetChar().Type", gotEvent.Type, test.wantKey.Type)
|
||||
assert(t, "r.GetChar().Char", gotEvent.Char, test.wantKey.Char)
|
||||
}
|
||||
|
||||
r.Close()
|
||||
}
|
||||
|
||||
/*
|
||||
Quick reference
|
||||
---------------
|
||||
|
||||
(tabstop=18)
|
||||
(this is not mapping table, it merely puts multiple constants ranges in one table)
|
||||
|
||||
¹) the two columns are each other implicit alias
|
||||
²) explicit aliases here
|
||||
|
||||
%v section # tcell ctrl key¹ tcell ctrl char¹ tcell alias² tui constants tcell named keys tcell mods
|
||||
-- --------- -------------- --------------- ----------- ------------- ---------------- ----------
|
||||
0 2 KeyCtrlSpace KeyNUL = ^@ Rune ModNone
|
||||
1 1 KeyCtrlA KeySOH = ^A CtrlA ModShift
|
||||
2 1 KeyCtrlB KeySTX = ^B CtrlB ModCtrl
|
||||
3 1 KeyCtrlC KeyETX = ^C CtrlC
|
||||
4 1 KeyCtrlD KeyEOT = ^D CtrlD ModAlt
|
||||
5 1 KeyCtrlE KeyENQ = ^E CtrlE
|
||||
6 1 KeyCtrlF KeyACK = ^F CtrlF
|
||||
7 1 KeyCtrlG KeyBEL = ^G CtrlG
|
||||
8 1 KeyCtrlH KeyBS = ^H KeyBackspace CtrlH ModMeta
|
||||
9 1 KeyCtrlI KeyTAB = ^I KeyTab Tab
|
||||
10 1 KeyCtrlJ KeyLF = ^J CtrlJ
|
||||
11 1 KeyCtrlK KeyVT = ^K CtrlK
|
||||
12 1 KeyCtrlL KeyFF = ^L CtrlL
|
||||
13 1 KeyCtrlM KeyCR = ^M KeyEnter CtrlM
|
||||
14 1 KeyCtrlN KeySO = ^N CtrlN
|
||||
15 1 KeyCtrlO KeySI = ^O CtrlO
|
||||
16 1 KeyCtrlP KeyDLE = ^P CtrlP
|
||||
17 1 KeyCtrlQ KeyDC1 = ^Q CtrlQ
|
||||
18 1 KeyCtrlR KeyDC2 = ^R CtrlR
|
||||
19 1 KeyCtrlS KeyDC3 = ^S CtrlS
|
||||
20 1 KeyCtrlT KeyDC4 = ^T CtrlT
|
||||
21 1 KeyCtrlU KeyNAK = ^U CtrlU
|
||||
22 1 KeyCtrlV KeySYN = ^V CtrlV
|
||||
23 1 KeyCtrlW KeyETB = ^W CtrlW
|
||||
24 1 KeyCtrlX KeyCAN = ^X CtrlX
|
||||
25 1 KeyCtrlY KeyEM = ^Y CtrlY
|
||||
26 1 KeyCtrlZ KeySUB = ^Z CtrlZ
|
||||
27 7 KeyCtrlLeftSq KeyESC = ^[ KeyEsc, KeyEscape ESC
|
||||
28 2 KeyCtrlBackslash KeyFS = ^\ CtrlSpace
|
||||
29 2 KeyCtrlRightSq KeyGS = ^] CtrlBackSlash
|
||||
30 2 KeyCtrlCarat KeyRS = ^^ CtrlRightBracket
|
||||
31 2 KeyCtrlUnderscore KeyUS = ^_ CtrlCaret
|
||||
32 CtrlSlash
|
||||
33 Invalid
|
||||
34 Resize
|
||||
35 Mouse
|
||||
36 DoubleClick
|
||||
37 LeftClick
|
||||
38 RightClick
|
||||
39 BTab
|
||||
40 Backspace
|
||||
41 Del
|
||||
42 PgUp
|
||||
43 PgDn
|
||||
44 Up
|
||||
45 Down
|
||||
46 Left
|
||||
47 Right
|
||||
48 Home
|
||||
49 End
|
||||
50 Insert
|
||||
51 SUp
|
||||
52 SDown
|
||||
53 ShiftLeft
|
||||
54 SRight
|
||||
55 F1
|
||||
56 F2
|
||||
57 F3
|
||||
58 F4
|
||||
59 F5
|
||||
60 F6
|
||||
61 F7
|
||||
62 F8
|
||||
63 F9
|
||||
64 F10
|
||||
65 F11
|
||||
66 F12
|
||||
67 Change
|
||||
68 BackwardEOF
|
||||
69 AltBackspace
|
||||
70 AltUp
|
||||
71 AltDown
|
||||
72 AltLeft
|
||||
73 AltRight
|
||||
74 AltSUp
|
||||
75 AltSDown
|
||||
76 AltShiftLeft
|
||||
77 AltShiftRight
|
||||
78 Alt
|
||||
79 CtrlAlt
|
||||
..
|
||||
127 3 KeyDEL KeyBackspace2
|
||||
..
|
||||
256 6 KeyRune
|
||||
257 4 KeyUp
|
||||
258 4 KeyDown
|
||||
259 4 KeyRight
|
||||
260 4 KeyLeft
|
||||
261 8 KeyUpLeft
|
||||
262 8 KeyUpRight
|
||||
263 8 KeyDownLeft
|
||||
264 8 KeyDownRight
|
||||
265 8 KeyCenter
|
||||
266 5 KeyPgUp
|
||||
267 5 KeyPgDn
|
||||
268 5 KeyHome
|
||||
269 5 KeyEnd
|
||||
270 5 KeyInsert
|
||||
271 5 KeyDelete
|
||||
272 8 KeyHelp
|
||||
273 8 KeyExit
|
||||
274 8 KeyClear
|
||||
275 8 KeyCancel
|
||||
276 8 KeyPrint
|
||||
277 8 KeyPause
|
||||
278 5 KeyBacktab
|
||||
279 5 KeyF1
|
||||
280 5 KeyF2
|
||||
281 5 KeyF3
|
||||
282 5 KeyF4
|
||||
283 5 KeyF5
|
||||
284 5 KeyF6
|
||||
285 5 KeyF7
|
||||
286 5 KeyF8
|
||||
287 5 KeyF9
|
||||
288 5 KeyF10
|
||||
289 5 KeyF11
|
||||
290 5 KeyF12
|
||||
291 8 KeyF13
|
||||
292 8 KeyF14
|
||||
293 8 KeyF15
|
||||
294 8 KeyF16
|
||||
295 8 KeyF17
|
||||
296 8 KeyF18
|
||||
297 8 KeyF19
|
||||
298 8 KeyF20
|
||||
299 8 KeyF21
|
||||
300 8 KeyF22
|
||||
301 8 KeyF23
|
||||
302 8 KeyF24
|
||||
303 8 KeyF25
|
||||
304 8 KeyF26
|
||||
305 8 KeyF27
|
||||
306 8 KeyF28
|
||||
307 8 KeyF29
|
||||
308 8 KeyF30
|
||||
309 8 KeyF31
|
||||
310 8 KeyF32
|
||||
311 8 KeyF33
|
||||
312 8 KeyF34
|
||||
313 8 KeyF35
|
||||
314 8 KeyF36
|
||||
315 8 KeyF37
|
||||
316 8 KeyF38
|
||||
317 8 KeyF39
|
||||
318 8 KeyF40
|
||||
319 8 KeyF41
|
||||
320 8 KeyF42
|
||||
321 8 KeyF43
|
||||
322 8 KeyF44
|
||||
323 8 KeyF45
|
||||
324 8 KeyF46
|
||||
325 8 KeyF47
|
||||
326 8 KeyF48
|
||||
327 8 KeyF49
|
||||
328 8 KeyF50
|
||||
329 8 KeyF51
|
||||
330 8 KeyF52
|
||||
331 8 KeyF53
|
||||
332 8 KeyF54
|
||||
333 8 KeyF55
|
||||
334 8 KeyF56
|
||||
335 8 KeyF57
|
||||
336 8 KeyF58
|
||||
337 8 KeyF59
|
||||
338 8 KeyF60
|
||||
339 8 KeyF61
|
||||
340 8 KeyF62
|
||||
341 8 KeyF63
|
||||
342 8 KeyF64
|
||||
-- --------- -------------- --------------- ----------- ------------- ---------------- ----------
|
||||
%v section # tcell ctrl key tcell ctrl char tcell alias tui constants tcell named keys tcell mods
|
||||
*/
|
@ -1,47 +1,54 @@
|
||||
// +build !windows
|
||||
//go:build !windows
|
||||
|
||||
package tui
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var devPrefixes = [...]string{"/dev/pts/", "/dev/"}
|
||||
|
||||
var tty atomic.Value
|
||||
|
||||
func ttyname() string {
|
||||
if cached := tty.Load(); cached != nil {
|
||||
return cached.(string)
|
||||
}
|
||||
|
||||
var stderr syscall.Stat_t
|
||||
if syscall.Fstat(2, &stderr) != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, prefix := range devPrefixes {
|
||||
files, err := ioutil.ReadDir(prefix)
|
||||
files, err := os.ReadDir(prefix)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if stat, ok := file.Sys().(*syscall.Stat_t); ok && stat.Rdev == stderr.Rdev {
|
||||
return prefix + file.Name()
|
||||
info, err := file.Info()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if stat, ok := info.Sys().(*syscall.Stat_t); ok && stat.Rdev == stderr.Rdev {
|
||||
value := prefix + file.Name()
|
||||
tty.Store(value)
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// TtyIn returns terminal device to be used as STDIN, falls back to os.Stdin
|
||||
func TtyIn() *os.File {
|
||||
in, err := os.OpenFile(consoleDevice, syscall.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
tty := ttyname()
|
||||
if len(tty) > 0 {
|
||||
if in, err := os.OpenFile(tty, syscall.O_RDONLY, 0); err == nil {
|
||||
return in
|
||||
}
|
||||
}
|
||||
return os.Stdin
|
||||
}
|
||||
return in
|
||||
// TtyIn returns terminal device to read user input
|
||||
func TtyIn() (*os.File, error) {
|
||||
return openTtyIn()
|
||||
}
|
||||
|
||||
// TtyIn returns terminal device to write to
|
||||
func TtyOut() (*os.File, error) {
|
||||
return openTtyOut()
|
||||
}
|
||||
|
@ -1,14 +1,21 @@
|
||||
// +build windows
|
||||
//go:build windows
|
||||
|
||||
package tui
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func ttyname() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// TtyIn on Windows returns os.Stdin
|
||||
func TtyIn() *os.File {
|
||||
return os.Stdin
|
||||
func TtyIn() (*os.File, error) {
|
||||
return os.Stdin, nil
|
||||
}
|
||||
|
||||
// TtyIn on Windows returns nil
|
||||
func TtyOut() (*os.File, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var atExitFuncs []func()
|
||||
|
||||
// AtExit registers the function fn to be called on program termination.
|
||||
// The functions will be called in reverse order they were registered.
|
||||
func AtExit(fn func()) {
|
||||
if fn == nil {
|
||||
panic("AtExit called with nil func")
|
||||
}
|
||||
once := &sync.Once{}
|
||||
atExitFuncs = append(atExitFuncs, func() {
|
||||
once.Do(fn)
|
||||
})
|
||||
}
|
||||
|
||||
// RunAtExitFuncs runs any functions registered with AtExit().
|
||||
func RunAtExitFuncs() {
|
||||
fns := atExitFuncs
|
||||
for i := len(fns) - 1; i >= 0; i-- {
|
||||
fns[i]()
|
||||
}
|
||||
atExitFuncs = nil
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAtExit(t *testing.T) {
|
||||
want := []int{3, 2, 1, 0}
|
||||
var called []int
|
||||
for i := 0; i < 4; i++ {
|
||||
n := i
|
||||
AtExit(func() { called = append(called, n) })
|
||||
}
|
||||
RunAtExitFuncs()
|
||||
if !reflect.DeepEqual(called, want) {
|
||||
t.Errorf("AtExit: want call order: %v got: %v", want, called)
|
||||
}
|
||||
|
||||
RunAtExitFuncs()
|
||||
if !reflect.DeepEqual(called, want) {
|
||||
t.Error("AtExit: should only call exit funcs once")
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue