fpf-cli 1.2.0 → 1.5.0

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 (4) hide show
  1. package/LICENSE +201 -674
  2. package/README.md +7 -2
  3. package/fpf +307 -5
  4. package/package.json +3 -2
package/README.md CHANGED
@@ -38,15 +38,16 @@ On macOS, default auto mode uses both `brew` and `bun` together.
38
38
 
39
39
  On Linux, default auto mode uses your distro manager plus installed cross-platform managers (`snap`, `flatpak`, `brew`, `npm`, `bun`).
40
40
 
41
+ On Windows (Git Bash / MSYS / Cygwin), default auto mode uses installed Windows managers (`winget`, `choco`, `scoop`) plus `npm` and `bun`.
42
+
41
43
  ## Supported Managers
42
44
 
43
45
  - Linux: `apt`, `dnf`, `pacman`, `zypper`, `emerge`
46
+ - Windows: `winget`, `choco`, `scoop`
44
47
  - Cross-platform: `snap`, `flatpak`
45
48
  - Dev: `npm`, `bun`
46
49
  - macOS: `brew`
47
50
 
48
- (`winget` intentionally not included.)
49
-
50
51
  ## Manager Override Flags
51
52
 
52
53
  - `-ap` apt
@@ -55,6 +56,9 @@ On Linux, default auto mode uses your distro manager plus installed cross-platfo
55
56
  - `-zy` zypper
56
57
  - `-em` emerge
57
58
  - `-br` brew
59
+ - `-wg` winget
60
+ - `-ch` choco
61
+ - `-sc` scoop
58
62
  - `-sn` snap
59
63
  - `-fp` flatpak
60
64
  - `-np` npm
@@ -79,4 +83,5 @@ On Linux, default auto mode uses your distro manager plus installed cross-platfo
79
83
  ## Notes
80
84
 
81
85
  - Requires: `bash` + `fzf`
86
+ - If `fzf` is missing, `fpf` can prompt to auto-install it using a compatible detected manager.
82
87
  - Root managers (`apt`, `dnf`, `pacman`, `zypper`, `emerge`, `snap`) use `sudo` when needed.
package/fpf CHANGED
@@ -43,13 +43,13 @@ run_as_root() {
43
43
  }
44
44
 
45
45
  manager_list() {
46
- printf "%s\n" "apt dnf pacman zypper emerge brew snap flatpak npm bun"
46
+ printf "%s\n" "apt dnf pacman zypper emerge brew winget choco scoop snap flatpak npm bun"
47
47
  }
48
48
 
49
49
  manager_supported() {
50
50
  local manager="$1"
51
51
  case "${manager}" in
52
- apt|dnf|pacman|zypper|emerge|brew|snap|flatpak|npm|bun)
52
+ apt|dnf|pacman|zypper|emerge|brew|winget|choco|scoop|snap|flatpak|npm|bun)
53
53
  return 0
54
54
  ;;
55
55
  *)
@@ -79,6 +79,15 @@ manager_command_ready() {
79
79
  brew)
80
80
  command_exists brew
81
81
  ;;
82
+ winget)
83
+ command_exists winget
84
+ ;;
85
+ choco)
86
+ command_exists choco
87
+ ;;
88
+ scoop)
89
+ command_exists scoop
90
+ ;;
82
91
  snap)
83
92
  command_exists snap
84
93
  ;;
@@ -97,6 +106,128 @@ manager_command_ready() {
97
106
  esac
98
107
  }
99
108
 
