Compare commits
514
Commits
a4e0c04de4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7466188d35 | ||
|
|
2608a6cd72 | ||
|
|
642c981e4b | ||
|
|
451097d384 | ||
|
|
1ec69309cf | ||
|
|
27f780e733 | ||
|
|
9368a4864c | ||
|
|
6689e69ece | ||
|
|
5f55438581 | ||
|
|
0ef99e4874 | ||
|
|
df929c5335 | ||
|
|
6ef0859e43 | ||
|
|
01f4e376ae | ||
|
|
31d04a2fe0 | ||
|
|
8866236bda | ||
|
|
f7b207aaf4 | ||
|
|
1cb6f37b5b | ||
|
|
a8468f3402 | ||
|
|
040c98c0a7 | ||
|
|
3c0bba1737 | ||
|
|
489e3cc7de | ||
|
|
7ad3b90503 | ||
|
|
db21efee0c | ||
|
|
207540c093 | ||
|
|
6b2d3bf491 | ||
|
|
c3a2e35465 | ||
|
|
e02919de21 | ||
|
|
516b2ba26c | ||
|
|
a981fa7f0a | ||
|
|
760b8e68fd | ||
|
|
04fd832974 | ||
|
|
77c68558b2 | ||
|
|
0554a3dddc | ||
|
|
fbb6b6e740 | ||
|
|
2cf61b0590 | ||
|
|
d748289c11 | ||
|
|
d2e07effc1 | ||
|
|
9d6923f225 | ||
|
|
c0628dbd4c | ||
|
|
31b47ddfc5 | ||
|
|
9642cd69db | ||
|
|
7fa5ca2568 | ||
|
|
94a4fbe45f | ||
|
|
04a02d089f | ||
|
|
3ef83d1747 | ||
|
|
f865ad766d | ||
|
|
f32e0d0ce5 | ||
|
|
8a937124d3 | ||
|
|
d8feaf7143 | ||
|
|
22dcd31c05 | ||
|
|
cbce46b63f | ||
|
|
8ab69f53ed | ||
|
|
c17f6663db | ||
|
|
20adb8f75c | ||
|
|
0e63b4fbb7 | ||
|
|
adbcd1d3c0 | ||
|
|
9e037f2a08 | ||
|
|
96df21444b | ||
|
|
7875b83a94 | ||
|
|
0765a2726a | ||
|
|
80d4f5d9fa | ||
|
|
391e2b6750 | ||
|
|
fc420fad72 | ||
|
|
dfdc1063ba | ||
|
|
4ff120cc5d
|
||
|
|
7c99b475e3 | ||
|
|
262b53c6c4 | ||
|
|
0ff6be3f81 | ||
|
|
86d20105e5
|
||
|
|
6790bf1430
|
||
|
|
e76668d3b1
|
||
|
|
204b13781d
|
||
|
|
0b9cf5a928 | ||
|
|
93831564a8 | ||
|
|
82d761b026
|
||
|
|
742fd7941d
|
||
|
|
cb74cd84e2
|
||
|
|
89fdfc8e72
|
||
|
|
0e9c3b4b27
|
||
|
|
d5535a38ad
|
||
|
|
01553b71fd
|
||
|
|
ffff95f3b9
|
||
|
|
674a50ea05
|
||
|
|
a2d52e1ec2 | ||
|
|
84c6e9b79d | ||
|
|
2d84bcdf7e
|
||
|
|
935ba904bd
|
||
|
|
8b0b5ee85a | ||
|
|
a1297a417e | ||
|
|
5c54ede483
|
||
|
|
f9086bd2ca
|
||
|
|
f9dfc4ca4c | ||
|
|
a899448fda | ||
|
|
429c407548
|
||
|
|
2fb8e3718b
|
||
|
|
11097e32de
|
||
|
|
9d1acf0fb3 | ||
|
|
7d95e7854c | ||
|
|
1972ea5bb9
|
||
|
|
2b9b8e495c | ||
|
|
231162bd03
|
||
|
|
94e4e0dfab
|
||
|
|
7dca813556 | ||
|
|
0fe183c93e
|
||
|
|
dd28fc784b
|
||
|
|
7183ed712b
|
||
|
|
d91c0c8deb | ||
|
|
d2f3da4a23
|
||
|
|
0d8a2110cf | ||
|
|
7ca9d19b93
|
||
|
|
29daf01b95 | ||
|
|
4202be5d3a | ||
|
|
05db9b57d7
|
||
|
|
a690e814eb | ||
|
|
f2874bf890
|
||
|
|
d085d5c597 | ||
|
|
4a00bc5492
|
||
|
|
5b1d90c59d | ||
|
|
11a9db5fad | ||
|
|
12ee2bac89
|
||
|
|
6feaa0ea9e
|
||
|
|
7bbd705d0f
|
||
|
|
d9c8000f68
|
||
|
|
8dba8a31fe
|
||
|
|
6b484599ae | ||
|
|
6e6f276896 | ||
|
|
bbe8aaf88d
|
||
|
|
f62404c692
|
||
|
|
1192e62eaf | ||
|
|
2c624d1a28 | ||
|
|
69e59806df | ||
|
|
ba6146c343
|
||
|
|
8951644c75 | ||
|
|
e180e8d452
|
||
|
|
3155449ef6 | ||
|
|
528ce2a984
|
||
|
|
afad1c9933
|
||
|
|
ea66507c76
|
||
|
|
3e00f4e321
|
||
|
|
78f957b211 | ||
|
|
d6c37fe0ad
|
||
|
|
e63fd8b525
|
||
|
|
c770afa6c4 | ||
|
|
49e487ac3b | ||
|
|
911e656e5e
|
||
|
|
0f02def439 | ||
|
|
24cdfe4129
|
||
|
|
1b69ff9a7f | ||
|
|
0ba43b6226
|
||
|
|
b898cf1030
|
||
|
|
ce1722d97f | ||
|
|
f02714416c
|
||
|
|
cd08c0782e | ||
|
|
927d28c01a | ||
|
|
25fb02b7ac
|
||
|
|
c126296935
|
||
|
|
48e6a96c6d
|
||
|
|
a5e6efc761
|
||
|
|
ca130ff612 | ||
|
|
51f2c020d1 | ||
|
|
5b43f3bbd3
|
||
|
|
19e5225254 | ||
|
|
c2506bdf9c | ||
|
|
c4980a15b1
|
||
|
|
ddaaf35c85 | ||
|
|
7a0e1f0930 | ||
|
|
ef384b9c7c
|
||
|
|
fe59a7c22c
|
||
|
|
1c671d71ac
|
||
|
|
819a3b1541
|
||
|
|
6ac647e0c1
|
||
|
|
690bfd64d0
|
||
|
|
d972de3df5
|
||
|
|
413b8d8fa1
|
||
|
|
27b6b22f6a | ||
|
|
b6034114ad | ||
|
|
e651566e14
|
||
|
|
f6a3ba0453 | ||
|
|
cd08403416
|
||
|
|
4ca008836c
|
||
|
|
980834e961 | ||
|
|
f2f4d4ef49 | ||
|
|
05ba0a4f10
|
||
|
|
49c8191037 | ||
|
|
ab030d7ec0
|
||
|
|
4f00b5a0f4 | ||
|
|
5c21788c8f | ||
|
|
625a58fa9f
|
||
|
|
e20cff41d4
|
||
|
|
5c24d2c72d | ||
|
|
92bcc49962 | ||
|
|
4197e7faec
|
||
|
|
daf81bf0a4
|
||
|
|
cbd5faa66c
|
||
|
|
a65e05b661
|
||
|
|
00f70e8558
|
||
|
|
8d6ca1797a
|
||
|
|
02c46ebea7
|
||
|
|
5f4306b6ca
|
||
|
|
4c51ef7a33
|
||
|
|
67fb29687c
|
||
|
|
b4a58af23c | ||
|
|
073dbd9b14
|
||
|
|
6cd0de7ccf
|
||
|
|
d23cbfc733 | ||
|
|
1bfcd519b8 | ||
|
|
e684eb6134
|
||
|
|
ab2f03213b
|
||
|
|
16e969ee15
|
||
|
|
936f13f712
|
||
|
|
3bb534f20b
|
||
|
|
a4054de4f6
|
||
|
|
c096433b5d
|
||
|
|
36a03202c6
|
||
|
|
e4ef26fe03
|
||
|
|
424a3c76ab
|
||
|
|
beb89e406a
|
||
|
|
63e71ac9dd
|
||
|
|
61a82540fb
|
||
|
|
3ccc5d2210
|
||
|
|
efa86e8eda
|
||
|
|
83e8c52298 | ||
|
|
f674ae303c | ||
|
|
29b69c7b03
|
||
|
|
8c869cc1b9 | ||
|
|
fcc2f6ccc2 | ||
|
|
38bce499bd
|
||
|
|
f3533835be
|
||
|
|
68eb3b0092 | ||
|
|
3362c33339 | ||
|
|
ec47b0671c
|
||
|
|
8495cbaa24
|
||
|
|
fe3eb818ba | ||
|
|
5930514847 | ||
|
|
8068dcb312 | ||
|
|
7afb470a42
|
||
|
|
4761c48d96
|
||
|
|
0a83bd425c | ||
|
|
83d5bd2d40 | ||
|
|
de349a423e
|
||
|
|
0250669306
|
||
|
|
7caf75b940
|
||
|
|
453b5f1d50
|
||
|
|
5cf5ca07c5
|
||
|
|
fbfc52e675
|
||
|
|
b791010e48
|
||
|
|
c6c13c2e99
|
||
|
|
b82166872f
|
||
|
|
ec99ceb018
|
||
|
|
a422400d72
|
||
|
|
2772b26704
|
||
|
|
180ea9337f
|
||
|
|
72920c04ce
|
||
|
|
614c064524 | ||
|
|
5ee09bf13e | ||
|
|
390072e919
|
||
|
|
cd240f4460 | ||
|
|
f6fd093850 | ||
|
|
67f22c8a60
|
||
|
|
6f8fd855e4
|
||
|
|
93829285d8
|
||
|
|
533ab60321
|
||
|
|
43b3cf51f6
|
||
|
|
26b90ecc72
|
||
|
|
b506f2aa39
|
||
|
|
7a1a213add
|
||
|
|
98a5cb4c7c
|
||
|
|
93554695dc
|
||
|
|
8852ed3108 | ||
|
|
47487ddcc0 | ||
|
|
2a5aef2a64
|
||
|
|
bdf4581b28 | ||
|
|
f92ac6ac37
|
||
|
|
cb30f19c32
|
||
|
|
4a5536aeb6
|
||
|
|
5103ddc43d | ||
|
|
29637799f6 | ||
|
|
ec1f00320b
|
||
|
|
878bc360d9
|
||
|
|
6bd6436c81
|
||
|
|
a76e4de605 | ||
|
|
cf8dc8d7e1 | ||
|
|
d3851fcddc
|
||
|
|
261e663e97
|
||
|
|
83abb5b6c6 | ||
|
|
1433844c2b | ||
|
|
034ebade0d
|
||
|
|
8dfbc2a9be | ||
|
|
ed8de40d46
|
||
|
|
d87582253c | ||
|
|
7079319a09
|
||
|
|
3fcc8a3ab5 | ||
|
|
fdd0733b3f | ||
|
|
c3e39b7a96
|
||
|
|
c7d1e642e5
|
||
|
|
3bdc712fa9 | ||
|
|
b81cbd3b02 | ||
|
|
7474760525
|
||
|
|
70f1ec2eeb
|
||
|
|
46dd6cd3a9
|
||
|
|
58e21eba95
|
||
|
|
5cbb01497c
|
||
|
|
7d277e52bd | ||
|
|
dda63a05ff | ||
|
|
399f481adb | ||
|
|
6a6eff2d00 | ||
|
|
a9190cf7ec
|
||
|
|
0c7f7df4ec | ||
|
|
70b4492986 | ||
|
|
1aac43af62
|
||
|
|
68a9cd17bf
|
||
|
|
7564604c53
|
||
|
|
548df81c08 | ||
|
|
b4bac6a562 | ||
|
|
2ff553f7b6
|
||
|
|
914613c751
|
||
|
|
78df24cba1
|
||
|
|
4f266f691b
|
||
|
|
ca0a35e8c7
|
||
|
|
c2ec031af2
|
||
|
|
3990bd13b4 | ||
|
|
429ccc3876 | ||
|
|
a7e6ae4d21
|
||
|
|
5b74fbe427
|
||
|
|
b998cc652e
|
||
|
|
2e1750b5a4
|
||
|
|
764f2253f6
|
||
|
|
2e6abec499
|
||
|
|
5c3d169572 | ||
|
|
50e4d92249 | ||
|
|
a5966fd982
|
||
|
|
976f46757c
|
||
|
|
2a7cb0f5cb
|
||
|
|
8f845f7cf2
|
||
|
|
69384f6427
|
||
|
|
9f9248deb1
|
||
|
|
3a054021cf
|
||
|
|
015daec928
|
||
|
|
d68bedef95
|
||
|
|
e96f874469
|
||
|
|
178214c812
|
||
|
|
45cba3a15b
|
||
|
|
11dc584104
|
||
|
|
0167370823
|
||
|
|
8d0f425b10
|
||
|
|
a483c30c05
|
||
|
|
3befc07887
|
||
|
|
2a9a7ed2ff
|
||
|
|
d1949953df
|
||
|
|
7463d894f2
|
||
|
|
1e1c2003f3
|
||
|
|
e6de825fb1
|
||
|
|
b6ed77d8f9
|
||
|
|
522fd03c12
|
||
|
|
d68f68bec7 | ||
|
|
a92847e6ed | ||
|
|
682e93c794
|
||
|
|
953aafd055
|
||
|
|
39688b28f4 | ||
|
|
654503062b
|
||
|
|
9d2a498089 | ||
|
|
64c559dbab | ||
|
|
93fc5e0517
|
||
|
|
1253f67c9c | ||
|
|
045f141e30 | ||
|
|
f76a45e273
|
||
|
|
95f2ad9112 | ||
|
|
4210f3b445
|
||
|
|
8b9bd248fd | ||
|
|
b323fedf49 | ||
|
|
4f8c45c4ef
|
||
|
|
16394da0d9
|
||
|
|
7527f01a2b
|
||
|
|
0670fbbdad
|
||
|
|
b5513ccbde
|
||
|
|
4c77f3b0af
|
||
|
|
eb828a09d5
|
||
|
|
ab284641a5
|
||
|
|
fefcb9034b
|
||
|
|
e90cdeb259 | ||
|
|
3eec6c3f89 | ||
|
|
36a303f7d4
|
||
|
|
5c224694ec
|
||
|
|
bc0b67a498
|
||
|
|
a3b60718de
|
||
|
|
7744f4f569 | ||
|
|
4eea14576c | ||
|
|
681a48f3c5
|
||
|
|
965d72230c | ||
|
|
71aa38c7ca | ||
|
|
499bf672f8
|
||
|
|
477a4ab265
|
||
|
|
bd0eac8413
|
||
|
|
fc63b4f1b0
|
||
|
|
0cbb7c6892
|
||
|
|
35e86dcd6e
|
||
|
|
4bfea67cc5
|
||
|
|
85a7889c5c | ||
|
|
97f783e9a8 | ||
|
|
764a9d35e5
|
||
|
|
cfd4749e72
|
||
|
|
bddb068ec0
|
||
|
|
608b0227cb
|
||
|
|
5a018fe975
|
||
|
|
cc14f7fb3d
|
||
|
|
bff084db07
|
||
|
|
f75d64bf9c
|
||
|
|
43fd36f5ea
|
||
|
|
9a820fc3e6
|
||
|
|
d20f7f8d7b
|
||
|
|
a4f6ee26cb
|
||
|
|
c9174f9d4a
|
||
|
|
c372c96dd7
|
||
|
|
aa8e4437ec
|
||
|
|
87960cc8cc
|
||
|
|
a9d1d6ac4d | ||
|
|
fc17c9fd61 | ||
|
|
780bda7ab7
|
||
|
|
e4bcbd3da2 | ||
|
|
4bef8f9c91 | ||
|
|
e776e7fba6
|
||
|
|
a170d82086
|
||
|
|
c04c1a4bc2
|
||
|
|
4c989a45c1
|
||
|
|
cccef17031
|
||
|
|
b0debaa421 | ||
|
|
6edeb5bdd1 | ||
|
|
b64e7d4f3c
|
||
|
|
251f512806
|
||
|
|
43135aef02
|
||
|
|
c909a4f054
|
||
|
|
5394a6d494
|
||
|
|
c9ac952553
|
||
|
|
85be47582b
|
||
|
|
8de2cf229b | ||
|
|
0cced863f8 | ||
|
|
7fcf268fc7
|
||
|
|
76349ad94b
|
||
|
|
eb1b780a80
|
||
|
|
2ce41d0c55
|
||
|
|
e30ccbc633
|
||
|
|
7e266cb61a
|
||
|
|
be3dd7494e
|
||
|
|
0382d6ab9c
|
||
|
|
f17229d0b8
|
||
|
|
621d67e89e
|
||
|
|
f9ba0e20ea | ||
|
|
6d15701ad4 | ||
|
|
e30fc7a15c
|
||
|
|
7bd080769e
|
||
|
|
dc97892a29
|
||
|
|
ce84db593c
|
||
|
|
cdf850f2e7
|
||
|
|
c5d6e35afc
|
||
|
|
17dcc99fc2 | ||
|
|
831c7beb4d
|
||
|
|
f4157fb4ba | ||
|
|
79f8445e25
|
||
|
|
e86b537f6d | ||
|
|
23e2f43447
|
||
|
|
32630443a8 | ||
|
|
21126012dc | ||
|
|
13eb93ce12
|
||
|
|
8911146d3f
|
||
|
|
1637dc3122
|
||
|
|
bceff8f4ec
|
||
|
|
d21aa4ed4b
|
||
|
|
43123ff390
|
||
|
|
8e7e450a9d
|
||
|
|
d53237f53c
|
||
|
|
8ad10c41d7 | ||
|
|
2f199066f8
|
||
|
|
f444bfa464
|
||
|
|
345d0086a5
|
||
|
|
8e32196a79
|
||
|
|
38bdc3df65 | ||
|
|
21437d1881
|
||
|
|
fe6670f188
|
||
|
|
27fd6e4e05 | ||
|
|
9cb9fff5ce
|
||
|
|
a9ce4b9ada
|
||
|
|
5e1fa470cb | ||
|
|
bf2ad2f1e7 | ||
|
|
de07040c16
|
||
|
|
9795164eda
|
||
|
|
c098498f0c
|
||
|
|
8ea448adb8
|
||
|
|
8541ef2658
|
||
|
|
761ac9eb1b
|
||
|
|
9779dcc8ec
|
||
|
|
ea1aa20ac7 | ||
|
|
b6aa81f3b1
|
||
|
|
91ee993302
|
||
|
|
97b65c56a8 | ||
|
|
9959bd4dc6 | ||
|
|
278ceb2c06
|
||
|
|
945b8ddabf
|
||
|
|
bc8339895a
|
||
|
|
c9d360809d
|
||
|
|
e2738f2ab4
|
||
|
|
d4f99a79fe
|
||
|
|
b03ec287b2
|
||
|
|
0959d82018 | ||
|
|
fe1ef6f2ee | ||
|
|
569d17a342
|
||
|
|
cf56f58dcd | ||
|
|
4117b0ddb6
|
||
|
|
b2dd199e2f | ||
|
|
7359c12e79
|
||
|
|
c9a5577c11
|
||
|
|
329dae0f08
|
||
|
|
dbddc4c1de | ||
|
|
103f99b9f7 | ||
|
|
ba92267a80
|
@@ -1,45 +0,0 @@
|
||||
name: Offline docs drift reminder
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'README.md'
|
||||
|
||||
jobs:
|
||||
remind:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Check whether offline doc changed in same push
|
||||
id: drift
|
||||
run: |
|
||||
if git diff --name-only HEAD~1 HEAD | grep -q '^docs/fish-config\.md$'; then
|
||||
echo "synced=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "synced=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Open drift reminder issue
|
||||
if: steps.drift.outputs.synced == 'false'
|
||||
uses: actions/gitea-issue-create@v1
|
||||
with:
|
||||
token: ${{ secrets.GITEA_TOKEN }}
|
||||
title: "docs: README updated — review docs/fish-config.md for drift"
|
||||
body: |
|
||||
README.md was modified in commit ${{ github.sha }} but
|
||||
`docs/fish-config.md` (the offline manual) was not updated in
|
||||
the same push.
|
||||
|
||||
Please review the README diff and update the offline documentation
|
||||
if any functions, keybindings, abbreviations, or configuration
|
||||
options were added, removed, or changed.
|
||||
|
||||
Commit: ${{ github.sha }}
|
||||
Branch: ${{ github.ref_name }}
|
||||
labels: documentation
|
||||
@@ -1,37 +0,0 @@
|
||||
name: Generate man page
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'docs/fish-config.md'
|
||||
|
||||
jobs:
|
||||
build-manpage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- name: Install pandoc
|
||||
run: sudo apt-get update -qq && sudo apt-get install -y pandoc
|
||||
|
||||
- name: Compile man page
|
||||
run: |
|
||||
pandoc --standalone \
|
||||
--from markdown \
|
||||
--to man \
|
||||
docs/fish-config.md \
|
||||
-o docs/fish-config.1
|
||||
|
||||
- name: Commit man page
|
||||
run: |
|
||||
git config user.name "Gitea Actions"
|
||||
git config user.email "actions@gitea"
|
||||
git add docs/fish-config.1
|
||||
git diff --cached --quiet && echo "No changes to commit" && exit 0
|
||||
git commit -m "chore(docs): regenerate fish-config.1 man page"
|
||||
git push
|
||||
@@ -0,0 +1,110 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "docs/manual/**"
|
||||
- "docs/build-manual.py"
|
||||
- "docs/manualtools.py"
|
||||
- "docs/verify-manual.py"
|
||||
- "docs/site/**"
|
||||
- "functions/**"
|
||||
- "conf.d/**"
|
||||
- "config.fish"
|
||||
- "completions/**"
|
||||
- "integrations/**"
|
||||
- "tests/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: racknerd-mini
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- name: Install fish
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y software-properties-common
|
||||
sudo add-apt-repository -y ppa:fish-shell/release-4
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y fish
|
||||
|
||||
- name: Run fish config tests
|
||||
run: fish tests/run-tests.fish
|
||||
|
||||
build-docs:
|
||||
needs: test
|
||||
runs-on: racknerd-mini
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y software-properties-common
|
||||
sudo add-apt-repository -y ppa:fish-shell/release-4
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y pandoc python3-yaml fish
|
||||
|
||||
- name: Generate concatenated markdown
|
||||
run: python3 docs/build-manual.py --concat -o docs/fish-config.md
|
||||
|
||||
# Regeneration MUST run before verification: verify-manual.py's
|
||||
# test_concat_roundtrips_original compares a freshly-built concat
|
||||
# against docs/fish-config.md on disk. Before this step ran, that
|
||||
# file was still the stale pre-push copy, so any ordinary edit under
|
||||
# docs/manual/** failed the round-trip check before anything was
|
||||
# regenerated. Do not reorder this back — verification still gates
|
||||
# pandoc and the auto-commit below, it just no longer requires a
|
||||
# contributor to hand-sync the generated file before pushing.
|
||||
- name: Verify manual integrity
|
||||
run: python3 docs/verify-manual.py
|
||||
|
||||
- name: Compile man page
|
||||
run: |
|
||||
pandoc --standalone \
|
||||
--from markdown \
|
||||
--to man \
|
||||
docs/fish-config.md \
|
||||
-o docs/fish-config.1
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
|
||||
- name: Build documentation site
|
||||
run: |
|
||||
python3 docs/build-manual.py --site
|
||||
cd docs/site
|
||||
npm ci
|
||||
npx astro build
|
||||
|
||||
- name: Deploy to Cloudflare Pages
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
run: |
|
||||
cd docs/site
|
||||
npx --yes wrangler pages deploy dist/ \
|
||||
--project-name=fish-config-docs \
|
||||
--branch=main \
|
||||
--commit-dirty=true
|
||||
|
||||
- name: Commit generated docs
|
||||
run: |
|
||||
git config user.name "Gitea Actions"
|
||||
git config user.email "actions@gitea"
|
||||
git add docs/fish-config.md docs/fish-config.1 conf.d/__fish_config_op_registry.fish
|
||||
git diff --cached --quiet && echo "No changes to commit" && exit 0
|
||||
git commit -m "chore(docs): regenerate manual, man page, and component registry"
|
||||
git push
|
||||
+221
@@ -57,6 +57,29 @@
|
||||
[Tt][Ee][Ss][Tt][Ii][Nn][Gg]/
|
||||
.[Tt][Ee][Ss][Tt][Ii][Nn][Gg]/
|
||||
|
||||
# ──────────────────── Planning Artifacts ───────────────────
|
||||
# Catalog files generated by pre-implementation analysis passes
|
||||
opinionated_catalog.md
|
||||
.superpowers
|
||||
docs/superpowers
|
||||
docs/specs
|
||||
docs/plans
|
||||
|
||||
# ──────────────────── Runtime State Files ───────────────────
|
||||
# Sentinel file written/removed at runtime to coordinate logging state
|
||||
# across the fish config and the Kitty Python watcher. Never committed.
|
||||
.logging_disabled
|
||||
|
||||
# ──────────────── Fisher-Managed Plugin Files ───────────────
|
||||
# Fisher writes these into the repo directory on install/update.
|
||||
# They are owned by Fisher — do not commit them.
|
||||
functions/fisher.fish
|
||||
completions/fisher.fish
|
||||
conf.d/sponge.fish
|
||||
functions/_sponge*.fish
|
||||
functions/sponge_*.fish
|
||||
!functions/sponge_filter_secrets.fish
|
||||
|
||||
# ─────────────────── AI Sessions and Rules ──────────────────
|
||||
# Matches CLAUDE.md, .claud*, etc.
|
||||
[Cc][Ll][Aa][Uu][Dd][Ee].[Mm][Dd]
|
||||
@@ -87,3 +110,201 @@ fish_variables
|
||||
config.local.fish
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/fish
|
||||
|
||||
# id: gi-patterns-e390e9c720b3dda36906a2b4cb76ffdd
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
### Python Patch ###
|
||||
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
||||
poetry.toml
|
||||
|
||||
# ruff
|
||||
.ruff_cache/
|
||||
|
||||
# LSP config files
|
||||
pyrightconfig.json
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||
|
||||
# ──────────────── Added by agents-init ──────────────────
|
||||
# agents-init --agents
|
||||
AGENTS/
|
||||
# ────────────────────────────────────────────────────────
|
||||
|
||||
# ──────────────── Added by agents-init ──────────────────
|
||||
# agents-init --plugins
|
||||
docs/devlogs
|
||||
# ────────────────────────────────────────────────────────
|
||||
/.cache_ggshield
|
||||
user-dots
|
||||
|
||||
# ──────────────────── Generated Docs Site ───────────────────
|
||||
docs/site/node_modules/
|
||||
docs/site/dist/
|
||||
docs/site/.astro/
|
||||
docs/site/src/content/docs/
|
||||
docs/site/src/sidebar.json
|
||||
/conf.d/uv.env.fish
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
# Fish Shell Configuration
|
||||
|
||||
A feature-rich Fish shell configuration for CachyOS (Arch Linux), built around a Catppuccin Mocha aesthetic with a curated set of modern CLI tool integrations, smart shell functions, and a heavily customized abbreviation system for keyboard-driven workflows.
|
||||
A feature-rich Fish shell configuration for CachyOS (Arch Linux),
|
||||
built around a Catppuccin Mocha aesthetic with a curated set of modern
|
||||
CLI tool integrations, smart shell functions, and a heavily customized
|
||||
abbreviation system for keyboard-driven workflows.
|
||||
|
||||
📖 **[Documentation site](https://fish.rootiest.fyi/)**
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Structure](#structure)
|
||||
- [Plugins](#plugins)
|
||||
- [Theme & Prompt](#theme--prompt)
|
||||
- [Integrations](#integrations)
|
||||
- [Key Bindings](#key-bindings)
|
||||
- [Functions](#functions)
|
||||
- [Abbreviations](#abbreviations)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Session Logging](#session-logging)
|
||||
- [Documentation](#documentation)
|
||||
- [Installation](#installation)
|
||||
- [Personalization](#personalization)
|
||||
- [Minimal Mode](#minimal-mode)
|
||||
- [Testing](#testing)
|
||||
- [Attribution](#attribution)
|
||||
- [License](#license)
|
||||
|
||||
@@ -24,653 +25,144 @@ A feature-rich Fish shell configuration for CachyOS (Arch Linux), built around a
|
||||
|
||||
This config layers on top of the CachyOS base Fish configuration and adds:
|
||||
|
||||
- **Catppuccin Mocha** theming throughout (prompt, FZF, Zellij)
|
||||
- **Starship** prompt with VI key bindings
|
||||
- **Fisher** plugin management with FZF key bindings and Catppuccin syntax colors
|
||||
- **Catppuccin Mocha** theming throughout (prompt, FZF, syntax highlighting)
|
||||
- **Starship** prompt with VI key bindings; Catppuccin Mocha nim-style fallback prompt when Starship is absent or C3 overrides are disabled
|
||||
- **Fisher** plugin manager bootstrapped automatically; manages `sponge` (failed-command history filter); FZF bindings, Catppuccin theme, done, autopair, and puffer-fish are bundled directly with the config as customized versions
|
||||
- **Smart CLI wrappers** that prefer modern tools (`eza`, `bat`, `btop`, `dust`, `prettyping`) with graceful fallbacks
|
||||
- **Auto Python venv** activation on directory change (direnv-aware)
|
||||
- **Kitty terminal** deep integration for splits, tabs, and SSH
|
||||
- **AI workflow** helpers for Claude and Gemini session management
|
||||
- **Named background jobs** — `jobrunner` (short: `jr`) starts, lists, inspects, re-attaches to, and kills detached tasks via `tmux` or GNU `screen`, so long-running work survives closing the shell
|
||||
- **Optional session logging** — terminal scrollback, multiplexer panes (tmux/zellij), and AUR-helper output can be captured to `~/.terminal_history`; **off by default**, opt in when you want it (see the caution below and [Session Logging](#session-logging))
|
||||
- **AI workflow** helpers for Claude and Antigravity session management
|
||||
- **WakaTime** shell activity tracking
|
||||
- **Opt-out toggles** for every opinionated component — see [Minimal Mode](#minimal-mode)
|
||||
|
||||
> [!CAUTION]
|
||||
> **This configuration *can* log your terminal sessions to disk.** Logging is
|
||||
> **off by default** — but once enabled it silently captures terminal output to
|
||||
> `~/.terminal_history`: Kitty scrollback when a window closes, live tmux pane
|
||||
> streams, zellij pane snapshots on exit, and full `paru`/`yay` output. These
|
||||
> logs can contain command output, file contents, and anything else printed to
|
||||
> your terminal. Nothing is sent off your machine, but the files persist
|
||||
> locally until pruned.
|
||||
>
|
||||
> To turn logging on, set the C5 category variable:
|
||||
>
|
||||
> ```fish
|
||||
> set -U __fish_config_op_logging on
|
||||
> ```
|
||||
>
|
||||
> Or run **`config-settings`** for an interactive menu to flip logging (and any
|
||||
> other opinionated category) on or off — no variable names to remember.
|
||||
>
|
||||
> This takes effect immediately in every open shell. See [Session Logging](#session-logging)
|
||||
> for exactly what is captured and where, and [Minimal Mode](#minimal-mode) for the
|
||||
> full set of opt-out toggles.
|
||||
|
||||
---
|
||||
|
||||
## Structure
|
||||
## Session Logging
|
||||
|
||||
```
|
||||
~/.config/fish/
|
||||
├── config.fish # Main entry point
|
||||
├── fish_plugins # Fisher plugin list
|
||||
├── fish_variables # Universal variables
|
||||
├── conf.d/ # Auto-sourced configuration fragments
|
||||
│ ├── abbr.fish # All abbreviations
|
||||
│ ├── cheat.fish # cheat.sh completions
|
||||
│ ├── key_bindings.fish # Custom key bindings
|
||||
│ ├── fzf.fish # FZF key binding initialization
|
||||
│ ├── tailscale.fish # Tailscale CLI completions
|
||||
│ ├── theme.fish # Theme syntax highlighting colors
|
||||
│ ├── done.fish # Done plugin (desktop notifications for long commands)
|
||||
│ ├── tricks.fish # PATH, bang-bang helpers, bat man pages, system aliases, history/backup utilities
|
||||
│ ├── paru-wrapper.fish # Auto-generates ~/.local/bin/paru logging wrapper on first run
|
||||
│ ├── yay-wrapper.fish # Auto-generates ~/.local/bin/yay logging wrapper on first run
|
||||
│ ├── starship.fish # fish_prompt with OSC 133;A/B shell-integration markers
|
||||
│ ├── wakatime.fish # WakaTime shell hook
|
||||
│ └── zoxide.fish # Zoxide z/zi aliases
|
||||
├── functions/ # Custom functions (one per file)
|
||||
├── completions/ # Custom tab completions
|
||||
├── integrations/ # Integration scripts
|
||||
│ └── fzf.fish # FZF theme and binding config
|
||||
└── themes/ # Catppuccin theme files
|
||||
├── Catppuccin Mocha.theme
|
||||
├── Catppuccin Macchiato.theme
|
||||
├── Catppuccin Frappe.theme
|
||||
└── Catppuccin Latte.theme
|
||||
This config can capture terminal output to `~/.terminal_history` (override with
|
||||
`$SCROLLBACK_HISTORY_DIR`) so you can search back through past sessions. It is
|
||||
**off by default** — opt in with `set -U __fish_config_op_logging on`. Once
|
||||
enabled, five sources feed it:
|
||||
|
||||
| Source | When it captures | Log file |
|
||||
|---|---|---|
|
||||
| Kitty scrollback | When a Kitty window/tab closes | `scrollback_<timestamp>.log` |
|
||||
| tmux pane | Continuously while the pane is open (`pipe-pane`) | `tmux_<session>-w<win>-p<pane>_<timestamp>.log` |
|
||||
| zellij pane | Snapshot taken on **clean** shell exit (`dump-screen`) | `zellij_<session>-p<pane>_<timestamp>.log` |
|
||||
| `paru` wrapper | Every `paru` invocation | `paru_<timestamp>.log` |
|
||||
| `yay` wrapper | Every `yay` invocation | `yay_<timestamp>.log` |
|
||||
|
||||
Old logs are pruned automatically to stay within `$SCROLLBACK_HISTORY_MAX_FILES`
|
||||
(default 100) per source, and empty/trivial captures are discarded.
|
||||
|
||||
> **zellij caveat:** zellij has no continuous pipe like tmux, so its pane is
|
||||
> snapshotted only on a clean shell exit (`exit`/Ctrl-D). Closing a pane or
|
||||
> quitting zellij directly tears down the pane/server before it can be dumped,
|
||||
> so those sessions are not logged. End with `exit` to guarantee a log.
|
||||
|
||||
**These logs can contain secrets** — anything printed to your terminal (command
|
||||
output, file dumps, tokens echoed to stdout) ends up in them. They never leave
|
||||
your machine, but treat `~/.terminal_history` as sensitive.
|
||||
|
||||
All of it is controlled by a single universal variable:
|
||||
|
||||
```fish
|
||||
set -U __fish_config_op_logging on # enable; takes effect in every open shell
|
||||
set -U __fish_config_op_logging off # disable again
|
||||
set -Ue __fish_config_op_logging # erase — back to the default (off)
|
||||
```
|
||||
|
||||
---
|
||||
Unlike the other categories, C5 is opt-in: an unset variable means off, and
|
||||
`__fish_config_opinionated` cannot turn it on for you.
|
||||
|
||||
## Plugins
|
||||
Prefer an interactive interface? Run **`config-settings`** for a full-screen
|
||||
picker that flips logging — and every other opinionated category — on or off
|
||||
per session or universally, without memorizing variable names.
|
||||
|
||||
Managed via [Fisher](https://github.com/jorgebucaran/fisher):
|
||||
Disabling (or leaving it unset) also removes the generated `paru`/`yay` log
|
||||
wrappers and tells the Kitty watcher to skip capture via a sentinel file — no
|
||||
shell or terminal restart required. Logging is category **C5** in
|
||||
[Minimal Mode](#minimal-mode); `set -U __fish_config_opinionated 0` keeps it
|
||||
off along with everything else.
|
||||
|
||||
| Plugin | Purpose |
|
||||
The Kitty scrollback capture is provided by a watcher script that fish-config can
|
||||
install and manage for you. Inside Kitty, if it isn't set up yet, you'll see a
|
||||
one-time-per-session reminder. Manage it with:
|
||||
|
||||
| Command | Action |
|
||||
|---|---|
|
||||
| `jorgebucaran/fisher` | Plugin manager |
|
||||
| `patrickf1/fzf.fish` | FZF key bindings for history, files, processes, git |
|
||||
| `catppuccin/fish` | Catppuccin Mocha syntax highlighting |
|
||||
| `jorgebucaran/autopair.fish` | Auto-close brackets, quotes, and other pairs |
|
||||
| `jorgebucaran/replay.fish` | Run bash commands in fish without losing state |
|
||||
| `nickeb96/puffer-fish` | Expand `...` to `../..`, `!!` to last command, etc. |
|
||||
| `jorgebucaran/spark.fish` | Sparkline bar charts in the terminal |
|
||||
| `kitty-logging install` | Symlink the watcher into your Kitty config and wire it into `kitty.conf` |
|
||||
| `kitty-logging uninstall` | Remove the managed block and the watcher symlink |
|
||||
| `kitty-logging status` | Show whether it's wired, the watcher version, and C5 state |
|
||||
| `kitty-logging dismiss` | Stop the per-session reminder without installing |
|
||||
|
||||
Fisher and all listed plugins are installed automatically by the bootstrap script in `config.fish` upon launching the shell for the first time.
|
||||
`install` adds a clearly-marked managed block to `kitty.conf` and comments out
|
||||
any conflicting `watcher` line. It affects **new** Kitty windows (existing
|
||||
windows keep their current watcher until restarted). With C5 logging off the
|
||||
watcher is inert without needing to be uninstalled, and the reminder stays
|
||||
silent until you enable logging.
|
||||
|
||||
---
|
||||
|
||||
## Theme & Prompt
|
||||
## Documentation
|
||||
|
||||
### Starship
|
||||
### [📖 Documentation Site](https://fish.rootiest.fyi/)
|
||||
|
||||
The primary prompt is [Starship](https://starship.rs/), managed via `conf.d/starship.fish`. Configure it via `~/.config/starship.toml`.
|
||||
A Starlight-powered site rebuilt on every push to `main`. It covers
|
||||
configuration variables, key bindings, abbreviations, all functions, the
|
||||
dependency catalog, customization, and more, with full-text search. Also
|
||||
published as [`llms.txt`](https://fish.rootiest.fyi/llms.txt) (with
|
||||
`llms-full.txt` and `llms-small.txt` variants) for AI agents and other
|
||||
LLM tooling.
|
||||
|
||||
`conf.d/starship.fish` defines a `fish_prompt` wrapper that only activates when `starship` is in `PATH`. It emits OSC 133;A (prompt start) immediately before Starship renders and OSC 133;B (input start) immediately after, placing both markers on the prompt line itself rather than on the blank line above it. This enables `ov` to use them as sticky section headers when browsing scrollback logs. Without Starship, fish's built-in prompt already handles these markers correctly with no wrapper needed.
|
||||
Contributing to the docs? There are two sources, split by content type:
|
||||
|
||||
### FZF
|
||||
- **Function documentation** comes from the man-page-style comment header
|
||||
above each function in `functions/*.fish`. Edit the function; the entry
|
||||
and its site page are generated from the header.
|
||||
- **Everything else** lives under `docs/manual/**`.
|
||||
|
||||
FZF is themed to Catppuccin Mocha with the following colors set via `FZF_DEFAULT_OPTS`:
|
||||
Never edit the generated `docs/fish-config.md` — it's rebuilt from both
|
||||
sources and any hand-edits are discarded.
|
||||
|
||||
- Background: `#1E1E2E` / `#313244`
|
||||
- Foreground: `#CDD6F4`
|
||||
- Highlights: `#F38BA8` (red), `#CBA6F7` (mauve), `#B4BEFE` (lavender)
|
||||
|
||||
See [FZF Bindings](#fzf-bindings) under Key Bindings for the default FZF shortcuts.
|
||||
|
||||
---
|
||||
|
||||
## Integrations
|
||||
|
||||
> [!NOTE]
|
||||
> All integrations listed below are designed to gracefully fallback to basic commands or safely ignore their configuration if their required external dependencies are not installed on the system.
|
||||
|
||||
### Zoxide
|
||||
|
||||
Smart `cd` replacement powered by frecency scoring. `cd`, `z`, and `cdi`/`zi` are all mapped to zoxide-backed navigation functions.
|
||||
To browse the docs from the terminal:
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `cd <path>` / `z <path>` | Jump to a matching directory by frecency; falls back to exact path |
|
||||
| `cdi` / `zi` | Open an interactive fzf selector across all frecency-ranked directories |
|
||||
| `help config` | Open the terminal manual in the best available pager |
|
||||
| `help config <keyword>` | Jump directly to a section matching the keyword |
|
||||
| `help config --html` | Open the documentation site in the default browser |
|
||||
| `help config --man` | Open the compiled man page via `man -l` |
|
||||
| `help config <keyword> --man` | Open the man page jumping to the nearest match |
|
||||
| `repo-open` | Open this repo's web page in the browser (deep-links to the current branch and sub-directory) |
|
||||
|
||||
Tab completions for `cd` and `z` blend standard directory entries (CWD and `CDPATH`) with zoxide frecency results, so familiar paths and frequently-visited destinations appear together in a single list. Full tab completions for the `zoxide` CLI itself (subcommands: `add`, `query`, `remove`, `import`, `init`) are provided via `completions/zoxide.fish`.
|
||||
The pager falls back through: **ov** → **bat** → **man -l** → **less** → **cat**.
|
||||
|
||||
### DirEnv
|
||||
|
||||
Automatically loads `.envrc` files on directory change. Takes priority over the built-in auto-venv logic.
|
||||
|
||||
### Auto Python Venv
|
||||
|
||||
When entering a directory containing a `.venv/`, the virtualenv is automatically activated.
|
||||
It is automatically deactivated when you leave the project tree.
|
||||
|
||||
> [!TIP]
|
||||
> DirEnv-managed directories are skipped by the auto-venv logic to avoid conflicts.
|
||||
|
||||
### WakaTime
|
||||
|
||||
Every shell command is reported to WakaTime for time-tracking. Disable by setting `FISH_WAKATIME_DISABLED=1`.
|
||||
|
||||
### Tailscale
|
||||
|
||||
Full tab completion for the `tailscale` CLI is provided via `conf.d/tailscale.fish`.
|
||||
|
||||
### Pager
|
||||
|
||||
`$PAGER` is set in `config.fish` to `ov` when available, falling back to `less`. This ensures any application that honours `$PAGER` (git, man, etc.) uses the configured pager automatically.
|
||||
|
||||
The `less` wrapper function implements a full pager hierarchy, so anything that calls `less` directly also benefits:
|
||||
|
||||
```
|
||||
$PAGER → ov → less → more → cat
|
||||
```
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `PAGER` | `ov` (if installed), else `less` | System-wide pager used by `less`, `logs`, and any tool that honours `$PAGER` |
|
||||
|
||||
### bat Man Pages
|
||||
|
||||
When `bat` is installed, man pages are automatically rendered through it for syntax highlighting. `MANPAGER` and `MANROFFOPT` are set in `conf.d/tricks.fish`:
|
||||
|
||||
```fish
|
||||
set -gx MANROFFOPT -c
|
||||
set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'"
|
||||
```
|
||||
|
||||
### Done Notifications
|
||||
|
||||
Desktop notifications for long-running commands via [franciscolourenco/done](https://github.com/franciscolourenco/done). A notification fires when a command takes longer than 10 seconds and the terminal window is not focused.
|
||||
|
||||
| Variable | Value | Description |
|
||||
|---|---|---|
|
||||
| `__done_min_cmd_duration` | `10000` ms | Minimum duration before a notification is sent |
|
||||
| `__done_notification_urgency_level` | `low` | Desktop notification urgency |
|
||||
|
||||
### Scrollback History
|
||||
|
||||
When running inside Kitty, closing a shell session with `exit` automatically saves a timestamped scrollback snapshot to `SCROLLBACK_HISTORY_DIR` (default: `~/.terminal_history`). Snapshots are named `scrollback_YYYY-MM-DD_HH-MM-SS.log` and the oldest files are pruned automatically once the count exceeds `SCROLLBACK_HISTORY_MAX_FILES`.
|
||||
|
||||
The `paru` and `yay` wrappers (auto-generated in `~/.local/bin/` by `conf.d/paru-wrapper.fish` and `conf.d/yay-wrapper.fish`) tee all AUR helper output to timestamped log files (`paru_YYYY-MM-DD_HH-MM-SS.log` / `yay_YYYY-MM-DD_HH-MM-SS.log`) in the same directory.
|
||||
|
||||
Before pruning to the max-files limit — and before displaying the log browser — junk logs are automatically removed by `_scrollback_prune_junk`: empty files, files with only a single meaningful line (e.g. bare `[exited]` captures), and Kitty tab-rename prompt captures are all silently discarded.
|
||||
|
||||
Use `exit --no-log` (or `exit -n`) to close without saving.
|
||||
|
||||
The `cat` function detects files inside `SCROLLBACK_HISTORY_DIR` (and any file containing raw ANSI escape sequences) and pipes them through `command cat` instead of `bat`, preserving color output.
|
||||
|
||||
Both variables can be overridden in `local.fish`:
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `SCROLLBACK_HISTORY_DIR` | `~/.terminal_history` | Directory where scrollback snapshots are written |
|
||||
| `SCROLLBACK_HISTORY_MAX_FILES` | `100` | Maximum number of snapshots to keep before pruning |
|
||||
|
||||
---
|
||||
|
||||
## Key Bindings
|
||||
|
||||
### FZF Bindings
|
||||
|
||||
These are the default FZF bindings (from `fzf.fish`):
|
||||
|
||||
| Binding | Action |
|
||||
|---|---|
|
||||
| `Ctrl+R` | Search command history |
|
||||
| `Ctrl+Alt+F` | Search git-tracked files |
|
||||
| `Ctrl+Alt+L` | Search git log |
|
||||
| `Ctrl+Alt+S` | Search git status |
|
||||
| `Ctrl+V` | Search shell variables |
|
||||
| `Ctrl+Alt+P` | Search running processes |
|
||||
|
||||
### User Bindings
|
||||
|
||||
Beyond standard shell and FZF bindings, these custom interactive shortcuts are available:
|
||||
|
||||
| Binding | Action | Description |
|
||||
|---|---|---|
|
||||
| `Ctrl+G` | Previous Path Head | Behaves like `!$:h` in Bash. Inserts the directory part of the previous command's last argument. |
|
||||
| `Ctrl+F` | Interactive History Substitution | Behaves like `!!:s/old/new/` in Bash. Performs substitution on the previous command using `old/new` syntax. When no text is entered, prepends `sudo` to the previous command. The `old/new/n` syntax will perform substitution on the command `n` lines previous in the history. |
|
||||
| `Ctrl+Alt+U` | Replace Command Token | Strips the first token (the command) from the current line. **If the line is empty**, it pulls the previous command and strips its first token, placing the cursor at the start for a quick replacement (e.g., changing `mkdir` to `cd` while keeping the paths). |
|
||||
| `Ctrl+Alt+=` | Inline Qalculate! Evaluation | Passes the current command-line buffer to `qalc` (Qalculate!) and prints the result, then clears the buffer. Allows rapid-fire math without leaving the shell — type `150 * 1.08`, press `Ctrl+Alt+=`, and see `162` immediately. |
|
||||
| `Ctrl+Enter` | Smart Execute | Context-aware Enter key. Empty buffer → standard Enter. Buffer ending with `=` → evaluates it as a math expression via `qalc` (same as `Ctrl+Alt+=`). Any other content → executes the command normally. |
|
||||
| `@@` | FZF Inline Picker | Opens an interactive `fzf` session and injects the selected item directly at the cursor position in the current command line. Useful for inserting file paths, branch names, or any fzf-searchable content mid-command. |
|
||||
|
||||
---
|
||||
|
||||
## Functions
|
||||
|
||||
### Modern CLI Replacements
|
||||
|
||||
These functions wrap modern alternatives with graceful fallbacks to standard tools.
|
||||
|
||||
| Function | Replaces | Tool |
|
||||
|---|---|---|
|
||||
| `ls` | `ls` | `eza` (falls back to `lsd`, then system `ls`) |
|
||||
| `cat` | `cat` | `bat` (plain, no pager); falls back to `command cat` for ANSI log files and scrollback snapshots |
|
||||
| `less` | `less` | `ov` (modern pager); falls back to `less` → `more` → `cat` |
|
||||
| `ping` | `ping` | `prettyping --nolegend` |
|
||||
| `top` | `top` | `btop` |
|
||||
| `rg` | `rg` | ripgrep with `--hyperlink-format=kitty` |
|
||||
| `ssh` | `ssh` | `kitten ssh` when inside Kitty |
|
||||
| `du` | `du` | `duf` (disks) / `dust` (directories) — auto-detected by argument |
|
||||
| `mkdir` | `mkdir` | Always passes `-p` in interactive mode; reports created directories as `Created directory: ~/path/` (falls back silently when flags like `-m` are present) |
|
||||
| `copy` | `cp` | Strips trailing `/` from a source directory before `cp -r`; falls through to `cp` for all other cases |
|
||||
|
||||
#### `du` — Smart Disk Usage
|
||||
|
||||
```fish
|
||||
du # → duf (disk overview)
|
||||
du /some/dir # → dust (directory breakdown)
|
||||
du --disk # → duf (force disk view)
|
||||
du --dir # → dust (force directory view)
|
||||
du --dua # → dua (interactive mode)
|
||||
```
|
||||
|
||||
#### `rm` — Trash-Aware Remove
|
||||
|
||||
```fish
|
||||
rm # List current trash contents
|
||||
rm file.txt # Move to trash (recoverable)
|
||||
rm -r dir/ # Move directory to trash
|
||||
rm -e # Empty all trash
|
||||
rm -e --within 2weeks # Empty trash older than 2 weeks
|
||||
rm -S file.txt # Permanent secure delete + fstrim
|
||||
rm -f file.txt # Falls through to standard rm -f
|
||||
```
|
||||
|
||||
### Directory & File Listing
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `mkcd <dir> [-s]` | Create directory (including missing parents) and `cd` into it; shows a tree of newly-created dirs by default; `-s`/`--silent` suppresses the tree |
|
||||
| `poke <file>...` | `touch` with automatic parent directory creation; shows a tree of newly-created dirs |
|
||||
| `ls` | `eza` — long listing, all files, icons, color, hyperlinks |
|
||||
| `lss` | `eza` — size-sorted long listing with gradient color scale |
|
||||
| `lsr` | `eza` — reversed time-sorted oneline listing |
|
||||
| `ltr` | `eza` — long listing, reversed modification time, age color scale |
|
||||
| `lD` | `eza` — directories only |
|
||||
| `lx` | `eza` — long listing sorted by extension |
|
||||
| `lt` | `eza` — tree listing, depth 2 |
|
||||
| `lstree` | `eza` — full recursive tree |
|
||||
|
||||
### Git
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `branch` | Switch to or create a git branch |
|
||||
| `gitup` | Fetch updates and show git status |
|
||||
| `git-clean` | Fetch, prune, update current branch, delete orphaned local branches |
|
||||
| `git-clean --force` | Same but force-deletes unmerged orphaned branches |
|
||||
| `clone` | `clone-in-kitty` wrapper |
|
||||
| `gitui` | Fast terminal Git UI |
|
||||
| `gi` | Generate and append `.gitignore` patterns from gitignore.io; `gi` (no args) appends boilerplate then prompts interactively; `gi <targets>` appends named patterns; `gi -s <targets>` prints to stdout; `gi -l` lists all targets |
|
||||
|
||||
### Package Management
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `pkg <name>...` | Toggle package: installs if missing, removes if present; `-i` force-install, `-u` force-uninstall. Auto-detects the system package manager (paru, yay, pacman, apt, dnf, zypper, yum, brew, pkg) |
|
||||
| `search <query>` | Search/install interactively: `paru <query>` (Arch only) |
|
||||
| `upgrade` | Full system upgrade: `paru -Syu --noconfirm` (Arch only) |
|
||||
| `cleanup` | Log and remove orphaned packages |
|
||||
|
||||
`conf.d/paru-wrapper.fish` and `conf.d/yay-wrapper.fish` auto-generate thin wrapper scripts at `~/.local/bin/paru` and `~/.local/bin/yay` on first shell start (when the respective AUR helper is installed). These wrappers tee all output to timestamped log files in `SCROLLBACK_HISTORY_DIR` and prune old logs to stay under `SCROLLBACK_HISTORY_MAX_FILES`.
|
||||
|
||||
### Offline Documentation
|
||||
|
||||
A curated offline reference manual is available at `docs/fish-config.md`. It covers every function, keybinding, abbreviation, and configuration variable, written for terminal readability (no hyperlinks or GitHub-specific callouts).
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `config_help` | Open the offline manual in the best available pager |
|
||||
| `config_help <keyword>` | Jump directly to a section matching the keyword |
|
||||
|
||||
The viewer falls back through: **ov** (syntax highlight + section navigation) → **bat** (syntax highlight) → **man -l** (pre-compiled man page) → **less** → **cat**.
|
||||
|
||||
Examples: `config_help keybindings` · `config_help pkg` · `config_help fish-deps` · `config_help abbreviations`
|
||||
|
||||
### Dependency Management
|
||||
|
||||
`fish-deps` is a unified command for checking, installing, and updating all tools this config depends on.
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `fish-deps` / `fish-deps status` | Show installed/missing status for all deps, grouped by tier |
|
||||
| `fish-deps install` | Interactively install each missing dep (prompts per-dep, prompts method when multiple exist) |
|
||||
| `fish-deps update` | Update all installed deps using their preferred install method |
|
||||
| `fish-deps sync` | Install missing deps then update installed ones |
|
||||
| `fzf-update` | Install or upgrade fzf from git HEAD into `~/.fzf` (guarantees the latest build) |
|
||||
| `check_fish_deps` | Legacy alias — delegates to `fish-deps status` |
|
||||
|
||||
Install method priority: **git+cargo source build** (fish) → **cargo** (other Rust tools, gets latest crate) → **system PM** (paru/apt/brew/etc.) → **git clone** (fzf) → **curl installer** (starship, fisher) → **pipx** (Python tools). When multiple methods are available for a tool, you are prompted to choose.
|
||||
|
||||
> [!NOTE]
|
||||
> Upgrading Fish from source requires **cargo** and **[uv](https://docs.astral.sh/uv/)**. Both are managed dependencies — `fish-deps install` will offer to install them before attempting the Fish build. If both are unavailable, `fish-deps update` falls back to the system package manager.
|
||||
|
||||
### Docker
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `ld` / `lzd` | Launch LazyDocker using the currently active Docker context |
|
||||
| `dockup [dir]` | Pull latest images and restart docker compose services |
|
||||
| `docker ps` | Intercepted to use `dops` for a prettier process listing |
|
||||
|
||||
### Network
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `gip` | Show both public IPv4 and IPv6 addresses |
|
||||
| `gip4` | Show public IPv4 address only |
|
||||
| `gip6` | Show public IPv6 address (or error if unavailable) |
|
||||
| `ports` | List all active TCP listeners via `lsof` |
|
||||
| `fast-cli` | Run a bandwidth speed test using fast.com |
|
||||
| `fast` | Friendly error shown when `fast` is typed instead of `fast-cli` |
|
||||
|
||||
### Clipboard
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `y <text>` | Copy text to clipboard (Wayland `wl-copy` or X11 `xclip`) |
|
||||
| `cb <text>` | Copy to clipboard (alias for `y`) |
|
||||
| `paste` | Paste from clipboard to stdout |
|
||||
|
||||
### Terminal
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `split [-h\|-v] [cmd]` | Open a new split pane, optionally running a command |
|
||||
| `spwin` | Spawn a new OS window |
|
||||
| `detach <cmd>` | Run a command fully detached (`nohup`), no output |
|
||||
| `bkg <cmd>` | Background a command, discarding all output |
|
||||
|
||||
### System
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `lock` | Lock the session via `loginctl lock-session` |
|
||||
| `screensleep` | Turn off the display via KDE PowerDevil |
|
||||
| `wake-lock <cmd>` | Run a command with `systemd-inhibit` to prevent sleep |
|
||||
| `swapstat` | Colorized zRAM compression ratio, swappiness, and swap priority report |
|
||||
| `sudo-toggle` | Toggle sudo password bypass — writes/clears a `NOPASSWD` rule in `/etc/sudoers.d/nofail-toggle` |
|
||||
| `smart_exit` | Captures Kitty terminal scrollback to a timestamped log on exit; `--no-log` skips capture; runs `_scrollback_prune_junk` then auto-prunes oldest logs when count exceeds `SCROLLBACK_HISTORY_MAX_FILES` |
|
||||
| `logs` | Browse scrollback, paru, and yay log files interactively with fzf; `Enter` opens in `$PAGER`, `Ctrl-E` opens in `$EDITOR`, `Ctrl-D` deletes (with Y/n confirm), `?` toggles a keybind help overlay; `-c <category>` filters to `scrollback`, `paru`, or `yay`; paru/yay logs open in `ov` with syntax highlights and sticky section headers; scrollback logs open in `ov` with per-command sticky prompt headers via OSC 133;A markers |
|
||||
| `psmem` | List all processes sorted by memory usage (descending) |
|
||||
| `psmem10` | Top 10 processes by memory usage |
|
||||
| `tmux-clean` | Kill all detached tmux sessions |
|
||||
| `limine-edit` | Safely edit and re-verify Limine bootloader configuration |
|
||||
| `sbver` | Verify bootloader signing status for Secure Boot |
|
||||
|
||||
### Media & Utilities
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `dng2avif` | Convert DNG raw images to 10-bit HDR AVIF |
|
||||
| `steam-dl` | Run Steam while inhibiting system sleep |
|
||||
|
||||
### Editors & Development
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `edit` / `e` | Open in Neovim (or `$EDITOR`) |
|
||||
| `view` | Open in Neovim read-only mode |
|
||||
| `fc` | Edit and execute the last command (Bash-style `fc`) |
|
||||
| `nvimup` | Update Neovim headlessly |
|
||||
| `nlazyup` | Sync Lazy.nvim plugins headlessly |
|
||||
|
||||
### AI Assistants
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `claude` | Wrapper for `claude` that always injects `--remote-control` (skips if already present) |
|
||||
| `claude-resume` | Resume Claude Code session from `.claude_session` in CWD |
|
||||
| `antigravity-resume` | Resume antigravity-cli session from `.antigravity_session` in CWD |
|
||||
| `code-resume` | Smart resume — tries Claude then antigravity-cli, falls back to picker |
|
||||
| `superpowers [on\|off]` | Enable/disable the Superpowers extension for Claude and antigravity-cli |
|
||||
| `claude-docs` | Ask Claude to sync `README.md` with recent session changes |
|
||||
| `claude-pr` | Create a branch, commit, push, and open a PR via Claude |
|
||||
|
||||
### Fetch & Info
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `ffetch` | Run fastfetch with `~/.fastfetch.jsonc` if present |
|
||||
| `cffetch` | Clear screen then run fastfetch |
|
||||
| `hist` | FZF history search — selected command is placed in the prompt and copied to clipboard |
|
||||
| `history` | Built-in `history` override — prepends `YYYY-MM-DD HH:MM:SS` timestamps to every entry |
|
||||
| `qr <text>` | Generate a terminal QR code |
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `upgrade` | System upgrade via paru |
|
||||
| `zellij` | Zellij with `--theme catppuccin-mocha` |
|
||||
| `scrub` | Recursively purge OS/editor/compiler garbage from CWD; `-a` aggressive mode adds logs, `node_modules`, IDE dirs; `-d` dry-run preview; requires `fd` |
|
||||
| `antigravity` | Wrapper for `agy` (antigravity-cli) that suppresses a noisy warning |
|
||||
| `antigravity-ide` | Wrapper for `antigravity-ide` binary that suppresses a noisy warning |
|
||||
| `backup <file>` | Copy `<file>` to `<file>.bak` |
|
||||
| `bash` | Drop into bash (raw Fish session via `rawfish`) |
|
||||
|
||||
### Shell Aliases
|
||||
|
||||
These aliases are defined in `conf.d/tricks.fish` via `alias` (which creates Fish functions). They are active in all interactive sessions.
|
||||
|
||||
#### Navigation
|
||||
|
||||
| Alias | Expands To |
|
||||
|---|---|
|
||||
| `..` | `cd ..` |
|
||||
| `...` | `cd ../..` |
|
||||
| `....` | `cd ../../..` |
|
||||
| `.....` | `cd ../../../..` |
|
||||
| `......` | `cd ../../../../..` |
|
||||
|
||||
#### Color Overrides
|
||||
|
||||
Force color output for common tools:
|
||||
|
||||
| Alias | Command |
|
||||
|---|---|
|
||||
| `grep` | `grep --color=auto` |
|
||||
| `fgrep` | `fgrep --color=auto` |
|
||||
| `egrep` | `egrep --color=auto` |
|
||||
| `dir` | `dir --color=auto` |
|
||||
| `vdir` | `vdir --color=auto` |
|
||||
|
||||
#### Safety Wrappers
|
||||
|
||||
These aliases add `-i` (interactive confirmation) to destructive commands:
|
||||
|
||||
| Alias | Command |
|
||||
|---|---|
|
||||
| `cp` | `cp -i` |
|
||||
| `mv` | `mv -i` |
|
||||
|
||||
#### Archives & Networking
|
||||
|
||||
| Alias | Command | Description |
|
||||
|---|---|---|
|
||||
| `tarnow` | `tar -acf` | Create a compressed archive (auto-detects format from extension) |
|
||||
| `untar` | `tar -zxvf` | Extract a gzip-compressed archive |
|
||||
| `wget` | `wget -c` | Resume interrupted downloads by default |
|
||||
| `tb` | `nc termbin.com 9999` | Pipe content to [termbin.com](https://termbin.com) for quick sharing |
|
||||
|
||||
#### System Logs
|
||||
|
||||
| Alias | Command | Description |
|
||||
|---|---|---|
|
||||
| `jctl` | `journalctl -p 3 -xb` | Show priority-3 (error) journal entries from the current boot |
|
||||
|
||||
---
|
||||
|
||||
## Abbreviations
|
||||
|
||||
Abbreviations expand in-place as you type, keeping your history clean.
|
||||
|
||||
### History Expansions (Bash-style)
|
||||
|
||||
These abbreviations replicate Bash's bang-style history expansions. They expand anywhere in the command line when a trigger key (like `Space` or `Enter`) is pressed.
|
||||
|
||||
| Abbr | Expansion | Description |
|
||||
|---|---|---|
|
||||
| `!^` | First argument | Expands to the first argument of the previous command |
|
||||
| `!*` | All arguments | Expands to all arguments of the previous command |
|
||||
| `!-n` | n-th previous | Expands to the n-th previous command in history (e.g., `!-2`) |
|
||||
| `!string` | Prefix search | Expands to the most recent command starting with `string` |
|
||||
| `!?string?` | Contains search | Expands to the most recent command containing `string` |
|
||||
| `^old^new` | Quick substitution | Replaces `old` with `new` in the previous command and expands to it |
|
||||
|
||||
### Editors
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `n`, `nv` | `nvim` |
|
||||
| `e` | `edit` |
|
||||
| `se` | `sudoedit` |
|
||||
| `v` | `antigravity-ide` (VSCode-equivalent) |
|
||||
| `k` | `kate` |
|
||||
|
||||
### Listing
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `l` | `ls` |
|
||||
| `lS` | `lss` (size-sorted) |
|
||||
| `lsR` | `lsr` (reversed time) |
|
||||
| `lX` | `lx` (extension-sorted) |
|
||||
| `lT` | `lt` (tree, depth 2) |
|
||||
| `lsT` | `lstree` (full tree) |
|
||||
|
||||
### Navigation
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `cdnv` | `cd ~/.config/nvim` |
|
||||
| `:cdf` | `cd ~/.config/fish/` |
|
||||
| `:cdk` | `cd ~/.config/kitty/` |
|
||||
| `:cdh` | `cd ~` |
|
||||
| `:cdp` | `cd ~/projects/` (with cursor placement) |
|
||||
| `:cdcz` | `cd ~/.local/share/chezmoi/` |
|
||||
|
||||
### Git
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `g` | `git` |
|
||||
| `lg` | `lazygit` |
|
||||
| `gitig` / `git-ignore` | `gi` |
|
||||
|
||||
### Chezmoi
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `cm` / `cz` | `chezmoi` |
|
||||
| `cmcd` | `chezmoi cd` |
|
||||
| `cme` | `chezmoi edit` |
|
||||
| `cmad` | `chezmoi add` |
|
||||
| `cmap` | `chezmoi apply` |
|
||||
| `cmf` | `chezmoi forget` |
|
||||
| `cmi` | `chezmoi init` |
|
||||
|
||||
### Kitty / WezTerm Window Management
|
||||
|
||||
These abbreviations mirror Vim/tmux ergonomics for managing terminal splits, tabs, and windows. They automatically detect whether you are using Kitty or WezTerm and execute the appropriate terminal CLI commands.
|
||||
|
||||
| Abbr | Action |
|
||||
|---|---|
|
||||
| `:q` | Close active pane |
|
||||
| `:Q` | Close active tab |
|
||||
| `:w` | New OS window |
|
||||
| `:t` | New tab |
|
||||
| `:wv` | Horizontal split |
|
||||
| `:wh` | Vertical split |
|
||||
| `:tp` / `:tn` | Navigate tabs left/right |
|
||||
| `:tl "Title"` | Rename current tab |
|
||||
| `:tgn` | New tab in `~/.config/nvim` |
|
||||
| `:tgf` | New tab in `~/.config/fish` |
|
||||
| `:tgp` | New tab in `~/projects` |
|
||||
| `:tgr` | New root tab (`sudo -i`) |
|
||||
|
||||
### SSH
|
||||
|
||||
Machine-specific SSH abbreviations (e.g. `sshr`, `sshrt`) live in `~/.config/.user-dots/fish/local.fish`.
|
||||
(See [Personalization](#personalization) for examples)
|
||||
|
||||
### Docker
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `dcl` | `docker context use default` |
|
||||
| `dcls` | `docker context ls` |
|
||||
| `lzd` | `ld` (LazyDocker) |
|
||||
|
||||
Named context shortcuts (e.g. `dcr`, `dck`) live in `~/.config/.user-dots/fish/local.fish`.
|
||||
(See [Personalization](#personalization) for examples)
|
||||
|
||||
### Systemctl
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `sc` | `systemctl` |
|
||||
| `ssc` | `sudo systemctl` |
|
||||
| `scu` | `systemctl --user` |
|
||||
| `st` | `systemctl status` |
|
||||
| `scs` | `systemctl start` |
|
||||
| `scr` | `systemctl restart` |
|
||||
| `ssct` | `sudo systemctl status` |
|
||||
| `sscs` | `sudo systemctl start` |
|
||||
| `sscr` | `sudo systemctl restart` |
|
||||
|
||||
### Speed Test
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `speedtest-fast` | `fast-cli` (speed test via fast.com) |
|
||||
|
||||
### Beads (bd)
|
||||
|
||||
| Abbr | Expands To |
|
||||
|---|---|
|
||||
| `bl` | `bd list` |
|
||||
| `bs` | `bd sync` |
|
||||
| `bC` | `bd create --title` |
|
||||
| `bsh` | `bd show` |
|
||||
| `lb` | `lazybeads` |
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Required
|
||||
|
||||
| Tool | Version | Purpose |
|
||||
|---|---|---|
|
||||
| [uv](https://docs.astral.sh/uv/) | any | Python runner (needed to build Fish from source) |
|
||||
| [Rust / cargo](https://www.rust-lang.org/tools/install) | any | Installs Rust-based tools; required to build Fish |
|
||||
| [Fish](https://fishshell.com/) | **≥ 4.0** | Shell |
|
||||
| [Fisher](https://github.com/jorgebucaran/fisher) | any | Plugin manager |
|
||||
| [Starship](https://starship.rs/) | any | Prompt |
|
||||
| [fzf](https://github.com/junegunn/fzf) | any | Fuzzy finder |
|
||||
| [zoxide](https://github.com/ajeetdsouza/zoxide) | any | Smart directory jumper |
|
||||
| [direnv](https://direnv.net/) | any | Per-directory env loading |
|
||||
|
||||
> [!WARNING]
|
||||
> Fish **4.0 or newer is required.** This config uses `test` syntax and other constructs that are incompatible with Fish 3.x. Older versions will produce errors on startup.
|
||||
> Run `fish-deps install` or `fish-deps update` to upgrade — it will install `uv` and `cargo` automatically if missing, then build the latest Fish from source.
|
||||
|
||||
### Recommended
|
||||
|
||||
| Tool | Replaces |
|
||||
|---|---|
|
||||
| [Rust / cargo](https://www.rust-lang.org/tools/install) | Build tool for Rust-based CLI replacements below |
|
||||
| [paru](https://github.com/Morganamilo/paru) / [yay](https://github.com/Jguer/yay) | AUR helper (Arch only) |
|
||||
| [eza](https://github.com/eza-community/eza) | `ls` (preferred) |
|
||||
| [lsd](https://github.com/lsd-rs/lsd) | `ls` (fallback) |
|
||||
| [bat](https://github.com/sharkdp/bat) | `cat` |
|
||||
| [btop](https://github.com/aristocratsupply/btop) | `top` |
|
||||
| [dust](https://github.com/bootandy/dust) | `du` (directories) |
|
||||
| [duf](https://github.com/muesli/duf) | `du` (disks) |
|
||||
| [prettyping](https://github.com/denilsonsa/prettyping) | `ping` |
|
||||
| [ov](https://github.com/noborus/ov) | `less` / `$PAGER` |
|
||||
| [ripgrep](https://github.com/BurntSushi/ripgrep) | `grep` |
|
||||
| [lazygit](https://github.com/jesseduffield/lazygit) | git TUI |
|
||||
| [lazydocker](https://github.com/jesseduffield/lazydocker) | Docker TUI |
|
||||
| [trash-cli](https://github.com/andreafrancia/trash-cli) | Safe `rm` |
|
||||
| [Kitty](https://sw.kovidgoyal.net/kitty/) / [WezTerm](https://wezfurlong.org/wezterm/) | Terminal emulator |
|
||||
| [WakaTime](https://wakatime.com/) | Activity tracking |
|
||||
|
||||
### Full Requirements
|
||||
|
||||
For a complete, categorized list of all non-standard tools required or used by this configuration, see [requirements.md](requirements.md).
|
||||
> **Note:** `fish-config` (hyphen) is this configuration's man page. `fish_config` (underscore) is fish's built-in browser-based configuration tool — a completely separate command. Don't mix them up.
|
||||
|
||||
---
|
||||
|
||||
@@ -686,22 +178,39 @@ mv ~/.config/fish ~/.config/fish.bak
|
||||
git clone https://git.rootiest.dev/rootiest/fish-config.git ~/.config/fish
|
||||
```
|
||||
|
||||
Then open a new Fish shell — Fisher and all plugins will be installed automatically on first launch, and the Catppuccin Mocha theme will be applied.
|
||||
Then open a new Fish shell — Fisher will be installed automatically on first launch and the Catppuccin Mocha theme will be applied. All plugin functionality is bundled directly with this config and requires no additional installation.
|
||||
|
||||
A [chezmoi](https://www.chezmoi.io/) dotfile manager is also configured — secrets are sourced from `~/.config/.user-dots/fish/secrets.fish` and excluded from version control.
|
||||
A [chezmoi](https://www.chezmoi.io/) dotfile manager is also configured — secrets are kept in a private overlay directory (see [Personalization](#personalization)) and excluded from version control.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> `config.fish` ends with a `return` sentinel guard. Any lines appended **after** it by a tool's setup command will silently have no effect. Many tools (starship, zoxide, mise, etc.) offer a setup command that appends an `init | source` line to your `config.fish` — all integrations are managed through `conf.d/` files instead. If you add a new tool and its shell integration appears to do nothing, check whether its setup command appended an init line to the bottom of `config.fish` and create a `conf.d/<tool>.fish` file for it instead.
|
||||
|
||||
### Updating the Config
|
||||
|
||||
Pull the latest changes from upstream without needing a configured git remote:
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `config-update` | Fetch and apply the latest commits from upstream |
|
||||
| `config-update --dry-run` | Preview available changes without applying them |
|
||||
| `config-update --force` | Stash local changes, pull, then restore the stash |
|
||||
|
||||
---
|
||||
|
||||
## Personalization
|
||||
|
||||
Sensitive credentials and machine-specific paths are kept out of version control via a secondary private directory at `~/.config/.user-dots/fish/`. Two files are sourced automatically by `config.fish` if they exist:
|
||||
Sensitive credentials and machine-specific paths are kept out of version control via a private overlay directory. The path defaults to `~/.config/.user-dots/fish/` but can be changed by setting a universal variable:
|
||||
|
||||
```fish
|
||||
set -U __fish_user_dots_path /path/to/your/dots/fish
|
||||
```
|
||||
|
||||
`config.fish` sources `local.fish` from that directory. `local.fish` is responsible for sourcing its own `secrets.fish` companion:
|
||||
|
||||
```
|
||||
~/.config/.user-dots/fish/
|
||||
$__fish_user_dots_path/
|
||||
├── secrets.fish # API keys, tokens, passwords, personal identifiers
|
||||
└── local.fish # Machine-specific paths and environment variables
|
||||
└── local.fish # Machine-specific paths, env vars, and sourcing secrets
|
||||
```
|
||||
|
||||
### secrets.fish
|
||||
@@ -753,25 +262,88 @@ abbr -a dcw 'docker context use work-server'
|
||||
|
||||
### How it works
|
||||
|
||||
`config.fish` sources both files with an existence check so the public config works cleanly on any machine that doesn't have the private repo:
|
||||
`config.fish` sources only `local.fish` with an existence check so the public config works cleanly on any machine without the private repo. `local.fish` is responsible for sourcing its own `secrets.fish`:
|
||||
|
||||
```fish
|
||||
if test -f $HOME/.config/.user-dots/fish/secrets.fish
|
||||
source $HOME/.config/.user-dots/fish/secrets.fish
|
||||
end
|
||||
|
||||
if test -f $HOME/.config/.user-dots/fish/local.fish
|
||||
source $HOME/.config/.user-dots/fish/local.fish
|
||||
end
|
||||
# config.fish resolves the path, then sources local.fish
|
||||
set -q __fish_user_dots_path
|
||||
or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
|
||||
test -f "$__fish_user_dots_path/local.fish"
|
||||
and source "$__fish_user_dots_path/local.fish"
|
||||
```
|
||||
|
||||
For convenience, a git-ignored `user-dots` symlink in the fish config directory is pointed at `$__fish_user_dots_path` on startup, so the overlay can be browsed from `~/.config/fish/`. It is recreated if missing and repointed if the path variable changes. Creation is a C2 startup side-effect (`__fish_config_op_autoexec`); it only ever manages a symlink and never clobbers a real file or directory at that path.
|
||||
|
||||
To opt out, set `__fish_user_dots_symlink` to a falsy value (or toggle **Dots link** off on the **Paths** page of `config-settings`). Disabling it stops the symlink being generated and removes any existing one immediately — honoured regardless of the C2 master switch.
|
||||
|
||||
`fish_variables` (which fish auto-manages and may contain universal variable state) is excluded from this repo via `.gitignore`.
|
||||
|
||||
---
|
||||
|
||||
## Minimal Mode
|
||||
|
||||
Everything opinionated in this config — command shadows, startup side-effects, key and environment overrides, terminal integrations, and the first-run greeting — is active by default but can be switched off. Logging (C5) is the exception: it is **opt-in**, off until you explicitly enable it.
|
||||
|
||||
> **The easy way — `config-settings`:** Run `config-settings` for an interactive TUI that manages settings across four pages — **Universal** and **Session** (the opinionated category toggles below, persistent or per-shell), **Sponge** (history-scrubbing: delay, exit codes, purge-on-exit, and extra sensitive variable names), and **Paths** (scrollback log dir, max files, and the user-dots path) — without typing a single variable name. Navigate with the arrow keys (or `h`/`j`/`k`/`l`); toggle rows step OFF ← DEFAULT → ON, value rows edit inline with `Enter` and clear with `←`. `Tab`/`Shift-Tab` cycle pages and `q` quits. Changes apply instantly. The panel auto-sizes to your terminal width (four tiers from 52- to 78-wide with a 6-column margin), centers itself horizontally, and redraws within ~0.3 s of a resize.
|
||||
|
||||
If you'd rather set them by hand, each category is controlled by a universal variable. Six category toggles and one master switch are available:
|
||||
|
||||
| Variable | Disables |
|
||||
|---|---|
|
||||
| `__fish_config_op_aliases` | Command shadows: `ls`→eza, `cat`→bat, `cd`→zoxide, `rm`→trash, `top`→btop, `edit`→multi-editor launcher, and friends; `grep`/`cp`/`mv`/`wget` flag injection |
|
||||
| `__fish_config_op_autoexec` | Startup side-effects: Fisher bootstrap, theme apply, `paru`/`yay` wrapper generation, auto venv activation, WakaTime hook, auto-pull background fast-forward |
|
||||
| `__fish_config_op_overrides` | Vi mode, `exit`→`smart_exit`, `$PAGER`/`$MANPAGER`/`$CDPATH`/`XDG`/`PATH`, bang-bang history expansion, autopair, puffer, Starship prompt, theme colors |
|
||||
| `__fish_config_op_integrations` | Kitty/WezTerm window abbreviations, `done` notifications, `spwin`/`tab`/`split`, `hist`, `logs`, `upgrade`, WakaTime |
|
||||
| `__fish_config_op_logging` | **Opt-in — off unless explicitly enabled.** Scrollback capture on exit, tmux `pipe-pane` pane logging, zellij `dump-screen` capture on exit, `paru`/`yay` AUR log wrappers, Kitty watcher capture (sentinel-file coordinated) |
|
||||
| `__fish_config_op_greeting` | Per-session `fish_greeting` (suppresses distro greetings such as CachyOS fastfetch by overriding with an empty function); first-run welcome banner |
|
||||
| `__fish_config_opinionated` | Master switch — disables all six categories at once (it is a master *off* switch; it cannot enable opt-in C5 logging) |
|
||||
|
||||
Set any of them to a falsy value (`0`, `false`, `no`, `off`, `n`) to disable; erase the variable to re-enable. An explicit per-category truthy value overrides a falsy master switch, so you can disable everything with `__fish_config_opinionated=0` and selectively re-enable individual categories:
|
||||
|
||||
```fish
|
||||
# Plain shell: disable everything opinionated
|
||||
set -U __fish_config_opinionated 0
|
||||
|
||||
# Or pick a single category, e.g. keep integrations but drop command shadows
|
||||
set -U __fish_config_op_aliases off
|
||||
|
||||
# Minimal mode but keep the greeting (per-category overrides master)
|
||||
set -U __fish_config_opinionated 0
|
||||
set -U __fish_config_op_greeting 1
|
||||
|
||||
# Opt in to session logging (C5 is off by default)
|
||||
set -U __fish_config_op_logging on
|
||||
|
||||
# Back to full flavor
|
||||
set -Ue __fish_config_opinionated
|
||||
set -Ue __fish_config_op_greeting
|
||||
```
|
||||
|
||||
Command shadows react immediately; bindings, prompt, and abbreviations take effect in new shells. With aliases disabled, `rm` deletes permanently again instead of trashing. See `help config opinionated` for the full component list.
|
||||
|
||||
Each category further sub-divides into two to six sub-categories with
|
||||
their own `__fish_config_op_<category>_<subcategory>` toggles (e.g.
|
||||
`__fish_config_op_aliases_filesystem`), following the exact same
|
||||
truthy/falsy/unset cascade one level deeper. Run `config-settings` and
|
||||
press Enter on a category row to browse and toggle its sub-categories, or
|
||||
see the [Components Reference](https://fish.rootiest.fyi/08-components-reference/)
|
||||
for the full sub-category list per category.
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
```fish
|
||||
fish tests/run-tests.fish
|
||||
```
|
||||
|
||||
Runs before every push (and gates the [documentation build](.github/workflows/ci.yml) in CI, so a broken config can't get published): syntax-lints every `.fish` file, then loads the config in an isolated `HOME`/XDG sandbox — never this checkout itself, since it doubles as a real `~/.config/fish` — and runs functional checks against foundational behavior (XDG/PATH/CDPATH setup, key bindings, abbreviations, core functions, the opinionated-component registry, and more).
|
||||
|
||||
---
|
||||
|
||||
## Attribution
|
||||
|
||||
The core of the [Zoxide integration](#zoxide) in this repository was originally adapted from the [icezyclon/zoxide.fish](https://github.com/icezyclon/zoxide.fish) plugin (MIT Licensed) and has since been heavily customized for performance and Fish 4.x compatibility.
|
||||
The core of the [Zoxide integration](https://fish.rootiest.fyi/02-path-setup/) in this repository was originally adapted from the [icezyclon/zoxide.fish](https://github.com/icezyclon/zoxide.fish) plugin (MIT Licensed) and has since been heavily customized for performance and Fish 4.x compatibility.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# Completions for the `auto-pull` registry command.
|
||||
|
||||
function __auto_pull_registered
|
||||
set -l list "$XDG_CONFIG_HOME/.user-dots/fish/auto-pull.list"
|
||||
test -r "$list"; or return
|
||||
for l in (command cat "$list" 2>/dev/null)
|
||||
test -n "$l"; or continue
|
||||
printf '%s\t%s\n' (path basename "$l") "$l"
|
||||
end
|
||||
end
|
||||
|
||||
set -l subcmds list add remove status
|
||||
|
||||
# Subcommands (only as the first argument).
|
||||
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a list -d 'Show registered repos'
|
||||
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a add -d "Register a repo (default: current)"
|
||||
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a remove -d 'Unregister a repo'
|
||||
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a status -d 'Show enabled state and registry path'
|
||||
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-s h -l help -d 'Show help'
|
||||
|
||||
# `add` takes a directory path.
|
||||
complete -c auto-pull -n "__fish_seen_subcommand_from add" -a '(__fish_complete_directories)'
|
||||
|
||||
# `remove` completes registered repo basenames.
|
||||
complete -c auto-pull -f -n "__fish_seen_subcommand_from remove" -a '(__auto_pull_registered)'
|
||||
@@ -0,0 +1,103 @@
|
||||
# fish completion for copilot
|
||||
# Generated by `copilot completion fish`. Do not edit by hand.
|
||||
|
||||
complete -c copilot -n '__fish_use_subcommand' -f -a 'login' -d 'Authenticate with Copilot'
|
||||
complete -c copilot -n '__fish_use_subcommand' -f -a 'help' -d 'Display help information'
|
||||
complete -c copilot -n '__fish_use_subcommand' -f -a 'init' -d 'Initialize Copilot instructions'
|
||||
complete -c copilot -n '__fish_use_subcommand' -f -a 'update' -d 'Download the latest version'
|
||||
complete -c copilot -n '__fish_use_subcommand' -f -a 'version' -d 'Display version information'
|
||||
complete -c copilot -n '__fish_use_subcommand' -f -a 'plugin' -d 'Manage plugins'
|
||||
complete -c copilot -n '__fish_use_subcommand' -f -a 'mcp' -d 'Manage MCP servers'
|
||||
complete -c copilot -n '__fish_use_subcommand' -f -a 'completion' -d 'Generate a shell completion script'
|
||||
complete -c copilot -l version -s v -f -d 'show version information'
|
||||
complete -c copilot -l interactive -s i -r -d 'Start interactive mode and automatically execute this prompt'
|
||||
complete -c copilot -l prompt -s p -r -d 'Execute a prompt in non-interactive mode (exits after completion)'
|
||||
complete -c copilot -l silent -s s -f -d 'Output only the agent response (no stats), useful for scripting with -p'
|
||||
complete -c copilot -l enable-memory -f -d 'Enable memory in prompt mode (disabled by default)'
|
||||
complete -c copilot -l model -r -d 'Set the AI model to use (use \'auto\' to let Copilot pick automatically)'
|
||||
complete -c copilot -l effort -l reasoning-effort -r -d 'Set the reasoning effort level' -a 'none low medium high xhigh max'
|
||||
complete -c copilot -l context -r -d 'Set the context window tier (overrides persisted setting)' -a 'default long_context'
|
||||
complete -c copilot -l enable-reasoning-summaries -f -d 'Request reasoning summaries for OpenAI models'
|
||||
complete -c copilot -l agent -r -d 'Specify a custom agent to use'
|
||||
complete -c copilot -l resume -s r -r -d 'Resume from a previous session (optionally specify existing session ID, task ID, ID prefix, or name; name matching is exact, case-insensitive)'
|
||||
complete -c copilot -l continue -f -d 'Resume the most recent session'
|
||||
complete -c copilot -l name -s n -r -d 'Set a name for the new session'
|
||||
complete -c copilot -l session-id -r -d 'Resume an existing session or task by ID, or set the UUID for a new session'
|
||||
complete -c copilot -l connect -r -d 'Connect directly to a remote session (optionally specify session ID or task ID)'
|
||||
complete -c copilot -l allow-all-tools -f -d 'Allow all tools to run automatically without confirmation; required for non-interactive mode'
|
||||
complete -c copilot -l allow-all-paths -f -d 'Disable file path verification and allow access to any path'
|
||||
complete -c copilot -l disallow-temp-dir -f -d 'Prevent automatic access to the system temporary directory'
|
||||
complete -c copilot -l no-custom-instructions -f -d 'Disable loading of custom instructions from AGENTS.md and related files'
|
||||
complete -c copilot -l no-auto-update -f -d 'Disable downloading CLI update automatically (disabled by default in CI environments)'
|
||||
complete -c copilot -l no-ask-user -f -d 'Disable the ask_user tool (agent works autonomously without asking questions)'
|
||||
complete -c copilot -l banner -f -d 'Show the startup banner'
|
||||
complete -c copilot -l no-color -f -d 'Disable all color output'
|
||||
complete -c copilot -l screen-reader -f -d 'Enable screen reader optimizations'
|
||||
complete -c copilot -l plain-diff -f -d 'Disable rich diff rendering (syntax highlighting via diff tool specified by git config)'
|
||||
complete -c copilot -s C -r -d 'Change working directory before doing anything else'
|
||||
complete -c copilot -l log-dir -r -d 'Set log file directory (default: ~/.copilot/logs/)'
|
||||
complete -c copilot -l extension-sdk-path -r -d 'Override the bundled @github/copilot-sdk injected into extension subprocesses with a local `copilot-sdk/` folder. Invalid paths fall back to the bundled SDK.'
|
||||
complete -c copilot -l log-level -r -d 'Set the log level' -a 'none error warning info debug all default'
|
||||
complete -c copilot -l stream -r -d 'Enable or disable streaming mode' -a 'on off'
|
||||
complete -c copilot -l output-format -r -d 'Output format: \'text\' (default) or \'json\' (JSONL, one JSON object per line)' -a 'text json'
|
||||
complete -c copilot -l share -r -d 'Share session to markdown file after completion in non-interactive mode (default: ./copilot-session-<id>.md)'
|
||||
complete -c copilot -l share-gist -f -d 'Share session to a secret GitHub gist after completion in non-interactive mode'
|
||||
complete -c copilot -l add-dir -r -d 'Add a directory to the allowed list for file access (can be used multiple times)'
|
||||
complete -c copilot -l attachment -r -d 'Attach a file (image or native document) to the initial prompt; only valid in non-interactive mode (can be used multiple times)'
|
||||
complete -c copilot -l disable-mcp-server -r -d 'Disable a specific MCP server (can be used multiple times)'
|
||||
complete -c copilot -l disable-builtin-mcps -f -d 'Disable all built-in MCP servers (currently: github-mcp-server)'
|
||||
complete -c copilot -l enable-all-github-mcp-tools -f -d 'Enable all GitHub MCP server tools instead of the default CLI subset. Overrides --add-github-mcp-toolset and --add-github-mcp-tool options.'
|
||||
complete -c copilot -l add-github-mcp-toolset -r -d 'Add a toolset to enable for the GitHub MCP server instead of the default CLI subset (can be used multiple times). Use "all" for all toolsets.'
|
||||
complete -c copilot -l add-github-mcp-tool -r -d 'Add a tool to enable for the GitHub MCP server instead of the default CLI subset (can be used multiple times). Use "*" for all tools.'
|
||||
complete -c copilot -l plugin-dir -r -d 'Load a plugin from a local directory (can be used multiple times)'
|
||||
complete -c copilot -l additional-mcp-config -r -d 'Additional MCP servers configuration as JSON string or file path (prefix with @) (can be used multiple times; augments config from ~/.copilot/mcp-config.json for this session)'
|
||||
complete -c copilot -l allow-tool -r -d 'Tools the CLI has permission to use; will not prompt for permission'
|
||||
complete -c copilot -l deny-tool -r -d 'Tools the CLI does not have permission to use; will not prompt for permission'
|
||||
complete -c copilot -l available-tools -r -d 'Only these tools will be available to the model'
|
||||
complete -c copilot -l excluded-tools -r -d 'These tools will not be available to the model'
|
||||
complete -c copilot -l secret-env-vars -r -d 'Environment variable names whose values are stripped from shell and MCP server environments and redacted from output (e.g., --secret-env-vars=MY_KEY,OTHER_KEY)'
|
||||
complete -c copilot -l allow-url -r -d 'Allow access to specific URLs or domains'
|
||||
complete -c copilot -l deny-url -r -d 'Deny access to specific URLs or domains, takes precedence over --allow-url'
|
||||
complete -c copilot -l allow-all-urls -f -d 'Allow access to all URLs without confirmation'
|
||||
complete -c copilot -l allow-all -f -d 'Enable all permissions (equivalent to --allow-all-tools --allow-all-paths --allow-all-urls)'
|
||||
complete -c copilot -l yolo -f -d 'Enable all permissions (equivalent to --allow-all-tools --allow-all-paths --allow-all-urls)'
|
||||
complete -c copilot -l max-autopilot-continues -r -d 'Maximum number of continuation messages in autopilot mode'
|
||||
complete -c copilot -l mode -r -d 'Set the initial agent mode' -a 'interactive plan autopilot'
|
||||
complete -c copilot -l autopilot -f -d 'Start in autopilot mode'
|
||||
complete -c copilot -l plan -f -d 'Start in plan mode'
|
||||
complete -c copilot -l experimental -f -d 'Enable experimental features'
|
||||
complete -c copilot -l no-experimental -f -d 'Disable experimental features'
|
||||
complete -c copilot -l bash-env -r -d 'Enable BASH_ENV support for bash shells (on|off)'
|
||||
complete -c copilot -l no-bash-env -f -d 'Disable BASH_ENV support for bash shells'
|
||||
complete -c copilot -l mouse -r -d 'Enable mouse support in alt screen mode (on|off)'
|
||||
complete -c copilot -l no-mouse -f -d 'Disable mouse support in alt screen mode'
|
||||
complete -c copilot -l acp -f -d 'Start as Agent Client Protocol server'
|
||||
complete -c copilot -l remote -f -d 'Enable remote control of your session from GitHub web and mobile'
|
||||
complete -c copilot -l no-remote -f -d 'Disable remote control of your session from GitHub web and mobile'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from login' -l host -r -d 'GitHub host URL (default: https://github.com)'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a 'install' -d 'Install a plugin'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a 'uninstall' -d 'Uninstall a plugin'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a 'update' -d 'Update a plugin'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a 'list' -d 'List installed plugins'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a 'marketplace' -d 'Manage plugin marketplaces'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from update' -l all -f -d 'Update all installed plugins'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a 'add' -d 'Add a marketplace'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a 'remove' -d 'Remove a marketplace'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a 'list' -d 'List registered marketplaces'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a 'browse' -d 'Browse plugins in a marketplace'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a 'update' -d 'Update marketplace plugin catalogs'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace; and __fish_seen_subcommand_from remove' -l force -s f -f -d 'Force removal even if plugins are installed'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp' -f -a 'list' -d 'List configured MCP servers'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp' -f -a 'get' -d 'Show server details'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp' -f -a 'add' -d 'Add an MCP server'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp' -f -a 'remove' -d 'Remove an MCP server'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from list' -l json -f -d 'Output as JSON'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from get' -l json -f -d 'Output as JSON'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from get' -l show-secrets -f -d 'Show full environment variable and header values (masked by default)'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l transport -r -d 'Server transport' -a 'stdio http sse'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l env -r -d 'Environment variable (KEY=VALUE, can be repeated)'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l header -r -d 'HTTP header for remote servers, can be repeated'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l tools -r -d 'Tool filter: "*" for all, comma-separated list, or "" for none'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l timeout -r -d 'Timeout in milliseconds'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l json -f -d 'Output added config as JSON'
|
||||
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l show-secrets -f -d 'Show full environment variable and header values in output, masked by default'
|
||||
@@ -0,0 +1,79 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# Completions for the `jobrunner` background job manager.
|
||||
# `jr` inherits these via `function jr --wraps jobrunner`.
|
||||
|
||||
# Offer running jobs as name<TAB>description pairs.
|
||||
function __jobrunner_complete_jobs
|
||||
set -l tool ""
|
||||
set -l tokens (commandline -opc)
|
||||
set -l idx 1
|
||||
while test $idx -le (count $tokens)
|
||||
switch $tokens[$idx]
|
||||
case -t --tool
|
||||
set idx (math $idx + 1)
|
||||
if test $idx -le (count $tokens)
|
||||
set tool $tokens[$idx]
|
||||
end
|
||||
case '--tool=*'
|
||||
set tool (string replace -- "--tool=" "" $tokens[$idx])
|
||||
case '-t*'
|
||||
set tool (string replace -r "^-t" "" $tokens[$idx])
|
||||
end
|
||||
set idx (math $idx + 1)
|
||||
end
|
||||
|
||||
for row in (__jobrunner_sessions $tool)
|
||||
set -l f (string split \t -- $row)
|
||||
printf '%s\t%s job (PID %s)\n' $f[1] $f[3] $f[2]
|
||||
end
|
||||
end
|
||||
|
||||
set -l subcmds run list attach kill logs help
|
||||
set -l needs_job "__fish_seen_subcommand_from attach kill logs -a --attach -k --kill -o --output"
|
||||
|
||||
# No file completions; jobs are named, not paths.
|
||||
complete -c jobrunner -f
|
||||
|
||||
# Backend tool selection flag.
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-s t -l tool -x -a "tmux screen" -d 'Force specific backend'
|
||||
|
||||
# Subcommands (only as the first argument).
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a run -d 'Start a named job in the background'
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a list -d 'List all managed background jobs'
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a attach -d 'Re-attach interactively to a job'
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a kill -d 'Terminate a running background job'
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a logs -d "Print a job's output without attaching"
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a help -d 'Show usage help'
|
||||
|
||||
# Flag forms.
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-s r -l run -d 'Start a named job in the background'
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-s l -l list -d 'List all managed background jobs'
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-s a -l attach -d 'Re-attach interactively to a job'
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-s k -l kill -d 'Terminate a running background job'
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-s o -l output -d "Print a job's output without attaching"
|
||||
complete -c jobrunner -s h -l help -d 'Show usage help'
|
||||
|
||||
# Running jobs, for the subcommands that take one.
|
||||
complete -c jobrunner -n "$needs_job" -a '(__jobrunner_complete_jobs)'
|
||||
|
||||
# A bare job name attaches to it, so offer jobs in first position too.
|
||||
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
|
||||
-a '(__jobrunner_complete_jobs)'
|
||||
|
||||
# After `run <name>`, complete the command to execute.
|
||||
complete -c jobrunner -n "__fish_seen_subcommand_from run -r --run; and test (count (commandline -opc)) -ge 3" \
|
||||
-a '(__fish_complete_subcommand)'
|
||||
@@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
complete -c rand_string -f
|
||||
|
||||
complete -c rand_string -s s -l separator -x -a 'dash underscore dot none' -d 'Set separator for following words'
|
||||
complete -c rand_string -s c -l case -x -a 'lower upper title' -d 'Set casing for following words'
|
||||
complete -c rand_string -s h -l help -d 'Show usage help'
|
||||
|
||||
# List of all available lists in data/words
|
||||
set -l categories
|
||||
if set -q __fish_config_dir
|
||||
set categories (string replace -r '\.txt$' '' (command ls $__fish_config_dir/data/words/*.txt 2>/dev/null | command xargs -n 1 basename 2>/dev/null))
|
||||
end
|
||||
|
||||
for cat in $categories
|
||||
complete -c rand_string -a "$cat" -d "Pick a random word from the $cat list"
|
||||
end
|
||||
|
||||
complete -c rand_string -a 'digits=' -d 'Generate N random digits (e.g. digits=3)'
|
||||
complete -c rand_string -a 'literal=' -d 'Insert a literal string exactly as provided'
|
||||
@@ -0,0 +1,146 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# GENERATED FILE --- do not edit by hand.
|
||||
# Regenerate with __fish_config_op_registry_rebuild after editing a
|
||||
# # COMPONENT header, or automatically via docs/build-manual.py.
|
||||
# Source: docs/generate_component_registry.py
|
||||
#
|
||||
# This file must be sourced before any other conf.d/*.fish file that
|
||||
# calls the opinionated guard. That currently holds only because fish's
|
||||
# glob-based conf.d loading happens to sort this filename first
|
||||
# alphabetically among the guard-calling files -- do not rename it
|
||||
# without preserving that ordering.
|
||||
|
||||
set -g __fish_config_op_registry_keys \
|
||||
"__auto_source_fallback_venv:" \
|
||||
"__fish_config_sync_logging:" \
|
||||
"__fish_user_dots_link:" \
|
||||
"_zellij_dump_log:" \
|
||||
"abbr:abbr-integrations" \
|
||||
"abbr:abbr-overrides" \
|
||||
"agy:" \
|
||||
"auto-pull:" \
|
||||
"autopair:" \
|
||||
"bash:" \
|
||||
"bash_expands:" \
|
||||
"cat:" \
|
||||
"claude:" \
|
||||
"config:cachyos-strip-aliases" \
|
||||
"config:cachyos-strip-overrides" \
|
||||
"config:cachyos-tricks" \
|
||||
"config:cdpath" \
|
||||
"config:exit-wiring" \
|
||||
"config:greeting-stamp" \
|
||||
"config:pager-editor-gpg" \
|
||||
"config:path-setup" \
|
||||
"config:vi-mode" \
|
||||
"done:" \
|
||||
"du:" \
|
||||
"edit:" \
|
||||
"first_run:first-run-bootstrap" \
|
||||
"first_run:first-run-greeting" \
|
||||
"fish_right_prompt:" \
|
||||
"help:" \
|
||||
"hist:" \
|
||||
"key_bindings:" \
|
||||
"kitty-logging:" \
|
||||
"kitty-watcher-reminder:" \
|
||||
"less:" \
|
||||
"logs:" \
|
||||
"ls:" \
|
||||
"mkdir:" \
|
||||
"mv:" \
|
||||
"paru-wrapper:paru-autoexec" \
|
||||
"paru-wrapper:paru-logging" \
|
||||
"ping:" \
|
||||
"puffer:" \
|
||||
"rg:" \
|
||||
"rm:" \
|
||||
"smart_exit:exit-plain" \
|
||||
"smart_exit:logging-guard" \
|
||||
"split:" \
|
||||
"spwin:" \
|
||||
"ssh:" \
|
||||
"starship:" \
|
||||
"tab:" \
|
||||
"theme:" \
|
||||
"tmux-logging:" \
|
||||
"top:" \
|
||||
"tricks:aliases-tricks" \
|
||||
"tricks:tricks-bang" \
|
||||
"tricks:tricks-manpager" \
|
||||
"upgrade:" \
|
||||
"wakatime:wakatime-autoexec" \
|
||||
"wakatime:wakatime-hook" \
|
||||
"yay-wrapper:yay-autoexec" \
|
||||
"yay-wrapper:yay-logging" \
|
||||
"yt-dlp:" \
|
||||
"zoxide:"
|
||||
|
||||
set -g __fish_config_op_registry_values \
|
||||
"autoexec/venv" \
|
||||
"logging/terminal-capture" \
|
||||
"autoexec/sync" \
|
||||
"logging/multiplexer-capture" \
|
||||
"integrations/terminal-abbrs" \
|
||||
"overrides/key-bindings" \
|
||||
"aliases/dev-tools" \
|
||||
"autoexec/sync" \
|
||||
"overrides/key-bindings" \
|
||||
"aliases/shell-tools" \
|
||||
"overrides/key-bindings" \
|
||||
"aliases/filesystem" \
|
||||
"aliases/dev-tools" \
|
||||
"aliases/filesystem" \
|
||||
"overrides/key-bindings" \
|
||||
"overrides/environment" \
|
||||
"overrides/environment" \
|
||||
"overrides/key-bindings" \
|
||||
"greeting/greeting-message" \
|
||||
"overrides/environment" \
|
||||
"overrides/environment" \
|
||||
"overrides/key-bindings" \
|
||||
"integrations/notifications" \
|
||||
"aliases/filesystem" \
|
||||
"aliases/dev-tools" \
|
||||
"autoexec/plugin-management" \
|
||||
"greeting/first-run" \
|
||||
"overrides/prompt" \
|
||||
"aliases/shell-tools" \
|
||||
"integrations/history-logs" \
|
||||
"overrides/key-bindings" \
|
||||
"logging/terminal-capture" \
|
||||
"logging/terminal-capture" \
|
||||
"aliases/shell-tools" \
|
||||
"integrations/history-logs" \
|
||||
"aliases/filesystem" \
|
||||
"aliases/filesystem" \
|
||||
"aliases/filesystem" \
|
||||
"autoexec/pkg-wrappers" \
|
||||
"logging/pkg-logs" \
|
||||
"aliases/network" \
|
||||
"overrides/key-bindings" \
|
||||
"aliases/search" \
|
||||
"aliases/filesystem" \
|
||||
"overrides/key-bindings" \
|
||||
"logging/terminal-capture" \
|
||||
"integrations/window-mgmt" \
|
||||
"integrations/window-mgmt" \
|
||||
"aliases/network" \
|
||||
"overrides/prompt" \
|
||||
"integrations/window-mgmt" \
|
||||
"overrides/prompt" \
|
||||
"logging/multiplexer-capture" \
|
||||
"aliases/monitor" \
|
||||
"aliases/filesystem" \
|
||||
"overrides/key-bindings" \
|
||||
"overrides/environment" \
|
||||
"integrations/pkg-upgrade" \
|
||||
"autoexec/telemetry" \
|
||||
"integrations/notifications" \
|
||||
"autoexec/pkg-wrappers" \
|
||||
"logging/pkg-logs" \
|
||||
"aliases/network" \
|
||||
"aliases/filesystem"
|
||||
|
||||
+565
-182
@@ -8,308 +8,691 @@
|
||||
# This file contains all the abbreviations for the terminal.
|
||||
# It is sourced by Fish on startup.
|
||||
|
||||
# COMPONENT
|
||||
# site abbr-integrations: integrations/terminal-abbrs
|
||||
# site abbr-overrides: overrides/key-bindings
|
||||
|
||||
# Neovim
|
||||
# @category Editors
|
||||
# @desc nvim
|
||||
abbr -a n nvim
|
||||
# @category Editors
|
||||
# @desc nvim
|
||||
abbr -a nv nvim
|
||||
# @category Editors
|
||||
# @desc nvim
|
||||
abbr -a neovim nvim
|
||||
# @category Editors
|
||||
# @desc cd ~/.config/nvim
|
||||
abbr -a cdnv 'cd ~/.config/nvim # Neovim Config'
|
||||
# @category Editors
|
||||
# @desc cd ~/.config/nvim; nvim
|
||||
abbr -a cdnvn 'cd ~/.config/nvim;nvim'
|
||||
# VSCode
|
||||
# @category AI Assistants
|
||||
# @desc antigravity-ide
|
||||
abbr -a v antigravity-ide
|
||||
# Kate
|
||||
# @category Editors
|
||||
# @desc kate
|
||||
abbr -a k kate
|
||||
# WezTerm SSH
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category AI Assistants
|
||||
# @desc wezterm ssh (WezTerm only)
|
||||
abbr -a s wezterm ssh
|
||||
end
|
||||
# Neovim in a new tab
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Open new tab with nvim (terminal-aware)
|
||||
abbr -a editt kitty @ launch --type=tab --cwd=current nvim # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Open new tab with nvim (terminal-aware)
|
||||
abbr -a editt wezterm cli spawn nvim # WezTerm
|
||||
end
|
||||
# LazyGit
|
||||
# @category Git
|
||||
# @desc lazygit
|
||||
abbr -a lg lazygit
|
||||
# Sudo shell
|
||||
# @category Miscellaneous
|
||||
# @desc sudo -s
|
||||
abbr -a sudu sudo -s
|
||||
# Kitty
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Miscellaneous
|
||||
# @desc kitty (Kitty only)
|
||||
abbr -a kt kitty
|
||||
end
|
||||
# cat
|
||||
# @category Miscellaneous
|
||||
# @desc cat
|
||||
abbr -a c cat
|
||||
# chezmoi
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi
|
||||
abbr -a cm chezmoi
|
||||
# chezmoi cd
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi cd
|
||||
abbr -a cmcd chezmoi cd
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi cd
|
||||
abbr -a czcd chezmoi cd
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi cd
|
||||
abbr -a cdcm chezmoi cd
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi cd
|
||||
abbr -a cdcz chezmoi cd
|
||||
# chezmoi edit
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi edit
|
||||
abbr -a cme chezmoi edit
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi edit
|
||||
abbr -a cze chezmoi edit
|
||||
# chezmoi add
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi add
|
||||
abbr -a cmad chezmoi add
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi add
|
||||
abbr -a czad chezmoi add
|
||||
# chezmoi apply
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi apply
|
||||
abbr -a cmap chezmoi apply
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi apply
|
||||
abbr -a czap chezmoi apply
|
||||
# chezmoi rm
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi forget
|
||||
abbr -a cmrm chezmoi forget
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi forget
|
||||
abbr -a cmf chezmoi forget
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi forget
|
||||
abbr -a czrm chezmoi forget
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi forget
|
||||
abbr -a czf chezmoi forget
|
||||
# chezmoi init
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi init
|
||||
abbr -a cmi chezmoi init
|
||||
# @category Chezmoi
|
||||
# @desc chezmoi init
|
||||
abbr -a czi chezmoi init
|
||||
# Edit
|
||||
# @category Editors
|
||||
# @desc edit
|
||||
abbr -a e edit
|
||||
# Sudoedit
|
||||
# @category Editors
|
||||
# @desc sudoedit
|
||||
abbr -a se sudoedit
|
||||
# Git
|
||||
# @category Git
|
||||
# @desc git
|
||||
abbr -a g git
|
||||
# @category Git
|
||||
# @desc generate .gitignore
|
||||
abbr -a gitig gi
|
||||
# @category Git
|
||||
# @desc generate .gitignore
|
||||
abbr -a git-ignore gi
|
||||
# Antigravity
|
||||
abbr -a ag antigravity
|
||||
abbr -a ag. antigravity .
|
||||
# @category AI Assistants
|
||||
# @desc agy
|
||||
abbr -a ag agy
|
||||
# @category AI Assistants
|
||||
# @desc agy .
|
||||
abbr -a ag. agy .
|
||||
# Quit
|
||||
# @category Miscellaneous
|
||||
# @desc exit
|
||||
abbr -a /exit exit
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :q kitty @ close-window # Kitty (Closes the active split/pane)
|
||||
abbr -a :Q kitty @ close-tab # Kitty (Closes the whole tab)
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :q wezterm cli kill-pane # WezTerm
|
||||
abbr -a :Q wezterm cli kill-pane # WezTerm
|
||||
# Window-management abbreviations are opinionated (C4 integrations)
|
||||
if __fish_config_op_enabled (status basename) abbr-integrations
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Close current pane/window
|
||||
abbr -a :q kitty @ close-window # Kitty (Closes the active split/pane)
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Close current tab
|
||||
abbr -a :Q kitty @ close-tab # Kitty (Closes the whole tab)
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Close current pane/window
|
||||
abbr -a :q wezterm cli kill-pane # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Close current tab
|
||||
abbr -a :Q wezterm cli kill-pane # WezTerm
|
||||
end
|
||||
end
|
||||
|
||||
######### Alternates ##########
|
||||
### ls alternates
|
||||
# List all files
|
||||
# @category Navigation and Listing
|
||||
# @desc ls
|
||||
abbr -a l ls
|
||||
# List all files by size
|
||||
# @category Navigation and Listing
|
||||
# @desc lss (sort by size)
|
||||
abbr -a lS lss
|
||||
# List all files by reverse modified time
|
||||
# @category Navigation and Listing
|
||||
# @desc lsr (sort by time, oldest first)
|
||||
abbr -a lsR lsr
|
||||
# List by extension
|
||||
# @category Navigation and Listing
|
||||
# @desc lx (sort by extension)
|
||||
abbr -a lX lx
|
||||
# Tree listing (depth 2)
|
||||
# @category Navigation and Listing
|
||||
# @desc lt (tree, depth 2)
|
||||
abbr -a lT lt
|
||||
# Full tree listing
|
||||
# @category Navigation and Listing
|
||||
# @desc lstree (full recursive tree)
|
||||
abbr -a lsT lstree
|
||||
### speed-test alternates
|
||||
# Speedtest using fast.com
|
||||
# @category Miscellaneous
|
||||
# @desc fast-cli
|
||||
abbr -a speedtest-fast fast-cli
|
||||
|
||||
# Window Creation (OS Windows)
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :w kitty @ launch --type=os-window # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :w wezterm cli spawn --new-window # WezTerm
|
||||
end
|
||||
# Kitty/WezTerm window-management abbreviations are opinionated (C4
|
||||
# integrations): they assume an active Kitty or WezTerm session.
|
||||
if __fish_config_op_enabled (status basename) abbr-integrations
|
||||
# Window Creation (OS Windows)
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window
|
||||
abbr -a :w kitty @ launch --type=os-window # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window
|
||||
abbr -a :w wezterm cli spawn --new-window # WezTerm
|
||||
end
|
||||
|
||||
# Window Splits (Panes)
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :wv kitty @ launch --location=hsplit # Kitty (Horizontal split)
|
||||
abbr -a :wh kitty @ launch --location=vsplit # Kitty (Vertical split)
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :wv wezterm cli split-pane --bottom # WezTerm
|
||||
abbr -a :wh wezterm cli split-pane --right # WezTerm
|
||||
end
|
||||
# Window Splits (Panes)
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split pane horizontally (new pane below)
|
||||
abbr -a :wv kitty @ launch --location=hsplit # Kitty (Horizontal split)
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split pane vertically (new pane to the right)
|
||||
abbr -a :wh kitty @ launch --location=vsplit # Kitty (Vertical split)
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split pane horizontally (new pane below)
|
||||
abbr -a :wv wezterm cli split-pane --bottom # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split pane vertically (new pane to the right)
|
||||
abbr -a :wh wezterm cli split-pane --right # WezTerm
|
||||
end
|
||||
|
||||
# Window Detach (Move Pane)
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :wo kitty @ detach-window --target-tab=new # Kitty (Moves pane to new tab)
|
||||
abbr -a :wot kitty @ detach-window # Kitty (Same as above, default behavior)
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :wo wezterm cli move-pane-to-new-tab --new-window # WezTerm
|
||||
abbr -a :wot wezterm cli move-pane-to-new-tab # WezTerm
|
||||
end
|
||||
# Window Detach (Move Pane)
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Detach current window to its own OS window
|
||||
abbr -a :wo kitty @ detach-window --target-tab=new # Kitty (Moves pane to new tab)
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Move current pane to a new tab
|
||||
abbr -a :wot kitty @ detach-window # Kitty (Same as above, default behavior)
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Detach current window to its own OS window
|
||||
abbr -a :wo wezterm cli move-pane-to-new-tab --new-window # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Move current pane to a new tab
|
||||
abbr -a :wot wezterm cli move-pane-to-new-tab # WezTerm
|
||||
end
|
||||
|
||||
# Tab Creation
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :t kitty @ launch --type=tab # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :t wezterm cli spawn # WezTerm
|
||||
end
|
||||
# Tab Creation
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab
|
||||
abbr -a :t kitty @ launch --type=tab # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab
|
||||
abbr -a :t wezterm cli spawn # WezTerm
|
||||
end
|
||||
|
||||
# Rename Tab
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :tl "kitty @ set-tab-title" # Kitty -> Usage: :tl "New Title"
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :tl wezterm cli set-tab-title # WezTerm
|
||||
end
|
||||
# Rename Tab
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Set tab title
|
||||
abbr -a :tl "kitty @ set-tab-title" # Kitty -> Usage: :tl "New Title"
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Set tab title
|
||||
abbr -a :tl wezterm cli set-tab-title # WezTerm
|
||||
end
|
||||
|
||||
# Rename Window
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :tw "kitty @ set-window-title" # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :tw wezterm cli set-window-title # WezTerm
|
||||
end
|
||||
# Rename Window
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Set window title
|
||||
abbr -a :tw "kitty @ set-window-title" # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Set window title
|
||||
abbr -a :tw wezterm cli set-window-title # WezTerm
|
||||
end
|
||||
|
||||
# Rename Workspace
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :twk wezterm cli rename-workspace # WezTerm
|
||||
end
|
||||
# Kitty does not have a direct CLI equivalent for renaming a dynamic "workspace" session.
|
||||
# Rename Workspace
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Rename workspace (WezTerm only)
|
||||
abbr -a :twk wezterm cli rename-workspace # WezTerm
|
||||
end
|
||||
# Kitty does not have a direct CLI equivalent for renaming a dynamic "workspace" session.
|
||||
|
||||
# Tab Navigation
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :tp "kitty @ focus-tab --match neighbor:left" # Kitty
|
||||
abbr -a :tn "kitty @ focus-tab --match neighbor:right" # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :tp wezterm cli activate-tab --tab-relative -1 # WezTerm
|
||||
abbr -a :tn wezterm cli activate-tab --tab-relative 1 # WezTerm
|
||||
end
|
||||
# Tab Navigation
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Focus previous tab
|
||||
abbr -a :tp "kitty @ focus-tab --match neighbor:left" # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Focus next tab
|
||||
abbr -a :tn "kitty @ focus-tab --match neighbor:right" # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Focus previous tab
|
||||
abbr -a :tp wezterm cli activate-tab --tab-relative -1 # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Focus next tab
|
||||
abbr -a :tn wezterm cli activate-tab --tab-relative 1 # WezTerm
|
||||
end
|
||||
|
||||
# Specialty Tab Shortcuts (New Tab in specific dir)
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :tgk kitty @ launch --type=tab --cwd ~/.config/kitty # Kitty
|
||||
abbr -a :tgn kitty @ launch --type=tab --cwd ~/.config/nvim # Kitty
|
||||
abbr -a :tgf kitty @ launch --type=tab --cwd ~/.config/fish # Kitty
|
||||
abbr -a :tgh kitty @ launch --type=tab --cwd ~
|
||||
abbr -a :tgcz kitty @ launch --type=tab --cwd ~/.local/share/chezmoi # Kitty
|
||||
abbr -a :tgcm kitty @ launch --type=tab --cwd ~/.config/chezmoi # Kitty
|
||||
abbr -a :tgp kitty @ launch --type=tab --cwd ~/projects # Kitty
|
||||
abbr -a :tgr kitty @ launch --type=tab -- sudo -i
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :tgk wezterm cli spawn --cwd ~/.config/kitty # WezTerm
|
||||
abbr -a :tgn wezterm cli spawn --cwd ~/.config/nvim # WezTerm
|
||||
abbr -a :tgf wezterm cli spawn --cwd ~/.config/fish # WezTerm
|
||||
abbr -a :tgh wezterm cli spawn --cwd ~ # WezTerm
|
||||
abbr -a :tgcz wezterm cli spawn --cwd ~/.local/share/chezmoi # WezTerm
|
||||
abbr -a :tgcm wezterm cli spawn --cwd ~/.config/chezmoi # WezTerm
|
||||
abbr -a :tgp wezterm cli spawn --cwd ~/projects # WezTerm
|
||||
abbr -a :tgr wezterm cli spawn -- sudo -i # WezTerm
|
||||
end
|
||||
# Specialty Tab Shortcuts (New Tab in specific dir)
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.config/kitty
|
||||
abbr -a :tgk kitty @ launch --type=tab --cwd ~/.config/kitty # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.config/nvim
|
||||
abbr -a :tgn kitty @ launch --type=tab --cwd ~/.config/nvim # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.config/fish
|
||||
abbr -a :tgf kitty @ launch --type=tab --cwd ~/.config/fish # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~
|
||||
abbr -a :tgh kitty @ launch --type=tab --cwd ~
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.local/share/chezmoi
|
||||
abbr -a :tgcz kitty @ launch --type=tab --cwd ~/.local/share/chezmoi # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.config/chezmoi
|
||||
abbr -a :tgcm kitty @ launch --type=tab --cwd ~/.config/chezmoi # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/projects
|
||||
abbr -a :tgp kitty @ launch --type=tab --cwd ~/projects # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at / (root)
|
||||
abbr -a :tgr kitty @ launch --type=tab -- sudo -i
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.config/kitty
|
||||
abbr -a :tgk wezterm cli spawn --cwd ~/.config/kitty # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.config/nvim
|
||||
abbr -a :tgn wezterm cli spawn --cwd ~/.config/nvim # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.config/fish
|
||||
abbr -a :tgf wezterm cli spawn --cwd ~/.config/fish # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~
|
||||
abbr -a :tgh wezterm cli spawn --cwd ~ # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.local/share/chezmoi
|
||||
abbr -a :tgcz wezterm cli spawn --cwd ~/.local/share/chezmoi # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/.config/chezmoi
|
||||
abbr -a :tgcm wezterm cli spawn --cwd ~/.config/chezmoi # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at ~/projects
|
||||
abbr -a :tgp wezterm cli spawn --cwd ~/projects # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New tab at / (root)
|
||||
abbr -a :tgr wezterm cli spawn -- sudo -i # WezTerm
|
||||
end
|
||||
|
||||
# Specialty Window Shortcuts (New OS Window in specific dir)
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :wgk kitty @ launch --type=os-window --cwd ~/.config/kitty # Kitty
|
||||
abbr -a :wgn kitty @ launch --type=os-window --cwd ~/.config/nvim # Kitty
|
||||
abbr -a :wgf kitty @ launch --type=os-window --cwd ~/.config/fish # Kitty
|
||||
abbr -a :wgh kitty @ launch --type=os-window --cwd ~
|
||||
abbr -a :wgzd kitty @ launch --type=os-window --cwd ~/.local/share/chezmoi # Kitty
|
||||
abbr -a :wgcz kitty @ launch --type=os-window --cwd ~/.config/chezmoi # Kitty
|
||||
abbr -a :wgp kitty @ launch --type=os-window --cwd ~/projects # Kitty
|
||||
abbr -a :wgr kitty @ launch --type=os-window -- sudo -i # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :wgk wezterm cli spawn --new-window --cwd ~/.config/kitty # WezTerm
|
||||
abbr -a :wgn wezterm cli spawn --new-window --cwd ~/.config/nvim # WezTerm
|
||||
abbr -a :wgf wezterm cli spawn --new-window --cwd ~/.config/fish # WezTerm
|
||||
abbr -a :wgh wezterm cli spawn --new-window --cwd ~ # WezTerm
|
||||
abbr -a :wgzd wezterm cli spawn --new-window --cwd ~/.local/share/chezmoi # WezTerm
|
||||
abbr -a :wgcz wezterm cli spawn --new-window --cwd ~/.config/chezmoi # WezTerm
|
||||
abbr -a :wgp wezterm cli spawn --new-window --cwd ~/projects # WezTerm
|
||||
abbr -a :wgr wezterm cli spawn --new-window -- sudo -i # WezTerm
|
||||
end
|
||||
# Specialty Window Shortcuts (New OS Window in specific dir)
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.config/kitty
|
||||
abbr -a :wgk kitty @ launch --type=os-window --cwd ~/.config/kitty # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.config/nvim
|
||||
abbr -a :wgn kitty @ launch --type=os-window --cwd ~/.config/nvim # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.config/fish
|
||||
abbr -a :wgf kitty @ launch --type=os-window --cwd ~/.config/fish # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~
|
||||
abbr -a :wgh kitty @ launch --type=os-window --cwd ~
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.local/share/chezmoi
|
||||
abbr -a :wgzd kitty @ launch --type=os-window --cwd ~/.local/share/chezmoi # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.config/chezmoi
|
||||
abbr -a :wgcz kitty @ launch --type=os-window --cwd ~/.config/chezmoi # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/projects
|
||||
abbr -a :wgp kitty @ launch --type=os-window --cwd ~/projects # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at / (root)
|
||||
abbr -a :wgr kitty @ launch --type=os-window -- sudo -i # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.config/kitty
|
||||
abbr -a :wgk wezterm cli spawn --new-window --cwd ~/.config/kitty # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.config/nvim
|
||||
abbr -a :wgn wezterm cli spawn --new-window --cwd ~/.config/nvim # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.config/fish
|
||||
abbr -a :wgf wezterm cli spawn --new-window --cwd ~/.config/fish # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~
|
||||
abbr -a :wgh wezterm cli spawn --new-window --cwd ~ # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.local/share/chezmoi
|
||||
abbr -a :wgzd wezterm cli spawn --new-window --cwd ~/.local/share/chezmoi # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/.config/chezmoi
|
||||
abbr -a :wgcz wezterm cli spawn --new-window --cwd ~/.config/chezmoi # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at ~/projects
|
||||
abbr -a :wgp wezterm cli spawn --new-window --cwd ~/projects # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc New OS window at / (root)
|
||||
abbr -a :wgr wezterm cli spawn --new-window -- sudo -i # WezTerm
|
||||
end
|
||||
|
||||
# Specialty Window Vertical Shortcuts (Split Bottom)
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :wvgk kitty @ launch --location=hsplit --cwd ~/.config/kitty # Kitty
|
||||
abbr -a :wvgn kitty @ launch --location=hsplit --cwd ~/.config/nvim # Kitty
|
||||
abbr -a :wvgf kitty @ launch --location=hsplit --cwd ~/.config/fish # Kitty
|
||||
abbr -a :wvgh kitty @ launch --location=hsplit --cwd ~ # Kitty
|
||||
abbr -a :wvgcz kitty @ launch --location=hsplit --cwd ~/.local/share/chezmoi # Kitty
|
||||
abbr -a :wvgcm kitty @ launch --location=hsplit --cwd ~/.config/chezmoi # Kitty
|
||||
abbr -a :wvgp kitty @ launch --location=hsplit --cwd ~/projects # Kitty
|
||||
abbr -a :wvgr kitty @ launch --location=hsplit -- sudo -i # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :wvgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm
|
||||
abbr -a :wvgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm
|
||||
abbr -a :wvgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm
|
||||
abbr -a :wvgh wezterm cli split-pane --bottom --cwd ~ # WezTerm
|
||||
abbr -a :wvgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm
|
||||
abbr -a :wvgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm
|
||||
abbr -a :wvgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm
|
||||
abbr -a :wvgr wezterm cli split-pane --bottom -- sudo -i # WezTerm
|
||||
end
|
||||
# Specialty Window Vertical Shortcuts (Split Bottom)
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.config/kitty
|
||||
abbr -a :wvgk kitty @ launch --location=hsplit --cwd ~/.config/kitty # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.config/nvim
|
||||
abbr -a :wvgn kitty @ launch --location=hsplit --cwd ~/.config/nvim # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.config/fish
|
||||
abbr -a :wvgf kitty @ launch --location=hsplit --cwd ~/.config/fish # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~
|
||||
abbr -a :wvgh kitty @ launch --location=hsplit --cwd ~ # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.local/share/chezmoi
|
||||
abbr -a :wvgcz kitty @ launch --location=hsplit --cwd ~/.local/share/chezmoi # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.config/chezmoi
|
||||
abbr -a :wvgcm kitty @ launch --location=hsplit --cwd ~/.config/chezmoi # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/projects
|
||||
abbr -a :wvgp kitty @ launch --location=hsplit --cwd ~/projects # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at / (root)
|
||||
abbr -a :wvgr kitty @ launch --location=hsplit -- sudo -i # Kitty
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.config/kitty
|
||||
abbr -a :wvgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.config/nvim
|
||||
abbr -a :wvgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.config/fish
|
||||
abbr -a :wvgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~
|
||||
abbr -a :wvgh wezterm cli split-pane --bottom --cwd ~ # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.local/share/chezmoi
|
||||
abbr -a :wvgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/.config/chezmoi
|
||||
abbr -a :wvgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at ~/projects
|
||||
abbr -a :wvgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split bottom at / (root)
|
||||
abbr -a :wvgr wezterm cli split-pane --bottom -- sudo -i # WezTerm
|
||||
end
|
||||
|
||||
# Specialty Window Horizontal Shortcuts (Split Right)
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :whgk kitty @ launch --location=vsplit --cwd ~/.config/kitty # Kitty
|
||||
abbr -a :whgn kitty @ launch --location=vsplit --cwd ~/.config/nvim # Kitty
|
||||
abbr -a :whgf kitty @ launch --location=vsplit --cwd ~/.config/fish # Kitty
|
||||
abbr -a :whgh kitty @ launch --location=vsplit --cwd ~ # Kitty
|
||||
abbr -a :whgcz kitty @ launch --location=vsplit --cwd ~/.local/share/chezmoi # Kitty
|
||||
abbr -a :whgcm kitty @ launch --location=vsplit --cwd ~/.config/chezmoi # Kitty
|
||||
abbr -a :whgp kitty @ launch --location=vsplit --cwd ~/projects # Kitty
|
||||
abbr -a :whgr kitty @ launch --location=vsplit --cwd current sudo -i # Kitty -> Specialty cd Shortcuts
|
||||
abbr -a :cdk 'cd ~/.config/kitty/ # Kitty Config'
|
||||
abbr -a :cdkn 'cd ~/.config/kitty;nvim'
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
abbr -a :whgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm
|
||||
abbr -a :whgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm
|
||||
abbr -a :whgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm
|
||||
abbr -a :whgh wezterm cli split-pane --bottom --cwd ~ # WezTerm
|
||||
abbr -a :whgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm
|
||||
abbr -a :whgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm
|
||||
abbr -a :whgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm
|
||||
abbr -a :whgr wezterm cli split-pane --bottom -- sudo -i # WezTerm
|
||||
end
|
||||
abbr -a :cdn cd '~/.config/nvim/ # Neovim Config'
|
||||
abbr -a :cdnn 'cd ~/.config/nvim;nvim'
|
||||
abbr -a :cdf 'cd ~/.config/fish/ # Fish Config'
|
||||
abbr -a :cdfn 'cd ~/.config/fish;nvim'
|
||||
abbr -a :cdh 'cd ~ # Home Directory'
|
||||
abbr -a :cdhn 'cd ~;nvim'
|
||||
abbr -a :cdcz cd '~/.local/share/chezmoi/ # Chezmoi Source'
|
||||
abbr -a :cdczn 'cd ~/.local/share/chezmoi;nvim'
|
||||
abbr -a :cdcm 'cd ~/.config/chezmoi/ # Chezmoi Config'
|
||||
abbr -a :cdcmn 'cd ~/.config/chezmoi;nvim'
|
||||
abbr -a :cdp --regex ':cdp' --set-cursor 'cd ~/projects/%'
|
||||
# abbr -a cdp_slash --position anywhere --regex ':cdp/' --set-cursor 'cd ~/projects/%'
|
||||
abbr -a :cdpn 'cd ~/projects;nvim'
|
||||
abbr -a :cdw 'cd ~/.config/wezterm/ # WezTerm Config'
|
||||
abbr -a :cdwn 'cd ~/.config/wezterm;nvim'
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a editt kitty @ launch --type tab nvim
|
||||
end
|
||||
# Spawn window
|
||||
if test "$TERM" = xterm-kitty
|
||||
abbr -a :sw spwin
|
||||
# Specialty Window Horizontal Shortcuts (Split Right)
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.config/kitty
|
||||
abbr -a :whgk kitty @ launch --location=vsplit --cwd ~/.config/kitty # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.config/nvim
|
||||
abbr -a :whgn kitty @ launch --location=vsplit --cwd ~/.config/nvim # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.config/fish
|
||||
abbr -a :whgf kitty @ launch --location=vsplit --cwd ~/.config/fish # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~
|
||||
abbr -a :whgh kitty @ launch --location=vsplit --cwd ~ # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.local/share/chezmoi
|
||||
abbr -a :whgcz kitty @ launch --location=vsplit --cwd ~/.local/share/chezmoi # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.config/chezmoi
|
||||
abbr -a :whgcm kitty @ launch --location=vsplit --cwd ~/.config/chezmoi # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/projects
|
||||
abbr -a :whgp kitty @ launch --location=vsplit --cwd ~/projects # Kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at / (root)
|
||||
abbr -a :whgr kitty @ launch --location=vsplit --cwd current sudo -i # Kitty -> Specialty cd Shortcuts
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/kitty
|
||||
abbr -a :cdk 'cd ~/.config/kitty/ # Kitty Config'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/kitty; nvim
|
||||
abbr -a :cdkn 'cd ~/.config/kitty;nvim'
|
||||
end
|
||||
if test "$TERM_PROGRAM" = WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.config/kitty
|
||||
abbr -a :whgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.config/nvim
|
||||
abbr -a :whgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.config/fish
|
||||
abbr -a :whgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~
|
||||
abbr -a :whgh wezterm cli split-pane --bottom --cwd ~ # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.local/share/chezmoi
|
||||
abbr -a :whgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/.config/chezmoi
|
||||
abbr -a :whgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at ~/projects
|
||||
abbr -a :whgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Split right at / (root)
|
||||
abbr -a :whgr wezterm cli split-pane --bottom -- sudo -i # WezTerm
|
||||
end
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/nvim
|
||||
abbr -a :cdn cd '~/.config/nvim/ # Neovim Config'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/nvim; nvim
|
||||
abbr -a :cdnn 'cd ~/.config/nvim;nvim'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/fish
|
||||
abbr -a :cdf 'cd ~/.config/fish/ # Fish Config'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/fish; nvim
|
||||
abbr -a :cdfn 'cd ~/.config/fish;nvim'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~
|
||||
abbr -a :cdh 'cd ~ # Home Directory'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~; nvim
|
||||
abbr -a :cdhn 'cd ~;nvim'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.local/share/chezmoi
|
||||
abbr -a :cdcz cd '~/.local/share/chezmoi/ # Chezmoi Source'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.local/share/chezmoi; nvim
|
||||
abbr -a :cdczn 'cd ~/.local/share/chezmoi;nvim'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/chezmoi
|
||||
abbr -a :cdcm 'cd ~/.config/chezmoi/ # Chezmoi Config'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/chezmoi; nvim
|
||||
abbr -a :cdcmn 'cd ~/.config/chezmoi;nvim'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/projects/...
|
||||
abbr -a :cdp --regex ':cdp' --set-cursor 'cd ~/projects/%'
|
||||
# abbr -a cdp_slash --position anywhere --regex ':cdp/' --set-cursor 'cd ~/projects/%'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/projects; nvim
|
||||
abbr -a :cdpn 'cd ~/projects;nvim'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/wezterm
|
||||
abbr -a :cdw 'cd ~/.config/wezterm/ # WezTerm Config'
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc cd ~/.config/wezterm; nvim
|
||||
abbr -a :cdwn 'cd ~/.config/wezterm;nvim'
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Open new tab with nvim (terminal-aware)
|
||||
abbr -a editt kitty @ launch --type tab nvim
|
||||
end
|
||||
# Spawn window
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc spwin (spawn new OS window)
|
||||
abbr -a :sw spwin
|
||||
end
|
||||
end
|
||||
|
||||
### Docker ###
|
||||
# @category Docker
|
||||
# @desc docker context use default
|
||||
abbr -a dcl 'docker context use default # Local Host'
|
||||
# @category Docker
|
||||
# @desc ld (lazydocker)
|
||||
abbr -a lzd ld
|
||||
# @category Docker
|
||||
# @desc docker context ls
|
||||
abbr -a dcls 'docker context ls'
|
||||
|
||||
### Beads ###
|
||||
# @category Miscellaneous
|
||||
# @desc bd list
|
||||
abbr -a bl 'bd list'
|
||||
# @category Miscellaneous
|
||||
# @desc bd sync
|
||||
abbr -a bs 'bd sync'
|
||||
# @category Miscellaneous
|
||||
# @desc bd create --title
|
||||
abbr -a bC 'bd create --title'
|
||||
# @category Miscellaneous
|
||||
# @desc bd show
|
||||
abbr -a bsh 'bd show'
|
||||
# @category Miscellaneous
|
||||
# @desc lazybeads
|
||||
abbr -a lb lazybeads
|
||||
|
||||
### Systemctl ###
|
||||
# @category Systemctl
|
||||
# @desc systemctl
|
||||
abbr -a sc systemctl
|
||||
# @category Systemctl
|
||||
# @desc sudo systemctl
|
||||
abbr -a ssc 'sudo systemctl'
|
||||
# @category Systemctl
|
||||
# @desc systemctl --user
|
||||
abbr -a scu 'systemctl --user'
|
||||
# @category Systemctl
|
||||
# @desc systemctl status
|
||||
abbr -a st 'systemctl status'
|
||||
# @category Systemctl
|
||||
# @desc systemctl start
|
||||
abbr -a scs 'systemctl start'
|
||||
# @category Systemctl
|
||||
# @desc systemctl restart
|
||||
abbr -a scr 'systemctl restart'
|
||||
# @category Systemctl
|
||||
# @desc sudo systemctl status
|
||||
abbr -a ssct 'sudo systemctl status'
|
||||
# @category Systemctl
|
||||
# @desc sudo systemctl start
|
||||
abbr -a sscs 'sudo systemctl start'
|
||||
# @category Systemctl
|
||||
# @desc sudo systemctl restart
|
||||
abbr -a sscr 'sudo systemctl restart'
|
||||
|
||||
### Alternate command names ###
|
||||
# Expand to the canonical function name so muscle-memory typos still work,
|
||||
# while surfacing the real command instead of silently forwarding to it.
|
||||
# @category Miscellaneous
|
||||
# @desc repo-open
|
||||
abbr -a open-repo repo-open
|
||||
# @category Miscellaneous
|
||||
# @desc open-url
|
||||
abbr -a url-open open-url
|
||||
|
||||
### History Expansions and Substitutions ###
|
||||
abbr -a !^ --position anywhere --function expand_bang_caret
|
||||
abbr -a '!*' --position anywhere --function expand_bang_all
|
||||
abbr -a typo_sub --position anywhere --regex '\^([^^]+)\^([^^]*)' --function expand_typo_sub
|
||||
abbr -a bang_string --position anywhere --regex '![\w.-]+' --function expand_bang_string
|
||||
abbr -a bang_search --position anywhere --regex '!\?[\w.-]+\??' --function expand_bang_search
|
||||
abbr -a bang_minus_n --position anywhere --regex '!-(\d+)' --function expand_bang_minus_n
|
||||
# Bash-style history expansion is opinionated (C3 overrides), gated atomically
|
||||
# with conf.d/tricks.fish, conf.d/puffer.fish, and functions/expand_*.fish.
|
||||
if __fish_config_op_enabled (status basename) abbr-overrides
|
||||
# @category History Expansion
|
||||
# @name !^
|
||||
# @desc Expand to the first argument of the previous command
|
||||
abbr -a !^ --position anywhere --function expand_bang_caret
|
||||
# @category History Expansion
|
||||
# @name !*
|
||||
# @desc Expand to all arguments of the previous command
|
||||
abbr -a '!*' --position anywhere --function expand_bang_all
|
||||
# @category History Expansion
|
||||
# @name ^old^new^
|
||||
# @desc Interactive typo substitution (replace 'old' with 'new' in previous command)
|
||||
abbr -a typo_sub --position anywhere --regex '\^([^^]+)\^([^^]*)' --function expand_typo_sub
|
||||
# @category History Expansion
|
||||
# @name !string
|
||||
# @desc Expand to the most recent command starting with 'string'
|
||||
abbr -a bang_string --position anywhere --regex '![\w.-]+' --function expand_bang_string
|
||||
# @category History Expansion
|
||||
# @name !?string?
|
||||
# @desc Expand to the most recent command containing 'string'
|
||||
abbr -a bang_search --position anywhere --regex '!\?[\w.-]+\??' --function expand_bang_search
|
||||
# @category History Expansion
|
||||
# @name !-n
|
||||
# @desc Expand to the nth-previous command
|
||||
abbr -a bang_minus_n --position anywhere --regex '!-(\d+)' --function expand_bang_minus_n
|
||||
end
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# ╭──────────────────────────────────────────────────────────╮
|
||||
# │ Auto-Pull (C2 — Autoexec) │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
#
|
||||
# Background, fast-forward-only `git pull` for opted-in repositories. Fires
|
||||
# when the working directory enters the fish-config repo (always covered as a
|
||||
# baseline) or any repository registered via the `auto-pull` command. The
|
||||
# actual sync is delegated to `_auto_pull_sync`, which only ever fast-forwards
|
||||
# a clean repo — see that function for the full safety contract.
|
||||
#
|
||||
# Manage the registry with: auto-pull add / remove / list / status
|
||||
|
||||
# C2 guard: when auto-execution is disabled, do not register the handler.
|
||||
__fish_config_op_enabled (status basename); or exit
|
||||
|
||||
# COMPONENT
|
||||
# autoexec/sync
|
||||
#
|
||||
# SYNOPSIS
|
||||
# __auto_pull_on_pwd (event handler, --on-variable PWD)
|
||||
#
|
||||
# DESCRIPTION
|
||||
# On every directory change, checks whether the new $PWD is inside a
|
||||
# registered repository (or the fish-config baseline) and, if so, kicks a
|
||||
# background fast-forward. A throttle global ensures it fires once per
|
||||
# repository entry rather than on every sub-directory change.
|
||||
function __auto_pull_on_pwd --on-variable PWD
|
||||
set -q __fish_config_dir; or set -g __fish_config_dir $XDG_CONFIG_HOME/fish
|
||||
set -q __fish_user_dots_path; or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
|
||||
set -l list "$__fish_user_dots_path/auto-pull.list"
|
||||
|
||||
# Candidate roots: the fish-config repo plus the user's registry.
|
||||
set -l roots $__fish_config_dir
|
||||
test -r "$list"; and set -a roots (command cat "$list" 2>/dev/null)
|
||||
|
||||
# Find the registered root containing $PWD (exact match or a sub-directory).
|
||||
set -l hit
|
||||
for r in $roots
|
||||
test -n "$r"; or continue
|
||||
if test "$PWD" = "$r"; or string match -q -- "$r/*" "$PWD"
|
||||
set hit "$r"
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# Outside every registered repo: clear the throttle so re-entry re-syncs.
|
||||
if test -z "$hit"
|
||||
set -e __auto_pull_last
|
||||
return
|
||||
end
|
||||
|
||||
# Already synced for this repo entry — skip until we leave and return.
|
||||
test "$hit" = "$__auto_pull_last"; and return
|
||||
set -g __auto_pull_last "$hit"
|
||||
|
||||
# Background fast-forward. A --no-config child sources just the worker so
|
||||
# it stays fast and free of shell side-effects; real `git`, no shadows.
|
||||
set -l worker "$__fish_config_dir/functions/_auto_pull_sync.fish"
|
||||
test -r "$worker"; or return
|
||||
fish --no-config -c 'source $argv[1]; _auto_pull_sync $argv[2]' -- "$worker" "$hit" &
|
||||
disown 2>/dev/null
|
||||
end
|
||||
@@ -1,5 +1,12 @@
|
||||
status is-interactive || exit
|
||||
|
||||
# COMPONENT
|
||||
# overrides/key-bindings
|
||||
|
||||
# Local modification: opinionated guard (AGENTS.md Task #3). Bracket
|
||||
# auto-pairing intercepts single-character input, classified as C3 overrides.
|
||||
__fish_config_op_enabled (status basename) || exit
|
||||
|
||||
set --global autopair_left "(" "[" "{" '"' "'"
|
||||
set --global autopair_right ")" "]" "}" '"' "'"
|
||||
set --global autopair_pairs "()" "[]" "{}" '""' "''"
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# overrides/key-bindings
|
||||
|
||||
# Provides bash-style history expansion functions for abbreviations.
|
||||
# These functions are gated by the C3 overrides switch.
|
||||
|
||||
# Execute expand_bang_all
|
||||
function expand_bang_all --description 'Execute expand_bang_all'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
set -l token $argv[1]
|
||||
if test -z "$token"; set token (commandline -t); end
|
||||
|
||||
set -l tokens (string split -n " " -- $history[1])
|
||||
if test (count $tokens) -gt 1
|
||||
echo -- (string join " " -- $tokens[2..-1])
|
||||
else
|
||||
echo -- $token
|
||||
end
|
||||
end
|
||||
|
||||
# Execute expand_bang_caret
|
||||
function expand_bang_caret --description 'Execute expand_bang_caret'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
# Split the last history item into a list
|
||||
set -l tokens (string split -n ' ' -- $history[1])
|
||||
# tokens[1] is the command, tokens[2] is the first argument
|
||||
if set -q tokens[2]
|
||||
echo -- $tokens[2]
|
||||
end
|
||||
end
|
||||
|
||||
# Execute expand_bang_minus_n
|
||||
function expand_bang_minus_n --description 'Execute expand_bang_minus_n'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
set -l token $argv[1]
|
||||
if test -z "$token"; set token (commandline -t); end
|
||||
|
||||
# Extract the number from the regex match
|
||||
if string match -qr '!-(\d+)' -- "$token"
|
||||
set -l n (string match -r '!-(\d+)' -- "$token")[2]
|
||||
|
||||
if test (count $history) -ge $n
|
||||
echo -- $history[$n]
|
||||
else
|
||||
echo -- $token
|
||||
end
|
||||
else
|
||||
echo -- $token
|
||||
end
|
||||
end
|
||||
|
||||
# Execute expand_bang_search
|
||||
function expand_bang_search --description 'Execute expand_bang_search'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
set -l token $argv[1]
|
||||
if test -z "$token"
|
||||
set token (commandline -t)
|
||||
end
|
||||
|
||||
# Extract query: looks for text after !? and before an optional ?
|
||||
set -l query (string match -r '!\?([^?]+)' -- $token)[2]
|
||||
|
||||
if test -n "$query"
|
||||
# Search history for a match anywhere in the command
|
||||
set -l match (builtin history search --contains --max=1 -- $query)
|
||||
|
||||
if test -n "$match"
|
||||
echo -- $match
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
echo -- $token
|
||||
end
|
||||
|
||||
# Execute expand_bang_string
|
||||
function expand_bang_string --description 'Execute expand_bang_string'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
# Fish 4.x passes the matched token as argv[1]
|
||||
set -l token $argv[1]
|
||||
if test -z "$token"
|
||||
set token (commandline -t)
|
||||
end
|
||||
|
||||
# Remove the '!' to get the search query
|
||||
set -l query (string sub -s 2 -- $token)
|
||||
|
||||
if test -n "$query"
|
||||
# Search history for a prefix match
|
||||
set -l match (builtin history search --prefix --max=1 -- $query)
|
||||
|
||||
if test -n "$match"
|
||||
echo -- $match
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
# If no match or empty query, return the token so it doesn't vanish
|
||||
echo -- $token
|
||||
end
|
||||
|
||||
# Execute expand_typo_sub
|
||||
function expand_typo_sub --description 'Execute expand_typo_sub'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
# In newer Fish, the matched token is often passed as $argv[1]
|
||||
# if the abbr is set up correctly. We'll fallback to commandline just in case.
|
||||
set -l last_cmd $history[1]
|
||||
set -l current_token $argv[1]
|
||||
if test -z "$current_token"
|
||||
set current_token (commandline -t)
|
||||
end
|
||||
|
||||
if string match -qr '\^([^^]+)\^([^^]*)' -- "$current_token"
|
||||
set -l captured (string match -r '\^([^^]+)\^([^^]*)' -- "$current_token")
|
||||
set -l old $captured[2]
|
||||
set -l new $captured[3]
|
||||
|
||||
if test -n "$old"
|
||||
# Using -- to ensure strings starting with '-' aren't treated as flags
|
||||
echo -- (string replace -a -- "$old" "$new" "$last_cmd")
|
||||
end
|
||||
else
|
||||
# Return the token itself so it doesn't vanish
|
||||
echo -- "$current_token"
|
||||
end
|
||||
end
|
||||
@@ -19,11 +19,18 @@
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
# COMPONENT
|
||||
# integrations/notifications
|
||||
|
||||
if not status is-interactive
|
||||
exit
|
||||
end
|
||||
|
||||
# Local modification: opinionated guard (AGENTS.md Task #3). Desktop
|
||||
# notifications assume a graphical session, classified as C4 integrations.
|
||||
__fish_config_op_enabled (status basename); or exit
|
||||
|
||||
set -g __done_version 1.19.1
|
||||
|
||||
function __done_run_powershell_script
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# ╭──────────────────────────────────────────────────────────╮
|
||||
# │ First-Run Initialization │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
#
|
||||
# Runs exactly once on the first interactive fish session after install.
|
||||
# To reset for testing, run: set -Ue __fish_config_first_run_complete
|
||||
#
|
||||
# COMPONENT
|
||||
# site first-run-greeting: greeting/first-run
|
||||
# site first-run-bootstrap: autoexec/plugin-management
|
||||
|
||||
# Exit early in non-interactive shells (scripts, completions, subshells)
|
||||
if not status is-interactive
|
||||
return
|
||||
end
|
||||
|
||||
# Skip if this shell has already been initialized
|
||||
if set -q __fish_config_first_run_complete
|
||||
return
|
||||
end
|
||||
|
||||
# Set the flag immediately — before actions — so a mid-run crash doesn't
|
||||
# leave the shell in a state that re-triggers everything next session.
|
||||
set -U __fish_config_first_run_complete 1
|
||||
|
||||
# ──────────────────────────── Man page symlink ──────────────────────────
|
||||
# Install fish-config.1 into the user man database once, like an install step.
|
||||
# Unconditional: standard enough that no category gate is warranted.
|
||||
set -l _man1 ~/.local/share/man/man1
|
||||
set -l _src ~/.config/fish/docs/fish-config.1
|
||||
if test -f $_src; and not test -L $_man1/fish-config.1
|
||||
mkdir -p $_man1
|
||||
ln -sf $_src $_man1/fish-config.1
|
||||
end
|
||||
|
||||
# ──────────────────────────── Welcome message ───────────────────────────
|
||||
# Printing a first-run welcome banner is opinionated (C6 greeting). The
|
||||
# first-run state variable is already set unconditionally above, so
|
||||
# disabling the greeting never re-triggers this file.
|
||||
if __fish_config_op_enabled (status basename) first-run-greeting
|
||||
echo ""
|
||||
echo " Welcome to your fish shell configuration!"
|
||||
echo " Run 'help config' for offline documentation."
|
||||
echo " Run 'fish-deps' to check and install dependencies."
|
||||
echo ""
|
||||
end
|
||||
|
||||
# ─────────────────────── Opinionated auto-exec guard ────────────────────
|
||||
# Startup side-effects below (Fisher curl, fisher update, theme apply) are
|
||||
# opinionated (C2 auto-execution). The first-run state variable is already
|
||||
# set above either way, so disabling auto-exec never re-triggers this file.
|
||||
if not __fish_config_op_enabled (status basename) first-run-bootstrap
|
||||
return
|
||||
end
|
||||
|
||||
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
|
||||
if not type -q fisher
|
||||
echo " [first-run] Installing Fisher plugin manager..."
|
||||
if curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
|
||||
echo " [first-run] Fisher installed."
|
||||
if not fisher update 2>/dev/null
|
||||
echo " [first-run] Fisher update failed — run 'fisher update' manually." >&2
|
||||
end
|
||||
else
|
||||
echo " [first-run] Fisher install failed — run 'fisher update' manually." >&2
|
||||
end
|
||||
end
|
||||
|
||||
# ───────────────────────────── Apply theme ──────────────────────────────
|
||||
# Catppuccin Mocha theme ships with this config in themes/; it is always available.
|
||||
if not fish_config theme choose "Catppuccin Mocha" 2>/dev/null
|
||||
echo " [first-run] Could not apply Catppuccin Mocha theme — set manually with 'fish_config theme choose'." >&2
|
||||
end
|
||||
@@ -0,0 +1,70 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# ╭──────────────────────────────────────────────────────────╮
|
||||
# │ help config wrapper │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/shell-tools
|
||||
#
|
||||
# SYNOPSIS
|
||||
# help [topic] [sub-topic...]
|
||||
# help config [section] [-w|--html] [-m|--man] [-h|--help]
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Wraps the built-in Fish help command. Intercepts the specific topic
|
||||
# "config" and forwards any subsequent sub-topics/arguments straight to the
|
||||
# custom 'config-help' utility. For all other topics, it forwards the
|
||||
# arguments intact to the original, built-in system help utility.
|
||||
#
|
||||
# When the first argument is "config", the following flags are recognized
|
||||
# and delegated to 'config-help':
|
||||
# -w, --html Open the offline HTML docs in the default browser
|
||||
# -m, --man Open the compiled man page via man -l
|
||||
# -h, --help Print config-help usage reference
|
||||
#
|
||||
# Flags that appear WITHOUT a leading "config" argument — including
|
||||
# -h/--help — are forwarded unchanged to the native Fish help command, so
|
||||
# built-in behavior is never overridden for non-config topics.
|
||||
#
|
||||
# NOTES
|
||||
# To prevent infinite recursion, the wrapper backs up the native help
|
||||
# function as '__original_help' before shadowing it. This MUST happen from
|
||||
# conf.d, not functions/help.fish: as of Fish 4.x the native help is
|
||||
# embedded in the binary (embedded:functions/help.fish) with no on-disk
|
||||
# file to source, and a functions/help.fish autoload shadow makes the name
|
||||
# 'help' resolve to our own wrapper (or nothing, mid-autoload) — so the
|
||||
# backup could never capture the real help. Sourced here at startup, before
|
||||
# any shadow exists, `functions -c help` copies the embedded original.
|
||||
#
|
||||
# EXAMPLE
|
||||
# help config keys # → config-help keys
|
||||
# help config --html # opens the offline HTML docs in the browser
|
||||
# help config keys --man # opens the compiled man page via man -l
|
||||
# help string # forwards to native fish docs for 'string'
|
||||
|
||||
# --- Initialization & Backup ---
|
||||
# Copy the native (embedded) help to __original_help before we shadow it.
|
||||
if not functions -q __original_help
|
||||
functions -c help __original_help
|
||||
end
|
||||
|
||||
# --- Wrapper Definition ---
|
||||
function help --wraps help --description "Custom wrapper to intercept 'help config'"
|
||||
# Opinionated guard (C1): fall back to the native fish help when disabled.
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
__original_help $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
if test "$argv[1]" = config
|
||||
# All arguments after 'config' — including flags (-w/--html, -m/--man,
|
||||
# -h/--help) and section keywords — are forwarded to config-help.
|
||||
# Flags are only intercepted here when 'config' is the first argument,
|
||||
# so native fish help flags are never shadowed for other topics.
|
||||
config-help $argv[2..]
|
||||
else
|
||||
__original_help $argv
|
||||
end
|
||||
end
|
||||
@@ -8,6 +8,9 @@
|
||||
# This file defines custom key bindings for the Fish shell.
|
||||
# It is sourced by Fish on startup.
|
||||
|
||||
# COMPONENT
|
||||
# overrides/key-bindings
|
||||
|
||||
# ────────────────── Bind Prewious Path Head to Ctrl+G ─────────────────
|
||||
# Bindings to insert the previous path head into the command line
|
||||
# Behaves like `!$:h` does in bash
|
||||
@@ -46,6 +49,14 @@
|
||||
|
||||
function fish_user_key_bindings
|
||||
|
||||
# Custom key chords are opinionated (C3 overrides); skip them entirely
|
||||
# when overrides are disabled so stock bindings remain untouched.
|
||||
# NOTE: (status basename), not (status current-function) -- this guard
|
||||
# lives inside fish's own reserved fish_user_key_bindings function, whose
|
||||
# name is not this file's identity; the registry key is this file's
|
||||
# bare basename, key_bindings.
|
||||
__fish_config_op_enabled (status basename); or return
|
||||
|
||||
# ───────────────────────────── Set Bindings ─────────────────────────────
|
||||
#
|
||||
# Set Emacs mode bindings:
|
||||
@@ -54,7 +65,8 @@ function fish_user_key_bindings
|
||||
bind ctrl-alt-u _replace_command_token
|
||||
type -q qalc && bind ctrl-alt-= _qalc_eval
|
||||
bind ctrl-enter _smart_execute
|
||||
bind @@ __fzf_inline_picker
|
||||
bind ctrl-right nextd-or-forward-word
|
||||
bind \e\[1\;5C nextd-or-forward-word
|
||||
|
||||
# Set bindings for all Vi modes:
|
||||
# 'default' is Vi-Command, 'insert' is Vi-Insert, 'visual' is Vi-Visual
|
||||
@@ -64,6 +76,17 @@ function fish_user_key_bindings
|
||||
bind --mode $mode ctrl-alt-u _replace_command_token
|
||||
type -q qalc && bind --mode $mode ctrl-alt-= _qalc_eval
|
||||
bind --mode $mode ctrl-enter _smart_execute
|
||||
bind --mode $mode @@ __fzf_inline_picker
|
||||
bind --mode $mode ctrl-right nextd-or-forward-word
|
||||
bind --mode $mode \e\[1\;5C nextd-or-forward-word
|
||||
end
|
||||
|
||||
# @ is Emacs/Vi-insert only. Emacs bindings and Vi's "default" (normal)
|
||||
# mode share the same bind_mode name, so a mode-less `bind @` would also
|
||||
# land in Vi normal mode, turning its current no-op @ into a self-insert.
|
||||
# Register the mode-less form only when Vi bindings aren't the active
|
||||
# base, and rely on the explicit insert-mode bind otherwise.
|
||||
if test "$fish_key_bindings" != fish_vi_key_bindings
|
||||
bind @ __fzf_inline_picker
|
||||
end
|
||||
bind --mode insert @ __fzf_inline_picker
|
||||
end
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# logging/terminal-capture
|
||||
|
||||
#
|
||||
# C5 — Logging & Capture: a non-blocking, per-session reminder shown inside Kitty
|
||||
# when the fish-config scrollback watcher is not yet set up. It never blocks the
|
||||
# shell; it simply prints how to enable or silence it. The notice stops once the
|
||||
# user runs `kitty-logging install` (a watcher line then exists in kitty.conf) or
|
||||
# `kitty-logging dismiss` (sets the universal variable below).
|
||||
|
||||
status is-interactive; or exit
|
||||
type -q kitty; or exit
|
||||
set -q KITTY_WINDOW_ID; or exit
|
||||
__fish_config_op_enabled (status basename); or exit
|
||||
__fish_variable_check __fish_config_kitty_watcher_dismissed; and exit
|
||||
__kitty_logging_has_watcher; and exit
|
||||
|
||||
set_color --bold yellow
|
||||
echo "Kitty session logging is available but not set up."
|
||||
set_color normal
|
||||
echo " Enable: kitty-logging install"
|
||||
echo " Silence: kitty-logging dismiss"
|
||||
@@ -0,0 +1,27 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# C5 — Logging & Capture: registers --on-variable event handlers at shell
|
||||
# startup so that changes to __fish_config_op_logging or the master
|
||||
# __fish_config_opinionated take effect immediately in every running shell.
|
||||
# Also calls __fish_config_sync_logging once to reconcile sentinel-file and
|
||||
# wrapper state with any variable values that were pre-set before this shell
|
||||
# started.
|
||||
#
|
||||
# These functions must be defined in conf.d (not functions/) because fish
|
||||
# only autoloads from functions/ on explicit call — event handlers that live
|
||||
# solely in functions/ are never registered and their --on-variable triggers
|
||||
# never fire.
|
||||
|
||||
function __fish_config_logging_changed --on-variable __fish_config_op_logging \
|
||||
--description 'C5 event handler: sync logging state when __fish_config_op_logging changes'
|
||||
__fish_config_sync_logging
|
||||
end
|
||||
|
||||
function __fish_config_opinionated_changed --on-variable __fish_config_opinionated \
|
||||
--description 'C5 event handler: sync logging state when master opinionated switch changes'
|
||||
__fish_config_sync_logging
|
||||
end
|
||||
|
||||
# Sync once at startup so pre-set variable values take effect without a re-set
|
||||
__fish_config_sync_logging
|
||||
@@ -2,15 +2,34 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Generates ~/.local/bin/paru on first run (and on version bump) when
|
||||
# /usr/bin/paru is installed. The wrapper tees paru output to a
|
||||
# timestamped log file and prunes old logs, mirroring smart_exit behavior.
|
||||
# paru is installed. The wrapper runs paru in a PTY so progress
|
||||
# bars are preserved, renders the captured animation to a clean static log
|
||||
# (via scripts/clean_progress_log.py), and prunes old logs.
|
||||
|
||||
set -l _paru_real /usr/bin/paru
|
||||
# COMPONENT
|
||||
# site paru-autoexec: autoexec/pkg-wrappers
|
||||
# site paru-logging: logging/pkg-logs
|
||||
|
||||
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
|
||||
# Wrapper generation is also gated by C5 (Logging & Capture).
|
||||
__fish_config_op_enabled (status basename) paru-autoexec; or return
|
||||
|
||||
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off
|
||||
if not __fish_config_op_enabled (status basename) paru-logging
|
||||
if test -f "$HOME/.local/bin/paru"
|
||||
and grep -q "# paru-wrapper-version:" "$HOME/.local/bin/paru" 2>/dev/null
|
||||
rm -f "$HOME/.local/bin/paru"
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# Resolve the real paru binary, skipping our own shim (never /usr/bin-assumed).
|
||||
set -l _paru_real (__fish_real_command paru)
|
||||
set -l _paru_wrapper "$HOME/.local/bin/paru"
|
||||
set -l _paru_wrapper_version 1
|
||||
set -l _paru_wrapper_version 6
|
||||
|
||||
# Skip entirely if the real paru binary isn't present
|
||||
test -x $_paru_real; or return
|
||||
test -x "$_paru_real"; or return
|
||||
|
||||
# Check if wrapper already exists at the expected version
|
||||
if test -f $_paru_wrapper
|
||||
@@ -25,14 +44,31 @@ printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
"# paru-wrapper-version: $_paru_wrapper_version" \
|
||||
'# Auto-generated by conf.d/paru-wrapper.fish — do not edit by hand.' \
|
||||
'# Tees paru output to a timestamped log file and prunes old ones.' \
|
||||
'set -o pipefail' \
|
||||
'# Runs paru in a PTY via script(1) so progress bars are preserved on screen,' \
|
||||
'# then renders the captured terminal animation to a clean static log.' \
|
||||
'' \
|
||||
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
|
||||
'mkdir -p "$log_dir"' \
|
||||
'log_file="$log_dir/paru_$(date +%Y-%m-%d_%H-%M-%S).log"' \
|
||||
'' \
|
||||
'/usr/bin/paru "$@" 2>&1 | tee "$log_file"' \
|
||||
'# Build a safely-quoted command string for script(1).' \
|
||||
'# script(1) allocates a PTY so paru detects a real terminal and shows progress.' \
|
||||
"cmd_str=\"$_paru_real\"" \
|
||||
'for arg in "$@"; do' \
|
||||
' cmd_str+=" $(printf '"'"'%q'"'"' "$arg")"' \
|
||||
'done' \
|
||||
'script -q -e -c "$cmd_str" "$log_file"' \
|
||||
'exit_code=$?' \
|
||||
'' \
|
||||
'# Render the captured terminal animation (progress bars repaint in place via' \
|
||||
'# cursor moves) down to its final static frame, preserving ANSI color. Falls' \
|
||||
'# back to dropping only the script(1) header/footer when python3 is missing.' \
|
||||
'cleaner="${XDG_CONFIG_HOME:-$HOME/.config}/fish/scripts/clean_progress_log.py"' \
|
||||
'if command -v python3 >/dev/null 2>&1 && [[ -f "$cleaner" ]]; then' \
|
||||
' python3 "$cleaner" < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
|
||||
'else' \
|
||||
' sed -i "/^Script \(started\|done\) on /d" "$log_file" 2>/dev/null || true' \
|
||||
'fi' \
|
||||
'' \
|
||||
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
|
||||
'mapfile -t logs < <(ls -1t "$log_dir"/paru_*.log 2>/dev/null)' \
|
||||
@@ -40,6 +76,8 @@ printf '%s\n' \
|
||||
'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \
|
||||
' rm -f "${logs[$i]}"' \
|
||||
'done' \
|
||||
'' \
|
||||
'exit $exit_code' \
|
||||
> $_paru_wrapper
|
||||
|
||||
chmod +x $_paru_wrapper
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
status is-interactive || exit
|
||||
|
||||
# COMPONENT
|
||||
# overrides/key-bindings
|
||||
|
||||
# Local modification: opinionated guard (AGENTS.md Task #3). Puffer's key
|
||||
# intercepts are part of the bang-bang system, gated atomically under C3
|
||||
# overrides with conf.d/tricks.fish, conf.d/abbr.fish, and expand_*.fish.
|
||||
__fish_config_op_enabled (status basename) || exit
|
||||
|
||||
function _puffer_fish_key_bindings --on-variable fish_key_bindings
|
||||
set -l modes
|
||||
if test "$fish_key_bindings" = fish_default_key_bindings
|
||||
@@ -8,9 +16,21 @@ function _puffer_fish_key_bindings --on-variable fish_key_bindings
|
||||
set modes insert default
|
||||
end
|
||||
|
||||
# @category History Expansion
|
||||
# @name !.
|
||||
# @desc Expand .. to ../.. and so on
|
||||
bind --mode $modes[1] '.' _puffer_fish_expand_dot
|
||||
# @category History Expansion
|
||||
# @name !!
|
||||
# @desc Expand to the previous command
|
||||
bind --mode $modes[1] '!' _puffer_fish_expand_bang
|
||||
# @category History Expansion
|
||||
# @name !$
|
||||
# @desc Expand to the last argument of the previous command
|
||||
bind --mode $modes[1] '$' _puffer_fish_expand_buck
|
||||
# @category History Expansion
|
||||
# @name !*
|
||||
# @desc Expand to all arguments of the previous command
|
||||
bind --mode $modes[1] '*' _puffer_fish_expand_star
|
||||
bind --mode $modes[2] --erase '.' '!' '$' '*'
|
||||
end
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# ╭──────────────────────────────────────────────────────────╮
|
||||
# │ Sponge Privacy Pattern Registration │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
#
|
||||
# Two-layer approach to keeping credentials out of shell history:
|
||||
#
|
||||
# Layer 1 — Static patterns (registered as universal, persistent):
|
||||
# Covers structural signatures: auth flags, env var assignments,
|
||||
# credential-bearing URLs, Authorization headers, sshpass, etc.
|
||||
# Patterns are added idempotently; user additions are preserved.
|
||||
#
|
||||
# Layer 2 — Dynamic secret values (registered as session globals):
|
||||
# On the first prompt (after secrets.fish has loaded), reads the
|
||||
# literal values of all exported variables whose names indicate
|
||||
# credentials (TOKEN, PASSWORD, SECRET, KEY, etc.) and adds them
|
||||
# as a session-scoped pattern overlay. Refreshes automatically
|
||||
# each login, so rotated tokens never leave stale patterns behind.
|
||||
#
|
||||
# Layer 3 — Per-command filter (sponge_filter_secrets):
|
||||
# Catches mid-session variables set after login — e.g. a token
|
||||
# exported interactively or sourced from a project .env file.
|
||||
#
|
||||
# To add your own persistent patterns:
|
||||
# set -U -a sponge_regex_patterns 'your-regex-here'
|
||||
|
||||
if not status is-interactive
|
||||
return
|
||||
end
|
||||
|
||||
# Only register if sponge is loaded
|
||||
if not set -q sponge_version
|
||||
return
|
||||
end
|
||||
|
||||
# ──────────────────── Layer 1: Static patterns ────────────────────
|
||||
|
||||
set -l _privacy_patterns
|
||||
|
||||
# Common auth flags with values: --password x, --token x, --passphrase x, --api-key x
|
||||
# Use \- to avoid the pattern string starting with --, which string match
|
||||
# would misinterpret as an unknown option flag.
|
||||
set -a _privacy_patterns '\-\-(?:password|passwd|passphrase|token|secret|api[-_]key)(?:\s+|=)\S+'
|
||||
|
||||
# Inline env var assignments with sensitive names: GITHUB_TOKEN=xxx, MY_API_KEY=abc
|
||||
set -a _privacy_patterns '(?i)\b[A-Z][A-Z0-9_]*(?:PASSWORD|PASSWD|SECRET|TOKEN|API_KEY|PRIVATE_KEY|ACCESS_KEY|AUTH_KEY|CREDENTIAL)[A-Z0-9_]*=\S+'
|
||||
|
||||
# Fish set with sensitive variable names: set -gx GITHUB_TOKEN xxx, set -U MY_SECRET yyy
|
||||
set -a _privacy_patterns '(?i)set\s+-\S+\s+\S*(?:password|passwd|token|secret|api.?key|private.?key|access.?key|credential)\S*\s+\S+'
|
||||
|
||||
# URLs with embedded credentials: https://user:password@host
|
||||
set -a _privacy_patterns 'https?://[^:@\s]+:[^@\s]+@'
|
||||
|
||||
# HTTP Authorization headers: curl -H "Authorization: Bearer xxx"
|
||||
set -a _privacy_patterns 'curl\s.*[Aa]uthorization:'
|
||||
|
||||
# Basic auth flags: curl -u user:pass, wget --user user --password pass
|
||||
set -a _privacy_patterns '(?:curl|wget)\s.*(?:-u|--user)\s+\S+:\S+'
|
||||
|
||||
# sshpass — exposes credentials as a CLI argument by design
|
||||
set -a _privacy_patterns '\bsshpass\b'
|
||||
|
||||
# Docker login with inline password
|
||||
set -a _privacy_patterns 'docker\s+login\s.*(?:-p|--password)\s+\S+'
|
||||
|
||||
# openssl passphrase arguments: -passin pass:xxx, -passout env:VAR
|
||||
set -a _privacy_patterns 'openssl\s.*-pass(?:in|out)\s+\S+'
|
||||
|
||||
# Remove any previously stored patterns that begin with -- ; string match
|
||||
# passes patterns before its own -- sentinel and would treat them as flags.
|
||||
for _i in (seq (count $sponge_regex_patterns) -1 1)
|
||||
if string match --quiet -- '--*' $sponge_regex_patterns[$_i]
|
||||
set -Ue sponge_regex_patterns[$_i]
|
||||
end
|
||||
end
|
||||
|
||||
# Idempotent registration into universal sponge_regex_patterns
|
||||
for _pattern in $_privacy_patterns
|
||||
if not contains -- $_pattern $sponge_regex_patterns
|
||||
set -U -a sponge_regex_patterns $_pattern
|
||||
end
|
||||
end
|
||||
|
||||
# ──────────── Layer 2: Dynamic secret values (session globals) ────────────
|
||||
|
||||
# Runs once on the first prompt — by which point config.fish and secrets.fish
|
||||
# have fully loaded, so all secret env vars are in scope.
|
||||
# Builds a session-scoped global that combines the universal static patterns
|
||||
# with the literal values of any credential-holding env vars. Globals shadow
|
||||
# universals in Fish, so the combined list is what sponge sees for this session.
|
||||
function __sponge_register_secret_values --on-event fish_prompt
|
||||
functions --erase __sponge_register_secret_values # run exactly once
|
||||
|
||||
set -l secret_values
|
||||
|
||||
# Base credential-name tokens, plus any user-supplied extras from
|
||||
# __fish_sponge_extra_sensitive (set via config-settings → Sponge page).
|
||||
set -l _sensitive_names \
|
||||
TOKEN PASSWORD PASSWD SECRET 'API[_-]KEY' 'PRIVATE[_-]KEY' \
|
||||
'ACCESS[_-]KEY' 'AUTH[_-]KEY' CREDENTIAL KOPIA_PASSWORD \
|
||||
$__fish_sponge_extra_sensitive
|
||||
set -l _sensitive_alt (string join '|' $_sensitive_names)
|
||||
|
||||
# --entire returns the full matching variable NAME (e.g. GITHUB_TOKEN), not
|
||||
# just the matched token substring (TOKEN) — required so $$var below
|
||||
# dereferences the real variable instead of an unset partial name.
|
||||
set -l sensitive_vars (set --names --export | string match --regex --entire -- \
|
||||
"(?i)(?:$_sensitive_alt)")
|
||||
|
||||
for var in $sensitive_vars
|
||||
# Take only the first element — array vars yield multiple values.
|
||||
set -l value $$var[1]
|
||||
# If the var is unset or holds an empty list, value has no elements;
|
||||
# set -q catches that before string length receives zero arguments.
|
||||
set -q value[1]; or continue
|
||||
test (string length -- $value) -gt 8; or continue
|
||||
string match --quiet --regex '^[/~]' -- $value; and continue
|
||||
set -a secret_values (string escape --style=regex -- $value)
|
||||
end
|
||||
|
||||
if test (count $secret_values) -gt 0
|
||||
# Merge static universals + dynamic values into a session global
|
||||
set -g sponge_regex_patterns $sponge_regex_patterns $secret_values
|
||||
end
|
||||
end
|
||||
|
||||
# ──────────── Layer 3: Mid-session filter (sponge_filter_secrets) ─────────
|
||||
|
||||
# Catches credentials in variables exported after login (e.g. project .env files).
|
||||
# Only register if not already in sponge_filters.
|
||||
if functions --query sponge_filter_secrets
|
||||
if not contains -- sponge_filter_secrets $sponge_filters
|
||||
set -U -a sponge_filters sponge_filter_secrets
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,17 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# overrides/prompt
|
||||
|
||||
#
|
||||
# Defines fish_prompt only when starship is installed.
|
||||
# Without starship, fish's built-in prompt already emits OSC 133;A
|
||||
# on the prompt line itself, so no wrapper is needed.
|
||||
|
||||
# Replacing the prompt is opinionated (C3 overrides)
|
||||
__fish_config_op_enabled (status basename); or return
|
||||
|
||||
type -q starship; or return
|
||||
|
||||
function fish_prompt
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# overrides/prompt
|
||||
|
||||
#
|
||||
# ╭──────────────────────────────────────────────────────────╮
|
||||
# │ Fish Theme │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
# Catppuccin Mocha
|
||||
|
||||
# Forcing theme colors and $FZF_DEFAULT_OPTS is opinionated (C3 overrides).
|
||||
# The FZF variable is universal, so clean up our Catppuccin value if it
|
||||
# lingers from a session where overrides were still enabled.
|
||||
if not __fish_config_op_enabled (status basename)
|
||||
if set -q FZF_DEFAULT_OPTS; and string match -q '*#1E1E2E*' -- "$FZF_DEFAULT_OPTS"
|
||||
set --erase FZF_DEFAULT_OPTS
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# ────────────────────── Syntax highlighting colors ──────────────────────
|
||||
set --global fish_color_autosuggestion 6c7086
|
||||
set --global fish_color_cancel f38ba8
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# logging/multiplexer-capture
|
||||
|
||||
#
|
||||
# C5 — Logging & Capture: starts a pipe-pane log for the current tmux pane
|
||||
# when fish launches inside a tmux session. Each fish shell gets its own
|
||||
# timestamped log file in SCROLLBACK_HISTORY_DIR (default: ~/.terminal_history).
|
||||
# Naming: tmux_<session>-w<window>-p<pane>_YYYY-MM-DD_HH-MM-SS.log
|
||||
|
||||
__fish_config_op_enabled (status basename); or exit
|
||||
status is-interactive; or exit
|
||||
type -q tmux; or exit
|
||||
set -q TMUX; or exit
|
||||
|
||||
_tmux_pipe_log
|
||||
+104
-36
@@ -7,6 +7,11 @@
|
||||
# │ system aliases, and history/backup utilities │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
|
||||
# COMPONENT
|
||||
# site aliases-tricks: aliases/filesystem
|
||||
# site tricks-manpager: overrides/environment
|
||||
# site tricks-bang: overrides/key-bindings
|
||||
|
||||
## Environment setup
|
||||
# Apply .profile: use this to put fish compatible .profile stuff in
|
||||
if test -f ~/.fish_profile
|
||||
@@ -17,8 +22,14 @@ end
|
||||
fish_add_path ~/.local/bin
|
||||
fish_add_path ~/Applications/depot_tools
|
||||
|
||||
# Expose user-local man pages
|
||||
if not contains ~/.local/share/man $MANPATH
|
||||
set -gx MANPATH ~/.local/share/man $MANPATH
|
||||
end
|
||||
|
||||
# Format man pages using bat (only if bat is installed)
|
||||
if type -q bat
|
||||
# Overriding $MANPAGER is opinionated (C3 overrides)
|
||||
if type -q bat; and __fish_config_op_enabled (status basename) tricks-manpager
|
||||
set -gx MANROFFOPT -c
|
||||
set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'"
|
||||
end
|
||||
@@ -29,38 +40,58 @@ set -gx __done_notification_urgency_level low
|
||||
|
||||
## Functions
|
||||
# Functions needed for !! and !$ https://github.com/oh-my-fish/plugin-bang-bang
|
||||
function __history_previous_command
|
||||
switch (commandline -t)
|
||||
case "!"
|
||||
commandline -t $history[1]
|
||||
commandline -f repaint
|
||||
case "*"
|
||||
commandline -i !
|
||||
# The bang-bang system is opinionated (C3 overrides) and is gated atomically
|
||||
# here, in conf.d/abbr.fish, conf.d/puffer.fish, and functions/expand_*.fish.
|
||||
if __fish_config_op_enabled (status basename) tricks-bang
|
||||
function __history_previous_command
|
||||
switch (commandline -t)
|
||||
case "!"
|
||||
commandline -t $history[1]
|
||||
commandline -f repaint
|
||||
case "*"
|
||||
commandline -i !
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function __history_previous_command_arguments
|
||||
switch (commandline -t)
|
||||
case "!"
|
||||
commandline -t ""
|
||||
commandline -f history-token-search-backward
|
||||
case "*"
|
||||
commandline -i '$'
|
||||
function __history_previous_command_arguments
|
||||
switch (commandline -t)
|
||||
case "!"
|
||||
commandline -t ""
|
||||
commandline -f history-token-search-backward
|
||||
case "*"
|
||||
commandline -i '$'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Apply bang-bang key bindings based on current key binding mode
|
||||
if [ "$fish_key_bindings" = fish_vi_key_bindings ]
|
||||
bind -Minsert ! __history_previous_command
|
||||
bind -Minsert '$' __history_previous_command_arguments
|
||||
else
|
||||
bind ! __history_previous_command
|
||||
bind '$' __history_previous_command_arguments
|
||||
# Apply bang-bang key bindings based on current key binding mode
|
||||
if [ "$fish_key_bindings" = fish_vi_key_bindings ]
|
||||
# @category History Expansion
|
||||
# @name !!
|
||||
# @desc Expand to the previous command
|
||||
bind -Minsert ! __history_previous_command
|
||||
# @category History Expansion
|
||||
# @name !$
|
||||
# @desc Expand to the last argument of the previous command
|
||||
bind -Minsert '$' __history_previous_command_arguments
|
||||
else
|
||||
# @category History Expansion
|
||||
# @name !!
|
||||
# @desc Expand to the previous command
|
||||
bind ! __history_previous_command
|
||||
# @category History Expansion
|
||||
# @name !$
|
||||
# @desc Expand to the last argument of the previous command
|
||||
bind '$' __history_previous_command_arguments
|
||||
end
|
||||
end
|
||||
|
||||
# Fish command history override to show timestamps
|
||||
function history
|
||||
builtin history --show-time='%F %T '
|
||||
# Shadowing the history command is opinionated (C1 aliasing); when disabled,
|
||||
# the function is never defined and fish's stock history behavior applies.
|
||||
if __fish_config_op_enabled (status basename) aliases-tricks
|
||||
function history
|
||||
builtin history --show-time='%F %T '
|
||||
end
|
||||
end
|
||||
|
||||
# Quick file backup utility
|
||||
@@ -80,28 +111,65 @@ end
|
||||
## Useful aliases
|
||||
|
||||
# Navigation short-cuts
|
||||
# @category Shell Aliases
|
||||
# @desc cd ..
|
||||
alias ..='cd ..'
|
||||
# @category Shell Aliases
|
||||
# @desc cd ../..
|
||||
alias ...='cd ../..'
|
||||
# @category Shell Aliases
|
||||
# @desc cd ../../..
|
||||
alias ....='cd ../../..'
|
||||
# @category Shell Aliases
|
||||
# @desc cd ../../../..
|
||||
alias .....='cd ../../../..'
|
||||
# @category Shell Aliases
|
||||
# @desc cd ../../../../..
|
||||
alias ......='cd ../../../../..'
|
||||
|
||||
# Tools & Core command color overrides
|
||||
alias dir='dir --color=auto'
|
||||
alias vdir='vdir --color=auto'
|
||||
alias grep='grep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
# Silent flag injection into POSIX tools is opinionated (C1 aliasing)
|
||||
if __fish_config_op_enabled (status basename) aliases-tricks
|
||||
# Tools & Core command color overrides
|
||||
# @category Shell Aliases
|
||||
# @desc dir --color=auto
|
||||
alias dir='dir --color=auto'
|
||||
# @category Shell Aliases
|
||||
# @desc vdir --color=auto
|
||||
alias vdir='vdir --color=auto'
|
||||
# @category Shell Aliases
|
||||
# @desc grep --color=auto
|
||||
alias grep='grep --color=auto'
|
||||
# @category Shell Aliases
|
||||
# @desc fgrep --color=auto
|
||||
alias fgrep='fgrep --color=auto'
|
||||
# @category Shell Aliases
|
||||
# @desc egrep --color=auto
|
||||
alias egrep='egrep --color=auto'
|
||||
|
||||
# Safety aliases (Confirmation before overwriting/deleting)
|
||||
alias cp="cp -i"
|
||||
alias mv="mv -i"
|
||||
# Safety aliases (Confirmation before overwriting/deleting)
|
||||
# @category Shell Aliases
|
||||
# @desc cp -i
|
||||
alias cp="cp -i"
|
||||
# @category Shell Aliases
|
||||
# @desc mv -i
|
||||
alias mv="mv -i"
|
||||
|
||||
# Force wget to resume partial downloads
|
||||
alias wget='wget -c '
|
||||
end
|
||||
|
||||
# Archives and networking short-hands
|
||||
# @category Shell Aliases
|
||||
# @desc tar -acf
|
||||
alias tarnow='tar -acf '
|
||||
# @category Shell Aliases
|
||||
# @desc tar -zxvf
|
||||
alias untar='tar -zxvf '
|
||||
alias wget='wget -c '
|
||||
# @category Shell Aliases
|
||||
# @desc nc termbin.com 9999
|
||||
alias tb='nc termbin.com 9999'
|
||||
|
||||
# System Logs
|
||||
# @category Shell Aliases
|
||||
# @desc journalctl -p 3 -xb
|
||||
alias jctl="journalctl -p 3 -xb"
|
||||
|
||||
@@ -5,6 +5,16 @@
|
||||
# see: https://github.com/ik11235/wakatime.fish
|
||||
###
|
||||
|
||||
# COMPONENT
|
||||
# site wakatime-autoexec: autoexec/telemetry
|
||||
# site wakatime-hook: integrations/notifications
|
||||
|
||||
# Local modification: opinionated guard (AGENTS.md Task #3). WakaTime
|
||||
# reporting is classified under both C2 auto-execution and C4 integrations;
|
||||
# disabling either category skips registering the hook.
|
||||
__fish_config_op_enabled (status basename) wakatime-autoexec; or exit
|
||||
__fish_config_op_enabled (status basename) wakatime-hook; or exit
|
||||
|
||||
function __register_wakatime_fish_before_exec -e fish_postexec
|
||||
if set -q FISH_WAKATIME_DISABLED
|
||||
return 0
|
||||
|
||||
+46
-8
@@ -2,15 +2,34 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Generates ~/.local/bin/yay on first run (and on version bump) when
|
||||
# /usr/bin/yay is installed. The wrapper tees yay output to a
|
||||
# timestamped log file and prunes old logs, mirroring smart_exit behavior.
|
||||
# yay is installed. The wrapper runs yay in a PTY so progress
|
||||
# bars are preserved, renders the captured animation to a clean static log
|
||||
# (via scripts/clean_progress_log.py), and prunes old logs.
|
||||
|
||||
set -l _yay_real /usr/bin/yay
|
||||
# COMPONENT
|
||||
# site yay-autoexec: autoexec/pkg-wrappers
|
||||
# site yay-logging: logging/pkg-logs
|
||||
|
||||
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
|
||||
# Wrapper generation is also gated by C5 (Logging & Capture).
|
||||
__fish_config_op_enabled (status basename) yay-autoexec; or return
|
||||
|
||||
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off
|
||||
if not __fish_config_op_enabled (status basename) yay-logging
|
||||
if test -f "$HOME/.local/bin/yay"
|
||||
and grep -q "# yay-wrapper-version:" "$HOME/.local/bin/yay" 2>/dev/null
|
||||
rm -f "$HOME/.local/bin/yay"
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# Resolve the real yay binary, skipping our own shim (never /usr/bin-assumed).
|
||||
set -l _yay_real (__fish_real_command yay)
|
||||
set -l _yay_wrapper "$HOME/.local/bin/yay"
|
||||
set -l _yay_wrapper_version 1
|
||||
set -l _yay_wrapper_version 6
|
||||
|
||||
# Skip entirely if the real yay binary isn't present
|
||||
test -x $_yay_real; or return
|
||||
test -x "$_yay_real"; or return
|
||||
|
||||
# Check if wrapper already exists at the expected version
|
||||
if test -f $_yay_wrapper
|
||||
@@ -25,14 +44,31 @@ printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
"# yay-wrapper-version: $_yay_wrapper_version" \
|
||||
'# Auto-generated by conf.d/yay-wrapper.fish — do not edit by hand.' \
|
||||
'# Tees yay output to a timestamped log file and prunes old ones.' \
|
||||
'set -o pipefail' \
|
||||
'# Runs yay in a PTY via script(1) so progress bars are preserved on screen,' \
|
||||
'# then renders the captured terminal animation to a clean static log.' \
|
||||
'' \
|
||||
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
|
||||
'mkdir -p "$log_dir"' \
|
||||
'log_file="$log_dir/yay_$(date +%Y-%m-%d_%H-%M-%S).log"' \
|
||||
'' \
|
||||
'/usr/bin/yay "$@" 2>&1 | tee "$log_file"' \
|
||||
'# Build a safely-quoted command string for script(1).' \
|
||||
'# script(1) allocates a PTY so yay detects a real terminal and shows progress.' \
|
||||
"cmd_str=\"$_yay_real\"" \
|
||||
'for arg in "$@"; do' \
|
||||
' cmd_str+=" $(printf '"'"'%q'"'"' "$arg")"' \
|
||||
'done' \
|
||||
'script -q -e -c "$cmd_str" "$log_file"' \
|
||||
'exit_code=$?' \
|
||||
'' \
|
||||
'# Render the captured terminal animation (progress bars repaint in place via' \
|
||||
'# cursor moves) down to its final static frame, preserving ANSI color. Falls' \
|
||||
'# back to dropping only the script(1) header/footer when python3 is missing.' \
|
||||
'cleaner="${XDG_CONFIG_HOME:-$HOME/.config}/fish/scripts/clean_progress_log.py"' \
|
||||
'if command -v python3 >/dev/null 2>&1 && [[ -f "$cleaner" ]]; then' \
|
||||
' python3 "$cleaner" < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
|
||||
'else' \
|
||||
' sed -i "/^Script \(started\|done\) on /d" "$log_file" 2>/dev/null || true' \
|
||||
'fi' \
|
||||
'' \
|
||||
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
|
||||
'mapfile -t logs < <(ls -1t "$log_dir"/yay_*.log 2>/dev/null)' \
|
||||
@@ -40,6 +76,8 @@ printf '%s\n' \
|
||||
'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \
|
||||
' rm -f "${logs[$i]}"' \
|
||||
'done' \
|
||||
'' \
|
||||
'exit $exit_code' \
|
||||
> $_yay_wrapper
|
||||
|
||||
chmod +x $_yay_wrapper
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# C5 — Logging & Capture: registers a fish_exit handler that dumps the current
|
||||
# Zellij pane's scrollback to a log file when the shell exits. Unlike tmux
|
||||
# (streamed live via pipe-pane), Zellij has no continuous-capture facility, so
|
||||
# we snapshot once on exit via `zellij action dump-screen --full`.
|
||||
#
|
||||
# The handler is registered whenever fish runs inside Zellij; the C5 logging
|
||||
# guard is evaluated inside _zellij_dump_log at exit time, so toggling
|
||||
# __fish_config_op_logging takes effect on the next exit without a restart
|
||||
# (no sync_logging coordination needed, since there is no live stream to stop).
|
||||
#
|
||||
# Event-handler functions must be defined at startup (conf.d) so the --on-event
|
||||
# binding is registered; autoloaded functions in functions/ never register.
|
||||
|
||||
status is-interactive; or exit
|
||||
type -q zellij; or exit
|
||||
set -q ZELLIJ; or exit
|
||||
|
||||
function __zellij_dump_on_exit --on-event fish_exit \
|
||||
--description 'C5 event handler: dump Zellij pane scrollback on shell exit'
|
||||
_zellij_dump_log
|
||||
end
|
||||
+8
-1
@@ -3,6 +3,9 @@
|
||||
# Adapted from icezyclon/zoxide.fish (MIT)
|
||||
# Heavily customized for Fish 4.x compatibility and performance
|
||||
|
||||
# COMPONENT
|
||||
# aliases/filesystem
|
||||
|
||||
if status is-interactive
|
||||
|
||||
if type -q zoxide
|
||||
@@ -63,7 +66,11 @@ if status is-interactive
|
||||
|
||||
# -------------
|
||||
|
||||
alias cd=z
|
||||
# Shadowing cd with zoxide is opinionated (C1 aliasing); z and zi
|
||||
# remain available either way.
|
||||
if __fish_config_op_enabled (status basename)
|
||||
alias cd=z
|
||||
end
|
||||
|
||||
# use custom completion
|
||||
complete -c z -f # disable files by default
|
||||
|
||||
+168
-92
@@ -5,78 +5,149 @@
|
||||
# │ Fish Configuration │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
|
||||
# ───────────────────── Opinionated component guards ─────────────────────
|
||||
# Opinionated components (AGENTS.md Task #3) are wrapped in
|
||||
# __fish_config_op_enabled <identity> [<site>] guards throughout this file and conf.d/.
|
||||
# The helper always evaluates the master switch __fish_config_opinionated
|
||||
# first (falsy disables everything), then the per-category opt-out variable:
|
||||
# __fish_config_op_aliases C1 — command shadows / flag injection
|
||||
# __fish_config_op_autoexec C2 — startup side-effects
|
||||
# __fish_config_op_overrides C3 — key bindings, env, prompt overrides
|
||||
# __fish_config_op_integrations C4 — terminal/tool coupling
|
||||
# __fish_config_op_logging C5 — scrollback capture / AUR log wrappers
|
||||
# (opt-in: unset means OFF)
|
||||
# __fish_config_op_greeting C6 — per-session greeting / first-run welcome
|
||||
# Example: set -U __fish_config_op_aliases off (erase to re-enable)
|
||||
# C5 is the one exception: it defaults to disabled and needs an explicit
|
||||
# truthy value — set -U __fish_config_op_logging on
|
||||
|
||||
# COMPONENT
|
||||
# site cachyos-tricks: overrides/environment
|
||||
# site cachyos-strip-aliases: aliases/filesystem
|
||||
# site cachyos-strip-overrides: overrides/key-bindings
|
||||
# site pager-editor-gpg: overrides/environment
|
||||
# site exit-wiring: overrides/key-bindings
|
||||
# site path-setup: overrides/environment
|
||||
# site cdpath: overrides/environment
|
||||
# site vi-mode: overrides/key-bindings
|
||||
# site greeting-stamp: greeting/greeting-message
|
||||
|
||||
# ──────────────────────── Source CachyOS configs ────────────────────────
|
||||
if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
|
||||
source /usr/share/cachyos-fish-config/cachyos-config.fish
|
||||
# Source our tricks over the cachyOS config
|
||||
test -f "$__fish_config_dir/conf.d/tricks.fish"
|
||||
and source "$__fish_config_dir/conf.d/tricks.fish"
|
||||
# Erase CachyOS aliases/functions that shadow our versions, then
|
||||
# re-source our versions since functions --erase removes autoload entries.
|
||||
for _fname in ls lt cleanup copy
|
||||
functions --erase $_fname
|
||||
source "$__fish_config_dir/functions/$_fname.fish"
|
||||
# Surgically overriding the distro config is opinionated (C3 overrides):
|
||||
# skip it entirely when overrides are disabled, keeping CachyOS defaults.
|
||||
if __fish_config_op_enabled (status basename) cachyos-tricks
|
||||
# Source our tricks over the cachyOS config
|
||||
test -f "$__fish_config_dir/conf.d/tricks.fish"
|
||||
and source "$__fish_config_dir/conf.d/tricks.fish"
|
||||
# Erase CachyOS aliases/functions that shadow our versions, then
|
||||
# re-source our versions since functions --erase removes autoload entries.
|
||||
for _fname in ls lt cleanup copy
|
||||
functions --erase $_fname
|
||||
source "$__fish_config_dir/functions/$_fname.fish"
|
||||
end
|
||||
end
|
||||
|
||||
# The distro config ships opinionated pieces of its own (it is the origin
|
||||
# of tricks.fish); strip them when the matching category is disabled so
|
||||
# the guards hold on CachyOS systems too.
|
||||
if not __fish_config_op_enabled (status basename) cachyos-strip-aliases
|
||||
for _fname in grep fgrep egrep dir vdir wget
|
||||
functions -q $_fname; and functions --erase $_fname
|
||||
end
|
||||
# Restore fish's stock versions where they exist (erasing alone would
|
||||
# also block autoloading the stock function).
|
||||
for _fname in history ls
|
||||
functions -q $_fname; and functions --erase $_fname
|
||||
test -f $__fish_data_dir/functions/$_fname.fish
|
||||
and source $__fish_data_dir/functions/$_fname.fish
|
||||
end
|
||||
end
|
||||
if not __fish_config_op_enabled (status basename) cachyos-strip-overrides
|
||||
for _fname in __history_previous_command __history_previous_command_arguments
|
||||
functions -q $_fname; and functions --erase $_fname
|
||||
end
|
||||
bind --erase ! 2>/dev/null
|
||||
bind --erase '$' 2>/dev/null
|
||||
bind -M insert --erase ! 2>/dev/null
|
||||
bind -M insert --erase '$' 2>/dev/null
|
||||
end
|
||||
end
|
||||
set --erase _fname
|
||||
|
||||
# ───────────────────────────── XDG variables ────────────────────────────
|
||||
# XDG Base Directory variables (standard practice)
|
||||
set -gx XDG_CONFIG_HOME $HOME/.config # Sets default config dir to ~/.config
|
||||
set -gx XDG_CACHE_HOME $HOME/.cache # Sets default cache dir to ~/.cache
|
||||
set -gx XDG_DATA_HOME $HOME/.local/share # Sets default data dir to ~/.local/share
|
||||
set -gx XDG_STATE_HOME $HOME/.local/state # Sets default state dir to ~/.local/state
|
||||
# We set these unconditionally to ensure a consistent baseline, but only if
|
||||
# they are not already defined by the system/user.
|
||||
set -q XDG_CONFIG_HOME; or set -gx XDG_CONFIG_HOME $HOME/.config # Sets default config dir to ~/.config
|
||||
set -q XDG_CACHE_HOME; or set -gx XDG_CACHE_HOME $HOME/.cache # Sets default cache dir to ~/.cache
|
||||
set -q XDG_DATA_HOME; or set -gx XDG_DATA_HOME $HOME/.local/share # Sets default data dir to ~/.local/share
|
||||
set -q XDG_STATE_HOME; or set -gx XDG_STATE_HOME $HOME/.local/state # Sets default state dir to ~/.local/state
|
||||
|
||||
# Attempt to keep various config/cache files out of the home directory root
|
||||
set -gx RANDFILE "$XDG_STATE_HOME/rnd"
|
||||
set -gx WGETRC "$XDG_CONFIG_HOME/wget/wgetrc"
|
||||
set -gx WGET_HSTS_FILE "$XDG_CACHE_HOME/wget-hsts"
|
||||
set -gx NPM_CONFIG_PREFIX "$XDG_DATA_HOME/npm-global"
|
||||
set -gx NPM_CONFIG_USERCONFIG "$XDG_CONFIG_HOME/npm/npmrc"
|
||||
set -gx ANDROID_USER_HOME "$XDG_DATA_HOME/android"
|
||||
set -gx CARGO_HOME "$XDG_DATA_HOME/cargo"
|
||||
set -gx RUSTUP_HOME "$XDG_DATA_HOME/rustup"
|
||||
set -gx GOPATH "$XDG_DATA_HOME/go"
|
||||
set -gx BUN_INSTALL "$XDG_DATA_HOME/bun"
|
||||
set -gx GNUPGHOME "$XDG_CONFIG_HOME/gnupg"
|
||||
set -gx WAKATIME_HOME "$XDG_CONFIG_HOME/wakatime"
|
||||
set -gx HISTFILE "$XDG_STATE_HOME/bash_history"
|
||||
set -gx EXINIT "set viminfofile=$XDG_STATE_HOME/vim/viminfo | source $MYVIMRC"
|
||||
set -gx NVIDIA_SETTINGS_RW_CONFIG_FILE "$XDG_CONFIG_HOME/nvidia/settings"
|
||||
set -gx CODEIUM_HOME "$XDG_CONFIG_HOME/codeium"
|
||||
set -gx WORDLIST "$XDG_CONFIG_HOME/hunspell_en_US"
|
||||
set -q RANDFILE; or set -gx RANDFILE "$XDG_STATE_HOME/rnd"
|
||||
set -q WGETRC; or set -gx WGETRC "$XDG_CONFIG_HOME/wget/wgetrc"
|
||||
set -q WGET_HSTS_FILE; or set -gx WGET_HSTS_FILE "$XDG_CACHE_HOME/wget-hsts"
|
||||
set -q NPM_CONFIG_PREFIX; or set -gx NPM_CONFIG_PREFIX "$XDG_DATA_HOME/npm-global"
|
||||
set -q NPM_CONFIG_USERCONFIG; or set -gx NPM_CONFIG_USERCONFIG "$XDG_CONFIG_HOME/npm/npmrc"
|
||||
set -q ANDROID_USER_HOME; or set -gx ANDROID_USER_HOME "$XDG_DATA_HOME/android"
|
||||
set -q CARGO_HOME; or set -gx CARGO_HOME "$XDG_DATA_HOME/cargo"
|
||||
set -q RUSTUP_HOME; or set -gx RUSTUP_HOME "$XDG_DATA_HOME/rustup"
|
||||
set -q GOPATH; or set -gx GOPATH "$XDG_DATA_HOME/go"
|
||||
set -q BUN_INSTALL; or set -gx BUN_INSTALL "$XDG_DATA_HOME/bun"
|
||||
set -q GNUPGHOME; or set -gx GNUPGHOME "$XDG_CONFIG_HOME/gnupg"
|
||||
set -q WAKATIME_HOME; or set -gx WAKATIME_HOME "$XDG_CONFIG_HOME/wakatime"
|
||||
set -q HISTFILE; or set -gx HISTFILE "$XDG_STATE_HOME/bash_history"
|
||||
set -q EXINIT; or set -gx EXINIT "set viminfofile=$XDG_STATE_HOME/vim/viminfo | source $MYVIMRC"
|
||||
set -q NVIDIA_SETTINGS_RW_CONFIG_FILE; or set -gx NVIDIA_SETTINGS_RW_CONFIG_FILE "$XDG_CONFIG_HOME/nvidia/settings"
|
||||
set -q CODEIUM_HOME; or set -gx CODEIUM_HOME "$XDG_CONFIG_HOME/codeium"
|
||||
set -q WORDLIST; or set -gx WORDLIST "$XDG_CONFIG_HOME/hunspell_en_US"
|
||||
|
||||
# ─────────────────────────── Pager variables ────────────────────────────
|
||||
if type -q ov
|
||||
set -gx PAGER ov
|
||||
else if type -q less
|
||||
set -gx PAGER less
|
||||
end
|
||||
# Overriding $PAGER, $EDITOR, and $GPG_TTY is opinionated (C3 overrides)
|
||||
if __fish_config_op_enabled (status basename) pager-editor-gpg
|
||||
if type -q ov
|
||||
set -gx PAGER ov
|
||||
else if type -q less
|
||||
set -gx PAGER less
|
||||
end
|
||||
|
||||
# ─────────────────────────── Editor variables ───────────────────────────
|
||||
# Set Editor variables with fallback to vi if nvim isn't available. This ensures that
|
||||
# tools that rely on these variables (like git commit messages) will work out of the box,
|
||||
# while still preferring nvim if it's installed.
|
||||
if type -q nvim
|
||||
set -gx NVIM_APPNAME nvim
|
||||
set -gx EDITOR (command -s nvim)
|
||||
else
|
||||
set -gx EDITOR (command -s vi)
|
||||
end
|
||||
set -gx VISUAL $EDITOR
|
||||
set -gx SUDO_EDITOR $EDITOR
|
||||
# ─────────────────────────── Editor variables ───────────────────────────
|
||||
# Set Editor variables with fallback to vi if nvim isn't available. This ensures that
|
||||
# tools that rely on these variables (like git commit messages) will work out of the box,
|
||||
# while still preferring nvim if it's installed.
|
||||
if type -q nvim
|
||||
set -gx NVIM_APPNAME nvim
|
||||
set -gx EDITOR (command -s nvim)
|
||||
else
|
||||
set -gx EDITOR (command -s vi)
|
||||
end
|
||||
# set -gx VISUAL $EDITOR # <- Use local.fish to set your preferred GUI editor.
|
||||
set -gx SUDO_EDITOR $EDITOR
|
||||
|
||||
# ──────────────────────────── GPG variables ─────────────────────────────
|
||||
# Helps ensure that GPG can prompt for passphrases correctly when invoked from the terminal.
|
||||
set -gx GPG_TTY (tty)
|
||||
# ──────────────────────────── GPG variables ─────────────────────────────
|
||||
# Helps ensure that GPG can prompt for passphrases correctly when invoked from the terminal.
|
||||
set -gx GPG_TTY (tty)
|
||||
end
|
||||
|
||||
# ────────────────────────── Scrollback History ──────────────────────────
|
||||
# Directory where scrollback history is saved into log files.
|
||||
# Optional fish-style source of truth (set -U via config-settings); exported
|
||||
# for the POSIX wrappers (paru/yay/tmux/zellij/_prune_terminal_logs) that read
|
||||
# them. We export the default unconditionally, then override from the universal
|
||||
# var only if set — deliberately NOT creating a global, which would shadow the
|
||||
# universal and stop live edits (config-settings → Paths) from taking effect.
|
||||
set -gx SCROLLBACK_HISTORY_DIR "$HOME/.terminal_history"
|
||||
# Maximum number of scrollback history files to keep
|
||||
set -q __fish_scrollback_history_dir
|
||||
and set -gx SCROLLBACK_HISTORY_DIR $__fish_scrollback_history_dir
|
||||
|
||||
set -gx SCROLLBACK_HISTORY_MAX_FILES 100
|
||||
set -q __fish_scrollback_history_max_files
|
||||
and set -gx SCROLLBACK_HISTORY_MAX_FILES $__fish_scrollback_history_max_files
|
||||
# Wire up a clean exit function that won't fire on background subshells
|
||||
if status is-interactive
|
||||
# Replacing the exit builtin is opinionated (C3 overrides); smart_exit also
|
||||
# guards itself so a live toggle takes effect without restarting the shell.
|
||||
if status is-interactive; and __fish_config_op_enabled (status basename) exit-wiring
|
||||
function exit --description 'Safe interactive exit'
|
||||
# If the smart_exit file exists in our function path, invoke it explicitly
|
||||
if functions -q smart_exit
|
||||
@@ -92,16 +163,19 @@ end
|
||||
# Adds common user bin directories to the PATH. The -mg --move option for cargo ensures that
|
||||
# the cargo bin directory is moved to the end of the PATH, which can help avoid conflicts
|
||||
# with system-installed Rust tools while still allowing user-installed cargo binaries to be found.
|
||||
fish_add_path $HOME/.local/bin # Standard user-local executables (XDG spec)
|
||||
fish_add_path $HOME/.local/share/../bin # Alternative/legacy path for local user binaries
|
||||
fish_add_path $HOME/Applications # User-installed applications and standalone apps
|
||||
fish_add_path $HOME/scripts # Custom personal shell scripts and automation
|
||||
fish_add_path -mga $CARGO_HOME/bin # Rust binaries and tools installed via Cargo
|
||||
fish_add_path $BUN_INSTALL/bin # Bun runtime executables and globally installed packages
|
||||
fish_add_path $XDG_DATA_HOME/npm-global/bin # Global Node.js/npm packages (XDG compliant location)
|
||||
fish_add_path $HOME/.lmstudio/bin # LM Studio CLI tools for local LLM management
|
||||
fish_add_path $HOME/.resend/bin # Resend email service CLI tools
|
||||
fish_add_path $HOME/.fzf/bin # Fuzzy Finder (fzf) core binary and helper scripts
|
||||
# PATH setup is opinionated (C3 overrides)
|
||||
if __fish_config_op_enabled (status basename) path-setup
|
||||
fish_add_path $HOME/.local/bin # Standard user-local executables (XDG spec)
|
||||
fish_add_path $HOME/.local/share/../bin # Alternative/legacy path for local user binaries
|
||||
fish_add_path $HOME/Applications # User-installed applications and standalone apps
|
||||
fish_add_path $HOME/scripts # Custom personal shell scripts and automation
|
||||
fish_add_path -mga $CARGO_HOME/bin # Rust binaries and tools installed via Cargo
|
||||
fish_add_path $BUN_INSTALL/bin # Bun runtime executables and globally installed packages
|
||||
fish_add_path $XDG_DATA_HOME/npm-global/bin # Global Node.js/npm packages (XDG compliant location)
|
||||
fish_add_path $HOME/.lmstudio/bin # LM Studio CLI tools for local LLM management
|
||||
fish_add_path $HOME/.resend/bin # Resend email service CLI tools
|
||||
fish_add_path $HOME/.fzf/bin # Fuzzy Finder (fzf) core binary and helper scripts
|
||||
end
|
||||
|
||||
# ───────────────────────── CDPATH projects dir ──────────────────────────
|
||||
# Allows cd-ing to directories within $HOME/projects or $HOME without needing to specify the full path.
|
||||
@@ -112,22 +186,13 @@ fish_add_path $HOME/.fzf/bin # Fuzzy Finder (fzf) core binary an
|
||||
# Additionally, directories inside the CWD will still take precedence over CDPATH,
|
||||
# so if you have a directory named 'myproject' in the current directory,
|
||||
# running 'cd myproject' will take you there instead of $HOME/projects/myproject.
|
||||
set -gx CDPATH . $HOME/projects $HOME
|
||||
# CDPATH injection is opinionated (C3 overrides)
|
||||
if __fish_config_op_enabled (status basename) cdpath
|
||||
set -gx CDPATH . $HOME/projects $HOME
|
||||
end
|
||||
|
||||
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
|
||||
if not type -q fisher
|
||||
echo "Fisher plugin manager not found."
|
||||
read -l -P "Install Fisher and plugins now? [Y/n] " _fisher_reply
|
||||
if test -z "$_fisher_reply" -o "$_fisher_reply" = Y -o "$_fisher_reply" = y
|
||||
echo "Installing Fisher..."
|
||||
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
|
||||
fisher update
|
||||
fish_config theme choose "Catppuccin Mocha"
|
||||
else
|
||||
echo "Skipping Fisher install. Some features may be unavailable."
|
||||
end
|
||||
set --erase _fisher_reply
|
||||
end
|
||||
# Fisher is bootstrapped automatically on first run via conf.d/first_run.fish
|
||||
|
||||
# ─────────────────────── Visual/Interactive setup ───────────────────────
|
||||
# Run only if we're in an interactive session (not a script or non-interactive shell)
|
||||
@@ -135,7 +200,11 @@ if status is-interactive
|
||||
# ────────────────────────────── Key bindings ────────────────────────────
|
||||
# Helps ensure that key bindings are consistent with the Vi editing mode set below.
|
||||
# This is optional but can improve the user experience for those who prefer Vi-style key bindings.
|
||||
set -g fish_key_bindings fish_vi_key_bindings
|
||||
# Global Vi mode is opinionated (C3 overrides); without it fish keeps its
|
||||
# default Emacs-style bindings.
|
||||
if __fish_config_op_enabled (status basename) vi-mode
|
||||
set -g fish_key_bindings fish_vi_key_bindings
|
||||
end
|
||||
|
||||
# ──────────────────────── Source FZF integration ────────────────────────
|
||||
# Prefer fzf's own fish integration (fzf --fish, available since fzf 0.48)
|
||||
@@ -173,23 +242,30 @@ if status is-interactive
|
||||
# │ This is useful for machine-specific behavior or configurations. │
|
||||
# ╰────────────────────────────── OVERRIDES ─────────────────────────────╯
|
||||
#
|
||||
# Define user-dots path variable for a more legible secrets/local config.
|
||||
set -l dot_fish "$XDG_CONFIG_HOME/.user-dots/fish"
|
||||
# ───────────────────────── Source user secrets ──────────────────────────
|
||||
# Sources a secrets.fish file if it exists, which can be used to store
|
||||
# sensitive environment variables and configurations that shouldn't be
|
||||
# committed to version control.
|
||||
# This allows you to keep things like API keys, database credentials,
|
||||
# and other secrets out of your main config files and safely ignored by git.
|
||||
test -f "$dot_fish/secrets.fish"; and source "$dot_fish/secrets.fish"
|
||||
# Resolve user-dots path. Customize via: set -U __fish_user_dots_path /your/path
|
||||
set -q __fish_user_dots_path
|
||||
or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
|
||||
# ────────────────────── user-dots convenience symlink ───────────────────
|
||||
# Keep $__fish_config_dir/user-dots tracking the resolved path so it can be
|
||||
# browsed from the fish config dir. Git-ignored. Controlled by the
|
||||
# __fish_user_dots_symlink toggle (config-settings → Paths); creation is a
|
||||
# C2 side-effect, removal-on-opt-out is honoured regardless. See the helper.
|
||||
__fish_user_dots_link
|
||||
|
||||
# ─────────────────────── Source machine-local config ────────────────────
|
||||
# Sources a local.fish file if it exists, which can be used for machine-specific
|
||||
# variables and configurations that shouldn't be shared across machines.
|
||||
# This allows you to have different settings on different machines without affecting
|
||||
# your main config or secrets files. For example, you might want different PATH additions,
|
||||
# aliases, or environment variables on your work laptop vs. your home desktop.
|
||||
test -f "$dot_fish/local.fish"; and source "$dot_fish/local.fish"
|
||||
# Sources local.fish if it exists. That file handles sourcing its own
|
||||
# secrets.fish companion when needed.
|
||||
test -f "$__fish_user_dots_path/local.fish"; and source "$__fish_user_dots_path/local.fish"
|
||||
|
||||
# ─────────────────── C6: Greeting & First-Run UI override ───────────────
|
||||
# When the greeting category is disabled, stamp out any fish_greeting
|
||||
# function that distro configs set (e.g., CachyOS defines it as fastfetch).
|
||||
# This runs last inside the interactive block so our empty definition wins
|
||||
# over whatever cachyos-config.fish or vendor conf.d installed.
|
||||
if not __fish_config_op_enabled (status basename) greeting-stamp
|
||||
function fish_greeting
|
||||
end
|
||||
end
|
||||
#
|
||||
# ╭──────────────────────────── END OVERRIDES ──────────────────────────╮
|
||||
# │ End of override section. │
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
admiring
|
||||
adoring
|
||||
affectionate
|
||||
agitated
|
||||
amazing
|
||||
angry
|
||||
awesome
|
||||
beautiful
|
||||
blissful
|
||||
bold
|
||||
boring
|
||||
brave
|
||||
busy
|
||||
charming
|
||||
clever
|
||||
compassionate
|
||||
competent
|
||||
condescending
|
||||
confident
|
||||
cool
|
||||
cranky
|
||||
crazy
|
||||
dazzling
|
||||
determined
|
||||
distracted
|
||||
dreamy
|
||||
eager
|
||||
ecstatic
|
||||
elastic
|
||||
elated
|
||||
elegant
|
||||
eloquent
|
||||
epic
|
||||
exciting
|
||||
fervent
|
||||
festive
|
||||
flamboyant
|
||||
focused
|
||||
friendly
|
||||
frosty
|
||||
funny
|
||||
gallant
|
||||
gifted
|
||||
goofy
|
||||
gracious
|
||||
great
|
||||
happy
|
||||
hardcore
|
||||
heuristic
|
||||
hopeful
|
||||
hungry
|
||||
infallible
|
||||
inspiring
|
||||
intelligent
|
||||
interesting
|
||||
jolly
|
||||
jovial
|
||||
keen
|
||||
kind
|
||||
laughing
|
||||
loving
|
||||
lucid
|
||||
magical
|
||||
modest
|
||||
musing
|
||||
mystifying
|
||||
naughty
|
||||
nervous
|
||||
nice
|
||||
nifty
|
||||
nostalgic
|
||||
objective
|
||||
optimistic
|
||||
peaceful
|
||||
pedantic
|
||||
pensive
|
||||
practical
|
||||
priceless
|
||||
quirky
|
||||
quizzical
|
||||
recursing
|
||||
relaxed
|
||||
reverent
|
||||
romantic
|
||||
sad
|
||||
serene
|
||||
sharp
|
||||
silly
|
||||
sleepy
|
||||
stoic
|
||||
strange
|
||||
stupefied
|
||||
suspicious
|
||||
sweet
|
||||
tender
|
||||
thirsty
|
||||
trusting
|
||||
unruffled
|
||||
upbeat
|
||||
vibrant
|
||||
vigilant
|
||||
vigorous
|
||||
wizardly
|
||||
wonderful
|
||||
xenodochial
|
||||
youthful
|
||||
zealous
|
||||
zen
|
||||
@@ -0,0 +1,223 @@
|
||||
aardvark
|
||||
albatross
|
||||
alligator
|
||||
alpaca
|
||||
ant
|
||||
anteater
|
||||
antelope
|
||||
ape
|
||||
armadillo
|
||||
baboon
|
||||
badger
|
||||
barracuda
|
||||
bat
|
||||
bear
|
||||
beaver
|
||||
bee
|
||||
bison
|
||||
boar
|
||||
buffalo
|
||||
butterfly
|
||||
camel
|
||||
capybara
|
||||
caribou
|
||||
cat
|
||||
caterpillar
|
||||
cattle
|
||||
chamois
|
||||
cheetah
|
||||
chicken
|
||||
chimpanzee
|
||||
chinchilla
|
||||
chough
|
||||
clam
|
||||
cobra
|
||||
cockroach
|
||||
cod
|
||||
cormorant
|
||||
coyote
|
||||
crab
|
||||
crane
|
||||
crocodile
|
||||
crow
|
||||
curlew
|
||||
deer
|
||||
dinosaur
|
||||
dog
|
||||
dogfish
|
||||
dolphin
|
||||
donkey
|
||||
dotterel
|
||||
dove
|
||||
dragonfly
|
||||
duck
|
||||
dugong
|
||||
dunlin
|
||||
eagle
|
||||
echidna
|
||||
eel
|
||||
eland
|
||||
elephant
|
||||
elk
|
||||
emu
|
||||
falcon
|
||||
ferret
|
||||
finch
|
||||
fish
|
||||
flamingo
|
||||
fly
|
||||
fox
|
||||
frog
|
||||
gaur
|
||||
gazelle
|
||||
gerbil
|
||||
giraffe
|
||||
gnat
|
||||
gnu
|
||||
goat
|
||||
goldfinch
|
||||
goldfish
|
||||
goose
|
||||
gorilla
|
||||
goshawk
|
||||
grasshopper
|
||||
grouse
|
||||
guanaco
|
||||
gull
|
||||
hamster
|
||||
hare
|
||||
hawk
|
||||
hedgehog
|
||||
heron
|
||||
herring
|
||||
hippopotamus
|
||||
hornet
|
||||
horse
|
||||
human
|
||||
hummingbird
|
||||
hyena
|
||||
ibex
|
||||
ibis
|
||||
jackal
|
||||
jaguar
|
||||
jay
|
||||
jellyfish
|
||||
kangaroo
|
||||
kingfisher
|
||||
koala
|
||||
kookabura
|
||||
kouprey
|
||||
kudu
|
||||
lapwing
|
||||
lark
|
||||
lemur
|
||||
leopard
|
||||
lion
|
||||
llama
|
||||
lobster
|
||||
locust
|
||||
loris
|
||||
louse
|
||||
lyrebird
|
||||
magpie
|
||||
mallard
|
||||
manatee
|
||||
mandrill
|
||||
mantis
|
||||
marten
|
||||
meerkat
|
||||
mink
|
||||
mole
|
||||
mongoose
|
||||
monkey
|
||||
moose
|
||||
mosquito
|
||||
mouse
|
||||
mule
|
||||
narwhal
|
||||
newt
|
||||
nightingale
|
||||
octopus
|
||||
okapi
|
||||
opossum
|
||||
oryx
|
||||
ostrich
|
||||
otter
|
||||
owl
|
||||
oyster
|
||||
panther
|
||||
parrot
|
||||
partridge
|
||||
peafowl
|
||||
pelican
|
||||
penguin
|
||||
pheasant
|
||||
pig
|
||||
pigeon
|
||||
pony
|
||||
porcupine
|
||||
porpoise
|
||||
quail
|
||||
quelea
|
||||
quetzal
|
||||
rabbit
|
||||
raccoon
|
||||
rail
|
||||
ram
|
||||
rat
|
||||
raven
|
||||
red-deer
|
||||
red-panda
|
||||
reindeer
|
||||
rhinoceros
|
||||
rook
|
||||
salamander
|
||||
salmon
|
||||
sand-dollar
|
||||
sandpiper
|
||||
sardine
|
||||
scorpion
|
||||
seahorse
|
||||
seal
|
||||
shark
|
||||
sheep
|
||||
shrew
|
||||
skunk
|
||||
snail
|
||||
snake
|
||||
sparrow
|
||||
spider
|
||||
spoonbill
|
||||
squid
|
||||
squirrel
|
||||
starling
|
||||
stingray
|
||||
stinkbug
|
||||
stork
|
||||
swallow
|
||||
swan
|
||||
tapir
|
||||
tarsier
|
||||
termite
|
||||
tiger
|
||||
toad
|
||||
trout
|
||||
turkey
|
||||
turtle
|
||||
viper
|
||||
vulture
|
||||
wallaby
|
||||
walrus
|
||||
wasp
|
||||
weasel
|
||||
whale
|
||||
wildcat
|
||||
wolf
|
||||
wolverine
|
||||
wombat
|
||||
woodcock
|
||||
woodpecker
|
||||
worm
|
||||
wren
|
||||
yak
|
||||
zebra
|
||||
@@ -0,0 +1,81 @@
|
||||
amber
|
||||
amethyst
|
||||
apricot
|
||||
aqua
|
||||
aquamarine
|
||||
auburn
|
||||
azure
|
||||
beige
|
||||
black
|
||||
blue
|
||||
bronze
|
||||
brown
|
||||
buff
|
||||
carmine
|
||||
celadon
|
||||
cerise
|
||||
cerulean
|
||||
charcoal
|
||||
chartreuse
|
||||
chocolate
|
||||
cinnamon
|
||||
copper
|
||||
coral
|
||||
cream
|
||||
crimson
|
||||
cyan
|
||||
denim
|
||||
emerald
|
||||
fuchsia
|
||||
gold
|
||||
goldenrod
|
||||
gray
|
||||
green
|
||||
grey
|
||||
indigo
|
||||
ivory
|
||||
jade
|
||||
khaki
|
||||
lavender
|
||||
lemon
|
||||
lilac
|
||||
lime
|
||||
magenta
|
||||
mahogany
|
||||
maroon
|
||||
mauve
|
||||
mustard
|
||||
navy
|
||||
ochre
|
||||
olive
|
||||
orange
|
||||
orchid
|
||||
peach
|
||||
pear
|
||||
periwinkle
|
||||
pink
|
||||
plum
|
||||
puce
|
||||
purple
|
||||
quartz
|
||||
red
|
||||
rose
|
||||
ruby
|
||||
rust
|
||||
salmon
|
||||
sapphire
|
||||
scarlet
|
||||
silver
|
||||
slate
|
||||
tan
|
||||
taupe
|
||||
teal
|
||||
tomato
|
||||
topaz
|
||||
turquoise
|
||||
ultramarine
|
||||
umber
|
||||
vanilla
|
||||
violet
|
||||
white
|
||||
yellow
|
||||
@@ -0,0 +1,236 @@
|
||||
agnesi
|
||||
albattani
|
||||
allen
|
||||
almeida
|
||||
antonelli
|
||||
archimedes
|
||||
ardinghelli
|
||||
aryabhata
|
||||
austin
|
||||
babbage
|
||||
banach
|
||||
banzai
|
||||
bardeen
|
||||
bartik
|
||||
bassi
|
||||
beaver
|
||||
bell
|
||||
benz
|
||||
bhabha
|
||||
bhaskara
|
||||
black
|
||||
blackburn
|
||||
blackwell
|
||||
bohr
|
||||
booth
|
||||
borg
|
||||
bose
|
||||
bouman
|
||||
boyd
|
||||
brahmagupta
|
||||
brattain
|
||||
brown
|
||||
buck
|
||||
burnell
|
||||
cannon
|
||||
carson
|
||||
cartwright
|
||||
carver
|
||||
cerf
|
||||
chandrasekhar
|
||||
chaplygin
|
||||
chatelet
|
||||
chatterjee
|
||||
chaum
|
||||
chebyshev
|
||||
clarke
|
||||
cohen
|
||||
colden
|
||||
cori
|
||||
cray
|
||||
curie
|
||||
curran
|
||||
darwin
|
||||
davinci
|
||||
dewdney
|
||||
dhawan
|
||||
diffie
|
||||
dijkstra
|
||||
dirac
|
||||
driscoll
|
||||
dubinsky
|
||||
easley
|
||||
edison
|
||||
einstein
|
||||
elbakyan
|
||||
elgamal
|
||||
elion
|
||||
ellis
|
||||
engelbart
|
||||
euclid
|
||||
euler
|
||||
faraday
|
||||
feistel
|
||||
fermat
|
||||
fermi
|
||||
feynman
|
||||
franklin
|
||||
gagarin
|
||||
galileo
|
||||
galois
|
||||
ganguly
|
||||
gates
|
||||
gauss
|
||||
germain
|
||||
goldberg
|
||||
goldstine
|
||||
goldwasser
|
||||
golick
|
||||
goodall
|
||||
gould
|
||||
greider
|
||||
grothendieck
|
||||
haibt
|
||||
hamilton
|
||||
haslett
|
||||
hawking
|
||||
heisenberg
|
||||
hellman
|
||||
hermann
|
||||
herschel
|
||||
hertz
|
||||
heyrovsky
|
||||
hodgkin
|
||||
hofstadter
|
||||
hoover
|
||||
hopper
|
||||
hugle
|
||||
hypatia
|
||||
ishizaka
|
||||
jackson
|
||||
jang
|
||||
jemison
|
||||
jennings
|
||||
jepsen
|
||||
johnson
|
||||
joliot
|
||||
jones
|
||||
kalam
|
||||
kapitsa
|
||||
kare
|
||||
keldysh
|
||||
keller
|
||||
kepler
|
||||
khayyam
|
||||
khorana
|
||||
kilby
|
||||
kirch
|
||||
knuth
|
||||
kowalevski
|
||||
lalande
|
||||
lamarr
|
||||
lamport
|
||||
leakey
|
||||
leavitt
|
||||
lederberg
|
||||
lehmann
|
||||
lewin
|
||||
lichterman
|
||||
liskov
|
||||
lovelace
|
||||
lumiere
|
||||
mahavira
|
||||
margulis
|
||||
matsumoto
|
||||
maxwell
|
||||
mayer
|
||||
mccarthy
|
||||
mcclintock
|
||||
mclaren
|
||||
mclean
|
||||
mcnulty
|
||||
meitner
|
||||
mendel
|
||||
mendeleev
|
||||
meninsky
|
||||
merkle
|
||||
mestorf
|
||||
mirzakhani
|
||||
montalcini
|
||||
moore
|
||||
morse
|
||||
moser
|
||||
murdock
|
||||
napier
|
||||
nash
|
||||
neumann
|
||||
newton
|
||||
nightingale
|
||||
nobel
|
||||
noether
|
||||
northcutt
|
||||
noyce
|
||||
panini
|
||||
pare
|
||||
pascal
|
||||
pasteur
|
||||
payne
|
||||
perlman
|
||||
pike
|
||||
poincare
|
||||
poitras
|
||||
proskuriakova
|
||||
ptolemy
|
||||
raman
|
||||
ramanujan
|
||||
rhodes
|
||||
ride
|
||||
ritchie
|
||||
robinson
|
||||
roentgen
|
||||
rosalind
|
||||
rubin
|
||||
saha
|
||||
sammet
|
||||
sanderson
|
||||
satoshi
|
||||
shamir
|
||||
shannon
|
||||
shaw
|
||||
shirley
|
||||
shockley
|
||||
shtern
|
||||
sinoussi
|
||||
snyder
|
||||
solomon
|
||||
spence
|
||||
stonebraker
|
||||
sutherland
|
||||
swanson
|
||||
swartz
|
||||
swirles
|
||||
taussig
|
||||
tesla
|
||||
tharp
|
||||
thompson
|
||||
torvalds
|
||||
tu
|
||||
turing
|
||||
varahamihira
|
||||
vaughan
|
||||
villani
|
||||
visvesvaraya
|
||||
volhard
|
||||
wescoff
|
||||
wilbur
|
||||
wiles
|
||||
williams
|
||||
williamson
|
||||
wilson
|
||||
wing
|
||||
wozniak
|
||||
wright
|
||||
wu
|
||||
yalow
|
||||
yonath
|
||||
zhukovsky
|
||||
+1296
File diff suppressed because it is too large
Load Diff
+1000
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,865 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Generate publishable artifacts from the docs/manual SSOT.
|
||||
|
||||
--concat one ordered markdown document for pandoc / config-help
|
||||
--site Starlight content tree + sidebar.json
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import manualtools as mt
|
||||
import generate_component_registry
|
||||
|
||||
DOCS = Path(__file__).parent
|
||||
MANUAL = DOCS / "manual"
|
||||
FUNCTIONS = DOCS.parent / "functions"
|
||||
SLUG_DIR = "reference"
|
||||
|
||||
|
||||
def _is_function_page(path: Path, root: Path) -> bool:
|
||||
"""True for a Section 5 category stub (not its index)."""
|
||||
rel = path.relative_to(root)
|
||||
return bool(rel.parts) and rel.parts[0].endswith("-functions") and rel.name != "index.md"
|
||||
|
||||
|
||||
def _entry_slug(title: str) -> str:
|
||||
"""The site's page slug for an entry heading."""
|
||||
return re.sub(r"[^\w-]+", "-", title.strip().lower()).strip("-")
|
||||
|
||||
|
||||
def _entry_link(name: str, functions: dict) -> str:
|
||||
"""Link a dependency name to its entry page; plain code span if unknown."""
|
||||
fn = functions.get(name)
|
||||
if not fn:
|
||||
return f"`{name}`"
|
||||
category = re.sub(r"^\d+-", "", fn["CATEGORY"][0])
|
||||
return f"[`{name}`](/{SLUG_DIR}/{category}/{_entry_slug(name)}/)"
|
||||
|
||||
|
||||
def _with_entries(body: str, path: Path, entries: dict) -> str:
|
||||
"""Append this category's generated `## name` entries to its stub body."""
|
||||
generated = entries.get(path.stem, [])
|
||||
if not generated:
|
||||
return body
|
||||
blocks = [f"## {name}\n\n{entry}" for name, entry in generated]
|
||||
return "\n\n".join(([body] if body.strip() else []) + blocks)
|
||||
|
||||
|
||||
def _with_abbreviations(body: str, abbrs: dict[str, list[dict]]) -> str:
|
||||
"""Inject generated abbreviation tables into the document placeholders."""
|
||||
rendered_abbrs = {}
|
||||
for cat, items in abbrs.items():
|
||||
lines_cat = [" Abbreviation Description", " ───────────────────────────────────────────────────────────────────"]
|
||||
for abbr in items:
|
||||
name = abbr["name"]
|
||||
desc = abbr["desc"]
|
||||
|
||||
# Left-pad description to ensure at least 2 spaces for cell split
|
||||
name_part = name.ljust(16)
|
||||
if len(name_part) < len(name) + 2:
|
||||
name_part = name + " "
|
||||
|
||||
lines_cat.append(f" {name_part}{desc}")
|
||||
rendered_abbrs[cat] = "\n".join(lines_cat)
|
||||
|
||||
for cat, table in rendered_abbrs.items():
|
||||
placeholder = f"<!-- GENERATED: {cat} -->"
|
||||
body = body.replace(placeholder, table)
|
||||
|
||||
return body
|
||||
|
||||
|
||||
def build_concat(root: Path) -> str:
|
||||
"""Concatenate the manual into one ordered markdown document.
|
||||
|
||||
Each file contributes `# {manTitle or title}` at a level matching its
|
||||
depth, and its body headings are demoted by the same amount.
|
||||
|
||||
`root / "_pandoc.yml"` (if present) holds the original document's
|
||||
pandoc metadata block (title/section/header/date/author) as raw text,
|
||||
with no frontmatter fences and no Astro-visible frontmatter key. When
|
||||
present, its contents are re-emitted byte-for-byte as the leading
|
||||
`---`-fenced block, ahead of every heading.
|
||||
"""
|
||||
entries = build_entries(mt.parse_functions(FUNCTIONS))
|
||||
chunks: list[str] = []
|
||||
pandoc_path = root / "_pandoc.yml"
|
||||
if pandoc_path.exists():
|
||||
raw = pandoc_path.read_text().rstrip("\n")
|
||||
chunks.append(f"---\n{raw}\n---")
|
||||
for path, depth in mt.walk(root):
|
||||
fm, body = mt.parse(path)
|
||||
if not fm.get("man", True):
|
||||
continue
|
||||
heading = fm.get("manTitle") or fm.get("title", path.stem)
|
||||
chunks.append("#" * (depth + 1) + " " + heading)
|
||||
if _is_function_page(path, root):
|
||||
body = _with_entries(body, path, entries)
|
||||
elif "04-abbreviations" in path.parts:
|
||||
abbrs = mt.parse_abbreviations(DOCS.parent / "conf.d")
|
||||
body = _with_abbreviations(body, abbrs)
|
||||
if body:
|
||||
body = re.sub(r"<LinkButton.*?</LinkButton>\n*", "", body, flags=re.DOTALL)
|
||||
body = re.sub(r"<CardGrid.*?</CardGrid>\n*", "", body, flags=re.DOTALL)
|
||||
body = re.sub(r"\[([^\]]+)\]\(/[^)]+\)", r"\1", body)
|
||||
chunks.append(mt.shift_headings(body, depth))
|
||||
return "\n\n".join(chunks) + "\n"
|
||||
|
||||
|
||||
SENTENCE_RE = re.compile(r"^(.+?[.!?])(\s|$)", re.S)
|
||||
PIPELINE_KEYS = ("man", "site", "manTitle", "helpKeywords")
|
||||
JSX_ATTR_ESCAPES = (
|
||||
("&", "&"),
|
||||
('"', """),
|
||||
("<", "<"),
|
||||
("{", "{"),
|
||||
)
|
||||
|
||||
|
||||
def _jsx_attr_escape(value: str) -> str:
|
||||
"""Escape a string for safe use inside a quoted JSX attribute value.
|
||||
|
||||
`&` must go first so escaping later characters doesn't double-escape
|
||||
the ampersands it introduces. `"` closes the attribute early; `<` and
|
||||
`{` are otherwise-live MDX/JSX syntax that must not be interpreted.
|
||||
"""
|
||||
for char, escape in JSX_ATTR_ESCAPES:
|
||||
value = value.replace(char, escape)
|
||||
return value
|
||||
|
||||
|
||||
def _first_sentence(body: str) -> str:
|
||||
"""Extract a one-line description from the start of an entry body.
|
||||
|
||||
The `Synopsis:` block is skipped whole — label line plus its
|
||||
deeper-indented continuation lines. It restates the calling convention,
|
||||
which the card already shows as its title, so using one as the card
|
||||
description wastes the line.
|
||||
|
||||
Source prose is hard-wrapped, so the leading paragraph is unwrapped
|
||||
before the sentence match — otherwise a card truncates at the first
|
||||
line break, mid-clause.
|
||||
"""
|
||||
para: list[str] = []
|
||||
in_fence = False
|
||||
syn_indent: int | None = None
|
||||
for raw in body.split("\n"):
|
||||
line = raw.strip()
|
||||
indent = len(raw) - len(raw.lstrip())
|
||||
if syn_indent is not None:
|
||||
if line and indent <= syn_indent:
|
||||
syn_indent = None
|
||||
else:
|
||||
continue
|
||||
if line.startswith("```"):
|
||||
in_fence = not in_fence
|
||||
if para:
|
||||
break
|
||||
continue
|
||||
if in_fence:
|
||||
continue
|
||||
if not line or line.startswith(("#", "|", "-", "*", ">")):
|
||||
if para:
|
||||
break
|
||||
continue
|
||||
if line.startswith("Synopsis:"):
|
||||
syn_indent = indent
|
||||
continue
|
||||
para.append(line)
|
||||
if not para:
|
||||
return ""
|
||||
text = " ".join(para)
|
||||
m = SENTENCE_RE.match(text)
|
||||
return (m.group(1) if m else text)[:160]
|
||||
|
||||
|
||||
# Commands common enough in this manual that a block whose every line starts
|
||||
# with one is certainly shell, not prose or a two-column reference table.
|
||||
SHELL_HEADS = frozenset(
|
||||
"""
|
||||
abbr alias apt bg bind brew builtin cargo cat cd chmod code command cp curl
|
||||
dnf docker echo end env exec export fg fish fisher for funcsave function git help
|
||||
if jobs kitty ls man math mkdir mv nvim npm pacman paru pip pip3 pkg printf
|
||||
python python3 rm set shutdown source string sudo switch systemctl test time
|
||||
tmux touch trash type wget wezterm while yay zellij zypper
|
||||
fish_default_key_bindings fish_vi_key_bindings
|
||||
""".split()
|
||||
)
|
||||
|
||||
SYNOPSIS_PREFIX = "Synopsis:"
|
||||
EXAMPLE_PREFIX = "Example:"
|
||||
INDENT = " "
|
||||
|
||||
|
||||
def _is_prose(para: list[str]) -> bool:
|
||||
"""True when a paragraph reads as sentences rather than as code or a table.
|
||||
|
||||
Column-aligned reference tables are the main thing to keep out of a
|
||||
syntax-highlighted fence, and internal runs of two-or-more spaces are
|
||||
what distinguishes them from prose. `<` and `{` are excluded because
|
||||
the emitted paragraph is live markdown, where both would be parsed.
|
||||
"""
|
||||
text = " ".join(para)
|
||||
if "<" in text or "{" in text:
|
||||
return False
|
||||
if not para or para[-1].rstrip()[-1:] not in ".:":
|
||||
return False
|
||||
return all(
|
||||
len(line.split()) >= 3 and " " not in line.strip() for line in para
|
||||
)
|
||||
|
||||
|
||||
def _is_shell(para: list[str], entry_name: str | None) -> bool:
|
||||
"""True when every line of a paragraph looks like a shell command."""
|
||||
name_re = (
|
||||
re.compile(rf"(?<![\w-]){re.escape(entry_name)}(?![\w-])")
|
||||
if entry_name
|
||||
else None
|
||||
)
|
||||
for line in para:
|
||||
stripped = line.strip()
|
||||
if not stripped or stripped.startswith("#"):
|
||||
continue
|
||||
if name_re and name_re.search(stripped):
|
||||
continue
|
||||
if stripped.split()[0].lstrip("$").rstrip(";") not in SHELL_HEADS:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# A lone indented line that's just a path ending in a known extension —
|
||||
# e.g. pointing at where a file lives — reads better as a titled snippet
|
||||
# than an unhighlighted grey slab.
|
||||
PATH_LINE_RE = re.compile(r"^[~$][\w./{}-]*\.\w+$")
|
||||
|
||||
# A leading "# in local.fish" / "# local.fish" comment names the file an
|
||||
# example belongs to; promote it to the fence title instead of leaving it
|
||||
# as a literal comment inside the code.
|
||||
FILENAME_COMMENT_RE = re.compile(r"^#\s*(?:in\s+)?([$~\w./-]+\.\w+)\s*$")
|
||||
|
||||
CELL_SPLIT = re.compile(r"\s{2,}")
|
||||
|
||||
# A rule line under a header row — the "Component Reference" tables'
|
||||
# authoring convention (header, dashes, data rows all at the same indent,
|
||||
# no ":"-terminated label). Either one solid run of dashes, or (RST-style)
|
||||
# one dash run per column, gapped the same way CELL_SPLIT splits cells.
|
||||
RULE_CELL_RE = re.compile(r"^[─\-]{3,}$")
|
||||
|
||||
|
||||
def _cell(text: str, code: bool) -> str:
|
||||
"""Render one table cell. `|` must be escaped even inside a code span."""
|
||||
text = text.strip().replace("|", r"\|")
|
||||
return f"`{text}`" if code and text else text
|
||||
|
||||
|
||||
def _as_table(para: list[str]) -> str | None:
|
||||
"""Render an aligned two-column block as a markdown table, else None.
|
||||
|
||||
Option and subcommand tables are the one thing in this manual that is
|
||||
genuinely tabular, and the indented-code fallback renders them as a grey
|
||||
slab. Everything else stays in that fallback: returning None is always
|
||||
safe, so every check here is free to be conservative.
|
||||
|
||||
The rows must form one contiguous indented run, optionally introduced by
|
||||
a label line (`Options:`) and closed by a sentence. Lines indented deeper
|
||||
than the run are wrapped descriptions and fold into the row above.
|
||||
"""
|
||||
starts = [i for i, ln in enumerate(para) if ln.startswith(" ")]
|
||||
if len(starts) < 2 or starts != list(range(starts[0], starts[-1] + 1)):
|
||||
return None
|
||||
head = para[: starts[0]]
|
||||
body = para[starts[0] : starts[-1] + 1]
|
||||
tail = para[starts[-1] + 1 :]
|
||||
if head and not head[-1].rstrip().endswith(":"):
|
||||
return None # a head that isn't a label means mixed content
|
||||
|
||||
indent = min(len(ln) - len(ln.lstrip()) for ln in body)
|
||||
rows: list[list[str]] = []
|
||||
for line in body:
|
||||
if len(line) - len(line.lstrip()) > indent and rows:
|
||||
rows[-1][1] += " " + line.strip()
|
||||
continue
|
||||
parts = CELL_SPLIT.split(line.strip(), 1)
|
||||
if len(parts) != 2 or not parts[1].strip():
|
||||
return None # not column-aligned; a numbered list, or prose
|
||||
rows.append([parts[0], parts[1].strip()])
|
||||
if len(rows) < 2:
|
||||
return None
|
||||
if any("<" in value or "{" in value for _, value in rows):
|
||||
return None # live markdown in the prose column
|
||||
|
||||
out = [line.strip() for line in head]
|
||||
out += ["| | |", "|---|---|"]
|
||||
out += [f"| {_cell(k, True)} | {_cell(v, False)} |" for k, v in rows]
|
||||
out += [line.strip() for line in tail]
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def _as_ruled_table(para: list[str]) -> str | None:
|
||||
"""Render a header + solid-rule + rows block as an N-column table, else None.
|
||||
|
||||
This is the "Component Reference" tables' convention: header row, a
|
||||
dashed rule, then data rows at the same indent (no ":"-label, no extra
|
||||
nesting — the two things _as_table looks for). A row that splits into
|
||||
just one cell is a word-wrapped continuation of the row above; anything
|
||||
else that doesn't match the header's column count is a source alignment
|
||||
bug, so bail out to the code-block fallback rather than guess.
|
||||
"""
|
||||
if len(para) < 4:
|
||||
return None
|
||||
rule_cells = CELL_SPLIT.split(para[1].strip())
|
||||
if not all(RULE_CELL_RE.match(cell) for cell in rule_cells):
|
||||
return None
|
||||
header = CELL_SPLIT.split(para[0].strip())
|
||||
n = len(header)
|
||||
if n < 2:
|
||||
return None
|
||||
rows: list[list[str]] = []
|
||||
for line in para[2:]:
|
||||
parts = CELL_SPLIT.split(line.strip(), n - 1)
|
||||
if len(parts) == n:
|
||||
rows.append(parts)
|
||||
elif len(parts) == 1 and rows:
|
||||
rows[-1][-1] += " " + parts[0].strip()
|
||||
else:
|
||||
return None
|
||||
if len(rows) < 2:
|
||||
return None
|
||||
|
||||
# Unlike _as_table's prose column, these tables legitimately contain
|
||||
# placeholders like <session> or brace globs — code-span protects them
|
||||
# instead of rejecting the whole table.
|
||||
def cell(text: str, code: bool) -> str:
|
||||
needs_protection = ("<" in text or "{" in text) and "`" not in text
|
||||
return _cell(text, code or needs_protection)
|
||||
|
||||
out = [f"| {' | '.join(header)} |", "|" + "|".join(["---"] * n) + "|"]
|
||||
for row in rows:
|
||||
cells = [cell(row[0], True)] + [cell(c, False) for c in row[1:]]
|
||||
out.append(f"| {' | '.join(cells)} |")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
TREE_ROOT_RE = re.compile(r"^[~$][\w./{}-]*/$")
|
||||
TREE_BRANCH_RE = re.compile(r"^([│ \t]*)[├└]──\s*(\S+)\s*(.*)$")
|
||||
|
||||
|
||||
def _as_file_tree(para: list[str]) -> str | None:
|
||||
"""Render a hand-drawn box-drawing tree as a Starlight <FileTree>, else None."""
|
||||
if len(para) < 2 or not TREE_ROOT_RE.match(para[0].strip()):
|
||||
return None
|
||||
branches = []
|
||||
for line in para[1:]:
|
||||
m = TREE_BRANCH_RE.match(line)
|
||||
if not m:
|
||||
return None
|
||||
branches.append(m.groups())
|
||||
out = ["<FileTree>", f"- {para[0].strip()}"]
|
||||
for prefix, name, desc in branches:
|
||||
depth = len(prefix.replace('\t', ' ')) // 4
|
||||
indent = " " * (depth + 1)
|
||||
out.append(f"{indent}- {name} {desc}".rstrip())
|
||||
out.append("</FileTree>")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def _render_para(para: list[str], entry_name: str | None, deeper: bool) -> str:
|
||||
"""Render one paragraph of a former indented block.
|
||||
|
||||
`deeper` marks paragraphs carrying their own extra indentation — nested
|
||||
option tables, whose alignment only survives inside a code block.
|
||||
"""
|
||||
if not deeper:
|
||||
if _is_prose(para):
|
||||
return "\n".join(line.strip() for line in para)
|
||||
if len(para) == 1 and PATH_LINE_RE.match(para[0].strip()):
|
||||
path = para[0].strip()
|
||||
name = path.rsplit("/", 1)[-1]
|
||||
return f'```fish title="{name}"\n{path}\n```'
|
||||
if _is_shell(para, entry_name):
|
||||
body = para
|
||||
title = None
|
||||
m = FILENAME_COMMENT_RE.match(para[0].strip())
|
||||
if m:
|
||||
title, body = m.group(1), para[1:]
|
||||
info = f'fish title="{title}"' if title else "fish"
|
||||
return f"```{info}\n" + "\n".join(body) + "\n```"
|
||||
table = _as_ruled_table(para) or _as_table(para) or _as_file_tree(para)
|
||||
if table is not None:
|
||||
return table
|
||||
return "\n".join(INDENT + line for line in para)
|
||||
|
||||
|
||||
def _prettify_block(block: list[str], entry_name: str | None) -> str:
|
||||
"""Convert one indented block into fenced code, prose, and tables.
|
||||
|
||||
The manual is authored man-page style: every example, table, and
|
||||
description sits in a single 4-space-indented block, which renders on
|
||||
the site as one unhighlighted grey slab. Splitting a block into its
|
||||
paragraphs recovers the structure the indentation flattened.
|
||||
"""
|
||||
lines = [line[len(INDENT) :] if line.startswith(INDENT) else line for line in block]
|
||||
|
||||
out: list[str] = []
|
||||
if lines and lines[0].startswith(SYNOPSIS_PREFIX):
|
||||
synopsis = [lines.pop(0)[len(SYNOPSIS_PREFIX) :].strip()]
|
||||
# A multi-line synopsis is authored aligned under the first line;
|
||||
# keep the whole thing in one fence rather than orphaning the rest.
|
||||
while lines and lines[0].startswith(" "):
|
||||
synopsis.append(lines.pop(0).strip())
|
||||
# A "Usage" title (Starlight's filename-title convention, repurposed
|
||||
# as a label) makes the synopsis read as a snippet of the function
|
||||
# it documents rather than a bare command example.
|
||||
info = 'fish title="Usage"' if entry_name else "fish"
|
||||
out.append(f"```{info}\n" + "\n".join(synopsis) + "\n```")
|
||||
|
||||
para: list[str] = []
|
||||
for line in lines + [""]:
|
||||
if line.strip():
|
||||
para.append(line)
|
||||
continue
|
||||
if para:
|
||||
if para[0].strip() == EXAMPLE_PREFIX:
|
||||
example = para[1:]
|
||||
if example and _is_shell(example, entry_name):
|
||||
body = "\n".join(example)
|
||||
out.append(f'```fish title="Examples"\n{body}\n```')
|
||||
else:
|
||||
deeper = any(line.startswith(" ") for line in example)
|
||||
out.append(_render_para(example, entry_name, deeper))
|
||||
else:
|
||||
deeper = any(line.startswith(" ") for line in para)
|
||||
out.append(_render_para(para, entry_name, deeper))
|
||||
para = []
|
||||
return "\n\n".join(chunk for chunk in out if chunk.strip())
|
||||
|
||||
|
||||
ASIDE_LABELS: dict[str, tuple[str, str, str | None]] = {
|
||||
"NOTE": ("note", "Note", None),
|
||||
"IMPORTANT": ("note", "Important", "star"),
|
||||
"TIP": ("tip", "Tip", None),
|
||||
"HINT": ("tip", "Hint", "question-circle"),
|
||||
"WARNING": ("caution", "Warning", "warning"),
|
||||
"CAUTION": ("caution", "Caution", None),
|
||||
"DANGER": ("danger", "Danger", None),
|
||||
}
|
||||
ASIDE_RE = re.compile(rf"^({'|'.join(ASIDE_LABELS)}):\s*(.*)$")
|
||||
|
||||
|
||||
def _as_aside(para: list[str]) -> str | None:
|
||||
"""Render a `LABEL: ...` flat paragraph as a Starlight <Aside>, else None."""
|
||||
m = ASIDE_RE.match(para[0])
|
||||
if not m:
|
||||
return None
|
||||
label, rest = m.groups()
|
||||
aside_type, title, icon = ASIDE_LABELS[label]
|
||||
body = "\n".join(([rest] if rest else []) + para[1:])
|
||||
attrs = f'type="{aside_type}" title="{title}"'
|
||||
if icon:
|
||||
attrs += f' icon="{icon}"'
|
||||
return f"<Aside {attrs}>\n{body}\n</Aside>"
|
||||
|
||||
|
||||
def prettify(body: str, entry_name: str | None = None) -> str:
|
||||
"""Rewrite a body's indented code blocks and labeled asides for the website.
|
||||
|
||||
Site-only: the man page and `config-help` keep reading the untouched
|
||||
SSOT, where the indented form and the `LABEL:` text are exactly what
|
||||
pandoc/`config-help` want.
|
||||
"""
|
||||
out: list[str] = []
|
||||
block: list[str] = []
|
||||
flat: list[str] = []
|
||||
in_fence = False
|
||||
|
||||
def flush_flat() -> None:
|
||||
out.append(_as_aside(flat) or "\n".join(flat))
|
||||
|
||||
for line in body.split("\n"):
|
||||
if mt.FENCE_RE.match(line):
|
||||
in_fence = not in_fence
|
||||
if not in_fence and (line.startswith(INDENT) or (not line.strip() and block)):
|
||||
if flat:
|
||||
flush_flat()
|
||||
flat.clear()
|
||||
block.append(line)
|
||||
continue
|
||||
if block:
|
||||
while block and not block[-1].strip():
|
||||
block.pop()
|
||||
out.append(_prettify_block(block, entry_name))
|
||||
out.append("")
|
||||
block = []
|
||||
if in_fence or not line.strip():
|
||||
if flat:
|
||||
flush_flat()
|
||||
flat.clear()
|
||||
out.append(line)
|
||||
else:
|
||||
flat.append(line)
|
||||
|
||||
if flat:
|
||||
flush_flat()
|
||||
if block:
|
||||
while block and not block[-1].strip():
|
||||
block.pop()
|
||||
out.append(_prettify_block(block, entry_name))
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
ENTRY_HEADS = {
|
||||
"ARGUMENTS": "Arguments:",
|
||||
"EXIT STATUS": "Exit Status:",
|
||||
"RETURNS": "Returns:",
|
||||
"NOTES": "Notes:",
|
||||
}
|
||||
|
||||
|
||||
def render_entry(fn: dict[str, list[str]], used_by: list[str], link=None) -> str:
|
||||
"""Render one parsed function header as a manual entry body.
|
||||
|
||||
Emits the same man-page shape Section 5 was authored in — one 4-space
|
||||
indented block opening with `Synopsis:` — so `prettify` keeps handling it
|
||||
for the site and pandoc keeps handling it for the man page, with no
|
||||
special case on either side.
|
||||
|
||||
`link` maps a function name to its markdown link, or is None for the man
|
||||
page, where a URL in the middle of a sentence is noise.
|
||||
"""
|
||||
out: list[str] = []
|
||||
syn = fn.get("SYNOPSIS", [])
|
||||
if syn:
|
||||
pad = " " * len(SYNOPSIS_PREFIX + " ")
|
||||
out.append(f"{SYNOPSIS_PREFIX} {syn[0]}")
|
||||
out += [pad + line for line in syn[1:]]
|
||||
out.append("")
|
||||
for line in fn.get("DESCRIPTION", []):
|
||||
out.append(line)
|
||||
for label, head in ENTRY_HEADS.items():
|
||||
body = fn.get(label)
|
||||
if not body:
|
||||
continue
|
||||
out += ["", head] + [" " + line for line in body]
|
||||
if fn.get("EXAMPLE"):
|
||||
out += ["", EXAMPLE_PREFIX] + fn["EXAMPLE"]
|
||||
|
||||
block = "\n".join((INDENT + line).rstrip() for line in out)
|
||||
|
||||
def names(raw: list[str]) -> list[str]:
|
||||
return [n for n in re.split(r"[,\s]+", " ".join(raw)) if n]
|
||||
|
||||
refs = []
|
||||
for label, values in (
|
||||
("Dependencies", names(fn.get("DEPENDENCIES", []))),
|
||||
("Used by", sorted(used_by)),
|
||||
):
|
||||
if values:
|
||||
rendered = ", ".join(link(v) if link else f"`{v}`" for v in values)
|
||||
refs.append(f"**{label}:** {rendered}")
|
||||
if refs:
|
||||
block += "\n\n" + "\n\n".join(refs)
|
||||
return block
|
||||
|
||||
|
||||
def build_entries(functions: dict[str, dict], link=None) -> dict[str, list[tuple[str, str]]]:
|
||||
"""Group rendered entries by category stem, ordered by function name.
|
||||
|
||||
The `Used by` reverse index is computed here in one pass rather than
|
||||
authored: a bidirectional link maintained by hand drifts the moment one
|
||||
side is edited.
|
||||
"""
|
||||
used_by: dict[str, list[str]] = {}
|
||||
for name, fn in functions.items():
|
||||
for dep in re.split(r"[,\s]+", " ".join(fn.get("DEPENDENCIES", []))):
|
||||
if dep in functions:
|
||||
used_by.setdefault(dep, []).append(name)
|
||||
|
||||
out: dict[str, list[tuple[str, str]]] = {}
|
||||
for name in sorted(functions):
|
||||
fn = functions[name]
|
||||
body = render_entry(fn, used_by.get(name, []), link)
|
||||
out.setdefault(fn["CATEGORY"][0], []).append((name, body))
|
||||
return out
|
||||
|
||||
|
||||
def _page_fm(fm: dict) -> dict:
|
||||
"""Strip pipeline-only keys from frontmatter destined for the site."""
|
||||
return {k: v for k, v in fm.items() if k not in PIPELINE_KEYS}
|
||||
|
||||
|
||||
def _split_entries(body: str) -> tuple[str, list[tuple[str, str]]]:
|
||||
"""Split a category body into (intro, [(entry title, entry body)]).
|
||||
|
||||
Fence-aware: an H2-looking line (`## ...`) inside a fenced code block
|
||||
(tracked the same way as `manualtools.shift_headings`) is treated as
|
||||
ordinary body text, not an entry boundary.
|
||||
"""
|
||||
lines = body.split("\n")
|
||||
heading_re = re.compile(r"^## (.+)$")
|
||||
boundaries: list[tuple[int, str]] = []
|
||||
in_fence = False
|
||||
for i, line in enumerate(lines):
|
||||
if mt.FENCE_RE.match(line):
|
||||
in_fence = not in_fence
|
||||
continue
|
||||
if not in_fence:
|
||||
m = heading_re.match(line)
|
||||
if m:
|
||||
boundaries.append((i, m.group(1)))
|
||||
|
||||
if not boundaries:
|
||||
return body.strip(), []
|
||||
|
||||
intro = "\n".join(lines[: boundaries[0][0]]).strip()
|
||||
entries = []
|
||||
for idx, (line_no, title) in enumerate(boundaries):
|
||||
start = line_no + 1
|
||||
end = boundaries[idx + 1][0] if idx + 1 < len(boundaries) else len(lines)
|
||||
# Strip newlines only: a bare .strip() would eat the leading
|
||||
# indentation of the entry's first line, detaching the `Synopsis:`
|
||||
# line from the indented block it opens.
|
||||
entry_body = "\n".join(lines[start:end]).strip("\n")
|
||||
entries.append((title.strip(), entry_body))
|
||||
return intro, entries
|
||||
|
||||
|
||||
|
||||
def _inject_subheading_cards(body: str) -> str:
|
||||
"""Extract `## Heading`s and inject a CardGrid after the intro."""
|
||||
headings = []
|
||||
for line in body.splitlines():
|
||||
m = re.match(r"^##\s+(.+)$", line)
|
||||
if m:
|
||||
headings.append(m.group(1).strip())
|
||||
|
||||
if len(headings) < 2:
|
||||
return body
|
||||
|
||||
parts = body.split("\n## ", 1)
|
||||
if len(parts) != 2:
|
||||
return body
|
||||
|
||||
intro = parts[0].strip()
|
||||
rest = "## " + parts[1]
|
||||
|
||||
cards = []
|
||||
for title in headings:
|
||||
safe_title = _jsx_attr_escape(title)
|
||||
slug = re.sub(r"[^\w\s-]", "", title.lower())
|
||||
slug = re.sub(r"[-\s]+", "-", slug).strip("-")
|
||||
cards.append(f' <LinkCard title="{safe_title}" href="#{slug}" />')
|
||||
|
||||
cardgrid = "<CardGrid>\n" + "\n".join(cards) + "\n</CardGrid>\n\n"
|
||||
|
||||
return f"{intro}\n\n{cardgrid}{rest}"
|
||||
|
||||
ASTRO_ASIDE_COMPONENTS = {"<Aside": "Aside", "<FileTree": "FileTree", "<LinkButton": "LinkButton", "<CardGrid": "CardGrid", "<LinkCard": "LinkCard"}
|
||||
|
||||
|
||||
def _write_prettified(target: Path, fm: dict, content: str) -> None:
|
||||
"""Write a prettified page, promoting to .mdx when it needs a component import.
|
||||
|
||||
A page stays .md (prettify()'s default, no imports) unless its rendered
|
||||
content actually contains an <Aside> or <FileTree> — the only two
|
||||
components a prettified (non-hand-built) page can contain.
|
||||
"""
|
||||
needed = [name for marker, name in ASTRO_ASIDE_COMPONENTS.items() if marker in content]
|
||||
if needed:
|
||||
imports = f"import {{ {', '.join(needed)} }} from '@astrojs/starlight/components';\n\n"
|
||||
target = target.with_suffix(".mdx")
|
||||
content = imports + content
|
||||
target.write_text(mt.serialize(fm, content))
|
||||
|
||||
|
||||
def build_site(root: Path, out: Path) -> list[dict]:
|
||||
"""Write the Starlight content tree. Returns the sidebar structure."""
|
||||
if out.exists():
|
||||
shutil.rmtree(out)
|
||||
out.mkdir(parents=True)
|
||||
|
||||
functions = mt.parse_functions(FUNCTIONS)
|
||||
entries = build_entries(functions, link=lambda n: _entry_link(n, functions))
|
||||
|
||||
sidebar: list[dict] = [{"label": "Home", "link": "/"}]
|
||||
standard_groups: dict = {}
|
||||
functions_group: dict = {}
|
||||
functions_index_target = None
|
||||
functions_index_fm = None
|
||||
functions_index_body = None
|
||||
functions_cards = []
|
||||
for path, _depth in mt.walk(root):
|
||||
fm, body = mt.parse(path)
|
||||
if not fm.get("site", True):
|
||||
continue
|
||||
|
||||
rel = path.relative_to(root)
|
||||
is_function_dir = rel.parts and rel.parts[0].endswith("-functions")
|
||||
|
||||
if not is_function_dir:
|
||||
target = out / rel
|
||||
if "04-abbreviations" in path.parts:
|
||||
abbrs = mt.parse_abbreviations(DOCS.parent / "conf.d")
|
||||
body = _with_abbreviations(body, abbrs)
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
body = _inject_subheading_cards(body)
|
||||
_write_prettified(target, _page_fm(fm), prettify(body))
|
||||
|
||||
if len(rel.parts) > 1:
|
||||
group_dir = rel.parts[0]
|
||||
if rel.name == "index.md":
|
||||
group = {
|
||||
"label": fm["title"],
|
||||
"collapsed": True,
|
||||
"items": [{"label": "Categories", "link": f"/{group_dir}/"}]
|
||||
}
|
||||
standard_groups[group_dir] = group
|
||||
sidebar.append(group)
|
||||
elif rel.name != "404.md":
|
||||
if group_dir in standard_groups:
|
||||
standard_groups[group_dir]["items"].append({
|
||||
"label": fm["title"],
|
||||
"link": f"/{group_dir}/{rel.stem}/"
|
||||
})
|
||||
else:
|
||||
sidebar.append({"label": fm["title"], "link": f"/{group_dir}/{rel.stem}/"})
|
||||
else:
|
||||
if rel.name not in ("index.md", "404.md"):
|
||||
sidebar.append({"label": fm["title"], "link": "/" + rel.stem + "/"})
|
||||
continue
|
||||
|
||||
# Section 5: category index page keeps its slot; entries explode.
|
||||
#
|
||||
# Deliberately NOT "functions": Cloudflare Pages reserves a top-level
|
||||
# `functions/` directory in the deploy output for Pages Functions
|
||||
# (server-side handlers) and silently drops it from the static-asset
|
||||
# upload. The pages build fine and never arrive — every entry 404s in
|
||||
# production while working locally. test_site_avoids_reserved_dir
|
||||
# guards this.
|
||||
slug_dir = SLUG_DIR
|
||||
if rel.name == "index.md":
|
||||
functions_index_target = out / slug_dir / "index.md"
|
||||
functions_index_fm = fm
|
||||
functions_index_body = body
|
||||
functions_cards = []
|
||||
|
||||
# Built explicitly rather than by `autogenerate`, which labels
|
||||
# each group with its raw directory slug and republishes this
|
||||
# index as a child of the group it already titles.
|
||||
functions_group = {
|
||||
"label": fm["title"],
|
||||
"collapsed": True,
|
||||
"items": [{"label": "Categories", "link": f"/{slug_dir}/"}],
|
||||
}
|
||||
sidebar.append(functions_group)
|
||||
continue
|
||||
|
||||
category = re.sub(r"^\d+-", "", rel.stem)
|
||||
cat_dir = out / slug_dir / category
|
||||
cat_dir.mkdir(parents=True, exist_ok=True)
|
||||
intro, page_entries = _split_entries(_with_entries(body, path, entries))
|
||||
|
||||
cat_title = fm["title"]
|
||||
cat_desc = fm.get("description", "")
|
||||
safe_title = _jsx_attr_escape(cat_title)
|
||||
safe_desc = _jsx_attr_escape(cat_desc)
|
||||
href = f"/{slug_dir}/{category}/"
|
||||
functions_cards.append(
|
||||
f' <LinkCard title="{safe_title}" href="{href}"'
|
||||
+ (f' description="{safe_desc}"' if cat_desc else "")
|
||||
+ " />"
|
||||
)
|
||||
|
||||
cards = []
|
||||
links = []
|
||||
for title, entry_body in page_entries:
|
||||
entry_slug = _entry_slug(title)
|
||||
desc = _first_sentence(entry_body)
|
||||
entry_fm = {"title": title}
|
||||
if desc:
|
||||
entry_fm["description"] = desc
|
||||
_write_prettified(
|
||||
cat_dir / f"{entry_slug}.md",
|
||||
entry_fm,
|
||||
prettify(entry_body, title.split()[0]),
|
||||
)
|
||||
href = f"/{slug_dir}/{category}/{entry_slug}/"
|
||||
links.append({"label": title, "link": href})
|
||||
safe_title = _jsx_attr_escape(title)
|
||||
safe_desc = _jsx_attr_escape(desc)
|
||||
cards.append(
|
||||
f' <LinkCard title="{safe_title}" href="{href}"'
|
||||
+ (f' description="{safe_desc}"' if desc else "")
|
||||
+ " />"
|
||||
)
|
||||
|
||||
overview = (
|
||||
"import { CardGrid, LinkCard } from '@astrojs/starlight/components';\n\n"
|
||||
+ (f"{intro}\n\n" if intro else "")
|
||||
+ "<CardGrid>\n"
|
||||
+ "\n".join(cards)
|
||||
+ "\n</CardGrid>\n"
|
||||
)
|
||||
(cat_dir / "index.mdx").write_text(mt.serialize(_page_fm(fm), overview))
|
||||
|
||||
functions_group.setdefault("items", []).append(
|
||||
{
|
||||
"label": fm["title"],
|
||||
"collapsed": True,
|
||||
"items": [
|
||||
{"label": f"{fm['title']} Overview", "link": f"/{slug_dir}/{category}/"},
|
||||
*links,
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
if functions_index_target:
|
||||
overview_content = (
|
||||
(f"{functions_index_body}\n\n" if functions_index_body.strip() else "")
|
||||
+ "<CardGrid>\n"
|
||||
+ "\n".join(functions_cards)
|
||||
+ "\n</CardGrid>\n"
|
||||
)
|
||||
_write_prettified(functions_index_target, _page_fm(functions_index_fm), prettify(overview_content))
|
||||
|
||||
return sidebar
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("--concat", action="store_true", help="emit the pandoc document")
|
||||
ap.add_argument("--site", action="store_true", help="emit the Starlight content tree")
|
||||
ap.add_argument("-o", "--output", type=Path, help="write to PATH instead of stdout")
|
||||
args = ap.parse_args()
|
||||
|
||||
if not (args.concat or args.site):
|
||||
ap.error("nothing to do: pass --concat and/or --site")
|
||||
|
||||
generate_component_registry.main()
|
||||
|
||||
if args.site:
|
||||
src = DOCS / "site" / "src"
|
||||
out = src / "content" / "docs"
|
||||
sidebar = build_site(MANUAL, out)
|
||||
(src / "sidebar.json").write_text(json.dumps(sidebar, indent=2) + "\n")
|
||||
print(f"wrote site content to {out} ({len(sidebar)} sidebar entries)")
|
||||
|
||||
if args.concat:
|
||||
text = build_concat(MANUAL)
|
||||
if args.output:
|
||||
args.output.write_text(text)
|
||||
print(f"wrote {args.output}")
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
raise SystemExit(main())
|
||||
+5187
File diff suppressed because it is too large
Load Diff
+167
-17
@@ -2,7 +2,7 @@
|
||||
# Format: keyword=exact heading text as it appears in fish-config.md
|
||||
# Multiple keywords may map to the same heading.
|
||||
# Update this file whenever headings are added, removed, or renamed.
|
||||
# config_help uses this for fast exact lookups; unknown keywords fall back
|
||||
# config-help uses this for fast exact lookups; unknown keywords fall back
|
||||
# to a normalized heading scan automatically.
|
||||
|
||||
# ── Top-level ─────────────────────────────────────────────────
|
||||
@@ -11,6 +11,10 @@ synopsis=# SYNOPSIS
|
||||
description=# DESCRIPTION
|
||||
toc=# TABLE OF CONTENTS
|
||||
contents=# TABLE OF CONTENTS
|
||||
autopair=# DESCRIPTION
|
||||
puffer=# DESCRIPTION
|
||||
puffer-fish=# DESCRIPTION
|
||||
logging-events=# DESCRIPTION
|
||||
|
||||
# ── Section 1: Configuration Variables ───────────────────────
|
||||
variables=# 1. CONFIGURATION VARIABLES
|
||||
@@ -20,6 +24,9 @@ toolhomes=## Tool Homes (XDG-compliant)
|
||||
editor=## Editor and Pager
|
||||
pager=## Editor and Pager
|
||||
scrollback=## Scrollback History
|
||||
__fish_scrollback_history_dir=## Scrollback History
|
||||
__fish_scrollback_history_max_files=## Scrollback History
|
||||
scrollback-dir=## Scrollback History
|
||||
|
||||
# ── Section 2: PATH ───────────────────────────────────────────
|
||||
path=# 2. PATH SETUP
|
||||
@@ -29,8 +36,8 @@ keybindings=# 3. KEY BINDINGS
|
||||
bindings=# 3. KEY BINDINGS
|
||||
key-bindings=# 3. KEY BINDINGS
|
||||
keys=# 3. KEY BINDINGS
|
||||
fzf-bindings=## FZF Bindings (from fzf --fish integration)
|
||||
fzf=## FZF Bindings (from fzf --fish integration)
|
||||
fzf-bindings=## FZF Bindings (bundled from PatrickF1/fzf.fish)
|
||||
fzf=## FZF Bindings (bundled from PatrickF1/fzf.fish)
|
||||
|
||||
# ── Section 4: Abbreviations ──────────────────────────────────
|
||||
abbreviations=# 4. ABBREVIATIONS
|
||||
@@ -71,6 +78,7 @@ mkdir=### mkdir
|
||||
mkcd=### mkcd
|
||||
poke=### poke
|
||||
rm=### rm
|
||||
rg=### rg
|
||||
scrub=### scrub
|
||||
nav-fns=## 5.2 Navigation
|
||||
cdi=### cdi
|
||||
@@ -83,6 +91,7 @@ less=### less
|
||||
rawfish=### rawfish
|
||||
view=### view
|
||||
git=## 5.4 Git and Version Control
|
||||
auto-pull=### auto-pull
|
||||
branch=### branch
|
||||
gi=### gi
|
||||
gitignore=### gi
|
||||
@@ -116,6 +125,8 @@ split=### split
|
||||
spwin=### spwin
|
||||
detach=### detach
|
||||
bkg=### bkg
|
||||
jobrunner=### jobrunner
|
||||
jr=### jr
|
||||
ssh=### ssh
|
||||
clipboard=## 5.9 Clipboard
|
||||
copy-fn=### y
|
||||
@@ -128,16 +139,37 @@ logging=## 5.11 Pager and Logging
|
||||
logs=### logs
|
||||
smart-exit=### smart_exit
|
||||
ai=## 5.12 AI and Developer Tools
|
||||
antigravity=### antigravity
|
||||
claude=### claude-resume
|
||||
antigravity-ide=### antigravity-ide
|
||||
agy=### agy
|
||||
agents-init=### agents-init
|
||||
agents=### agents-init
|
||||
agents-tools=### agents-init
|
||||
version-bump=### agents-init
|
||||
.version=### agents-init
|
||||
structure-version=### agents-init
|
||||
core.hooksPath=### agents-init
|
||||
devlogs=### agents-init
|
||||
claude-cli=### claude
|
||||
claude-docs=### claude-docs
|
||||
claude-pr=### claude-pr
|
||||
code-resume=### code-resume
|
||||
qc=### qc
|
||||
quick-chat=### qc
|
||||
aichat=### qc
|
||||
superpowers=### superpowers
|
||||
media=## 5.13 Media and Utilities
|
||||
dng2avif=### dng2avif
|
||||
spark=### spark
|
||||
yt-dlp=### yt-dlp
|
||||
miscfns=## 5.14 Miscellaneous
|
||||
config-help=### config-help
|
||||
open-url=### open-url
|
||||
url-open=### open-url
|
||||
repo-open=### repo-open
|
||||
open-repo=### repo-open
|
||||
config-update=### config-update
|
||||
config-settings=### config-settings
|
||||
config-toggle=### config-settings
|
||||
toggle=### config-settings
|
||||
bash=### bash
|
||||
cheat=### cheat
|
||||
dockup=### dockup
|
||||
@@ -145,7 +177,37 @@ joplin=### joplin
|
||||
replay=### replay
|
||||
tmux=### tmux-clean
|
||||
wake-lock=### wake-lock
|
||||
zellij=### zellij
|
||||
|
||||
# ── Tool-name synonyms (replacement → shadowed command) ──────
|
||||
# These tools don't appear in any heading, so the fallback scan can't
|
||||
# find them; map each to the function that wraps it.
|
||||
eza=### ls
|
||||
exa=### ls
|
||||
lsd=### ls
|
||||
trash=### rm
|
||||
btop=### top
|
||||
prettyping=### ping
|
||||
duf=### du
|
||||
dust=### du
|
||||
kitten=### ssh
|
||||
bat=### cat
|
||||
|
||||
# ── Tool integrations (Section: Integrations) ────────────────
|
||||
zoxide=### Zoxide
|
||||
z=### Zoxide
|
||||
direnv=### DirEnv
|
||||
venv=### Auto Python Venv
|
||||
virtualenv=### Auto Python Venv
|
||||
python=### Auto Python Venv
|
||||
wakatime=### WakaTime
|
||||
tailscale=### Tailscale
|
||||
done=### Done Notifications
|
||||
notifications=### Done Notifications
|
||||
notify=### Done Notifications
|
||||
pager-hierarchy=## Pager Hierarchy
|
||||
shell-aliases=## 4.11 Shell Aliases
|
||||
kitty-logging=### kitty-logging
|
||||
watcher=### kitty-logging
|
||||
|
||||
# ── Section 6: Dependency Catalog ────────────────────────────
|
||||
catalog=# 6. DEPENDENCY CATALOG
|
||||
@@ -159,18 +221,106 @@ install-methods=## Install Methods
|
||||
customization=# 7. CUSTOMIZATION
|
||||
customize=# 7. CUSTOMIZATION
|
||||
local=## Machine-local Configuration
|
||||
user-dots=## Machine-local Configuration
|
||||
dots-link=## Machine-local Configuration
|
||||
secrets=## Secrets and API Keys
|
||||
overrides=## Overriding Configuration Variables
|
||||
universal=## Fish Universal Variables
|
||||
opinionated=## Opinionated Components (Minimal Mode)
|
||||
minimal=## Opinionated Components (Minimal Mode)
|
||||
minimal-mode=## Opinionated Components (Minimal Mode)
|
||||
opt-out=## Opinionated Components (Minimal Mode)
|
||||
toggles=## Opinionated Components (Minimal Mode)
|
||||
component-reference=# 8. COMPONENTS REFERENCE
|
||||
components=# 8. COMPONENTS REFERENCE
|
||||
c1=## C1 — Command Shadows
|
||||
command-shadows=## C1 — Command Shadows
|
||||
aliases-detail=## C1 — Command Shadows
|
||||
c2=## C2 — Startup Side-Effects
|
||||
autoexec=## C2 — Startup Side-Effects
|
||||
startup=## C2 — Startup Side-Effects
|
||||
c3=## C3 — Key and Environment Overrides
|
||||
overrides-detail=## C3 — Key and Environment Overrides
|
||||
bang-bang=## C3 — Key and Environment Overrides
|
||||
c4=## C4 — Terminal and Tool Integration
|
||||
integrations-detail=## C4 — Terminal and Tool Integration
|
||||
c5=## C5 — Logging and Capture
|
||||
logging-detail=## C5 — Logging and Capture
|
||||
logging-sentinel=## C5 — Logging and Capture
|
||||
zellij=## C5 — Logging and Capture
|
||||
zellij-logging=## C5 — Logging and Capture
|
||||
tmux-logging=## C5 — Logging and Capture
|
||||
pipe-pane=## C5 — Logging and Capture
|
||||
dump-screen=## C5 — Logging and Capture
|
||||
c6=## C6 — Greeting and First-Run UI
|
||||
greeting=## C6 — Greeting and First-Run UI
|
||||
|
||||
# ── Prompt and Theme ──────────────────────────────────────────
|
||||
prompt-theme=## Prompt and Theme
|
||||
starship=### Starship
|
||||
fallback-prompt=### Catppuccin Fallback Prompt
|
||||
catppuccin-prompt=### Catppuccin Fallback Prompt
|
||||
nim-prompt=### Catppuccin Fallback Prompt
|
||||
fzf-theme=### FZF
|
||||
catppuccin-theme=### Catppuccin Mocha Syntax Highlighting
|
||||
|
||||
# ── Section 9: Fisher Plugins ─────────────────────────────────
|
||||
plugins=# 9. FISHER PLUGINS
|
||||
fisher=# 9. FISHER PLUGINS
|
||||
fisher-managed=## Fisher-Managed Plugins
|
||||
sponge=## Fisher-Managed Plugins
|
||||
sponge-filtering=## Sponge History Filtering
|
||||
history-filtering=## Sponge History Filtering
|
||||
privacy=## Sponge History Filtering
|
||||
__fish_sponge_extra_sensitive=## Sponge History Filtering
|
||||
extra-sensitive=## Sponge History Filtering
|
||||
sponge-settings=### config-settings
|
||||
bundled-plugins=## Bundled Plugin Functionality
|
||||
fish-plugins-manifest=## fish_plugins Manifest
|
||||
|
||||
# ── Section 10: Installation ────────────────────────────────────
|
||||
installation=# 10. INSTALLATION
|
||||
install=# 10. INSTALLATION
|
||||
sentinel=## Return Sentinel
|
||||
updating=## Updating
|
||||
|
||||
# ── Section 11: Personalization ───────────────────────────────
|
||||
personalization=# 11. PERSONALIZATION
|
||||
personalize=# 11. PERSONALIZATION
|
||||
secrets-file=## secrets.fish
|
||||
local-config=## local.fish
|
||||
|
||||
# ── Section 12: Troubleshooting ──────────────────────────────
|
||||
troubleshooting=# 12. TROUBLESHOOTING
|
||||
troubleshoot=# 12. TROUBLESHOOTING
|
||||
faq=# 12. TROUBLESHOOTING
|
||||
uninstall=## Uninstalling and Reverting to Backup
|
||||
revert=## Uninstalling and Reverting to Backup
|
||||
fish-version=## Fish Version Requirement
|
||||
version-req=## Fish Version Requirement
|
||||
disable-logging=## Enable or Disable Session Logging
|
||||
enable-logging=## Enable or Disable Session Logging
|
||||
disable-greeting=## Change or Disable the Greeting
|
||||
change-greeting=## Change or Disable the Greeting
|
||||
secrets-trouble=## Secrets and Machine-Local Configuration
|
||||
local-trouble=## Secrets and Machine-Local Configuration
|
||||
return-sentinel=## Tool Init Does Nothing (Return Sentinel)
|
||||
tool-init=## Tool Init Does Nothing (Return Sentinel)
|
||||
missing-deps=## Missing Dependencies
|
||||
vi-mode=## Vi Mode Keybindings
|
||||
vi-trouble=## Vi Mode Keybindings
|
||||
emacs-mode=## Vi Mode Keybindings
|
||||
minimal-trouble=## What's with the C1-C6 stuff?
|
||||
|
||||
# ── Section 13: Viewing This Manual ──────────────────────────
|
||||
viewing=# 13. VIEWING THIS MANUAL
|
||||
manual=# 13. VIEWING THIS MANUAL
|
||||
ov=## In the terminal
|
||||
man-page=## As a man page
|
||||
manpage=## As a man page
|
||||
jump=## In the terminal
|
||||
html=## The documentation website
|
||||
browser=## The documentation website
|
||||
site=## The documentation website
|
||||
|
||||
# ── Section 8: Fisher Plugins ─────────────────────────────────
|
||||
plugins=# 8. FISHER PLUGINS
|
||||
fisher=# 8. FISHER PLUGINS
|
||||
|
||||
# ── Section 9: Viewing This Manual ───────────────────────────
|
||||
viewing=# 9. VIEWING THIS MANUAL
|
||||
manual=# 9. VIEWING THIS MANUAL
|
||||
ov=## With ov (recommended)
|
||||
man-page=## As a man page (if compiled)
|
||||
manpage=## As a man page (if compiled)
|
||||
jump=## Jumping to a section
|
||||
|
||||
+3317
-552
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Generate the committed opinionated-component registry.
|
||||
|
||||
Walks every `# COMPONENT` header in functions/*.fish, conf.d/*.fish, and
|
||||
config.fish and writes conf.d/__fish_config_op_registry.fish, the fish
|
||||
data file __fish_config_op_registry_lookup reads at shell startup.
|
||||
|
||||
Run manually (via __fish_config_op_registry_rebuild) after editing a
|
||||
# COMPONENT header, and automatically as a pre-step in build-manual.py
|
||||
before the manual is built.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import manualtools as mt
|
||||
|
||||
DOCS = Path(__file__).parent
|
||||
REPO = DOCS.parent
|
||||
OUTPUT = REPO / "conf.d" / "__fish_config_op_registry.fish"
|
||||
|
||||
|
||||
def collect_components() -> dict[str, list[str]]:
|
||||
"""Gather every `# COMPONENT` header across the whole repo.
|
||||
|
||||
Concatenates raw component lines when the same identity appears in
|
||||
more than one source (e.g. functions/auto-pull.fish and
|
||||
conf.d/auto-pull.fish both self-identify as "auto-pull" at runtime,
|
||||
since the guard can only ever look up the bare status
|
||||
current-function/basename string) rather than letting one silently
|
||||
overwrite the other.
|
||||
"""
|
||||
out: dict[str, list[str]] = {}
|
||||
for source in (
|
||||
mt.parse_components(REPO / "functions"),
|
||||
mt.parse_components(REPO / "conf.d"),
|
||||
mt.parse_component_file(REPO / "config.fish"),
|
||||
):
|
||||
for identity, lines in source.items():
|
||||
out.setdefault(identity, []).extend(lines)
|
||||
return out
|
||||
|
||||
|
||||
def build_registry(components: dict[str, list[str]]) -> tuple[dict[str, list[str]], list[str]]:
|
||||
"""Turn {identity: [raw COMPONENT lines]} into ({"identity:site": [tags]}, warnings).
|
||||
|
||||
A site with both always/on and always/off tagged is a contradiction:
|
||||
both are stripped and a warning is emitted, but generation continues
|
||||
-- any other real tag on that same site survives. A site whose
|
||||
effective tag set is empty after stripping produces no registry entry
|
||||
at all, which __fish_config_op_enabled already treats as always/on
|
||||
(fail-open) at guard time -- see spec §4.5.
|
||||
"""
|
||||
registry: dict[str, list[str]] = {}
|
||||
warnings: list[str] = []
|
||||
for identity, raw_lines in components.items():
|
||||
by_site: dict[str, list[str]] = {}
|
||||
for site, tag in mt.parse_component_lines(raw_lines):
|
||||
by_site.setdefault(site, []).append(tag)
|
||||
for site, tags in by_site.items():
|
||||
if "always/on" in tags and "always/off" in tags:
|
||||
label = identity if not site else f"{identity}:{site}"
|
||||
warnings.append(
|
||||
f"{label}: both always/on and always/off tagged; ignoring both"
|
||||
)
|
||||
tags = [t for t in tags if t not in ("always/on", "always/off")]
|
||||
if tags:
|
||||
registry[f"{identity}:{site}"] = list(dict.fromkeys(tags))
|
||||
return registry, warnings
|
||||
|
||||
|
||||
def render(registry: dict[str, list[str]]) -> str:
|
||||
keys = sorted(registry)
|
||||
lines = [
|
||||
"# Copyright (C) 2026 Rootiest",
|
||||
"# SPDX-License-Identifier: AGPL-3.0-or-later",
|
||||
"#",
|
||||
"# GENERATED FILE --- do not edit by hand.",
|
||||
"# Regenerate with __fish_config_op_registry_rebuild after editing a",
|
||||
"# # COMPONENT header, or automatically via docs/build-manual.py.",
|
||||
"# Source: docs/generate_component_registry.py",
|
||||
"#",
|
||||
"# This file must be sourced before any other conf.d/*.fish file that",
|
||||
"# calls the opinionated guard. That currently holds only because fish's",
|
||||
"# glob-based conf.d loading happens to sort this filename first",
|
||||
"# alphabetically among the guard-calling files -- do not rename it",
|
||||
"# without preserving that ordering.",
|
||||
"",
|
||||
]
|
||||
if not keys:
|
||||
lines.append("set -g __fish_config_op_registry_keys")
|
||||
lines.append("set -g __fish_config_op_registry_values")
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
quoted_keys = [f'"{k}"' for k in keys]
|
||||
lines.append("set -g __fish_config_op_registry_keys \\")
|
||||
lines += [f" {k} \\" for k in quoted_keys[:-1]] + [f" {quoted_keys[-1]}"]
|
||||
lines.append("")
|
||||
|
||||
values = ['"' + " ".join(registry[k]) + '"' for k in keys]
|
||||
lines.append("set -g __fish_config_op_registry_values \\")
|
||||
lines += [f" {v} \\" for v in values[:-1]] + [f" {values[-1]}"]
|
||||
lines.append("")
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
components = collect_components()
|
||||
registry, warnings = build_registry(components)
|
||||
for w in warnings:
|
||||
print(f" WARN {w}", file=sys.stderr)
|
||||
OUTPUT.write_text(render(registry))
|
||||
print(f"wrote {OUTPUT} ({len(registry)} entries)", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Name
|
||||
manTitle: NAME
|
||||
man: true
|
||||
site: false
|
||||
sidebar:
|
||||
order: 1
|
||||
---
|
||||
|
||||
fish-config - personal fish shell configuration for Fish 4.x with modern CLI tool integration
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Synopsis
|
||||
manTitle: SYNOPSIS
|
||||
man: true
|
||||
site: false
|
||||
sidebar:
|
||||
order: 2
|
||||
---
|
||||
|
||||
help config [SECTION]
|
||||
|
||||
Open this manual in the best available pager. Optionally jump to a section
|
||||
by keyword:
|
||||
|
||||
help config keybindings
|
||||
help config pkg
|
||||
help config abbreviations
|
||||
help config logs
|
||||
|
||||
The `help config` syntax integrates with fish's built-in help command.
|
||||
The underlying `config-help` function is also available directly.
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: Table Of Contents
|
||||
manTitle: TABLE OF CONTENTS
|
||||
man: true
|
||||
site: false
|
||||
sidebar:
|
||||
order: 4
|
||||
---
|
||||
|
||||
1. Configuration Variables
|
||||
2. PATH Setup
|
||||
3. Key Bindings
|
||||
4. Abbreviations
|
||||
4.1 Editors
|
||||
4.2 Navigation and Listing
|
||||
4.3 Git
|
||||
4.4 Terminal Windows, Tabs, and Panes
|
||||
4.5 Chezmoi
|
||||
4.6 Docker
|
||||
4.7 Systemctl
|
||||
4.8 AI Assistants
|
||||
4.9 History Expansion
|
||||
4.10 Miscellaneous
|
||||
4.11 Shell Aliases
|
||||
5. Functions Reference
|
||||
5.1 File and Directory
|
||||
5.2 Navigation
|
||||
5.3 Editors and Viewers
|
||||
5.4 Git and Version Control
|
||||
5.5 Package Management
|
||||
5.6 Dependency Management
|
||||
5.7 System and Monitoring
|
||||
5.8 Terminal Management
|
||||
5.9 Clipboard
|
||||
5.10 Network
|
||||
5.11 Pager and Logging
|
||||
5.12 AI and Developer Tools
|
||||
5.13 Media and Utilities
|
||||
5.14 Miscellaneous
|
||||
6. Dependency Catalog
|
||||
7. Customization
|
||||
8. Fisher Plugins
|
||||
9. Installation
|
||||
10. Personalization
|
||||
11. Troubleshooting
|
||||
11.1 Uninstalling and Reverting to Backup
|
||||
11.2 Fish Version Requirement
|
||||
11.3 Enable or Disable Session Logging
|
||||
11.4 Change or Disable the Greeting
|
||||
11.5 Secrets and Machine-Local Configuration
|
||||
11.6 Tool Init Does Nothing (Return Sentinel)
|
||||
11.7 Missing Dependencies
|
||||
11.8 Vi Mode Keybindings
|
||||
11.9 What's with the C1-C6 stuff?
|
||||
12. Viewing This Manual
|
||||
|
||||
---
|
||||
@@ -0,0 +1,155 @@
|
||||
---
|
||||
title: Configuration Variables
|
||||
manTitle: 1. CONFIGURATION VARIABLES
|
||||
sidebar:
|
||||
order: 5
|
||||
helpKeywords:
|
||||
- variables
|
||||
- config
|
||||
---
|
||||
|
||||
These variables are exported from config.fish on every interactive session.
|
||||
Override them in local.fish (see Section 10, Personalization).
|
||||
|
||||
## Environment Directories (XDG)
|
||||
|
||||
| Variable | Value |
|
||||
|---|---|
|
||||
| `XDG_CONFIG_HOME` | `~/.config` |
|
||||
| `XDG_CACHE_HOME` | `~/.cache` |
|
||||
| `XDG_DATA_HOME` | `~/.local/share` |
|
||||
| `XDG_STATE_HOME` | `~/.local/state` |
|
||||
|
||||
Tools that respect XDG are directed to these paths rather than polluting `$HOME`.
|
||||
|
||||
## Tool Homes (XDG-compliant)
|
||||
|
||||
| Variable | Value |
|
||||
|---|---|
|
||||
| `CARGO_HOME` | `$XDG_DATA_HOME/cargo` |
|
||||
| `RUSTUP_HOME` | `$XDG_DATA_HOME/rustup` |
|
||||
| `GOPATH` | `$XDG_DATA_HOME/go` |
|
||||
| `BUN_INSTALL` | `$XDG_DATA_HOME/bun` |
|
||||
| `NPM_CONFIG_PREFIX` | `$XDG_DATA_HOME/npm-global` |
|
||||
| `GNUPGHOME` | `$XDG_CONFIG_HOME/gnupg` |
|
||||
| `WAKATIME_HOME` | `$XDG_CONFIG_HOME/wakatime` |
|
||||
|
||||
## Editor and Pager
|
||||
|
||||
| Variable | Value / Notes |
|
||||
|---|---|
|
||||
| `EDITOR` | `nvim` (falls back to `vi` if `nvim` is absent) |
|
||||
| `VISUAL` | unset by default; set a GUI editor via `local.fish` (the `edit` function falls back to a GUI chain when `VISUAL` is empty) |
|
||||
| `SUDO_EDITOR` | same as `EDITOR` |
|
||||
| `PAGER` | `ov` (falls back to `less`) |
|
||||
|
||||
## Scrollback History
|
||||
|
||||
| Variable | Value / Notes |
|
||||
|---|---|
|
||||
| `__fish_scrollback_history_dir` | (unset → `~/.terminal_history`) |
|
||||
| `__fish_scrollback_history_max_files` | (unset → `100`) |
|
||||
| `SCROLLBACK_HISTORY_DIR` | `~/.terminal_history` (exported mirror) |
|
||||
| `SCROLLBACK_HISTORY_MAX_FILES` | `100` (exported mirror) |
|
||||
|
||||
The `__fish_scrollback_history_*` universal variables are the fish-style source
|
||||
of truth — set them via `config-settings` → Paths, or `set -U` directly.
|
||||
`config.fish` exports the `SCROLLBACK_HISTORY_*` mirrors from them, because the
|
||||
POSIX wrapper scripts (`paru`/`yay`/`tmux`/`zellij` logging and `_prune_terminal_logs`)
|
||||
read the exported names from the environment. When the `__fish_` vars are unset,
|
||||
the documented defaults are exported. `config.fish` deliberately does not create
|
||||
a global source var, which would shadow the universal and stop live edits from
|
||||
taking effect.
|
||||
|
||||
Scrollback logs accumulate in `SCROLLBACK_HISTORY_DIR` as timestamped files.
|
||||
When the count exceeds `SCROLLBACK_HISTORY_MAX_FILES` the oldest are pruned
|
||||
automatically on exit. Use `logs` to browse them interactively.
|
||||
|
||||
## Other
|
||||
|
||||
| Variable | Value | Notes |
|
||||
|---|---|---|
|
||||
| `GPG_TTY` | `$(tty)` | ensures GPG passphrase prompts work |
|
||||
| `CLAUDE_CODE_NO_FLICKER` | `1` | suppress terminal flicker in Claude Code |
|
||||
| `CDPATH` | `. ~/projects ~` | |
|
||||
|
||||
Opinionated defaults (`CDPATH`, `PAGER`/`MANPAGER`, Vi mode, command shadows,
|
||||
terminal integrations) can be switched off per category with universal
|
||||
variables — see Section 7, "Opinionated Components (Minimal Mode)".
|
||||
|
||||
## Pager Hierarchy
|
||||
|
||||
`$PAGER` is set to `ov` when available, falling back to `less`. The `less` wrapper
|
||||
function extends this into a full chain so anything that calls `less` directly
|
||||
also benefits:
|
||||
|
||||
`$PAGER` → `ov` → `less` → `more` → `cat`
|
||||
|
||||
When `bat` is installed, man pages are rendered with syntax highlighting:
|
||||
|
||||
| Variable | Value |
|
||||
|---|---|
|
||||
| `MANROFFOPT` | `-c` |
|
||||
| `MANPAGER` | `sh -c 'col -bx \| bat -l man -p'` |
|
||||
|
||||
## Integrations
|
||||
|
||||
### Zoxide
|
||||
|
||||
`cd`, `z`, and `cdi`/`zi` are all mapped to `zoxide`-backed navigation. Tab completions
|
||||
for `cd` and `z` blend standard directory entries (CWD and `CDPATH`) with frecency
|
||||
results so both familiar and frequently-visited paths appear in one list.
|
||||
|
||||
### DirEnv
|
||||
|
||||
Automatically loads `.envrc` files on directory change. Takes priority over
|
||||
the auto-venv logic — if a directory is managed by `direnv`, the auto-venv
|
||||
activation is skipped entirely.
|
||||
|
||||
### Auto Python Venv
|
||||
|
||||
When entering a directory that contains a `.venv/`, the virtualenv is activated
|
||||
automatically and deactivated when you leave the project tree.
|
||||
|
||||
### WakaTime
|
||||
|
||||
Every shell command is reported to WakaTime for time-tracking. Set
|
||||
`FISH_WAKATIME_DISABLED=1` to disable without removing the plugin.
|
||||
|
||||
### Tailscale
|
||||
|
||||
Full tab completion for the `tailscale` CLI is provided via `conf.d/tailscale.fish`.
|
||||
|
||||
### Done Notifications
|
||||
|
||||
Desktop notifications fire when a command takes longer than 10 seconds and
|
||||
the terminal window is not focused. Configured via fish universal variables:
|
||||
|
||||
| Variable | Value |
|
||||
|---|---|
|
||||
| `__done_min_cmd_duration` | `10000` ms |
|
||||
| `__done_notification_urgency_level` | `low` |
|
||||
|
||||
### Scrollback History
|
||||
|
||||
When running inside Kitty, closing a shell session via `exit` saves a timestamped
|
||||
scrollback snapshot to `SCROLLBACK_HISTORY_DIR`. Files are named:
|
||||
|
||||
`scrollback_YYYY-MM-DD_HH-MM-SS.log`
|
||||
|
||||
The `paru` and `yay` wrappers (auto-generated in `~/.local/bin/`) run the command
|
||||
inside a PTY via `script(1)` so download progress bars are preserved on screen,
|
||||
then render the captured terminal animation down to a clean static log via
|
||||
`scripts/clean_progress_log.py` (a small terminal-screen emulator that replays
|
||||
cursor movements, collapses repainted progress frames to their final state,
|
||||
and preserves ANSI color). If `python3` is unavailable the wrapper falls back to
|
||||
dropping only the `script(1)` header/footer. Output is saved to:
|
||||
|
||||
- `paru_YYYY-MM-DD_HH-MM-SS.log`
|
||||
- `yay_YYYY-MM-DD_HH-MM-SS.log`
|
||||
|
||||
Before pruning, `_scrollback_prune_junk` silently removes empty files, files
|
||||
with only a single meaningful line (e.g. bare `[exited]` captures), and Kitty
|
||||
tab-rename prompt captures. Use `exit --no-log` (or `exit -n`) to skip capture.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: PATH Setup
|
||||
manTitle: 2. PATH SETUP
|
||||
sidebar:
|
||||
order: 6
|
||||
helpKeywords:
|
||||
- path
|
||||
---
|
||||
|
||||
Directories prepended to PATH in this order (first wins):
|
||||
|
||||
| Directory | Purpose |
|
||||
|---|---|
|
||||
| `~/.local/bin` | Standard user-local executables |
|
||||
| `~/Applications` | User-installed standalone apps |
|
||||
| `~/scripts` | Personal shell scripts |
|
||||
| `~/bin` | Cargo binaries (appended — lowest priority) |
|
||||
| `$BUN_INSTALL/bin` | Bun runtime and global packages |
|
||||
| `$NPM_CONFIG_PREFIX/bin` | Global npm packages |
|
||||
| `~/.lmstudio/bin` | LM Studio CLI |
|
||||
| `~/.resend/bin` | Resend CLI |
|
||||
| `~/.fzf/bin` | `fzf` binary (git-installed) |
|
||||
|
||||
Cargo binaries are intentionally appended (lowest priority) to avoid
|
||||
shadowing system-installed Rust tools.
|
||||
|
||||
NOTE: While these directories are merged with your system's existing `$PATH` values, any executables in the prepended directories above will override (shadow) system binaries of the same name.
|
||||
|
||||
TIP: This standard PATH setup is gated behind the opinionated component overrides toggle. If you prefer to manage your PATH completely manually, you can disable it by setting `__fish_config_op_overrides` to `0` (or toggle it off in the `config-settings` menu).
|
||||
|
||||
---
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: Key Bindings
|
||||
manTitle: 3. KEY BINDINGS
|
||||
sidebar:
|
||||
order: 7
|
||||
helpKeywords:
|
||||
- keybindings
|
||||
- bindings
|
||||
- key-bindings
|
||||
- keys
|
||||
---
|
||||
|
||||
The shell uses Vi key bindings (fish_vi_key_bindings). All custom bindings
|
||||
are active in Insert, Normal, and Visual modes unless noted.
|
||||
|
||||
Binding Action
|
||||
─────────────────────────────────────────────────────────────────────
|
||||
Ctrl+G Insert the head of the previous command's last path
|
||||
argument. Equivalent to !$:h in Bash.
|
||||
Example: previous = "cd /usr/local/bin"
|
||||
Ctrl+G inserts "/usr/local"
|
||||
|
||||
Ctrl+F Interactive history substitution. Type old/new then
|
||||
press Ctrl+F to apply s/old/new/ to the previous
|
||||
command. Equivalent to !!:s/old/new/ in Bash.
|
||||
Example: previous = "echo this is a test"
|
||||
type "this is/that was", press Ctrl+F
|
||||
result = "echo that was a test"
|
||||
|
||||
Ctrl+Alt+U Strip the first token of the current command line,
|
||||
leaving arguments in place with the cursor at the
|
||||
start. Useful for quickly retyping the command.
|
||||
Example: "mkdir new_folder" -> " new_folder"
|
||||
|
||||
Ctrl+Alt+= Evaluate the current command line buffer with
|
||||
Qalculate! (qalc) and print the result inline.
|
||||
Requires qalc to be installed.
|
||||
Example: type "150 * 1.08", press Ctrl+Alt+=
|
||||
prints 162
|
||||
|
||||
Ctrl+Enter Smart execute: runs commands instantly without
|
||||
pressing Enter a second time for certain fast-path
|
||||
commands (speedtest-fast, etc.).
|
||||
|
||||
@@ FZF inline picker. Type @ twice anywhere on the
|
||||
command line to open an fzf picker and replace the
|
||||
@@ with the selection. The @@ must be typed as its
|
||||
own token: "cat @@" triggers it, but "cat@@" does
|
||||
not.
|
||||
|
||||
Ctrl+Right Accept autosuggestion one word/directory segment
|
||||
at a time. (Restores Fish 3.x behavior by binding
|
||||
to nextd-or-forward-word).
|
||||
|
||||
## FZF Bindings (bundled from PatrickF1/fzf.fish)
|
||||
|
||||
Ctrl+R Search command history
|
||||
Ctrl+Alt+F Search git-tracked files
|
||||
Ctrl+Alt+L Search git log
|
||||
Ctrl+Alt+S Search git status
|
||||
Ctrl+V Search shell variables
|
||||
Ctrl+Alt+P Search running processes
|
||||
|
||||
---
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Editors
|
||||
manTitle: 4.1 Editors
|
||||
---
|
||||
|
||||
<!-- GENERATED: Editors -->
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Navigation and Listing
|
||||
manTitle: 4.2 Navigation and Listing
|
||||
---
|
||||
|
||||
<!-- GENERATED: Navigation and Listing -->
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Git
|
||||
manTitle: 4.3 Git
|
||||
---
|
||||
|
||||
<!-- GENERATED: Git -->
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Terminal Windows, Tabs, and Panes
|
||||
manTitle: 4.4 Terminal Windows, Tabs, and Panes
|
||||
---
|
||||
|
||||
These abbreviations control the terminal emulator. Each has a Kitty
|
||||
variant and a WezTerm variant; the correct one is inserted based on
|
||||
`$TERM` or `$TERM_PROGRAM`.
|
||||
|
||||
<!-- GENERATED: Terminal Windows, Tabs, and Panes -->
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Chezmoi
|
||||
manTitle: 4.5 Chezmoi
|
||||
---
|
||||
|
||||
<!-- GENERATED: Chezmoi -->
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Docker
|
||||
manTitle: 4.6 Docker
|
||||
---
|
||||
|
||||
<!-- GENERATED: Docker -->
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Systemctl
|
||||
manTitle: 4.7 Systemctl
|
||||
---
|
||||
|
||||
<!-- GENERATED: Systemctl -->
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: AI Assistants
|
||||
manTitle: 4.8 AI Assistants
|
||||
---
|
||||
|
||||
<!-- GENERATED: AI Assistants -->
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: History Expansion
|
||||
manTitle: 4.9 History Expansion
|
||||
---
|
||||
|
||||
Bash-style history expansions trigger on Space or Enter. Some are implemented
|
||||
as abbreviations (e.g. `!*`), while others (`!!`, `!$`, `!.`) are implemented
|
||||
as keybindings, but they all serve the same purpose.
|
||||
|
||||
<!-- GENERATED: History Expansion -->
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Miscellaneous
|
||||
manTitle: 4.10 Miscellaneous
|
||||
---
|
||||
|
||||
<!-- GENERATED: Miscellaneous -->
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Shell Aliases
|
||||
manTitle: 4.11 Shell Aliases
|
||||
---
|
||||
|
||||
These aliases are defined in conf.d/tricks.fish via alias (which creates Fish
|
||||
functions). They are active in all interactive sessions.
|
||||
|
||||
<!-- GENERATED: Shell Aliases -->
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Abbreviations
|
||||
manTitle: 4. ABBREVIATIONS
|
||||
sidebar:
|
||||
order: 8
|
||||
helpKeywords:
|
||||
- abbreviations
|
||||
- abbr
|
||||
- abbrs
|
||||
---
|
||||
|
||||
Abbreviations expand when you press Space or Enter. They are terminal-aware:
|
||||
some expand differently in Kitty vs WezTerm vs other terminals.
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard title="Editors" href="/04-abbreviations/01-editors/" />
|
||||
<LinkCard title="Navigation and Listing" href="/04-abbreviations/02-navigation-and-listing/" />
|
||||
<LinkCard title="Git" href="/04-abbreviations/03-git/" />
|
||||
<LinkCard title="Terminal Windows, Tabs, and Panes" href="/04-abbreviations/04-terminal-windows-tabs-and-panes/" />
|
||||
<LinkCard title="Chezmoi" href="/04-abbreviations/05-chezmoi/" />
|
||||
<LinkCard title="Docker" href="/04-abbreviations/06-docker/" />
|
||||
<LinkCard title="Systemctl" href="/04-abbreviations/07-systemctl/" />
|
||||
<LinkCard title="AI Assistants" href="/04-abbreviations/08-ai-assistants/" />
|
||||
<LinkCard title="History Expansion" href="/04-abbreviations/09-history-expansion/" />
|
||||
<LinkCard title="Miscellaneous" href="/04-abbreviations/10-miscellaneous/" />
|
||||
<LinkCard title="Shell Aliases" href="/04-abbreviations/11-shell-aliases/" />
|
||||
</CardGrid>
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: File and Directory
|
||||
manTitle: 5.1 File and Directory
|
||||
sidebar:
|
||||
order: 1
|
||||
helpKeywords:
|
||||
- files
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Navigation
|
||||
manTitle: 5.2 Navigation
|
||||
sidebar:
|
||||
order: 2
|
||||
helpKeywords:
|
||||
- nav-fns
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Editors and Viewers
|
||||
manTitle: 5.3 Editors and Viewers
|
||||
sidebar:
|
||||
order: 3
|
||||
helpKeywords:
|
||||
- editors
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Git and Version Control
|
||||
manTitle: 5.4 Git and Version Control
|
||||
sidebar:
|
||||
order: 4
|
||||
helpKeywords:
|
||||
- git
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Package Management
|
||||
manTitle: 5.5 Package Management
|
||||
sidebar:
|
||||
order: 5
|
||||
helpKeywords:
|
||||
- package-manager
|
||||
- packages
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Dependency Management
|
||||
manTitle: 5.6 Dependency Management
|
||||
sidebar:
|
||||
order: 6
|
||||
helpKeywords:
|
||||
- deps
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: System and Monitoring
|
||||
manTitle: 5.7 System and Monitoring
|
||||
sidebar:
|
||||
order: 7
|
||||
helpKeywords:
|
||||
- system
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Terminal Management
|
||||
manTitle: 5.8 Terminal Management
|
||||
sidebar:
|
||||
order: 8
|
||||
helpKeywords:
|
||||
- terminal-mgmt
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Clipboard
|
||||
manTitle: 5.9 Clipboard
|
||||
sidebar:
|
||||
order: 9
|
||||
helpKeywords:
|
||||
- clipboard
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Network
|
||||
manTitle: 5.10 Network
|
||||
sidebar:
|
||||
order: 10
|
||||
helpKeywords:
|
||||
- network
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Pager and Logging
|
||||
manTitle: 5.11 Pager and Logging
|
||||
sidebar:
|
||||
order: 11
|
||||
helpKeywords:
|
||||
- logging
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: AI and Developer Tools
|
||||
manTitle: 5.12 AI and Developer Tools
|
||||
sidebar:
|
||||
order: 12
|
||||
helpKeywords:
|
||||
- ai
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Media and Utilities
|
||||
manTitle: 5.13 Media and Utilities
|
||||
sidebar:
|
||||
order: 13
|
||||
helpKeywords:
|
||||
- media
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Miscellaneous
|
||||
manTitle: 5.14 Miscellaneous
|
||||
sidebar:
|
||||
order: 14
|
||||
helpKeywords:
|
||||
- miscfns
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Functions Reference
|
||||
manTitle: 5. FUNCTIONS REFERENCE
|
||||
sidebar:
|
||||
order: 9
|
||||
helpKeywords:
|
||||
- functions
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: Dependency Catalog
|
||||
manTitle: 6. DEPENDENCY CATALOG
|
||||
sidebar:
|
||||
order: 10
|
||||
helpKeywords:
|
||||
- catalog
|
||||
- deps-catalog
|
||||
---
|
||||
|
||||
fish-deps manages these tools. Run `fish-deps` to check status,
|
||||
`fish-deps install` to install missing Required/Recommended ones, or add
|
||||
`--optional`, `--terminals`, or `--all` to also include the Optional and/or
|
||||
Terminal Emulators tiers.
|
||||
|
||||
## Required
|
||||
|
||||
| Tool | Description |
|
||||
|---|---|
|
||||
| `fish` | Fish shell >= 4.0 |
|
||||
| `fzf` | Fuzzy finder |
|
||||
|
||||
## Recommended
|
||||
|
||||
| Tool | Description |
|
||||
|---|---|
|
||||
| `cargo` | Rust toolchain (via rustup); used by `fish-deps` to install Rust-based tools and to build fish from source. All paths are gated on `type -q cargo` and degrade gracefully. |
|
||||
| `starship` | Cross-shell prompt; loaded via `type -q starship` guard. Without it the Catppuccin nim-style fallback prompt activates. |
|
||||
| `uv` | Python package and project manager (Astral); used by the fish-from-source build path in `fish-deps`. All consumers degrade gracefully without it. |
|
||||
| `direnv` | Per-directory environment loading; integration is fully guarded with `type -q direnv`. Without it the direnv hook is simply not loaded and auto-venv activates normally. |
|
||||
| `paru` | AUR helper (Arch only; preferred); guarded throughout — non-Arch systems silently skip AUR-specific paths. |
|
||||
| `yay` | AUR helper (Arch only; fallback to paru); same guards apply. |
|
||||
| `eza` | Modern `ls` replacement |
|
||||
| `zoxide` | Smart cd with frecency |
|
||||
| `lsd` | `ls` replacement (fallback to `eza`) |
|
||||
| `bat` | Syntax-highlighted `cat` |
|
||||
| `ov` | Modern pager (replaces `less`); also backs the `logs` viewer. Not a Rust crate, despite the name collision with an unrelated `ov` crate on crates.io. Prefers `go install github.com/noborus/ov@latest` when `go` is available (always gets the latest release, and covers distros like Debian/Ubuntu that don't package `ov` in their base repos); falls back to the system PM (AUR on Arch) otherwise. |
|
||||
| `ripgrep` | Fast line search |
|
||||
| `trash` | Safe delete (`trash-cli`); backs the `rm` and `scrub` wrappers. |
|
||||
| `python3` | Standalone interpreter — used by the `paru`/`yay` log cleaner. Note: `uv` does not provide `python3` on PATH, and Arch's base does not include it, so it is listed separately. All consumers degrade gracefully without it. |
|
||||
|
||||
## Optional
|
||||
|
||||
Single-purpose tools that back one wrapper function (or less) and only
|
||||
matter if you already use that specific tool. Skipped by
|
||||
`fish-deps install`/`sync` unless you pass `--optional`.
|
||||
|
||||
| Tool | Description |
|
||||
|---|---|
|
||||
| `btop` | Modern resource monitor; backs the `top` wrapper (falls back to system `top`). |
|
||||
| `dust` | Disk usage tree (Rust); one of two backends for the `du` wrapper (falls back to system `du`). |
|
||||
| `duf` | Disk usage/free overview; the other backend for the `du` wrapper (falls back to system `du`). |
|
||||
| `prettyping` | Colorized ping wrapper; backs the `ping` wrapper (falls back to system `ping`). |
|
||||
| `go` | Go toolchain; only used to install `ov` via `go install` (see below), which gets the latest release and doesn't depend on your distro packaging `ov`. Package name varies by distro (`go` on Arch/Homebrew, `golang`/`golang-go` on Debian/Fedora) — install manually if the listed package name doesn't resolve on your system. |
|
||||
| `lazygit` | Terminal git UI; only referenced by the `lg` abbreviation. |
|
||||
| `lazydocker` | Terminal docker UI; backs the `ld` wrapper. |
|
||||
| `docker` | Container runtime; gates the Docker context indicator in the right prompt and backs the `ld` wrapper. Both consumers are guarded with `type -q docker` and degrade gracefully without it. Installing the daemon package does not enable/start the service — do that yourself if you want it running. |
|
||||
| `yt-dlp` | Video/media downloader; backs the `yt-dlp` wrapper function. The wrapper falls back to the system `yt-dlp` and the rest of the config works without it. |
|
||||
| `screen` | GNU screen; fallback backend for `jobrunner` when `tmux` is unavailable. |
|
||||
|
||||
## Terminal Emulators
|
||||
|
||||
GPU-accelerated terminal emulators. Only one is ever relevant to a given
|
||||
user — the one matching `$TERM` — so neither is installed by default.
|
||||
Skipped by `fish-deps install`/`sync` unless you pass `--terminals` (or
|
||||
`--all`).
|
||||
|
||||
| Tool | Description |
|
||||
|---|---|
|
||||
| `kitty` | GPU-accelerated terminal; unlocks kitty-specific abbreviations and `--hyperlink-format=kitty` in the `rg` wrapper when `$TERM = xterm-kitty`. |
|
||||
| `wezterm` | GPU-accelerated terminal; unlocks WezTerm-specific abbreviations when it's the active terminal. |
|
||||
|
||||
## Integrations
|
||||
|
||||
Opt-in third-party services that require their own account/setup.
|
||||
|
||||
| Tool | Description |
|
||||
|---|---|
|
||||
| `wakatime` | Developer time tracking |
|
||||
| `tailscale` | Mesh VPN client |
|
||||
|
||||
## Install Methods
|
||||
|
||||
The install priority for each tool:
|
||||
|
||||
| Method | Packages |
|
||||
|---|---|
|
||||
| `cargo` | Rust tools (`eza`, `lsd`, `bat`, `dust`, `ripgrep`, `trashy`, `zoxide`, `starship`) — always gets the latest crate version |
|
||||
| `go install` | `ov` — preferred over the system PM when `go` is available; always gets the latest release |
|
||||
| system PM | `paru` / `apt` / `brew` / `dnf` / etc. — for tools without a crate or `go install` path |
|
||||
| `git clone` | `fzf` — installed from GitHub to `~/.fzf/` |
|
||||
| `curl` | `starship` installer, `fisher` bootstrap, `uv` installer |
|
||||
|
||||
---
|
||||
@@ -0,0 +1,225 @@
|
||||
---
|
||||
title: Customization
|
||||
manTitle: 7. CUSTOMIZATION
|
||||
sidebar:
|
||||
order: 11
|
||||
helpKeywords:
|
||||
- customization
|
||||
- customize
|
||||
---
|
||||
This section explains how to adapt the configuration to your specific workflow, including local machine overrides and opinionated component toggles.
|
||||
|
||||
|
||||
## Machine-local Configuration
|
||||
|
||||
Place machine-specific settings that should not be committed to git in:
|
||||
|
||||
$__fish_user_dots_path/local.fish
|
||||
|
||||
`__fish_user_dots_path` defaults to `~/.config/.user-dots/fish`. Set a
|
||||
custom location with:
|
||||
|
||||
set -U __fish_user_dots_path /path/to/your/dots/fish
|
||||
|
||||
Typical uses: additional PATH entries, local aliases, hostname-specific env
|
||||
vars, work-specific tool configs.
|
||||
|
||||
For convenience, a git-ignored `user-dots` symlink in the fish config
|
||||
directory tracks `$__fish_user_dots_path` so the overlay can be browsed from
|
||||
`~/.config/fish/`. It is created if missing and repointed if the path changes.
|
||||
Opt out by setting `__fish_user_dots_symlink` to a falsy value, or toggling
|
||||
"Dots link" off on the config-settings Paths page — this stops generation and
|
||||
removes any existing link. It only ever manages a symlink and never clobbers a
|
||||
real file or directory at that path.
|
||||
|
||||
|
||||
## Secrets and API Keys
|
||||
|
||||
$__fish_user_dots_path/secrets.fish
|
||||
|
||||
Store API tokens, GPG keys, private credentials here. This file is never
|
||||
committed. It is sourced by local.fish directly, not by config.fish.
|
||||
|
||||
`local.fish` is sourced at the end of config.fish on every interactive
|
||||
session, so it and its companion secrets.fish can override anything set
|
||||
earlier.
|
||||
|
||||
|
||||
## Overriding Configuration Variables
|
||||
|
||||
Any variable set in local.fish after the main config loads takes effect.
|
||||
Example: to increase the scrollback history limit:
|
||||
|
||||
# in local.fish
|
||||
set -gx SCROLLBACK_HISTORY_MAX_FILES 200
|
||||
|
||||
|
||||
## Fish Universal Variables
|
||||
|
||||
Some settings (fzf colors, theme) are stored in fish_variables via
|
||||
`set -U`. These are machine-local and git-ignored. Do not commit
|
||||
fish_variables.
|
||||
|
||||
|
||||
## Opinionated Components (Minimal Mode)
|
||||
|
||||
Every opinionated piece of this config is active by default but can be
|
||||
switched off through six category opt-out variables, each evaluated via
|
||||
`__fish_variable_check`. Set a variable to any falsy value (0, false, no,
|
||||
off, n) to disable its category; erase it or set a truthy value (1, true,
|
||||
yes, on, y) to re-enable. Unset means enabled — except for C5 logging, which
|
||||
is opt-in (see below).
|
||||
|
||||
An explicit per-category truthy value takes precedence over the master
|
||||
switch: setting `__fish_config_opinionated`=0 disables all unset categories,
|
||||
but a category with an explicit truthy value remains enabled regardless.
|
||||
|
||||
C5 (logging) is the one exception to "unset means enabled". Because it
|
||||
writes terminal output to disk, it is opt-in: unset means disabled, and the
|
||||
master switch cannot enable it. Only an explicit truthy value turns logging
|
||||
on.
|
||||
|
||||
Variable Disables
|
||||
────────────────────────────────────────
|
||||
__fish_config_op_aliases Command shadows and flag injection:
|
||||
ls->eza, cat->bat, cd->zoxide,
|
||||
rm->trash, less->ov, top->btop,
|
||||
ping->prettyping, ssh->kitten,
|
||||
du->duf/dust, mkdir/bash wrappers,
|
||||
history timestamps, grep/cp/mv/wget
|
||||
flag injection, help intercept, claude
|
||||
AGENTS.md auto-link
|
||||
__fish_config_op_autoexec Startup side-effects: Fisher
|
||||
bootstrap, theme apply, paru/yay
|
||||
wrapper generation, auto venv
|
||||
activation, WakaTime hook
|
||||
__fish_config_op_overrides Key and env overrides: Vi mode,
|
||||
exit->smart_exit, PAGER/MANPAGER,
|
||||
CDPATH, bang-bang system, autopair,
|
||||
puffer, starship prompt, theme
|
||||
colors, FZF_DEFAULT_OPTS, right
|
||||
prompt
|
||||
__fish_config_op_integrations Terminal/tool coupling: Kitty/
|
||||
WezTerm window abbreviations, done
|
||||
notifications, spwin/tab/split,
|
||||
hist, logs, upgrade, WakaTime
|
||||
__fish_config_op_logging Logging & capture (OPT-IN — this one
|
||||
is off unless explicitly enabled):
|
||||
scrollback capture on exit, paru/yay
|
||||
AUR log wrappers, Kitty watcher
|
||||
capture; sentinel file coordinates
|
||||
cross-process state
|
||||
__fish_config_op_greeting Greeting & first-run UI: per-session
|
||||
fish_greeting override (defines empty
|
||||
function late in config.fish to
|
||||
suppress distro greetings such as
|
||||
CachyOS fastfetch); first-run welcome
|
||||
banner in conf.d/first_run.fish
|
||||
|
||||
Examples:
|
||||
|
||||
# Disable command shadows only (rm becomes plain rm again):
|
||||
set -U __fish_config_op_aliases off
|
||||
|
||||
# Turn session logging on (opt-in; off until you do this):
|
||||
set -U __fish_config_op_logging on
|
||||
|
||||
# Full minimal mode — disable all six categories at once:
|
||||
set -U __fish_config_opinionated 0
|
||||
|
||||
# Re-enable everything (except C5 logging, which stays opt-in):
|
||||
set -Ue __fish_config_opinionated
|
||||
|
||||
# Minimal mode but keep the greeting:
|
||||
set -U __fish_config_opinionated 0
|
||||
set -U __fish_config_op_greeting 1
|
||||
# (erase both to go back to full-flavor defaults)
|
||||
|
||||
For an interactive alternative to setting these variables by hand, run
|
||||
config-settings — a full-screen TUI that flips any category (including C5
|
||||
logging) on or off, per session or universally. See its entry in Section 5.
|
||||
|
||||
NOTE:
|
||||
- Command shadows (rm, cat, ls, ...) react immediately; conf.d-level components (bindings, prompt, abbreviations, hooks) take effect in new shells.
|
||||
- With aliases disabled, rm falls back to bare `command rm` — files are deleted permanently, not trashed.
|
||||
- Disabled integration commands (spwin, tab, split, hist, logs, upgrade) print an error naming the variable that disabled them.
|
||||
- On CachyOS, the distro fish config's own aliases, history override, and bang-bang bindings are stripped per category as well.
|
||||
|
||||
### Sub-categories
|
||||
|
||||
Each of the six categories further sub-divides into two to six
|
||||
sub-categories, each with its own `__fish_config_op_<category>_<subcategory>`
|
||||
variable (e.g. `__fish_config_op_aliases_filesystem`). These follow the
|
||||
exact same truthy/falsy/unset cascade one level deeper: an explicit
|
||||
sub-category value overrides the master switch and the parent category's
|
||||
setting, and an unset sub-category inherits from its parent category (which
|
||||
in turn inherits from `__fish_config_opinionated`). Run config-settings and
|
||||
press Enter on a category row to browse and toggle its sub-categories
|
||||
interactively. See [Components Reference](/08-components-reference/) for the
|
||||
full sub-category breakdown of every category.
|
||||
|
||||
|
||||
## Prompt and Theme
|
||||
|
||||
### Starship
|
||||
|
||||
The primary prompt is Starship, initialized by conf.d/starship.fish.
|
||||
Configure it via ~/.config/starship.toml.
|
||||
|
||||
conf.d/starship.fish defines a fish_prompt wrapper that only activates when
|
||||
starship is in PATH. It emits OSC 133;A (prompt start) immediately before
|
||||
Starship renders and OSC 133;B (input start) immediately after, placing both
|
||||
markers on the prompt line itself. This allows ov to use them as sticky
|
||||
section headers when browsing scrollback logs. Without Starship, fish's
|
||||
built-in prompt handles these markers automatically.
|
||||
|
||||
### Catppuccin Fallback Prompt
|
||||
|
||||
When Starship is absent or C3 overrides are disabled, a built-in nim-style
|
||||
two-line prompt activates from functions/fish_prompt.fish. No external
|
||||
dependencies — fish builtins only.
|
||||
|
||||
Layout:
|
||||
|
||||
┬─[user@host:~/path] (main)
|
||||
╰─>$
|
||||
|
||||
Elements:
|
||||
|
||||
user Yellow (Catppuccin Yellow); red if root
|
||||
@host Blue (local) or Teal (SSH)
|
||||
~/path prompt_pwd abbreviation (Catppuccin Text)
|
||||
(main) Current git branch in Catppuccin Pink; omitted outside repos
|
||||
─[V:name] Active Python venv basename; omitted when none
|
||||
─[N/I/R/V] Vi-mode indicator when vi bindings are active
|
||||
┬─ / ╰─> Connector lines: Catppuccin Green on success, Red on failure
|
||||
|
||||
The right prompt (fish_right_prompt.fish) always renders, regardless of C3
|
||||
state. On failure it shows a red ✘ and the exit code; on success it shows
|
||||
only the dim timestamp. When starship is installed and C3 is enabled, the
|
||||
active Docker context is also shown (if non-default):
|
||||
|
||||
✘ 1 myctx Fri Jun 12 00:51:21 2026 ← failed, starship+C3 active
|
||||
✘ 1 Fri Jun 12 00:51:21 2026 ← failed, fallback prompt
|
||||
Fri Jun 12 00:51:21 2026 ← success (no ✘)
|
||||
|
||||
### FZF
|
||||
|
||||
FZF is themed to Catppuccin Mocha via FZF_DEFAULT_OPTS set in
|
||||
integrations/fzf.fish. The colors applied:
|
||||
|
||||
Background: #1E1E2E (base) #313244 (surface0)
|
||||
Foreground: #CDD6F4 (text)
|
||||
Highlights: #F38BA8 (red) #CBA6F7 (mauve) #B4BEFE (lavender)
|
||||
|
||||
To customize, override FZF_DEFAULT_OPTS in local.fish.
|
||||
|
||||
### Catppuccin Mocha Syntax Highlighting
|
||||
|
||||
The Catppuccin Mocha theme ships with this config in themes/ and is applied
|
||||
on first run via `conf.d/first_run.fish`. Colors are stored in fish_variables
|
||||
(universal). To switch variants, install a different theme from themes/:
|
||||
|
||||
fish_config theme save "Catppuccin Latte"
|
||||
|
||||
`---`
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
title: C1 — Command Shadows
|
||||
---
|
||||
|
||||
Disabling `__fish_config_op_aliases` restores standard system behavior for
|
||||
all of these commands.
|
||||
|
||||
Command / Alias Active behavior Disabled fallback
|
||||
───────────────────────────────────────────────────────────────────────────
|
||||
ls eza -l -a --icons --hyperlink system ls
|
||||
cat bat syntax-highlighted; dirs → ls /usr/bin/cat
|
||||
cd zoxide frecency-based navigation fish builtin cd
|
||||
rm moves files to trash (recoverable) command rm (permanent)
|
||||
less $PAGER → ov → less → more → cat system less
|
||||
du duf (disk overview) or dust (dir tree) system du
|
||||
top btop resource monitor system top
|
||||
ping prettyping --nolegend animation system ping
|
||||
ssh kitten ssh in Kitty terminal system ssh
|
||||
rg rg --hyperlink-format=kitty system rg
|
||||
mkdir verbose path-tree display on creation mkdir -p silently
|
||||
bash XDG bashrc + $SHELL reset on exit system bash
|
||||
history timestamps prepended to every entry fish builtin history
|
||||
cp / mv forced -i confirmation prompt cp / mv unmodified
|
||||
wget forced --continue (resume downloads) system wget
|
||||
grep/fgrep/egrep forced --color=auto system grep variants
|
||||
dir / vdir forced --color=auto system dir / vdir
|
||||
help config intercepts "help config" → config-help fish builtin help
|
||||
claude auto-links AGENTS.md as CLAUDE.md before launch command claude
|
||||
edit multi-editor launcher (GUI/term + fallbacks) $EDITOR/nvim/nano/vi
|
||||
|
||||
When C1 is disabled, `rm` uses bare `command rm` with no wrapper — files
|
||||
are permanently deleted, not trashed. There is no intermediate safety net.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_aliases` sub-divides into six sub-categories, each with
|
||||
its own `__fish_config_op_aliases_<slug>` toggle:
|
||||
|
||||
## filesystem
|
||||
|
||||
`ls`, `cat`, `cd`, `du`, `mkdir`, `rm`, `mv`, and `cd`/zoxide navigation --
|
||||
the everyday filesystem-inspection and -modification shadows.
|
||||
|
||||
## search
|
||||
|
||||
`rg`, with its Kitty hyperlink formatting.
|
||||
|
||||
## network
|
||||
|
||||
`ping`, `ssh`, and `yt-dlp` -- shadows that talk to the network.
|
||||
|
||||
## monitor
|
||||
|
||||
`top` -> `btop`.
|
||||
|
||||
## shell-tools
|
||||
|
||||
`bash` (XDG bashrc + `$SHELL` reset), `less` (`$PAGER` fallback chain),
|
||||
and the `help config` interception.
|
||||
|
||||
## dev-tools
|
||||
|
||||
`claude` (AGENTS.md/CLAUDE.md auto-linking) and `edit` (multi-editor
|
||||
launcher), plus `agy`.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
title: C2 — Startup Side-Effects
|
||||
---
|
||||
|
||||
These run automatically without any user action. Disabling
|
||||
`__fish_config_op_autoexec` prevents all of them.
|
||||
|
||||
Component Trigger What it does
|
||||
───────────────────────────────────────────────────────────────────────────
|
||||
Fisher bootstrap First shell only Downloads and installs fisher
|
||||
Fisher update After bootstrap Installs all fish_plugins entries
|
||||
Catppuccin Mocha theme First shell only Applies theme via fish_config
|
||||
paru wrapper Every startup Writes ~/.local/bin/paru wrapper
|
||||
yay wrapper Every startup Writes ~/.local/bin/yay wrapper
|
||||
Python venv activation On every cd Sources .venv/bin/activate.fish
|
||||
WakaTime command hook On every command Reports to WakaTime API
|
||||
Auto-pull fast-forward On entering a repo Background ff-only git pull
|
||||
user-dots symlink Every startup Links $__fish_config_dir/user-dots
|
||||
to $__fish_user_dots_path
|
||||
|
||||
When C2 is disabled: no Fisher install, no theme application, no paru/yay
|
||||
wrapper generation, no automatic venv activation, no WakaTime reporting,
|
||||
no auto-pull (the PWD handler is never registered), and the user-dots
|
||||
convenience symlink is not created. The symlink is git-ignored and only ever
|
||||
managed as a symlink — a real file or directory at that path is left untouched.
|
||||
The symlink has its own opt-out independent of C2: set `__fish_user_dots_symlink`
|
||||
to a falsy value (or toggle "Dots link" off on the config-settings Paths page)
|
||||
to stop generating it and remove any existing link — honoured even when C2 is
|
||||
enabled. Managed by the `__fish_user_dots_link` helper.
|
||||
The first-run completion marker (`__fish_config_first_run_complete`) is still
|
||||
set so the init does not re-run on subsequent shells.
|
||||
|
||||
Python venv activation fires on every directory change. If a directory uses
|
||||
direnv (`.envrc` present), direnv takes priority and auto-venv is skipped for
|
||||
that directory.
|
||||
|
||||
Auto-pull fast-forwards opted-in repositories in the background when you cd
|
||||
into them. The fish-config repo is always covered; other repos are added with
|
||||
the `auto-pull` command (see its entry in the functions reference). It only
|
||||
ever fast-forwards a clean repo whose branch has an upstream — never rebases,
|
||||
merges, or overwrites work — so it is a no-op on dirty trees, divergent
|
||||
branches, or repos without a remote. The handler fires once per repo entry
|
||||
(not on every sub-directory `cd`). The registry is machine-local at
|
||||
`$__fish_user_dots_path/auto-pull.list` (defaults to `~/.config/.user-dots/fish/auto-pull.list`) and is never committed.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_autoexec` sub-divides into five sub-categories, each
|
||||
with its own `__fish_config_op_autoexec_<slug>` toggle:
|
||||
|
||||
## plugin-management
|
||||
|
||||
Fisher bootstrap on first run.
|
||||
|
||||
## pkg-wrappers
|
||||
|
||||
`paru`/`yay` wrapper generation.
|
||||
|
||||
## venv
|
||||
|
||||
Automatic Python virtualenv activation.
|
||||
|
||||
## telemetry
|
||||
|
||||
The WakaTime hook's startup bootstrap.
|
||||
|
||||
## sync
|
||||
|
||||
Auto-pull background fast-forward, and the user-dots convenience symlink.
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: C3 — Key and Environment Overrides
|
||||
---
|
||||
|
||||
These change fundamental shell behavior: how keys work, which pager opens,
|
||||
and what the prompt looks like. Disabling `__fish_config_op_overrides` removes
|
||||
all of them.
|
||||
|
||||
Override What it replaces or sets
|
||||
───────────────────────────────────────────────────────────────────────────
|
||||
Vi mode fish_vi_key_bindings replaces default Emacs mode
|
||||
PATH setup Prepends custom bin directories to the PATH
|
||||
exit → smart_exit exit wrapper that captures scrollback before closing
|
||||
PAGER=ov ov used by git, man, and all $PAGER-aware tools
|
||||
EDITOR=nvim nvim fallback to vi for git commit, etc.
|
||||
GPG_TTY Sets GPG_TTY to current terminal tty
|
||||
MANPAGER=bat pipeline man pages rendered with syntax highlighting
|
||||
CDPATH=. ~/projects ~ bare dir names resolve against ~/projects and ~
|
||||
Bang-bang system ! and $ keys expand history; !^, !*, !-N, !?str?,
|
||||
^old^new abbreviations; six expand_bang_* helpers
|
||||
Autopair ( [ { " ' auto-close to (), [], {}, "", ''
|
||||
Puffer key intercepts . ! $ * keys intercepted for smart expansion
|
||||
Starship prompt fish_prompt replaced by Starship + OSC 133 markers
|
||||
Catppuccin colors 30+ fish_color_* variables set to Mocha palette
|
||||
FZF_DEFAULT_OPTS FZF themed to Catppuccin Mocha colors
|
||||
Right prompt fish_right_prompt: exit code (on failure) + dim timestamp; always rendered; Docker context added when starship+C3 active
|
||||
|
||||
The bang-bang system spans `key_bindings.fish`, `abbr.fish`, `puffer.fish`, and
|
||||
six `expand_bang_*.fish` functions. All are gated together — disabling C3
|
||||
removes the entire bang-expansion system at once.
|
||||
|
||||
When C3 is disabled, `exit` falls back to `builtin exit` with no scrollback
|
||||
capture, no Kitty IPC, and no file I/O on exit. The scrollback capture block
|
||||
is independently controlled by C5 (see below).
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_overrides` sub-divides into three sub-categories, each
|
||||
with its own `__fish_config_op_overrides_<slug>` toggle:
|
||||
|
||||
## key-bindings
|
||||
|
||||
Vi mode, autopair, puffer key intercepts, bang-bang history expansion,
|
||||
and `smart_exit`'s plain-exit path.
|
||||
|
||||
## environment
|
||||
|
||||
`$PATH`, `$PAGER`/`$EDITOR`/`$GPG_TTY`, and `$CDPATH`.
|
||||
|
||||
## prompt
|
||||
|
||||
Starship, the right prompt, Catppuccin syntax/prompt colors, and FZF
|
||||
theming (`$FZF_DEFAULT_OPTS`) -- all driven by the same guard as a single
|
||||
unit, not independently toggleable from each other.
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: C4 — Terminal and Tool Integration
|
||||
---
|
||||
|
||||
These features couple the shell to specific external tools. Disabling
|
||||
`__fish_config_op_integrations` disables all of them.
|
||||
|
||||
Component Requires
|
||||
───────────────────────────────────────────────────────────────────────────
|
||||
≈ 60 Kitty/WezTerm abbrs Active Kitty or WezTerm session
|
||||
(:w, :wv, :wh, :t, etc.)
|
||||
Done desktop notifications Graphical desktop with a notification daemon
|
||||
spwin Kitty or WezTerm
|
||||
tab Kitty, WezTerm, or Konsole
|
||||
split Kitty or WezTerm
|
||||
hist fzf + wl-copy (Wayland clipboard)
|
||||
logs fzf + ov; reads from ~/.terminal_history/
|
||||
upgrade paru or yay (Arch Linux only)
|
||||
WakaTime hook wakatime CLI and a configured API key
|
||||
|
||||
Disabled integration commands (`spwin`, `tab`, `split`, `hist`, `logs`, `upgrade`) print
|
||||
a colored error to stderr naming the variable that disabled them rather than
|
||||
silently failing.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_integrations` sub-divides into five sub-categories,
|
||||
each with its own `__fish_config_op_integrations_<slug>` toggle:
|
||||
|
||||
## terminal-abbrs
|
||||
|
||||
The Kitty/WezTerm abbreviation set.
|
||||
|
||||
## window-mgmt
|
||||
|
||||
`spwin`, `tab`, `split`.
|
||||
|
||||
## notifications
|
||||
|
||||
`done`'s completion notifications, and the WakaTime activity hook.
|
||||
|
||||
## history-logs
|
||||
|
||||
`hist`, `logs`.
|
||||
|
||||
## pkg-upgrade
|
||||
|
||||
`upgrade`.
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
title: C5 — Logging and Capture
|
||||
---
|
||||
|
||||
Five components capture shell output to disk. Unlike every other category,
|
||||
C5 is opt-in: it stays off until `__fish_config_op_logging` is set to an
|
||||
explicit truthy value, and a truthy master switch does not enable it. While
|
||||
it is off, all capture is skipped and the logging wrappers are removed.
|
||||
|
||||
CAUTION: This configuration is capable of silently recording terminal output and secrets directly to disk. See below for details on how this capture mechanism works, where files are stored, and how to manage its state.
|
||||
|
||||
# Turn it on (persistently, in every shell):
|
||||
set -U __fish_config_op_logging on
|
||||
|
||||
# Turn it back off:
|
||||
set -U __fish_config_op_logging off # or: set -Ue __fish_config_op_logging
|
||||
|
||||
Component What it captures
|
||||
───────────────────────────────────────────────────────────────────────────
|
||||
Scrollback capture Terminal session output saved to:
|
||||
`~/.terminal_history/scrollback_YYYY-MM-DD_HH-MM-SS.log`
|
||||
tmux pane capture Continuous pane stream via pipe-pane, saved to:
|
||||
`~/.terminal_history/tmux_<session>-w<win>-p<pane>_YYYY-MM-DD_HH-MM-SS.log`
|
||||
zellij pane capture Pane scrollback snapshot on shell exit, saved to:
|
||||
`~/.terminal_history/zellij_<session>-p<pane>_YYYY-MM-DD_HH-MM-SS.log`
|
||||
paru wrapper All paru/AUR output captured to:
|
||||
`~/.terminal_history/paru_YYYY-MM-DD_HH-MM-SS.log`
|
||||
yay wrapper All yay/AUR output captured to:
|
||||
`~/.terminal_history/yay_YYYY-MM-DD_HH-MM-SS.log`
|
||||
Kitty watcher `watcher.py` captures scrollback when Kitty closes
|
||||
|
||||
NOTE: **Turning off logging does not delete any existing logs.**
|
||||
They remain in `$SCROLLBACK_HISTORY_DIR` (defaults to: `~/.terminal_history/`)
|
||||
until you remove them manually.
|
||||
|
||||
The tmux capture starts automatically when fish launches inside any tmux
|
||||
pane (`$TMUX` is set). It uses tmux's native pipe-pane to stream all pane
|
||||
output directly to disk without an intermediate process. Each fish shell
|
||||
session gets its own log file; a new log is created on each shell start
|
||||
(including exec fish and new splits). Before each new log, the oldest
|
||||
`tmux_*.log` files are pruned (by modification time) to keep the total within
|
||||
`SCROLLBACK_HISTORY_MAX_FILES`, matching the paru/yay wrapper behaviour.
|
||||
|
||||
The zellij capture works differently: Zellij has no live output-streaming
|
||||
facility like pipe-pane, so the log is taken as a one-shot snapshot when the
|
||||
shell exits, via `zellij action dump-screen --full --ansi` (the `--ansi` flag
|
||||
preserves color). The dump is captured on the fish process's stdout and
|
||||
written to the log file by fish itself (not via `--path`, which would make the
|
||||
zellij server write the file). A fish_exit handler (registered whenever
|
||||
`$ZELLIJ` is set) writes the pane's full scrollback and then prunes old
|
||||
`zellij_*.log` files the same way. Because the capture happens at exit, toggling
|
||||
`__fish_config_op_logging` takes effect on the next exit with no restart or
|
||||
sentinel coordination needed — the C5 guard is re-checked when the handler
|
||||
fires.
|
||||
|
||||
LIMITATION — zellij capture only fires on a clean shell exit (typing `exit`,
|
||||
Ctrl-D, or a logout), because that is when the fish_exit handler runs. It does
|
||||
NOT capture when you close a pane or quit zellij through zellij itself:
|
||||
|
||||
- Closing a pane signals the shell and tears the pane down concurrently, so
|
||||
even if the handler runs, `dump-screen` may find the pane buffer already
|
||||
gone.
|
||||
- Quitting zellij kills the zellij server, and `dump-screen` needs a live
|
||||
server to read from — there is nothing left to snapshot.
|
||||
|
||||
This is a structural difference from tmux, NOT a bug. tmux streams pane output
|
||||
to disk continuously via pipe-pane, so whatever was printed is already saved
|
||||
no matter how the pane dies. Zellij can only snapshot, and the only reliable
|
||||
snapshot point from the shell is a clean exit. To guarantee a zellij pane is
|
||||
logged, end the session with `exit` or Ctrl-D rather than zellij's close-pane
|
||||
or quit actions.
|
||||
|
||||
The Kitty watcher is managed by the kitty-logging command: it symlinks the
|
||||
watcher (`fish-config-watcher.py`) into the Kitty config directory and wires it
|
||||
into `kitty.conf` via a managed block. Inside Kitty, a non-blocking
|
||||
per-session reminder points first-time users at `kitty-logging install` until
|
||||
they install or run `kitty-logging dismiss`; the reminder is itself gated on
|
||||
C5, so it stays silent until you enable logging. Install affects new Kitty
|
||||
windows only; runtime disable is still handled by the `.logging_disabled`
|
||||
sentinel.
|
||||
|
||||
Logging coordination via sentinel file
|
||||
|
||||
C5 uses a sentinel file to synchronize state between the shell and
|
||||
out-of-process components (the Kitty watcher and all running shells):
|
||||
|
||||
~/.config/fish/.logging_disabled
|
||||
|
||||
Because C5 is off by default, the sentinel is present on a fresh install —
|
||||
the startup sync in `conf.d/logging-events.fish` reconciles it on every shell
|
||||
start, so it appears without any action on your part.
|
||||
|
||||
Disabling `__fish_config_op_logging` (or leaving it unset):
|
||||
1. Creates the sentinel immediately in every open shell.
|
||||
2. Removes `~/.local/bin/paru` and `~/.local/bin/yay` logging wrappers;
|
||||
bare `/usr/bin/paru` and `/usr/bin/yay` are used instead.
|
||||
3. Kitty's `watcher.py` reads the sentinel on each save attempt and
|
||||
skips capture — no Kitty restart required.
|
||||
4. smart_exit stops saving scrollback logs.
|
||||
5. Stops `tmux pipe-pane` capture in every open fish shell inside tmux.
|
||||
|
||||
Enabling `__fish_config_op_logging`:
|
||||
1. Removes the sentinel in every open shell.
|
||||
2. Regenerates paru/yay logging wrappers in `~/.local/bin/`.
|
||||
3. Kitty watcher resumes capture on the next session exit.
|
||||
4. Restarts tmux pipe-pane capture in every open fish shell inside tmux.
|
||||
|
||||
Changes propagate to all running shells through an event handler that fires
|
||||
whenever `__fish_config_op_logging` changes — no shell restart needed.
|
||||
|
||||
Note: C3 and C5 compose independently. C3 controls whether the smart_exit
|
||||
wrapper is active at all; C5 controls only the scrollback-capture block
|
||||
inside it. With C3 disabled, exit is plain builtin exit regardless of C5.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_logging` sub-divides into three sub-categories, each
|
||||
with its own `__fish_config_op_logging_<slug>` toggle (all still opt-in
|
||||
by default, inherited from C5's own opt-in behavior -- see §3 of the
|
||||
design spec):
|
||||
|
||||
## terminal-capture
|
||||
|
||||
Kitty watcher scrollback capture, and `smart_exit`'s logging-guard path.
|
||||
|
||||
## multiplexer-capture
|
||||
|
||||
tmux `pipe-pane` and zellij `dump-screen` capture.
|
||||
|
||||
## pkg-logs
|
||||
|
||||
`paru`/`yay` AUR log wrappers.
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: C6 — Greeting and First-Run UI
|
||||
---
|
||||
|
||||
Component What it shows
|
||||
───────────────────────────────────────────────────────────────────────────
|
||||
First-run welcome banner One-time message on first interactive session
|
||||
fish_greeting override Empty function defined late in config.fish to
|
||||
suppress distro greetings (e.g. CachyOS sets
|
||||
fish_greeting to fastfetch by default)
|
||||
|
||||
When C6 is disabled, no greeting is printed by this config. Any greeting
|
||||
set by the distro or other configs runs normally — this config simply does
|
||||
not override it.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_greeting` sub-divides into two sub-categories, each
|
||||
with its own `__fish_config_op_greeting_<slug>` toggle:
|
||||
|
||||
## first-run
|
||||
|
||||
The first-run welcome banner.
|
||||
|
||||
## greeting-message
|
||||
|
||||
The per-session `fish_greeting` override.
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Components Reference
|
||||
manTitle: 8. COMPONENTS REFERENCE
|
||||
sidebar:
|
||||
order: 12
|
||||
helpKeywords:
|
||||
- componentsreference
|
||||
---
|
||||
The following tables detail every component in each category. Use this
|
||||
reference to understand exactly which behaviors change when you toggle a
|
||||
category variable.
|
||||
|
||||
Category Description
|
||||
──────────────────────────────────────────────────────────────────────────
|
||||
C1 [Command Shadows](/08-components-reference/01-c1-command-shadows/) — Wraps destructive commands (`rm`, `cp`) to be safe by default
|
||||
C2 [Startup Side-Effects](/08-components-reference/02-c2-startup-side-effects/) — Bootstraps Fisher, generates wrappers, auto-activates venvs
|
||||
C3 [Overrides](/08-components-reference/03-c3-key-and-environment-overrides/) — Overrides `cd`, sets Vi mode, binds `<CR>` to `smart_enter`
|
||||
C4 [Integrations](/08-components-reference/04-c4-terminal-and-tool-integration/) — Kitty/Wezterm integrations, starship hooks, fzf theme
|
||||
C5 [Logging and Capture](/08-components-reference/05-c5-logging-and-capture/) — Session logs, command duration
|
||||
C6 [Greeting & First-Run UI](/08-components-reference/06-c6-greeting-and-first-run-ui/) — Custom startup banner
|
||||
|
||||
Each category further sub-divides into two to six sub-categories (24 in
|
||||
total) with their own `__fish_config_op_<category>_<subcategory>` toggles
|
||||
-- see that category's page for its sub-category list.
|
||||
|
||||
## Per-function overrides: `C0`/`always`
|
||||
|
||||
Every guarded function or file can also carry a reserved `always/on` or
|
||||
`always/off` tag in its `# COMPONENT` header, independent of every C1-C6
|
||||
category and sub-category toggle and invisible to `config-settings`. An
|
||||
`always/off` tag disables that function unconditionally; an `always/on`
|
||||
tag enables it unconditionally, ignoring the state of every other tagged
|
||||
sub-category. This is a per-function escape hatch for cases too granular
|
||||
or too idiosyncratic to justify a taxonomy entry -- edit the header
|
||||
directly and run `__fish_config_op_registry_rebuild` to apply the change.
|
||||
@@ -0,0 +1,126 @@
|
||||
---
|
||||
title: Fisher Plugins
|
||||
manTitle: 9. FISHER PLUGINS
|
||||
sidebar:
|
||||
order: 13
|
||||
helpKeywords:
|
||||
- plugins
|
||||
- fisher
|
||||
---
|
||||
|
||||
Fisher is bootstrapped automatically on the **first interactive session** via
|
||||
`conf.d/first_run.fish`. This also applies the Catppuccin Mocha theme and
|
||||
prints a one-time welcome message (gated by `__fish_config_op_greeting`; set
|
||||
it to 0 to suppress). Subsequent sessions skip all first-run logic with zero
|
||||
overhead.
|
||||
|
||||
To re-trigger first-run initialization (e.g., after a fresh install or for
|
||||
testing), run:
|
||||
|
||||
set -Ue __fish_config_first_run_complete
|
||||
|
||||
Then open a new shell.
|
||||
|
||||
## Fisher-Managed Plugins
|
||||
|
||||
The following plugins are fully managed by Fisher. Their files are installed
|
||||
into the repo directory by Fisher and are listed in `.gitignore` — do not
|
||||
commit them. Fisher installs and updates them automatically.
|
||||
|
||||
- [`jorgebucaran/fisher`](https://github.com/jorgebucaran/fisher) — Plugin manager itself
|
||||
- [`meaningful-ooo/sponge`](https://github.com/meaningful-ooo/sponge) — Remove failed commands from history
|
||||
|
||||
## Sponge History Filtering
|
||||
|
||||
Sponge removes failed commands from history and, via conf.d/sponge_privacy.fish,
|
||||
also filters privacy-sensitive commands through three layers. Detection is
|
||||
heuristic — pattern- and variable-name-based — so this reduces the risk of a
|
||||
credential landing in persistent history; it is not a guarantee that no
|
||||
secret can ever reach it, and it is not a substitute for rotating a
|
||||
credential that gets typed in plaintext. Treat it as a safety net, not a
|
||||
vault.
|
||||
|
||||
Layer 1 — Static patterns (universal, persistent across sessions):
|
||||
Commands matching any of these structural signatures are never recorded:
|
||||
|
||||
- `--password` / `--token` / `--passphrase` / `--api-key` flags with values
|
||||
- Inline env assignments: `GITHUB_TOKEN=xxx`, `MY_API_KEY=abc`
|
||||
- Fish set with sensitive names: `set -gx GITHUB_TOKEN xxx`
|
||||
- URLs with embedded credentials: `https://user:pass@host`
|
||||
- HTTP Authorization headers: `curl -H "Authorization: ..."`
|
||||
- Basic auth flags: `curl -u user:pass`
|
||||
- `sshpass`, `docker login -p`, `openssl -passin/-passout`
|
||||
|
||||
Layer 2 — Dynamic secret values (session globals, refreshed each login):
|
||||
On the first prompt, after secrets.fish has loaded, the literal values of
|
||||
all exported variables whose names suggest credentials (TOKEN, PASSWORD,
|
||||
SECRET, API_KEY, etc.) are collected, regex-escaped, and added as a
|
||||
session-scoped overlay. Because globals shadow universals in Fish, the
|
||||
combined list is what sponge sees. Rotating a token takes effect on the
|
||||
next login automatically.
|
||||
|
||||
Layer 3 — Per-command filter (sponge_filter_secrets):
|
||||
Catches credentials in variables exported after login, such as tokens
|
||||
sourced from a project .env file mid-session.
|
||||
|
||||
A match is actively deleted from history, not stored and redacted. Sponge
|
||||
queues a matched command on `fish_postexec` and purges anything past
|
||||
`sponge_delay` entries on the very next `fish_prompt`, immediately forcing
|
||||
a `history save`. With this config's (upstream) defaults, that means a
|
||||
matched command is gone from disk within about one prompt cycle — it is
|
||||
not left sitting in persistent history for the rest of the session.
|
||||
|
||||
This timing depends on `sponge_purge_only_on_exit` staying `false`, which
|
||||
is sponge's own default and is not overridden here. Turning it on defers
|
||||
all purging to the `fish_exit` event instead of the next prompt — and
|
||||
because `fish_exit` does not fire on a killed or crashed session, a
|
||||
matched command purged only on exit can survive indefinitely if the shell
|
||||
never exits cleanly. Leave this setting off.
|
||||
|
||||
To add your own persistent patterns:
|
||||
|
||||
set -U -a sponge_regex_patterns 'your-regex-here'
|
||||
|
||||
To mark additional variable NAMES as credential-bearing (so Layer 2 scrubs
|
||||
their values), add name tokens — via `config-settings` → Sponge, or directly:
|
||||
|
||||
set -U -a __fish_sponge_extra_sensitive ACME_API VAULT_PW
|
||||
|
||||
Tokens are folded into the Layer 2 name match case-insensitively as substrings,
|
||||
so ACME_API also covers ACME_API_KEY. (The match uses `--entire` to return the
|
||||
full variable name, so partial-name tokens dereference the right value.)
|
||||
|
||||
The `config-settings` Sponge page also surfaces sponge's own tuning variables —
|
||||
sponge_delay, sponge_successful_exit_codes, sponge_purge_only_on_exit, and
|
||||
sponge_allow_previously_successful — so they can be changed without typing
|
||||
variable names.
|
||||
|
||||
## Bundled Plugin Functionality
|
||||
|
||||
The remaining plugin functionality is bundled directly with this config rather
|
||||
than managed through Fisher. The bundled versions include customizations for
|
||||
Fish 4.x compatibility and improved behavior that differ from their upstream
|
||||
releases. Installing them through Fisher would overwrite these customizations.
|
||||
|
||||
Bundled components and their upstream origins:
|
||||
|
||||
- [`catppuccin/fish`](https://github.com/catppuccin/fish) → `themes/` + `conf.d/theme.fish`
|
||||
- [`PatrickF1/fzf.fish`](https://github.com/PatrickF1/fzf.fish) → `functions/_fzf_*.fish` + `conf.d/fzf.fish`
|
||||
- [`franciscolourenco/done`](https://github.com/franciscolourenco/done) → `conf.d/done.fish`
|
||||
- [`jorgebucaran/autopair.fish`](https://github.com/jorgebucaran/autopair.fish) → `functions/_autopair_*.fish` + `conf.d/autopair.fish`
|
||||
- [`nickeb96/puffer-fish`](https://github.com/nickeb96/puffer-fish) → `functions/_puffer_fish_*.fish` + `conf.d/puffer.fish`
|
||||
|
||||
Do not run `fisher install` for these — it will overwrite the customized
|
||||
versions. To update their behavior, edit the relevant bundled files directly.
|
||||
|
||||
## fish_plugins Manifest
|
||||
|
||||
The `fish_plugins` file at the config root:
|
||||
|
||||
- [`jorgebucaran/fisher`](https://github.com/jorgebucaran/fisher) — Plugin manager itself
|
||||
- [`meaningful-ooo/sponge`](https://github.com/meaningful-ooo/sponge) — Remove failed commands from history
|
||||
|
||||
To update all Fisher-managed plugins, run `fisher update` or `fish-deps
|
||||
update` which calls it as its first step.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: Installation
|
||||
manTitle: 10. INSTALLATION
|
||||
sidebar:
|
||||
order: 14
|
||||
helpKeywords:
|
||||
- installation
|
||||
- install
|
||||
---
|
||||
|
||||
This configuration is managed as a git repository. To deploy on a new machine:
|
||||
|
||||
mv ~/.config/fish ~/.config/fish.bak # back up any existing config
|
||||
git clone https://git.rootiest.dev/rootiest/fish-config.git ~/.config/fish
|
||||
|
||||
Then open a new Fish shell. Fisher installs automatically on first launch
|
||||
and the Catppuccin Mocha theme is applied. All other plugin functionality is
|
||||
bundled directly with this config and requires no additional installation.
|
||||
|
||||
## Return Sentinel
|
||||
|
||||
`config.fish` ends with a return sentinel guard. Any lines appended after it by
|
||||
a tool's setup command (`starship init fish | source`, `zoxide init fish | source`,
|
||||
etc.) will have no effect. All integrations are managed via `conf.d/` files.
|
||||
|
||||
If a new tool's shell integration appears to do nothing, check whether its
|
||||
setup command appended an init line below the sentinel and create a dedicated
|
||||
`conf.d/<tool>.fish` instead.
|
||||
|
||||
## Updating
|
||||
|
||||
Pull the latest changes from the upstream repository without needing a
|
||||
configured git remote:
|
||||
|
||||
- `config-update` — Fetch and apply the latest commits from upstream
|
||||
- `config-update --dry-run` — Preview available changes without applying them
|
||||
- `config-update --force` — Stash local changes, pull, then restore the stash
|
||||
|
||||
All git output is suppressed. Run `exec fish` after a successful update to reload.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: Personalization
|
||||
manTitle: 11. PERSONALIZATION
|
||||
sidebar:
|
||||
order: 15
|
||||
helpKeywords:
|
||||
- personalization
|
||||
- personalize
|
||||
---
|
||||
|
||||
Sensitive credentials and machine-specific settings are kept out of version
|
||||
control in a private directory. The path defaults to
|
||||
`~/.config/.user-dots/fish/` but can be overridden:
|
||||
|
||||
set -U __fish_user_dots_path /path/to/your/dots/fish
|
||||
|
||||
Or use the interactive TUI — run `config-settings` and navigate to the
|
||||
"Dots Path" row (last row). Press Enter to type a new path, or ← / h to
|
||||
reset to the default.
|
||||
|
||||
config.fish sources local.fish from that directory on every interactive
|
||||
session. local.fish is responsible for sourcing its own secrets.fish:
|
||||
|
||||
$__fish_user_dots_path/
|
||||
├── secrets.fish API keys, tokens, passwords, personal identifiers
|
||||
└── local.fish Machine-specific paths, env vars, and sourcing secrets
|
||||
|
||||
fish_variables (auto-managed by fish) is excluded from this repo via
|
||||
.gitignore. Do not commit it.
|
||||
|
||||
## secrets.fish
|
||||
|
||||
Store anything you would not commit to a public repo: API keys, auth tokens,
|
||||
passwords, and personal identifiers.
|
||||
|
||||
# secrets.fish
|
||||
set -gx MY_NAME "Your Name"
|
||||
set -gx MY_EMAIL "you@example.com"
|
||||
set -gx GPG_RECIPIENT "you@example.com"
|
||||
set -gx GITHUB_TOKEN ghp_yourTokenHere
|
||||
set -gx OPENAI_API_KEY sk-proj-yourKeyHere
|
||||
set -gx GITEA_TOKEN yourGiteaTokenHere
|
||||
set -gx GITEA_CHOSEN_LOGIN your.gitea.instance
|
||||
set -gx KOPIA_PASSWORD yourKopiaPassword
|
||||
|
||||
## local.fish
|
||||
|
||||
Store paths and variables specific to one machine — things that would be
|
||||
wrong on any other system.
|
||||
|
||||
# CDPATH — directories searched by cd
|
||||
set -gx CDPATH . /home/youruser/projects /home/youruser
|
||||
|
||||
# Path to your shared .gitignore boilerplate
|
||||
set -gx GITIGNORE_BOILERPLATE ~/.config/git/gitignore_boilerplate
|
||||
|
||||
# SSH shortcuts
|
||||
abbr -a sshr 'ssh you@your-server.local'
|
||||
abbr -a sshw 'ssh you@work-server.example.com'
|
||||
|
||||
# Docker context shortcuts
|
||||
abbr -a dcr 'docker context use my-remote-server'
|
||||
abbr -a dcw 'docker context use work-server'
|
||||
|
||||
local.fish is sourced at the end of config.fish with an existence check so
|
||||
the public config works cleanly on any machine without the private repo.
|
||||
local.fish in turn sources secrets.fish when it exists.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,249 @@
|
||||
---
|
||||
title: Troubleshooting
|
||||
manTitle: 12. TROUBLESHOOTING
|
||||
sidebar:
|
||||
order: 16
|
||||
helpKeywords:
|
||||
- troubleshooting
|
||||
- troubleshoot
|
||||
- faq
|
||||
- help
|
||||
- uninstall
|
||||
- revert
|
||||
---
|
||||
|
||||
This section covers common issues, their solutions, and how to safely revert changes or uninstall the configuration entirely.
|
||||
|
||||
## Uninstalling and Reverting to Backup
|
||||
|
||||
The installation step backs up any existing config to `~/.config/fish.bak`.
|
||||
To revert:
|
||||
|
||||
rm -rf ~/.config/fish
|
||||
mv ~/.config/fish.bak ~/.config/fish
|
||||
|
||||
If no backup exists, remove the directory and let Fish regenerate a default
|
||||
config on next launch:
|
||||
|
||||
rm -rf ~/.config/fish
|
||||
fish -c 'fish_config theme choose "Fish default"'
|
||||
|
||||
Clean up files generated outside the config directory:
|
||||
|
||||
rm -f ~/.local/bin/paru ~/.local/bin/yay # AUR log wrappers
|
||||
rm -f ~/.local/share/man/man1/fish-config.1 # man page symlink
|
||||
rm -f ~/.config/fish/.logging_disabled # C5 sentinel
|
||||
|
||||
Erase universal variables set by this config:
|
||||
|
||||
for v in (set -Un | string match '__fish_config*')
|
||||
set -Ue $v
|
||||
end
|
||||
for v in __done_min_cmd_duration __done_notification_urgency_level
|
||||
set -Ue $v
|
||||
end
|
||||
for v in (set -Un | string match 'sponge_*')
|
||||
set -Ue $v
|
||||
end
|
||||
|
||||
The `~/.terminal_history/` log directory contains your session logs. Remove
|
||||
it only if you do not want to keep them.
|
||||
|
||||
## Fish Version Requirement
|
||||
|
||||
This config requires Fish 4.x or newer. Check your version:
|
||||
|
||||
fish --version
|
||||
|
||||
Run `fish-deps` to see a status report — an outdated Fish shows ⚠ with an
|
||||
upgrade message.
|
||||
|
||||
Upgrading Fish by distribution:
|
||||
|
||||
# Arch / AUR
|
||||
pacman -S fish # or paru -S fish
|
||||
|
||||
# Ubuntu / Debian (PPA)
|
||||
sudo apt-add-repository ppa:fish-shell/release-4
|
||||
sudo apt update && sudo apt install fish
|
||||
|
||||
# Fedora
|
||||
sudo dnf install fish
|
||||
|
||||
# macOS
|
||||
brew install fish
|
||||
|
||||
For other systems or building from source, see https://fishshell.com.
|
||||
|
||||
## Enable or Disable Session Logging
|
||||
|
||||
Session logging is opt-in: it is off until you turn it on. To enable all
|
||||
logging and capture (scrollback, tmux/zellij pane logs, AUR helper wrappers,
|
||||
Kitty watcher):
|
||||
|
||||
set -U __fish_config_op_logging on
|
||||
|
||||
Or toggle it interactively: run `config-settings` and flip the Logging row.
|
||||
|
||||
Disable it again — either an explicit falsy value or erasing the variable
|
||||
returns you to the default off state:
|
||||
|
||||
set -U __fish_config_op_logging off
|
||||
set -Ue __fish_config_op_logging
|
||||
|
||||
This takes effect immediately in all running shells — no restart needed. The
|
||||
sentinel file, wrapper removal, and pipe-pane teardown happen automatically.
|
||||
|
||||
See [C5 — Logging and Capture](/08-components-reference/05-c5-logging-and-capture/) for the full component breakdown.
|
||||
|
||||
## Change or Disable the Greeting
|
||||
|
||||
This config suppresses the distro greeting (e.g. CachyOS fastfetch) by
|
||||
default. To let the distro greeting through:
|
||||
|
||||
set -U __fish_config_op_greeting off
|
||||
|
||||
To set a custom greeting, define fish_greeting in your local.fish:
|
||||
|
||||
# in $__fish_user_dots_path/local.fish
|
||||
function fish_greeting
|
||||
echo "Hello, world!"
|
||||
end
|
||||
|
||||
The first-run welcome banner runs exactly once. To re-trigger it (e.g. for
|
||||
testing):
|
||||
|
||||
set -Ue __fish_config_first_run_complete
|
||||
|
||||
See [C6 — Greeting and First-Run UI](/08-components-reference/06-c6-greeting-and-first-run-ui/) for details.
|
||||
|
||||
## Secrets and Machine-Local Configuration
|
||||
|
||||
Machine-specific config goes in `$__fish_user_dots_path/local.fish` (defaults
|
||||
to `~/.config/.user-dots/fish/local.fish`). Secrets go in `secrets.fish` in
|
||||
the same directory.
|
||||
|
||||
If local.fish is not loading, verify the path:
|
||||
|
||||
echo $__fish_user_dots_path
|
||||
test -f "$__fish_user_dots_path/local.fish"; and echo exists; or echo missing
|
||||
|
||||
Change the path via variable or TUI:
|
||||
|
||||
set -U __fish_user_dots_path /new/path/to/dots/fish
|
||||
|
||||
Or run `config-settings`, navigate to the Paths page, and edit "Dots path".
|
||||
|
||||
The `user-dots` convenience symlink in the config directory tracks this path.
|
||||
Disable it with:
|
||||
|
||||
set -U __fish_user_dots_symlink false
|
||||
|
||||
See [Personalization](/11-personalization/) for the full `local.fish` / `secrets.fish`
|
||||
layout.
|
||||
|
||||
## Tool Init Does Nothing (Return Sentinel)
|
||||
|
||||
Symptom: you ran a tool's setup command (e.g.
|
||||
`starship init fish >> ~/.config/fish/config.fish`) and nothing changed.
|
||||
|
||||
Cause: `config.fish` ends with a `return` guard. Any lines appended after it
|
||||
are never executed.
|
||||
|
||||
Fix: create a dedicated `conf.d/` file instead of appending to `config.fish`:
|
||||
|
||||
# ~/.config/fish/conf.d/mytool.fish
|
||||
mytool init fish | source
|
||||
|
||||
All existing integrations (starship, zoxide, direnv) already have `conf.d/`
|
||||
files. See [Return Sentinel](/10-installation/#return-sentinel) for background.
|
||||
|
||||
## Missing Dependencies
|
||||
|
||||
Run `fish-deps` (defaults to `fish-deps status`) to see what is installed
|
||||
and what is missing. Common symptoms and their missing tools:
|
||||
|
||||
Symptom Missing tool
|
||||
─────────────────────────────────────────────────────
|
||||
ls output has no icons or colors eza (or lsd)
|
||||
cd does not remember directories zoxide
|
||||
cat shows no syntax highlighting bat
|
||||
fzf keybindings do nothing fzf
|
||||
Starship prompt not appearing starship
|
||||
|
||||
Install missing dependencies interactively:
|
||||
|
||||
fish-deps install
|
||||
|
||||
Or install everything missing and update what is installed:
|
||||
|
||||
fish-deps sync
|
||||
|
||||
See [Dependency Catalog](/06-dependency-catalog/) for the full list grouped by tier
|
||||
(required, integrations, recommended).
|
||||
|
||||
## Vi Mode Keybindings
|
||||
|
||||
This config enables Vi mode by default (via C3 overrides), replacing the
|
||||
standard Emacs-style bindings. If Vi mode interferes with your workflow,
|
||||
override it in `local.fish` (See [Personalization](/11-personalization/)):
|
||||
|
||||
# $__fish_user_dots_path/local.fish
|
||||
fish_default_key_bindings
|
||||
|
||||
This restores Emacs-style bindings without disabling the rest of C3
|
||||
(bang-bang, autopair, starship prompt, pager settings, etc.).
|
||||
|
||||
To disable the entire C3 category (Vi mode and all other key/environment
|
||||
overrides):
|
||||
|
||||
set -U __fish_config_op_overrides off
|
||||
|
||||
See [C3 — Key and Environment Overrides](/08-components-reference/03-c3-key-and-environment-overrides/) for the full list of
|
||||
what C3 controls.
|
||||
|
||||
## What's with the C1-C6 stuff?
|
||||
|
||||
This configuration groups its opinionated behaviors into six categories (C1–C6), allowing you to selectively disable features that conflict with your workflow. The **C**ategory numbers are used as shorthand when referencing these. Disabling all of them leaves you with a "Minimal Mode" shell that only manages basic features like `XDG` variables, and your `local.fish` overrides.
|
||||
|
||||
Category Description
|
||||
──────────────────────────────────────────────────────────────────────────
|
||||
C1 [Command Shadows](/08-components-reference/01-c1-command-shadows/) — Wraps destructive commands (`rm`, `cp`) to be safe by default
|
||||
C2 [Startup Side-Effects](/08-components-reference/02-c2-startup-side-effects/) — Bootstraps Fisher, generates wrappers, auto-activates venvs
|
||||
C3 [Overrides](/08-components-reference/03-c3-key-and-environment-overrides/) — Overrides `cd`, sets Vi mode, binds `<CR>` to `smart_enter`
|
||||
C4 [Integrations](/08-components-reference/04-c4-terminal-and-tool-integration/) — Kitty/Wezterm integrations, starship hooks, fzf theme
|
||||
C5 [Logging and Capture](/08-components-reference/05-c5-logging-and-capture/) — Session logs, command duration
|
||||
C6 [Greeting & First-Run UI](/08-components-reference/06-c6-greeting-and-first-run-ui/) — Custom startup banner
|
||||
|
||||
Disable all opinionated features at once (Minimal Mode):
|
||||
|
||||
set -U __fish_config_opinionated 0
|
||||
|
||||
Disable a single category:
|
||||
|
||||
set -U __fish_config_op_aliases off # C1
|
||||
set -U __fish_config_op_autoexec off # C2
|
||||
set -U __fish_config_op_overrides off # C3
|
||||
set -U __fish_config_op_integrations off # C4
|
||||
set -U __fish_config_op_logging off # C5 (already off by default)
|
||||
set -U __fish_config_op_greeting off # C6
|
||||
|
||||
Keep one category active under a master disable:
|
||||
|
||||
set -U __fish_config_opinionated 0
|
||||
set -U __fish_config_op_aliases 1 # only C1 stays on
|
||||
|
||||
Re-enable everything:
|
||||
|
||||
set -Ue __fish_config_opinionated
|
||||
|
||||
Each category also has two to six sub-categories (e.g.
|
||||
`__fish_config_op_aliases_filesystem`) that can be checked, disabled, or
|
||||
reset the same way — `set -U __fish_config_op_<category>_<subcategory> off`
|
||||
and `set -Ue __fish_config_op_<category>_<subcategory>` work identically to
|
||||
the category-level recipes above, just one level more granular. See
|
||||
[Components Reference](/08-components-reference/) for the full list.
|
||||
|
||||
For an interactive alternative to setting these variables by hand, run `config-settings`.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: Viewing This Manual
|
||||
manTitle: 13. VIEWING THIS MANUAL
|
||||
sidebar:
|
||||
order: 17
|
||||
helpKeywords:
|
||||
- viewing
|
||||
- manual
|
||||
---
|
||||
|
||||
There are four ways to read this manual.
|
||||
|
||||
## The documentation website
|
||||
|
||||
help config --html
|
||||
|
||||
Opens https://fish.rootiest.fyi/ in the default browser — the
|
||||
Starlight-powered site built from `docs/manual/**` on every push to `main`.
|
||||
It has a section sidebar and full-text search. Deep links to a specific
|
||||
section aren't supported from the command line; once the site opens, use
|
||||
its search box to jump straight to what you need.
|
||||
|
||||
## As a man page
|
||||
|
||||
help config --man
|
||||
help config pkg --man
|
||||
|
||||
Opens the compiled docs/fish-config.1 directly via man -l, bypassing
|
||||
the pager fallback chain. If a section keyword is given, the pager opens
|
||||
at the nearest matching heading. The symlink is created once on first
|
||||
run (like an install step) and MANPATH is set each session, enabling
|
||||
the standard invocation:
|
||||
|
||||
man fish-config
|
||||
|
||||
NOTE: fish-config (hyphen) is this config's man page. fish_config
|
||||
(underscore) is fish's built-in browser-based configuration tool —
|
||||
a completely separate command. Do not mix them up.
|
||||
|
||||
## In the terminal
|
||||
|
||||
help config
|
||||
help config keybindings
|
||||
|
||||
Without a pager available beyond the basics, `help config [SECTION]` opens
|
||||
the Markdown manual in the best available viewer, falling back through:
|
||||
|
||||
1. ov + bat section navigation + syntax highlighting (best)
|
||||
2. ov alone section navigation, raw Markdown
|
||||
3. bat alone syntax highlighting, use / to search
|
||||
4. man -l pre-compiled man page (if available)
|
||||
5. less plain text with line-jump
|
||||
6. cat plain output
|
||||
|
||||
With ov, the Markdown renders with syntax highlighting and section-based
|
||||
navigation:
|
||||
|
||||
Space next section
|
||||
^ previous section
|
||||
Alt+u toggle section list sidebar
|
||||
/ search forward
|
||||
n / N next / previous search match
|
||||
g go to line number
|
||||
j interactive jump target (line, %, or 'section')
|
||||
q quit
|
||||
|
||||
If SECTION is given, the pager opens at the first heading that matches the
|
||||
keyword (case-insensitive; checks `docs/fish-config.index` aliases first,
|
||||
then falls back to a normalized heading scan):
|
||||
|
||||
help config keybindings
|
||||
help config abbreviations
|
||||
help config pkg
|
||||
help config logs
|
||||
help config fish-deps
|
||||
|
||||
## Reading the source directly
|
||||
|
||||
`docs/manual/**` is the single source of truth this manual, the man page,
|
||||
and the website are all generated from. Numbered files and directories
|
||||
correspond to the numbered sections in this manual — browse them in any
|
||||
editor, or from a shell:
|
||||
|
||||
cd ~/.config/fish/docs/manual
|
||||
grep -rn "keybindings" .
|
||||
|
||||
Section 5 is the exception. Function entries are generated from the
|
||||
man-page-style comment header above each function in `functions/*.fish`,
|
||||
so the documentation for a command lives beside the code that implements
|
||||
it and cannot drift from it. To read the source for a single function, or
|
||||
to correct its documentation, open the function itself:
|
||||
|
||||
functions/git-clean.fish
|
||||
|
||||
The files under `docs/manual/05-functions/` carry only the category
|
||||
titles, ordering, and search keywords.
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: '404'
|
||||
template: splash
|
||||
editUrl: false
|
||||
man: false
|
||||
hero:
|
||||
title: '404'
|
||||
tagline: 'That page doesn''t exist. Check the URL, try using the search bar, or use one of the links below:'
|
||||
---
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard title="Home" description="Return to the main manual page" href="/" />
|
||||
<LinkCard title="Installation" description="Set up the configuration" href="/10-installation/" />
|
||||
<LinkCard title="Troubleshooting" description="Fix common issues" href="/12-troubleshooting/" />
|
||||
<LinkCard title="Function Reference" description="Browse all functions" href="/reference/" />
|
||||
</CardGrid>
|
||||
@@ -0,0 +1,5 @@
|
||||
title: FISH-CONFIG
|
||||
section: 7
|
||||
header: Fish Shell Configuration User Manual
|
||||
date: June 2026
|
||||
author: Rootiest
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
title: Fish Shell Configuration
|
||||
description: Reference manual for the rootiest fish configuration.
|
||||
manTitle: DESCRIPTION
|
||||
sidebar:
|
||||
order: 3
|
||||
helpKeywords:
|
||||
- description
|
||||
- autopair
|
||||
- puffer
|
||||
- puffer-fish
|
||||
- logging-events
|
||||
---
|
||||
|
||||
A production-grade Fish shell configuration targeting Fish 4.x. It provides:
|
||||
|
||||
- Drop-in replacements for common Unix tools (`ls`, `cat`, `rm`, `du`, `ping`, `less`)
|
||||
- Deep Kitty and WezTerm terminal integration: tab/window/pane management from
|
||||
the command line
|
||||
- Optional session logging: terminal scrollback, tmux/zellij panes, and
|
||||
paru/yay output captured to `~/.terminal_history` (off by default; see [C5 Logging](/08-components-reference/05-c5-logging-and-capture/))
|
||||
- Automatic Python virtualenv activation on directory change
|
||||
- Cross-platform package management via pkg and fish-deps
|
||||
- AI scaffolding helpers for Claude Code and Antigravity
|
||||
- Catppuccin Mocha color theme throughout
|
||||
|
||||
<LinkButton href="/10-installation/" icon="cloud-download" style="font-size: 1.25rem; padding: 1rem 1.5rem; margin-right: 1rem;">Install now</LinkButton>
|
||||
<LinkButton href="/reference/" variant="secondary" style="font-size: 1.125rem; padding: 0.85rem 1.25rem;">Functions</LinkButton>
|
||||
<LinkButton href="/08-components-reference/" variant="secondary" style="font-size: 1.125rem; padding: 0.85rem 1.25rem;">Components</LinkButton>
|
||||
|
||||
The configuration uses a structured file tree:
|
||||
|
||||
~/.config/fish/
|
||||
├── config.fish Main entry point; sets env vars and PATH
|
||||
├── conf.d/
|
||||
│ ├── abbr.fish All abbreviations
|
||||
│ ├── autopair.fish Auto-pair brackets and quotes
|
||||
│ ├── cheat.fish cheat.sh tab completions
|
||||
│ ├── done.fish Desktop notifications for long commands
|
||||
│ ├── first_run.fish One-time init: Fisher bootstrap, theme
|
||||
│ ├── key_bindings.fish Custom key bindings and Vi mode
|
||||
│ ├── logging-events.fish C5 event handlers; syncs logging state
|
||||
│ ├── kitty-watcher-reminder.fish C5 per-session Kitty watcher reminder
|
||||
│ ├── paru-wrapper.fish Auto-generates paru logging wrapper
|
||||
│ ├── puffer.fish !! / !$ / ./ expansion
|
||||
│ ├── tmux-logging.fish C5 starts tmux pipe-pane capture
|
||||
│ ├── zellij-logging.fish C5 fish_exit handler for zellij
|
||||
│ ├── sponge_privacy.fish Sponge privacy patterns
|
||||
│ ├── starship.fish fish_prompt shell-integration markers
|
||||
│ ├── tailscale.fish Tailscale CLI tab completions
|
||||
│ ├── theme.fish Catppuccin syntax highlight colors
|
||||
│ ├── tricks.fish PATH, bang-bang helpers, bat man pages
|
||||
│ ├── wakatime.fish WakaTime shell hook
|
||||
│ ├── yay-wrapper.fish Auto-generates yay logging wrapper
|
||||
│ └── zoxide.fish Zoxide z/zi integration; overrides cd
|
||||
├── functions/ Custom functions, one per file
|
||||
├── completions/ Tab completion scripts
|
||||
├── integrations/
|
||||
│ └── fzf.fish FZF Catppuccin theme and key bindings
|
||||
├── scripts/
|
||||
│ ├── clean_progress_log.py Strips typescript animations for clean logs
|
||||
│ └── agents-tools/ AGENTS.md scripts and git hooks
|
||||
└── docs/ Offline documentation and man page
|
||||
├── fish-config.md Primary source manual
|
||||
├── fish-config.1 Compiled man page (auto-generated)
|
||||
├── fish-config.index Section index for help config
|
||||
├── html/ Chunked HTML docs (auto-generated)
|
||||
└── wiki/ Markdown wiki (auto-generated)
|
||||
|
||||
---
|
||||
@@ -0,0 +1,281 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Shared helpers for the docs/manual SSOT pipeline.
|
||||
|
||||
Frontmatter parsing, deterministic tree ordering, heading level shifts, and
|
||||
the `functions/*.fish` comment-header parser that is the SSOT for Section 5.
|
||||
Used by build-manual.py and verify-manual.py.
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
FENCE_RE = re.compile(r"^\s*(```|~~~)")
|
||||
HEADING_RE = re.compile(r"^(#{1,6})(\s)")
|
||||
|
||||
|
||||
def parse(path: Path) -> tuple[dict, str]:
|
||||
"""Split a markdown file into (frontmatter dict, body text).
|
||||
|
||||
Files without a leading `---` block yield an empty dict and the whole
|
||||
text as body. Body is returned with trailing whitespace stripped.
|
||||
"""
|
||||
text = path.read_text()
|
||||
if not text.startswith("---\n"):
|
||||
return {}, text.rstrip()
|
||||
end = text.find("\n---\n", 4)
|
||||
if end == -1:
|
||||
return {}, text.rstrip()
|
||||
fm = yaml.safe_load(text[4:end]) or {}
|
||||
return fm, text[end + 5 :].removeprefix("\n").rstrip()
|
||||
|
||||
|
||||
def serialize(fm: dict, body: str) -> str:
|
||||
"""Render a frontmatter dict and body back into markdown text."""
|
||||
block = yaml.safe_dump(fm, sort_keys=False, allow_unicode=True).rstrip()
|
||||
return f"---\n{block}\n---\n\n{body.rstrip()}\n"
|
||||
|
||||
|
||||
def shift_headings(body: str, by: int) -> str:
|
||||
"""Add `by` levels to every ATX heading, ignoring fenced code blocks.
|
||||
|
||||
Negative values promote headings. Level is clamped to [1, 6].
|
||||
"""
|
||||
if by == 0:
|
||||
return body
|
||||
out, in_fence = [], False
|
||||
for line in body.split("\n"):
|
||||
if FENCE_RE.match(line):
|
||||
in_fence = not in_fence
|
||||
if not in_fence:
|
||||
line = HEADING_RE.sub(
|
||||
lambda m: "#" * max(1, min(6, len(m.group(1)) + by)) + m.group(2), line
|
||||
)
|
||||
out.append(line)
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
HEADER_LABEL = re.compile(r"^#\s+([A-Z][A-Z ]*[A-Z])\s*$")
|
||||
FUNC_DEF = re.compile(r"^\s*function\s+(\S+)")
|
||||
SECTIONS = (
|
||||
"CATEGORY",
|
||||
"COMPONENT",
|
||||
"DEPENDENCIES",
|
||||
"SYNOPSIS",
|
||||
"DESCRIPTION",
|
||||
"ARGUMENTS",
|
||||
"EXIT STATUS",
|
||||
"RETURNS",
|
||||
"EXAMPLE",
|
||||
"NOTES",
|
||||
)
|
||||
|
||||
|
||||
def _header_blocks(lines: list[str]) -> list[tuple[int, dict[str, list[str]]]]:
|
||||
"""Find every man-page comment header in a file's lines.
|
||||
|
||||
Yields (index of the line that ended the block, {LABEL: body lines}).
|
||||
Body lines keep any indentation deeper than the standard `# ` prefix,
|
||||
which is what lets nested option tables survive into the rendered entry.
|
||||
Comment runs carrying no `# LABEL` line at all (the copyright preamble,
|
||||
ordinary inline comments) produce nothing.
|
||||
"""
|
||||
out: list[tuple[int, dict[str, list[str]]]] = []
|
||||
cur: dict[str, list[str]] = {}
|
||||
label: str | None = None
|
||||
for i, line in enumerate(lines + [""]):
|
||||
if not line.startswith("#"):
|
||||
if cur:
|
||||
out.append((i, cur))
|
||||
cur, label = {}, None
|
||||
continue
|
||||
m = HEADER_LABEL.match(line)
|
||||
if m:
|
||||
label = m.group(1)
|
||||
cur.setdefault(label, [])
|
||||
elif label is not None:
|
||||
body = line[1:]
|
||||
cur[label].append(body[3:] if body.startswith(" ") else body.strip())
|
||||
return out
|
||||
|
||||
|
||||
def _trailing_blanks(lines: list[str]) -> int:
|
||||
"""Count the blank `#` separator lines closing a section."""
|
||||
n = 0
|
||||
while n < len(lines) and not lines[len(lines) - 1 - n].strip():
|
||||
n += 1
|
||||
return n
|
||||
|
||||
|
||||
def _block_identity(path: Path, lines: list[str], end: int, blocks_count: int) -> str:
|
||||
"""Resolve a header block's associated name.
|
||||
|
||||
A file carrying exactly one header is associated with its own stem, so
|
||||
a `function` nested inside a `type -q` guard still resolves. A file
|
||||
with several headers walks forward to the next `function` definition.
|
||||
"""
|
||||
if blocks_count == 1:
|
||||
return path.stem
|
||||
after = (m.group(1) for ln in lines[end:] if (m := FUNC_DEF.match(ln)))
|
||||
return next(after, path.stem)
|
||||
|
||||
|
||||
def parse_functions(root: Path) -> dict[str, dict[str, list[str]]]:
|
||||
"""Parse the comment header above every documented public function.
|
||||
|
||||
`root` is the repository's `functions/` directory. Returns
|
||||
`{name: {LABEL: [lines]}}`.
|
||||
|
||||
`# CATEGORY` is the opt-in: a header without one produces no entry. That
|
||||
keeps bundled-plugin and prompt internals (`fish_prompt`, `sponge_filter_*`,
|
||||
`fisher`, …) out of the manual with no exclusion list to maintain.
|
||||
|
||||
A file carrying exactly one header is associated with its own stem, so a
|
||||
`function` nested inside a `type -q` guard still resolves. Only files with
|
||||
several headers walk forward to the next `function` definition.
|
||||
"""
|
||||
out: dict[str, dict[str, list[str]]] = {}
|
||||
for path in sorted(root.glob("*.fish")):
|
||||
lines = path.read_text(encoding="utf-8").split("\n")
|
||||
blocks = _header_blocks(lines)
|
||||
for end, sections in blocks:
|
||||
name = _block_identity(path, lines, end, len(blocks))
|
||||
if name.startswith("_") or "CATEGORY" not in sections:
|
||||
continue
|
||||
out[name] = {
|
||||
k: v[: len(v) - _trailing_blanks(v)] for k, v in sections.items()
|
||||
}
|
||||
return out
|
||||
|
||||
|
||||
def parse_abbreviations(root: Path) -> dict[str, list[dict]]:
|
||||
"""Parse annotated abbreviations from conf.d/.
|
||||
|
||||
Returns {category: [{"name": name, "desc": desc}, ...]}
|
||||
"""
|
||||
out: dict[str, list[dict]] = {}
|
||||
for filename in ("abbr.fish", "tricks.fish", "puffer.fish"):
|
||||
path = root / filename
|
||||
if not path.exists():
|
||||
continue
|
||||
lines = path.read_text(encoding="utf-8").split("\n")
|
||||
category = None
|
||||
desc = None
|
||||
name_override = None
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line.startswith("# @category "):
|
||||
category = line[12:].strip()
|
||||
elif line.startswith("# @desc "):
|
||||
desc = line[8:].strip()
|
||||
elif line.startswith("# @name "):
|
||||
name_override = line[8:].strip()
|
||||
elif line.startswith("abbr -a ") or line.startswith("bind ") or line.startswith("alias "):
|
||||
if category and desc:
|
||||
if name_override:
|
||||
name = name_override
|
||||
elif line.startswith("abbr -a "):
|
||||
name = line[8:].strip().split()[0].strip("'\"")
|
||||
elif line.startswith("alias "):
|
||||
name = line[6:].strip().split('=')[0]
|
||||
else:
|
||||
name = "unknown"
|
||||
# Only add if we haven't added this name to this category yet
|
||||
if not any(a["name"] == name for a in out.setdefault(category, [])):
|
||||
out[category].append({
|
||||
"name": name,
|
||||
"desc": desc
|
||||
})
|
||||
category = None
|
||||
desc = None
|
||||
name_override = None
|
||||
return out
|
||||
|
||||
|
||||
SITE_LINE_RE = re.compile(r"^site\s+(\S+):\s*(\S+)$")
|
||||
|
||||
|
||||
def parse_component_lines(lines: list[str]) -> list[tuple[str, str]]:
|
||||
"""Parse raw `# COMPONENT` body lines into (site, tag) pairs.
|
||||
|
||||
A line of the form `site <slug>: <tag>` scopes <tag> to that site; a
|
||||
bare `<tag>` line belongs to the default (unnamed) site, keyed "".
|
||||
Blank lines are skipped.
|
||||
"""
|
||||
out: list[tuple[str, str]] = []
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
m = SITE_LINE_RE.match(line)
|
||||
if m:
|
||||
out.append((m.group(1), m.group(2)))
|
||||
else:
|
||||
out.append(("", line))
|
||||
return out
|
||||
|
||||
|
||||
def _parse_component_blocks(path: Path) -> dict[str, list[str]]:
|
||||
"""Parse every `# COMPONENT` header block in one file.
|
||||
|
||||
Unlike parse_functions, there is no `# CATEGORY` gate and no
|
||||
underscore exclusion: component classification applies to every
|
||||
function/script, public or private, documented in the manual or not
|
||||
-- the registry needs to see every guarded identity, not just the
|
||||
ones that appear in the public function reference.
|
||||
"""
|
||||
lines = path.read_text(encoding="utf-8").split("\n")
|
||||
blocks = _header_blocks(lines)
|
||||
out: dict[str, list[str]] = {}
|
||||
for end, sections in blocks:
|
||||
if "COMPONENT" not in sections:
|
||||
continue
|
||||
name = _block_identity(path, lines, end, len(blocks))
|
||||
body = sections["COMPONENT"]
|
||||
out[name] = body[: len(body) - _trailing_blanks(body)]
|
||||
return out
|
||||
|
||||
|
||||
def parse_component_file(path: Path) -> dict[str, list[str]]:
|
||||
"""Parse `# COMPONENT` header block(s) in one specific file (e.g. config.fish)."""
|
||||
return _parse_component_blocks(path)
|
||||
|
||||
|
||||
def parse_components(root: Path) -> dict[str, list[str]]:
|
||||
"""Parse `# COMPONENT` header blocks across every `*.fish` file under root."""
|
||||
out: dict[str, list[str]] = {}
|
||||
for path in sorted(root.glob("*.fish")):
|
||||
out.update(_parse_component_blocks(path))
|
||||
return out
|
||||
|
||||
|
||||
def _sort_key(entry: Path) -> tuple:
|
||||
"""Order by sidebar.order when present, else by filename. Stable."""
|
||||
target = entry / "index.md" if entry.is_dir() else entry
|
||||
order = None
|
||||
if target.exists():
|
||||
fm, _ = parse(target)
|
||||
order = (fm.get("sidebar") or {}).get("order")
|
||||
return (order is None, order if order is not None else 0, entry.name)
|
||||
|
||||
|
||||
def walk(root: Path, depth: int = 0) -> list[tuple[Path, int]]:
|
||||
"""Return ordered (path, depth) pairs for every markdown file under root.
|
||||
|
||||
A directory sorts at the position of its index.md and its children are
|
||||
emitted immediately afterwards at depth+1.
|
||||
"""
|
||||
entries = [e for e in root.iterdir() if e.is_dir() or e.suffix == ".md"]
|
||||
result: list[tuple[Path, int]] = []
|
||||
for entry in sorted(entries, key=_sort_key):
|
||||
if entry.is_dir():
|
||||
index = entry / "index.md"
|
||||
if index.exists():
|
||||
result.append((index, depth))
|
||||
result.extend(walk(entry, depth + 1))
|
||||
elif entry.name != "index.md" or depth == 0:
|
||||
result.append((entry, depth))
|
||||
return result
|
||||
@@ -0,0 +1,24 @@
|
||||
# build output
|
||||
dist/
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# starlight-plugin-icons safelist cache
|
||||
.starlight-icons/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"recommendations": ["astro-build.astro-vscode"],
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "./node_modules/.bin/astro dev",
|
||||
"name": "Development server",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# fish-config docs site
|
||||
|
||||
[Starlight](https://starlight.astro.build) site for the
|
||||
[fish-config](https://git.rootiest.dev/rootiest/fish-config) manual.
|
||||
|
||||
## Generated, not authored
|
||||
|
||||
Everything under `src/content/docs/` is generated — **do not edit it
|
||||
directly**, changes will be overwritten. The sources are:
|
||||
|
||||
- `docs/manual/**` — prose for every section except the functions reference
|
||||
- `functions/*.fish` comment headers — the functions reference (Section 5)
|
||||
|
||||
Regenerate from the repo root:
|
||||
|
||||
```fish title="regenerate the site content"
|
||||
python3 docs/build-manual.py --site
|
||||
```
|
||||
|
||||
`docs/verify-manual.py` validates both sources before you build; run it
|
||||
first if you've touched a header or a manual page.
|
||||
|
||||
## llms.txt
|
||||
|
||||
The [`starlight-llms-txt`](https://www.npmjs.com/package/starlight-llms-txt)
|
||||
plugin emits `llms.txt`, `llms-full.txt`, and `llms-small.txt` alongside the
|
||||
built pages — no configuration needed, it just walks the generated content.
|
||||
|
||||
## Icons
|
||||
|
||||
[`starlight-plugin-icons`](https://docs.rettend.me/starlight-plugin-icons)
|
||||
+ [UnoCSS](https://unocss.dev) (`uno.config.ts`) render icons from any
|
||||
[Iconify](https://icones.js.org) set as `i-<collection>:<name>` classes.
|
||||
The Gitea link in the header uses it (see
|
||||
`src/components/starlight/SocialIcons.astro`) to show the real Gitea logo
|
||||
instead of Starlight's generic `code-branch` icon. Sidebar (`sidebar:
|
||||
true`) and codeblock (`codeblock: true`) icon support are wired up in
|
||||
`astro.config.mjs` but unused so far — see the plugin docs for the
|
||||
`icon:` sidebar syntax if you want to add them.
|
||||
|
||||
## Development
|
||||
|
||||
```fish title="local dev server"
|
||||
cd docs/site
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Deploy
|
||||
|
||||
Built and deployed to Cloudflare Pages by the Gitea Actions workflow on
|
||||
every push to `main` — there's no manual deploy step.
|
||||
@@ -0,0 +1,63 @@
|
||||
import { defineConfig } from 'astro/config';
|
||||
import UnoCSS from 'unocss/astro';
|
||||
import Icons from 'starlight-plugin-icons';
|
||||
import starlightLinksValidator from 'starlight-links-validator';
|
||||
import starlightCatppuccin from '@catppuccin/starlight';
|
||||
import starlightLlmsTxt from 'starlight-llms-txt';
|
||||
import sidebar from './src/sidebar.json' with { type: 'json' };
|
||||
|
||||
export default defineConfig({
|
||||
prerenderConflictBehavior: 'ignore',
|
||||
site: 'https://fish.rootiest.fyi',
|
||||
integrations: [
|
||||
UnoCSS(),
|
||||
...Icons({
|
||||
sidebar: true,
|
||||
codeblock: true,
|
||||
extractSafelist: true,
|
||||
starlight: {
|
||||
title: 'Rootiest Fish Config',
|
||||
description: 'Reference manual for the rootiest fish configuration.',
|
||||
favicon: '/favicon.svg',
|
||||
logo: {
|
||||
src: './src/assets/logo.svg',
|
||||
},
|
||||
social: [
|
||||
{
|
||||
icon: 'code-branch',
|
||||
label: 'Gitea',
|
||||
href: 'https://git.rootiest.dev/rootiest/fish-config',
|
||||
},
|
||||
],
|
||||
components: {
|
||||
SocialIcons: './src/components/starlight/SocialIcons.astro',
|
||||
},
|
||||
head: [
|
||||
{
|
||||
tag: 'script',
|
||||
content: 'document.addEventListener("DOMContentLoaded", () => { document.querySelectorAll("starlight-file-tree").forEach(tree => { tree.querySelectorAll("details").forEach((d, i) => { if (i !== 0) d.removeAttribute("open"); }); }); });',
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
starlightLinksValidator(),
|
||||
starlightCatppuccin({
|
||||
dark: { flavor: "mocha", accent: "green" },
|
||||
light: { flavor: "latte", accent: "sky" },
|
||||
}),
|
||||
starlightLlmsTxt(),
|
||||
],
|
||||
expressiveCode: {
|
||||
// Shiki ships both Catppuccin flavours; Starlight picks by the
|
||||
// reader's colour scheme, matching the palette in catppuccin.css.
|
||||
themes: ['catppuccin-mocha', 'catppuccin-latte'],
|
||||
styleOverrides: {
|
||||
borderRadius: '0.4rem',
|
||||
borderColor: 'var(--sl-color-gray-5)',
|
||||
codeFontSize: '0.875rem',
|
||||
},
|
||||
},
|
||||
sidebar,
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
Generated
+8682
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user