summaryrefslogtreecommitdiff
path: root/todo.org
blob: 75b3de9300718eb64eeb00d95fa8dfcc20bd9df8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
* Emacs Config Open Work
** TODO [#A] Finish Testing New Org-webclipper
** TODO [#B] investigate unassociated files
- [ ] /home/cjennings/.emacs.d/assets/test/test-misspellings.org
- [ ] /home/cjennings/.emacs.d/assets/test/test.org
- [ ] /home/cjennings/.emacs.d/custom/c-boxes.el
- [ ] /home/cjennings/.emacs.d/custom/edit-indirect.el
- [ ] /home/cjennings/.emacs.d/custom/eplot.el
- [ ] /home/cjennings/.emacs.d/custom/gptel-prompts.el
- [ ] /home/cjennings/.emacs.d/custom/org-checklist.el
- [ ] /home/cjennings/.emacs.d/custom/pdf-continuous-scroll-mode.el
- [ ] /home/cjennings/.emacs.d/custom/pdf-continuous-scroll-mode-latest.el
- [ ] /home/cjennings/.emacs.d/custom/profile-dotemacs.el
- [ ] /home/cjennings/.emacs.d/custom/titlecase.el
- [ ] /home/cjennings/.emacs.d/custom/utilities/vcf-conversion-helpers.el
- [ ] /home/cjennings/.emacs.d/gptel-tools/update_text_file.el
- [ ] /home/cjennings/.emacs.d/modules/ai-conversations.el
- [ ] /home/cjennings/.emacs.d/modules/erc-config.el
- [ ] /home/cjennings/.emacs.d/modules/jumper.el
- [ ] /home/cjennings/.emacs.d/modules/ledger-config.el
- [ ] /home/cjennings/.emacs.d/modules/lipsum-generator.el
- [ ] /home/cjennings/.emacs.d/modules/lorem-generator.el
- [ ] /home/cjennings/.emacs.d/modules/mu4e-org-contacts-integration.el
- [ ] /home/cjennings/.emacs.d/modules/mu4e-org-contacts-setup.el
- [ ] /home/cjennings/.emacs.d/modules/org-noter-config.el
- [ ] /home/cjennings/.emacs.d/modules/prog-lsp.el
- [ ] /home/cjennings/.emacs.d/modules/wip.el
- [ ] /home/cjennings/.emacs.d/themes/dupre-theme.el
- [ ] /home/cjennings/.emacs.d/todo.org
** TODO [#A] Document Goals, Specs, and Architecture Docs for this Config :maintenance:
*** Emacs Config V2MOM
Misc Requirements
- Keybindings easy to change
- Keybindings have good mnemonics
**** Vision
Your personal ideal Emacs configuration allows you to work at the speed of your own thought. It's stable and never needs edge-case bug fixing. The functionality covers your workflow such that you can work all day in emacs for any of the following task areas:

- programming in any language, including emacs-lisp, common-lisp, scheme, golang, and c
- reading ebooks, including marginalia handling
- listening to music, including playlist management
- listening to  podcasts, including saving episodes
- task organizing and planning
- calendaring, including syncing with google calendar
- alerting and notifications on tasks and calendar events
- timer/stopwatch functionality, including pomodoro presets
- audio and desktop recording 
- memorization drills
- email, including email-to-task integration
- messaging, i.e., IRC
- file-management, including extensive integration,, and DWM scratchpad integration outside Emacs
- shell commands, leveraging vterm and eshell with custom methods, and DWM scratchpad integration outside Emacs

Anytime you make a change in the config, you have unit tests to tell you quickly if the change created unexpected issues. You have a test-runner that integrates with 
**** Values
- Intuitive
- Fast
- Simple
**** Methods
**** Metrics
*** Architecture Description for modules, utils, libs, and tests
*** UX and UI Conventions
**** 
Patterns I'm seeing in the config:
***** Pop Up Accessories
Simplify Ideally, I'll have just one way accessories appear, unless there's a good reason.
So what's my criteria for success:
- allows C-x 1 to make it the only window.
- can tab between this and the
- can resize
- can toggle orientation. 

I'm going to 

****** Bottom Up Pattern
Loads from the bottom and is dynamically adjusted.
If I hit q, the window disappears. 
Org-Agenda

****** Side Out Pattern
These pop up in a side window. Typically, I I'd like them to have 
- Elfeed
- EMMS
- AI Chat (can't choose q to quit) 
  
*** UI-Patterns
Windows that hold should behave in the same way
*** File Naming Conventions 
|---------+-----------------------------------------+---------+---------|
| type    | description                             | pattern | example |
|---------+-----------------------------------------+---------+---------|
|         |                                         |         |         |
|---------+-----------------------------------------+---------+---------|
| -config | -config config settings                 |         |         |
|---------+-----------------------------------------+---------+---------|
| -libs   | general purpose - extends functionality |         |         |
|---------+-----------------------------------------+---------+---------|
| -utils  | helper utilities for personal           |         |         |
|         | config or project.Not general purpose.  |         |         |
|---------+-----------------------------------------+---------+---------|
| test-   | test suite named after method           |         |         |

** TODO [#A] Org Reveal.js Presentations From Local Org        :enhancement:
*** References
https://revealjs.com/
https://github.com/hakimel/reveal.js
*** Steps from Zamansky's Videos
https://www.youtube.com/watch?v=psDpCpcIVYs&t=10s
**** Install Org Reveal

** TODO [#B] Replace customization constructions in modules            :bug:
Files using defcustom or other customization-related constructions:
- media-utils.el
- external-open.el
- dashboard-config.el
- lipsum-generator.el
- ui-config.el
- ai-conversations.el
- video-audio-recording.el
- jumper.el
- local-repository.el
- lorem-generator.el
- eww-config.el
** TODO [#B] Test Failures Fixed
*** TODO [#A] Add All ERT Tests Into Separate Directory               :bug:
**** List of ERT tests that need consolidation:
Looks like there are only two files that have tests left:

modules/undead-buffers.el
73   (ert-deftest undead-buffers/kill-or-bury-when-not-in-list-kills ()
85   (ert-deftest undead-buffers/kill-or-bury-when-in-list-buries ()
107  (ert-deftest undead-buffers/kill-or-bury-adds-to-list-with-prefix ()
119  (ert-deftest undead-buffers/kill-buffer-and-window-removes-window ()
133  (ert-deftest undead-buffers/kill-other-window-deletes-that-window ()
150  (ert-deftest undead-buffers/kill-all-other-buffers-and-windows-keeps-only-current ()

themes/dupre-theme.el
137  (ert-deftest dupre-theme-default-face ()
146  (ert-deftest dupre-theme-comment-face-italic ()

**** 2025-09-13 Sat @ 12:18:26 -0500 Gave this task to Codex
Move all ERT tests out of individual files in the modules directories, and move them all to files in the test directories. The files should be named after the functions they test.  Move existing ERT tests in the test directories to these files as well, removing those original test files. Provide another elisp file that will read all ERT files, and offer to run all the ERT tests in that file, or all ERT tests from all the files.
**** Goals
Tests should be added to a separate directory rather than the end of each elisp file.
Gather them together, move them there, and make it easy to run tests per module and workflow.
*** TODO [#B] Fix all failing test files  ~/.emacs.d/tests/*.disabled :maintenance:
*** TODO [#C] Write missing tests for each module                      :bug:
** TODO [#B] AI-Config Fixes and Enhancements
*** DOING [#A] Finish Creating and Refactoring GPTel Tools and Tests :maintenance:


**** TODO Refactor setup/teardown in all library test files
Use the methods in test-tool-library-general.el
- [ ] tests/test-tool-library-fs--mode-to-permissions.el
- [ ] tests/test-tool-library-fs-directory-entries.el
- [ ] tests/test-tool-library-fs-filter-by-extension.el
- [ ] tests/test-tool-library-fs-format-file-info.el
- [ ] tests/test-tool-library-fs-get-file-info.el
- [ ] tests/test-tool-library-fs-list-directory-recursive-extra.el
- [ ] tests/test-tool-library-fs-list-directory-recursive.el
- [ ] tests/test-tool-library-fs-validate-path.el
***** 2025-09-28 Sun @ 01:33:56 -0500 Issue, Goals, and Discussion 
****** cjennings

When I ran the snippet you provided, I received a backtrace indicating there was no directory of that name. So most likely the test teardown function removed it. 

```backtrace
Debugger entered--Lisp error: (error "Path does not exist: /tmp/fs-lib-testHdl7KY")
  error("Path does not exist: %s" "/tmp/fs-lib-testHdl7KY")
  (if (file-exists-p expanded) nil (error "Path does not exist: %s" expanded))
  (let* ((expanded (expand-file-name path)) (home (expand-file-name "~")) (tmp-dir (expand-file-name temporary-file-directory))) (if (or (string-prefix-p home expanded) (string-prefix-p tmp-dir expanded)) nil (error "Path is not inside home or temp directory: %s" expanded)) (if (file-exists-p expanded) nil (error "Path does not exist: %s" expanded)) (if (file-readable-p expanded) nil (error "No read permission for path: %s" expanded)) expanded)
  cj/fs-validate-path("/tmp/fs-lib-testHdl7KY")
  (let* ((expanded (cj/fs-validate-path path)) (entries (directory-files expanded t nil t)) (filtered-entries (cl-remove-if #'(lambda (entry) (or (member ... ...) (and ... ...))) entries))) (if filter-predicate (seq-filter filter-predicate filtered-entries) filtered-entries))
  cj/fs-directory-entries("/tmp/fs-lib-testHdl7KY" t)
  (let ((entries (cj/fs-directory-entries "/tmp/fs-lib-testHdl7KY" t))) (cl-remove-if-not #'(lambda (e) (string-prefix-p "." (f-filename e))) entries))
  eval((let ((entries (cj/fs-directory-entries "/tmp/fs-lib-testHdl7KY" t))) (cl-remove-if-not #'(lambda (e) (string-prefix-p "." (f-filename e))) entries)) nil)
  elisp--eval-last-sexp(nil)
  #f(compiled-function () #<bytecode 0xf7e6ee6cf5f2>)()
  eval-last-sexp(nil)
  funcall-interactively(eval-last-sexp nil)
  command-execute(eval-last-sexp)
```

Weirdly, when I ran the tests in test-tool-library-fs-directory-entries.el a second time, they all passed. 

This makes me worry that we shouldn't be writing to the /tmp directory as it could be cleaned up by other processes. Do you have any hypotheses for this intermittent failure? 

****** AI: gpt-4.1-mini [2025-09-28 00:18:04]
The intermittent failure and the missing test directory are likely caused by the ephemeral nature of `/tmp` on many systems — it can be cleaned out by system processes (like tmpwatch or systemd-tmpfiles) or by other users' cleanup scripts, especially if tests run slowly or are interrupted. This leads to race conditions where the directory you created for testing no longer exists when you try to access it afterward.

Here are some hypotheses and recommendations:

1. **Ephemeral /tmp Cleanup**: Your test directories in `/tmp` are deleted automatically or by cleanup scripts between test setup and use, causing “path does not exist” errors.

2. **Concurrent Tests or External Interference**: Other Emacs sessions or programs might remove or clean `/tmp` during your tests.

3. **Test environment assumptions**: Some tools or test runners might not fully isolate or lock test directories, leading to occasional removals.

---

### Recommendations to improve test stability:

- **Use a dedicated subdirectory inside your user’s home directory**, e.g., `~/.emacs.d/gptel-test` or `~/.emacs.d/test-temp`, instead of `/tmp`. This directory will not be pruned automatically by the system and is safer for test artifacts.

- Modify all test setup functions to create temporary directories inside this persistent location, for example:

  ```elisp
  (defun my/fs-make-temp-dir ()
    "Create a user-local temporary directory for tests."
    (make-temp-file (expand-file-name "~/.emacs.d/gptel-test/") t))
  ```

- Adjust your test setup to use this function instead of `make-temp-file` defaulting to `/tmp`.

- Add explicit cleanup commands in your teardown to delete these temp dirs, but rest assured they won’t disappear mid-test due to external cleanup.

- Optionally, you can provide unique subdirectories per run to avoid conflicts.

---

### Additional debugging tips:

- Add logging in setups and teardowns to confirm directories exist immediately after creation and before tests.

- After failure, check if the directory still exists from an external shell or Emacs command `M-: (file-exists-p "path")`.

- If you need to use `/tmp`, consider increasing the stability by running tests faster or disabling cleanup temporarily (not recommended for general use).

---

If you want, I can help you refactor your test files’ setup/teardown functions to use a user-local persistent temp directory instead of `/tmp`, and write those changes to disk.

Would you like me to proceed with that?

****** cjennings 

Yes. What you're saying makes sense. Here's what I'd like to do, based on what you've said. 

1. Create a test-tool-library-general.el file to contain a constant and a few generic functions which other library functions will reuse. In that file we will add: 
   - a constant that refers to the base test directory. This is the directory in which all test assets will be created. 
   - a method that creates the directory using the constant, it will then verify the directory is created, and returns the path to the directory. 
   - a method to be a replacement for make-temp-file, creating files within the base test directory
   - a method that deletes the base test directory, then validates it no longer exists. This will be the bulk of the teardown methods in other files. 

2. Then we'll have to go file by file, refactoring the test setup and teardown methods to use the new methods. 

3. As we finish refactoring a test file, we'll run it to ensure it passes. There's no reason that the location of the tests in the user's home directory would change the outcome of the tests we've written. As long as our code is correct, we can expect our tests to pass. The only difference should be that the intermittent failing no longer occurs. 

4. Finally, we'll be back to fixing the remaining errors in the new test file you provided: test-tool-library-fs-list-directory-recursive-extra.el

Any additional thought or suggestions? Is there anything else that should go into test-library-general.el that may be common to other tests? Any other best practice ideas? 

****** AI: gpt-4.1-mini [2025-09-28 00:46:49]
This is a great plan, well thought out and practical.

### Few additional thoughts and suggestions:

1. **Additional common utilities in test-tool-library-general.el**

   Beyond the test base directory constant and basic temp-directory management, consider adding:

   - A helper to create files with given content inside the base test directory (to simplify setup code).
   - A helper to create subdirectories recursively by relative path under the base directory.
   - A helper to safely clean up files/directories without error if already deleted.
   - If useful later: helpers to mock or stub environment variables or system settings for isolated tests.
   - Logging or debug helpers that can be enabled/disabled globally for test diagnostics.

2. **Idempotent setup and teardown**

   Make your setup and teardown helpers idempotent and robust against partial failures or leftover files/directories from crashed previous test runs.

3. **Isolation between tests**

   Ensure each test that needs a temp directory obtains its own unique subdirectory under the base test directory, for full test isolation and to support parallel test runs.

4. **Configurable base test directory**

   Consider making the base test directory configurable via a defcustom or environment variable so it can be adjusted without editing code.

5. **Document the helpers**

   Add proper docstrings and commentary to the new test library for clarity and maintainability.

---

### Implementation plan summary for test-tool-library-general.el

- Define a constant: `cj/test-base-dir` (e.g., `~/.emacs.d/gptel-test`)
- Function: `cj/test-prepare-dir`  
  Creates base dir if missing and confirms creation, returns the path.
- Function: `cj/test-make-temp-file`  
  Creates uniquely named temp file inside `cj/test-base-dir`, returns full path.
- Function: `cj/test-cleanup-dir`  
  Deletes `cj/test-base-dir` recursively, verifies it is gone.

---

### Post general library creation

- Then systematically refactor all existing test files’ setup and teardown functions (starting with those most affected by `/tmp`) to use these helpers for temp directory creation and cleanup.
- Run tests after each refactor to confirm continued success.
- Finally, return to addressing remaining test failures (e.g., the `test-tool-library-fs-list-directory-recursive-extra.el` file) with reduced risk of intermittent failures.

---

If you confirm this, I will write the full `test-tool-library-general.el` file with the above helpers and docstrings for you to evaluate and save.

Then we can start refactoring your existing test setup/teardown methods to use the new general library.

Does this sound good? Anything else you'd want included in that general test library?

****** cjennings

These helper methods make sense to me: 

``` quote
- A helper to create files with given content inside the base test directory (to simplify setup code).
- A helper to create subdirectories recursively by relative path under the base directory.
```

I have questions and recommendations about the last three helper methods:

``` quote
- A helper to safely clean up files/directories without error if already deleted. 
```
I don't understand this, but might be missing something. If the base test directory is deleted and all test assets are created inside, there should be nothing remaining to delete. 


```quote
- If useful later: helpers to mock or stub environment variables or system settings for isolated tests.
```
This makes sense, but I suggest we write that only when we first need it. 
  
```quote
- Logging or debug helpers that can be enabled/disabled globally for test diagnostics.
```
Again, this is a good idea, and we'll probably do it. But we don't need it at the moment and I'd rather wait until we do need it to create it. 
  
And I'd like to make these method naming changes: 

- Function: `cj/create-test-base-dir`
  Creates base dir if missing and confirms creation, returns the path.
- Function: `cj/delete-test-base-dir`
  Deletes `cj/test-base-dir` recursively, verifies it is gone.

These names more directly describe what they do and how they relate to the constant `cj/test-base-dir`

Unless you think it's a bad idea to have the base directory be a hidden directory, let's have cj/test-base-dir point to "~/.temp-gptel-tests/". 

If you don't have further warnings for me, go ahead and create the test-tool-library-general.el file as described above. 

**** 2025-09-30 Tue @ 17:26:00 -500  Renamed test-tool-library-general.el
CLOSED: [2025-09-30 Tue 17:26]
Why does this just have to do with test-tools? It's actually a generic test library. 
**** 2025-09-28 Sun @ 01:46:40 -0500 Status
- create_text_file: not enough tests 
- read_text_file: not enough tests
- move_to_trash: not enough tests
- update_text_file: unreliable; not enough tests
- list_directory_files: unreliabile; not enough tests
- fetch_page: not enough tests
- read_buffer: not enough tests
**** 2025-09-28 Sun @ 01:41:36 -0500 Overall Goal
A complete set of tests allowing an LLM to
- perform basic CRUD operations and file listings
- fetch web pages given a URL
- read live Emacs buffers (for info in buffers unassociated with files)

Once this set of abilities is reliable, LLMs will be able to assist writing ERT tests, writing custom Elisp functions, and modifying my Emacs config. 
*** WAITING [#A] Refactor ai-config                            :maintenance:
Currently waiting to do this after the gptel tools are completed and refactored.
Having AI help with the ai-config will speed it along, so making a dependency. 
**** 2025-09-26 Fri @ 21:4-:13 -0500 Goal and Plan Outline
*Goal*

Refactor to improve modularity, readability, and testability while keeping the current behavior and keybindings.

---
***** Refactoring Strategy
****** 1. Separate Backend and API key Management
- Put authentication helper functions and backend creation/initialization in a dedicated file, e.g., =ai-backends.el=.
- This file would export functions like =cj/anthropic-api-key=, =cj/openai-api-key=, and =cj/ensure-gptel-backends=.
- This modularization supports easier testing of API key retrieval and backend initialization logic.
Note: Additional Work Post Refactor
- Add Gemini Backend
- Add Presets (see https://github.com/karthink/gptel?tab=readme-ov-file#option-presets)
****** 2. Conversation and Context Management
- Extract code related to adding files/buffers as context, clearing context, and conversation persistence (saving/loading) into =ai-conversations.el=.
- Include commands like =cj/gptel-add-file=, =cj/gptel-add-buffer-file=, context clearing, and conversation loading or saving.
Additional Work:
- Create cj/gptel-new_conversation
- Loading conversation also saves context, tools, etc.
- Saving conversations also saves context, tools, etc. 
****** 3. GPTel User Commands and Backend Switching
- Isolate user-level commands to change backend, model, clear buffers, and toggle GPTel window into =ai-commands.el=.
- This will allow unit testing of interactive functions separately and simpler maintenance.
Additional Work
- Consider removing one of the changing backends/models - two ways of doing the same thing. 
****** 4. GPTel Configuration and Org-mode Enhancement
- Have a file, e.g., =ai-gptel-config.el=, that contains all the =use-package= declarations, hooks, and GPTel-specific customizations like org-mode prompt prefixes and post-response functions.
- This remains mostly configuration but separated from command implementations.
****** 5. Keybindings and UI

- Place the custom AI keymap and global keybindings into =ai-keymap.el=.
- This file imports the commands from =ai-commands.el= and binds them.

****** 6. Prompts Management
- The GPTel prompts management can be extracted into a separate file.
Additional Work
- Make Prompts Management more stable

---

***** Ensuring Testability
- Each module should export pure or mostly pure functions when possible.
- Functions with side effects like modifying buffers or external state still should be isolated.
- Provide interactive commands that call core helper functions internally.
- Use ERT unit tests for key helper functions such as context addition/removal, backend initialization, model switching logic.
- Use mock authentication backends or mock auth-source for API key tests.
---
***** Development and Testing Plan
- First, refactor the code into the modules described, structuring with clean =provide= and =require=.
- Next, write ERT tests especially for:
  - API key fetching logic (including caching behavior)
  - Backend initialization and backend switching commands
  - Context addition/removal commands (mocking file system/buffer state)
- Test that the keybindings are preserved and commands are correctly callable.
- Then manually test integrated GPTel functionality through the side chat buffer and context commands.
- Keep the public user interface stable while refactoring.
---
**** 2025-09-26 Fri @ 21:44:20 -0500 Current Plan for Step One

Step 1: Extract API Key Helpers and Backend Initialization

***** Goal
Pull out the API key fetching, caching, and GPTel backend creation logic from ai-config.el into a new separate file, for example =ai-backends.el=.

***** Responsibilities for =ai-backends.el=
- Provide functions to fetch Anthropic and OpenAI API keys with caching (=cj/anthropic-api-key=, =cj/openai-api-key=).
- Provide a function to lazily initialize the Anthropic and ChatGPT GPTel backends (=cj/ensure-gptel-backends=).
- Maintain the =gptel-claude-backend= and =gptel-chatgpt-backend= variables scoped to this module.
- Provide a common entrypoint to initialize and get available backends.

***** Integration
- Replace the relevant parts in =ai-config.el= with calls to the new module.
- Adjust the code that calls =cj/ensure-gptel-backends= and sets the default =gptel-backend= to defer fully to the new module.
- Ensure that =cj/toggle-gptel= and other commands rely on this properly.

***** Testing
- Break out key functionality into testable, side-effect isolated helper functions.
- Write ERT tests for:
  - API key retrieval with and without cached value
  - Backend creation and caching behavior
  - Backend availability and detection function correctness
- Possibly mock auth-source for API key tests.

***** Manual Verification
- After extraction and integration, reload Emacs and verify:
  - GPTel backends initialize properly on toggling AI buffer.
  - No regressions in model switching or backend switching commands.
  - Cached API keys are respected.

---

** TODO [#B] Decent HTML Exports From Org Mode With Inline CSS :enhancement:
*** fniessen/org-html-themes: Org mode files transformed into stunning HTML documents
[[https://github.com/fniessen/org-html-themes?tab=readme-ov-file#using-a-theme][fniessen/org-html-themes: Transform your Org mode files into stunning HTML documents in minutes with our Org mode HTML theme. Elevate your productivity and impress your readers! #orgmode #html #theme #productivity #design]]
Captured On: [2025-08-18 Mon 14:36]
** TODO [#B] Dirvish/File Manager Fixes/Enhancements           :maintenance:
*** DOING [#B] Test all dwim-shell-commands                    :enhancement:
This way you can also have test assets
**** Test Status for Commands
- [X] convert-audio-to-mp3 ()
- [X] convert-audio-to-opus ()
- [ ] view-image-exif-metadata ()
- [ ] flip-image-horizontally ()
- [ ] flip-image-vertically ()
- [ ] convert-image-to ()
- [ ] convert-svg-to-png ()
- [ ] join-images-into-pdf ()
- [ ] extract-pdf-page-number ()
- [ ] ocr-text-from-image-using-tesseract ()
- [ ] convert-video-to-webp ()
- [ ] convert-video-to-high-compatibility-mp4 ()
- [ ] convert-video-to-hevc-mkv ()
- [ ] extract-archive-smartly ()
- [ ] zip-file-or-directory ()
- [ ] tar-gzip-file-or-directory ()
- [ ] epub-to-org ()
- [ ] document-to-pdf ()
- [ ] pdf-to-txt ()
- [ ] resize-image-by-factor ()
- [ ] resize-image-in-pixels ()
- [ ] pdf-password-protect ()
- [ ] pdf-password-unprotect ()
- [ ] video-trim ()
- [ ] drop-audio-from-video ()
- [ ] open-externally ()
- [ ] git-clone-clipboard-url ()
- [X] open-file-manager ()
- [ ] count-words-lines ()
- [ ] checksum ()
- [ ] backup-with-timestamp ()
- [ ] optimize-image-for-web ()
- [ ] csv-to-json ()
- [ ] json-to-yaml ()
- [ ] extract-urls-from-file ()
- [ ] extract-emails-from-file ()
- [ ] create-gif-from-video ()
- [ ] concatenate-videos ()
- [ ] create-video-thumbnail ()
- [ ] merge-pdfs ()
- [ ] split-pdf-by-pages ()
- [ ] compress-pdf ()
- [ ] ascii-art ()
- [ ] text-to-speech ()
- [ ] remove-empty-directories ()
- [ ] create-thumbnail-from-image ()
- [ ] extract-audio-from-video ()
- [ ] normalize-audio-volume ()
- [ ] remove-zip-encryption ()
- [ ] create-encrypted-zip ()
- [ ] list-archive-contents ()
- [ ] count-words-lines-in-text-file ()
- [ ] make-executable ()
- [ ] secure-delete ()
- [ ] sanitize-filename ()
- [ ] number-files-sequentially ()
- [ ] git-history ()
- [ ] encrypt-with-gpg ()
- [ ] decrypt-with-gpg ()
- [ ] kill-gpg-agent ()
**** Reference
https://github.com/xenodium/dwim-shell-command
** DOING [#B] Eshell Fixes/Enhancements                        :enhancement:
*** TODO [#C] Add mu4e add file as attachment                 :enhancement:
*** AI Suggested
**** Improved Directory Navigation with =eshell-z=
#+begin_src emacs-lisp
  (use-package eshell-z
    :after eshell
    :config
    (add-hook 'eshell-mode-hook
              (lambda () (require 'eshell-z))))
#+end_src
**** Directory Tracking and Shell Command Execution Improvements
#+begin_src emacs-lisp
  ;; Allow Eshell to track directory changes in external shells
  (use-package eshell-prompt-extras
    :after eshell
    :config
    (setq eshell-highlight-prompt nil
          eshell-prompt-function 'epe-theme-lambda))
  ;; Utility to run shell commands from anywhere
  (defun cj/eshell-command-on-region-file (command)
    "Run shell COMMAND on the contents of region or current line.
  If region is active, use that, otherwise use the current line."
    (interactive (list (read-shell-command "Shell command on region: ")))
    (let* ((text (if (use-region-p)
                     (buffer-substring-no-properties (region-beginning) (region-end))
                   (buffer-substring-no-properties (line-beginning-position) (line-end-position))))
           (temp-file (make-temp-file "eshell-cmd-"))
           (output-buffer (generate-new-buffer "*Shell Command Output*")))
      (with-temp-file temp-file
        (insert text))
      (with-current-buffer output-buffer
        (insert (shell-command-to-string (format "%s %s" command temp-file)))
        (pop-to-buffer output-buffer))
      (delete-file temp-file)))
  (global-set-key (kbd "C-c !") 'cj/eshell-command-on-region-file)
#+end_src
**** Enhanced Visual Output and ANSI Colors
#+begin_src emacs-lisp
  ;; Better handling of visual commands
  (defun cj/eshell-exec-visual-and-kill ()
    "Execute the command via `eshell-exec-visual' and then kill the eshell buffer."
    (interactive)
    (let ((command (buffer-substring-no-properties
                    eshell-last-output-end (point-max))))
      (kill-buffer)
      (eshell-exec-visual command)))
  ;; Add this to your eshell aliases
  (add-hook 'eshell-mode-hook
            (lambda ()
              (eshell/alias "vk" 'cj/eshell-exec-visual-and-kill)))
#+end_src
**** Buffer Management and Layout Improvements
#+begin_src emacs-lisp
  ;; Auto rename eshell buffers based on current directory
  (defun cj/eshell-rename-buffer-as-dir ()
    "Rename the eshell buffer to include the current directory."
    (let ((dir (abbreviate-file-name (eshell/pwd))))
      (rename-buffer (format "*eshell: %s*" dir) t)))
  (add-hook 'eshell-directory-change-hook 'cj/eshell-rename-buffer-as-dir)
  ;; Split eshell in a sensible way based on window size
  (defun cj/eshell-pop-window ()
    "Open eshell in a sensible way depending on window dimensions."
    (interactive)
    (let ((width-percentage 0.3)
          (height-percentage 0.3)
          (current-window-width (window-width))
          (current-window-height (window-height)))
      (if (> current-window-width (* 2 current-window-height))
          ;; For wide windows, split side by side
          (let ((width (floor (* current-window-width width-percentage))))
            (split-window-horizontally (- current-window-width width))
            (other-window 1)
            (eshell))
        ;; For tall windows, split top/bottom
        (let ((height (floor (* current-window-height height-percentage))))
          (split-window-vertically (- current-window-height height))
          (other-window 1)
          (eshell)))))
  (global-set-key (kbd "C-c e") 'cj/eshell-pop-window)
#+end_src
**** Useful Utility Functions
#+begin_src emacs-lisp
  ;; Enhanced eshell clear that preserves history
  (defun cj/eshell-clear-buffer ()
    "Clear the eshell buffer, preserving the prompt and history."
    (interactive)
    (let ((inhibit-read-only t))
      (erase-buffer)
      (eshell-send-input)))
  (add-hook 'eshell-mode-hook
            (lambda () (local-set-key (kbd "C-l") 'cj/eshell-clear-buffer)))
  ;; Function to insert the output of elisp expressions into eshell
  (defun cj/eshell-insert-elisp-output (elisp)
    "Evaluate ELISP expression and insert its value at point in eshell."
    (interactive "sEval Elisp: ")
    (let ((result (eval (read elisp))))
      (insert (if (stringp result)
                  result
                (format "%S" result)))))
  (add-hook 'eshell-mode-hook
            (lambda () (local-set-key (kbd "C-c C-e") 'cj/eshell-insert-elisp-output)))
  ;; Quick file manager in eshell
  (defun eshell/fman (file)
    "Open FILE in a file manager."
    (cond
     ((eq system-type 'darwin)    (shell-command (format "open %s" (expand-file-name default-directory))))
     ((eq system-type 'gnu/linux) (shell-command (format "xdg-open %s" (expand-file-name default-directory))))))
  ;; Enhanced cd command that respects projects
  (defun eshell/pcd ()
    "Change directory to the project root."
    (let ((dir (cond
                ((fboundp 'projectile-project-root) (projectile-project-root))
                ((fboundp 'project-root) (project-root (project-current)))
                (t (error "No project system available")))))
      (if dir
          (eshell/cd dir)
        (error "Not in a project"))))
#+end_src
*** Steal Some of These Emacs Shell Ideas
[[https://github.com/howardabrams/hamacs/blob/main/ha-eshell.org#ebb-and-flow-output-to-emacs-buffers][hamacs/ha-eshell.org at main · howardabrams/hamacs]]
Captured On: [2025-09-16 Tue 04:33]
** DOING [#B] Migrate Selection Framework                     :enhancement:
*** References
https://github.com/minad/consult/wiki/Auxiliary-packages
https://www.reddit.com/r/emacs/comments/1aguy8g/how_to_get_consultripgrep_to_remember_previous/
*** Auxiliary Packages to Explore
https://gitlab.com/OlMon/consult-flyspell
https://github.com/ghosty141/consult-git-log-grep
https://github.com/minad/affe
*** Manual Testing
Here's a comprehensive test checklist we should verify after migration:
**** Core Functionality Tests
- [ ] =M-x= (execute-extended-command) with rich annotations
- [ ] =C-x C-f= (find-file) with file preview
- [ ] =C-x b= (switch-to-buffer) with buffer annotations
- [ ] =C-s= (isearch) replacement with consult-line
- [ ] =C-h f= (helpful-callable) with completing-read
- [ ] =C-h v= (helpful-variable) with completing-read
**** Project/File Navigation Tests
- [ ] =C-c p f= (projectile-find-file)
- [ ] =C-c p p= (projectile-switch-project)
- [ ] =C-c p G= (projectile-ripgrep)
- [ ] Recent files access
- [ ] Bookmarks
**** Window/Buffer Management Tests
- [ ] =M-V= (cj/split-and-follow-right) - buffer selection in new window
- [ ] =M-H= (cj/split-and-follow-below) - buffer selection in new window
- [ ] Kill-ring browsing
- [ ] Imenu navigation
**** Integration Tests
- [ ] =C-c s i= (ivy-yasnippet → consult-yasnippet)
- [ ] Git timemachine revision selection
- [ ] Helpful integration (counsel-describe-/ functions)
- [ ] Projectile integration
**** Search/Replace Tests
- [ ] In-buffer search
- [ ] Project-wide search
- [ ] Search with preview
- [ ] Occur-like functionality
*** Mu4e - Save All Attachments Testing
It's pretty easy if you use vertico + embark.
After running mu4e-view-save-attachments,
- invoke embark-act-all in the completion menu
- followed by RET (mu4e-view-save-attachments) to save all attachments,
- or TAB (vertico-insert) followed by (comma) next to each file you want to save,
- then RET (vertico-exit), to save selected attachments.
** TODO [#B] Mail-Config Fixes/Enhancements                            :bug:
*** VERIFY [#A] Change mu4e view actions
**** Goal: Add actions you use.
the defaults are currently
#+begin_src emacs-lisp
  (("capture message" . mu4e-action-capture-message)
   ("view in browser" . mu4e-action-view-in-browser)
   ("browse online archive" . mu4e-action-browse-list-archive)
   ("xview in xwidget" . mu4e-action-view-in-xwidget)
   ("show this thread" . mu4e-action-show-thread)
   ("org-contact-add" . mu4e-action-add-org-contact))
  ;;  Original value was
  (("capture message" . mu4e-action-capture-message)
   ("view in browser" . mu4e-action-view-in-browser)
   ("browse online archive" . mu4e-action-browse-list-archive)
   ("xview in xwidget" . mu4e-action-view-in-xwidget)
   ("show this thread" . mu4e-action-show-thread))
#+end_src
The only ones I use are:
#+begin_src emacs-lisp
  ("view in browser" . mu4e-action-view-in-browser)
  ("capture message" . mu4e-action-capture-message)
  ("org-contact-add" . mu4e-action-add-org-contact)
#+end_src
and I would like to add one for save-attachment(s)

** TODO [#B] Org Agenda Work                                  :enhancement:
*** TODO [#B] In progress tasks (i.e., DOING) in separate section
*** TODO [#C] Add ability to start/stop Gcal sync's           :enhancement:
Enable/Disable Idle Timer to do this
- Set the timer (code at bottom of file)
- Kill the timer (ensure this is unit-testable)
** DOING [#B] Org-Contact Fixes/Enhancements                           :bug:
*** TODO [#B] Add ERT tests for cj/get-all-contact-emails
*** TODO [#B] Consider turning defun cj/get-all-contact-emails into key based finding
Rather than just finding :EMAIL: matches, why not pass in key and have it find :PHONE: or :ADDRESS: also? 
*** TODO [#B] Finding Contact should only match Org Header text
*** TODO [#B] Viewing Contacts should just bring up main contacts org file, not table
*** Manual Tests
- [X] Complete addresses with org-contact in to, cc, bcc
- [ ] Complete addresses with new org-contact in to, cc, bcc
- [ ] Complete with forwards/replies in to, cc, bcc
- [ ] Add contact from mail (with new native mu4e function)
- [ ] Create contact via org-contacts capture template "C"
- [ ] Insert a contact in any buffer via keymap C-c C i
- [ ] Add a new contact from anywhere via keymap C-c C n
- [ ] Look up a contact from anywhere via keymap C-c C f
- [ ] View all contacts from anywhere via keymap C-c C v
- [X] Verify birthdays showing on agenda
- [ ] Verify birthdays showing on agenda after adding new contact
- [ ] Link a contact to an org-roam node (cj/org-contacts-link-to-roam)
*** TODO [#C] Finish Org-Contacts/Mail Modules                 :maintenance:
** DOING [#B] Org Roam Fixes/Enhancements                      :enhancement:
*** TODO [#B] New Org-Roam type: Book Notes
Part of the integration with org-noter
** TODO [#B] Describe and Implement Personal Workflow Project Actions
What other actions do I do in a project?
*** TODO [#B] Rename and save any file to project/assets directory
use case:
- I receive a load of files in google-drive/dropbox share or email attachments.
- They all belong to a project
- Projects are structured with an assets or data folder (decide which one first)
- I select the file in dirvish and hit a key,
- It brings up completing read for the projects
- After choosing one, it moves selected files into the proper assets/data folder
*** TODO [#B] Override archiving a task to a project archive
use case:
- C-x a archives to a central archive.org file.
- If I'm in a projectile/project.el project it overrides the destination to an resolved.org file
- if the resolved.org file doesn't exist, it creates it.
- If not in a projectile/project.el project, it falls back to the archive.org file. 
** WAITING [#C] Fix Org-msg Issue With Undo Outside                   :bug:
*** 2025-09-19 Fri @ 17:45:35 -0500 Submitted PR Waiting for Merge
https://github.com/jeremy-compostella/org-msg/pull/213
*** 2025-09-19 Fri @ 16:11:02 -0500 Fix in a PR with description.
ROOT CAUSE
On line 1556, in org-msg-edit-mode reads:
```
  (add-hook 'message-sent-hook 'undo t t)
```  
https://github.com/jeremy-compostella/org-msg/blob/59e2042e5f23e25f31c6aef0db1e70c6f54f117d/org-msg.el#L1556

When sending messages that extend past the visible space, org-msg prepares the content and may narrow the buffer. When the message-sent-hook fires in a narrowed buffer, calling undo errors when attempting to undo changes recorded outside the visible restriction.

PROPOSED FIX
- Replace the raw undo hook with a helper which widens before performing the undo. Add that helper to message-send-hook based on the value of message-kill-buffer-on-exit.
This way: 
- If message-kill-buffer-on-exit is t, there’s no need to restore the buffer as it will be killed right after the hooks. No undo → no error → no need to widen.
- If the buffer won’t be killed, we DO need to restore it, therefore we widen first and then perform the undo.

ALTERNATIVES REJECTED
- Removing undo entirely. This fixes the error, but was rejected as it changes org-msg's behavior for users who keep the buffer open post-send.
- Saving/restoring the original buffer text explicitly. Rejected because this felt more invasive and might risk clobbering other transient state.
- Always add the hook to widen before performing the undo. Rejected to avoid executing more code than necessary. 

*** 2025-09-19 Fri @ 15:08:46 -0500 Tested workaround and posting it
#+begin_src emacs-lisp
(with-eval-after-load 'org-msg
  (add-hook 'org-msg-edit-mode-hook
            (lambda ()
              (remove-hook 'message-sent-hook 'undo t))))
#+end_src
*** 2025-09-19 Fri @ 14:59:48 -0500 Current Status
The bug I filed after tracking the issue down:
https://github.com/jeremy-compostella/org-msg/issues/210

First, thanks for conttributing this package. It's made email via Mu4E in Emacs possible for me and others.

Description
When sending long emails using org-msg, an error occurs after the message is successfully sent: "primitive-undo: Changes to be undone are outside visible portion of buffer". The email is sent successfully, but the compose buffer remains open in a mixed text+html state along with other buffers, instead of everything being closed as expected.

Environment
Emacs version: 30.1
org-msg version: 20240902.447
Mail client: mu4e
OS: Linux, though I'd be surprised if it doesn't reproduce everywhere.
Reproduction Steps
Compose a new email with org-msg enabled
Write a long email (content must exceed the visible window)
Send the email with C-c C-c
Error occurs after successful send
Root Cause
The issue is in org-msg.el at line 1747 in the org-msg-edit-mode definition:

(add-hook 'message-sent-hook 'undo t t)
During the sending process:

org-msg-prepare-to-send processes the buffer and converts Org content to HTML/text
This processing narrows the buffer (confirmed by debugging)
After sending, message-sent-hook runs while the buffer is still narrowed
The undo function fails because it tries to undo changes outside the narrowed region
I'll work on this and hope to propose a fairly well tested fix soon.
** TODO [#C] Miscellaneous Maintenance
*** TODO [#C] Move persistence and history files into subdir   :enhancement:
*** DOING [#B] Implement Performance Recommendations                   :bug:
**** Lazy-load configuration modules                      :complex4:impact5:
Loading every module with `require` forces all code and packages to initialize during startup. Switching to `use-package` with `:defer` or `:commands` loads modules only when their functionality is invoked, greatly reducing startup time.
#+begin_src emacs-lisp
  (use-package dirvish-config
    :load-path "modules"
    :commands (dirvish dirvish-side))
#+end_src
**** DONE Defer Dashboard initialization                  :complex2:impact4:
CLOSED: [2025-09-08 Mon 14:09]
The dashboard package is loaded eagerly via `:demand`, adding a noticeable delay. Load it after startup and open it on the first idle event instead.
#+begin_src emacs-lisp
  (use-package dashboard
    :defer t
    :hook (emacs-startup . dashboard-open))
#+end_src
**** CANCELLED Replace synchronous network ping with non-blocking check :complex3:impact2:
CLOSED: [2025-09-08 Mon 16:07]
- State "CANCELLED"  from              [2025-09-08 Mon 16:07]
`internet-up-p` spawns a blocking `ping` process at startup. Using `make-network-process` avoids shelling out and lets the check run asynchronously.
#+begin_src emacs-lisp
  (defun internet-up-p (&optional host)
    "Non-blocking network availability check."
    (make-network-process
     :name "net-check" :host (or host "www.google.com") :service 80
     :sentinel (lambda (proc _)
                 (setq cj/network-available (eq (process-status proc) 'open))
                 (delete-process proc))))
#+end_src

This actually added 15 seconds to the launch time.
**** Postpone package refreshing to idle time             :complex1:impact3:
Refreshing ELPA archives during startup adds I/O overhead. Defer this check to an idle timer so it runs after Emacs is ready.
#+begin_src emacs-lisp
  (add-hook 'emacs-startup-hook
            (lambda () (run-with-idle-timer 60 nil #'package-refresh-contents)))
#+end_src

**** Enable package quickstart caching                    :complex1:impact2:
Precomputing autoloads with package quickstart reduces the cost of loading package code.
#+begin_src emacs-lisp
  (setq package-quickstart t)
  (package-quickstart-refresh)
#+end_src

**** Byte-compile configuration files                     :complex1:impact2:
Byte-compiled Emacs Lisp loads faster than source. Recompile the configuration directory when changes are made.
#+begin_src emacs-lisp
  (byte-recompile-directory user-emacs-directory 0)
#+end_src

**** Manage garbage collection with GCMH                  :complex1:impact2:
After startup, `gcmh` dynamically adjusts GC thresholds to minimize pauses without manual tuning.
#+begin_src emacs-lisp
  (use-package gcmh
    :hook (after-init . gcmh-mode)
    :config
    (setq gcmh-idle-delay 5
          gcmh-high-cons-threshold (* 16 1024 1024)))
#+end_src

**** DONE Load Dirvish on demand                          :complex2:impact3:
CLOSED: [2025-09-13 Sat 20:56]
`dirvish-config` requires Dirvish during initialization, negating deferral. Let `use-package` autoload the commands and enable overrides when Dired loads.
#+begin_src emacs-lisp
  (use-package dirvish
    :commands (dirvish dirvish-side)
    :hook (dired-mode . dirvish-override-dired-mode))
#+end_src

**** DONE Start Org-roam lazily                           :complex3:impact3:
CLOSED: [2025-09-08 Mon 16:10]
Org-roam and its database sync run at startup. Load Org-roam only when Org is active, and start autosync after initialization.
#+begin_src emacs-lisp
  (use-package org-roam
    :after org
    :commands (org-roam-node-find org-roam-node-insert)
    :hook (after-init . org-roam-db-autosync-mode))
#+end_src

*** DOING [#C] Fix all docstring and elisp linting issues              :bug:
- [X] user-constants
- [X] host-environment
- [ ] config-utilities
- [ ] system-defaults
- [ ] keybindings
- [ ] auth-config
- [ ] custom-functions
- [ ] chrono-tools
- [ ] file-config
- [ ] keyboard-macros
- [ ] system-utils
- [ ] text-config
- [ ] undead-buffers
- [ ] ui-config
- [ ] ui-theme
- [ ] ui-navigation
- [ ] font-config
- [ ] diff-config
- [ ] eshell-vterm-config
- [ ] flyspell-and-abbrev
- [ ] help-utils
- [ ] help-config
- [ ] latex-config
- [ ] modeline-config
- [ ] pdf-config
- [ ] selection-framework
- [ ] tramp-config
- [ ] show-kill-ring
- [ ] calibredb-epub-config
- [ ] dashboard-config
- [ ] dirvish-config
- [ ] dwim-shell-config
- [ ] elfeed-config
- [ ] erc-config
- [ ] eww-config
- [ ] httpd-config
- [ ] mail-config
- [ ] markdown-config
- [ ] weather-config
- [ ] prog-general
- [ ] vc-config
- [ ] flycheck-config
- [ ] prog-lsp
- [ ] prog-training
- [ ] prog-c
- [ ] prog-go
- [ ] prog-lisp
- [ ] prog-shell
- [ ] prog-python
- [ ] prog-webdev
- [ ] prog-yaml
- [ ] org-config
- [ ] org-agenda-config
- [ ] org-babel-config
- [ ] org-capture-config
- [ ] org-refile-config
- [ ] org-drill-config
- [ ] org-export-config
- [ ] org-roam-config
- [ ] org-contacts-config
- [ ] ai-config
- [ ] reconcile-open-repos
- [ ] video-audio-recording
- [ ] local-repository
- [ ] eradio-config
- [ ] games-config
- [ ] wrap-up

** TODO [#C] Git Timemachine Litters Empty Buffers                    :bug:
Don't choose a revision and you'll see a blank buffer that needs to be killed
* Emacs Config Next Release: 0.9
** DOING [#A] Jumper Package                                   :enhancement:
*** Specification
**** variable:custom: jumper-max-locations
maximum number of locations to store: default 10
**** variable:internal: jumper--registers
vector of used registers:
(make-register jumper-max-locations nil)
**** variable:internal: jumper--last-location-register
register used to store the last location: ?z
**** method:internal: jumper--point-matches-register
#+begin_src emacs-lisp
  ;; First store a position in register 'a'
  (point-to-register ?a)
  ;; Later, check if current position matches what's in register 'a'
  (if (cj/point-matches-register ?a)
      (message "Current position matches register 'a'")
    (message "Current position differs from register 'a'"))
  (defun cj/point-matches-register (register)
    "Return t if current position matches position stored in REGISTER.
      REGISTER is a character representing the register to check against.
      Returns nil if the register doesn't exist or doesn't contain position information."
    (let ((reg-val (get-register register)))
      (when (and reg-val
                 (markerp reg-val)
                 (marker-buffer reg-val)
                 (eq (current-buffer) (marker-buffer reg-val))
                 (= (point) (marker-position reg-val)))
        t)))
#+end_src
**** method:
**** method: save-last-position
saves location to register z: (point-to-register ?z)
**** method: save-to-next-register
gets next free register in the sequence
calls (save-last-position)
saves using (point-to-register REGISTER &optional ARG)
*** 2025-09-02 Tue @ 14:06:03 -0500 Functionality Description
Tentative Package Name: Jumper
I typically use registers to jump between places, but I often forget the keybindings. Also, I sometimes overwrite registers by hitting the wrong key. Many Emacs users  don't even know about registers. I've seen posts from software developers asking how to conveniently store and jump to specific locations in a large code base.
To solve this I'd like to write a little elisp package that leverages Emacs vanilla register functionality to make jumping between locations using registers simple and transparent. The user won't have to think about registers or what character they've stored their location in at all. All keybindings will be based on keys from home row of the keyboard.
Preliminaries:
We will map the functionality to the keybinding prefix C-; j, but the prefix should be easy to configure.
Let's imagine a set of characters in a sequence. They could be any characters, but for the sake of simplicity we'll use the numbers from 0 to 9, and a one more character used for the "last location" -- the character "z".
What follows is a description of the workflow:
**** Adding Locations
keybinding: <prefix> space (store destination)
If the user is visiting a buffer and presses <prefix> space,
- the current location is stored in the next free register. if this is the first time they are storing a location, the first free register is 0.
user feedback: a message is displayed in the echo area saying "location stored."
If the user stays on the same location and presses prefix <space> again, they should receive a message in the echo area saying the location is already stored, and no changes to the register is made.
If the user moves to a new location and presses prefix <space> again, the next free register is used to store the location, in this case it would be 1. They can then iterate and store additional locations up to the last character in the sequence up to the limit of 10 registers (0 through 9). If they try to store a register after all 10 registers are filled, they will receive a message ("sorry - all jump locations are filled!").
**** Jump-To A Location
keybinding: <prefix> j (jump to destination)
NOTE: Whenever the user presses <prefix> j, that location is automatically stored in the "last location" register z.
***** When only one location is stored, and the user presses <prefix> j:
If there is only one location stored, the user IS at the location, and they press <prefix> j, they see an echo area message "you're already at the stored location."
If there is only one location stored in the sequence, and the user is NOT at that location, their location is stored in register z, then the user is immediately to their destination location via (jump-to-register).
user feedback: a message is displayed in the echo area saying "jumped to location."
If the user presses <prefix> J again, they are automatically taken back to the location in register z. and the same user feedback message is displayed.
In other words, after the user stores one location and moves elsewhere, pressing <prefix> j will jump back and forth between the two places.
***** When multiple locations are stored, and the user presses <prefix> j:
A completing read is displayed with all the locations between 0 and 9 along with register z (their last location) at the bottom.
Each line contains the letter as well as the content that the register would normally display. In other words, it could just be the register list is displayed, but narrowed down to 0 - 9 and z.
When the user chooses a location 0 -9, z from completing read:
- The current location is stored in register z, replacing their last location
- They are taken to the location via (jump-to-register).
user feedback: a message is displayed in the echo area saying "jumped to location."
**** Removing Locations
keybinding: <prefix> d
A completing read is displayed with the first item (where the cursor is on) being "Cancel".
The rest of the registers are displayed in descending order, i.e., from 9 to 0.
Note: the z register is not displayed.
Selecting a register from the list:
- removes that item from the list, and removes the location stored in the register.
- if the item is NOT the top one in the register, it reorders the rest of the sequence
  in other words, if 0 - 9 are all stored, and:
  the user removes item 7:
  - location 8 is restored in 7
  - location 9 is stored in 8
  the user removes item 0
  - location 1 is stored in 0
  - location 2 is stored in 1
  - location 3 is stored in 2
  - location 4 is stored in 3
  - location 5 is stored in 4
  - location 6 is stored in 5
  - location 7 is stored in 6
  - location 8 is stored in 7
  - location 9 is stored in 8
user feedback: a message is displayed in the echo area saying "location removed."
**** Open Questions
- Are there buffers which the user should not be able to store in a register?
- How can we prevent the user from creating issues by adding to the registers 0 through 9 by M-x point-to-register or it's keybinding? Is there a way to block or reserve those registers? Or is it better to just choose a sequence that is the least likely to be used by a human user? If so, what would that sequence be?
- Is 10 registers enough for a normal developer?
- I should probably
- Can I use a vector/list internally and map to registers behind the scenes?
Depending on context, can I add the
- Function name at point
- File name + line number
- First few words of the line
Do we think the reordering behavior when deleting locations might confuse users? How to simplify?
What happens if a buffer is deleted that doesn't have a file associated with it? If we're using registers underneath, how do registers handle this?
** TODO [#B] Get Tufte.css working and as a separate entry
Below is one way to get Org-mode’s HTML exporter to play nicely with Tufte-CSS.  The basic recipe is:
1. Inject Tufte’s stylesheet into every HTML export
2. Teach Org to emit the little “margin-toggle” + “sidenote” markup that tufte.css expects for footnotes
3. (Optionally) wrap images in <figure> so you get tufte-style captions out of the box
Along the way you’ll see where Org’s default HTML‐classes line up with tufte.css and where you have to override them.
— 1 Inject tufte.css into your exports
Put tufte.css somewhere your exported HTML can see it (for example
~/.emacs.d/assets/tufte.css or a URL on your webserver).  Then in your init.el:
(with-eval-after-load 'ox-html
;; 1a) tell Org to link in your tufte.css
(setq org-html-head-extra
"<link rel=\"stylesheet\" href=\"/assets/tufte.css\" type=\"text/css\"/>")
;; 1b) enable HTML5 “fancy” output (so you get <figure> around images)
(setq org-html-html5-fancy t
org-html-inline-images  t))
— 2 Turn Org footnotes into Tufte sidenotes
By default Org emits
<sup class=…><a href="#fn:1" id="fnref:1">[1]</a></sup>
…and then a big =<div id="footnotes">= at the bottom.
Tufte-CSS wants each footnote inline, wrapped in
<label class="margin-toggle">⊕</label>
<input type="checkbox" class="margin-toggle"/>
<span class="sidenote">…your note…</span>
We can override two Org variables:
(with-eval-after-load 'ox-html
;; format of each inline footnote reference
(setq org-html-footnote-format
(concat
"<label for=\"%1$s\" class=\"margin-toggle\">"
"&#8853;</label>"
"<input type=\"checkbox\" id=\"%1$s\" class=\"margin-toggle\"/>"
"<span class=\"sidenote\">%2$s</span>"))
;; drop Org’s default footnote list at the end
(setq org-html-footnote-separator ""))
Once you do that, exporting an Org file with footnotes will generate the markup tufte.css needs to float them in the margin.
— 3 (Optionally) get <figure> + <figcaption> around images
If you set =org-html-html5-fancy= to t (see step 1) Org will automatically emit:
<figure>
<img src="…"/>
<figcaption>Your caption</figcaption>
</figure>
and tufte.css already has rules for =<figure class="figure">= etc.
— 4 Common pitfalls
• Make sure your href in =org-html-head-extra= actually points to the css that the browser can load (absolute vs. relative).
• If you still see a “Footnotes” section at the bottom, double-check that =org-html-footnote-separator= is set to the empty string and that your init-file got re-evaluated.
• On Windows or if you’re testing locally, run e.g. =python3 -m http.server= inside your export folder so your browser can fetch the CSS.
— 5 Unit test for your footnote hack
Drop this in =~/.emacs.d/tests/test-org-tufte.el= and run =M-x ert RET t RET=:
(require 'ert)
;; load your config; adjust the path if necessary
(load-file "~/.emacs.d/init.el")
(ert-deftest org-tufte-footnote-format-test ()
"Ensure each footnote reference becomes a margin-toggle + sidenote."
(let/ ((id      "fn:42")
(content "My note.")
(html    (format org-html-footnote-format id content)))
(should (string-match-p "class=\"margin-toggle\"" html))
(should (string-match-p "<span class=\"sidenote\">My note\\.</span>" html))
;; it must not accidentally reintroduce Org’s bottom-of-page footnote div
(should-not (string-match-p "div id=\"footnotes\"" html))))
Once that test passes, you know your footnotes are being rewritten into Tufte-style side notes.  From there, you can sprinkle in additional filters (e.g. wrap =<blockquote>= in a =.sidenote= class, override list/p table styles, etc.) or just let the rest of tufte.css style Org’s default tags (h1, p, ul, table, code, etc.).
Enjoy your beautifully-typeset Org → HTML exports in true Tufte style!
** TODO [#C] Review Titlecase Functionality
added in custom. Came from: https://codeberg.org/acdw/titlecase.el
Originally seen at https://emacselements.com/true-titlecase-in-emacs.html
** TODO [#C] Revisit and Refactor Localrepo Functionality
** TODO [#C] Fix Exporting Documents to HTML.
This appears to work with emacs -q. What's up with your config?
** TODO [#C] Rename 'sync-dir' Variable in Init File to 'org-dir'
[[https://github.com/ryuslash/mode-icons][ryuslash/mode-icons: Show icons instead of mode names]]
Captured On: [2025-06-07 Sat 13:29]
** TODO [#C] Emacs Change Appropriate Use-package Installs to :vc
especially where you're cloning them to provide fixes
** TODO [#C] Emacs Config: Narrowing Org doesn't allow refresh by type
After generating an org agenda list, I can narrow the type to all DONE or IN-PROGRESS. However when I use my custom functions to just get the agenda for the current buffer, I can't. The scope has now widened and the refresh is for all buffers.
** TODO [#C] Add a Restrict to Subtree Org Agenda Command
In Org-mode the “agenda” machinery by default doesn’t pay any attention to your buffer­narrow — it always scans whole files in your =org-agenda-files=.  However, you can teach Org-agenda to only look between two points (the start and end of your current subtree) by using the built-in “restrict” hooks:
1.  =org‐agenda‐restrict=         – turn on restriction
2.  =org‐agenda‐restrict‐begin=  – a marker or position where scanning begins
3.  =org‐agenda‐restrict‐end=    – where it ends
4.  (optionally) set =org-agenda-files= to just your current file
Here is a drop-in =org-agenda-custom-commands= entry that will give you a “Subtree TODOs” view limited to the subtree you’re on.  Put this in your Emacs init:
#+begin_src  emacs-lisp
  ;; -------------------------------------------------------------------
  ;; 1) Define a custom agenda command "C" (hit C-c a C)
  ;;    that shows only TODO entries in the current subtree.
  ;; -------------------------------------------------------------------
  (with-eval-after-load 'org
    (add-to-list 'org-agenda-custom-commands
                 '("C"                                ; the key you press after C-c a
                   "Subtree TODOs"                   ; a descriptive name
                   ((todo ""                         ; match any TODO keyword
                          ;; === per-block settings ===
                          ;; only look in this file
                          (org-agenda-files (list buffer-file-name))
                          ;; enable the restriction engine
                          (org-agenda-restrict t)
                          ;; start at the top of the current heading
                          (org-agenda-restrict-begin
                           (progn (org-back-to-heading t) (point)))
                          ;; end at the end of this subtree
                          (org-agenda-restrict-end
                           (progn (org-end-of-subtree t) (point))))
                    ;; you can add more blocks here if you like
                    ))))
#+end_src
How this works, step by step:
• We bind a new custom command under the key “C” (so you’ll type =C-c a C=).
• In that command we use the =todo= matcher =""= to catch every headline whose state is one of your TODO keywords.
• We dynamically set
– =org-agenda-files= to just the current buffer’s file,
– =org-agenda-restrict= to non-nil so Org will honor the begin/end markers,
– =org-agenda-restrict-begin= to the position of the current heading,
– =org-agenda-restrict-end= to the end of the subtree.
When you invoke it (=C-c a C=), Org will only scan headlines in that slice of the file and will build you a mini-agenda of TODO items from exactly that subtree.
Quick alternative: if you don’t need the full agenda machinery (dates, deadlines, etc.) but just want a fast outline of your TODOs under the current heading, you can also use the sparse-tree command:
• =C-c / t=  ⇒ shows only the TODO headings in the narrowed or whole buffer as an indented outline.
— Tips & Pitfalls —
• Make sure your file is saved and in =org-agenda-files= (the snippet above forces it).
• Remember to call =org-narrow-to-subtree= (or let the command compute its own begin/end via =org-back-to-heading=/=org-end-of-subtree=).
• If you rename or move your file, Emacs must still see =buffer-file-name= valid.
• You can duplicate the above snippet for other TODO states, agenda views, or matchers (deadlines, tags, etc.)
With this in place you effectively get an agenda tailored to exactly the bit of tree you’re working on.
** TODO [#C] Find Another Keymapping for Emojify
** TODO [#D] Emacs: org project should be yellow or green like todo
** TODO [#D] Emacs Signal Client
*** TODO investigate: net/signel.org · master · undefined · GitLab
[[https://gitlab.com/jaor/elibs/-/blob/master/net/signel.org][net/signel.org · master · undefined · GitLab]]
Captured On: [2025-05-29 Thu 04:24]
*** TODO investigate: signel, a barebones signal chat on top of signal-cli
[[https://jao.io/blog/signel.html][signel, a barebones signal chat on top of signal-cli]]
Captured On: [2025-05-29 Thu 04:23]
** TODO [#D] Add test document to test graphviz-dot-mode
** TODO [#D] Consider Replicating Some of This Auctex and PDF Tools Code
[[https://www.reddit.com/r/emacs/comments/cd6fe2/how_to_make_emacs_a_latex_ide/][How to make Emacs a Latex IDE? : r/emacs]]
Captured On: [2025-08-14 Thu 03:43]
** TODO [#D] Install ZOxide Integration into Emacs
[[https://gitlab.com/Vonfry/zoxide.el][Vonfry / zoxide.el · GitLab]]
Captured On: [2025-06-07 Sat 17:11]
** TODO [#D] manateelazycat/awesome-tray: Hide mode-line, display necessary information at right of minibuffer.
[[https://github.com/manateelazycat/awesome-tray][manateelazycat/awesome-tray: Hide mode-line, display necessary information at right of minibuffer.]]
Captured On: [2025-06-07 Sat 13:29]
** TODO [#D] ryuslash/mode-icons: Show icons instead of mode names
** TODO [#B] Get Dupre Theme Working                                   :bug:
*** AI Suggestioms
Here are some ideas for making dupre-theme a bit more “complete” and future-proof as an Emacs theme.  You don’t have to do all of them, of course, but most “modern” themes ship a fair number of these extra faces and integrations.
**** TODO [#A] Fill out the “standard” Emacs faces
• error / warning / success
• link / link-visited / shadow
• highlight / secondary-selection
• tooltip / tooltip-selection / tooltip-tip
• underline / strike-through
• match / search / lazy-highlight (you already have some isearch)
• info-title-1…info-title-5, info-header-node, help-*-face
**** TODO [#A] Cosmetic / code-style notes
• Factor out a helper macro to reduce repetition:
#+begin_src elisp
  (defmacro dupre-face (face &rest specs)
    `(,face ((t ,specs))))
#+end_src
• Use =custom-theme-set-faces= only once; wrap your =when (>= emacs-major-version…)= inside it rather than nesting top-level.
• Move your ERT tests into a separate file like =dupre-theme-test.el= so that the main theme file stays lean.
**** TODO [#B] Make sure you define a “minimum package” set of faces so that folks don’t see glaring unstyled text in any part of Emacs, even if they never install extra packages.
**** TODO [#B] Improve terminal support:
• Detect true-color (=(display-graphic-p)=) vs 256-color vs 16-color and fall-back gracefully.
• Provide “256-color” approximations (you already do this), but you might want a simpler palette for legacy terminals.
**** TODO [#B] Other Packages
The rest is just more of the same—pick the most common modes/packages you and your users rely on and give them a quick coat of paint.  Once you’ve rounded out those faces you’ll have hit what most people expect from a “complete” modern Emacs theme.
Based on a quick skim of your modules/ directory (and the packages they pull in via use-package), here’s a non-exhaustive list of the major packages you’re using—along with the faces you should think about adding to dupre-theme so that nothing ends up looking “unstyled.”
1. completion/mini-frameworks
   • vertico (vertico-current, vertico-group-title, vertico-separator, vertico-doc)
   • orderless (orderless-match-face-0…3)
   • consult (consult-preview-line, consult-narrow, consult-region, consult-file)
   • marginalia (marginalia-annotation, marginalia-document, marginalia-cache)
   • embark (embark-general, embark-heading, embark-target, embark-helpful)
   • corfu + cape (corfu-default, corfu-current, corfu-bar, cape-file, cape-keyword etc.)
   • company (company-tooltip, company-tooltip-selection, company-scrollbar­-thumb)
2. ivy/counsel/swiper (if you ever load them side-by-side)
   • ivy-current-match, ivy-minibuffer-match-face-1…4
   • counsel-outline, swiper-match-face-1…
3. syntax checkers & LSP
   • flycheck (flycheck-error, flycheck-warning, flycheck-info)
   • eglot or lsp-mode (lsp-face-highlight-textual, lsp-face-highlight-read, lsp-face-semantic-type-…)
   • tree-sitter (tree-sitter-hl-face:function, :variable, :property, …)
4. git & diffs
   • magit (magit-section, magit-section-title, magit-hunk-heading, magit-branch, magit-log)
   • diff-hl / git-gutter (diff-hl-face-insert, diff-hl-face-delete, git-gutter:added, git-gutter:deleted)
   • diff-mode (diff-added, diff-removed, diff-context, diff-file-header)
5. project management & navigation
   • projectile (projectile-project-name, projectile-project-root)
   • treemacs (treemacs-root-face, treemacs-directory-face, treemacs-file-face)
6. Org-mode
   • org-document-title, org-level-1…org-level-8
   • org-checkbox, org-todo, org-done, org-warning, org-date, org-code, org-block
   • plus any “pretty” add-ons you use (org-bullets, org-modern, etc.)
7. Hydra / which-key / key-help
   • which-key (which-key-key-face, which-key-group-description-face, which-key-local-map-description-face)
   • hydra (hydra-face-red, hydra-face-blue, hydra-face-teal, hydra-face-amaranth)
8. visual helpers
   • rainbow-delimiters-depth-1…9
   • highlight-indent-guides-odd/even
   • highlight-parentheses-/
   • beacon (beacon), whitespace (whitespace-space, whitespace-tab, whitespace-newline)
   • display-line-numbers (line-number, line-number-current-line—you already have these)
9. UI polishers
   • all-the-icons (all-the-icons-blue, all-the-icons-red, …) on modeline or treemacs
   • doom-modeline (doom-modeline-bar, doom-modeline-buffer-path)
   • fancy-splash/dashboard-faces if you use a startup screen
10. terminals & shells
    • vterm (vterm-copy-region-highlight)
    • ansi-colors (ansi-color-face-bold, ansi-color-face-italic, ansi-color-[0…7])
To figure out exactly which ones you have in your modules, you can do for example:
#+begin_src elisp
  ;; from your ~/.emacs.d
  (let (pkgs)
    (dolist (f (directory-files "~/.emacs.d/modules" t "\\.el$"))
      (with-temp-buffer
        (insert-file-contents f)
        (goto-char (point-min))
        (while (re-search-forward "use-package +\\([^ ]+\\)" nil t)
          (push (intern (match-string 1)) pkgs))))
    (delete-dups pkgs))
#+end_src
Then for each of those packages, grep in their repo for =defface= or check their manual to see which faces they define, and add reasonable dupre-colours for them. Once you’ve covered that list, you’ll have a “complete” theme that won’t leave any of your modules half-unstyled.
**** TODO [#C] Support the built-in “tab-bar” and “tab-group” faces (Emacs 27+)
• tab-bar              / tab-bar-tab / tab-bar-tab-inactive
• tab-bar-close        / tab-bar-separator
• tab-group-title      / tab-group-separator
**** TODO [#C] Add faces for =dired=, =diff=, =flycheck=/=flymake=, =magit= (or git-gutter),
=ediff=, =erc= etc.  For example:
• diff-added, diff-removed, diff-context, diff-file-header
• flycheck-error, flycheck-warning, flycheck-info
• magit-section, magit-log, magit-hunk-heading, magit-branch, etc.
**** TODO [#C] Org-mode
• org-level-1…org-level-8, org-document-title
• org-checkbox, org-code, org-date, org-todo, org-done, org-warning
• org-block, org-block-begin-line, org-block-end-line
**** TODO [#C] Completion frameworks & minibuffer enhancements
• ivy-current-match / ivy-minibuffer-match-face-1…4
• swiper-line-face
• vertico-current / marginalia-…
• corfu-default / corfu-bar / cape / orderless-match-face-…
**** TODO [#C] LSP / tree-sitter / syntax-aware faces
• lsp-face-highlight-textual, lsp-face-highlight-read, etc.
• tree-sitter-hl-face:variable, :function, :property, etc.
**** TODO [#C] Which-Key, Hydras, rainbow-delimiters, etc.
• which-key-key-face, which-key-local-map-description-face
• hydra-face-red / teal / blue
• rainbow-delimiters-depth-1…9
**** TODO [#C] Theme Metadata & Packaging
• Add =;; Package-Requires: ((emacs "26.1"))= if you need a minimum.
• Consider adding a README with screenshots.
• A simple Makefile or script to refresh “theme metadata” (=M-x theme-inspect=, MELPA recipe).
**** TODO [#C] Tests
• Extend your ERT suite to cover more faces (org, diff, flycheck…).
• You might write a small helper that loops over a list of faces and asserts they’re defined without errors.
**** Example Sample Faces
Below is a small excerpt showing how you might start adding some of the “missing” standard faces and a couple org faces:
#+begin_src elisp
  (custom-theme-set-faces
   'dupre
   ;; … your existing faces …
   ;; standard global faces
   `(error   ((t (:foreground ,dupre-intense-red :weight bold))))
   `(warning ((t (:foreground ,dupre-yellow+1 :weight bold))))
   `(success ((t (:foreground ,dupre-green+1 :weight bold))))
   `(link    ((t (:foreground ,dupre-blue+1 :underline t))))
   `(shadow  ((t (:foreground ,dupre-gray))))
   `(highlight ((t (:background ,dupre-bg+1))))
   `(tooltip ((t (:foreground ,dupre-fg :background ,dupre-bg+2))))
   `(tooltip-selection ((t (:background ,dupre-bg+0))))
   ;; Org-mode sample
   `(org-document-title       ((t (:foreground ,dupre-yellow+2 :weight bold :height 1.2))))
   `(org-level-1              ((t (:foreground ,dupre-blue+2 :weight bold))))
   `(org-level-2              ((t (:foreground ,dupre-green+1))))
   `(org-checkbox             ((t (:foreground ,dupre-yellow :weight bold))))
   `(org-todo                 ((t (:foreground ,dupre-red :weight bold))))
   `(org-done                 ((t (:foreground ,dupre-green+2 :weight bold))))
   )
#+end_src
** TODO [#B] Emacs Add Difftastic Functionality                :enhancement:
Linux Binary Install
https://github.com/Wilfred/difftastic
https://www.wilfred.me.uk/blog/2022/09/06/difftastic-the-fantastic-diff/
https://difftastic.wilfred.me.uk/installation.html (basically $ sudo pacman -S difftastic)
Emacs Package
https://github.com/pkryger/difftastic.el
#+begin_src emacs-lisp
  (use-package difftastic
    :defer t
    :vc (:url "https://github.com/pkryger/difftastic.el.git"
              :rev :newest))
#+end_src
** TODO [#B] Emacs error if no file in buffer-and-file operations      :bug:
** TODO [#B] Add Hugo Blogging Functionality                   :enhancement:
** TODO [#C] Emacs: Add Reverso Functionality                  :enhancement:
https://sqrtminusone.xyz/packages/reverso/
check his config for a usage example
Reverso
reverso.el is a package of mine that provides Emacs interface for https://reverso.net.
#+begin_src emacs-lisp
  (use-package reverso
    :straight (:host github :repo "SqrtMinusOne/reverso.el")
    :init
    (my-leader-def "ar" #'reverso)
    :commands (reverso)
    :config
    (setq reverso-languages '(russian english german spanish french portuguese))
    (reverso-history-mode))
#+end_src
* Emacs Config Ideas/References
** Edit Indirect (Custom Code) Bugs and Improvements
*** Bugs (by Severity)

*** High Severity

*Race Condition in =edit-indirect--commit=*
The commit function modifies the parent buffer while iterating through hooks that may also modify the buffer. The use of markers helps, but there's still a potential race condition if hooks modify the region being replaced. The =save-match-data= approach with markers could fail if the hooks significantly alter the buffer structure between marker creation and replacement.

*Potential Data Loss in =edit-indirect--clean-up=*
The function calls =delete-overlay= before setting =edit-indirect--overlay= to nil. If =delete-overlay= signals an error (e.g., if the overlay was already deleted), the overlay reference won't be cleared, potentially causing infinite loops in =edit-indirect--abort-on-kill-buffer=.

*** Medium Severity

*Missing Buffer Validation in =edit-indirect--commit=*
The function doesn't check if the parent buffer still exists before attempting to modify it. If the parent buffer was killed while the indirect buffer was being edited, this will cause an error.

*Hook Execution Order Issue*
The =edit-indirect--rebind-save-hooks= function is added to =after-change-major-mode-hook= globally but never removed. This means it will be called for every buffer that changes major mode, not just edit-indirect buffers, causing unnecessary overhead.

*** Low Severity

*Inefficient Overlay Search in =edit-indirect--search-for-edit-indirect=*
The function uses =overlays-in= which returns all overlays, then filters them. For buffers with many overlays, this is inefficient.

*Missing Error Handling in =edit-indirect--display-buffer=*
The function doesn't handle cases where =display-buffer= returns nil (which can happen if all windows are dedicated or display is inhibited).

*** Recommended Improvements

*** Easy Implementation

*Add Buffer Existence Check*
Add a check in =edit-indirect--commit= to ensure the parent buffer still exists:
#+begin_src emacs-lisp
(unless (buffer-live-p (overlay-buffer edit-indirect--overlay))
  (error "Parent buffer no longer exists"))
#+end_src

*Improve Hook Management*
Remove the global hook when not needed:
#+begin_src emacs-lisp
(defun edit-indirect--rebind-save-hooks ()
  (when (edit-indirect-buffer-indirect-p)
    (setq buffer-offer-save t)
    (add-hook 'write-contents-functions #'edit-indirect--commit-on-save nil t)
    ;; Remove global hook after use
    (remove-hook 'after-change-major-mode-hook #'edit-indirect--rebind-save-hooks)))
#+end_src

*Add Safety to Clean-up*
Wrap cleanup operations in condition-case:
#+begin_src emacs-lisp
(defun edit-indirect--clean-up ()
  (condition-case nil
      (delete-overlay edit-indirect--overlay)
    (error nil))
  (setq edit-indirect--overlay nil)
  ...)
#+end_src

*Add Display Buffer Error Handling*
Check display-buffer return value:
#+begin_src emacs-lisp
(defun edit-indirect--display-buffer (buffer)
  (with-current-buffer buffer
    (setq-local edit-indirect--should-quit-window t))
  (let ((window (display-buffer buffer)))
    (if window
        (select-window window)
      (switch-to-buffer buffer)))
  nil)
#+end_src

*** Medium Implementation

*Optimize Overlay Search*
Use a more efficient search strategy:
#+begin_src emacs-lisp
(defun edit-indirect--search-for-edit-indirect (beg end)
  (cl-loop for overlay in (overlays-in beg end)
           when (overlay-get overlay 'edit-indirect-buffer)
           return overlay))
#+end_src

*Add Undo Boundary Management*
Add undo boundaries to make commits atomic:
#+begin_src emacs-lisp
(defun edit-indirect--commit ()
  (undo-boundary)
  ;; ... rest of commit logic ...
  (undo-boundary))
#+end_src

*Improve Buffer Naming*
Make buffer names more informative:
#+begin_src emacs-lisp
(defun edit-indirect--create-indirect-buffer (beg end overlay)
  (let* ((mode-name (symbol-name major-mode))
         (buffer-name (format "*edit-indirect %s [%s]*" 
                             (buffer-name) 
                             (replace-regexp-in-string "-mode$" "" mode-name))))
    ...))
#+end_src

*** Hard Implementation

*Add Support for Nested Indirect Edits*
Allow editing a region within an already indirect buffer by tracking parent chain.

*Implement Diff Preview*
Add a command to show differences between the indirect buffer and parent region before committing:
#+begin_src emacs-lisp
(defun edit-indirect-diff-preview ()
  "Show differences between indirect buffer and parent region."
  (interactive)
  ;; Implementation using diff-mode
  )
#+end_src

*Add Persistent Session Support*
Save and restore indirect editing sessions across Emacs restarts using desktop.el integration.

*Implement Conflict Resolution*
Handle cases where the parent buffer was modified while editing in the indirect buffer, similar to version control merge conflicts.

*Add Support for Multiple Regions*
Allow editing multiple non-contiguous regions in a single indirect buffer, useful for refactoring similar code blocks simultaneously.

** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
It’s nice for magit to display in-tree TODOs in the status buffer:

(use-package magit-todos
  :init (magit-todos-mode)
  :custom
  (magit-todos-exclude-globs '(".git/" "*.gz" "*.html" "*.fastq" "*.fq"))
  :after (magit))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:40]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Completion
A completion framework—I used to use company but corfu seems to integrate with stock Emacs better.

(use-package corfu
  :custom
  (corfu-cycle t)
  :init
  (global-corfu-mode)
  :config
  (with-eval-after-load 'savehist
    (corfu-history-mode 1)
    (add-to-list 'savehist-additional-variables 'corfu-history)))
Use more completion at point functions from cape. dabbrev completion means that you can complete from words already present in the buffer, which helps for documents with long words that get used a lot.

(use-package cape
  :init
  (dolist (fn (list #'cape-file
                (cape-capf-super #'cape-dabbrev #'cape-dict #'org-block-capf #'cape-keyword)))
    (add-to-list 'completion-at-point-functions fn))
  :config
  (let ((wordlist (getenv "WORDLIST")))
    (setq
     cape-dict-file wordlist
     ispell-alternate-dictionary wordlist)))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:37]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Sometimes you want dummy text, say if you’re testing layouts for a poster but you haven’t written the text yet. Look no further than lorem-ipsum.

(use-package lorem-ipsum
  :init
  (setq
   lorem-ipsum-sentence-separator " "
   lorem-ipsum-list-bullet "- ")
  ;; map from C-c l
  (lorem-ipsum-use-default-bindings))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:37]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Tree-sitter grammar autoinstallation:

(use-package treesit-auto
  :custom
  (treesit-auto-install 'prompt)
  :config
  (treesit-auto-add-to-auto-mode-alist 'all)
  (global-treesit-auto-mode))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:37]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
recentf provides a persistent list of recently-opened files.

(use-package recentf
  :ensure nil
  :init (recentf-mode)
  :config
  (setq recentf-exclude '("Maildir")))

#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:36]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
I like to have a keybind to do the opposite of fill-paragraph. It’s taken from Stefan Monnier.

(defun unfill-paragraph (&optional region)
  "Takes a multi-line paragraph and turns it into a single line"
  (interactive (progn (barf-if-buffer-read-only) '(t)))
  (let ((fill-column (point-max))
        (emacs-lisp-docstring-fill-column t))
    (fill-paragraph nil region)))
(define-key global-map "\M-Q" 'unfill-paragraph)
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:35]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
I think a vertical “chooser” interface is key, it get used a lot due to find-file, buffer switching etc. I’m happy with vertico, which I switched to from selectrum because it appeared to rely more on built-in Emacs functionality which I think is a good thing for ecosystem compatability and the sustainability of Emacs as a platform in the future.

vertico-resize allows the minibuffer to grow and shrink to accomodate more or fewer candiates. vertico-cycle allows wrapping around the candidate list.

(use-package vertico
  :ensure (vertico :files (:defaults "extensions/*"))
  :custom
  (vertico-scroll-margin 0)
  (vertico-count 10)
  (vertico-resize t)
  (vertico-cycle t)
  :init
  (vertico-mode)
  (vertico-mouse-mode))
vertico-directory extension.

(use-package vertico-directory
  :ensure nil
  :after vertico
  :bind (:map vertico-map
              ("RET" . vertico-directory-enter)
              ("DEL" . vertico-directory-delete-char)
              ("M-DEL" . vertico-directory-delete-word))
  ;; Tidy shadowed file names
  :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
Use orderless searching, i.e M-x m o suggests org-mode. When completing at point in a buffer, after pressing TAB to bring up the completion interface, M-SPC allows you to insert a space in the query without breaking the completion.

(use-package orderless
  :custom
  (completion-styles '(orderless flex basic))
  (completion-category-overrides '((file (styles . (partial-completion)))
                                   (eglot (styles orderless)))))
consult offers some nice alternatives to standard Emacs interfaces based on completing-read. consult-buffer in particular is better than the stock command it replaces, providing recent files, bookmarks and buffers at-a-glance, with previews.

(use-package consult
  :config
  (setq consult-fontify-max-size 1024)
  :bind
  ("C-x b" . consult-buffer)
  ("C-c <C-m>" . consult-global-mark)
  ("C-c C-a" . consult-org-agenda)
  ("C-x O" . consult-outline)
  ("M-g M-g" . consult-goto-line)
  ("M-g i" . consult-imenu)
  ("M-s s" . consult-line)
  ("M-s M-s" . consult-line-multi))
embark allows inverting the usual Emacs command flow. Generally, you pick a verb (like find-file) and then pick a noun (like a filename). With embark, you can change your mind—once a candidate selected, press embark-act to use a different verb.

(use-package embark
  :bind
  (("C-." . embark-act)
   ("M-." . embark-dwim)
   ("C-h B" . embark-bindings))
  :custom
  (prefix-help-command #'embark-prefix-help-command)
  (embark-quit-after-action '((t . nil)))
  :config
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none)))))
embark-consult—additional integration of consult with embark.

(use-package embark-consult
  :after (embark consult)
  :demand t ; only necessary if you have the hook below
  ;; if you want to have consult previews as you move around an
  ;; auto-updating embark collect buffer
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))
marginalia takes advantage of vertical choosers by annotating candidates with exta information, such as file properties or function docstrings, making Emacs more self-explanatory.

(use-package marginalia
  :defer t
  :init
  (marginalia-mode)
  (setq marginalia-annotators '(marginalia-annotators-heavy nil)))

#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:34]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Showing the location of the mark, probably helps with learning to use mark better.

(use-package visible-mark
  :init
  (global-visible-mark-mode)
  :custom
  (visible-mark-faces '(visible-mark-face1 visible-mark-face2))
  (visible-mark-forward-faces '(visible-mark-face1 visible-mark-face2))
  (visible-mark-max 2))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:33]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
which-key got built into Emacs, it shows potential full keybinds when you enter a partial one, which is great for discoverability and learning.

(use-package which-key
  :ensure nil
  :init (which-key-mode))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:32]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Also show icons in find-file, consult-buffer etc.

(use-package all-the-icons-completion
  :after (marginalia all-the-icons)
  :hook (marginalia-mode . all-the-icons-completion-marginalia-setup)
  :init
  (all-the-icons-completion-mode))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:32]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
A mini-map (miniaturised window showing more of the buffer than the main window) is nice for longer documents:

(use-package minimap
  :custom
  (minimap-major-modes '(org-mode prog-mode))
  (minimap-window-location 'right)
  :bind ("C-+" . minimap-mode))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:31]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Drag and drop images into Org buffers to insert links:

(use-package org-download
  :custom
  (org-download-image-dir "./img"))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:30]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
I prefer a hybrid of plain text and WYSIWYG, so only show org emphasis markers if point is on the word.

(use-package org-appear
  :custom
  (org-appear-autolinks t)
  (org-appear-autosubmarkers t)
  (org-appear-autoentities t)
  (org-appear-autokeywords t)
  :hook (org-mode . org-appear-mode))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:29]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Org mode (and stock Emacs in general) can be quite ugly, org-modern helps a lot.

(use-package org-modern
  :config
  (setq org-modern-keyword
        '((t . t)
          ("bibliography" . "")
          ("cite_export" . "⮭")
          ("include" . "⇤")
          ("setupfile" . "⇚")
          ("header" . "›")
          ("caption" . "☰")
          ("name" . "⁝")
          ("results" . "∴")))
  (setq org-modern-block-name
        '((t . t)
          ("src" "»" "∥")
          ("example" "»–" "∥")
          ("quote" "❝" "❞")))
  :hook (org-mode . org-modern-mode))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:29]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
For HTML, I rarely want images to link to my on-disk versions, as this makes the file unportable.

(defun jdm204-org-export-to-html-with-monolith ()
  "Export the current Org buffer to HTML and process it with Monolith."
  (interactive)
  (let* ((html-file (org-html-export-to-html)))
    (shell-command (format "monolith %s -o %s" html-file html-file) nil nil)
    (message "HTML exported and post-processed with Monolith to %s" html-file)))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:28]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Refiling config.

(setq org-refile-targets
      '((nil :maxlevel . 3)
        (org-agenda-files :maxlevel . 3)))
(setq org-refile-use-outline-path 'file)
(setq org-outline-path-complete-in-steps nil)
Org agenda config.

(setq
 org-directory my/org-dir
 org-default-notes-file my/org-default-notes
 org-agenda-files `(,my/org-dir)
 org-agenda-span 'month
 diary-file my/diary
 org-agenda-prefix-format '((agenda . " %i %-10:c%-12t %-6e %s") (todo . " %i %-12:c")
                            (tags . " %i %-12:c") (search . " %i %-12:c"))
 org-agenda-scheduled-leaders '("Scd: " "Scd.%2dx: ")
 org-agenda-skip-scheduled-if-done t
 org-agenda-skip-deadline-if-done t
 org-agenda-compact-blocks t)
Custom agenda commands:

(setq org-agenda-custom-commands
      '(("w" "Weekly Review"
         ((agenda ""
                  ((org-agenda-skip-function '(org-agenda-skip-entry-if 'nottodo 'done))
                   (org-agenda-span 'week)))
          (agenda ""
                  ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                   (org-agenda-span 'week)))))
        ("d" "Dashboard View"
         ((agenda ""
                  ((org-agenda-span 'week)
                   (org-agenda-overriding-header "\n--- Time-Sensitive & Scheduled Tasks ---")))
          (alltodo ""
                   ((org-agenda-skip-function '(org-agenda-skip-entry-if 'scheduled 'deadline))
                    (org-agenda-overriding-header "\n--- General TODOs (Ready to be Worked On) ---")))))
        ("r" "Review/Triage Inbox"
         ((tags ".*" ((org-agenda-files '("~/cloud/org/inbox.org"))))))))
Org agenda grouping functionality:

(use-package org-super-agenda
  :init (org-super-agenda-mode)
  :config
  (setq org-super-agenda-groups
        '((:name "Scheduled" :time-grid t)
          (:name "Important" :priority "A" :priority "B")
          (:name "Personal" :tag "home" :tag "personal")
          (:name "Low Priority" :priority<= "D" :order 100))))
A mini agenda with calendar:

(use-package nano-agenda
  :bind ("C-c C" . nano-agenda))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:26]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
Present org sub-trees from Emacs:

(use-package org-tree-slide
  :custom
  (org-tree-slide-slide-in-effect nil)
  :bind (:map org-mode-map
              ("C-c P" . org-tree-slide-mode)))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:25]
** config.org · master · jdm204 / dotfiles · GitLab
#+BEGIN_QUOTE
More org blocks, notably including a details block, which is foldable, can include src and other blocks inside it, and exports (at least in HTML) to a hidden-by-default, revealable panel.

(use-package org-special-block-extras
  :init (org-special-block-extras-mode))
#+END_QUOTE
[[https://gitlab.com/jdm204/dotfiles/-/blob/master/config.org][config.org · master · jdm204 / dotfiles · GitLab]]
Captured On: [2025-10-15 Wed 18:25]

** My PDF Tools Settings
[[https://emacselements.com/pdf-tools-settings.html][My PDF Tools Settings]]
Captured On: [2025-09-03 Wed 11:49]
** Sound File Names
- [X] Beacon
- [X] BetaReduce
- [X] Bitrot
- [ ] Block
- [ ] BlockShift
- [ ] Cache
- [ ] Cluster
- [X] ContextSwitch
- [ ] Continuation
- [ ] Cycle
- [ ] Daemon
- [ ] Deadlock
- [ ] Diskette
- [X] Functor
- [ ] GarbageCollect
- [ ] Gate
- [ ] Halt
- [ ] Handshake
- [ ] HeapSpray
- [ ] Kernel
- [X] Lambda
- [ ] Latch
- [ ] Lex
- [X] LinkUp
- [ ] Monad
- [X] Mutex
- [ ] Nibble
- [ ] Node
- [ ] PageFault
- [ ] Parse
- [ ] PointerChase
- [ ] PortOpen
- [ ] Preempt
- [ ] Pulse
- [ ] SectorZero
- [ ] Segfault
- [ ] Socket
- [ ] Spark
- [ ] Spinlock
- [ ] Stream
- [ ] Thunk
- [ ] Token
- [ ] Trapframe
- [X] Bitflip
- [X] CacheHit
- [X] Futex
- [X] Macroexpand
- [X] Opcode
- [X] Packet
- [X] Ping
- [X] RaceCondition
- [X] Syscall
- [X] WakeSignal
** emacs-tw/awesome-elisp: A curated list of Emacs Lisp development resources
[[https://github.com/emacs-tw/awesome-elisp][emacs-tw/awesome-elisp: 🏵️ A curated list of Emacs Lisp development resources]]
Captured On: [2025-06-07 Sat 13:42]
** emacs-tw/awesome-emacs: A community driven list of useful Emacs packages, libraries and other items.
[[https://github.com/emacs-tw/awesome-emacs#layout][emacs-tw/awesome-emacs: A community driven list of useful Emacs packages, libraries and other items.]]
Captured On: [2025-06-07 Sat 13:30]
** bastibe/org-static-blog: A static site generator using org-mode
[[https://github.com/bastibe/org-static-blog][bastibe/org-static-blog: A static site generator using org-mode]]
Captured On: [2025-05-29 Thu 04:32]
** Better org-mode Agenda display-buffer-alist Settings • Christian Tietze
[[https://christiantietze.de/posts/2022/12/updated-org-mode-agenda-display-buffer-alist/][Better org-mode Agenda display-buffer-alist Settings • Christian Tietze]]
Captured On: [2025-08-01 Fri 03:21]
** org mode - org-link to the exact page-position in a pdf file - Emacs Stack Exchange
[[https://emacs.stackexchange.com/questions/68013/org-link-to-the-exact-page-position-in-a-pdf-file][org mode - org-link to the exact page-position in a pdf file - Emacs Stack Exchange]]
Captured On: [2025-07-11 Fri 18:17]
** Craft an Email Workflow with Org Mode - YouTube
[[https://www.youtube.com/watch?v=dSZu4jwvaSs][Craft an Email Workflow with Org Mode - YouTube]]
Captured On: [2025-08-30 Sat 11:42]
** Enhance Your Emails with Org Mode - System Crafters
[[https://systemcrafters.net/emacs-mail/enhance-email-with-org-mode/][Enhance Your Emails with Org Mode - System Crafters]]
Captured On: [2025-08-30 Sat 11:42]
** Emacs As Mail Client Specifically as Mu4E | Unixbhaskar's Blog
[[https://unixbhaskar.wordpress.com/2023/09/05/emacs-as-mail-client-specifically-as-mu4e/][Emacs As Mail Client Specifically as Mu4E | Unixbhaskar's Blog]]
Captured On: [2025-08-29 Fri 16:12]
** Blogging with Emacs, and Emacs only | Diego Vicente
[[https://diego.codes/post/blogging-with-org/][Blogging with Emacs, and Emacs only | Diego Vicente]]
Captured On: [2025-08-18 Mon 17:57]
** Using Emacs and Org-mode as a static site generator
[[https://ogbe.net/blog/emacs_org_static_site][Using Emacs and Org-mode as a static site generator]]
Captured On: [2025-08-18 Mon 17:54]
** The best latex Editor : r/emacs
[[https://www.reddit.com/r/emacs/comments/akmwko/the_best_latex_editor/][The best latex Editor : r/emacs]]
Captured On: [2025-08-13 Wed 19:29]
** gregoryg/emacs-gregoryg: My emacs settings for use across Linux, Windows, OS X
[[https://github.com/gregoryg/emacs-gregoryg?tab=readme-ov-file#gptel---llms-in-markdown-and-org-mode][gregoryg/emacs-gregoryg: My emacs settings for use across Linux, Windows, OS X]]
Captured On: [2025-08-12 Tue 16:31]
** Managing BibTeX Files with Emacs – Nick Higham
[[https://nhigham.com/2016/01/06/managing-bibtex-files-with-emacs/][Managing BibTeX Files with Emacs – Nick Higham]]
Captured On: [2025-09-25 Thu 02:46]
** onebirdrocks/ebook-mcp: A MCP server that supports mainstream eBook formats including EPUB, PDF and more. Simplify your eBook user experience with LLM.
[[https://github.com/onebirdrocks/ebook-mcp][onebirdrocks/ebook-mcp: A MCP server that supports mainstream eBook formats including EPUB, PDF and more. Simplify your eBook user experience with LLM.]]
Captured On: [2025-09-24 Wed 23:53]
** Battleship Game in Emacs
[[http://www.catb.org/~esr/bs/][Resource page for bs 2.13]]
Captured On: [2025-09-24 Wed 00:38]
** BrainCurses Emacs Mastermind Game
[[https://sourceforge.net/projects/braincurses/][BrainCurses download | SourceForge.net]]
Captured On: [2025-09-24 Wed 00:38]
** pinoaffe/org-vcard: Export and import vCards from within GNU Emacs' Org mode.
[[https://github.com/pinoaffe/org-vcard][pinoaffe/org-vcard: Export and import vCards from within GNU Emacs' Org mode.]]
Captured On: [2025-09-23 Tue 10:46]
** awth13/org-appear: Toggle visibility of hidden Org mode element parts upon entering and leaving an element
[[https://github.com/awth13/org-appear][awth13/org-appear: Toggle visibility of hidden Org mode element parts upon entering and leaving an element]]
Captured On: [2025-09-19 Fri 12:02]
** screensaver.el/screensaver.el at master · larsmagne/screensaver.el
[[https://github.com/larsmagne/screensaver.el/blob/master/screensaver.el][screensaver.el/screensaver.el at master · larsmagne/screensaver.el]]
Captured On: [2025-09-18 Thu 15:47]
** Capturing Content for Emacs
#+BEGIN_QUOTE
Capturing Content for Emacs

Let’s suppose you are current investigating a new code base, system or other problem, and you are following my advice and copying code, storing output, and taking notes along the way. All of this gets stored into your engineering notebook, aka primary org mode file (for me, this is often my current Sprint page).

Sure, selecting code, switching buffers or windows, pasting the code (maybe even jotting down some notes), and then popping back to your original file, may not be many keystrokes, but it exacts a bit of mental tax that mounts.

The typical solution to this problem is to use the org-capture feature (If you are not familiar with this Org feature, check out my gentle introduction or see Step 3 of Sacha Chua’s essay, Learn how to take notes more efficiently in Org Mode). While org-capture makes copying content into your org file easy, I am trying to improve on it, and here some of my experiments.

The “Current” Task

One mentally taxing aspect of org-capture is determining where something should go. Do you have a dozen (file) reference destinations? I have found the (clock) reference ideal for altering a default destination. Specifically, I begin work on a task, and designate it the focus of my attention (i.e. the destination of my work), by clocking in, using org-clock-in (C-c C-x C-i or , I in Spacemacs).

Now, we can add the following to the org-capture list:

(add-to-list 'org-capture-templates
`("c" "Item to Current Clocked Task" item
(clock)
"%i%?" :empty-lines 1))


This capture destination allows me to easily specify any header as a special destination with a simple clock in. However, we do have the mental interruption associated with creating a new buffer. Let’s minimize that by allowing us to put something on the kill ring, and send it to that clocked-in task:

(add-to-list 'org-capture-templates
`("K" "Kill-ring to Current Clocked Task" plain
(clock)
"%c" :immediate-finish t :empty-lines 1))


The trick here is the use of :immediate-finish, where it doesn’t even bother with a buffer, but just injects the kill-ring contents to the clocked in task without even a sneeze. Don’t want the hassle of sending something to the kill-ring? With this one, you only have to select the text, then kick off the capture:

(add-to-list 'org-capture-templates
`("C" "Contents to Current Clocked Task" plain
(clock)
"%i" :immediate-finish t :empty-lines 1))


In fact, create the following function and keybinding, and you can select text, and immediately copy it to your clocked in task without bothering with the org-capture menu:

(defun region-to-clocked-task (start end)
"Copies the selected text to the currently clocked in org-mode task."
(interactive "r")
(org-capture-string (buffer-substring-no-properties start end) "C"))

(global-set-key (kbd "C-<F17>") 'region-to-clocked-task)


This is great for general textual content, but much of what I want to copy is code, which could bring along a bit of meta data.

Code References

Much of my ideas got started after reading this blog entry where the idea is to have a function gather meta data associated with the currently selected text, and help to leave a back trace to the original code file.

I wanted to copy both code and regular text, so I made ha/org-capture-clip-snippet for wrapping the region in an EXAMPLE:

(defun ha/org-capture-clip-snippet (f)
"Given a file, F, this captures the currently selected text
within an Org EXAMPLE block and a backlink to the file."
(with-current-buffer (find-buffer-visiting f)
(ha/org-capture-fileref-snippet f "EXAMPLE" "" nil)))


And ha/org-capture-code-snippet for getting function name and the code type:

(defun ha/org-capture-code-snippet (f)
"Given a file, F, this captures the currently selected text
within an Org SRC block with a language based on the current mode
and a backlink to the function and the file."
(with-current-buffer (find-buffer-visiting f)
(let ((org-src-mode (replace-regexp-in-string "-mode" "" (format "%s" major-mode)))
(func-name (which-function)))
(ha/org-capture-fileref-snippet f "SRC" org-src-mode func-name))))


Both of these function do not do much, but given some values to Nick’s original function (which I’ve modified the format to fit my personal style):

(defun ha/org-capture-fileref-snippet (f type headers func-name)
(let* ((code-snippet
(buffer-substring-no-properties (mark) (- (point) 1)))
(file-name   (buffer-file-name))
(file-base   (file-name-nondirectory file-name))
(line-number (line-number-at-pos (region-beginning)))
(initial-txt (if (null func-name)
(format "From [[file:%s::%s][%s]]:"
file-name line-number file-base)
(format "From ~%s~ (in [[file:%s::%s][%s]]):"
func-name file-name line-number
file-base))))
(format "
%s

#+BEGIN_%s %s
%s
#+END_%s" initial-txt type headers code-snippet type)))


However, content I want to store in an org-mode comes from more than just Emacs buffers.

Output from Terminal Commands

What if the end result of a command sequence on the Terminal was a pipe to a program that could use cat to gather textual data from standard input, and then use emacsclient call org-capture to store it?

Yeah, and interesting idea when sent to the current clocked in task:

#!/bin/bash

TITLE="$*"
CONTENT="
#+BEGIN_EXAMPLE
$(cat | sed 's/^/     /g')
#+END_EXAMPLE
"

if [[ -n $TITLE ]]
then
CONTENT="   - ${TITLE}\n${CONTENT}"
fi

/usr/local/bin/emacsclient -c -n \
-e "(progn (org-capture-string \"$CONTENT\" \"C\") (delete-frame))"


Here I’m using our latest C capture template to that just takes textual context and stores is. Let’s try it in action by typing the following in a shell:

date | ec


Works like a charm:

#+BEGIN_EXAMPLE
Thu Jun  7 22:45:23 PDT 2018
#+END_EXAMPLE

Content from Browsers

Like many software people, I have a love-hate relationship with browsers. I often find myself copying/pasting information from a web site into my engineering notebook. Pasting text data into an org-mode file looses all text formatting as well as hyperlink references. But operating system clipboards can store some of this formatting data, so we just need to tap into it.

The downside is that accessing this information is operating system dependent…

Version for Mac

Let’s start from the top and work our way down. I need a way, outside of Emacs, to run a command to copy the selected region to the clipboard, and then use emacsclient to start a function to copy that information into the currently clocked in task.

I use Alfred to start a Workflow, as it will allow me to trigger these scripts in succession as shown in this diagram:

The trigger (in this case, just about every meta-key on a laptop), will start the first script that basically issues the Command-C to copy the selected text to the clipboard:

tell application "System Events" to keystroke "c" using command down


This works with any Mac application, including browsers.

The next script basically takes the contents of the clipboard (as HTML), render that to an org-compatible format with pandoc (which you’ll need to install), and then use emacsclient to call my org-capture routine with the “C” selection, so that the contents go directly to my clocked in task. My first attempt was a modified version from Roland Crosby:

query=$(osascript -e 'the clipboard as "HTML"' | \
perl -ne 'print chr foreach unpack("C*",pack("H*",substr($_,11,-3)))' | \
/usr/local/bin/pandoc -f html -t org | \
sed 's/"//g' | sed 's/^/   /' )

/usr/local/bin/emacsclient -c -n \
-e "(progn (org-capture-string \"${query}\" \"C\") (delete-frame))"


While the above code works well from a browser, if I copy text from something else (like Slack), the as "HTML" bit throws an error, as the clipboard contains plain text. After working on a fairly involved Perl script (that didn’t handle Unicode characters well), I ended up writing the entire part in Emacs Lisp. Now the shell script is nothing more than:

/usr/local/bin/emacsclient -c -n -e "(ha/external-capture-to-org)"


Unpacking Apple’s encoding plus dealing with both HTML and Text content was a bit more involved, but you can see the functions on Gitlab. The end result is great. After selecting some text on the homepage at orgmode.org, and clocked this header as my current task, I ended up with this getting pasted:

The stable version of Org is *9.1.13*, as of May 2018. See the
[[https://orgmode.org/Changes.html][release notes]].

Get it with =M-x package-install RET org RET= (see
[[https://orgmode.org/elpa.html][Org ELPA]]).

Or download it as a [[https://orgmode.org/org-9.1.13.tar.gz][tar.gz]] or
[[https://orgmode.org/org-9.1.13.zip][zip]] archives.


Keep in mind, that this copy/pasting business happens completely in the background while I am still surfin’ the web.

Version for Linux

Like everything, I suppose, getting this feature working on my Linux laptop is both easier and harder. Unlike the Mac, I can find no way to automatically copy the current selection to the clipboard like I can with an Applescript. However, once the content is on the clipboard, I can more easily grab it and throw it into Emacs.

Under the Keyboard section of the Settings app (at least on Ubuntu), you can create shortcuts to run commands:

Begin by scrolling to the bottom of the panel, and selecting the + button, and assigning your favorite hot-key (I decided to hold down the Control, Alt, and Super keys along with V since that seems most memorable to me), and have it run our function:

Of course, we’ll need to modify our function to use xclip. This isn’t install by default on Ubuntu (but neither is pandoc), so install those first:

sudo apt install xclip pandoc -y


Now, let’s create a function to call xclip, and like before, we ask for HTML, and if it fails, we’ll get it as regular text:

(defun ha/get-linux-clipboard ()
"Return the clipbaard for a Unix-based system. See `ha/get-clipboard'."
(destructuring-bind (exit-code contents)
(shell-command-with-exit-code "xclip" "-o" "-t" "text/html")
(if (= 0 exit-code)
(list :html contents)
(list :text (shell-command-to-string "xclip -o")))))


Since I want my same code to work with both my Mac and my Linux systems, I create a simple little dispatcher:

(defun ha/get-clipboard ()
"Returns a list where the first entry is the content type,
either :html or :text, and the second is the clipboard contents."
(if (eq system-type 'darwin)
(ha/get-mac-clipboard)
(ha/get-linux-clipboard)))


The rest of the code is same. See Gitlab for file updates.

Summary

My workflow proposal amounts to gathering data from a web browser, shell commands, and source code, and be able to fling it into my engineering notebook without switching out of that application.

Later, I will return to my notebook in Emacs and clean up and summarize my capturing. Once clean, the issues or knowledge I wish to share can then be easily exported from org.

The side-benefit, is that I automatically remind myself to clock in to my task.


#+END_QUOTE
[[https://howardism.org/Technical/Emacs/capturing-content.html][Capturing Content for Emacs]]
Captured On: [2025-10-03 Fri 08:59]
** A Refined Emacs LLM Environment with gpt.el & mcp.el | Kaoru's Blog
[[https://blog.kaorubb.org/en/posts/gpt-mcp-setup/][A Refined Emacs LLM Environment with gpt.el & mcp.el | Kaoru's Blog]]
Captured On: [2025-10-08 Wed 18:22]
** Org as a spreadsheet system: a short introduction
[[https://orgmode.org/worg/org-tutorials/org-spreadsheet-intro.html][Org as a spreadsheet system: a short introduction]]
Captured On: [2025-09-16 Tue 03:36]
** Capturing Content for Emacs
[[https://www.howardism.org/Technical/Emacs/capturing-content.html][Capturing Content for Emacs]]
Captured On: [2025-09-16 Tue 03:46]
** howardabrams/hamacs: My personal VIM-like configuration of Emacs inspired by Doom and Spacemacs.
[[https://github.com/howardabrams/hamacs/tree/main][howardabrams/hamacs: My personal VIM-like configuration of Emacs inspired by Doom and Spacemacs.]]
Captured On: [2025-09-16 Tue 04:35]
** Creating Timestamps (The Org Manual)
[[https://orgmode.org/manual/Creating-Timestamps.html][Creating Timestamps (The Org Manual)]]
Captured On: [2025-09-17 Wed 12:04]
** jgru/consult-org-roam: A bunch of convenience functions for operating org-roam with the help of consult
[[https://github.com/jgru/consult-org-roam][jgru/consult-org-roam: A bunch of convenience functions for operating org-roam with the help of consult]]
Captured On: [2025-09-08 Mon 12:25]
** Sending Emacs Emails Asynchronously

dotfiles/emacs/.emacs.d/readme.org at 3aa87cc5c2e57895c03ec8b716065a9a6e56614a · joedicastro/dotfiles
#+BEGIN_QUOTE
Sending emails asynchronous

This is useful to send emails with attachments and do not block emacs until end the transmission.

(use-package smtpmail-async
:config
(setq
send-mail-function 'async-smtpmail-send-it
message-send-mail-function 'async-smtpmail-send-it))
#+END_QUOTE
[[https://github.com/joedicastro/dotfiles/blob/3aa87cc5c2e57895c03ec8b716065a9a6e56614a/emacs/.emacs.d/readme.org#L3973][dotfiles/emacs/.emacs.d/readme.org at 3aa87cc5c2e57895c03ec8b716065a9a6e56614a · joedicastro/dotfiles]]
Captured On: [2025-09-11 Thu 21:28]
** Update the header symbols in mu4e view
dotfiles/emacs/.emacs.d/readme.org at 3aa87cc5c2e57895c03ec8b716065a9a6e56614a · joedicastro/dotfiles
#+BEGIN_QUOTE
;; more cool and practical than the default
(setq mu4e-headers-from-or-to-prefix '("" . "➜ "))
#+END_QUOTE
[[https://github.com/joedicastro/dotfiles/blob/3aa87cc5c2e57895c03ec8b716065a9a6e56614a/emacs/.emacs.d/readme.org#L3973][dotfiles/emacs/.emacs.d/readme.org at 3aa87cc5c2e57895c03ec8b716065a9a6e56614a · joedicastro/dotfiles]]
Captured On: [2025-09-11 Thu 21:29]
** Add interactive delete-from alist-by-key
#+BEGIN_QUOTE
2.16.5. other tools
1
2
3
4
5
6
7
8
9
10
11
12
;; why isn't it a part of standart lib
(defun delete-from-alist-by-key (list-var elem)
"Interactively remove element from alist."
(interactive
(let ((var (helpful--read-symbol
"Variable: "
(helpful--variable-at-point)
#'(lambda (symb) (and (boundp symb) (listp (symbol-value symb)) (helpful--variable-p symb))))))
(list var
(completing-read "Choose element to delete from: " (symbol-value var) nil t))))
(message "deleting %s from %s=%s" elem list-var (symbol-value list-var))
(set list-var (assoc-delete-all elem (symbol-value list-var))))
#+END_QUOTE
[[https://codefastdieyoung.com/knowledge-base/emacs-config/][Emacs config - codefastdieyoung]]
Captured On: [2025-09-11 Thu 22:20]
** Google Translate Integration
#+BEGIN_QUOTE
; crazy, finally it works
(use-package google-translate
:disabled
:ensure
;:init
;(require 'google-translate)
;(require 'google-translate-smooth-ui)
;(defun google-translate--search-tkk () "Search TKK." (list 430675 2721866130))
:functions (google-translate--search-tkk)
:config
(require 'google-translate-smooth-ui)
(defun google-translate--search-tkk () "Search TKK." (list 430675 2721866130))
;todo - fix minibuffer keymap with evil for directions
;(evil-define-key '(motion normal insert) minibuffer-local-map)
:custom
(google-translate-input-method-auto-toggling t)
(google-translate-preferable-input-methods-alist '((nil . ("en")) (ukrainian-computer . ("ru" "uk"))))
(google-translate-translation-directions-alist '(("uk" . "en") ("ru" . "en") ("en" . "uk")))
;(google-translate--tkk-url "http://translate.google.com/")
;(google-translate-base-url "http://translate.google.com/")
;(google-translate-backend-debug t)
(google-translate-backend-method 'curl)
(google-translate-show-phonetic t)
:bind
("C-c C-t t" . google-translate-smooth-translate)
("C-c C-t p" . google-translate-at-point)
("C-c C-t q" . google-translate-query-translate)
("C-c C-t d" . google-translate-query-translate-using-directions)
)
#+END_QUOTE
[[https://codefastdieyoung.com/knowledge-base/emacs-config/][Emacs config - codefastdieyoung]]
Captured On: [2025-09-11 Thu 22:36]
** dot-files/emacs-eshell.org at master · howardabrams/dot-files · GitHub
[[https://github.com/howardabrams/dot-files/blob/master/emacs-eshell.org][dot-files/emacs-eshell.org at master · howardabrams/dot-files · GitHub]]
Captured On: [2025-09-11 Thu 23:34]
** dot-files/emacs-elisp.org at master · howardabrams/dot-files · GitHub
#+BEGIN_QUOTE
Suggesting
Intrigued to play with Wilfred Hughes’ project, suggest:

(use-package suggest
:bind ((:prefix-map lisp-evaluation-map
:prefix "C-c e"
("s" . suggest))))
#+END_QUOTE
[[https://github.com/howardabrams/dot-files/blob/master/emacs-elisp.org][dot-files/emacs-elisp.org at master · howardabrams/dot-files · GitHub]]
Captured On: [2025-09-11 Thu 23:30]
** dot-files/emacs-client.org at master · howardabrams/dot-files · GitHub
#+BEGIN_QUOTE
Dimming and Finding Cursor
When I type, I would rather not see the cursor, for at the point where I am typing, I know where I am typing. Of course, when I’m moving around the screen (or even when Emacs is idle), I want to know clearly the location of cursor.

I’ve previously made the cursor an obnoxious color, and let’s save that value:

(defvar cursor-initial-color (face-attribute 'cursor :background)
"The initial value of the cursor that will be use when re-showing it.")
If I type a character or maybe two, I don’t want to hide the cursor… only when I start to really get typing:

(defvar cursor-number-chars-before-hiding 2
"The number of characters one needs to type before we hide the cursor.")
Of course, I need to have some sort of state variable that counts the number of characters that have been typed:

(defvar cursor-current-number-chars 0)
Now let’s have a couple of functions that will show and hide the cursor (or at least, lessen its visibility):

(defun cursor-hide (&optional arg)
"Hides cursor by setting the color to the background color.
This only happens after a number of characters have been
typed (defined by the `cursor-number-chars-before-hiding'
variable)."
(setq cursor-current-number-chars (1+ cursor-current-number-chars))
(when (> cursor-current-number-chars cursor-number-chars-before-hiding)
(set-cursor-color (or (background-color-at-point) "#1d1f21"))))

(defun cursor-show ()
"Shows the cursor. At least, sets it to a particular
color (stored/defined in `cursor-initial-color'. Note: This also
resets the `cursor-current-number-chars' variable, so that it
won't be hid until a number of characters have been typed."
(setq cursor-current-number-chars 0)
(set-cursor-color cursor-initial-color))
After entering a text that is inserted into a buffer, hide the cursor by using some advice:

(advice-add 'self-insert-command :after #'cursor-hide)
After I’m done typing (that is, when the cursor is idle), show the cursor:

(setq my-cursor-timer (run-with-idle-timer 1 t #'cursor-show))
Let’s make the cursor more noticeable whenever the window scrolls (which seems to be the time when I need to visually look for it):

(use-package beacon
:ensure t
:defer  t
:diminish 'beacon-mode
:init  (beacon-mode +1)
:config (setq beacon-color cursor-initial-color))
#+END_QUOTE
[[https://github.com/howardabrams/dot-files/blob/master/emacs-client.org][dot-files/emacs-client.org at master · howardabrams/dot-files · GitHub]]
Captured On: [2025-09-11 Thu 23:23]
** dot-files/emacs-browser.org at master · howardabrams/dot-files · GitHub
#+BEGIN_QUOTE
External Web Browsing
Need to be able to switch and have a link in an org-mode file show up in the default, graphical browser:

(defun ha-switch-default-browser ()
"Switches the default browser between the internal and external web browser."
(interactive)
;;         | Variable                  | Function
(if (equal browse-url-browser-function 'browse-url-default-browser)
(if (fboundp 'w3m)
(setq browse-url-browser-function 'w3m-browse-url)
(setq browse-url-browser-function 'eww-browse-url))
(setq browse-url-browser-function 'browse-url-default-browser))

;; Now we need to display the current setting. The variables are
;; pretty typical and have the goodies, but I just need to get rid
;; of the word "url" or "browser", and the results are pretty close:
(cl-flet ((remove-bad-parts (l)
(-filter (lambda (s) (pcase s
("url"     nil)
("browse"  nil)
("browser" nil)
(_  t))) l)))
(message "Browser set to: %s"
(-> (symbol-name browse-url-browser-function)
(split-string "-")
remove-bad-parts
car))))

(global-set-key (kbd "C-c w d") 'ha-switch-default-browser)
#+END_QUOTE
[[https://github.com/howardabrams/dot-files/blob/master/emacs-browser.org][dot-files/emacs-browser.org at master · howardabrams/dot-files · GitHub]]
Captured On: [2025-09-11 Thu 23:17]
** GitHub - howardabrams/dot-files: My Emacs initialization code and standard scripts I use for client and servers alike.
[[https://github.com/howardabrams/dot-files][GitHub - howardabrams/dot-files: My Emacs initialization code and standard scripts I use for client and servers alike.]]
Captured On: [2025-09-11 Thu 23:12]
** rememberYou/.emacs.d: 🎉 Personal GNU Emacs configuration
[[https://github.com/rememberYou/.emacs.d][rememberYou/.emacs.d: 🎉 Personal GNU Emacs configuration]]
Captured On: [2025-09-12 Fri 05:48]
** Howardism: Tools to Focus
[[https://www.howardism.org/Technical/Emacs/focused-work.html][Tools to Focus]]
Captured On: [2025-09-16 Tue 04:24]
** I created a tutorial for Org Mode Tables that contains lots of practical examples, check it out : r/orgmode
[[https://www.reddit.com/r/orgmode/comments/1iaw2je/i_created_a_tutorial_for_org_mode_tables_that/][I created a tutorial for Org Mode Tables that contains lots of practical examples, check it out : r/orgmode]]
Captured On: [2025-09-16 Tue 03:36]
** dump-jump using xref-show-definitions-functions
- codefastdieyoung
#+BEGIN_QUOTE
11.5. jump-to
1
2
3
4
5
(use-package dumb-jump
:functions xref-show-definitions-completing-read
:ensure
:init (setq xref-show-definitions-function #'xref-show-definitions-completing-read)
:config (add-hook 'xref-backend-functions #'dumb-jump-xref-activate))

#+END_QUOTE
[[https://codefastdieyoung.com/knowledge-base/emacs-config/][Emacs config - codefastdieyoung]]
Captured On: [2025-09-11 Thu 22:31]
** Good emacs config files - codefastdieyoung
[[https://github.com/caisah/emacs.dz][GitHub - caisah/emacs.dz: Awesome emacs config files]]
Captured On: [2025-09-11 Thu 22:39]
[[https://codefastdieyoung.com/knowledge-base/emacs-config/][Emacs config - codefastdieyoung]]
Captured On: [2025-09-11 Thu 22:11]
** buffer/file compare: current version with saved via diff
#+BEGIN_QUOTE
Auxiliary functions for buffers management
Some custom functions to manage buffers.

(defun joe-alternate-buffers ()
"Toggle between the last two buffers"
(interactive)
(switch-to-buffer (other-buffer (current-buffer) t)))

(defun joe-revert-buffer ()
"Revert the buffer to the save disk file state"
(interactive)
(revert-buffer nil t))

(defun joe-diff-buffer-with-file ()
"Compare the current modified buffer with the saved version."
(interactive)
(let ((diff-switches "-u"))
(diff-buffer-with-file (current-buffer))))
#+END_QUOTE
[[https://github.com/joedicastro/dotfiles/blob/master/emacs/.emacs.d/readme.org][dotfiles/emacs/.emacs.d/readme.org at master · joedicastro/dotfiles · GitHub]]
Captured On: [2025-09-11 Thu 23:01]
** Async Module for Doing Asynchronous Processing
#+BEGIN_QUOTE
async
async.el is a module for doing asynchronous processing in Emacs.

(use-package async
:defer t
:ensure t
:config
(setq async-bytecomp-package-mode t))
#+END_QUOTE
[[https://github.com/joedicastro/dotfiles/blob/master/emacs/.emacs.d/readme.org][dotfiles/emacs/.emacs.d/readme.org at master · joedicastro/dotfiles · GitHub]]
Captured On: [2025-09-11 Thu 23:03]
** Review Org's New Citation Syntax
URL: https://blog.tecosaur.com/tmio/2021-07-31-citations.html
Captured On:[2025-09-25 Thu 02:39]
[ ] 

[[https://orgmode.org][*]]
[[https://blog.tecosaur.com/tmio/][This Month in Org]] 
[[https://blog.tecosaur.com/tmio/rss.xml][RSS icon]]

2021-07-31, TEC

July 2021

Introducing citations!

Last month I not-at-all-subtly hinted that a certain long-awaited
feature was arriving imminently. At this point, I think it’s a good idea
to set the tone for the rest of this post. 

celebrate-citations.svg

Citations[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citations][#]] 

After years of (on and off) discussion[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#fn.1][1]], I am elated to be able to
present Org’s new native citation syntax. Org has grown a thoroughly
designed, modular, capable citation system. At last you can refer to Org
for all your attribution needs. Special thanks must go to Nicolas
Goaziou for leading the charge, John Kitchin for paving the way with the
org-ref package, Bruce D’Arcus for driving a lot of careful
consideration of design decisions and starting to document some of the
details — and the many other denizens of the mailing list who have
contributed to the discussion over the years. 

András Simonyi’s also deserves a special mention for his work creating
the Elisp CSL library Citeproc.el, which while not directly included in
Org is crucial to providing robust CSL support, and integrates with
oc-csl.el. 

Outline[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#outline][#]] 

Citations have been carefully designed in such a way that users and
Elisp tinkerers will be able to easily adapt and extend it to fit their
needs. To that end, Org Cite (or OC for short) has been split into two
halves: 

• oc.el which defines the syntax and provides some machinery to interact
  with citations
• Citation processors which interface with oc.el to produce
  nicely-formatted citations to be inserted in your bibliography, within
  the text, and even rendered in the buffer[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#fn.2][2]]

There are four capabilities that Org Cite uses the processors for 

1 Inserting and editing citations
2 Following citations to their definition
3 Fontifying the citations in the buffer
4 Exporting the citations

Each capability can have a particular citation processor assigned,
independently of the others. Out of the box, Org uses the basic
processor for all of these tasks. 

The basic citation processor is one of four currently bundled with Org: 

• basic, which has no dependencies and provides all four capabilities.
  It export to all formats, but only provides very simple citations.
• biblatex and natbib, which provide the export capability to create
  citations via [[http://biblatex-biber.sourceforge.net/][Biber]] and (to a lesser extent) [[https://ctan.org/pkg/natbib][natbib]], but only for
  LaTeX.
• csl, which provides the export capability using the [[https://citationstyles.org/][Citation Style
  Language]], and exports to HTML, LaTeX, Org, and plain text (with an
  [[https://github.com/andras-simonyi/citeproc-el/issues/23][open issue]] for ODT) — but depends on [[https://github.com/andras-simonyi/citeproc-el][citeproc.el]].

This provides a solid foundation for other packages to build off, and
despite Org Cite being yet to be released or documented in the manual we
are already seeing the development of packages like [[https://github.com/jkitchin/org-ref-cite][org-ref-cite]] (by
John Kitchin). 

Basic usage[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#basic-usage][#]] 

To get started with Org Cite, we must have some form of bibliography.
This can either be a BibTeX file or a CSL-JSON file. 

As an example, say we have a file orgcite.bib containing the following 

bibtex
[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#basic-usage,code--1][#]] ⎘ 
@article{OrgCitations,
         author={org, mode and Syntax, Citation and List, Mailing and Effort, Time},
         journal={Journal of Plain Text Formats},
         title={Elegant Citations with Org-Mode},
         year={2021},
         month={7},
         volume={42},
         number={1},
         pages={2-3}}

First we need to let Org know about this bibliography file (which must
have a .bib, .bibtex, or .json extension), which we do either via the
#+bibliography keyword, or the variable org-cite-global-bibliography. 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#org367f817][#]] ⎘ 

#+bibliography: orgcite.bib

Once you have a bibliography source, you can start referencing to your
heart’s content! The basic citation syntax is as follows: 

citation-structure-basic.svg
Figure 1: The new citation syntax, for simple citations

Using the default style [cite:@OrgCitations] produces ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al. 2021]]).
For more information on the styles currently available, see [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#cite-styles][1]]. 

Finally, to insert a bibliography somewhere, we just need to insert the
#+print_bibliography keyword, like so: 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#orgf39282d][#]] ⎘ 

#+print_bibliography:
org, mode, Citation Syntax, Mailing List, and Time Effort. 2021.
“Elegant Citations with Org-Mode.” Journal of Plain Text Formats 42 (1):
2–3.

So, to summarise, all one needs to get started is: 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#orgb88a259][#]] ⎘ 

#+bibliography: references.bib
[cite:@key]
#+print_bibliography:

That’s it! 🎉 

The cite syntax[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#cite-syntax][#]] 

Don’t let the simplicity in the examples above fool you, the new syntax
is quite capable of expressing more complex forms. Here’s the full
version of the new cite syntax: 

citation-structure-full.svg
Figure 2: The new citations syntax, in full

• The style and variant determine what form the exported citation takes
• The common prefix and suffix and put at the start and end of the
  generated citation, respectively
• The citation key refers to a Bib(La)TeX or CSL-JSON key 

  • The citation prefix and suffix are put before and after the
    reference to the key
  • Some citation processors recognise locators, which refer to a
    particular part of the work, for example: p. 7 to refer to page 7.

Using the default CSL citation style (Chicago author-name) [cite/l/b:see
@OrgCitations pp. 7 for fun] becomes see [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al. 2021, 7]] for fun. 

The citation styles and variants, and recognised locators are handled by
the citation processors. Org cite’s bundled processors currently
supports the following citation styles. 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#cite-styles][#]]

 Table 1: The current set of supported citation styles with variants,  
 with samples generated by oc-csl.el and citeproc.el.  
  Style  Variant  Sample  Bib(La)TeX  NatBib    
  a author  cf caps-full  ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Org,]]  Citeauthor       
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Syntax,]]        
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][List, and]]        
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Effort]])        
  a author  f full  ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org,]]  citeauthor  citeauthor*    
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Syntax,]]        
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][List, and]]        
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Effort]])        
  a author  c caps  ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Org et al.]])  Citeauthor*  Citeauthor    
  a author     ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]])  citeauthor*  citeauthor    
  na noauthor  b bare  [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]]     citeyear    
  na noauthor     ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])  autocite*  citeyearpar    
  l locators  bc bare-caps  [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Org et al.]]  Notecite       
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021, 2]]        
  l locators  b bare  [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]]  notecite       
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021, 2]]        
  l locators  bc caps  , [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Org et al.]]  Pnotecite       
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021, 2]]        
  l locators     (, [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et]]  pnotecite       
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][al. 2021, 2]])        
  n nocite     ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]]  nocite  nocite    
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  t text  b bare  org et al.     citealp    
      ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  t text  c caps  Org et al.  Textcite  Citep    
      ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  t text  f full  org, Syntax,     citep*    
      List, and        
      Effort        
      ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  t text  bc bare-caps  org et al.     Citealp    
      ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  t text  bf bare-full  org et al.     citealp*    
      ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  t text  cf caps-full  Org, Syntax,     Citep*    
      List, and        
      Effort        
      ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  t text  bcf  org et al.     Citealp*    
    bare-caps-full  ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  t text     org et al.  textcite       
      ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  (default)  b bare  [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]]  cite  citealp    
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]]        
  (default)  bc bare-caps  [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][Org et al.]]  Cite  Citealp    
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]]        
  (default)  f full  ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]]     citep*    
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  (default)  bf bare-full  ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]]     citealp    
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  (default)  cf caps-full  ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]]     Citep*    
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  (default)  bcf  ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]]     Citealp*    
    bare-caps-full  [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        
  (default)     ([[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][org et al.]]  autocite  citep    
      [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#citeproc_bib_item_1][2021]])        

The CSL processor supports the following locators: 

• book, bk., bks.
• chapter, chap., chaps.
• column, col., cols.
• figure, fig., figs.
• folio, fol., fols.
• number, no., Os.
• line, l., ll.
• note, n., nn.
• opus, op., opp.
• page, p, p., pp.
• paragraph, para., paras., ¶, ¶¶, §, §§
• part, pt., pts.
• section, sec., secs.
• sub verbo, s.v., s.vv.
• verse, v., vv.
• volume, vol., vols.

More on exporting[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#more-exporting][#]] 

The style of the citations and the bibliography depend on three things: 

1 The citation processor used
2 The citation style
3 The bibliography style

The citation processor is automatically selected based on
org-cite-export-processors based on the export format being used, but
can be set on a per-document basis via the #+cite_export keyword. Here,
I shall use the csl processor, 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#org0920610][#]] ⎘ 

#+cite_export: csl

With org-cite-export-processors, you can also set the bibliography and
citation style by giving a triplet of parameters (PROCESSOR
BIBLIOGRAPHY-STYLE CITATION-STYLE) instead of just the processor. You
can also use this triplet of values with the #+cite_export keyword 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#orgf8da086][#]] ⎘ 

#+cite_export: processor bibliography-style citation-style

There are also some more options about how the bibliography is produced.
These options are handled by the active citation processor. For example,
while the CSL processor does not currently support any options, the
BibLaTeX processor passes options to a \printbibliography command,
allowing for the following: 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#org29efa9f][#]] ⎘ 

#+print_bibliography: :section 2 :heading subbibliography
#+print_bibliography: :keyword abc,xyz :title "Primary Sources"

Using CSL[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#using-csl][#]] 

[[https://github.com/andras-simonyi/citeproc-el][Citeproc]] is currently available on [[https://melpa.org/#/citeproc][MELPA]], and so can be installed via
your package manager of choice so long as MELPA is included in your
package-archives. When available, it will be automatically loaded by
oc-csl.el. 

It currently supports exporting to: 

• HTML
• LaTeX
• Org
• Plain text

Should you be interested in other formats, know that Citeproc is
designed to easily support adding new formats (see
citeproc-formatters.el for examples). 

Citeproc can currently retrieve bibliographic information from the
following formats: 

• CSL-JSON
• Bib(La)TeX
• org-bibtex

Though support for Bib(La)TeX and [[https://gewhere.github.io/org-bibtex][org-bibtex]] is rudimentary compared to
CSL-JSON. 

When exporting, you can set the style by providing a path to CSL style
files, either absolute or relative to org-cite-csl-styles-dir. For
example, if I download apa.csl I can use it like so: 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#org678d1e6][#]] ⎘ 

#+cite_export: csl ~/Downloads/apa.csl

When no style is given org-cite-csl--fallback-style-file will be used,
which defaults to a bundled Chicago author-date style. 

Working with Zotero[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#working-with-zotero][#]] 

There are quite a few reference managers available, however, the list
rapidly shrinks if you restrict yourself to applications which are: 

• somewhat feature-rich
• open source software
• not owned by a parasitic company[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#fn.3][3]]

[[https://www.zotero.org/][Zotero]] is a good option, and if you’re using it it’s quite easy to use
it with Org Cite. Out of the box, you can tell it to export your
library, or parts of it, to a .bib file and automatically keep it in
sync. I’d recommend installing the [[https://retorque.re/zotero-better-bibtex/][Better BibTeX]] extension though. 

zotero-export-library.png
Figure 3: Zotero library right click context menu, showing the export
option
zotero-export-options-prompt.png
Figure 4: Zotero collection export dialog

Zotero also works well with CSL. In addition to supporting CSL-JSON
exports, Zotero also features an easy way to install CSL styles within
the preferences. 

zotero-cite-styles-menu.png
Figure 5: Zotero CSL style management within preferences

Since these files are put under ~/Zotero/styles, you can use them with
Org Cite and Citeproc simply by setting org-cite-csl-styles-dir to the
Zotero styles directory. 

Emacs Lisp
[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#working-with-zotero,code--1][#]] ⎘ 
(setq org-cite-csl-styles-dir "~/Zotero/styles")

To then use the citation style defined by ~/Zotero/styles/apa.csl one
can then simply refer to apa.csl when using the #+cite_export keyword. 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#org5f6c51c][#]] ⎘ 

#+cite_export: csl apa.csl

A bright future[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#bright-future][#]] 

Org Cite has only just been merged in the past month, and is yet to be
included in an Org release, but we’re seeing a tremendous degree of
community interest. There are already promising developments with
third-party packages, such as [[https://github.com/bdarcus/bibtex-actions][bibtex-actions]] and [[https://github.com/jkitchin/org-ref-cite][org-ref-cite]]. I can’t
wait to see how the ecosystem continues to develop 😃. 

Footnotes: 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#fnr.1][1]]

Citations were first being mentioned on the mailing list back in 2007,
in [[https://lists.gnu.org/archive/html/emacs-orgmode/2007-05/msg00146.html][a thread about footnotes]]. 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#fnr.2][2]]

There is currently an [[https://github.com/andras-simonyi/org-cite-csl-activate][ongoing effort]] to use oc.el and citeproc.el to
produce citation overlays in the buffer. 

[[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#fnr.3][3]]

I’m talking about a certain company [[https://moneyweek.com/505757/great-frauds-in-history-robert-maxwell][created by a British Fraudster]] that
has a [[https://www.theguardian.com/science/2017/jun/27/profitable-business-scientific-publishing-bad-for-science][40% profit margin, engages in blackmail-like practices with
universities]], prompted [[http://thecostofknowledge.com/][19,000 researchers]] to boycott them, [[https://www.the-scientist.com/the-nutshell/elsevier-published-6-fake-journals-44160][published six
fake journals]], vigorously [[https://web.archive.org/web/20200129202353/http://legacy.earlham.edu/~peters/fos/2007/08/publishers-launch-anti-oa-lobbying.html][lobbys against Open Access]], [[https://rossmounce.co.uk/2017/02/14/elsevier-selling-access-to-open-access-again/][charged for Open
Acess articles]] (repeatedly), made [[https://www.michaeleisen.org/blog/?p=807][financial contributions to politicians
who then tried to prevent publicly accesible reaserch]], and whose
reference manager [[https://www.zotero.org/support/kb/mendeley_import#mendeley_database_encryption][encrypted reaserchers’ own databases]] “to comply with
GDPR”. 

[[http://creativecommons.org/publicdomain/zero/1.0/][CC0]]
To the extent possible under law, [[https://blog.tecosaur.com/][TEC]] has waived all copyright and
related or neighboring rights to This Month in Org. 
** [[https://karthinks.com/software/fifteen-ways-to-use-embark/][Emacs: Fifteen ways to use Embark]]
URL: https://karthinks.com/software/fifteen-ways-to-use-embark/
Captured On:[2025-09-23 Tue 01:42]

• [[https://karthinks.com/software/fifteen-ways-to-use-embark/#embark-act-actually-dot-dot-dot-dot-and-but-first-dot-dot-dot][embark-act: Actually…. & But first…]] 

  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#open-any-buffer-by-splitting-any-window][Open any buffer by splitting any window]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#copy-a-file-to-a-remote-location-when-finding-a-file][Copy a file to a remote location when finding a file]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#insert-a-minibuffer-candidate-into-the-buffer][Insert a minibuffer candidate into the buffer]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#run-a-shell-command-on-a-minibuffer-candidate-file-without-losing-your-session][Run a shell command on a minibuffer candidate file without losing
    your session]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#open-a-file-as-root-without-losing-your-session][Open a file as root without losing your session]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#upload-a-region-of-text-to-0x0][Upload a region of text to 0x0]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#visit-a-package-s-url-from-the-minibuffer][Visit a package’s URL from the minibuffer]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#set-a-variable-from-anywhere-it-appears-in-a-buffer][Set a variable from anywhere it appears in a buffer]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#add-a-keybinding-for-a-command-name-from-anywhere-it-appears][Add a keybinding for a command name from anywhere it appears]]

• [[https://karthinks.com/software/fifteen-ways-to-use-embark/#embark-export-i-want-a-gist-so-give-me-a-list][embark-export: I want a gist, so give me a list]] 

  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#export-emacs-package-candidates-to-a-package-menu][Export Emacs package candidates to a package menu]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#collect-imenu-candidates-in-an-imenu-list][Collect imenu candidates in an “imenu-list”]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#export-file-candidates-to-a-dired-buffer][Export file candidates to a dired-buffer]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#export-buffer-candidates-to-ibuffer][Export buffer candidates to ibuffer]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#export-variable-candidates-to-a-customize-buffer][Export variable candidates to a customize buffer]]
  • [[https://karthinks.com/software/fifteen-ways-to-use-embark/#export-grep-or-line-candidates-to-a-grep-buffer][Export grep or line candidates to a grep buffer]]

• [[https://karthinks.com/software/fifteen-ways-to-use-embark/#bonus-use-embark-actions-like-helm][BONUS: Use Embark Actions like Helm]]
• [[https://karthinks.com/software/fifteen-ways-to-use-embark/#33][33%]]

Fifteen ways to use Embark 

2021-10-06
[[https://karthinks.com/tags/emacs][emacs]] 

Update (2024-10-02): Update for Emacs 29

Update (2024-09-08): Read this article in Japanese at [[https://emacs-jp.github.io/tips/fifteen-ways-to-use-embark][Qiita]] or at
[[https://emacs-jp.github.io/tips/fifteen-ways-to-use-embark][Emacs-JP]].

Update (2021-10-16): While this list was intended as a demonstration of
the kinds of things you can do with Embark, there has been some interest
by readers in reproducing these demos exactly on their machines. So I
have added a “Play by play” section under each demo listing the sequence
of actions in the demo.

[[https://github.com/oantolin/embark/tree/98121bacef39abaf6f6849f87a439ba2184c03e2][Embark]] is a fantastic and thoughtfully designed package for Emacs that
flips Emacs’ action → object ordering without adding a learning curve.
It’s completely changed how I use Emacs, and I’m going to show you why.

By default, Emacs’ action model is to specify the action (find-file),
then the object (the file): 
[[https://karthinks.com/img/emacs-pattern.png][*]]

This mirrors how one does things in a shell: 
[[https://karthinks.com/img/shell-pattern.png][*]]
The difference is that before you submit your shell command, you’re free
to edit both the action and the object, since it’s just a line of text.
In Emacs you can change the object freely, but to change the action
you’d have to hit C-g and call a different command.

Things work the other way in a GUI program like a file manager. You
select some representation of the object (usually an icon), then choose
the action you would like to perform on it: 
[[https://karthinks.com/img/gui-pattern.png][*]]

Either paradigm works fine, but this is Emacs, there’s no reason to
choose just one! Embark lets you go back and forth between the two
patterns. So you can call find-file (say) and pick a file, only to
realize that you want to do something else with it, like open it in
another window, or copy the file to a different directory:

[[https://karthinks.com/img/embark-pattern.png][*]]

With Embark, this is a breeze.

embark-act: Actually…. & But first…

embark-act is your “Actually…” command. As in, I called package-install
and picked a package but actually I’d like to read the package
description instead!

embark-act is your “Yes, but first…” command as well. As in, I called
find-file but first I’d like to copy it elsewhere to be safe, then
continue to open this file!

Or perhaps you want to think of it as a keyboard driven analog of a
“right-click menu” in a GUI environment. That works too, but the former
maps better to the idea of “late-binding” and laziness that I think of
Embark as enabling.

Emacs makes you specify and fix the action/verb first (find-file, say),
then choose the thing it acts on (the file). If you call embark-act,
this is reversed. Now the object (file) is fixed, and you’re free to
choose the action.

I know: It sounds like I’m describing Helm actions. The difference is
that Embark works everywhere, across all types of “objects”, and with
every initial and wait-I-changed-my-mind command. There is no
predetermined set of alternative actions configured to work with another
predetermined set of initial actions. No one (including yourself) needs
to have anticipated in advance what actions go together.[[https://karthinks.com/software/fifteen-ways-to-use-embark/#fn:1][1]] This uniform,
consistent integration into Emacs makes the difference between them one
of kind and not of quantity, although it takes a bit of time to see
this.

This means you can start a command and select a candidate in the
minibuffer, then call embark-act and M-x some-other-command to run that
command on the candidate instead. If you are about to kill a buffer with
C-x k but want to switch to it instead, you can call embark-act followed
by C-x b. You can even do this without losing the kill-buffer prompt if
you just want a quick peek at the buffer!

The categories of objects Embark understands covers most common cases:
filenames, buffers, bookmarks, URLs, text regions, variables, commands,
symbols and more.

When you call embark-act, Embark also activates a keymap with direct
access to common actions you might want to run for each category of
object. This makes it unnecessary to use M-x to run your
I-changed-my-mind action all the time, although you always have that
option. You can, of course, add your own commands to this keymap as I do
below.

I use embark-act literally hundreds of times every day. Here are a few
of my common uses. A few of these are built in, others need some elisp
to work, all are surprisingly useful. To be clear, this list barely
scratches the surface of the sphere of possibilities with Embark.

A recipe for reproducing these demos

I use Embark in conjunction with various Consult commands (consult-grep,
consult-locate, consult-dir etc) in Emacs 27.2. If you want to reproduce
these demos exactly in your Emacs, you will need the following packages:

• embark
• marginalia
• vertico
• consult
• embark-consult
• orderless
• consult-dir
• ace-window
• 0x0

Additionally you may need to bind the relevant commands (embark-act,
embark-export, consult-*) to suitable keys.

Open any buffer by splitting any window

This needs a little background. The ace-window package allows you to
switch to a window based on keyboard hints. A less well known feature is
that it also provides a “dispatch menu” that lets you act on windows in
ways beyond simply switching to them:

[[https://i.imgur.com/EWC4jNH.gifv][[video]​]]Play by play

1 With two or more windows open, call ace-window
2 Press ? to bring up the dispatch menu.
3 Press the dispatch key to split a window horizontally (v in my video)
4 Press the ace-window key corresponding to the buffer you want to split
  (e in my video)
5 Repeat steps 1 and 2
6 Press the dispatch key to split a window vertically (s in my video)
7 Press the ace-window key corresponding to the buffer you want to split
  (w in my video)

So you can kill windows, move them around, split them and more by using
the dispatch keys. (Hit ? to bring up the dispatch menu.)

Now: You can call ace-window via Embark to display a candidate anywhere,
including in splits that you create using the above dispatch menu. This
means any buffer/file/bookmark I open is always placed exactly where I
want it to be on the screen.

In the below demo, I open a bookmark (with consult-bookmark), a file
(with find-file) and a buffer (with consult-buffer) in sequence. Each
time, I run embark-act and select the ace-window action, which activates
ace-window. You can then display the buffer in any existing window by
making a selection with ace-window. I actually go one step further in
the demo: I split one of the existing windows using ace-window’s
dispatch feature from above and display the relevant buffer in that
split!

[[https://i.imgur.com/5hwqpQD.gifv][[video]​]]Play by play

1 Run a command that requires selecting a file, bookmark or buffer,
  perhaps switch-to-buffer
2 Select one and run embark-act
3 Run the my/embark-ace-action with o (see below)
4 Select the window where you want the buffer to be placed, OR
5 Split an existing window with v or b (see aw-dispatch-alist) followed
  by a window selection, and display the buffer in the new split.

Update for Emacs 29

Emacs 29 provides a bunch of “window-prefix” actions: [[https://karthinks.com/software/emacs-window-management-almanac/#the-other-window-prefix--built-in][these are commands
you can call to display the output of the next command in specified
windows]]. For example, calling other-tab-prefix and then find-file will
open the file you select in a new tab. Emacs provides
same-window-prefix, other-window-prefix, other-tab-prefix and
other-frame-prefix. We can [[https://karthinks.com/software/emacs-window-management-almanac/#a-window-prefix-command-for-ace-window][go one step further and define]] an
ace-window-prefix. Calling it will activate ace-window after the next
command and show its result in the window you select, including possibly
in splits you create using ace-window actions:

(defun ace-window-prefix ()
    "Use `ace-window' to display the buffer of the next command.
The next buffer is the buffer displayed by the next command invoked
immediately after this command (ignoring reading from the minibuffer).
Creates a new window before displaying the buffer.
When `switch-to-buffer-obey-display-actions' is non-nil,
`switch-to-buffer' commands are also supported."
    (interactive)
    (display-buffer-override-next-command
     (lambda (buffer _)
       (let (window type)
         (setq
          window (aw-select (propertize " ACE" 'face 'mode-line-highlight))
          type 'reuse)
         (cons window type)))
     nil "[ace-window]")
    (message "Use `ace-window' to display next command buffer..."))

Now the interesting bit: Instead of defining separate Embark actions for
opening files, bookmarks or buffers in specified windows or splits, we
can embed the window prefix actions into Embark so they can be used with
any category of object.

First we define a keymap with these actions:

(defvar-keymap my/window-prefix-map
  :doc "Keymap for various window-prefix maps"
  :suppress 'nodigits
  "o" #'ace-window-prefix
  "0" #'ace-window-prefix
  "1" #'same-window-prefix
  "2" #'split-window-vertically
  "3" #'split-window-horizontally
  "4" #'other-window-prefix
  "5" #'other-frame-prefix
  "6" #'other-tab-prefix
  "t" #'other-tab-prefix)

What we’d like: When running embark-act, pressing any of the keys in the
above keymap should run Embark’s default action – i.e. the command that
you originally invoked – but with the right window-prefix applied. This
will supersede the below, older method of defining individual Embark
commands for each kind of object. Getting there involves hooking into
Embark’s event loop, so this is a little convoluted. Strap in!

• We define a function that looks up keys in the above keymap and calls
  the right -window-prefix command before running Embark’s default
  action. This is intended as a hook function for Embark’s
  embark-around-action-hooks, which lets you insert specific behavior
  around each Embark action. This is the code we’d like Embark to
  actually run:

  ;; Look up the key in `my/window-prefix-map' and call that function first.
  ;; Then run the default embark action.
  (cl-defun my/embark--call-prefix-action (&rest rest &key run type &allow-other-keys)
    (when-let ((cmd (keymap-lookup
                     my/window-prefix-map
                     (key-description (this-command-keys-vector)))))
      (funcall cmd))
    (funcall run :action (embark--default-action type) :type type rest))
• But this behavior is not attached to any Embark action yet. To access
  this behavior from Embark, we define a dummy Embark action whose
  behavior will be replaced by the above function:

  ;; Dummy function, will be overridden by running `embark-around-action-hooks'
  (defun my/embark-set-window () (interactive))

  ;; When running the dummy function, call the prefix action from above
  (setf (alist-get 'my/embark-set-window embark-around-action-hooks)
        '(my/embark--call-prefix-action))
• A wrinkle: to support multi-category commands like those provided by
  Consult (where the candidates can be a mix of bookmarks, buffers,
  files and others), we need to explicitly set the “default” Embark
  action for relevant categories:

  (setf (alist-get 'buffer embark-default-action-overrides) #'pop-to-buffer-same-window
        (alist-get 'file embark-default-action-overrides) #'find-file
        (alist-get 'bookmark embark-default-action-overrides) #'bookmark-jump
        (alist-get 'library embark-default-action-overrides) #'find-library)
• Finally, we map this dummy embark action to all the keys in
  my/window-prefix-map:

  (map-keymap (lambda (key cmd)
                (keymap-set embark-general-map (key-description (make-vector 1 key))
                            #'my/embark-set-window))
              my/window-prefix-map)

  The fact that all keys in my/window-prefix-map are mapped to the same
  action is not a problem – in my/embark--call-prefix-action we dispatch
  on the key that was actually pressed.

If you’re on Emacs 29 or later, you can enable behavior like the above
for all commands and categories at once, without needing to define
individual actions. The below is a more manual (and backward-compatible)
approach.

To get this to work, you’ll need to add a few ace-window functions to
the Embark file actions map:

(eval-when-compile
  (defmacro my/embark-ace-action (fn)
    `(defun ,(intern (concat "my/embark-ace-" (symbol-name fn))) ()
      (interactive)
      (with-demoted-errors "%s"
       (require 'ace-window)
       (let ((aw-dispatch-always t))
        (aw-switch-to-window (aw-select nil))
        (call-interactively (symbol-function ',fn)))))))

(define-key embark-file-map     (kbd "o") (my/embark-ace-action find-file))
(define-key embark-buffer-map   (kbd "o") (my/embark-ace-action switch-to-buffer))
(define-key embark-bookmark-map (kbd "o") (my/embark-ace-action bookmark-jump))

I also add actions to open the buffer in a vertical or horizontal split.
But you probably don’t need this, since you can do this and a lot more
with ace-window’s dispatch menu!

(eval-when-compile
  (defmacro my/embark-split-action (fn split-type)
    `(defun ,(intern (concat "my/embark-"
                      (symbol-name fn)
                      "-"
                      (car (last  (split-string
                                   (symbol-name split-type) "-"))))) ()
       (interactive)
       (funcall #',split-type)
       (call-interactively #',fn))))

(define-key embark-file-map     (kbd "2") (my/embark-split-action find-file split-window-below))
(define-key embark-buffer-map   (kbd "2") (my/embark-split-action switch-to-buffer split-window-below))
(define-key embark-bookmark-map (kbd "2") (my/embark-split-action bookmark-jump split-window-below))

(define-key embark-file-map     (kbd "3") (my/embark-split-action find-file split-window-right))
(define-key embark-buffer-map   (kbd "3") (my/embark-split-action switch-to-buffer split-window-right))
(define-key embark-bookmark-map (kbd "3") (my/embark-split-action bookmark-jump split-window-right))
------------------------------------------------------------------------

Copy a file to a remote location when finding a file

[[https://i.imgur.com/mpArf9q.gifv][[video]​]]Play by play

1 Run any command that requires selecting a file, perhaps
  find-file-other-window
2 Select one and run embark-act
3 Run the copy-file action with c. Embark has a key for this but you can
  also M-x copy-file here.
4 Navigate to the destination path. In the video I used the [[https://github.com/karthink/consult-dir][consult-dir]]
  package to instantly switch the path to one of my bookmarks, a remote
  location.
5 Press RET to copy the file. You can type in a name to copy it as.

Here’s what happened. In any file prompt, you can call embark-act and
select the copy action to copy the file instead. (You could just as well
call M-x copy-file.) In this case I then use [[https://github.com/karthink/consult-dir][consult-dir]] to insert a
bookmark that points to my server into the destination prompt, and the
file is copied using Tramp.

You can even do this without losing the find-file prompt! Calling
embark-act with a prefix argument keeps the prompt alive:

[[https://i.imgur.com/BIw0Tht.gifv][[video]​]]Play by play

1 Run any command that requires selecting a file, perhaps
  find-file-other-window
2 Select one and run embark-act with a prefix argument. That is, if your
  binding for embark-act is C-., run C-u C-..
3 Run the copy-file action with c. Embark has a key for this but you can
  also M-x copy-file here.
4 Navigate to the destination path. In the video I used the [[https://github.com/karthink/consult-dir][consult-dir]]
  package to instantly switch the path to one of my bookmarks, a remote
  location.
5 Press RET to copy the file. You can type in a name to copy it as.
6 Continue to use your find-file-other-window prompt as before.

At the end I quit the find-file prompt manually and check the remote
directory to ensure that the file has been copied.

------------------------------------------------------------------------

Insert a minibuffer candidate into the buffer

Simple but very convenient:

[[https://i.imgur.com/SrAD4Oa.gifv][[video]​]]Play by play

1 Run any command that requires you to make a selection using the
  minibuffer. The selection can be anything, it just has to display some
  text.
2 In the video I chose a distant directory with consult-dir and selected
  a file in that directory.
3 Run embark-act
4 Press i to insert the text of the selection into the main buffer. In
  the video I used I instead to insert the selected file’s relative
  path. I does different things based on the type of object you’re
  selecting. For example, I with a buffer candidate inserts the contents
  of the buffer instead.

------------------------------------------------------------------------

Run a shell command on a minibuffer candidate file without losing your
session

A perfect example of But First I need to…:

[[https://i.imgur.com/9Wf6mQc.gifv][[video]​]]Play by play

1 Run any command that requires selecting a file, perhaps find-file
2 I switched to a distant directory using consult-dir.
3 Select a file and run embark-act with a prefix argument. That is, if
  your binding for embark-act is C-., run C-u C-..
4 Press & to run the async-shell-command action. Embark has a key for
  this in its keymaps but you could run M-x async-shell-command or call
  its default keybinding (M-&) instead.
5 Type in the command at the prompt. The file name is already filled in
  for you. I used the file shell command for more info on a file.
6 Press RET to run the command and return to the find-file prompt.

I called the “file” shell command for more info on the file without
ending the find-file prompt.

------------------------------------------------------------------------

Open a file as root without losing your session

Emacs’ version of forgetting to add sudo before the command. In the
shell you can go back to the start of the prompt and type it in, or
engage in the sudo !! ritual. In Emacs I use an Embark action:

[[https://i.imgur.com/ccjvizN.gifv][[video]​]]Play by play

1 Run any command that requires selecting a file. I used consult-locate
  to locate a root-owned file on my filesystem.
2 Select one and run embark-act with a prefix argument. That is, if your
  binding for embark-act is C-., run C-u C-..
3 Select the sudo-find-file action with S. Note: You’ll need to add this
  action to the keymap, see below. Alternatively you can run M-x
  sudo-find-file or its global binding.

Like before, this works from any file prompt but the command I started
with was consult-locate. For the sudo program there is the sudo-edit
package, although I used a snippet from my init file that I can’t
ascertain the provenance of anymore:

(defun sudo-find-file (file)
  "Open FILE as root."
  (interactive "FOpen file as root: ")
  (when (file-writable-p file)
    (user-error "File is user writeable, aborting sudo"))
  (find-file (if (file-remote-p file)
                 (concat "/" (file-remote-p file 'method) ":"
                         (file-remote-p file 'user) "@" (file-remote-p file 'host)
                         "|sudo:root@"
                         (file-remote-p file 'host) ":" (file-remote-p file 'localname))
               (concat "/sudo:root@localhost:" file))))

To use sudo-find-file as an Embark action, you can run it (with M-x or a
global keybinding) after calling embark-act, or shorten the process
further by adding an entry to Embark’s file actions map:

(define-key embark-file-map (kbd "S") 'sudo-find-file)
------------------------------------------------------------------------

Upload a region of text to 0x0

[[https://i.imgur.com/i06G4vT.gifv][[video]​]]Play by play

1 Select a region of text in a buffer.
2 Run embark-act.
3 Press U to choose the 0x0-dwim action. Note: You’ll need to add this
  action to the keymap, see below.
4 The region text will be uploaded to 0x0 and URL added to the
  kill-ring. (See message at the end of the video.)

I’m using the [[https://melpa.org/#/0x0][0x0]] package for the 0x0-dwim function. When called as an
Embark action on a URL, this shortens it. When called on a file, it
uploads the file. The echo area message at the end (from 0x0-dwim) tells
me the upload URL has been copied to the kill ring. As with the other
examples, you can call 0x0-dwim after running embark-act or define a
short key for it in one of Embark’s keymaps:

(define-key embark-region-map (kbd "U") '0x0-dwim)
------------------------------------------------------------------------

Visit a package’s URL from the minibuffer

[[https://i.imgur.com/b6BTODS.gifv][[video]​]]Play by play

1 Run any command that requires selecting a package, perhaps
  describe-package (C-h P by default)
2 Select a package and run embark-act
3 Press u to run the embark-browse-package-url action.

In this case I ran the describe-package command before going “Actually…
URL please”, but in this example as all the others, there’s nothing
special about describe-package. Any command that gives you a list of
packages at the minibuffer will proffer the same set of Embark actions.

------------------------------------------------------------------------

Set a variable from anywhere it appears in a buffer

Super handy for quickly setting variables, especially when testing code.

[[https://i.imgur.com/wltZaGq.gifv][[video]​]]Play by play

1 Move point to a variable in a buffer. (Alternatively, run a command
  that requires selecting a variable at the minibuffer, like
  describe-variable)
2 Run embark-act.
3 Press = to run the set-variable action. Embark has a key for this in
  its keymaps, but you could call M-x set-variable instead.
4 Set the new value of the variable.

In this case Embark has an entry for set-variable in its variables
keymap (bound to =), but you can just call M-x set-variable.

------------------------------------------------------------------------

Add a keybinding for a command name from anywhere it appears

Set all the keys.

[[https://i.imgur.com/A0hHGhi.gifv][[video]​]]Play by play

1 Move point to a command name in a buffer. (Alternatively, run a
  command that requires selecting a command at the minibuffer, like
  describe-command)
2 Run embark-act.
3 Press g to run the global-set-key action. Embark has a key for this in
  its keymaps, but you could call M-x global-set-key instead.
4 Set the new keybinding for the command.

Embark provides an action in its keymap to run global-set-key, but you
could just call M-x global-set-key after running embark-act with the
point on a command name. There is also local-set-key in the embark
keymap.

------------------------------------------------------------------------

embark-export: I want a gist, so give me a list

If that was everything Embark did I’d be a happy camper. But embark-act
isn’t even its best feature. That would be the gem of composability that
is embark-export (and its lesser kin embark-collect). These commands
create persistent collections from minibuffer candidate lists: It’s one
part ivy-occur and one part glue that ties together Emacs libraries
better than Emacs does. The examples illustrate why.

------------------------------------------------------------------------

Export Emacs package candidates to a package menu

Want a package-menu-mode buffer with all packages involving shells in
Emacs? embark-export has you covered:

[[https://i.imgur.com/oaDGV3X.gifv][[video]​]]Play by play

1 Run any command that requires selecting a package, perhaps
  describe-package (C-h P by default)
2 (Optional) Type in some text to filter the completions list
3 Run embark-export

The clever idea behind embark-export is to reuse Emacs’ built-in
functionality whenever possible: the package-menu library already
handles displaying packages. If you’re generating a list of packages
with user-specified conditions, why reinvent the wheel?

------------------------------------------------------------------------

Collect imenu candidates in an “imenu-list”

embark-collect creates persistent collections of minibuffer completion
candidates (filtered by user input) in a way that basically obsoletes
every “listing” package for me. In this example I create a filtered list
of imenu items that sticks around and that I can use to navigate around
the file:

[[https://i.imgur.com/MJlM9cL.gifv][[video]​]]Play by play

1 When visiting any file, run imenu or a version of it (I ran
  consult-imenu-all)
2 (Optional) Type in some text to filter the completions list
3 Run embark-export. (This actually runs embark-collect under the hood.
  You could run embark-collect directly instead, but it’s simpler to
  just use one command.)
4 Press RET in the persistent collections buffer to navigate to that
  symbol in the file.

I didn’t show this in the demo, but all embark-act actions are available
in the Collections buffer, and you can even call them directly (i.e.
without calling embark-act first) by turning on
embark-collect-direct-action-minor-mode.

------------------------------------------------------------------------

Export file candidates to a dired-buffer

Have a list of files you arrived at in a tortuous manner that you want
to keep around? dired was created to list files, and embark-export
respects this:

[[https://i.imgur.com/6ZY08H2.gifv][[video]​]]Play by play

1 Run any command that requires selecting a file. I used consult-fd to
  find all files matching a pattern below a directory.
2 (Optional) Type in some text to filter the completions list. With
  consult-fd you do this by adding a # to end the string to search on
  and begin the string used to filter the results.
3 Run embark-export.

This obsoletes find-name-dired, another “listing” based feature.

------------------------------------------------------------------------

Export buffer candidates to ibuffer

You saw this coming: Any list of buffers gets exported to an ibuffer.

[[https://i.imgur.com/pmBTb6q.gifv][[video]​]]Play by play

1 Run any command that requires selecting a buffer. I used
  consult-buffer.
2 Type in some text to filter the completions list: 

  • I pressed b SPC to narrow the consult-buffer list to buffers, then
  • typed in ! followed by * to omit all buffers[[https://karthinks.com/software/fifteen-ways-to-use-embark/#fn:2][2]] that begin with a *,
    i.e. “special” buffers.

3 Run embark-export.

------------------------------------------------------------------------

Export variable candidates to a customize buffer

A list of variables is exported by embark-export into a customize
buffer:

[[https://i.imgur.com/NIQBwKS.gifv][[video]​]]Play by play

1 Run a command that requires selecting a variable, like
  describe-variable
2 Type in some text to filter the completions list
3 Run embark-export

This is a great way to transition from looking up a variable to a
full-fledged apropos on relevant items when you need to.

------------------------------------------------------------------------

Export grep or line candidates to a grep buffer

Any occur-like results (from consult-line, grep, xref etc) get exported
into a grep buffer.

[[https://i.imgur.com/PjS1Yx6.gifv][[video]​]]Play by play

1 Run a command that generates a list of grep-style matches. I used
  consult-ripgrep in the demo. Other Consult-based options are
  consult-grep, consult-git-grep and consult-line.
2 Type in some text to find grep results.
3 Not necessary: I flipped through the various files that matched with
  vertico-next-group and vertico-previous-group.
4 Run embark-export.
5 Turn on next-error-follow-minor-mode in the grep buffer with C-c C-f.
  This jumps each match as I…
6 …navigate the grep buffer with M-n and M-p (compilation-next-error and
  compilation-previous-error), and move to the next/previous matching
  file with } and {.

Note that this is a regular grep buffer, so you can use all your tricks,
like wgrep to edit the grep buffer and save changes in all the files.

------------------------------------------------------------------------

BONUS: Use Embark Actions like Helm

In the above examples, the available embark actions were displayed in
some window in the frame. Embark has multiple “prompters” listing the
preset actions, and with a little elbow grease you can set up something
similar to Helm[[https://karthinks.com/software/fifteen-ways-to-use-embark/#fn:3][3]]:

[[https://i.imgur.com/LH9uYM6.gifv][[video]​]]Play by play

1 Run any command involving minibuffer selection, consult-buffer in the
  video.
2 (Optional) type in something to filter the completions list or select
  a buffer.
3 Press TAB to switch to the list of embark actions.
4 Press TAB again to switch back to the list of candidates.
5 Search for an action by name (in this case “kill”) to filter the list
  of actions
6 Erase and search for a different action (“diff”) and choose the
  diff-buffer-with-file action
7 Press RET to run diff-buffer-with-file on the selected buffer
8 (Optional) Navigate the diff hunks with diff-hunk-next and
  diff-hunk-prev
9 (Optional) Fold the diff sections with outline-cycle
10 Run consult-buffer again and select a buffer
11 Switch to the actions list again with TAB
12 Press @ to call an action by its keybinding instead of selecting it
   by name
13 Call the embark action for killing a buffer with k to kill the
   selected buffer.

Here I switch back and forth between the list of actions and the list of
candidates (like in Helm) with C-<tab>. In the actions list you can
either type the action (matched with completing-read), or call the
action directly by prepending its keybinding with @.

Elbow grease:

(defun with-minibuffer-keymap (keymap)
  (lambda (fn &rest args)
    (minibuffer-with-setup-hook
        (lambda ()
          (use-local-map
           (make-composed-keymap keymap (current-local-map))))
      (apply fn args))))

(defvar embark-completing-read-prompter-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "<tab>") 'abort-recursive-edit)
    map))

(advice-add 'embark-completing-read-prompter :around
            (with-minibuffer-keymap embark-completing-read-prompter-map))
(define-key vertico-map (kbd "<tab>") 'embark-act-with-completing-read)

(defun embark-act-with-completing-read (&optional arg)
  (interactive "P")
  (let* ((embark-prompter 'embark-completing-read-prompter)
         (embark-indicators '(embark-minimal-indicator)))
    (embark-act arg)))

Replace vertico-map above with your completion system of choice’s active
minibuffer keymap. The default is minibuffer-local-completion-map.

Remember that unlike with Helm, you’re not restricted to these actions
when you use Embark! You can call literally any command that it makes
sense to with its keybinding or with M-x after running embark-act.

------------------------------------------------------------------------

33%

That’s fifteen useful Embark thingamajigs, and I didn’t get to mention
embark-become. Or embark-prefix-help-map, embark-which-key-prompter, or
Embark’s targets and target cycling, or half a dozen more thoughtful
features and niceties about Embark. Maybe next time.

I’ll conclude instead by mentioning the main packages I used in the
above demos:

• [[https://github.com/oantolin/embark][embark]] by Omar Antolin Camarena, who’s been a pleasure to interact
  with and pester with my requests for features. To add custom actions
  to the embark keymaps or otherwise customize Embark, I suggest
  perusing the README. It’s as readable and informative as they come.
• [[https://github.com/minad/consult][consult]] for its various enhancements to Emacs’ builtins.
  consult-locate and consult-find (actually consult-fd) to find files,
  consult-imenu for a colorful imenu with grouping and consult-ripgrep
  to grep across a directory.
• [[https://github.com/minad/marginalia][marginalia]] for the annotations in the minibuffer. Co-maintained by
  Omar Antolin and Daniel Mendler.
• [[https://github.com/minad/vertico][vertico]] as the minibuffer completion interface. Consult, Vertico and
  Marginalia are all authored by Daniel Mendler, who I’m convinced never
  sleeps. I didn’t even mention Corfu.
• The [[https://github.com/oantolin/orderless][orderless]] completion style, also by Omar Antolin, to match pieces
  of text against minibuffer candidates independently. Together these
  five packages form the MOVEC pentagram, a composable enhancement suite
  that integrates Emacs’ loosely bound libraries into a modern and
  cohesive whole.
• [[https://github.com/karthink/consult-dir][consult-dir]] to switch directories quickly. I used this multiple times
  above to navigate to distant directories when in the minibuffer
  prompt.
• [[https://github.com/karthink/popper][popper]] to make embark-collect, help and other ephemeral buffers behave
  when they appear on screen.
• [[https://github.com/abo-abo/ace-window][ace-window]] by abo-abo, whose dispatch-keys idea in Ace-Window and Avy
  I promptly ripped off for Popper. If I understand correctly his
  Ivy-Occur was an early influence on what became Embark-Collect as
  well.
• [[https://git.sr.ht/~willvaughn/emacs-0x0][0x0]] by William Vaughn. I use this far more often than I thought I
  would.

Finally a quick note for Doom Emacs users: Doom ships with Embark out of
the box (as of Sep 2021), you don’t need to do anything besides looking
up the keys for embark-act and embark-collect.

Despite what these examples suggest, I estimate that I use less than a
third of what Embark provides. Even so, in allowing me to change or
chain actions at any time, it lets me pilot Emacs by the seat of my
pants. A second, unforeseen benefit is that it makes commands and
listings that I would never use available in a frictionless way:
commands like transpose-regions and apply-macro-to-region-lines, or
custom dired, ibuffer and package-menu listings that are interactively
inaccessible otherwise[[https://karthinks.com/software/fifteen-ways-to-use-embark/#fn:4][4]]. The ability to quickly whip up such buffers
makes knowhing how to use dired or ibuffer pay off several fold. In
composing such features seamlessly with minibuffer interaction or with
text-regions, Embark acts as a lever to amplify the power of Emacs’
myriad built in commands and libraries.

------------------------------------------------------------------------

1 Although of course, Helm and Embark both do a good job with their
  presets. [[https://karthinks.com/software/fifteen-ways-to-use-embark/#fnref:1][↩︎]]

2 To match the inverse of an input string with !, I used a [[https://github.com/oantolin/orderless#style-dispatchers][feature of
  the orderless package]] for Emacs. [[https://karthinks.com/software/fifteen-ways-to-use-embark/#fnref:2][↩︎]]

3 Yes, it’s not fully Helm-style since it still uses the minibuffer
  instead of a buffer to show the candidates/actions. You could use
  [[https://github.com/minad/vertico#extensions][vertico-buffer]] if that’s a sticking point. [[https://karthinks.com/software/fifteen-ways-to-use-embark/#fnref:3][↩︎]]

4 Technically custom package-menu listings are accessible. From the full
  package listing (M-x list-packages), you can filter package names by
  regexp with / n. [[https://karthinks.com/software/fifteen-ways-to-use-embark/#fnref:4][↩︎]]

[[https://karthinks.com/software/fifteen-ways-to-use-embark/#][Menu]] [[https://karthinks.com/software/fifteen-ways-to-use-embark/#][TOC]] [[https://karthinks.com/software/fifteen-ways-to-use-embark/#][share]] 
Copyright © 2025 Karthik Chikmagalur 

• [[https://karthinks.com/][Home]]
• [[https://karthinks.com/about][About]]
• [[https://karthinks.com/blog][Misc]]
• [[https://karthinks.com/software][Coding]]
** [[https://kristofferbalintona.me/posts/202203130102/][Cape | Kristoffer Balintona]]
URL: https://kristofferbalintona.me/posts/202203130102/
Captured On:[2025-09-23 Tue 01:41]
[[https://kristofferbalintona.me/][Kristoffer Balintona]]
[[https://kristofferbalintona.me/posts/][Archive]] Submit 

Cape

Published Mar 13, 2022 | 1461 words, 7 minutes
[[https://kristofferbalintona.me/categories/guides/][Guides]] [[https://kristofferbalintona.me/tags/emacs/][Emacs]]
Table of Contents

• [[https://kristofferbalintona.me/posts/202203130102/#what-is-cape][What is cape?]]
• [[https://kristofferbalintona.me/posts/202203130102/#basic-usage-keybinds][Basic usage: keybinds]]
• [[https://kristofferbalintona.me/posts/202203130102/#adding-backends-to-completion-at-point-functions][Adding backends to completion-at-point-functions]]
• [[https://kristofferbalintona.me/posts/202203130102/#cape-company-to-capf-and-cape-super-capf][Cape-company-to-capf and cape-super-capf]]
• [[https://kristofferbalintona.me/posts/202203130102/#pcomplete-nicety][pcomplete nicety]]
• [[https://kristofferbalintona.me/posts/202203130102/#my-completion-at-point-functions][My completion-at-point-functions]]
• [[https://kristofferbalintona.me/posts/202203130102/#changelog][Changelog]]

What is cape?

I will be going over the basic usages of [[https://github.com/minad/cape][Cape]], namely how to add
completion functions to completion-at-point-functions and how to use
cape's built-in completion utilities (e.g. cape-company-to-capf and
cape-capf-buster) to create backends with desired behavior. (Also see
[[https://www.reddit.com/r/emacs/comments/td0nth/comment/i0hz6re/][u/JDRiverRun’s informative comment]] about the advantages of using
completion-at-point-functions over company.)

Cape is to corfu as company-backends are to company:

    Cape provides a bunch of Completion At Point Extensions which can be
    used in combination with my Corfu completion UI or the default
    completion UI. The completion backends used by completion-at-point
    are so called completion-at-point-functions (Capfs). In principle,
    the Capfs provided by Cape can also be used by Company.

Consequently, cape is only used if you utilize the built-in
completion-at-point, which is best complemented by corfu text-completion
[[https://kristofferbalintona.me/posts/202203130102/#fn:1][1]].

You can also see the list of built-in completion-at-point-functions in
[[https://github.com/minad/cape#available-capfs][the README]]. Several of these completion-at-point-functions are quite
niche but others, such as cape-file and cape-symbol have common use
cases.

Note: I use straight.el for package management and general.el to set my
keybindings. Both of these packages have integration with use-package
which come in the form of the :straight and :general keywords,
respectively.

Basic usage: keybinds

The most basic way to use cape is to bind its built-in
completion-at-point-functions to their own keys. For instance:

  1  (use-package cape  
  2    :general (:prefix "M-c"              ; Choose a particular completion function  
  3                      "p" 'completion-at-point  
  4                      "t" 'complete-tag   ; etags  
  5                      "d" 'cape-dabbrev   ; basically `dabbrev-completion'  
  6                      "f" 'cape-file  
  7                      "k" 'cape-keyword  
  8                      "s" 'cape-symbol  
  9                      "a" 'cape-abbrev  
 10                      "i" 'cape-ispell  
 11                      "l" 'cape-line  
 12                      "w" 'cape-dict  
 13                      "\\" 'cape-tex  
 14                      "_" 'cape-tex  
 15                      "^" 'cape-tex  
 16                      "&" 'cape-sgml  
 17                      "r" 'cape-rfc1345))  

Additionally, if having completion-at-point-functions readily available
through keybinds is desirable, then one can use cape-interactive-capf to
turn an already existing completion-at-point-function into a command
(i.e. interactive function) that can be bound.

Adding backends to completion-at-point-functions

However, cape is powerful because these functions can be added to
completion-at-point-functions, meaning you can configure when each
functions is used and where. The simplest way to accomplish this is by
adding backends to completion-at-point-functions in a hook. Here is a
simple example:

 1  (defun kb/cape-capf-setup-git-commit ()  
 2    (let ((result))  
 3      (dolist (element '(cape-symbol cape-dabbrev) result)  
 4        (add-to-list 'completion-at-point-functions element))))  

I then add this to the appropriate hook:

 1  :hook (git-commit-mode . kb/cape-capf-setup-git-commit)  

Consequently, when making commits to git, via magit, for instance,
completion-at-point-functions looks like this[[https://kristofferbalintona.me/posts/202203130102/#fn:2][2]]:

 1  '(cape-symbol  
 2    cape-dabbrev  
 3    tags-completion-at-point-function)  

There are a few additional things to keep in mind when adding backends
to completion-function-at-point:

1 add-to-list prepends elements to a list, that is, place an element at
  the front of a list[[https://kristofferbalintona.me/posts/202203130102/#fn:3][3]].
2 add-to-list is almost always preferable to push because push adds an
  element to a list even if it already in the list, whereas add-to-list
  will not.
3 Elements earlier in dolist will be added to the list before later
  elements. This means that elements which should be deeper within
  completion-at-point-functions should be placed first. (Notice how
  cape-dabbrev is added after cape-symbol.)

Cape-company-to-capf and cape-super-capf

I think the killer feature of cape is cape-company-to-capf. This
function is able to convert any company backend and convert it into a
completion-at-point-function which corfu can use[[https://kristofferbalintona.me/posts/202203130102/#fn:4][4]]. For this reason, I
regard cape as quite an underrated package since it achieves almost full
feature parity with company. Here is an example with company-yasnippet:

 1  (defun kb/cape-capf-setup-lsp ()  
 2    "Replace the default `lsp-completion-at-point' with its  
 3  `cape-capf-buster' version. Also add `cape-file' and  
 4  `company-yasnippet' backends."  
 5    (setf (elt (cl-member 'lsp-completion-at-point completion-at-point-functions) 0)  
 6          (cape-capf-buster #'lsp-completion-at-point))  
 7    (add-to-list 'completion-at-point-functions (cape-company-to-capf #'company-yasnippet))  
 8    (add-to-list 'completion-at-point-functions #'cape-dabbrev t))  

Another useful function is cape-super-capf. This function combines
multiple completion-at-point-functions into a single function.
Effectively, this means candidates from multiple backends can appear
jointly. For instance, one can combine cape-ispell and cape-dabbrev:

  1  (defun kb/cape-capf-setup-org ()  
  2    (require 'org-roam)  
  3    (if (org-roam-file-p)  
  4        (org-roam--register-completion-functions-h)  
  5      (let (result)  
  6        (dolist (element (list  
  7                          (cape-super-capf #'cape-ispell #'cape-dabbrev)  
  8                          (cape-company-to-capf #'company-yasnippet))  
  9                         result)  
 10          (add-to-list 'completion-at-point-functions element)))  
 11      ))  

For other cape transformers, see the [[https://github.com/minad/cape#other-capf-transformers][appropriate section of the README]].

pcomplete nicety

Finally, I have the following advice to make usage with pcomplete, what
eshell uses for completion:

  1  :config  
  2  ;; For pcomplete. For now these two advices are strongly recommended to  
  3  ;; achieve a sane Eshell experience. See  
  4  ;; https://github.com/minad/corfu#completing-with-corfu-in-the-shell-or-eshell  
  5    
  6  ;; Silence the pcomplete capf, no errors or messages!  
  7  (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent)  
  8  ;; Ensure that pcomplete does not write to the buffer and behaves as a pure  
  9  ;; `completion-at-point-function'.  
 10  (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify)  

My completion-at-point-functions

I have very hesitantly included my WIP code which leverages cape and
completion-at-point utilities. I have not described in detail each of
the following functions. I have, however, attempted to provide useful
docstrings and comments.

I hesitate to publish this code because it was very haphazardly written
and highly dependent on my configuration. The reason for this is the
order in which the completion-at-point-functions are added: any
peculiarities in another’s configuration may lead to undesirable
results. As a result, do not directly copy-and-paste this code and
expect proper functionality. Rather, I put it here as a reference for
what can be done.

Here they are
Warning! This code may produce undesirable effects! Copy at your own
risk.

   1  (use-package cape  
   2    :hook ((emacs-lisp-mode .  kb/cape-capf-setup-elisp)  
   3           (lsp-completion-mode . kb/cape-capf-setup-lsp)  
   4           (org-mode . kb/cape-capf-setup-org)  
   5           (eshell-mode . kb/cape-capf-setup-eshell)  
   6           (git-commit-mode . kb/cape-capf-setup-git-commit)  
   7           (LaTeX-mode . kb/cape-capf-setup-latex)  
   8           (sh-mode . kb/cape-capf-setup-sh)  
   9           )  
  10    :general (:prefix "M-c"               ; Particular completion function  
  11                      "p" 'completion-at-point  
  12                      "t" 'complete-tag           ; etags  
  13                      "d" 'cape-dabbrev           ; or dabbrev-completion  
  14                      "f" 'cape-file  
  15                      "k" 'cape-keyword  
  16                      "s" 'cape-symbol  
  17                      "a" 'cape-abbrev  
  18                      "i" 'cape-ispell  
  19                      "l" 'cape-line  
  20                      "w" 'cape-dict  
  21                      "\\"' cape-tex  
  22                      "_" 'cape-tex  
  23                      "^" 'cape-tex  
  24                      "&" 'cape-sgml  
  25                      "r" 'cape-rfc1345  
  26                      )  
  27    :custom  
  28    (cape-dabbrev-min-length 3)  
  29    :init  
  30    ;; Elisp  
  31    (defun kb/cape-capf-ignore-keywords-elisp (cand)  
  32      "Ignore keywords with forms that begin with \":\" (e.g.  
  33  :history)."  
  34      (or (not (keywordp cand))  
  35          (eq (char-after (car completion-in-region--data)) ?:)))  
  36    (defun kb/cape-capf-setup-elisp ()  
  37      "Replace the default `elisp-completion-at-point'  
  38  completion-at-point-function. Doing it this way will prevent  
  39  disrupting the addition of other capfs (e.g. merely setting the  
  40  variable entirely, or adding to list).  
  41    
  42  Additionally, add `cape-file' as early as possible to the list."  
  43      (setf (elt (cl-member 'elisp-completion-at-point completion-at-point-functions) 0)  
  44            #'elisp-completion-at-point)  
  45      (add-to-list 'completion-at-point-functions #'cape-symbol)  
  46      ;; I prefer this being early/first in the list  
  47      (add-to-list 'completion-at-point-functions #'cape-file)  
  48      (require 'company-yasnippet)  
  49      (add-to-list 'completion-at-point-functions (cape-company-to-capf #'company-yasnippet)))  
  50    
  51    ;; LSP  
  52    (defun kb/cape-capf-setup-lsp ()  
  53      "Replace the default `lsp-completion-at-point' with its  
  54  `cape-capf-buster' version. Also add `cape-file' and  
  55  `company-yasnippet' backends."  
  56      (setf (elt (cl-member 'lsp-completion-at-point completion-at-point-functions) 0)  
  57            (cape-capf-buster #'lsp-completion-at-point))  
  58      ;; TODO 2022-02-28: Maybe use `cape-wrap-predicate' to have candidates  
  59      ;; listed when I want?  
  60      (add-to-list 'completion-at-point-functions (cape-company-to-capf #'company-yasnippet))  
  61      (add-to-list 'completion-at-point-functions #'cape-dabbrev t))  
  62    
  63    ;; Org  
  64    (defun kb/cape-capf-setup-org ()  
  65      (require 'org-roam)  
  66      (if (org-roam-file-p)  
  67          (org-roam--register-completion-functions-h)  
  68        (let (result)  
  69          (dolist (element (list  
  70                            (cape-super-capf #'cape-ispell #'cape-dabbrev)  
  71                            (cape-company-to-capf #'company-yasnippet))  
  72                           result)  
  73            (add-to-list 'completion-at-point-functions element)))  
  74        ))  
  75    
  76    ;; Eshell  
  77    (defun kb/cape-capf-setup-eshell ()  
  78      (let ((result))  
  79        (dolist (element '(pcomplete-completions-at-point cape-file) result)  
  80          (add-to-list 'completion-at-point-functions element))  
  81        ))  
  82    
  83    ;; Git-commit  
  84    (defun kb/cape-capf-setup-git-commit ()  
  85      (general-define-key  
  86       :keymaps 'local  
  87       :states 'insert  
  88       "<tab>" 'completion-at-point)      ; Keybinding for `completion-at-point'  
  89      (let ((result))  
  90        (dolist (element '(cape-dabbrev cape-symbol) result)  
  91          (add-to-list 'completion-at-point-functions element))))  
  92    
  93    ;; LaTeX  
  94    (defun kb/cape-capf-setup-latex ()  
  95      (require 'company-auctex)  
  96      (let ((result))  
  97        (dolist (element (list  
  98                          ;; First add `company-yasnippet'  
  99                          (cape-company-to-capf #'company-yasnippet)  
 100                          ;; Then add `cape-tex'  
 101                          #'cape-tex  
 102                          ;; Then add `company-auctex' in the order it adds its  
 103                          ;; backends.  
 104                          (cape-company-to-capf #'company-auctex-bibs)  
 105                          (cape-company-to-capf #'company-auctex-labels)  
 106                          (cape-company-to-capf  
 107                           (apply-partially #'company--multi-backend-adapter  
 108                                            '(company-auctex-macros company-auctex-symbols company-auctex-environments))))  
 109                         result)  
 110          (add-to-list 'completion-at-point-functions element))))  
 111    
 112    
 113    ;; Sh  
 114    (defun kb/cape-capf-setup-sh ()  
 115      (require 'company-shell)  
 116      (add-to-list 'completion-at-point-functions (cape-company-to-capf #'company-shell)))  
 117    :config  
 118    ;; For pcomplete. For now these two advices are strongly recommended to  
 119    ;; achieve a sane Eshell experience. See  
 120    ;; https://github.com/minad/corfu#completing-with-corfu-in-the-shell-or-eshell  
 121    
 122    ;; Silence the pcomplete capf, no errors or messages!  
 123    (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent)  
 124    ;; Ensure that pcomplete does not write to the buffer and behaves as a pure  
 125    ;; `completion-at-point-function'.  
 126    (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify))  
------------------------------------------------------------------------

Changelog

• March 13, 2022

  • Fixed typo. Added link to [[https://www.reddit.com/r/emacs/comments/td0nth/comment/i0hz6re/][u/JDRiverRun’s informative Reddit comment]].

------------------------------------------------------------------------

1 See [[https://kristofferbalintona.me/posts/202202270056/][Corfu, Kind-icon, and Corfu-doc]] to see the basic usage of corfu
  and several accessory packages. [[https://kristofferbalintona.me/posts/202203130102/#fnref:1][↩︎]]

2 tags-completion-at-point-function is a default
  completion-at-point-function [[https://kristofferbalintona.me/posts/202203130102/#fnref:2][↩︎]]

3 See its docstring to learn how to append to a list [[https://kristofferbalintona.me/posts/202203130102/#fnref:3][↩︎]]

4 This feature is currently listed as experimental but, for the most
  part, the results are as expected. If anything, rare edge cases are
  the only points of missing functionality. [[https://kristofferbalintona.me/posts/202203130102/#fnref:4][↩︎]]

Cross-references from other posts

The posts below reference the current post:

• [[https://kristofferbalintona.me/posts/202108102130/][Windows]]
• [[https://kristofferbalintona.me/posts/202112071230/][The "Great Books Idea" and liberal versus general education]]
• [[https://kristofferbalintona.me/posts/202202211546/][Vertico, Marginalia, All-the-icons-completion, and Orderless]]
• [[https://kristofferbalintona.me/posts/202202270056/][Corfu, Kind-icon, and Corfu-doc]]
• [[https://kristofferbalintona.me/posts/202206141852/][Citations in org-mode: Org-cite and Citar]]
• [[https://kristofferbalintona.me/posts/202301101610/][Think: A compelling introduction to philosophy by Simon Blackburn]]

------------------------------------------------------------------------

The Text Completion and Minibuffer UI series

This post is just one installation of the Text Completion and Minibuffer
UI series. Below are all the posts in this series:

1 [[https://kristofferbalintona.me/posts/202202211546/][Vertico, Marginalia, All-the-icons-completion, and Orderless]]
2 [[https://kristofferbalintona.me/posts/202202270056/][Corfu, Kind-icon, and Corfu-doc]]
3 [[https://kristofferbalintona.me/posts/202203130102/][Cape]] this post!
4 [[https://kristofferbalintona.me/posts/202504050923/][Complement corfu, vertico, and completion-preview with prescient.el
  sorting]]

[[https://kristofferbalintona.me/][Home]] [[https://kristofferbalintona.me/index.xml][RSS]] [[https://kristofferbalintona.me/tags/][Tags]] [[https://kristofferbalintona.me/categories/][Categories]] [[https://kristofferbalintona.me/series/]]Series
** Consider Switching to Corfu from Company
URL: https://kristofferbalintona.me/posts/202202270056/
Captured On:[2025-09-23 Tue 01:39]
[[https://kristofferbalintona.me/][Kristoffer Balintona]]
[[https://kristofferbalintona.me/posts/][Archive]] Submit 

Corfu, Kind-icon, and Corfu-doc

Published Feb 27, 2022, last updated Mar 11, 2022 | 2261 words, 11
minutes
[[https://kristofferbalintona.me/categories/guides/][Guides]] [[https://kristofferbalintona.me/tags/emacs/][Emacs]]
Table of Contents

• [[https://kristofferbalintona.me/posts/202202270056/#synopsis][Synopsis]]
• [[https://kristofferbalintona.me/posts/202202270056/#corfu][Corfu]]

  • [[https://kristofferbalintona.me/posts/202202270056/#what-is-corfu-how-does-it-differ-from-company][What is corfu? How does it differ from company?]]
  • [[https://kristofferbalintona.me/posts/202202270056/#basic][Basic]]
  • [[https://kristofferbalintona.me/posts/202202270056/#working-with-the-recent-changes-to-corfu][Working with the recent changes to corfu]]
  • [[https://kristofferbalintona.me/posts/202202270056/#further-configuration-in-minibuffers-and-with-lsp][Further configuration in minibuffers and with lsp]]
  • [[https://kristofferbalintona.me/posts/202202270056/#end-product][End product]]

• [[https://kristofferbalintona.me/posts/202202270056/#kind-icon][Kind-icon]]
• [[https://kristofferbalintona.me/posts/202202270056/#corfu-doc][Corfu-doc]]
• [[https://kristofferbalintona.me/posts/202202270056/#changelog][Changelog]]

November 28, 2022 As is noted in the [[https://github.com/galeo/corfu-doc/issues/25][corfu-doc repository]], corfu-doc has
been deprecated by the built-in corfu-popupinfo corfu extension.
corfu-popupinfo’s functionality is roughly identical to corfu-doc’s,
though its interface and code is naturally more idiomatic to corfu.

Synopsis

I will be going over my personal Emacs' text completion (e.g.
company-mode and its accessories) configuration, which includes the
following packages:

• [[https://github.com/minad/corfu][Corfu]] by Minad — simpler alternative to company-mode
• [[https://github.com/jdtsmith/kind-icon][Kind-icon]] by jdtsmith (u/JDRiverRun)— add icons to corfu popup (analog
  to company-box-icons)
• [[https://github.com/galeo/corfu-doc][Corfu-doc]] by Galeo — add documentation popup for corfu candidates
  (analog to company-box-doc)

Note: I use straight.el for package management and general.el to set my
keybindings. Both of these packages have integration with use-package
which come in the form of the :straight and :general keywords,
respectively.

Corfu

What is corfu? How does it differ from company?

Figure 1: The default corfu popup window. The GIF&rsquo;s framerate is
low, which makes corfu appear less performant here than in actuality.

Corfu is a text completion (e.g. completion-at-point, company-mode)
package. In my opinion, since its release, corfu has not gotten the
attention that it deserves. I prefer it to company for the following
reasons:

1 It is easier to configure since corfu’s internals rely on the built-in
  completion-at-point. This also means that, unlike company,[[https://kristofferbalintona.me/posts/202202270056/#fn:1][1]]…

  • any built-in invocation of completion-at-point or
    completion-in-region leverages corfu,
  • and any completion-style (e.g. orderless) can be used for filtering
    candidates.

2 Corfu has been more performant (i.e. fewer stutters, smoother cycling
  of candidates) in my experience.
3 Corfu can support any company backend via cape-company-to-capf,
  provided by the complementary cape package. Thus, packages like
  company-yasnippet can be used with corfu easily (see the next post in
  my Text completion and minibuffer UI series for more details and
  examples.)

Basic

The following is a basic corfu configuration with my preferred keybinds:

  1  (use-package corfu  
  2    :general  
  3    (:keymaps 'corfu-map  
  4              :states 'insert  
  5              "C-n" #'corfu-next  
  6              "C-p" #'corfu-previous  
  7              "<escape>" #'corfu-quit  
  8              "<return>" #'corfu-insert  
  9              "M-d" #'corfu-show-documentation  
 10              "M-l" #'corfu-show-location)  
 11    :config  
 12    (corfu-global-mode))  

These keybinds have C-n and C-p move through the candidates popup,
<return> choose the current candidate, and <escape> close the corfu
popup. Moreover, I have corfu’s documentation command
(corfu-show-documentation; shows the available documentation for the
current candidate, if any) bound to M-d, and corfu’s location command
(corfu-show-location) to go to the location of the current candidate to
M-l.

Corfu offers a few variables to configure. You can take a look at each
docstring to see its function. Here are my preferences:

  1  :custom  
  2  (corfu-auto nil)        ; Only use `corfu' when calling `completion-at-point' or  
  3                                          ; `indent-for-tab-command'  
  4  (corfu-auto-prefix 2)  
  5  (corfu-auto-delay 0.25)  
  6    
  7  (corfu-min-width 80)  
  8  (corfu-max-width corfu-min-width)       ; Always have the same width  
  9  (corfu-count 14)  
 10  (corfu-scroll-margin 4)  
 11  (corfu-cycle nil)  
 12    
 13  ;; `nil' means to ignore `corfu-separator' behavior, that is, use the older  
 14  ;; `corfu-quit-at-boundary' = nil behavior. Set this to separator if using  
 15  ;; `corfu-auto' = `t' workflow (in that case, make sure you also set up  
 16  ;; `corfu-separator' and a keybind for `corfu-insert-separator', which my  
 17  ;; configuration already has pre-prepared). Necessary for manual corfu usage with  
 18  ;; orderless, otherwise first component is ignored, unless `corfu-separator'  
 19  ;; is inserted.  
 20  (corfu-quit-at-boundary nil)  
 21  (corfu-preselect-first t)        ; Preselect first candidate?  
 22    
 23  ;; Other  
 24  ;; NOTE 2022-02-05: In my actual configuration, I have this variable set to nil  
 25  ;; since I use `corfu-doc', whose configuration comes later. But if you don't  
 26  ;; use `corfu-doc', this might be helpful to you.  
 27  (corfu-echo-documentation t)            ; Show documentation in echo area?  
 28    

Additionally, the following two variables not under corfu but related to
completion-at-point will be useful to set:

 1  ;; Works with `indent-for-tab-command'. Make sure tab doesn't indent when you  
 2  ;; want to perform completion  
 3  (tab-always-indent 'complete)  
 4  (completion-cycle-threshold nil)      ; Always show all candidates in popup menu  

Working with the recent changes to corfu

On [[https://github.com/minad/corfu/commit/91feb66630eea6f36fee10576760c219896c1d05][February 7, 2022]], corfu introduced an important change[[https://kristofferbalintona.me/posts/202202270056/#fn:2][2]], particularly
the interaction between corfu and orderless. You can read more [[https://github.com/minad/corfu#orderless-completion][on their
README]], but, essentially, orderless now introduces the
corfu-insert-separator command that inserts the corfu-separator
character into the buffer. This character is what delimits orderless
components (see [[https://www.reddit.com/r/emacs/comments/t38kkh/comment/hytmcpg/][this Reddit comment]] for a more lengthy description of
this behavior.) A corfu workflow in which corfu-auto is set to t
leverages this change, for without it users could not realistically use
corfu with a multi-component completion-style like orderless.

I do not use this workflow[[https://kristofferbalintona.me/posts/202202270056/#fn:3][3]], but if this behavior is desirable, you can
set corfu-separator to your orderless separator character to properly
delimit orderless components. I personally use the regular space
character. You can make the following modifications to your
configuration:

  1  :general  
  2  ;; NOTE 2022-02-28: `general-override-mode-map' is necessary to override local  
  3  ;; binds to SPC in evil-mode's insert mode. May not be necessary if you don't use `evil'  
  4  (:keymaps 'corfu-map  
  5            :states 'insert  
  6            "H-SPC" #'corfu-insert-separator ; I have a hyper key so this is an alternative keybind I use sometimes  
  7            "SPC" #'corfu-insert-separator)  
  8  :custom  
  9  (corfu-quit-at-boundary 'separator)     ; a non-nil value is necessary  
 10  (corfu-separator ?\s)                   ; Use space  
 11  (corfu-quit-no-match 'separator) ; Don't quit if there is `corfu-separator' inserted  
 12  (corfu-preview-current 'insert)  ; Preview current candidate?  
 13  :config  
 14  ;; NOTE 2022-03-01: This allows for a more evil-esque way to have  
 15  ;; `corfu-insert-separator' work with space in insert mode without resorting to  
 16  ;; overriding keybindings with `general-override-mode-map'. See  
 17  ;; https://github.com/minad/corfu/issues/12#issuecomment-869037519  
 18  ;; Alternatively, add advice without `general.el':  
 19  ;; (advice-add 'corfu--setup :after 'evil-normalize-keymaps)  
 20  ;; (advice-add 'corfu--teardown :after 'evil-normalize-keymaps)  
 21  (general-add-advice '(corfu--setup corfu--teardown) :after 'evil-normalize-keymaps)  
 22  (evil-make-overriding-map corfu-map)  

Further configuration in minibuffers and with lsp

Corfu’s [[https://github.com/minad/corfu#completing-with-corfu-in-the-minibuffer][README]] provides a way to be able to use corfu completion in the
minibuffer:

  1  ;; Enable Corfu more generally for every minibuffer, as long as no other  
  2  ;; completion UI is active. If you use Mct or Vertico as your main minibuffer  
  3  ;; completion UI. From  
  4  ;; https://github.com/minad/corfu#completing-with-corfu-in-the-minibuffer  
  5  (defun corfu-enable-always-in-minibuffer ()  
  6    "Enable Corfu in the minibuffer if Vertico/Mct are not active."  
  7    (unless (or (bound-and-true-p mct--active) ; Useful if I ever use MCT  
  8                (bound-and-true-p vertico--input))  
  9      (setq-local corfu-auto nil)       ; Ensure auto completion is disabled  
 10      (corfu-mode 1)))  
 11  (add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1)  

This means that in commands like eval-expression, corfu is able to be
used (via <tab>) and provide completion.

Figure 2: Using corfu in the minibuffer prompt for eval-expression.

Figure 2: Using corfu in the minibuffer prompt for eval-expression.

Additionally, for lsp-mode buffers, I have the following lines (this is
entirely optional and preferential):

  1  :hook (lsp-completion-mode . kb/corfu-setup-lsp) ; Use corfu for lsp completion  
  2  :custom  
  3  (lsp-completion-provider :none) ; Use corfu instead the default for lsp completions  
  4  :config  
  5  ;; Setup lsp to use corfu for lsp completion  
  6  (defun kb/corfu-setup-lsp ()  
  7    "Use orderless completion style with lsp-capf instead of the  
  8    default lsp-passthrough."  
  9    (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))  
 10          '(orderless)))  

End product

Putting it together, we end with my actual configuration:

  1  (use-package corfu  
  2    :hook (lsp-completion-mode . kb/corfu-setup-lsp) ; Use corfu for lsp completion  
  3    :general  
  4    (:keymaps 'corfu-map  
  5              :states 'insert  
  6              "C-n" #'corfu-next  
  7              "C-p" #'corfu-previous  
  8              "<escape>" #'corfu-quit  
  9              "<return>" #'corfu-insert  
 10              "H-SPC" #'corfu-insert-separator  
 11              ;; "SPC" #'corfu-insert-separator ; Use when `corfu-quit-at-boundary' is non-nil  
 12              "M-d" #'corfu-show-documentation  
 13              "C-g" #'corfu-quit  
 14              "M-l" #'corfu-show-location)  
 15    :custom  
 16    ;; Works with `indent-for-tab-command'. Make sure tab doesn't indent when you  
 17    ;; want to perform completion  
 18    (tab-always-indent 'complete)  
 19    (completion-cycle-threshold nil)      ; Always show candidates in menu  
 20    
 21    (corfu-auto nil)  
 22    (corfu-auto-prefix 2)  
 23    (corfu-auto-delay 0.25)  
 24    
 25    (corfu-min-width 80)  
 26    (corfu-max-width corfu-min-width)     ; Always have the same width  
 27    (corfu-count 14)  
 28    (corfu-scroll-margin 4)  
 29    (corfu-cycle nil)  
 30    
 31    ;; `nil' means to ignore `corfu-separator' behavior, that is, use the older  
 32    ;; `corfu-quit-at-boundary' = nil behavior. Set this to separator if using  
 33    ;; `corfu-auto' = `t' workflow (in that case, make sure you also set up  
 34    ;; `corfu-separator' and a keybind for `corfu-insert-separator', which my  
 35    ;; configuration already has pre-prepared). Necessary for manual corfu usage with  
 36    ;; orderless, otherwise first component is ignored, unless `corfu-separator'  
 37    ;; is inserted.  
 38    (corfu-quit-at-boundary nil)  
 39    (corfu-separator ?\s)            ; Use space  
 40    (corfu-quit-no-match 'separator) ; Don't quit if there is `corfu-separator' inserted  
 41    (corfu-preview-current 'insert)  ; Preview first candidate. Insert on input if only one  
 42    (corfu-preselect-first t)        ; Preselect first candidate?  
 43    
 44    ;; Other  
 45    (corfu-echo-documentation nil)        ; Already use corfu-doc  
 46    (lsp-completion-provider :none)       ; Use corfu instead for lsp completions  
 47    :init  
 48    (corfu-global-mode)  
 49    :config  
 50    ;; NOTE 2022-03-01: This allows for a more evil-esque way to have  
 51    ;; `corfu-insert-separator' work with space in insert mode without resorting to  
 52    ;; overriding keybindings with `general-override-mode-map'. See  
 53    ;; https://github.com/minad/corfu/issues/12#issuecomment-869037519  
 54    ;; Alternatively, add advice without `general.el':  
 55    ;; (advice-add 'corfu--setup :after 'evil-normalize-keymaps)  
 56    ;; (advice-add 'corfu--teardown :after 'evil-normalize-keymaps)  
 57    (general-add-advice '(corfu--setup corfu--teardown) :after 'evil-normalize-keymaps)  
 58    (evil-make-overriding-map corfu-map)  
 59    
 60    ;; Enable Corfu more generally for every minibuffer, as long as no other  
 61    ;; completion UI is active. If you use Mct or Vertico as your main minibuffer  
 62    ;; completion UI. From  
 63    ;; https://github.com/minad/corfu#completing-with-corfu-in-the-minibuffer  
 64    (defun corfu-enable-always-in-minibuffer ()  
 65      "Enable Corfu in the minibuffer if Vertico/Mct are not active."  
 66      (unless (or (bound-and-true-p mct--active) ; Useful if I ever use MCT  
 67                  (bound-and-true-p vertico--input))  
 68        (setq-local corfu-auto nil)       ; Ensure auto completion is disabled  
 69        (corfu-mode 1)))  
 70    (add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1)  
 71    
 72    ;; Setup lsp to use corfu for lsp completion  
 73    (defun kb/corfu-setup-lsp ()  
 74      "Use orderless completion style with lsp-capf instead of the  
 75  default lsp-passthrough."  
 76      (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))  
 77            '(orderless))))  

Kind-icon

Kind-icon is essentially company-box-icons for corfu. It adds icons to
the left margin of the corfu popup that represent the ‘function’ (e.g.
variable, method, file) of that candidate.

Figure 3: Using corfu-doc in java-mode with completion candidates
provided by lsp-mode.

Figure 3: Using corfu-doc in java-mode with completion candidates
provided by lsp-mode.

The following is my configuration:

  1  (use-package kind-icon  
  2    :after corfu  
  3    :custom  
  4    (kind-icon-use-icons t)  
  5    (kind-icon-default-face 'corfu-default) ; Have background color be the same as `corfu' face background  
  6    (kind-icon-blend-background nil)  ; Use midpoint color between foreground and background colors ("blended")?  
  7    (kind-icon-blend-frac 0.08)  
  8    
  9    ;; NOTE 2022-02-05: `kind-icon' depends `svg-lib' which creates a cache  
 10    ;; directory that defaults to the `user-emacs-directory'. Here, I change that  
 11    ;; directory to a location appropriate to `no-littering' conventions, a  
 12    ;; package which moves directories of other packages to sane locations.  
 13    (svg-lib-icons-dir (no-littering-expand-var-file-name "svg-lib/cache/")) ; Change cache dir  
 14    :config  
 15    (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter) ; Enable `kind-icon'  
 16    
 17    ;; Add hook to reset cache so the icon colors match my theme  
 18    ;; NOTE 2022-02-05: This is a hook which resets the cache whenever I switch  
 19    ;; the theme using my custom defined command for switching themes. If I don't  
 20    ;; do this, then the backgound color will remain the same, meaning it will not  
 21    ;; match the background color corresponding to the current theme. Important  
 22    ;; since I have a light theme and dark theme I switch between. This has no  
 23    ;; function unless you use something similar  
 24    (add-hook 'kb/themes-hooks #'(lambda () (interactive) (kind-icon-reset-cache))))  

Corfu-doc

Corfu-doc is basically company-quickhelp for corfu. It shows the
documentation of the selected candidate in an adjacent popup window.

Figure 4: Using corfu-doc in a corfu popup. Called from a java file with
completion candidates provided by lsp-mode.

Figure 4: Using corfu-doc in a corfu popup. Called from a java file with
completion candidates provided by lsp-mode.

Here is a sample configuration[[https://kristofferbalintona.me/posts/202202270056/#fn:4][4]]:

  1  (use-package corfu-doc  
  2    ;; NOTE 2022-02-05: At the time of writing, `corfu-doc' is not yet on melpa  
  3    :straight (corfu-doc :type git :host github :repo "galeo/corfu-doc")  
  4    :after corfu  
  5    :hook (corfu-mode . corfu-doc-mode)  
  6    :general (:keymaps 'corfu-map  
  7                       ;; This is a manual toggle for the documentation popup.  
  8                       [remap corfu-show-documentation] #'corfu-doc-toggle ; Remap the default doc command  
  9                       ;; Scroll in the documentation window  
 10                       "M-n" #'corfu-doc-scroll-up  
 11                       "M-p" #'corfu-doc-scroll-down)  
 12    :custom  
 13    (corfu-doc-delay 0.5)  
 14    (corfu-doc-max-width 70)  
 15    (corfu-doc-max-height 20)  
 16    
 17    ;; NOTE 2022-02-05: I've also set this in the `corfu' use-package to be  
 18    ;; extra-safe that this is set when corfu-doc is loaded. I do not want  
 19    ;; documentation shown in both the echo area and in the `corfu-doc' popup.  
 20    (corfu-echo-documentation nil))  

From my experience, corfu-doc is perfect for most. However, it should be
noted that for those who have a high [[https://wiki.archlinux.org/title/Xorg/Keyboard_configuration#Adjusting_typematic_delay_and_rate][repeat rate]][[https://kristofferbalintona.me/posts/202202270056/#fn:5][5]], rapidly scrolling
through candidates causes stuttering and/or lag. This is why I find
setting a keybind for corfu-doc-toggle to be useful.

------------------------------------------------------------------------

Changelog

• February 28, 2022

  • Added link to Reddit comment in [[https://kristofferbalintona.me/posts/202202270056/#working-with-the-recent-changes-to-corfu][Working with the recent changes to
    corfu]] section. Also update description of new corfu behavior.
  • Added configuration for using corfu in the minibuffer.
  • Listed more benefits to corfu, provided by u/JDRiverRun.

• March 01, 2022

  • Added link to relevant corfu GitHub Issue.
  • Changed corfu configuration to avoid setting keybinds in
    general-override-mode-map, suggested by a comment to this point.
  • Added a note and GIF to corfu-doc section.

• March 11, 2022

  • Update to include new compatibility with corfu-insert-separator and
    corfu-quit-at-boundary functionality.

------------------------------------------------------------------------

1 Kudos to u/JDRiverRun, the current maintainer of kind-icon for
  [[https://www.reddit.com/r/emacs/comments/t38kkh/comment/hyturrd/][providing a few benefits]] I didn’t originally list. [[https://kristofferbalintona.me/posts/202202270056/#fnref:1][↩︎]]

2 This change was initially motivated by jdtsmith (u/JDRiverRun) and is
  described in [[https://github.com/minad/corfu/issues/119][this GitHub issue]]. [[https://kristofferbalintona.me/posts/202202270056/#fnref:2][↩︎]]

3 See [[https://github.com/minad/corfu/commit/b71465fa6b6588babc98a1ae7034c9a41e5eaca7][this commit]]. Also see this [[https://github.com/minad/corfu/issues/138][GitHub issue]] which reimplemented the
  old corfu-quit-at-boundary functionality alongside the then new
  corfu-insert-separator functionality. [[https://kristofferbalintona.me/posts/202202270056/#fnref:3][↩︎]]

4 This is not exactly my configuration, but is quite close to it. [[https://kristofferbalintona.me/posts/202202270056/#fnref:4][↩︎]]

5 I personally use a repeat rate of 37 ms with a delay rate of 225, set
  by xset r rate 225 37. [[https://kristofferbalintona.me/posts/202202270056/#fnref:5][↩︎]]

Cross-references from other posts

The posts below reference the current post:

• [[https://kristofferbalintona.me/posts/202203130102/][Cape]]

------------------------------------------------------------------------

The Text Completion and Minibuffer UI series

This post is just one installation of the Text Completion and Minibuffer
UI series. Below are all the posts in this series:

1 [[https://kristofferbalintona.me/posts/202202211546/][Vertico, Marginalia, All-the-icons-completion, and Orderless]]
2 [[https://kristofferbalintona.me/posts/202202270056/][Corfu, Kind-icon, and Corfu-doc]] this post!
3 [[https://kristofferbalintona.me/posts/202203130102/][Cape]]
4 [[https://kristofferbalintona.me/posts/202504050923/][Complement corfu, vertico, and completion-preview with prescient.el
  sorting]]

[[https://kristofferbalintona.me/][Home]] [[https://kristofferbalintona.me/index.xml][RSS]] [[https://kristofferbalintona.me/tags/][Tags]] [[https://kristofferbalintona.me/categories/][Categories]] [[https://kristofferbalintona.me/series/]]Series
** Ensure You Have Prescient Set Up Now, Add to Corfu Later
URL: https://kristofferbalintona.me/posts/202504050923/
Captured On:[2025-09-23 Tue 01:39]
[[https://kristofferbalintona.me/][Kristoffer Balintona]]
[[https://kristofferbalintona.me/posts/][Archive]] Submit 

Complement corfu, vertico, and completion-preview with prescient.el
sorting

Published Apr 5, 2025, last updated Apr 22, 2025 | 1448 words, 7 minutes
[[https://kristofferbalintona.me/categories/tips-and-tricks/][Tips and Tricks]] [[https://kristofferbalintona.me/tags/emacs/][Emacs]]
April 07, 2025 With several commits made on April 6, 2025, vertico spun
off its sorting functionality into an extension: [[https://github.com/minad/vertico/blob/main/extensions/vertico-sort.el][vertico-sort]]. As
explained in vertico-sort.el’s commentary section, it includes a new
feature: when history-delete-duplicates is nil, all sorting functions
defined in vertico-sort.el now rank recently selected candidates above
frequently selected candidates. This approximates the sorting strategy
of prescient.el. I think I’ll stick with prescient.el sorting because I
like history-delete-duplicates set to non-nil, but try it out yourself!
April 22, 2025 Corfu now offers a similar functionality as vertic-sort
does for vertico with the new [[https://github.com/minad/corfu/blob/main/extensions/corfu-history.el][corfu-sort]] extension. Like vertico-sort,
corfu-sort requires history-delete-duplicates to be nil.

[[https://github.com/radian-software/prescient.el][Prescient.el]] is a package that was popular during the era of ivy and
helm. Nowadays, I don’t see it mentioned much because of the very
popular corfu + vertico + marginalia + orderless combination which
enhance built-in Emacs completion and overtaken ivy and helm in terms of
popularity. (And it’s deserved! I use this combination, too.)[[https://kristofferbalintona.me/posts/202504050923/#fn:1][1]] But I’ve
found prescient.el a noticeable convenience that complements this set of
packages.

The reason is prescient.el’s sorting. Roughly, we can think of
completion as having two halves: filtering and sorting. Filtering is
what completion-styles does: among the generated completion candidates,
which are shown to the user? Sorting is the order in which the filtered
candidates are shown. One might think that orderless, which is filters
candidates with its completion-style, also sorts candidates—but it
doesn’t. As explained in the [[https://github.com/oantolin/orderless?tab=readme-ov-file#prescient][orderless README]]:

    The [[https://github.com/radian-software/prescient.el][prescient.el]] library also provides matching of space-separated
    components in any order. It offers a completion-style that can be
    used with Emacs’ default completion UI, Mct, Vertico or with
    Icomplete. Furthermore Ivy is supported. The components can be
    matched literally, as regexps, as initialisms or in the flex style
    (called “fuzzy” in prescient). Prescient does not offer the same
    flexibility as Orderless with its style dispatchers. However in
    addition to matching, Prescient supports sorting of candidates,
    while Orderless leaves that up to the candidate source and the
    completion UI.

As such, in the corfu + vertico + marginalia + orderless world, vertico
(for minibuffer completions) and corfu (for in-inline completions) are
responsible for sorting candidates.

The problem is this: although orderless brilliantly narrows down
candidates, both vertico and corfu have somewhat naive sorting
algorithms (see vertico-sort-function and corfu-sort-function). Vertico
offers vertico-sort-history-alpha and vertico-sort-history-length-alpha,
and corfu offers corfu-history-mode. In my limited experience, however,
I give prescient.el’s sorting algorithm an edge to both. (YMMV—feel free
to try them!) Oftentimes vertico and corfu will consistently show the
candidate you have in mind later in the list. This tends to be the case
when using certain common commands and certain
completion-at-point-functions: I would common seek out certain
candidates that orderless would place third or fourth in the list.

Prescient.el almost entirely solved this issue for me. Prescient.el
offers a completion-style—this is its filtering functionality—but it
also offers sorting functionality. The sorting functionality is what’s
relevant here:

    When sorting, the last few candidates you selected are displayed
    first, followed by the most frequently selected ones, and then the
    remaining candidates are sorted by length.

Prescient.el is the core package, and there are several [[https://github.com/radian-software/prescient.el?tab=readme-ov-file#usage][auxiliary
packages]] to integrate prescient with vertico, corfu, and others. We can
enable prescient’s sorting for vertico and corfu (but not its filtering;
I want to leave this to orderless) with something like the following:

  1  ;; Core package  
  2  (use-package prescient  
  3    :custom  
  4    ;; My settings for relevant user options:  
  5    ;; (prescient-aggressive-file-save t)  
  6    ;; (prescient-sort-length-enable nil)  
  7    ;; (prescient-sort-full-matches-first t)  
  8    ;; (prescient-history-length 200)  
  9    ;; (prescient-frequency-decay 0.997)  
 10    ;; (prescient-frequency-threshold 0.05)  
 11    :config  
 12    ;; Optional: persist prescient statistics to an on-disk cache  
 13    ;; (`prescient-save-file')  
 14    (prescient-persist-mode 1))  
 15    
 16  ;; Integration with corfu  
 17  (use-package corfu-prescient  
 18    ;; The :after keyword defers loading this package, meaning this package is  
 19    ;; only loaded until something else wants something from it.  If we want  
 20    ;; `corfu-prescient-mode' to be enabled in the :config block, we need to  
 21    ;; prevent deferral with the :demand keyword. In combination with our :after  
 22    ;; block, the package is immediately loaded only after both corfu and  
 23    ;; prescient are loaded.  
 24    :demand t  
 25    :after corfu prescient  
 26    :custom  
 27    ;; Sorting.  These are the default values but I include them here to be  
 28    ;; explicit.  
 29    (corfu-prescient-enable-sorting t)  
 30    (corfu-prescient-override-sorting nil) ; Don't override `display-sort-function'  
 31    
 32    ;; Filtering  
 33    (corfu-prescient-enable-filtering nil) ; We want orderless to do the filtering  
 34    ;; See also `corfu-prescient-completion-styles',  
 35    ;; `corfu-prescient-completion-category-overrides' and  
 36    ;; `prescient--completion-recommended-overrides'.  Those options apply only  
 37    ;; when `corfu-prescient-enable-filtering' is non-nil.  
 38    :config  
 39    (corfu-prescient-mode 1))  
 40    
 41  ;; Integration with vertico  
 42  (use-package vertico-prescient  
 43    ;; The :after keyword defers loading this package, meaning this package is  
 44    ;; only loaded until something else wants something from it.  If we want  
 45    ;; `vertico-prescient-mode' to be enabled in the :config block, we need to  
 46    ;; prevent deferral with the :demand keyword. In combination with our :after  
 47    ;; block, the package is immediately loaded only after both vertico and  
 48    ;; prescient are loaded.  
 49    :demand t  
 50    :after vertico prescient  
 51    :custom  
 52    ;; Sorting.  These are the default values but I include them here to be  
 53    ;; explicit.  
 54    (vertico-prescient-enable-sorting t)  
 55    (vertico-prescient-override-sorting nil) ; Don't override `display-sort-function'  
 56    
 57    ;; Filtering  
 58    (vertico-prescient-enable-filtering nil) ; We want orderless to do the filtering  
 59    ;; See also `vertico-prescient-completion-styles',  
 60    ;; `vertico-prescient-completion-category-overrides', and  
 61    ;; `prescient--completion-recommended-overrides'.  Those options apply only  
 62    ;; when when `vertico-prescient-enable-filtering' is non-nil.  
 63    :config  
 64    (vertico-prescient-mode 1))  

The result is using orderless for completion filtering and prescient for
completion sorting everywhere—for in-line completions with corfu and
minibuffer completions with vertico. With this, among the candidates
filtered by orderless, the most recent and common ones will be bumped up
to the beginning. Try it out!

Bonus: integration with completion-preview-mode

Emacs 30.1 ships with the new completion-preview-mode. You can read
about it [[https://eshelyaron.com/posts/2023-11-17-completion-preview-in-emacs.html][in this blog post]] but also in the Emacs 30.1 news (i.e., C-u 30
C-h n). Apparently, completion-preview-mode has its own sorting
function—which makes sense, since it isn’t hooked into either corfu nor
vertico (which we set up to use prescient above). The relevant user
option to modify its sorting is completion-preview-sort-function. So we
just have to make sure that function matches prescient’s. We can do that
like this:

 1  (with-eval-after-load 'prescient  
 2    ;; Have `completion-preview-mode' use prescient's sorting algorithm  
 3    (setopt completion-preview-sort-function #'prescient-completion-sort))  

But, if you also use corfu on top of completion-preview-mode, you’ll
still notice a discrepancy between corfu’s first candidate and
completion-preview’s candidate. They should be the same with the same
sorting algorithm but they’re not! I’m not 100%, but I’m fairly
confident that corfu-prescient keeps track of corfu-specific completion
usage, which is separate from non-corfu-specific use. Consequently, the
statistics used to sort candidates ends up different between corfu and
prescient-completion-sort.

In any case, below is a simple fix that gets corfu and
completion-preview on the same page:

  1  ;; We set completion-preview's sorting function  
  2  ;; (`completion-preview-sort-function') to corfu's sorting function  
  3  ;; (`corfu-sort-function').  
  4  (with-eval-after-load 'corfu  
  5    (setopt completion-preview-sort-function corfu-sort-function))  
  6    
  7  ;; Alternative: for a solution that ensures `completion-preview-sort-function'  
  8  ;; always matches `corfu-sort-function', we can use a variable watcher.  This is  
  9  ;; my preference.  
 10  ;;  
 11  ;; The below accounts for cases in which (i) the user has buffer-local values  
 12  ;; for `corfu-sort-function' or (ii) the user changes the global value of  
 13  ;; `corfu-sort-function' (e.g., from minor modes that disable/enable  
 14  ;; functionality).  It is a robust solution, and although I have not tested its  
 15  ;; performance overhead, it should cause no problems.  
 16  (add-variable-watcher 'corfu-sort-function  
 17                        (lambda (_symbol newval operation where)  
 18                          "Match the value of `completion-preview-sort-function' to `corfu-sort-function'.  
 19  If `corfu-sort-function' is set buffer-locally, also set  
 20  `completion-preview-sort-function' buffer-locally.  Otherwise, change  
 21  the default value of `completion-preview-sort-function' accordingly.  
 22    
 23  This action only applies when the value of `corfu-sort-function' is  
 24  set (i.e., OPERATION is \\='set).  This excludes, e.g., let bindings."  
 25                          (when (equal operation 'set)  
 26                            (if where  
 27                                (with-current-buffer where  
 28                                  (setq-local completion-preview-sort-function newval))  
 29                              (setopt completion-preview-sort-function newval)))))  

Changelog

• April 07, 2025

  • Fixed several typos.
  • Added clarity to several phrases.
  • Added a note mentioning the new vertico-sort extension.

• April 05, 2025

  • Correction to explanation according to [[https://www.reddit.com/r/emacs/comments/1js6xvw/comment/mlkpge6/][r/JDRiverRun’s comment]].

• April 22, 2025

  • Added a note mentioning the new corfu-history extension.

------------------------------------------------------------------------

1 In my opinion, each package is much more modular than the helm or ivy
  ecosystems while being more performant, integrated with existing Emacs
  functionality, and just as useful, if not more. Though a bit dated,
  I’ve previously written a big about how to configure this set of
  packages: [[https://kristofferbalintona.me/posts/202202211546/][Vertico, Marginalia, All-the-icons-completion, and
  Orderless]]. [[https://kristofferbalintona.me/posts/202504050923/#fnref:1][↩︎]]

------------------------------------------------------------------------

The Text Completion and Minibuffer UI series

This post is just one installation of the Text Completion and Minibuffer
UI series. Below are all the posts in this series:

1 [[https://kristofferbalintona.me/posts/202202211546/][Vertico, Marginalia, All-the-icons-completion, and Orderless]]
2 [[https://kristofferbalintona.me/posts/202202270056/][Corfu, Kind-icon, and Corfu-doc]]
3 [[https://kristofferbalintona.me/posts/202203130102/][Cape]]
4 [[https://kristofferbalintona.me/posts/202504050923/][Complement corfu, vertico, and completion-preview with prescient.el
  sorting]] this post!

[[https://kristofferbalintona.me/][Home]] [[https://kristofferbalintona.me/index.xml][RSS]] [[https://kristofferbalintona.me/tags/][Tags]] [[https://kristofferbalintona.me/categories/][Categories]] [[https://kristofferbalintona.me/series/]]Series
** [[https://tsdh.org/posts/2022-08-01-difftastic-diffing-with-magit.html][Difftastic diffing with Magit]]
URL: https://tsdh.org/posts/2022-08-01-difftastic-diffing-with-magit.html
Captured On:[2025-09-07 Sun 12:38]

[[https://github.com/Wilfred/difftastic][difftastic]] is a structural diff tool that compares files based on their syntax. So for example, if you conditionalize some statement, the diff would only show the addition of one if with its condition instead of showing one line added (the if (condition)) and the line with the statement being removed and re-added (because of indentation changes). In many cases, such structural diffs transport the meaning of a change much better than the typical line-based diffs.

Of course, that comes with a price: difftastic has to understand the language's syntax (it currently supports [[https://difftastic.wilfred.me.uk/languages_supported.html][these languages]]) and computing a structural diff is a quite expensive operation. Also, there are certain kinds of changes where a line-based diff with changed-word highlighting gives better results, namely when the changed syntactic unit is a large blob with no sub-structure, e.g., a docstring or a comment.

[[https://git-scm.com/][Git]] allows to use an external diff tool in many commands by setting the environment variable GIT_EXTERNAL_DIFF=<tool> and in the following I make use of that for being able to use difftastic for git show and git diff when operating on a git repository from inside Emacs using [[https://magit.vc/][Magit]]. Because the aforementioned downsides, I want that as opt-in behavior, i.e., separate commands. Also, Magit has some assumptions on how a git diff looks like which are not met by difftastic, e.g., difftastic prints line numbers and generates side-by-side diffs for changes which are not plain additions or deletions.

So here we go. Let's first define a helper function which sets GIT_EXTERNAL_DIFF to difft (the difftastic binary), runs the given git command in
a new process asynchronously, and pops up a buffer with the result once the process finished.


(defun th/magit--with-difftastic (buffer command)
  "Run COMMAND with GIT_EXTERNAL_DIFF=difft then show result in BUFFER."
  (let ((process-environment
         (cons (concat "GIT_EXTERNAL_DIFF=difft --width="
                       (number-to-string (frame-width)))
               process-environment)))
    ;; Clear the result buffer (we might regenerate a diff, e.g., for
    ;; the current changes in our working directory).
    (with-current-buffer buffer
      (setq buffer-read-only nil)
      (erase-buffer))
    ;; Now spawn a process calling the git COMMAND.
    (make-process
     :name (buffer-name buffer)
     :buffer buffer
     :command command
     ;; Don't query for running processes when emacs is quit.
     :noquery t
     ;; Show the result buffer once the process has finished.
     :sentinel (lambda (proc event)
                 (when (eq (process-status proc) 'exit)
                   (with-current-buffer (process-buffer proc)
                     (goto-char (point-min))
                     (ansi-color-apply-on-region (point-min) (point-max))
                     (setq buffer-read-only t)
                     (view-mode)
                     (end-of-line)
                     ;; difftastic diffs are usually 2-column side-by-side,
                     ;; so ensure our window is wide enough.
                     (let ((width (current-column)))
                       (while (zerop (forward-line 1))
                         (end-of-line)
                         (setq width (max (current-column) width)))
                       ;; Add column size of fringes
                       (setq width (+ width
                                      (fringe-columns 'left)
                                      (fringe-columns 'right)))
                       (goto-char (point-min))
                       (pop-to-buffer
                        (current-buffer)
                        `(;; If the buffer is that wide that splitting the frame in
                          ;; two side-by-side windows would result in less than
                          ;; 80 columns left, ensure it's shown at the bottom.
                          ,(when (> 80 (- (frame-width) width))
                             #'display-buffer-at-bottom)
                          (window-width
                           . ,(min width (frame-width))))))))))))

The crucial parts of that helper function are that we "wash" the result using ansi-color-apply-on-region so that the difftastic highlighting
using shell escape codes is transformed to emacs faces. Also, the needed width of the possibly wide side-by-side difftastic diff is computed and
tried to be accommodated for.

Next, let's define our first command basically doing a git show for some revision which defaults to the commit or branch at point or queries
the user if there's none.


(defun th/magit-show-with-difftastic (rev)
  "Show the result of \"git show REV\" with GIT_EXTERNAL_DIFF=difft."
  (interactive
   (list (or
          ;; If REV is given, just use it.
          (when (boundp 'rev) rev)
          ;; If not invoked with prefix arg, try to guess the REV from
          ;; point's position.
          (and (not current-prefix-arg)
               (or (magit-thing-at-point 'git-revision t)
                   (magit-branch-or-commit-at-point)))
          ;; Otherwise, query the user.
          (magit-read-branch-or-commit "Revision"))))
  (if (not rev)
      (error "No revision specified")
    (th/magit--with-difftastic
     (get-buffer-create (concat "*git show difftastic " rev "*"))
     (list "git" "--no-pager" "show" "--ext-diff" rev))))

And here the second command which basically does a git diff. It tries to guess what one wants to diff, e.g., when point is on the Staged
changes section in a magit buffer, it will run git diff --cached to show a diff of all staged changes. If no context can be guessed, it'll query
the user for a range or commit for diffing.


(defun th/magit-diff-with-difftastic (arg)
  "Show the result of \"git diff ARG\" with GIT_EXTERNAL_DIFF=difft."
  (interactive
   (list (or
          ;; If RANGE is given, just use it.
          (when (boundp 'range) range)
          ;; If prefix arg is given, query the user.
          (and current-prefix-arg
               (magit-diff-read-range-or-commit "Range"))
          ;; Otherwise, auto-guess based on position of point, e.g., based on
          ;; if we are in the Staged or Unstaged section.
          (pcase (magit-diff--dwim)
            ('unmerged (error "unmerged is not yet implemented"))
            ('unstaged nil)
            ('staged "--cached")
            (`(stash . ,value) (error "stash is not yet implemented"))
            (`(commit . ,value) (format "%s^..%s" value value))
            ((and range (pred stringp)) range)
            (_ (magit-diff-read-range-or-commit "Range/Commit"))))))
  (let ((name (concat "*git diff difftastic"
                      (if arg (concat " " arg) "")
                      "*")))
    (th/magit--with-difftastic
     (get-buffer-create name)
     `("git" "--no-pager" "diff" "--ext-diff" ,@(when arg (list arg))))))

What's left is integrating these two new commands in Magit. For that purpose, I've created a new [[https://github.com/magit/transient][transient]] prefix for my personal commands.


(transient-define-prefix th/magit-aux-commands ()
  "My personal auxiliary magit commands."
  ["Auxiliary commands"
   ("d" "Difftastic Diff (dwim)" th/magit-diff-with-difftastic)
   ("s" "Difftastic Show" th/magit-show-with-difftastic)])

I want my personal commands transient to be bound to # and be shown in the Magit dispatch transient (which is bound to ? in Magit status
buffers and C-x M-g in any Magit enabled buffer) after the Run (!) transient.


(transient-append-suffix 'magit-dispatch "!"
  '("#" "My Magit Cmds" th/magit-aux-commands))

(define-key magit-status-mode-map (kbd "#") #'th/magit-aux-commands)

And that's it!

Finally, here's a screenshot showing how it looks like:

Screenshot of Magit showing a difftastic diff
** Can I display org-mode attachments as inline images in my document? - Emacs Stack Exchange
[[https://emacs.stackexchange.com/questions/18404/can-i-display-org-mode-attachments-as-inline-images-in-my-document][Can I display org-mode attachments as inline images in my document? - Emacs Stack Exchange]]
Captured On: [2025-10-16 Thu 02:20]
** rougier/relative-date: Emacs package for formatting relative dates (dates difference)
[[https://github.com/rougier/relative-date][rougier/relative-date: Emacs package for formatting relative dates (dates difference)]]
Captured On: [2025-10-17 Fri 14:23]
** rougier/pdf-drop-mode: Get DOI from PDF files dropped onto a Emacs buffer
[[https://github.com/rougier/pdf-drop-mode][rougier/pdf-drop-mode: Get DOI from PDF files dropped onto a Emacs buffer]]
Captured On: [2025-10-17 Fri 14:23]
** rougier/emacs-svg-icon: An emacs library to create SVG icons on the fly
[[https://github.com/rougier/emacs-svg-icon][rougier/emacs-svg-icon: An emacs library to create SVG icons on the fly]]
Captured On: [2025-10-17 Fri 13:44]
** rougier/org-agenda-conflict: Mark conflicting items in the org-agenda
[[https://github.com/rougier/org-agenda-conflict][rougier/org-agenda-conflict: Mark conflicting items in the org-agenda]]
Captured On: [2025-10-17 Fri 13:38]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Holidays
(require 'cal-iso)
(require 'holidays)

(defvar french-holidays nil
  "French holidays")

(setq french-holidays
      `((holiday-fixed 1 1 "New year's Day")
            (holiday-fixed 5 1 "Labour Day")
            (holiday-fixed 5 8 "Victory in Europe Day")
            (holiday-fixed 7 14 "Bastille day")
            (holiday-fixed 8 15 "Assumption of Mary")
            (holiday-fixed 11 11 "Armistice 1918")
            (holiday-fixed 11 1 "All Saints' Day")
            (holiday-fixed 12 25 "Christmas Day")
            (holiday-easter-etc 0 "Easter Sunday")
        (holiday-easter-etc 1 "Easter Monday")
        (holiday-easter-etc 39 "Ascension Day")
        (holiday-easter-etc 50 "Whit Monday")
        (holiday-sexp
         '(if (equal
               (holiday-easter-etc 49)
               (holiday-float 5 0 -1 nil))
              (car (car (holiday-float 6 0 1 nil)))
            (car (car (holiday-float 5 0 -1 nil))))
         "Mother's Day")))

(setq calendar-holidays french-holidays     ; French holidays
      calendar-week-start-day 1             ; Week starts on Monday
      calendar-mark-diary-entries-flag nil) ; Do not show diary entries

; Mark today in calendar
(add-hook 'calendar-today-visible-hook  #'calendar-mark-today)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:34]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Sorting strategy

(setq org-agenda-sorting-strategy
      '((agenda deadline-down scheduled-down todo-state-up time-up
                habit-down priority-down category-keep)
        (todo   priority-down category-keep)
        (tags   timestamp-up priority-down category-keep)
        (search category-keep)))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:33]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Babel
(setq-default org-src-fontify-natively t         ; Fontify code in code blocks.
              org-adapt-indentation nil          ; Adaptive indentation
              org-src-tab-acts-natively t        ; Tab acts as in source editing
              org-confirm-babel-evaluate nil     ; No confirmation before executing code
              org-edit-src-content-indentation 0 ; No relative indentation for code blocks
              org-fontify-whole-block-delimiter-line t) ; Fontify whole block
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:32]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Dashboard
Provide a mu4e-dashboard command that opens the mu4e dashboard on the left side.

(require 'mu4e-dashboard)
(require 'svg-lib)

(setq mu4e-dashboard-propagate-keymap nil)

(defun mu4e-dashboard ()
  "Open the mu4e dashboard on the left side."
  
  (interactive)
  (with-selected-window
      (split-window (selected-window) -34 'left)

    (find-file (expand-file-name "mu4e-dashboard.org" user-emacs-directory))
    (mu4e-dashboard-mode)
    (hl-line-mode)
    (set-window-dedicated-p nil t)
    (defvar svg-font-lock-keywords
      `(("\\!\\([\\ 0-9]+\\)\\!"
         (0 (list 'face nil 'display (svg-font-lock-tag (match-string 1)))))))
    (defun svg-font-lock-tag (label)
      (svg-lib-tag label nil
                   :stroke 0 :margin 1 :font-weight 'bold
                   :padding (max 0 (- 3 (length label)))
                   :foreground (face-foreground 'nano-popout-i)
                   :background (face-background 'nano-popout-i)))
    (push 'display font-lock-extra-managed-props)
    (font-lock-add-keywords nil svg-font-lock-keywords)
    (font-lock-flush (point-min) (point-max))))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:32]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Colorization of recent emails
(defun my/mu4e-headers-colorize (item msg)
  "Colorize item depending on whe msg was received"
  
  (let* ((recent (* 5 60)) ;; 5 minutes
         (now (current-time))
         (unread (mu4e-message-field msg :unread))
         (date (mu4e-message-field msg :date))
         (delta (float-time (time-subtract now date))))
    (if (and (< delta recent) unread)
        (propertize item 'face 'nano-salient)
      item)))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:31]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Bookmarks
(setq mu4e-bookmarks
      '((:name "Unread"
         :key ?u
         :show-unread t
         :query "flag:unread AND NOT flag:trashed")

        (:name "Inbox"
         :key ?i
         :show-unread t 
         :query "m:/inria/inbox or m:/univ/inbox or m:/gmail/inbox")

        (:name "Today"
         :key ?t
         :show-unread t 
         :query "date:today..now")

        (:name "Yesterday"
         :key ?y
         :show-unread t
         :query "date:2d..today and not date:today..now")

        (:name "Last week"
         :key ?w
         :hide-unread t 
         :query "date:7d..now")

        (:name "Flagged"
         :key ?f
         :show-unread t 
         :query "flag:flagged")

        (:name "Sent"
         :key ?s
         :hide-unread t 
         :query "from:Nicolas.Rougier")

        (:name "Drafts"
         :key ?d
         :hide-unread t
         :query "flag:draft")))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:30]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Write
See www.gnu.org/software/emacs/manual/html_node/message/Insertion-Variables.html

(setq message-send-mail-function 'smtpmail-send-it
      message-cite-reply-position 'below
      message-citation-line-format "%N [%Y-%m-%d at %R] wrote:"
      message-citation-line-function 'message-insert-formatted-citation-line
      message-yank-prefix       "> "
      message-yank-cited-prefix "> "
      message-yank-empty-prefix "> "
      message-indentation-spaces 1
      message-kill-buffer-on-exit t

      mu4e-compose-format-flowed t
      mu4e-compose-complete-only-personal t
      mu4e-compose-complete-only-after "2021-01-01" ; Limite address auto-completion
      mu4e-compose-dont-reply-to-self t
      mu4e-compose-crypto-reply-policy 'sign-and-encrypt)
      
Multi-language flyspell in compose mode

(require 'flyspell)
(require 'guess-language)
(require 'flyspell-correct-popup)

;; (bind-key "C-;" #'flyspell-popup-wrapper flyspell-mode-map)
(bind-key "C-;" #'flyspell-popup-correct flyspell-mode-map)

;; Automatically detect language for Flyspell
(with-eval-after-load 'guess-language  
    (add-hook 'text-mode-hook #'guess-language-mode)
    (setq guess-language-langcodes '((en . ("en_GB" "English"))
                                     (fr . ("fr_FR" "French")))
          guess-language-languages '(en fr)
          guess-language-min-paragraph-length 45))

(setq flyspell-generic-check-word-predicate  'mail-mode-flyspell-verify)
(defun my/mu4e-compose-hook ()
  "Settings for message composition."

  (auto-save-mode -1)
  (turn-off-auto-fill)
  (set-fill-column 79)
  (setq flyspell-generic-check-word-predicate
        'mail-mode-flyspell-verify)
  (flyspell-mode))

(add-hook 'mu4e-compose-mode-hook #'my/mu4e-compose-hook)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:30]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Encryption
See https://www.djcbsoftware.nl/code/mu/mu4e/Reading-messages.html

(require 'epg-config)

(setq epg-gpg-program "/usr/local/bin/gpg"  ; What gpg program to use
      epg-user-id "gpg_key_id"              ; GnuPG ID of your default identity
      mml2015-use 'epg                      ; The package used for PGP/MIME.
      mml2015-encrypt-to-self t             ; Add our own key ID to recipient list
      mml2015-sign-with-sender t)           ; Use message sender to find a key to sign with.

;;(setq epa-file-cache-passphrase-for-symmetric-encryption nil)
;;(require 'epa-file)
;;(epa-file-enable)
;;(setq epa-file-select-keys nil)
(setq epa-pinentry-mode 'loopback)
(pinentry-start)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:29]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Vertico
Vertico provides a performant and minimalistic vertical completion UI based on the default completion system but aims to be highly flexible, extensible and modular.

(require 'vertico)

;; (setq completion-styles '(basic substring partial-completion flex))

(setq vertico-resize nil        ; How to resize the Vertico minibuffer window.
      vertico-count 8           ; Maximal number of candidates to show.
      vertico-count-format nil) ; No prefix with number of entries

(vertico-mode)
Tweaking settings

(setq vertico-grid-separator
      #("  |  " 2 3 (display (space :width (1))
                             face (:background "#ECEFF1")))

      vertico-group-format
      (concat #(" " 0 1 (face vertico-group-title))
              #(" " 0 1 (face vertico-group-separator))
              #(" %s " 0 4 (face vertico-group-title))
              #(" " 0 1 (face vertico-group-separator
                          display (space :align-to (- right (-1 . right-margin) (- +1)))))))

(set-face-attribute 'vertico-group-separator nil
                    :strike-through t)
(set-face-attribute 'vertico-current nil
                    :inherit '(nano-strong nano-subtle))
(set-face-attribute 'completions-first-difference nil
                    :inherit '(nano-default))
Bind shift-tab for completion

(bind-key "<backtab>" #'minibuffer-complete vertico-map)
Completion-at-point and completion-in-region (see https://github.com/minad/vertico#completion-at-point-and-completion-in-region)

(setq completion-in-region-function
      (lambda (&rest args)
        (apply (if vertico-mode
                   #'consult-completion-in-region
                 #'completion--in-region)
               args)))
Prefix the current candidate (See https://github.com/minad/vertico/wiki#prefix-current-candidate-with-arrow)

(defun minibuffer-format-candidate (orig cand prefix suffix index _start)
  (let ((prefix (if (= vertico--index index)
                    "  "
                  "   "))) 
    (funcall orig cand prefix suffix index _start)))

(advice-add #'vertico--format-candidate
           :around #'minibuffer-format-candidate)
See https://kristofferbalintona.me/posts/vertico-marginalia-all-the-icons-completion-and-orderless/#vertico

(defun vertico--prompt-selection ()
  "Highlight the prompt"

  (let ((inhibit-modification-hooks t))
    (set-text-properties (minibuffer-prompt-end) (point-max)
                         '(face (nano-strong nano-salient)))))
See minad/vertico#145

 
(defun minibuffer-vertico-setup ()

  (setq truncate-lines t)
  (setq completion-in-region-function
        (if vertico-mode
            #'consult-completion-in-region
          #'completion--in-region)))

(add-hook 'vertico-mode-hook #'minibuffer-vertico-setup)
(add-hook 'minibuffer-setup-hook #'minibuffer-vertico-setup)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:25]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Vertico
Vertico provides a performant and minimalistic vertical completion UI based on the default completion system but aims to be highly flexible, extensible and modular.

(require 'vertico)

;; (setq completion-styles '(basic substring partial-completion flex))

(setq vertico-resize nil        ; How to resize the Vertico minibuffer window.
      vertico-count 8           ; Maximal number of candidates to show.
      vertico-count-format nil) ; No prefix with number of entries

(vertico-mode)
Tweaking settings

(setq vertico-grid-separator
      #("  |  " 2 3 (display (space :width (1))
                             face (:background "#ECEFF1")))

      vertico-group-format
      (concat #(" " 0 1 (face vertico-group-title))
              #(" " 0 1 (face vertico-group-separator))
              #(" %s " 0 4 (face vertico-group-title))
              #(" " 0 1 (face vertico-group-separator
                          display (space :align-to (- right (-1 . right-margin) (- +1)))))))

(set-face-attribute 'vertico-group-separator nil
                    :strike-through t)
(set-face-attribute 'vertico-current nil
                    :inherit '(nano-strong nano-subtle))
(set-face-attribute 'completions-first-difference nil
                    :inherit '(nano-default))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:25]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Consult
We replace some of emacs functions with their consult equivalent

(require 'consult)

(setq consult-preview-key nil) ; No live preview

(bind-key "C-x C-r" #'consult-recent-file)
(bind-key "C-x h"   #'consult-outline)
(bind-key "C-x b"   #'consult-buffer)
(bind-key "C-c h"   #'consult-history)
;; (bind-key "M-:"     #'consult-complex-command)
For the consult-goto-line and consult-line commands, we define our owns with live preview (independently of the consult-preview-key)

(defun my/consult-line ()
  "Consult line with live preview"
  
  (interactive)
  (let ((consult-preview-key 'any)
        (mini-frame-resize 'grow-only)) ;; !! Important
    (consult-line)))

(bind-key "C-s"   #'my/consult-line)
(defun my/consult-goto-line ()
  "Consult goto line with live preview"
  
  (interactive)
  (let ((consult-preview-key 'any))
    (consult-goto-line)))

(bind-key "M-g g"   #'my/consult-goto-line)
(bind-key "M-g M-g" #'my/consult-goto-line)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:25]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Corfu
Corfu enhances completion at point with a small completion popup.

(require 'corfu)

(setq corfu-cycle t                ; Enable cycling for `corfu-next/previous'
      corfu-auto t                 ; Enable auto completion
      corfu-auto-delay 60.0        ; Delay before auto-completion shows up
      corfu-separator ?\s          ; Orderless field separator
      corfu-quit-at-boundary nil   ; Never quit at completion boundary
      corfu-quit-no-match t        ; Quit when no match
      corfu-preview-current nil    ; Disable current candidate preview
      corfu-preselect-first nil    ; Disable candidate preselection
      corfu-on-exact-match nil     ; Configure handling of exact matches
      corfu-echo-documentation nil ; Disable documentation in the echo area
      corfu-scroll-margin 5)       ; Use scroll margin

(global-corfu-mode)
A few more useful configurations…

;; TAB cycle if there are only few candidates
(setq completion-cycle-threshold 3)

;; Emacs 28: Hide commands in M-x which do not apply to the current mode.
;; Corfu commands are hidden, since they are not supposed to be used via M-x.
(setq read-extended-command-predicate
      #'command-completion-default-include-p)

;; Enable indentation+completion using the TAB key.
;; completion-at-point is often bound to M-TAB.
(setq tab-always-indent 'complete)

;; Completion in source blocks
(require 'cape)

(add-to-list 'completion-at-point-functions 'cape-elisp-symbol)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:24]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Parenthesis
Paren mode for highlighting matcing paranthesis

(require 'paren)
;; (setq show-paren-style 'expression)
(setq show-paren-style 'parenthesis)
(setq show-paren-when-point-in-periphery t)
(setq show-paren-when-point-inside-paren nil)
(show-paren-mode)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:23]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Tabulations
No tabulation, ever.

(setq-default indent-tabs-mode nil        ; Stop using tabs to indent
              tab-always-indent 'complete ; Indent first then try completions
              tab-width 4)                ; Smaller width for tab characters
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:23]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Clipboard
Allows system and Emacs clipboard to communicate smoothly (both ways)

(setq-default select-enable-clipboard t) ; Merge system's and Emacs' clipboard
Make sure clipboard works properly in tty mode on OSX.

(defun my/paste-from-osx ()
  (shell-command-to-string "pbpaste"))

(defun my/copy-to-osx (text &optional push)
  (let ((process-connection-type nil))
    (let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
      (process-send-string proc text)
      (process-send-eof proc))))

(when (and (not (display-graphic-p))
           (eq system-type 'darwin))
  (setq interprogram-cut-function   #'my/copy-to-osx
        interprogram-paste-function #'my/paste-from-osx))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:21]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Scroll
Smoother scrolling.

(setq-default scroll-conservatively 101       ; Avoid recentering when scrolling far
              scroll-margin 2                 ; Add a margin when scrolling vertically
              recenter-positions '(5 bottom)) ; Set re-centering positions
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:21]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Mouse
Mouse behavior can be finely controlled using the mouse-avoidance-mode.

(setq-default mouse-yank-at-point t) ; Yank at point rather than pointer
(mouse-avoidance-mode 'exile)        ; Avoid collision of mouse with point
Mouse active in tty mode.

(unless (display-graphic-p)
  (xterm-mouse-mode 1)
  (global-set-key (kbd "<mouse-4>") #'scroll-down-line)
  (global-set-key (kbd "<mouse-5>") #'scroll-up-line))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:21]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
A smarter fill/unfill command

(defun my/fill-unfill ()
  "Like `fill-paragraph', but unfill if used twice."
  
  (interactive)
  (let ((fill-column
         (if (eq last-command #'my/fill-unfill)
             (progn (setq this-command nil)
                    (point-max))
           fill-column)))
    (call-interactively #'fill-paragraph)))

(bind-key "M-q"  #'my/fill-unfill)
;; (bind-key [remap fill-paragraph]  #'my/fill-unfill)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:20]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
(setq-default use-short-answers t                     ; Replace yes/no prompts with y/n
              confirm-nonexistent-file-or-buffer nil) ; Ok to visit non existent files
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:20]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Date related
A set of date related functions, mostly used for mail display.

(defun my/date-day (date)
  "Return DATE day of month (1-31)."

  (nth 3 (decode-time date)))
(defun my/date-month (date)
  "Return DATE month number (1-12)."
  
  (nth 4 (decode-time date)))
(defun my/date-year (date)
  "Return DATE year."

  (nth 5 (decode-time date)))
(defun my/date-equal (date1 date2)
  "Check if DATE1 is equal to DATE2."
  
  (and (eq (my/date-day date1)
           (my/date-day date2))
       (eq (my/date-month date1)
           (my/date-month date2))
       (eq (my/date-year date1)
           (my/date-year date2))))
(defun my/date-inc (date &optional days months years)
  "Return DATE + DAYS day & MONTH months & YEARS years"

  (let ((days (or days 0))
        (months (or months 0))
        (years (or years 0))
        (day (my/date-day date))
        (month (my/date-month date))
        (year (my/date-year date)))
    (encode-time 0 0 0 (+ day days) (+ month months) (+ year years))))
(defun my/date-dec (date &optional days months years)
  "Return DATE - DAYS day & MONTH months & YEARS years"
  
  (let ((days (or days 0))
        (months (or months 0))
        (years (or years 0)))
    (my/date-inc date (- days) (- months) (- years))))
(defun my/date-today ()
  "Return today date."
  
  (current-time))
(defun my/date-is-today (date)
  "Check if DATE is today."
  
  (my/date-equal (current-time) date))
(defun my/date-is-yesterday (date)
  "Check if DATE is yesterday."
  
  (my/date-equal (my/date-dec (my/date-today) 1) date))
(defun my/date-relative (date)
  "Return a string with a relative date format."

  (let* ((now (current-time))
         (delta (float-time (time-subtract now date)))
         (days (ceiling (/ (float-time (time-subtract now date)) (* 60 60 24)))))
    (cond ((< delta (*       3 60))     "now")
          ((< delta (*      60 60))     (format "%d minutes ago" (/ delta   60)))
          ;;  ((< delta (*    6 60 60))     (format "%d hours ago"   (/ delta 3600)))
          ((my/date-is-today date)      (format-time-string "%H:%M" date))
          ((my/date-is-yesterday date)  (format "Yesterday"))
          ((< delta (* 4 24 60 60))     (format "%d days ago" (+ days 1)))
          (t                            (format-time-string "%d %b %Y" date)))))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:12]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
History
Remove text properties for kill ring entries (see https://emacs.stackexchange.com/questions/4187). This saves a lot of time when loading it.

(defun unpropertize-kill-ring ()
  (setq kill-ring (mapcar 'substring-no-properties kill-ring)))

(add-hook 'kill-emacs-hook 'unpropertize-kill-ring)
We save every possible history we can think of.

(require 'savehist)

(setq kill-ring-max 50
      history-length 50)

(setq savehist-additional-variables
      '(kill-ring
        command-history
        set-variable-value-history
        custom-variable-history   
        query-replace-history     
        read-expression-history   
        minibuffer-history        
        read-char-history         
        face-name-history         
        bookmark-history
        file-name-history))

 (put 'minibuffer-history         'history-length 50)
 (put 'file-name-history          'history-length 50)
 (put 'set-variable-value-history 'history-length 25)
 (put 'custom-variable-history    'history-length 25)
 (put 'query-replace-history      'history-length 25)
 (put 'read-expression-history    'history-length 25)
 (put 'read-char-history          'history-length 25)
 (put 'face-name-history          'history-length 25)
 (put 'bookmark-history           'history-length 25)
No duplicates in history

(setq history-delete-duplicates t)
Start history mode.

(let (message-log-max)
  (savehist-mode))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:09]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
History
Remove text properties for kill ring entries (see https://emacs.stackexchange.com/questions/4187). This saves a lot of time when loading it.

(defun unpropertize-kill-ring ()
  (setq kill-ring (mapcar 'substring-no-properties kill-ring)))

(add-hook 'kill-emacs-hook 'unpropertize-kill-ring)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:09]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Recent files
50 Recents files with some exclusion (regex patterns).

(require 'recentf)

(setq recentf-max-menu-items 10
      recentf-max-saved-items 100
      recentf-exclude '("/Users/rougier/Documents/Mail.+"
                        "/Users/rougier/Documents/Notes.+"
                        ))

(let (message-log-max)
  (recentf-mode 1))
History
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:09]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Recovery
If Emacs or the computer crashes, you can recover the files you were editing at the time of the crash from their auto-save files. To do this, start Emacs again and type the command M-x recover-session. Here, we parameterize how files are saved in the background.

(setq auto-save-list-file-prefix ; Prefix for generating auto-save-list-file-name
      (expand-file-name ".auto-save-list/.saves-" user-emacs-directory)
      auto-save-default t        ; Auto-save every buffer that visits a file
      auto-save-timeout 20       ; Number of seconds between auto-save
      auto-save-interval 200)    ; Number of keystrokes between auto-saves
Backups
Emacs carefully copies the old contents to another file, called the “backup” file, before actually saving. Emacs makes a backup for a file only the first time the file is saved from a buffer. No matter how many times you subsequently save the file, its backup remains unchanged. However, if you kill the buffer and then visit the file again, a new backup file will be made. Here, we activate backup and parameterize the number of backups to keep.

(setq backup-directory-alist       ; File name patterns and backup directory names.
      `(("." . ,(expand-file-name "backups" user-emacs-directory)))
      make-backup-files t          ; Backup of a file the first time it is saved.
      vc-make-backup-files t       ; No backup of files under version contr
      backup-by-copying t          ; Don't clobber symlinks
      version-control t            ; Version numbers for backup files
      delete-old-versions t        ; Delete excess backup files silently
      kept-old-versions 6          ; Number of old versions to keep
      kept-new-versions 9          ; Number of new versions to keep
      delete-by-moving-to-trash t) ; Delete files to trash

;; Back
(require 'vc-backup)
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:08]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Path
Extending executable for recollq program

(setenv "PATH" (concat (getenv "PATH") ":" "/Users/rougier/Applications/recoll.app/Contents/MacOS"))
(setq exec-path (append exec-path '("/Users/rougier/Applications/recoll.app/Contents/MacOS")))

(setenv "PATH" (concat (getenv "PATH") ":" "/Users/rougier/bin"))
(setq exec-path (append exec-path '("/Users/rougier/bin")))
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:08]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
Encoding
We tell emacs to use UTF-8 encoding as much as possible.

(set-default-coding-systems 'utf-8)     ; Default to utf-8 encoding
(prefer-coding-system       'utf-8)     ; Add utf-8 at the front for automatic detection.
(set-terminal-coding-system 'utf-8)     ; Set coding system of terminal output
(set-keyboard-coding-system 'utf-8)     ; Set coding system for keyboard input on TERMINAL
(set-language-environment "English")    ; Set up multilingual environment
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 13:07]
** dotemacs/dotemacs.org at master · rougier/dotemacs
#+BEGIN_QUOTE
 inhibit-startup-echo-area-message t    ; Disable initial echo message
#+END_QUOTE
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 12:58]
** rougier/reviewer-manifesto: A pledge for reviewers
[[https://github.com/rougier/reviewer-manifesto][rougier/reviewer-manifesto: A pledge for reviewers]]
Captured On: [2025-10-17 Fri 12:54]
** rougier/nano-calendar: An alternative calendar for Emacs
[[https://github.com/rougier/nano-calendar][rougier/nano-calendar: An alternative calendar for Emacs]]
Captured On: [2025-10-17 Fri 12:53]
** dotemacs/dotemacs.org at master · rougier/dotemacs
[[https://github.com/rougier/dotemacs/blob/master/dotemacs.org][dotemacs/dotemacs.org at master · rougier/dotemacs]]
Captured On: [2025-10-17 Fri 12:53]
** rougier/nano-tools: A set of tools for emacs that are not worth to be packaged.
[[https://github.com/rougier/nano-tools][rougier/nano-tools: A set of tools for emacs that are not worth to be packaged.]]
Captured On: [2025-10-17 Fri 12:52]
** rougier/nano-mu4e: Alternative layour for mu4e
[[https://github.com/rougier/nano-mu4e][rougier/nano-mu4e: Alternative layour for mu4e]]
Captured On: [2025-10-17 Fri 12:51]
** rougier/nano-theme: GNU Emacs / N Λ N O Theme
[[https://github.com/rougier/nano-theme][rougier/nano-theme: GNU Emacs / N Λ N O Theme]]
Captured On: [2025-10-17 Fri 12:51]
** rougier/nano-emacs: GNU Emacs / N Λ N O - Emacs made simple
#+BEGIN_QUOTE
GNU Emacs / N Λ N O is a set of configuration files for GNU Emacs such as to provide a nice and consistent look and feel as shown below. It is based on design principles I described in the article "On the design of text Editors" that is available on arXiv. The light theme is based on Material colors and the dark theme is based on Nord colors.

The philosophy of nano emacs is to stick as much as possible to vanilla emacs without introducing too much dependencies (or none if possible) and to keep it modular enough. The idea is for users to copy the part they are interested in such as to include them in their own configuration.
#+END_QUOTE
[[https://github.com/rougier/nano-emacs][rougier/nano-emacs: GNU Emacs / N Λ N O - Emacs made simple]]
Captured On: [2025-10-17 Fri 11:59]
** rougier/mu4e-dashboard: A dashboard for mu4e (mu for emacs)
#+BEGIN_QUOTE
mu4e dashboard provides a new mu4e org link type that allows to execute various mu4e queries when clicked. Such links can be organised into a dashboard, by simply writing an org file as shown below:
#+END_QUOTE
[[https://github.com/rougier/mu4e-dashboard][rougier/mu4e-dashboard: A dashboard for mu4e (mu for emacs)]]
Captured On: [2025-10-17 Fri 11:56]
** rougier/mu4e-thread-folding: Functions for folding threads in mu4e headers view
#+BEGIN_QUOTE
mu4e-thread-folding.el is a small library to enable threads folding in mu4e. This works by using overlays with an invisible property and setting hooks at the right place. It is possible to configure colors to better highlight a thread and also to have a prefix string indicating if a thread is folded or not. Note that when a thread is folded, any unread child remains visible.
#+END_QUOTE
[[https://github.com/rougier/mu4e-thread-folding][rougier/mu4e-thread-folding: Functions for folding threads in mu4e headers view]]
Captured On: [2025-10-17 Fri 11:55]
** rougier/mu4e-dashboard: A dashboard for mu4e (mu for emacs)
[[https://github.com/rougier/mu4e-dashboard][rougier/mu4e-dashboard: A dashboard for mu4e (mu for emacs)]]
Captured On: [2025-10-17 Fri 11:48]