fpf-cli 1.6.6 → 1.6.8

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 +3 -0
  2. package/fpf +91 -93
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -68,6 +68,7 @@ For no-query startup (`fpf`), each manager uses a lighter default query and per-
68
68
  - `-l, --list-installed` list installed packages
69
69
  - `-R, --remove` remove selected packages
70
70
  - `-U, --update` run update/upgrade flow
71
+ - `-v, --version` print version and exit
71
72
  - `-h, --help` show help
72
73
 
73
74
  ## Keybinds
@@ -78,6 +79,8 @@ For no-query startup (`fpf`), each manager uses a lighter default query and per-
78
79
  - `ctrl-n` next selected item
79
80
  - `ctrl-b` previous selected item
80
81
 
82
+ Installed packages are marked with `*` in the result list.
83
+
81
84
  ## Notes
82
85
 
83
86
  - Requires: `bash` + `fzf`
package/fpf CHANGED
@@ -3,9 +3,11 @@
3
3
  set -euo pipefail
4
4
 
5
5
  SCRIPT_NAME="fpf"
6
+ SCRIPT_VERSION="1.6.8"
6
7
  TMP_ROOT="${TMPDIR:-/tmp}/fpf"
7
- HELP_FILE="${TMP_ROOT}/help"
8
- KBINDS_FILE="${TMP_ROOT}/keybinds"
8
+ SESSION_TMP_ROOT=""
9
+ HELP_FILE=""
10
+ KBINDS_FILE=""
9
11
 
10
12
  ACTION="search"
11
13
  MANAGER_OVERRIDE=""
@@ -28,6 +30,22 @@ ensure_tmp_root() {
28
30
  mkdir -p "${TMP_ROOT}"
29
31
  }
30
32
 