109
+ manager_can_install_fzf() {
110
+ local manager="$1"
111
+ case "${manager}" in
112
+ apt|dnf|pacman|zypper|emerge|brew|winget|choco|scoop|snap)
113
+ return 0
114
+ ;;
115
+ *)
116
+ return 1
117
+ ;;
118
+ esac
119
+ }
120
+
121
+ install_fzf_with_manager() {
122
+ local manager="$1"
123
+
124
+ case "${manager}" in
125
+ apt)
126
+ run_as_root apt-get install -y fzf
127
+ ;;
128
+ dnf)
129
+ run_as_root dnf install -y fzf
130
+ ;;
131
+ pacman)
132
+ run_as_root pacman -S --needed fzf
133
+ ;;
134
+ zypper)
135
+ run_as_root zypper --non-interactive install --auto-agree-with-licenses fzf
136
+ ;;
137
+ emerge)
138
+ run_as_root emerge --ask=n app-shells/fzf
139
+ ;;
140
+ brew)
141
+ brew install fzf
142
+ ;;
143
+ winget)
144
+ winget install --id junegunn.fzf --exact --source winget --accept-package-agreements --accept-source-agreements --disable-interactivity ||
145
+ winget install --id fzf --exact --source winget --accept-package-agreements --accept-source-agreements --disable-interactivity
146
+ ;;
147
+ choco)
148
+ choco install fzf -y
149
+ ;;
150
+ scoop)
151
+ scoop install fzf
152
+ ;;
153
+ snap)
154
+ run_as_root snap install fzf
155
+ ;;
156
+ *)
157
+ return 1
158
+ ;;
159
+ esac
160
+ }
161
+
162
+ build_fzf_bootstrap_candidates() {
163
+ local seen=""
164
+ local manager
165
+
166
+ for manager in "$@"; do
167
+ [[ -n "${manager}" ]] || continue
168
+ manager_can_install_fzf "${manager}" || continue
169
+ manager_command_ready "${manager}" || continue
170
+ case " ${seen} " in
171
+ *" ${manager} "*)
172
+ continue
173
+ ;;
174
+ esac
175
+ printf "%s\n" "${manager}"
176
+ seen+=" ${manager}"
177
+ done
178
+
179
+ if [[ -n "${seen}" ]]; then
180
+ return
181
+ fi
182
+
183
+ for manager in apt dnf pacman zypper emerge brew winget choco scoop snap; do
184
+ manager_command_ready "${manager}" || continue
185
+ case " ${seen} " in
186
+ *" ${manager} "*)
187
+ continue
188
+ ;;
189
+ esac
190
+ printf "%s\n" "${manager}"
191
+ seen+=" ${manager}"
192
+ done
193
+ }
194
+
195
+ ensure_fzf() {
196
+ local candidates=()
197
+ local manager
198
+
199
+ if command_exists fzf; then
200
+ return
201
+ fi
202
+
203
+ while IFS= read -r manager; do
204
+ [[ -n "${manager}" ]] || continue
205
+ candidates+=("${manager}")
206
+ done < <(build_fzf_bootstrap_candidates "$@")
207
+
208
+ if [[ "${#candidates[@]}" -eq 0 ]]; then
209
+ die "fzf is required and no compatible manager is available to auto-install it"
210
+ fi
211
+
212
+ local candidate_labels
213
+ candidate_labels="$(join_manager_labels "${candidates[@]-}")"
214
+
215
+ if ! confirm_action "fzf is not installed. Install it now using ${candidate_labels}?"; then
216
+ die "fzf is required"
217
+ fi
218
+
219
+ for manager in "${candidates[@]-}"; do
220
+ log "Attempting fzf install with $(manager_label "${manager}")"
221
+ if install_fzf_with_manager "${manager}"; then
222
+ if command_exists fzf; then
223
+ return
224
+ fi
225
+ fi
226
+ done
227
+
228
+ die "Failed to auto-install fzf. Install fzf manually and rerun."
229
+ }
230
+
100
231
  normalize_manager() {
101
232
  printf "%s" "$1" | tr '[:upper:]' '[:lower:]'
102
233
  }
@@ -127,6 +258,9 @@ manager_label() {
127
258
  zypper) printf "Zypper" ;;
128
259
  emerge) printf "Portage (emerge)" ;;
129
260
  brew) printf "Homebrew" ;;
