fpf-cli 1.6.9 → 1.6.11
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 +107 -22
- 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.11"
|
|
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:]]* ]]
|
|
@@ -644,11 +710,16 @@ exact_match_entry() {
|
|
|
644
710
|
printf "%s\t-\n" "${query}"
|
|
645
711
|
fi
|
|
646
712
|
;;
|
|
647
|
-
npm
|
|
713
|
+
npm)
|
|
648
714
|
if command_exists npm && npm view "${query}" name >/dev/null 2>&1; then
|
|
649
715
|
printf "%s\t-\n" "${query}"
|
|
650
716
|
fi
|
|
651
717
|
;;
|
|
718
|
+
bun)
|
|
719
|
+
if bun info "${query}" >/dev/null 2>&1 || (command_exists npm && npm view "${query}" name >/dev/null 2>&1); then
|
|
720
|
+
printf "%s\t-\n" "${query}"
|
|
721
|
+
fi
|
|
722
|
+
;;
|
|
652
723
|
esac
|
|
653
724
|
}
|
|
654
725
|
|
|
@@ -661,7 +732,7 @@ manager_search_entries() {
|
|
|
661
732
|
|
|
662
733
|
if [[ -z "${query}" ]]; then
|
|
663
734
|
npm_search_limit="${FPF_NO_QUERY_NPM_LIMIT:-120}"
|
|
664
|
-
line_limit="${FPF_NO_QUERY_RESULT_LIMIT:-
|
|
735
|
+
line_limit="${FPF_NO_QUERY_RESULT_LIMIT:-120}"
|
|
665
736
|
fi
|
|
666
737
|
|
|
667
738
|
if ! [[ "${npm_search_limit}" =~ ^[0-9]+$ ]] || [[ "${npm_search_limit}" -eq 0 ]]; then
|
|
@@ -674,7 +745,7 @@ manager_search_entries() {
|
|
|
674
745
|
|
|
675
746
|
if [[ -z "${effective_query}" ]]; then
|
|
676
747
|
case "${manager}" in
|
|
677
|
-
apt|dnf|pacman|zypper|emerge|choco|scoop|snap
|
|
748
|
+
apt|dnf|pacman|zypper|emerge|choco|scoop|snap)
|
|
678
749
|
effective_query="a"
|
|
679
750
|
;;
|
|
680
751
|
brew|npm|bun)
|
|
@@ -828,17 +899,19 @@ manager_search_entries() {
|
|
|
828
899
|
;;
|
|
829
900
|
bun)
|
|
830
901
|
{
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
902
|
+
local bun_search_file
|
|
903
|
+
bun_search_file="$(mktemp "${SESSION_TMP_ROOT}/bun-search.XXXXXX")"
|
|
904
|
+
if bun search "${effective_query}" >"${bun_search_file}" 2>/dev/null; then
|
|
905
|
+
awk 'NR > 1 && NF > 0 { name=$1; $1=""; sub(/^[[:space:]]+/, "", $0); if ($0 == "") $0="-"; print name "\t" $0 }' "${bun_search_file}"
|
|
834
906
|
elif command_exists npm; then
|
|
835
907
|
npm search "${effective_query}" --searchlimit="${npm_search_limit}" --parseable 2>/dev/null |
|
|
836
908
|
awk -F'\t' 'NF >= 2 { print $1 "\t" $2 }'
|
|
837
909
|
fi
|
|
910
|
+
rm -f "${bun_search_file}"
|
|
838
911
|
exact_match_entry "${manager}" "${query}"
|
|
839
912
|
} || true
|
|
840
913
|
;;
|
|
841
|
-
esac | awk -F'\t' 'NF >= 1 { if ($2 == "") $2 = "-"; print $1 "\t" $2 }' |
|
|
914
|
+
esac | awk -F'\t' 'NF >= 1 { if ($2 == "") $2 = "-"; print $1 "\t" $2 }' | awk -F'\t' '!seen[$1]++' | {
|
|
842
915
|
if [[ "${line_limit}" -gt 0 ]]; then
|
|
843
916
|
awk -v limit="${line_limit}" 'NR <= limit'
|
|
844
917
|
else
|
|
@@ -1073,21 +1146,33 @@ collect_search_display_rows() {
|
|
|
1073
1146
|
|
|
1074
1147
|
if [[ -s "${output_file}" ]]; then
|
|
1075
1148
|
sort -u "${output_file}" -o "${output_file}"
|
|
1149
|
+
rank_display_rows_by_query "${query}" "${output_file}"
|
|
1076
1150
|
fi
|
|
1077
1151
|
}
|
|
1078
1152
|
|
|
1079
1153
|
build_dynamic_reload_command() {
|
|
1080
1154
|
local manager_override="$1"
|
|
1155
|
+
local fallback_file="$2"
|
|
1081
1156
|
local script_path="${BASH_SOURCE[0]}"
|
|
1157
|
+
local min_chars="${FPF_RELOAD_MIN_CHARS:-2}"
|
|
1158
|
+
local reload_debounce="${FPF_RELOAD_DEBOUNCE:-0.12}"
|
|
1159
|
+
|
|
1160
|
+
if ! [[ "${min_chars}" =~ ^[0-9]+$ ]]; then
|
|
1161
|
+
min_chars=2
|
|
1162
|
+
fi
|
|
1163
|
+
|
|
1164
|
+
if ! [[ "${reload_debounce}" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
|
|
1165
|
+
reload_debounce=0.12
|
|
1166
|
+
fi
|
|
1082
1167
|
|
|
1083
1168
|
if [[ "${script_path}" != /* ]]; then
|
|
1084
1169
|
script_path="$(pwd)/${script_path}"
|
|
1085
1170
|
fi
|
|
1086
1171
|
|
|
1087
1172
|
if [[ -n "${manager_override}" ]]; then
|
|
1088
|
-
printf
|
|
1173
|
+
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
1174
|
else
|
|
1090
|
-
printf
|
|
1175
|
+
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
1176
|
fi
|
|
1092
1177
|
}
|
|
1093
1178
|
|
|
@@ -1330,9 +1415,10 @@ run_fuzzy_selector() {
|
|
|
1330
1415
|
--delimiter=$'\t' \
|
|
1331
1416
|
--with-nth=1,2,3 \
|
|
1332
1417
|
--preview="${preview_cmd}" \
|
|
1333
|
-
--preview-window=55%:wrap:border-sharp \
|
|
1418
|
+
--preview-window=55%:wrap:border-sharp:hidden \
|
|
1334
1419
|
--layout=reverse \
|
|
1335
1420
|
--marker='>>' \
|
|
1421
|
+
--prompt='Search> ' \
|
|
1336
1422
|
--header="${header_line}" \
|
|
1337
1423
|
--info=inline-right \
|
|
1338
1424
|
--margin="2%,1%,2%,1%" \
|
|
@@ -1341,11 +1427,10 @@ run_fuzzy_selector() {
|
|
|
1341
1427
|
--bind=ctrl-k:preview:"cat ${KBINDS_FILE}" \
|
|
1342
1428
|
--bind=ctrl-h:preview:"cat ${HELP_FILE}" \
|
|
1343
1429
|
--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}')
|
|
1430
|
+
--bind=ctrl-n:next-selected,ctrl-b:prev-selected)
|
|
1346
1431
|
|
|
1347
1432
|
if [[ -n "${reload_cmd}" ]]; then
|
|
1348
|
-
fzf_args+=(--
|
|
1433
|
+
fzf_args+=(--bind="change:reload:${reload_cmd}")
|
|
1349
1434
|
else
|
|
1350
1435
|
fzf_args+=(-e)
|
|
1351
1436
|
fi
|
|
@@ -1513,7 +1598,7 @@ main() {
|
|
|
1513
1598
|
local reload_cmd=""
|
|
1514
1599
|
if [[ "${ACTION}" == "search" && -z "${query}" ]]; then
|
|
1515
1600
|
if dynamic_reload_enabled "${#managers[@]}"; then
|
|
1516
|
-
reload_cmd="$(build_dynamic_reload_command "${MANAGER_OVERRIDE}")"
|
|
1601
|
+
reload_cmd="$(build_dynamic_reload_command "${MANAGER_OVERRIDE}" "${display_file}")"
|
|
1517
1602
|
fi
|
|
1518
1603
|
fi
|
|
1519
1604
|
|