33
+ initialize_session_tmp_root() {
34
+ if [[ -n "${SESSION_TMP_ROOT}" ]]; then
35
+ return
36
+ fi
37
+
38
+ SESSION_TMP_ROOT="$(mktemp -d "${TMP_ROOT}/session.XXXXXX")"
39
+ HELP_FILE="${SESSION_TMP_ROOT}/help"
40
+ KBINDS_FILE="${SESSION_TMP_ROOT}/keybinds"
41
+ }
42
+
43
+ cleanup_session_tmp_root() {
44
+ if [[ -n "${SESSION_TMP_ROOT}" && -d "${SESSION_TMP_ROOT}" ]]; then
45
+ rm -rf "${SESSION_TMP_ROOT}"
46
+ fi
47
+ }
48
+
31
49
  run_as_root() {
32
50
  if [[ "${EUID}" -eq 0 ]]; then
33
51
  "$@"
@@ -412,7 +430,7 @@ build_help_file() {
412
430
  local default_managers="$1"
413
431
 
414
432
  cat >"${HELP_FILE}" <<EOF
415
- ${SCRIPT_NAME} - ultimate fuzzy package finder
433
+ ${SCRIPT_NAME} - fuzzy package finder
416
434
 
417
435
  Syntax:
418
436
  ${SCRIPT_NAME} [manager option] [action option] [query]
@@ -428,6 +446,7 @@ Action options:
428
446
  -l, --list-installed Fuzzy-search installed packages and show details
429
447
  -R, --remove Fuzzy-search installed packages and remove selected
430
448
  -U, --update Run manager update/upgrade flow
449
+ -v, --version Print version and exit
431
450
  -h, --help Show this help
432
451
 
433
452
  Manager options (one or two-letter style):
@@ -479,12 +498,19 @@ print_help() {
479
498
  cat "${HELP_FILE}"
480
499
  }
481
500
 
501
+ print_version() {
502
+ printf "%s %s\n" "${SCRIPT_NAME}" "${SCRIPT_VERSION}"
503
+ }
504
+
482
505
  parse_args() {
483
506
  while (($#)); do
484
507
  case "$1" in
485
508
  -h|--help)
486
509
  ACTION="help"
487
510
  ;;
511
+ -v|--version)
512
+ ACTION="version"
513
+ ;;
488
514
  -l|--list-installed)
489
515
  ACTION="list"
490
516
  ;;
@@ -716,15 +742,15 @@ manager_search_entries() {
716
742
  /^Name[[:space:]]+Id[[:space:]]+/ { next }
717
743
  /^[-[:space:]]+$/ { next }
718
744
  {
745
+ line = $0
746
+ sub(/^[[:space:]]+/, "", line)
719
747
  pkg = ""
720
- desc = "-"
721
- if (NF >= 2) {
722
- pkg = $2
723
- } else if (NF >= 1) {
724
- pkg = $1
748
+ n = split(line, cols, /[[:space:]][[:space:]]+/)
749
+ if (n >= 2) {
750
+ pkg = cols[2]
725
751
  }
726
752
  if (pkg != "") {
727
- print pkg "\t" desc
753
+ print pkg "\t-"
728
754
  }
729
755
  }
730
756
  '
@@ -854,17 +880,20 @@ manager_installed_entries() {
854
880
  /^Name[[:space:]]+Id[[:space:]]+/ { next }
855
881
  /^[-[:space:]]+$/ { next }
856
882
  {
883
+ line = $0
884
+ sub(/^[[:space:]]+/, "", line)
885
+
857
886
  pkg = ""
858
887
  ver = "installed"
859
- if (NF >= 3) {
860
- pkg = $2
861
- ver = $3
862
- } else if (NF >= 2) {
863
- pkg = $1
864
- ver = $2
865
- } else if (NF >= 1) {
866
- pkg = $1
888
+
889
+ n = split(line, cols, /[[:space:]][[:space:]]+/)
890
+ if (n >= 2) {
891
+ pkg = cols[2]
867
892
  }
893
+ if (n >= 3 && cols[3] != "") {
894
+ ver = cols[3]
895
+ }
896
+
868
897
  if (pkg != "") {
869
898
  print pkg "\t" ver
870
899
  }
@@ -905,9 +934,6 @@ manager_installed_entries() {
905
934
  if bun pm ls --global >/dev/null 2>&1; then
906
935
  bun pm ls --global 2>/dev/null |
907
936
  awk 'NR > 1 && NF > 0 { print $1 "\tglobal" }'
908
- elif bun pm ls >/dev/null 2>&1; then
909
- bun pm ls 2>/dev/null |
910
- awk 'NR > 1 && NF > 0 { print $1 "\tglobal" }'
911
937
  elif command_exists npm; then
912
938
  npm ls -g --depth=0 --parseable 2>/dev/null |
913
939
  awk -F'/' 'NR > 1 { print $NF "\tglobal" }'
@@ -928,7 +954,7 @@ mark_installed_packages() {
928
954
  local output_file="$3"
929
955
  local installed_file
930
956
 
931
- installed_file="$(mktemp "${TMP_ROOT}/installed.XXXXXX")"
957
+ installed_file="$(mktemp "${SESSION_TMP_ROOT}/installed.XXXXXX")"
932
958
  manager_installed_names "${manager}" >"${installed_file}" 2>/dev/null || true
933
959
 
934
960
  awk -F'\t' '
@@ -939,7 +965,7 @@ mark_installed_packages() {
939
965
  next
940
966
  }
941
967
  {
942
- mark = (installed[$1] ? "* " : " ")
968
+ mark = (installed[$1] ? "\033[32m*\033[0m " : " ")
943
969
  desc = $2
944
970
  if (desc == "") desc = "-"
945
971
  print $1 "\t" mark desc
@@ -964,12 +990,12 @@ collect_search_display_rows() {
964
990
  local gather_pid
965
991
 
966
992
  for manager in "${managers[@]-}"; do
967
- part_file="$(mktemp "${TMP_ROOT}/part.XXXXXX")"
993
+ part_file="$(mktemp "${SESSION_TMP_ROOT}/part.XXXXXX")"
968
994
  part_files+=("${part_file}")
969
995
 
970
996
  (
971
- local_source_file="$(mktemp "${TMP_ROOT}/source.XXXXXX")"
972
- local_marked_file="$(mktemp "${TMP_ROOT}/marked.XXXXXX")"
997
+ local_source_file="$(mktemp "${SESSION_TMP_ROOT}/source.XXXXXX")"
998
+ local_marked_file="$(mktemp "${SESSION_TMP_ROOT}/marked.XXXXXX")"
973
999
  manager_search_entries "${manager}" "${query}" >"${local_source_file}" || true
974
1000
  if [[ -s "${local_source_file}" ]]; then
975
1001
  mark_installed_packages "${manager}" "${local_source_file}" "${local_marked_file}"
@@ -1017,52 +1043,6 @@ build_dynamic_reload_command() {
1017
1043
  fi
1018
1044
  }
1019
1045
 
1020
- manager_preview_command() {
1021
- local manager="$1"
1022
-
1023
- case "${manager}" in
1024
- apt)
1025
- printf '%s' 'pkg={1}; apt-cache show "$pkg" 2>/dev/null; printf "\n"; dpkg -L "$pkg" 2>/dev/null'
1026
- ;;
1027
- dnf)
1028
- printf '%s' 'pkg={1}; dnf info "$pkg" 2>/dev/null; printf "\n"; rpm -ql "$pkg" 2>/dev/null'
1029
- ;;
1030
- pacman)
1031
- printf '%s' 'pkg={1}; pacman -Si "$pkg" 2>/dev/null; printf "\n"; pacman -Fl "$pkg" 2>/dev/null | awk "{print \$2}"'
1032
- ;;
1033
- zypper)
1034
- printf '%s' 'pkg={1}; zypper --non-interactive info "$pkg" 2>/dev/null'
1035
- ;;
1036
- emerge)
1037
- printf '%s' 'pkg={1}; emerge --search --color=n "$pkg" 2>/dev/null'
1038
- ;;
1039
- brew)
1040
- printf '%s' 'pkg={1}; brew info "$pkg" 2>/dev/null'
1041
- ;;
1042
- winget)
1043
- printf '%s' 'pkg={1}; winget show --id "$pkg" --exact --source winget --accept-source-agreements --disable-interactivity 2>/dev/null'
1044
- ;;
1045
- choco)
1046
- printf '%s' 'pkg={1}; choco info "$pkg" 2>/dev/null'
1047
- ;;
1048
- scoop)
1049
- printf '%s' 'pkg={1}; scoop info "$pkg" 2>/dev/null'
1050
- ;;
1051
- snap)
1052
- printf '%s' 'pkg={1}; snap info "$pkg" 2>/dev/null'
1053
- ;;
1054
- flatpak)
1055
- printf '%s' 'pkg={1}; flatpak info "$pkg" 2>/dev/null || flatpak remote-info flathub "$pkg" 2>/dev/null'
1056
- ;;
1057
- npm)
1058
- printf '%s' 'pkg={1}; npm view "$pkg" 2>/dev/null'
1059
- ;;
1060
- bun)
1061
- printf '%s' 'pkg={1}; bun info "$pkg" 2>/dev/null || npm view "$pkg" 2>/dev/null'
1062
- ;;
1063
- esac
1064
- }
1065
-
1066
1046
  manager_install() {
1067
1047
  local manager="$1"
1068
1048
  shift
@@ -1107,7 +1087,10 @@ manager_install() {
1107
1087
  flatpak)
1108
1088
  local pkg
1109
1089
  for pkg in "$@"; do
1110
- flatpak install -y --user flathub "${pkg}" 2>/dev/null || flatpak install -y --user "${pkg}"
1090
+ flatpak install -y --user flathub "${pkg}" 2>/dev/null ||
1091
+ flatpak install -y --user "${pkg}" 2>/dev/null ||
1092
+ run_as_root flatpak install -y flathub "${pkg}" 2>/dev/null ||
1093
+ run_as_root flatpak install -y "${pkg}"
1111
1094
  done
1112
1095
  ;;
1113
1096
  npm)