261
+ winget) printf "WinGet" ;;
262
+ choco) printf "Chocolatey" ;;
263
+ scoop) printf "Scoop" ;;
130
264
  snap) printf "Snap" ;;
131
265
  flatpak) printf "Flatpak" ;;
132
266
  npm) printf "npm" ;;
@@ -146,6 +280,14 @@ detect_default_manager() {
146
280
  fi
147
281
  fi
148
282
 
283
+ if [[ "${os}" == MINGW* || "${os}" == MSYS* || "${os}" == CYGWIN* || "${os}" == "Windows_NT" ]]; then
284
+ if command_exists winget; then printf "winget"; return; fi
285
+ if command_exists choco; then printf "choco"; return; fi
286
+ if command_exists scoop; then printf "scoop"; return; fi
287
+ if command_exists npm; then printf "npm"; return; fi
288
+ if command_exists bun; then printf "bun"; return; fi
289
+ fi
290
+
149
291
  if [[ "${os}" == "Linux" ]]; then
150
292
  local distro_id=""
151
293
  local distro_like=""
@@ -196,6 +338,9 @@ detect_default_manager() {
196
338
  fi
197
339
 
198
340
  if command_exists brew; then printf "brew"; return; fi
341
+ if command_exists winget; then printf "winget"; return; fi
342
+ if command_exists choco; then printf "choco"; return; fi
343
+ if command_exists scoop; then printf "scoop"; return; fi
199
344
  if command_exists npm; then printf "npm"; return; fi
200
345
  if command_exists bun; then printf "bun"; return; fi
201
346
 
@@ -231,6 +376,17 @@ detect_default_managers() {
231
376
  fi
232
377
  fi
233
378
 
379
+ if [[ "${os}" == MINGW* || "${os}" == MSYS* || "${os}" == CYGWIN* || "${os}" == "Windows_NT" ]]; then
380
+ add_detected_manager "winget"
381
+ add_detected_manager "choco"
382
+ add_detected_manager "scoop"
383
+ add_detected_manager "npm"
384
+ add_detected_manager "bun"
385
+ if [[ -n "${emitted}" ]]; then
386
+ return
387
+ fi
388
+ fi
389
+
234
390
  if [[ "${os}" == "Linux" ]]; then
235
391
  primary_manager="$(detect_default_manager)"
236
392
  add_detected_manager "${primary_manager}"
@@ -315,6 +471,9 @@ Manager options (one or two-letter style):
315
471
  -zy, --zypper Use Zypper
316
472
  -em, --emerge Use Portage (emerge)
317
473
  -br, --brew Use Homebrew
474
+ -wg, --winget Use WinGet
475
+ -ch, --choco Use Chocolatey
476
+ -sc, --scoop Use Scoop
318
477
  -sn, --snap Use Snap
319
478
  -fp, --flatpak Use Flatpak
320
479
  -np, --npm Use npm (global packages)
@@ -328,7 +487,9 @@ Examples:
328
487
  ${SCRIPT_NAME} -br -R wget
329
488
  ${SCRIPT_NAME} -sn firefox
330
489
  ${SCRIPT_NAME} -fp org.gimp.GIMP
490
+ ${SCRIPT_NAME} -wg Microsoft.VisualStudioCode
331
491
  ${SCRIPT_NAME} -np eslint
492
+ ${SCRIPT_NAME} -ch git
332
493
  ${SCRIPT_NAME} -m apt ripgrep
333
494
 
334
495
  Supported managers:
@@ -385,6 +546,15 @@ parse_args() {
385
546
  -br|--brew)
386
547
  MANAGER_OVERRIDE="brew"
387
548
  ;;
549
+ -wg|--winget)
550
+ MANAGER_OVERRIDE="winget"
551
+ ;;
552
+ -ch|--choco)
553
+ MANAGER_OVERRIDE="choco"
554
+ ;;
555
+ -sc|--scoop)
556
+ MANAGER_OVERRIDE="scoop"
557
+ ;;
388
558
  -sn|--snap)
