fpf-cli 1.6.9 → 1.6.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/fpf +95 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,11 +34,11 @@ fpf -U
|
|
|
34
34
|
|
|
35
35
|
By default, `fpf` auto-detects your package manager.
|
|
36
36
|
|
|
37
|
-
On every OS, default auto mode
|
|
37
|
+
On every OS, default auto mode includes all supported detected managers. If both `bun` and `npm` are available, auto mode keeps `bun` and skips `npm`.
|
|
38
38
|
|
|
39
39
|
For no-query startup (`fpf`), each manager uses a lighter default query and per-manager result cap to keep startup responsive.
|
|
40
40
|
|
|
41
|
-
Live reload is enabled by default
|
|
41
|
+
Live reload is enabled by default, with a minimum query length and debounce to reduce lag while typing.
|
|
42
42
|
|
|
43
43
|
## Supported Managers
|
|
44
44
|
|
|
@@ -88,5 +88,7 @@ Installed packages are marked with `*` in the result list.
|
|
|
88
88
|
- Requires: `bash` + `fzf`
|
|
89
89
|
- If `fzf` is missing, `fpf` auto-installs it using a compatible detected manager.
|
|
90
90
|
- Root managers (`apt`, `dnf`, `pacman`, `zypper`, `emerge`, `snap`) use `sudo` when needed.
|
|
91
|
-
- `FPF_DYNAMIC_RELOAD`: `
|
|
91
|
+
- `FPF_DYNAMIC_RELOAD`: `always` (default), `single`, or `never`
|
|
92
|
+
- `FPF_RELOAD_MIN_CHARS`: minimum query length before live reload (default `2`)
|
|
93
|
+
- `FPF_RELOAD_DEBOUNCE`: reload debounce seconds (default `0.12`)
|
|
92
94
|
- `FPF_DISABLE_INSTALLED_CACHE=1` disables installed-package marker cache
|
package/fpf
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
set -euo pipefail
|
|
4
4
|
|
|
5
5
|
SCRIPT_NAME="fpf"
|
|
6
|
-
SCRIPT_VERSION="1.6.
|
|
6
|
+
SCRIPT_VERSION="1.6.10"
|
|
7
7
|
TMP_ROOT="${TMPDIR:-/tmp}/fpf"
|
|
8
8
|
SESSION_TMP_ROOT=""
|
|
9
9
|
HELP_FILE=""
|
|
@@ -300,8 +300,8 @@ detect_default_manager() {
|
|
|
300
300
|
if command_exists winget; then printf "winget"; return; fi
|
|
301
301
|
if command_exists choco; then printf "choco"; return; fi
|
|
302
302
|
if command_exists scoop; then printf "scoop"; return; fi
|
|
303
|
-
if command_exists npm; then printf "npm"; return; fi
|
|
304
303
|
if command_exists bun; then printf "bun"; return; fi
|
|
304
|
+
if command_exists npm; then printf "npm"; return; fi
|
|
305
305
|
fi
|
|
306
306
|
|
|
307
307
|
if [[ "${os}" == "Linux" ]]; then
|
|
@@ -349,16 +349,16 @@ detect_default_manager() {
|
|
|
349
349
|
if command_exists emerge; then printf "emerge"; return; fi
|
|
350
350
|
if command_exists snap; then printf "snap"; return; fi
|
|
351
351
|
if command_exists flatpak; then printf "flatpak"; return; fi
|
|
352
|
-
if command_exists npm; then printf "npm"; return; fi
|
|
353
352
|
if command_exists bun; then printf "bun"; return; fi
|
|
353
|
+
if command_exists npm; then printf "npm"; return; fi
|
|
354
354
|
fi
|
|
355
355
|
|
|
356
356
|
if command_exists brew; then printf "brew"; return; fi
|
|
357
357
|
if command_exists winget; then printf "winget"; return; fi
|
|
358
358
|
if command_exists choco; then printf "choco"; return; fi
|
|
359
359
|
if command_exists scoop; then printf "scoop"; return; fi
|
|
360
|
-
if command_exists npm; then printf "npm"; return; fi
|
|
361
360
|
if command_exists bun; then printf "bun"; return; fi
|
|
361
|
+
if command_exists npm; then printf "npm"; return; fi
|
|
362
362
|
|
|
363
363
|
die "Unable to auto-detect a supported package manager. Use --manager."
|
|
364
364
|
}
|
|
@@ -367,10 +367,20 @@ detect_default_managers() {
|
|
|
367
367
|
local emitted=""
|
|
368
368
|
local primary_manager=""
|
|
369
369
|
local manager
|
|
370
|
+
local prefer_bun=0
|
|
371
|
+
|
|
372
|
+
if manager_command_ready bun; then
|
|
373
|
+
prefer_bun=1
|
|
374
|
+
fi
|
|
370
375
|
|
|
371
376
|
add_detected_manager() {
|
|
372
377
|
local manager_name="$1"
|
|
373
378
|
[[ -n "${manager_name}" ]] || return
|
|
379
|
+
|
|
380
|
+
if [[ "${prefer_bun}" -eq 1 && "${manager_name}" == "npm" ]]; then
|
|
381
|
+
return
|
|
382
|
+
fi
|
|
383
|
+
|
|
374
384
|
case " ${emitted} " in
|
|
375
385
|
*" ${manager_name} "*)
|
|
376
386
|
return
|
|
@@ -385,7 +395,7 @@ detect_default_managers() {
|
|
|
385
395
|
primary_manager="$(detect_default_manager)"
|
|
386
396
|
add_detected_manager "${primary_manager}"
|
|
387
397
|
|
|
388
|
-
for manager in apt dnf pacman zypper emerge brew winget choco scoop snap flatpak npm
|
|
398
|
+
for manager in apt dnf pacman zypper emerge brew winget choco scoop snap flatpak bun npm; do
|
|
389
399
|
add_detected_manager "${manager}"
|
|
390
400
|
done
|
|
391
401
|
|
|
@@ -610,21 +620,77 @@ join_query() {
|
|
|
610
620
|
|
|
611
621
|
dynamic_reload_enabled() {
|
|
612
622
|
local manager_count="$1"
|
|
613
|
-
local mode="${FPF_DYNAMIC_RELOAD:-
|
|
623
|
+
local mode="${FPF_DYNAMIC_RELOAD:-always}"
|
|
614
624
|
|
|
615
625
|
case "${mode}" in
|
|
616
|
-
always|on|1|true|yes)
|
|
626
|
+
always|auto|on|1|true|yes)
|
|
617
627
|
return 0
|
|
618
628
|
;;
|
|
619
629
|
never|off|0|false|no)
|
|
620
630
|
return 1
|
|
621
631
|
;;
|
|
622
|
-
single
|
|
632
|
+
single)
|
|
623
633
|
[[ "${manager_count}" -eq 1 ]]
|
|
624
634
|
;;
|
|
635
|
+
*)
|
|
636
|
+
return 0
|
|
637
|
+
;;
|
|
625
638
|
esac
|
|
626
639
|
}
|
|
627
640
|
|
|
641
|
+
rank_display_rows_by_query() {
|
|
642
|
+
local query="$1"
|
|
643
|
+
local input_file="$2"
|
|
644
|
+
local ranked_file
|
|
645
|
+
|
|
646
|
+
[[ -n "${query}" ]] || return 0
|
|
647
|
+
|
|
648
|
+
ranked_file="$(mktemp "${SESSION_TMP_ROOT}/ranked.XXXXXX")"
|
|
649
|
+
|
|
650
|
+
awk -F'\t' -v query="${query}" '
|
|
651
|
+
function lower(s) { return tolower(s) }
|
|
652
|
+
BEGIN {
|
|
653
|
+
q = lower(query)
|
|
654
|
+
}
|
|
655
|
+
{
|
|
656
|
+
mgr = $1
|
|
657
|
+
pkg = $2
|
|
658
|
+
desc = $3
|
|
659
|
+
|
|
660
|
+
pkg_l = lower(pkg)
|
|
661
|
+
desc_l = lower(desc)
|
|
662
|
+
|
|
663
|
+
score = 8
|
|
664
|
+
if (q != "") {
|
|
665
|
+
if (pkg_l == q) {
|
|
666
|
+
score = 0
|
|
667
|
+
} else if (index(pkg_l, q) == 1) {
|
|
668
|
+
score = 1
|
|
669
|
+
} else if (index(pkg_l, q) > 0) {
|
|
670
|
+
score = 2
|
|
671
|
+
} else if (index(desc_l, q) > 0) {
|
|
672
|
+
score = 3
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
mgr_score = 9
|
|
677
|
+
if (mgr == "bun") {
|
|
678
|
+
mgr_score = 0
|
|
679
|
+
} else if (mgr == "npm") {
|
|
680
|
+
mgr_score = 1
|
|
681
|
+
} else if (mgr == "brew") {
|
|
682
|
+
mgr_score = 2
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
print score "\t" mgr_score "\t" length(pkg) "\t" pkg_l "\t" $0
|
|
686
|
+
}
|
|
687
|
+
' "${input_file}" |
|
|
688
|
+
sort -t $'\t' -k1,1n -k2,2n -k3,3n -k4,4 |
|
|
689
|
+
awk -F'\t' '{ print $5 "\t" $6 "\t" $7 }' >"${ranked_file}"
|
|
690
|
+
|
|
691
|
+
mv "${ranked_file}" "${input_file}"
|
|
692
|
+
}
|
|
693
|
+
|
|
628
694
|
query_is_single_token() {
|
|
629
695
|
local query="$1"
|
|
630
696
|
[[ -n "${query}" && "${query}" != *[[:space:]]* ]]
|
|
@@ -661,7 +727,7 @@ manager_search_entries() {
|
|
|
661
727
|
|
|
662
728
|
if [[ -z "${query}" ]]; then
|
|
663
729
|
npm_search_limit="${FPF_NO_QUERY_NPM_LIMIT:-120}"
|
|
664
|
-
line_limit="${FPF_NO_QUERY_RESULT_LIMIT:-
|
|
730
|
+
line_limit="${FPF_NO_QUERY_RESULT_LIMIT:-120}"
|
|
665
731
|
fi
|
|
666
732
|
|
|
667
733
|
if ! [[ "${npm_search_limit}" =~ ^[0-9]+$ ]] || [[ "${npm_search_limit}" -eq 0 ]]; then
|
|
@@ -838,7 +904,7 @@ manager_search_entries() {
|
|
|
838
904
|
exact_match_entry "${manager}" "${query}"
|
|
839
905
|
} || true
|
|
840
906
|
;;
|
|
841
|
-
esac | awk -F'\t' 'NF >= 1 { if ($2 == "") $2 = "-"; print $1 "\t" $2 }' |
|
|
907
|
+
esac | awk -F'\t' 'NF >= 1 { if ($2 == "") $2 = "-"; print $1 "\t" $2 }' | awk -F'\t' '!seen[$1]++' | {
|
|
842
908
|
if [[ "${line_limit}" -gt 0 ]]; then
|
|
843
909
|
awk -v limit="${line_limit}" 'NR <= limit'
|
|
844
910
|
else
|
|
@@ -1073,21 +1139,33 @@ collect_search_display_rows() {
|
|
|
1073
1139
|
|
|
1074
1140
|
if [[ -s "${output_file}" ]]; then
|
|
1075
1141
|
sort -u "${output_file}" -o "${output_file}"
|
|
1142
|
+
rank_display_rows_by_query "${query}" "${output_file}"
|
|
1076
1143
|
fi
|
|
1077
1144
|
}
|
|
1078
1145
|
|
|
1079
1146
|
build_dynamic_reload_command() {
|
|
1080
1147
|
local manager_override="$1"
|
|
1148
|
+
local fallback_file="$2"
|
|
1081
1149
|
local script_path="${BASH_SOURCE[0]}"
|
|
1150
|
+
local min_chars="${FPF_RELOAD_MIN_CHARS:-2}"
|
|
1151
|
+
local reload_debounce="${FPF_RELOAD_DEBOUNCE:-0.12}"
|
|
1152
|
+
|
|
1153
|
+
if ! [[ "${min_chars}" =~ ^[0-9]+$ ]]; then
|
|
1154
|
+
min_chars=2
|
|
1155
|
+
fi
|
|
1156
|
+
|
|
1157
|
+
if ! [[ "${reload_debounce}" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
|
|
1158
|
+
reload_debounce=0.12
|
|
1159
|
+
fi
|
|
1082
1160
|
|
|
1083
1161
|
if [[ "${script_path}" != /* ]]; then
|
|
1084
1162
|
script_path="$(pwd)/${script_path}"
|
|
1085
1163
|
fi
|
|
1086
1164
|
|
|
1087
1165
|
if [[ -n "${manager_override}" ]]; then
|
|
1088
|
-
printf
|
|
1166
|
+
printf 'q={q}; if [ ${#q} -lt %s ]; then cat %q; else sleep %s; FPF_SKIP_INSTALLED_MARKERS=1 %q --feed-search --manager %q -- "$q" 2>/dev/null || cat %q; fi' "${min_chars}" "${fallback_file}" "${reload_debounce}" "${script_path}" "${manager_override}" "${fallback_file}"
|
|
1089
1167
|
else
|
|
1090
|
-
printf
|
|
1168
|
+
printf 'q={q}; if [ ${#q} -lt %s ]; then cat %q; else sleep %s; FPF_SKIP_INSTALLED_MARKERS=1 %q --feed-search -- "$q" 2>/dev/null || cat %q; fi' "${min_chars}" "${fallback_file}" "${reload_debounce}" "${script_path}" "${fallback_file}"
|
|
1091
1169
|
fi
|
|
1092
1170
|
}
|
|
1093
1171
|
|
|
@@ -1330,9 +1408,10 @@ run_fuzzy_selector() {
|
|
|
1330
1408
|
--delimiter=$'\t' \
|
|
1331
1409
|
--with-nth=1,2,3 \
|
|
1332
1410
|
--preview="${preview_cmd}" \
|
|
1333
|
-
--preview-window=55%:wrap:border-sharp \
|
|
1411
|
+
--preview-window=55%:wrap:border-sharp:hidden \
|
|
1334
1412
|
--layout=reverse \
|
|
1335
1413
|
--marker='>>' \
|
|
1414
|
+
--prompt='Search> ' \
|
|
1336
1415
|
--header="${header_line}" \
|
|
1337
1416
|
--info=inline-right \
|
|
1338
1417
|
--margin="2%,1%,2%,1%" \
|
|
@@ -1341,11 +1420,10 @@ run_fuzzy_selector() {
|
|
|
1341
1420
|
--bind=ctrl-k:preview:"cat ${KBINDS_FILE}" \
|
|
1342
1421
|
--bind=ctrl-h:preview:"cat ${HELP_FILE}" \
|
|
1343
1422
|
--bind='ctrl-/:change-preview-window(hidden|)' \
|
|
1344
|
-
--bind=ctrl-n:next-selected,ctrl-b:prev-selected
|
|
1345
|
-
--bind='focus:transform-preview-label:echo [{1}] {2}')
|
|
1423
|
+
--bind=ctrl-n:next-selected,ctrl-b:prev-selected)
|
|
1346
1424
|
|
|
1347
1425
|
if [[ -n "${reload_cmd}" ]]; then
|
|
1348
|
-
fzf_args+=(--
|
|
1426
|
+
fzf_args+=(--bind="change:reload:${reload_cmd}")
|
|
1349
1427
|
else
|
|
1350
1428
|
fzf_args+=(-e)
|
|
1351
1429
|
fi
|
|
@@ -1513,7 +1591,7 @@ main() {
|
|
|
1513
1591
|
local reload_cmd=""
|
|
1514
1592
|
if [[ "${ACTION}" == "search" && -z "${query}" ]]; then
|
|
1515
1593
|
if dynamic_reload_enabled "${#managers[@]}"; then
|
|
1516
|
-
reload_cmd="$(build_dynamic_reload_command "${MANAGER_OVERRIDE}")"
|
|
1594
|
+
reload_cmd="$(build_dynamic_reload_command "${MANAGER_OVERRIDE}" "${display_file}")"
|
|
1517
1595
|
fi
|
|
1518
1596
|
fi
|
|
1519
1597
|
|