@@ -1146,7 +1129,7 @@ manager_remove() {
1146
1129
  winget)
1147
1130
  local pkg
1148
1131
  for pkg in "$@"; do
1149
- winget uninstall --id "${pkg}" --exact --disable-interactivity
1132
+ winget uninstall --id "${pkg}" --exact --source winget --disable-interactivity
1150
1133
  done
1151
1134
  ;;
1152
1135
  choco)
@@ -1159,13 +1142,13 @@ manager_remove() {
1159
1142
  run_as_root snap remove "$@"
1160
1143
  ;;
1161
1144
  flatpak)
1162
- flatpak uninstall -y --user "$@"
1145
+ flatpak uninstall -y --user "$@" 2>/dev/null || run_as_root flatpak uninstall -y "$@"
1163
1146
  ;;
1164
1147
  npm)
1165
1148
  npm uninstall -g "$@"
1166
1149
  ;;
1167
1150
  bun)
1168
- bun remove --global "$@" 2>/dev/null || bun remove "$@"
1151
+ bun remove --global "$@"
1169
1152
  ;;
1170
1153
  esac
1171
1154
  }
@@ -1257,13 +1240,13 @@ manager_update() {
1257
1240
  run_as_root snap refresh
1258
1241
  ;;
1259
1242
  flatpak)