389
559
  MANAGER_OVERRIDE="snap"
390
560
  ;;
@@ -450,7 +620,7 @@ manager_search_entries() {
450
620
 
451
621
  if [[ -z "${effective_query}" ]]; then
452
622
  case "${manager}" in
453
- apt|dnf|pacman|zypper|emerge|snap|flatpak|npm|bun)
623
+ apt|dnf|pacman|zypper|emerge|winget|choco|scoop|snap|flatpak|npm|bun)
454
624
  effective_query="a"
455
625
  ;;
456
626
  brew)
@@ -522,6 +692,45 @@ manager_search_entries() {
522
692
  brew search "${effective_query}" 2>/dev/null |
523
693
  awk 'NF > 0 { print $1 "\t-" }'
524
694
  ;;
695
+ winget)
696
+ winget search "${effective_query}" --source winget --accept-source-agreements --disable-interactivity 2>/dev/null |
697
+ awk '
698
+ /^[[:space:]]*$/ { next }
699
+ /^Name[[:space:]]+Id[[:space:]]+/ { next }
700
+ /^[-[:space:]]+$/ { next }
701
+ {
702
+ pkg = ""
703
+ desc = "-"
704
+ if (NF >= 2) {
705
+ pkg = $2
706
+ } else if (NF >= 1) {
707
+ pkg = $1
708
+ }
709
+ if (pkg != "") {
710
+ print pkg "\t" desc
711
+ }
712
+ }
713
+ '
714
+ ;;
715
+ choco)
716
+ choco search "${effective_query}" --limit-output 2>/dev/null |
717
+ awk -F'|' 'NF >= 1 && $1 != "" { ver=$2; if (ver == "") ver="-"; print $1 "\tversion " ver }'
718
+ ;;
719
+ scoop)
720
+ scoop search "${effective_query}" 2>/dev/null |
721
+ awk '
722
+ /^[[:space:]]*$/ { next }
723
+ /^[-[:space:]]+$/ { next }
724
+ /^Name[[:space:]]+/ { next }
725
+ {
726
+ name = $1
727
+ $1 = ""
728
+ sub(/^[[:space:]]+/, "", $0)
729
+ if ($0 == "") $0 = "-"
730
+ print name "\t" $0
731
+ }
732
+ '
733
+ ;;
525
734
  snap)
526
735
  snap find "${effective_query}" 2>/dev/null |
527
736
  awk '
@@ -611,6 +820,47 @@ manager_installed_entries() {
611
820
  brew list --versions 2>/dev/null |
612
821
  awk '{ name=$1; $1=""; sub(/^[[:space:]]+/, "", $0); if ($0 == "") $0="installed"; print name "\t" $0 }'
613
822
  ;;
823
+ winget)
824
+ winget list --source winget --accept-source-agreements --disable-interactivity 2>/dev/null |
825
+ awk '
826
+ /^[[:space:]]*$/ { next }
827
+ /^Name[[:space:]]+Id[[:space:]]+/ { next }
828
+ /^[-[:space:]]+$/ { next }
829
+ {
830
+ pkg = ""
831
+ ver = "installed"
832
+ if (NF >= 3) {
833
+ pkg = $2
834
+ ver = $3
835
+ } else if (NF >= 2) {
836
+ pkg = $1
837
+ ver = $2
838
+ } else if (NF >= 1) {
839
+ pkg = $1
840
+ }
841
+ if (pkg != "") {
842
+ print pkg "\t" ver
843
+ }
844
+ }
845
+ '
846
+ ;;
847
+ choco)
848
+ choco list --local-only --limit-output 2>/dev/null |
849
+ awk -F'|' 'NF >= 1 && $1 != "" { ver=$2; if (ver == "") ver="installed"; print $1 "\t" ver }'
850
+ ;;
851
+ scoop)
852
+ scoop list 2>/dev/null |
853
+ awk '
854
+ /^[[:space:]]*$/ { next }
855
+ /^[-[:space:]]+$/ { next }
856
+ /^Name[[:space:]]+/ { next }
857
+ {
858
+ ver = $2
859
+ if (ver == "") ver = "installed"
860
+ print $1 "\t" ver
861
+ }
862
+ '
863
+ ;;
614
864
  snap)
