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.
Files changed (3) hide show
  1. package/README.md +5 -3
  2. package/fpf +107 -22
  3. 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 now includes all supported package managers that are detected on your system in one combined list.
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 for single-manager mode (`--manager`), and disabled by default in all-manager mode to avoid lag/flicker while navigating.
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`: `single` (default), `always`, or `never`
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.9"
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 bun; do
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:-single}"
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|auto|*)
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|bun)
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:-200}"
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|flatpak)
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
- if bun search "${effective_query}" >/dev/null 2>&1; then
832
- bun search "${effective_query}" 2>/dev/null |
833
- awk 'NR > 1 && NF > 0 { name=$1; $1=""; sub(/^[[:space:]]+/, "", $0); if ($0 == "") $0="-"; print name "\t" $0 }'
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 }' | sort -u | {
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 "FPF_SKIP_INSTALLED_MARKERS=1 %q --feed-search --manager %q -- {q} 2>/dev/null || true" "${script_path}" "${manager_override}"
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 "FPF_SKIP_INSTALLED_MARKERS=1 %q --feed-search -- {q} 2>/dev/null || true" "${script_path}"
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+=(--disabled --bind="start:reload:${reload_cmd}" --bind="change:reload:${reload_cmd}")
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fpf-cli",
3
- "version": "1.6.9",
3
+ "version": "1.6.11",
4
4
  "description": "Cross-platform fuzzy package finder powered by fzf",
5
5
  "bin": {
6
6
  "fpf": "fpf"