1260
- flatpak update -y --user
1243
+ flatpak update -y --user 2>/dev/null || run_as_root flatpak update -y
1261
1244
  ;;
1262
1245
  npm)
1263
1246
  npm update -g
1264
1247
  ;;
1265
1248
  bun)
1266
- bun update --global 2>/dev/null || bun update
1249
+ bun update --global
1267
1250
  ;;
1268
1251
  esac
1269
1252
  }
@@ -1303,14 +1286,16 @@ run_fuzzy_selector() {
1303
1286
  --layout=reverse \
1304
1287
  --marker='>>' \
1305
1288
  --header="${header_line}" \
1306
- --info=hidden \
1289
+ --info=inline-right \
1290
+ --ansi \
1307
1291
  --margin="2%,1%,2%,1%" \
1308
1292
  --cycle \
1293
+ --tiebreak=begin,chunk,length \
1309
1294
  --bind=ctrl-k:preview:"cat ${KBINDS_FILE}" \
1310
1295
  --bind=ctrl-h:preview:"cat ${HELP_FILE}" \
1311
1296
  --bind='ctrl-/:change-preview-window(hidden|)' \
1312
1297
  --bind=ctrl-n:next-selected,ctrl-b:prev-selected \
1313
- --bind='focus:transform-preview-label:echo {1}: {2}')
1298
+ --bind='focus:transform-preview-label:echo [{1}] {2}')
1314
1299
 
1315
1300
  if [[ -n "${reload_cmd}" ]]; then
1316
1301
  fzf_args+=(--disabled --bind="start:reload:${reload_cmd}" --bind="change:reload:${reload_cmd}")