615
865
  snap list 2>/dev/null |
616
866
  awk 'NR > 1 { print $1 "\t" $2 }'
@@ -694,6 +944,15 @@ manager_preview_command() {
694
944
  brew)
695
945
  printf '%s' 'pkg={1}; brew info "$pkg" 2>/dev/null'
696
946
  ;;
947
+ winget)
948
+ printf '%s' 'pkg={1}; winget show --id "$pkg" --exact --source winget --accept-source-agreements --disable-interactivity 2>/dev/null'
949
+ ;;
950
+ choco)
951
+ printf '%s' 'pkg={1}; choco info "$pkg" 2>/dev/null'
952
+ ;;
953
+ scoop)
954
+ printf '%s' 'pkg={1}; scoop info "$pkg" 2>/dev/null'
955
+ ;;
697
956
  snap)
698
957
  printf '%s' 'pkg={1}; snap info "$pkg" 2>/dev/null'
699
958
  ;;
@@ -732,6 +991,18 @@ manager_install() {
732
991
  brew)
733
992
  brew install "$@"
734
993
  ;;
994
+ winget)
995
+ local pkg
996
+ for pkg in "$@"; do
997
+ winget install --id "${pkg}" --exact --source winget --accept-package-agreements --accept-source-agreements --disable-interactivity
998
+ done
999
+ ;;
1000
+ choco)
1001
+ choco install "$@" -y
1002
+ ;;
1003
+ scoop)
1004
+ scoop install "$@"
1005
+ ;;
735
1006
  snap)
736
1007
  local pkg
737
1008
  for pkg in "$@"; do
@@ -777,6 +1048,18 @@ manager_remove() {
777
1048
  brew)
778
1049
  brew uninstall "$@"
779
1050
  ;;
1051
+ winget)
1052
+ local pkg
1053
+ for pkg in "$@"; do
1054
+ winget uninstall --id "${pkg}" --exact --disable-interactivity
1055
+ done
1056
+ ;;
1057
+ choco)
1058
+ choco uninstall "$@" -y
1059
+ ;;
1060
+ scoop)
1061
+ scoop uninstall "$@"
1062
+ ;;
780
1063
  snap)
781
1064
  run_as_root snap remove "$@"
782
1065
  ;;
@@ -815,6 +1098,15 @@ manager_show_info() {
815
1098
  brew)
816
1099
  brew info "${package}" 2>/dev/null
817
1100
  ;;
1101
+ winget)
1102
+ winget show --id "${package}" --exact --source winget --accept-source-agreements --disable-interactivity 2>/dev/null
1103
+ ;;
1104
+ choco)
1105
+ choco info "${package}" 2>/dev/null
1106
+ ;;
1107
+ scoop)
1108
+ scoop info "${package}" 2>/dev/null
1109
+ ;;
818
1110
  snap)
819
1111
  snap info "${package}" 2>/dev/null
820
1112
  ;;
@@ -856,6 +1148,16 @@ manager_update() {
856
1148
  brew update
857
1149
  brew upgrade
858
1150
  ;;
1151
+ winget)
1152
+ winget upgrade --all --source winget --accept-package-agreements --accept-source-agreements --disable-interactivity
1153
+ ;;
1154
+ choco)
1155
+ choco upgrade all -y
1156
+ ;;
1157
+ scoop)
1158
+ scoop update
1159
+ scoop update "*"
1160
+ ;;
859
1161
  snap)
860
1162
  run_as_root snap refresh
861
1163
  ;;
