├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ └── publish.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── conf.d └── pnpm-shell-completion.fish ├── install.fish ├── install.zsh ├── pnpm-shell-completion.plugin.zsh ├── pnpm-shell-completion.ps1 ├── pnpm.fish ├── src ├── deps.rs ├── filter.rs ├── main.rs ├── monorepo.rs ├── pnpm_cmd.rs ├── scripts.rs └── types.rs └── zplug.zsh /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.{md,yml}] 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: g-plane 2 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*.*.*" 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | publish: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | settings: 17 | - host: macos-latest 18 | target: x86_64-apple-darwin 19 | build: cargo build --target=x86_64-apple-darwin --release 20 | - host: macos-14 21 | target: aarch64-apple-darwin 22 | build: | 23 | sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/*; 24 | export CC=$(xcrun -f clang); 25 | export CXX=$(xcrun -f clang++); 26 | SYSROOT=$(xcrun --sdk macosx --show-sdk-path); 27 | export CFLAGS="-isysroot $SYSROOT -isystem $SYSROOT"; 28 | cargo build --target=aarch64-apple-darwin --release 29 | - host: ubuntu-latest 30 | target: x86_64-unknown-linux-gnu 31 | build: cargo build --target=x86_64-unknown-linux-gnu --release 32 | - host: ubuntu-latest 33 | target: x86_64-unknown-linux-musl 34 | build: cargo build --target=x86_64-unknown-linux-musl --release 35 | - host: windows-latest 36 | target: x86_64-pc-windows-gnu 37 | build: cargo build --target=x86_64-pc-windows-gnu --release 38 | name: ${{ matrix.settings.target }} 39 | runs-on: ${{ matrix.settings.host }} 40 | steps: 41 | - uses: actions/checkout@v3 42 | - name: Install 43 | uses: dtolnay/rust-toolchain@stable 44 | with: 45 | targets: ${{ matrix.settings.target }} 46 | - name: Build 47 | run: ${{ matrix.settings.build }} 48 | - name: Pack 49 | if: matrix.settings.host != 'windows-latest' 50 | run: | 51 | mkdir dist 52 | cp ./target/${{ matrix.settings.target }}/release/pnpm-shell-completion dist/ 53 | cp ./pnpm-shell-completion.plugin.zsh dist/ 54 | cp ./install.zsh dist/ 55 | cp ./pnpm.fish dist/ 56 | cp ./install.fish dist/ 57 | cp ./README.md dist/ 58 | cp ./LICENSE dist/ 59 | cd dist 60 | zip ../pnpm-shell-completion_${{ matrix.settings.target }}.zip ./* 61 | tar -zcvf ../pnpm-shell-completion_${{ matrix.settings.target }}.tar.gz * 62 | ls -l 63 | cd .. 64 | - name: Pack 65 | shell: pwsh 66 | run: | 67 | if (Test-Path dist) { 68 | Remove-Item -Recurse -Force dist 69 | } 70 | New-Item -ItemType Directory dist 71 | if (Test-Path .\target\${{ matrix.settings.target }}\release\pnpm-shell-completion.exe) { 72 | Copy-Item .\target\${{ matrix.settings.target }}\release\pnpm-shell-completion.exe dist 73 | } 74 | elseif (Test-Path .\target\${{ matrix.settings.target }}\release\pnpm-shell-completion) { 75 | Copy-Item .\target\${{ matrix.settings.target }}\release\pnpm-shell-completion dist 76 | } 77 | Copy-Item .\pnpm-shell-completion.ps1 dist 78 | Copy-Item .\README.md dist 79 | Copy-Item .\LICENSE dist 80 | Compress-Archive "dist\*" pnpm-shell-completion_pwsh_${{ matrix.settings.target }}.zip 81 | - name: Release 82 | uses: softprops/action-gh-release@v1 83 | with: 84 | files: | 85 | pnpm-shell-completion_*.zip 86 | pnpm-shell-completion_*.tar.gz 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.9" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" 25 | dependencies = [ 26 | "cfg-if", 27 | "getrandom", 28 | "once_cell", 29 | "serde", 30 | "version_check", 31 | "zerocopy", 32 | ] 33 | 34 | [[package]] 35 | name = "aho-corasick" 36 | version = "1.1.2" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" 39 | dependencies = [ 40 | "memchr", 41 | ] 42 | 43 | [[package]] 44 | name = "anyhow" 45 | version = "1.0.80" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" 48 | 49 | [[package]] 50 | name = "autocfg" 51 | version = "1.1.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 54 | 55 | [[package]] 56 | name = "backtrace" 57 | version = "0.3.69" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 60 | dependencies = [ 61 | "addr2line", 62 | "cc", 63 | "cfg-if", 64 | "libc", 65 | "miniz_oxide", 66 | "object", 67 | "rustc-demangle", 68 | ] 69 | 70 | [[package]] 71 | name = "bstr" 72 | version = "1.9.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" 75 | dependencies = [ 76 | "memchr", 77 | "serde", 78 | ] 79 | 80 | [[package]] 81 | name = "cc" 82 | version = "1.0.86" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" 85 | 86 | [[package]] 87 | name = "cfg-if" 88 | version = "1.0.0" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 91 | 92 | [[package]] 93 | name = "crossbeam-deque" 94 | version = "0.8.5" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 97 | dependencies = [ 98 | "crossbeam-epoch", 99 | "crossbeam-utils", 100 | ] 101 | 102 | [[package]] 103 | name = "crossbeam-epoch" 104 | version = "0.9.18" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 107 | dependencies = [ 108 | "crossbeam-utils", 109 | ] 110 | 111 | [[package]] 112 | name = "crossbeam-utils" 113 | version = "0.8.19" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" 116 | 117 | [[package]] 118 | name = "either" 119 | version = "1.10.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" 122 | 123 | [[package]] 124 | name = "equivalent" 125 | version = "1.0.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 128 | 129 | [[package]] 130 | name = "futures" 131 | version = "0.3.30" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" 134 | dependencies = [ 135 | "futures-channel", 136 | "futures-core", 137 | "futures-executor", 138 | "futures-io", 139 | "futures-sink", 140 | "futures-task", 141 | "futures-util", 142 | ] 143 | 144 | [[package]] 145 | name = "futures-channel" 146 | version = "0.3.30" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 149 | dependencies = [ 150 | "futures-core", 151 | "futures-sink", 152 | ] 153 | 154 | [[package]] 155 | name = "futures-core" 156 | version = "0.3.30" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 159 | 160 | [[package]] 161 | name = "futures-executor" 162 | version = "0.3.30" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" 165 | dependencies = [ 166 | "futures-core", 167 | "futures-task", 168 | "futures-util", 169 | ] 170 | 171 | [[package]] 172 | name = "futures-io" 173 | version = "0.3.30" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 176 | 177 | [[package]] 178 | name = "futures-macro" 179 | version = "0.3.30" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 182 | dependencies = [ 183 | "proc-macro2", 184 | "quote", 185 | "syn", 186 | ] 187 | 188 | [[package]] 189 | name = "futures-sink" 190 | version = "0.3.30" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 193 | 194 | [[package]] 195 | name = "futures-task" 196 | version = "0.3.30" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 199 | 200 | [[package]] 201 | name = "futures-util" 202 | version = "0.3.30" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 205 | dependencies = [ 206 | "futures-channel", 207 | "futures-core", 208 | "futures-io", 209 | "futures-macro", 210 | "futures-sink", 211 | "futures-task", 212 | "memchr", 213 | "pin-project-lite", 214 | "pin-utils", 215 | "slab", 216 | ] 217 | 218 | [[package]] 219 | name = "getrandom" 220 | version = "0.2.12" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" 223 | dependencies = [ 224 | "cfg-if", 225 | "libc", 226 | "wasi", 227 | ] 228 | 229 | [[package]] 230 | name = "gimli" 231 | version = "0.28.1" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 234 | 235 | [[package]] 236 | name = "globset" 237 | version = "0.4.14" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" 240 | dependencies = [ 241 | "aho-corasick", 242 | "bstr", 243 | "log", 244 | "regex-automata", 245 | "regex-syntax", 246 | ] 247 | 248 | [[package]] 249 | name = "hashbrown" 250 | version = "0.14.3" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 253 | 254 | [[package]] 255 | name = "hermit-abi" 256 | version = "0.3.6" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" 259 | 260 | [[package]] 261 | name = "ignore" 262 | version = "0.4.22" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" 265 | dependencies = [ 266 | "crossbeam-deque", 267 | "globset", 268 | "log", 269 | "memchr", 270 | "regex-automata", 271 | "same-file", 272 | "walkdir", 273 | "winapi-util", 274 | ] 275 | 276 | [[package]] 277 | name = "indexmap" 278 | version = "2.2.3" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" 281 | dependencies = [ 282 | "equivalent", 283 | "hashbrown", 284 | ] 285 | 286 | [[package]] 287 | name = "itertools" 288 | version = "0.12.1" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 291 | dependencies = [ 292 | "either", 293 | ] 294 | 295 | [[package]] 296 | name = "itoa" 297 | version = "1.0.10" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" 300 | 301 | [[package]] 302 | name = "libc" 303 | version = "0.2.153" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 306 | 307 | [[package]] 308 | name = "log" 309 | version = "0.4.20" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 312 | 313 | [[package]] 314 | name = "memchr" 315 | version = "2.7.1" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" 318 | 319 | [[package]] 320 | name = "miniz_oxide" 321 | version = "0.7.2" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" 324 | dependencies = [ 325 | "adler", 326 | ] 327 | 328 | [[package]] 329 | name = "num_cpus" 330 | version = "1.16.0" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 333 | dependencies = [ 334 | "hermit-abi", 335 | "libc", 336 | ] 337 | 338 | [[package]] 339 | name = "object" 340 | version = "0.32.2" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 343 | dependencies = [ 344 | "memchr", 345 | ] 346 | 347 | [[package]] 348 | name = "once_cell" 349 | version = "1.19.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 352 | 353 | [[package]] 354 | name = "pin-project-lite" 355 | version = "0.2.13" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 358 | 359 | [[package]] 360 | name = "pin-utils" 361 | version = "0.1.0" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 364 | 365 | [[package]] 366 | name = "pnpm-shell-completion" 367 | version = "0.5.4" 368 | dependencies = [ 369 | "ahash", 370 | "anyhow", 371 | "futures", 372 | "globset", 373 | "ignore", 374 | "itertools", 375 | "serde", 376 | "serde_json", 377 | "serde_yaml", 378 | "tokio", 379 | ] 380 | 381 | [[package]] 382 | name = "proc-macro2" 383 | version = "1.0.78" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" 386 | dependencies = [ 387 | "unicode-ident", 388 | ] 389 | 390 | [[package]] 391 | name = "quote" 392 | version = "1.0.35" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 395 | dependencies = [ 396 | "proc-macro2", 397 | ] 398 | 399 | [[package]] 400 | name = "regex-automata" 401 | version = "0.4.5" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" 404 | dependencies = [ 405 | "aho-corasick", 406 | "memchr", 407 | "regex-syntax", 408 | ] 409 | 410 | [[package]] 411 | name = "regex-syntax" 412 | version = "0.8.2" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 415 | 416 | [[package]] 417 | name = "rustc-demangle" 418 | version = "0.1.23" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 421 | 422 | [[package]] 423 | name = "ryu" 424 | version = "1.0.17" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 427 | 428 | [[package]] 429 | name = "same-file" 430 | version = "1.0.6" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 433 | dependencies = [ 434 | "winapi-util", 435 | ] 436 | 437 | [[package]] 438 | name = "serde" 439 | version = "1.0.197" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" 442 | dependencies = [ 443 | "serde_derive", 444 | ] 445 | 446 | [[package]] 447 | name = "serde_derive" 448 | version = "1.0.197" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" 451 | dependencies = [ 452 | "proc-macro2", 453 | "quote", 454 | "syn", 455 | ] 456 | 457 | [[package]] 458 | name = "serde_json" 459 | version = "1.0.114" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" 462 | dependencies = [ 463 | "itoa", 464 | "ryu", 465 | "serde", 466 | ] 467 | 468 | [[package]] 469 | name = "serde_yaml" 470 | version = "0.9.32" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" 473 | dependencies = [ 474 | "indexmap", 475 | "itoa", 476 | "ryu", 477 | "serde", 478 | "unsafe-libyaml", 479 | ] 480 | 481 | [[package]] 482 | name = "slab" 483 | version = "0.4.9" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 486 | dependencies = [ 487 | "autocfg", 488 | ] 489 | 490 | [[package]] 491 | name = "syn" 492 | version = "2.0.50" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" 495 | dependencies = [ 496 | "proc-macro2", 497 | "quote", 498 | "unicode-ident", 499 | ] 500 | 501 | [[package]] 502 | name = "tokio" 503 | version = "1.36.0" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" 506 | dependencies = [ 507 | "backtrace", 508 | "num_cpus", 509 | "pin-project-lite", 510 | "tokio-macros", 511 | ] 512 | 513 | [[package]] 514 | name = "tokio-macros" 515 | version = "2.2.0" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" 518 | dependencies = [ 519 | "proc-macro2", 520 | "quote", 521 | "syn", 522 | ] 523 | 524 | [[package]] 525 | name = "unicode-ident" 526 | version = "1.0.12" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 529 | 530 | [[package]] 531 | name = "unsafe-libyaml" 532 | version = "0.2.10" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" 535 | 536 | [[package]] 537 | name = "version_check" 538 | version = "0.9.4" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 541 | 542 | [[package]] 543 | name = "walkdir" 544 | version = "2.4.0" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" 547 | dependencies = [ 548 | "same-file", 549 | "winapi-util", 550 | ] 551 | 552 | [[package]] 553 | name = "wasi" 554 | version = "0.11.0+wasi-snapshot-preview1" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 557 | 558 | [[package]] 559 | name = "winapi" 560 | version = "0.3.9" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 563 | dependencies = [ 564 | "winapi-i686-pc-windows-gnu", 565 | "winapi-x86_64-pc-windows-gnu", 566 | ] 567 | 568 | [[package]] 569 | name = "winapi-i686-pc-windows-gnu" 570 | version = "0.4.0" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 573 | 574 | [[package]] 575 | name = "winapi-util" 576 | version = "0.1.6" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" 579 | dependencies = [ 580 | "winapi", 581 | ] 582 | 583 | [[package]] 584 | name = "winapi-x86_64-pc-windows-gnu" 585 | version = "0.4.0" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 588 | 589 | [[package]] 590 | name = "zerocopy" 591 | version = "0.7.32" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" 594 | dependencies = [ 595 | "zerocopy-derive", 596 | ] 597 | 598 | [[package]] 599 | name = "zerocopy-derive" 600 | version = "0.7.32" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" 603 | dependencies = [ 604 | "proc-macro2", 605 | "quote", 606 | "syn", 607 | ] 608 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pnpm-shell-completion" 3 | version = "0.5.4" 4 | edition = "2021" 5 | authors = ["Pig Fang "] 6 | description = "Complete your pnpm command fastly." 7 | repository = "https://github.com/g-plane/pnpm-shell-completion" 8 | license = "MIT" 9 | publish = false 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ahash = { version = "0.8", features = ["serde"] } 15 | anyhow = "1.0" 16 | futures = "0.3" 17 | globset = "0.4" 18 | ignore = "0.4" 19 | itertools = "0.12" 20 | serde = { version = "1.0", features = ["derive"] } 21 | serde_json = "1.0" 22 | serde_yaml = "0.9" 23 | tokio = { version = "1.36", features = ["fs", "macros", "rt-multi-thread"] } 24 | 25 | [profile.release] 26 | codegen-units = 1 27 | strip = true 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-present Pig Fang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pnpm-shell-completion 2 | 3 | https://user-images.githubusercontent.com/17216317/218267283-ac16f583-506e-473f-9efc-e25095e38504.mp4 4 | 5 | or 6 | 7 | [![asciicast](https://asciinema.org/a/559081.svg)](https://asciinema.org/a/559081) 8 | 9 | **fish** 10 | 11 | https://user-images.githubusercontent.com/17974631/230724177-c23eb38c-6112-49f8-8091-54c68a074739.webm 12 | 13 | _You may also like:_ 14 | 15 | - [icd](https://github.com/g-plane/icd) - Powerful `cd` command with fuzzy-search tool. 16 | 17 | ## Features 18 | 19 | - Provide completion for `pnpm --filter `. 20 | - Provide completion for `pnpm remove` command, even in workspace's packages (by specifying `--filter` option). 21 | - Provide completion for npm scripts in `package.json`. 22 | 23 | ### Limitiation 24 | 25 | - Note that we won't provide completion for all commands and options, and we only focus those frequently used. Too many completion items may have impact on efficiency. 26 | - NPM scripts completion requires the presence of a `name` property in the `package.json` file. 27 | 28 | ### Supported shells 29 | 30 | - Zsh 31 | - PowerShell Core 32 | - Fish Shell 33 | 34 | ## Installation 35 | 36 | ### [zinit](https://github.com/zdharma/zinit) 37 | 38 | Update your `.zshrc` file with the following line: 39 | 40 | ```zsh 41 | zinit ice atload"zpcdreplay" atclone"./zplug.zsh" atpull"%atclone" 42 | zinit light g-plane/pnpm-shell-completion 43 | ``` 44 | 45 | ### [zplug](https://github.com/zplug/zplug) 46 | 47 | Update your `.zshrc` file with the following line: 48 | 49 | ```zsh 50 | zplug "g-plane/pnpm-shell-completion", hook-build:"./zplug.zsh", defer:2 51 | ``` 52 | 53 | ### Arch Linux 54 | 55 | Install it with any AUR helper, for example: 56 | 57 | ```shell 58 | paru -S pnpm-shell-completion 59 | ``` 60 | 61 | Then, update your `.zshrc` file with the following line: 62 | 63 | ```shell 64 | source /usr/share/zsh/plugins/pnpm-shell-completion/pnpm-shell-completion.zsh 65 | ``` 66 | 67 | ### Oh My Zsh 68 | 69 | #### Manual 70 | 71 | Please go to the [GitHub releases](https://github.com/g-plane/pnpm-shell-completion/releases) 72 | page and download the latest binary files. 73 | 74 | For Apple Silicon (M-series chips) users, please choose `aarch64-apple-darwin`; 75 | for Intel Mac users, please choose `x86_64-apple-darwin`; 76 | for Linux users, please choose `x86_64-unknown-linux-gnu` or `x86_64-unknown-linux-musl`. 77 | 78 | After downloaded, decompress the `.zip` or `.tar.gz` file. 79 | 80 | Then, run: 81 | 82 | ```shell 83 | ./install.zsh $ZSH_CUSTOM/plugins 84 | ``` 85 | 86 | Next, please edit your `.zshrc` file. 87 | Add `pnpm-shell-completion` to `plugins` section like this: 88 | 89 | ```diff 90 | plugins=( 91 | # ... your other plugins 92 | + pnpm-shell-completion 93 | ) 94 | ``` 95 | 96 | Restart your terminal. 97 | 98 | #### With Bun 99 | 100 | *Disclaimer: the `pnpm-oh-my-zsh-completion-install` package isn't maintained officially, and we can't guarantee the security so use at your own risk.* 101 | 102 | If you have [Bun](https://bun.sh/), you can run `bunx pnpm-oh-my-zsh-completion-install` which will download latest release, unpack, copy and add the plugin to your `.zshrc`. 103 | 104 | ### [Zim](https://github.com/zimfw/zimfw) 105 | 106 | Add the following line to your `.zimrc` file: 107 | 108 | ```shell 109 | zmodule git@github.com:g-plane/pnpm-shell-completion.git --on-pull './zplug.zsh' 110 | ``` 111 | 112 | Make sure this line comes after `zmodule completion`. If it doesn't exist, add it manually. 113 | 114 | ### PowerShell Core 115 | 116 | Please go to the [GitHub releases](https://github.com/g-plane/pnpm-shell-completion/releases) 117 | page and download `pnpm-shell-completion_x86_64-pc-windows-gnu.zip`, then decompress it. 118 | 119 | Edit your PowerShell profile file (if you don't know where it is, run `echo $PROFILE` to check it), 120 | and add the following line: 121 | 122 | ```powershell 123 | . path\to\the\directory\you\decompressed\pnpm-shell-completion.ps1 124 | ``` 125 | 126 | ### Fish 127 | 128 | #### [Fisher](https://github.com/jorgebucaran/fisher) 129 | 130 | ``` 131 | fisher install g-plane/pnpm-shell-completion 132 | ``` 133 | 134 | #### Manual Install 135 | 136 | Please go to the [GitHub releases](https://github.com/g-plane/pnpm-shell-completion/releases) 137 | page and download the latest binary files. 138 | 139 | For Apple Silicon (M-series chips) users, please choose `aarch64-apple-darwin`; 140 | for Intel Mac users, please choose `x86_64-apple-darwin`; 141 | for Linux users, please choose `x86_64-unknown-linux-gnu` or `x86_64-unknown-linux-musl`. 142 | 143 | After downloaded, decompress the `.zip` or `.tar.gz` file. 144 | 145 | Then, run: 146 | 147 | ```shell 148 | fish ./install.fish ${any path that has been added in your $PATH variable} 149 | ``` 150 | 151 | By default, `pnpm.fish` will be copied to your `~/.config/fish/completions/` according to the [official documentation](https://fishshell.com/docs/current/completions.html). 152 | 153 | ## License 154 | 155 | MIT License 156 | 157 | Copyright (c) 2023-present Pig Fang 158 | -------------------------------------------------------------------------------- /conf.d/pnpm-shell-completion.fish: -------------------------------------------------------------------------------- 1 | function _pnpm-shell-completion_install --on-event pnpm-shell-completion_install 2 | set OS (uname -s) 3 | set arch (uname -m) 4 | if test $OS = "Darwin" 5 | if test $arch = "arm64" 6 | set target "aarch64-apple-darwin" 7 | else 8 | set target "x86_64-apple-darwin" 9 | end 10 | else 11 | set target "x86_64-unknown-linux-musl" 12 | end 13 | 14 | echo "Downloading `pnpm-shell-completion` binary…" 15 | set release_url "https://github.com/g-plane/pnpm-shell-completion/releases/latest/download/pnpm-shell-completion_$target.zip" 16 | curl -sL $release_url -o release.zip 17 | 18 | unzip -o release.zip pnpm-shell-completion -d $HOME/.local/bin 19 | 20 | mkdir -p $__fish_config_dir/completions/ 21 | unzip -o release.zip pnpm.fish -d $__fish_config_dir/completions/ 22 | 23 | rm release.zip 24 | end 25 | -------------------------------------------------------------------------------- /install.fish: -------------------------------------------------------------------------------- 1 | if not set -q argv[1] 2 | echo "Plugins directory not specified. Please pass your zsh plugins directory as a parameter." 3 | exit 1 4 | end 5 | 6 | if test -d $argv[1] 7 | mkdir -p ~/.config/fish/completions/ 8 | cp ./pnpm.fish ~/.config/fish/completions/pnpm.fish 9 | cp ./pnpm-shell-completion $argv[1] 10 | else 11 | echo "$argv[1] is not exist" 12 | end 13 | -------------------------------------------------------------------------------- /install.zsh: -------------------------------------------------------------------------------- 1 | set -x 2 | 3 | if [ -z "$1" ]; then 4 | echo "Plugins directory not specified, please pass your zsh plugins directory as a parameter." 5 | exit 1 6 | fi 7 | 8 | if [ ! -d $1/pnpm-shell-completion ]; then 9 | mkdir $1/pnpm-shell-completion 10 | fi 11 | 12 | cp ./pnpm-shell-completion.plugin.zsh $1/pnpm-shell-completion 13 | cp ./pnpm-shell-completion $1/pnpm-shell-completion 14 | -------------------------------------------------------------------------------- /pnpm-shell-completion.plugin.zsh: -------------------------------------------------------------------------------- 1 | #compdef pnpm 2 | 3 | if command -v pnpm-shell-completion &> /dev/null; then 4 | pnpm_comp_bin="$(which pnpm-shell-completion)" 5 | else 6 | pnpm_comp_bin="$(dirname $0)/pnpm-shell-completion" 7 | fi 8 | 9 | _pnpm() { 10 | typeset -A opt_args 11 | 12 | _arguments \ 13 | '(--filter -F)'{--filter,-F}'=:flag:->filter' \ 14 | ':command:->scripts' \ 15 | '*:: :->command_args' 16 | 17 | local target_pkg=${opt_args[--filter]:-$opt_args[-F]} 18 | 19 | case $state in 20 | filter) 21 | if [[ -f ./pnpm-workspace.yaml ]]; then 22 | _values 'filter packages' $(FEATURE=filter $pnpm_comp_bin) 23 | fi 24 | ;; 25 | scripts) 26 | _values 'scripts' $(FEATURE=scripts TARGET_PKG=$target_pkg ZSH=true $pnpm_comp_bin) \ 27 | add remove install update publish 28 | ;; 29 | command_args) 30 | local cmd=$(FEATURE=pnpm_cmd $pnpm_comp_bin $words) 31 | case $cmd in 32 | add) 33 | _arguments \ 34 | '(--global -g)'{--global,-g}'[Install as a global package]' \ 35 | '(--save-dev -D)'{--save-dev,-D}'[Save package to your `devDependencies`]' \ 36 | '--save-peer[Save package to your `peerDependencies` and `devDependencies`]' 37 | ;; 38 | install|i) 39 | _arguments \ 40 | '(--dev -D)'{--dev,-D}'[Only `devDependencies` are installed regardless of the `NODE_ENV`]' \ 41 | '--fix-lockfile[Fix broken lockfile entries automatically]' \ 42 | '--force[Force reinstall dependencies]' \ 43 | "--ignore-scripts[Don't run lifecycle scripts]" \ 44 | '--lockfile-only[Dependencies are not downloaded. Only `pnpm-lock.yaml` is updated]' \ 45 | '--no-optional[`optionalDependencies` are not installed]' \ 46 | '--offline[Trigger an error if any required dependencies are not available in local store]' \ 47 | '--prefer-offline[Skip staleness checks for cached data, but request missing data from the server]' \ 48 | '(--prod -P)'{--prod,-P}"[Packages in \`devDependencies\` won't be installed]" 49 | ;; 50 | remove|rm|why) 51 | if [[ -f ./package.json ]]; then 52 | _values 'deps' $(FEATURE=deps TARGET_PKG=$target_pkg $pnpm_comp_bin) 53 | fi 54 | ;; 55 | update|upgrade|up) 56 | _arguments \ 57 | '(--dev -D)'{--dev,-D}'[Update packages only in "devDependencies"]' \ 58 | '(--global -g)'{--global,-g}'[Update globally installed packages]' \ 59 | '(--interactive -i)'{--interactive,-i}'[Show outdated dependencies and select which ones to update]' \ 60 | '(--latest -L)'{--latest,-L}'[Ignore version ranges in package.json]' \ 61 | "--no-optional[Don't update packages in \`optionalDependencies\`]" \ 62 | '(--prod -P)'{--prod,-P}'[Update packages only in "dependencies" and "optionalDependencies"]' \ 63 | '(--recursive -r)'{--recursive,-r}'[Update in every package found in subdirectories or every workspace package]' 64 | if [[ -f ./package.json ]]; then 65 | _values 'deps' $(FEATURE=deps TARGET_PKG=$target_pkg $pnpm_comp_bin) 66 | fi 67 | ;; 68 | publish) 69 | _arguments \ 70 | '--access=[Tells the registry whether this package should be published as public or restricted]: :(public restricted)' \ 71 | '--dry-run[Does everything a publish would do except actually publishing to the registry]' \ 72 | '--force[Packages are proceeded to be published even if their current version is already in the registry]' \ 73 | '--ignore-scripts[Ignores any publish related lifecycle scripts (prepublishOnly, postpublish, and the like)]' \ 74 | "--no-git-checks[Don't check if current branch is your publish branch, clean, and up to date]" \ 75 | '--otp[Specify a one-time password]' \ 76 | '--publish-branch[Sets branch name to publish]' \ 77 | '(--recursive -r)'{--recursive,-r}'[Publish all packages from the workspace]' \ 78 | '--tag=[Registers the published package with the given tag]' 79 | ;; 80 | run) 81 | if [[ -f ./package.json ]]; then 82 | _values 'scripts' $(FEATURE=scripts TARGET_PKG=$target_pkg ZSH=true $pnpm_comp_bin) 83 | fi 84 | ;; 85 | *) 86 | _files 87 | esac 88 | esac 89 | } 90 | 91 | compdef _pnpm pnpm 92 | -------------------------------------------------------------------------------- /pnpm-shell-completion.ps1: -------------------------------------------------------------------------------- 1 | Register-ArgumentCompleter -CommandName pnpm -Native -ScriptBlock { 2 | param($wordToComplete, $commandAst) 3 | 4 | $bin = if (Test-Path "$PSScriptRoot/pnpm-shell-completion.exe") { 5 | "$PSScriptRoot/pnpm-shell-completion.exe" 6 | } 7 | elseif (Test-Path "$PSScriptRoot/pnpm-shell-completion") { 8 | "$PSScriptRoot/pnpm-shell-completion" 9 | } 10 | elseif (Test-Path pnpm-shell-completion.exe) { 11 | "pnpm-shell-completion.exe" 12 | } 13 | elseif (Test-Path pnpm-shell-completion) { 14 | "pnpm-shell-completion" 15 | } 16 | else { 17 | return 18 | } 19 | 20 | if ($commandAst.CommandElements.Count -eq 1) { 21 | $items = @("add", "remove", "install", "update", "publish") 22 | if (Test-Path "./pnpm-workspace.yaml") { 23 | $items += @("-F", "--filter") 24 | } 25 | if (Test-Path "./package.json") { 26 | $env:FEATURE = "scripts" 27 | $items += $(& $bin $words).Split("`n") 28 | Remove-Item Env:\FEATURE 29 | } 30 | return $items | ForEach-Object { 31 | [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) 32 | } 33 | } 34 | 35 | $words = $commandAst.CommandElements | ForEach-Object { $_.ToString() } 36 | $words = $words[1..$words.Count] 37 | $snd = $commandAst.CommandElements[1].ToString() 38 | $hasFilterWithoutEquals = $snd -eq "-F" -or $snd -eq "--filter" 39 | 40 | $result = if ($hasFilterWithoutEquals -and $commandAst.CommandElements.Count -eq 2) { 41 | $env:FEATURE = "filter" 42 | $(& $bin).Split("`n") | ForEach-Object { 43 | [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) 44 | } 45 | } 46 | elseif ($wordToComplete.StartsWith("-F=") -or $wordToComplete.StartsWith("--filter=")) { 47 | $env:FEATURE = "filter" 48 | $param = $wordToComplete.Split("=")[0] 49 | $(& $bin).Split("`n") | ForEach-Object { 50 | $param = $wordToComplete.Split("=")[0] 51 | [System.Management.Automation.CompletionResult]::new($param + "=" + $_, $_, 'ParameterValue', $_) 52 | } 53 | } 54 | else { 55 | $env:FEATURE = "pnpm_cmd" 56 | $cmd = $(& $bin $words) 57 | 58 | if ($cmd -eq "add") { 59 | @( 60 | [System.Management.Automation.CompletionResult]::new("--global", "--global", 'ParameterValue', "Install as a global package"), 61 | [System.Management.Automation.CompletionResult]::new("--save-dev", "--save-dev", 'ParameterValue', "Save package to your ``devDependencies``"), 62 | [System.Management.Automation.CompletionResult]::new("--save-peer", "--save-peer", 'ParameterValue', "Save package to your ``peerDependencies`` and ``devDependencies``") 63 | ) 64 | } 65 | elseif ($cmd -eq "install" -or $cmd -eq "i") { 66 | @( 67 | [System.Management.Automation.CompletionResult]::new("--dev", "--dev", 'ParameterValue', "Only ``devDependencies`` are installed regardless of the ``NODE_ENV``"), 68 | [System.Management.Automation.CompletionResult]::new("--fix-lockfile", "--fix-lockfile", 'ParameterValue', "Fix broken lockfile entries automatically"), 69 | [System.Management.Automation.CompletionResult]::new("--force", "--force", 'ParameterValue', "Force reinstall dependencies"), 70 | [System.Management.Automation.CompletionResult]::new("--ignore-scripts", "--ignore-scripts", 'ParameterValue', "Don't run lifecycle scripts"), 71 | [System.Management.Automation.CompletionResult]::new("--lockfile-only", "--lockfile-only", 'ParameterValue', "Dependencies are not downloaded. Only ``pnpm-lock.yaml`` is updated"), 72 | [System.Management.Automation.CompletionResult]::new("--no-optional", "--no-optional", 'ParameterValue', "``optionalDependencies`` are not installed"), 73 | [System.Management.Automation.CompletionResult]::new("--offline", "--offline", 'ParameterValue', "Trigger an error if any required dependencies are not available in local store"), 74 | [System.Management.Automation.CompletionResult]::new("--prefer-offline", "--prefer-offline", 'ParameterValue', "Skip staleness checks for cached data, but request missing data from the server"), 75 | [System.Management.Automation.CompletionResult]::new("--prod", "--prod", 'ParameterValue', "Packages in ``devDependencies`` won't be installed") 76 | ) 77 | } 78 | elseif ($cmd -eq "remove" -or $cmd -eq "rm" -or $cmd -eq "why") { 79 | $env:FEATURE = "deps" 80 | $(& $bin $words).Split("`n") | ForEach-Object { 81 | [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) 82 | } 83 | } 84 | elseif ($cmd -eq "update" -or $cmd -eq "upgrade" -or $cmd -eq "up") { 85 | $options = @( 86 | [System.Management.Automation.CompletionResult]::new("--dev", "--dev", 'ParameterValue', "Update packages only in `"devDependencies`""), 87 | [System.Management.Automation.CompletionResult]::new("--global", "--global", 'ParameterValue', "Update globally installed packages"), 88 | [System.Management.Automation.CompletionResult]::new("--interactive", "--interactive", 'ParameterValue', "Show outdated dependencies and select which ones to update"), 89 | [System.Management.Automation.CompletionResult]::new("--latest", "--latest", 'ParameterValue', "Ignore version ranges in package.json"), 90 | [System.Management.Automation.CompletionResult]::new("--no-optional", "--no-optional", 'ParameterValue', "Don't update packages in ``optionalDependencies``"), 91 | [System.Management.Automation.CompletionResult]::new("--prod", "--prod", 'ParameterValue', "Update packages only in `"dependencies`" and `"optionalDependencies`""), 92 | [System.Management.Automation.CompletionResult]::new("--recursive", "--recursive", 'ParameterValue', "Update in every package found in subdirectories or every workspace package") 93 | ) 94 | $env:FEATURE = "deps" 95 | $deps = $(& $bin $words).Split("`n") | ForEach-Object { 96 | [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) 97 | } 98 | $options + $deps 99 | } 100 | elseif ($cmd -eq "publish") { 101 | @( 102 | [System.Management.Automation.CompletionResult]::new("--access", "--access", 'ParameterValue', "Tells the registry whether this package should be published as public or restricted"), 103 | [System.Management.Automation.CompletionResult]::new("--dry-run", "--dry-run", 'ParameterValue', "Does everything a publish would do except actually publishing to the registry"), 104 | [System.Management.Automation.CompletionResult]::new("--force", "--force", 'ParameterValue', "Packages are proceeded to be published even if their current version is already in the registry"), 105 | [System.Management.Automation.CompletionResult]::new("--ignore-scripts", "--ignore-scripts", 'ParameterValue', "Ignores any publish related lifecycle scripts (prepublishOnly, postpublish, and the like)"), 106 | [System.Management.Automation.CompletionResult]::new("--no-git-checks", "--no-git-checks", 'ParameterValue', "Don't check if current branch is your publish branch, clean, and up to date"), 107 | [System.Management.Automation.CompletionResult]::new("--otp", "--otp", 'ParameterValue', "Specify a one-time password"), 108 | [System.Management.Automation.CompletionResult]::new("--publish-branch", "--publish-branch", 'ParameterValue', "Sets branch name to publish"), 109 | [System.Management.Automation.CompletionResult]::new("--recursive", "--recursive", 'ParameterValue', "Publish all packages from the workspace"), 110 | [System.Management.Automation.CompletionResult]::new("--tag", "--tag", 'ParameterValue', "Registers the published package with the given tag") 111 | ) 112 | } 113 | elseif ($cmd -eq "run") { 114 | $env:FEATURE = "scripts" 115 | $(& $bin $words).Split("`n") | ForEach-Object { 116 | [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) 117 | } 118 | } 119 | else { 120 | $env:FEATURE = "scripts" 121 | $baseItems = @("add", "remove", "install", "update", "publish") 122 | $baseItems + $(& $bin $words).Split("`n") | ForEach-Object { 123 | [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) 124 | } 125 | } 126 | } 127 | 128 | Remove-Item Env:\FEATURE 129 | return $result 130 | } 131 | -------------------------------------------------------------------------------- /pnpm.fish: -------------------------------------------------------------------------------- 1 | set -g filter_flag 2 | 3 | set -g __fish_pnpm_cmdline 4 | set -g __fish_pnpm_remove_cmdline 5 | 6 | set -l deps_commands remove rm why update upgrade up 7 | set -l up_commands update upgrade up 8 | set -l install_commands install i 9 | 10 | complete -c pnpm -f 11 | complete -c pnpm -n "not __fish_seen_subcommand_from $deps_commands" -a "(__get_scripts)" 12 | complete -c pnpm -f -l filter -s F -r -a "$(FEATURE=filter pnpm-shell-completion)" -d 'Select specified packages' 13 | # add relative args 14 | complete -c pnpm -n "not __fish_use_subcommand" -f -a "add remove install update publish" 15 | complete -c pnpm -n __could_add_global -l global -s g 16 | 17 | complete -c pnpm -n "__fish_seen_subcommand_from add" -l save-dev -s D -d 'Save package to your `devDependencies`' 18 | complete -c pnpm -n "__fish_seen_subcommand_from add" -l save-peer -d 'Save package to your `peerDependencies` and `devDependencies`' 19 | 20 | complete -c pnpm -n "__fish_seen_subcommand_from $deps_commands" -f -a "(__get_deps)" 21 | 22 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l dev -s D -d 'Only `devDependencies` are installed regardless of the `NODE_ENV`' 23 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l fix-lockfile -d 'Fix broken lockfile entries automatically' 24 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l force -d 'Force reinstall dependencies' 25 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l ignore-scripts -d "Don't run lifecycle scripts" 26 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l lockfile-only -d 'Dependencies are not downloaded. Only `pnpm-lock.yaml` is updated' 27 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l no-optional -d '`optionalDependencies` are not installed' 28 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l offline -d 'Trigger an error if any required dependencies are not available in local store' 29 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l prefer-offline -d 'Skip staleness checks for cached data, but request missing data from the server' 30 | complete -c pnpm -n "__fish_seen_subcommand_from $install_commands" -l prod -s D -d "Packages in `devDependencies` won't be installed" 31 | 32 | complete -c pnpm -n "__fish_seen_subcommand_from $up_commands" -l save-dev -s D -d 'Update packages only in "devDependencies"' 33 | complete -c pnpm -n "__fish_seen_subcommand_from $up_commands" -l interactive -s i -d 'Show outdated dependencies and select which ones to update' 34 | complete -c pnpm -n "__fish_seen_subcommand_from $up_commands" -l latest -s L -d 'Ignore version ranges in package.json' 35 | complete -c pnpm -n "__fish_seen_subcommand_from $up_commands" -l no-optional -d "Don't update packages in `optionalDependencies`" 36 | complete -c pnpm -n "__fish_seen_subcommand_from $up_commands" -l prod -s P -d 'Update packages only in "dependencies" and "optionalDependencies"' 37 | complete -c pnpm -n "__fish_seen_subcommand_from $up_commands" -l recursive -s r -d 'Update in every package found in subdirectories or every workspace package' 38 | 39 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l access -x -a 'public restricted' -d 'Tells the registry whether this package should be published as public or restricted' 40 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l dry-run -d 'Does everything a publish would do except actually publishing to the registry' 41 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l force -d 'Packages are proceeded to be published even if their current version is already in the registry' 42 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l ignore-scripts -d 'Ignores any publish related lifecycle scripts (prepublishOnly, postpublish, and the like)' 43 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l no-git-checks -d "Don't check if current branch is your publish branch, clean, and up to date" 44 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l otp -d 'Specify a one-time password' 45 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l publish-branch -d 'Sets branch name to publish' 46 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l recursive -s r -d 'Publish all packages from the workspace' 47 | complete -c pnpm -n "__fish_seen_subcommand_from publish" -l tag -x -d 'Registers the published package with the given tag' 48 | 49 | function __get_scripts 50 | set -l cmdline (commandline -c) 51 | if set -q __fish_pnpm_cmdline; and test "$cmdline" = "$__fish_pnpm_cmdline" 52 | return 0 53 | end 54 | 55 | set -g __fish_pnpm_cmdline $cmdline 56 | 57 | set -l tokens (commandline -opc) 58 | set -e tokens[1] # assume the first token is `pnpm` 59 | argparse 'F/filter=' -- $tokens 2>/dev/null 60 | TARGET_PKG=$_flag_filter FEATURE=scripts pnpm-shell-completion 61 | end 62 | 63 | function __get_deps 64 | set -l cmdline (commandline -c) 65 | if set -q __fish_pnpm_remove_cmdline; and test "$cmdline" = "$__fish_pnpm_remove_cmdline" 66 | return 0 67 | end 68 | 69 | set -g __fish_pnpm_remove_cmdline $cmdline 70 | 71 | set -l tokens (commandline -opc) 72 | set -e tokens[1] # assume the first token is `pnpm` 73 | argparse 'F/filter=' -- $tokens 2>/dev/null 74 | TARGET_PKG=$_flag_filter FEATURE=deps pnpm-shell-completion 75 | end 76 | 77 | function __has_filter 78 | set -l tokens (commandline -opc) 79 | set -e tokens[1] # assume the first token is `pnpm` 80 | argparse 'F/filter=' -- $tokens 2>/dev/null 81 | if count $_flag_filter == 0 82 | return 1 83 | end 84 | return 0 85 | end 86 | 87 | # predicate function, 1 means false, 0 means true 88 | function __could_add_global 89 | if __has_filter == 0 90 | return 1 91 | end 92 | if __fish_seen_subcommand_from add == 0 93 | return 0 94 | end 95 | return 1 96 | end 97 | -------------------------------------------------------------------------------- /src/deps.rs: -------------------------------------------------------------------------------- 1 | use crate::monorepo::{read_package_jsons, read_root_package_json}; 2 | use itertools::Itertools; 3 | 4 | pub async fn provide_deps_candidate(target_pkg: Option<&str>) -> anyhow::Result { 5 | let manifest = if let Some(target_pkg) = target_pkg { 6 | read_package_jsons() 7 | .await? 8 | .into_iter() 9 | .find(|pkg| &pkg.name == target_pkg) 10 | } else { 11 | read_root_package_json().await.ok() 12 | }; 13 | 14 | let output = manifest.map(|manifest| { 15 | manifest 16 | .dependencies 17 | .iter() 18 | .flat_map(|deps| deps.keys()) 19 | .chain( 20 | manifest 21 | .dev_dependencies 22 | .iter() 23 | .flat_map(|dev_deps| dev_deps.keys()), 24 | ) 25 | .chain( 26 | manifest 27 | .peer_dependencies 28 | .iter() 29 | .flat_map(|peer_deps| peer_deps.keys()), 30 | ) 31 | .join("\n") 32 | }); 33 | 34 | Ok(output.unwrap_or_default()) 35 | } 36 | -------------------------------------------------------------------------------- /src/filter.rs: -------------------------------------------------------------------------------- 1 | use crate::{monorepo::read_package_jsons, types::PackageJson}; 2 | use itertools::Itertools; 3 | 4 | pub async fn provide_packages_candidate() -> anyhow::Result { 5 | let names = read_package_jsons() 6 | .await? 7 | .into_iter() 8 | .map(|PackageJson { name, .. }| name) 9 | .filter(|name| !name.trim().is_empty()) 10 | .join("\n"); 11 | Ok(names) 12 | } 13 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | mod deps; 4 | mod filter; 5 | mod monorepo; 6 | mod pnpm_cmd; 7 | mod scripts; 8 | mod types; 9 | 10 | #[tokio::main] 11 | async fn main() -> anyhow::Result<()> { 12 | let args = env::args().collect::>(); 13 | let target_pkg = env::var("TARGET_PKG") 14 | .ok() 15 | .or_else(|| monorepo::pick_target_pkg(&args).map(|s| s.to_owned())) 16 | .and_then(|value| (!value.is_empty()).then_some(value)); 17 | 18 | match env::var("FEATURE").as_deref() { 19 | Ok("filter") => println!("{}", filter::provide_packages_candidate().await?), 20 | Ok("scripts") => println!( 21 | "{}", 22 | scripts::provide_scripts_candidate(target_pkg.as_deref()).await? 23 | ), 24 | Ok("deps") => println!( 25 | "{}", 26 | deps::provide_deps_candidate(target_pkg.as_deref()).await? 27 | ), 28 | Ok("pnpm_cmd") => { 29 | if let Some(cmd) = pnpm_cmd::extract_pnpm_cmd(&args) { 30 | print!("{cmd}"); 31 | } 32 | } 33 | _ => {} 34 | } 35 | 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /src/monorepo.rs: -------------------------------------------------------------------------------- 1 | use crate::types::PackageJson; 2 | use futures::future::join_all; 3 | use globset::{GlobBuilder, GlobSet, GlobSetBuilder}; 4 | use itertools::Itertools; 5 | use serde::Deserialize; 6 | use std::{env, path::PathBuf}; 7 | use tokio::{fs, task::JoinError}; 8 | 9 | #[derive(Default, Deserialize)] 10 | struct PnpmWorkspace<'s> { 11 | #[serde(borrow)] 12 | packages: Vec<&'s str>, 13 | } 14 | 15 | pub async fn read_root_package_json() -> anyhow::Result { 16 | let json = fs::read_to_string( 17 | env::current_dir() 18 | .unwrap_or_else(|_| PathBuf::from(".")) 19 | .join("package.json"), 20 | ) 21 | .await; 22 | serde_json::from_str(json.as_deref().unwrap_or("{}")).map_err(anyhow::Error::from) 23 | } 24 | 25 | pub async fn read_package_jsons() -> anyhow::Result> { 26 | let globs = read_workspace_config().await?; 27 | let jsons = join_all( 28 | scan_directories(globs) 29 | .await? 30 | .into_iter() 31 | .map(|path| async { 32 | serde_json::from_str::( 33 | &fs::read_to_string(path).await.unwrap_or_default(), 34 | ) 35 | .unwrap_or_default() 36 | }), 37 | ) 38 | .await; 39 | Ok(jsons) 40 | } 41 | 42 | async fn scan_directories(globs: GlobSet) -> Result, JoinError> { 43 | tokio::task::spawn_blocking(move || { 44 | let base_dir = env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); 45 | ignore::WalkBuilder::new(&base_dir) 46 | // allow scanning files 47 | .hidden(false) 48 | .build() 49 | .map(|entry| entry.map(|entry| entry.into_path())) 50 | .filter(|path| { 51 | path.as_ref() 52 | .ok() 53 | .and_then(|path| path.strip_prefix(&base_dir).ok()) 54 | .map(|path| globs.is_match(path)) 55 | .unwrap_or_default() 56 | }) 57 | .map(|path| path.map(|path| path.join("package.json"))) 58 | .collect::, _>>() 59 | .unwrap_or_default() 60 | }) 61 | .await 62 | } 63 | 64 | async fn read_workspace_config() -> Result { 65 | let yaml = fs::read_to_string( 66 | env::current_dir() 67 | .map(|path| path.join("pnpm-workspace.yaml")) 68 | .unwrap_or_else(|_| PathBuf::from("./pnpm-workspace.yaml")), 69 | ) 70 | .await 71 | .unwrap_or_default(); 72 | 73 | build_glob_set( 74 | &serde_yaml::from_str::(&yaml) 75 | .unwrap_or_default() 76 | .packages, 77 | ) 78 | } 79 | 80 | fn build_glob_set(globs: &[&str]) -> Result { 81 | globs 82 | .iter() 83 | .try_fold(GlobSetBuilder::new(), |mut globset_builder, glob| { 84 | let mut glob_builder = GlobBuilder::new(&glob); 85 | glob_builder.literal_separator(true); 86 | globset_builder.add(glob_builder.build()?); 87 | Ok(globset_builder) 88 | })? 89 | .build() 90 | } 91 | 92 | pub fn pick_target_pkg(args: &[String]) -> Option<&str> { 93 | args.iter() 94 | .find_map(|arg| { 95 | arg.strip_prefix("--filter=") 96 | .or_else(|| arg.strip_prefix("-F=")) 97 | }) 98 | .or_else(|| { 99 | args.iter() 100 | .find_position(|arg| *arg == "--filter" || *arg == "-F") 101 | .and_then(|(i, ..)| args.get(i + 1)) 102 | .map(|s| s.as_str()) 103 | }) 104 | } 105 | -------------------------------------------------------------------------------- /src/pnpm_cmd.rs: -------------------------------------------------------------------------------- 1 | use itertools::Itertools; 2 | 3 | pub fn extract_pnpm_cmd(args: &[String]) -> Option<&String> { 4 | if let Some((i, _)) = args 5 | .iter() 6 | .find_position(|arg| *arg == "--filter" || *arg == "-F") 7 | { 8 | args.get(i + 2) 9 | } else if let Some((i, _)) = args 10 | .iter() 11 | .find_position(|arg| arg.starts_with("--filter=") || arg.starts_with("-F=")) 12 | { 13 | args.get(i + 1) 14 | } else { 15 | args.get(1) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/scripts.rs: -------------------------------------------------------------------------------- 1 | use crate::monorepo::{read_package_jsons, read_root_package_json}; 2 | use itertools::Itertools; 3 | use std::env; 4 | 5 | pub async fn provide_scripts_candidate(target_pkg: Option<&str>) -> anyhow::Result { 6 | let scripts = if let Some(target_pkg) = target_pkg { 7 | read_package_jsons() 8 | .await? 9 | .into_iter() 10 | .find(|pkg| &pkg.name == target_pkg) 11 | .and_then(|pkg| pkg.scripts) 12 | } else { 13 | read_root_package_json().await.unwrap_or_default().scripts 14 | }; 15 | 16 | let mut scripts = scripts 17 | .map(|scripts| scripts.keys().join("\n")) 18 | .unwrap_or_default(); 19 | // #8: escape colons for Zsh 20 | // this variable is set in "pnpm-shell-completion.plugin.zsh" 21 | if env::var("ZSH").is_ok() { 22 | scripts = scripts.replace(':', "\\:"); 23 | } 24 | Ok(scripts) 25 | } 26 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | use ahash::AHashMap; 2 | use serde::Deserialize; 3 | 4 | #[derive(Debug, Default, Deserialize)] 5 | #[serde(rename_all = "camelCase")] 6 | pub struct PackageJson { 7 | pub name: String, 8 | pub scripts: Option>, 9 | pub dependencies: Option>, 10 | pub dev_dependencies: Option>, 11 | pub peer_dependencies: Option>, 12 | } 13 | -------------------------------------------------------------------------------- /zplug.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | set -e 3 | 4 | local version=$(grep '^version =' Cargo.toml | cut -d'"' -f2) 5 | 6 | if [ $(uname) = "Darwin" ]; then 7 | if [ $(uname -m) = "arm64" ]; then 8 | target="aarch64-apple-darwin" 9 | else 10 | target="x86_64-apple-darwin" 11 | fi 12 | else 13 | target="x86_64-unknown-linux-musl" 14 | fi 15 | 16 | local url="https://github.com/g-plane/pnpm-shell-completion/releases/download/v$version/pnpm-shell-completion_$target.zip" 17 | 18 | if [ $(hash wget 2>/dev/null) ]; then 19 | wget $url > zipball.zip 20 | else 21 | curl -fsSL $url -o zipball.zip 22 | fi 23 | 24 | unzip -o zipball.zip pnpm-shell-completion 25 | rm zipball.zip 26 | --------------------------------------------------------------------------------