@@ -1323,9 +1308,16 @@ run_fuzzy_selector() {
1323
1308
 
1324
1309
  main() {
1325
1310
  ensure_tmp_root
1311
+ initialize_session_tmp_root
1312
+ trap cleanup_session_tmp_root EXIT
1326
1313
 
1327
1314
  parse_args "$@"
1328
1315
 
1316
+ if [[ "${ACTION}" == "version" ]]; then
1317
+ print_version
1318
+ exit 0
1319
+ fi
1320
+
1329
1321
  local detected_manager
1330
1322
  local detected_managers=()
1331
1323
  while IFS= read -r detected_manager; do
@@ -1371,8 +1363,11 @@ main() {
1371
1363
  local query
1372
1364
  query="$(join_query)"
1373
1365
 
1374
- if [[ "${ACTION}" == "update" ]]; then
1366
+ if [[ "${ACTION}" != "feed-search" ]]; then
1375
1367
  log "Using manager(s): ${manager_display}"
1368
+ fi
1369
+
1370
+ if [[ "${ACTION}" == "update" ]]; then
1376
1371
  if confirm_action "Run update/upgrade for ${manager_display}?"; then
1377
1372
  for manager in "${managers[@]-}"; do
1378
1373
  log "Updating with $(manager_label "${manager}")"
@@ -1385,7 +1380,7 @@ main() {
1385
1380
  fi
1386
1381
 
1387
1382
  local display_file
1388
- display_file="$(mktemp "${TMP_ROOT}/display.XXXXXX")"
1383
+ display_file="$(mktemp "${SESSION_TMP_ROOT}/display.XXXXXX")"
1389
1384
  : >"${display_file}"
1390
1385
 
1391
1386
  if [[ "${ACTION}" == "feed-search" ]]; then
@@ -1408,14 +1403,14 @@ main() {
1408
1403
  local gather_pid
1409
1404
 
1410
1405
  for manager in "${managers[@]-}"; do
1411
- part_file="$(mktemp "${TMP_ROOT}/part.XXXXXX")"
1412
- part_files+=("${part_file}")
1413
-
1414
- (
1415
- local_source_file="$(mktemp "${TMP_ROOT}/source.XXXXXX")"
1416
- manager_installed_entries "${manager}" >"${local_source_file}" || true
1417
- if [[ -s "${local_source_file}" ]]; then
1418
- awk -F'\t' -v mgr="${manager}" '
1406
+ part_file="$(mktemp "${SESSION_TMP_ROOT}/part.XXXXXX")"
1407
+ part_files+=("${part_file}")
1408
+
1409
+ (
1410
+ local_source_file="$(mktemp "${SESSION_TMP_ROOT}/source.XXXXXX")"
1411
+ manager_installed_entries "${manager}" >"${local_source_file}" || true
1412
+ if [[ -s "${local_source_file}" ]]; then
1413
+ awk -F'\t' -v mgr="${manager}" '
1419
1414
  NF >= 1 {
1420
1415
  desc = $2
1421
1416
  if (desc == "") desc = "-"
@@ -1446,13 +1441,16 @@ main() {
1446
1441
 
1447
1442
  if [[ ! -s "${display_file}" ]]; then
1448
1443
  rm -f "${display_file}"
1449
- die "No packages found for manager(s) '${manager_display}' and query '${query}'"
1444
+ if [[ -n "${query}" ]]; then
1445
+ die "No packages found for ${manager_display} matching '${query}'. Try a broader query or --manager."
1446
+ fi
1447
+ die "No packages found for ${manager_display}. Try adding a query or using --manager."
1450
1448
  fi
1451
1449
 
1452
1450
  local header
1453
1451
  case "${ACTION}" in
1454
1452
  search)
1455
- header="Select package(s) to install with ${manager_display} (TAB to multi-select)"
1453
+ header="Select package(s) to install with ${manager_display} (TAB to multi-select, * = installed)"
1456
1454
  ;;
1457
1455
  list)
1458
1456
  header="Select installed package(s) to inspect from ${manager_display}"
@@ -1476,7 +1474,7 @@ main() {
1476
1474
  rm -f "${display_file}"
1477
1475
 
1478
1476
  if [[ -z "${selected}" ]]; then
1479
- log "No package selected"
1477
+ log "Selection canceled"
1480
1478
  exit 0
1481
1479
  fi
1482
1480
 
@@ -1494,7 +1492,7 @@ main() {
1494
1492
  done <<<"${selected}"
1495
1493
 
1496
1494
  if [[ "${#selected_packages[@]}" -eq 0 ]]; then
1497
- log "No package selected"
1495
+ log "Selection canceled"
1498
1496
  exit 0
1499
1497
  fi
1500
1498
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fpf-cli",
3
- "version": "1.6.6",
3
+ "version": "1.6.8",
4
4
  "description": "Cross-platform fuzzy package finder powered by fzf",
5
5
  "bin": {
6
6
  "fpf": "fpf"