@@ -894,7 +1196,7 @@ run_fuzzy_selector() {
894
1196
  local header_line="$3"
895
1197
  local preview_cmd
896
1198
 
897
- preview_cmd='bash -c '\''mgr="$1"; pkg="$2"; case "$mgr" in apt) apt-cache show "$pkg" 2>/dev/null; printf "\n"; dpkg -L "$pkg" 2>/dev/null ;; dnf) dnf info "$pkg" 2>/dev/null; printf "\n"; rpm -ql "$pkg" 2>/dev/null ;; pacman) pacman -Si "$pkg" 2>/dev/null; printf "\n"; pacman -Fl "$pkg" 2>/dev/null | awk "{print \$2}" ;; zypper) zypper --non-interactive info "$pkg" 2>/dev/null ;; emerge) emerge --search --color=n "$pkg" 2>/dev/null ;; brew) brew info "$pkg" 2>/dev/null ;; snap) snap info "$pkg" 2>/dev/null ;; flatpak) flatpak info "$pkg" 2>/dev/null || flatpak remote-info flathub "$pkg" 2>/dev/null ;; npm) npm view "$pkg" 2>/dev/null ;; bun) bun info "$pkg" 2>/dev/null || npm view "$pkg" 2>/dev/null ;; esac'\'' _ {1} {2}'
1199
+ preview_cmd='bash -c '\''mgr="$1"; pkg="$2"; case "$mgr" in apt) apt-cache show "$pkg" 2>/dev/null; printf "\n"; dpkg -L "$pkg" 2>/dev/null ;; dnf) dnf info "$pkg" 2>/dev/null; printf "\n"; rpm -ql "$pkg" 2>/dev/null ;; pacman) pacman -Si "$pkg" 2>/dev/null; printf "\n"; pacman -Fl "$pkg" 2>/dev/null | awk "{print \$2}" ;; zypper) zypper --non-interactive info "$pkg" 2>/dev/null ;; emerge) emerge --search --color=n "$pkg" 2>/dev/null ;; brew) brew info "$pkg" 2>/dev/null ;; winget) winget show --id "$pkg" --exact --source winget --accept-source-agreements --disable-interactivity 2>/dev/null ;; choco) choco info "$pkg" 2>/dev/null ;; scoop) scoop info "$pkg" 2>/dev/null ;; snap) snap info "$pkg" 2>/dev/null ;; flatpak) flatpak info "$pkg" 2>/dev/null || flatpak remote-info flathub "$pkg" 2>/dev/null ;; npm) npm view "$pkg" 2>/dev/null ;; bun) bun info "$pkg" 2>/dev/null || npm view "$pkg" 2>/dev/null ;; esac'\'' _ {1} {2}'
898
1200
 
899
1201
  fzf -q "${query}" -e -m \
900
1202
  --delimiter=$'\t' \
@@ -978,7 +1280,7 @@ main() {
978
1280
  exit 0
979
1281
  fi
980
1282
 
981
- command_exists fzf || die "fzf is required"
1283
+ ensure_fzf "${managers[@]-}"
982
1284
 
983
1285
  local display_file
984
1286
  display_file="$(mktemp "${TMP_ROOT}/display.XXXXXX")"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fpf-cli",
3
- "version": "1.2.0",
3
+ "version": "1.5.0",
4
4
  "description": "Cross-platform fuzzy package finder powered by fzf",
5
5
  "bin": {
6
6
  "fpf": "fpf"
@@ -19,11 +19,12 @@
19
19
  "pacman",
20
20
  "zypper",
21
21
  "brew",
22
+ "winget",
22
23
  "npm",
23
24
  "bun"
24
25
  ],
25
26
  "author": "Timmy6942025 <timothy.thomas2011@hotmail.com>",
26
- "license": "GPL-3.0-or-later",
27
+ "license": "Apache-2.0",
27
28
  "repository": {
28
29
  "type": "git",
29
30
  "url": "git+https://github.com/Timmy6942025/fpf-cli.git"