politty 0.4.15 → 0.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{arg-registry-CB5gGtzp.d.cts → arg-registry-Cd6xnjHa.d.ts} +116 -4
- package/dist/arg-registry-Cd6xnjHa.d.ts.map +1 -0
- package/dist/{arg-registry-Dw0f11Zc.d.ts → arg-registry-MVWOAcvw.d.cts} +116 -4
- package/dist/arg-registry-MVWOAcvw.d.cts.map +1 -0
- package/dist/augment.d.cts +1 -1
- package/dist/augment.d.cts.map +1 -1
- package/dist/augment.d.ts +1 -1
- package/dist/augment.d.ts.map +1 -1
- package/dist/completion/index.cjs +2 -1
- package/dist/completion/index.d.cts +2 -2
- package/dist/completion/index.d.ts +2 -2
- package/dist/completion/index.js +2 -2
- package/dist/{completion-Ca5ESJlG.js → completion-B04iiki9.js} +512 -18
- package/dist/completion-B04iiki9.js.map +1 -0
- package/dist/{completion-B5fgnUGm.cjs → completion-BlZxMSeU.cjs} +516 -16
- package/dist/completion-BlZxMSeU.cjs.map +1 -0
- package/dist/docs/index.cjs +82 -22
- package/dist/docs/index.cjs.map +1 -1
- package/dist/docs/index.d.cts +1 -1
- package/dist/docs/index.d.cts.map +1 -1
- package/dist/docs/index.d.ts +1 -1
- package/dist/docs/index.d.ts.map +1 -1
- package/dist/docs/index.js +92 -31
- package/dist/docs/index.js.map +1 -1
- package/dist/{index-Dg9Fpz0R.d.ts → index-CPebddth.d.cts} +56 -4
- package/dist/index-CPebddth.d.cts.map +1 -0
- package/dist/{index-C1gGgUeB.d.cts → index-DR9HLxIP.d.ts} +56 -4
- package/dist/index-DR9HLxIP.d.ts.map +1 -0
- package/dist/index.cjs +5 -3
- package/dist/index.d.cts +36 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +36 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/log-collector-Cd2_mv87.cjs.map +1 -1
- package/dist/log-collector-Cu6MCtAx.js.map +1 -1
- package/dist/prompt/clack/index.cjs.map +1 -1
- package/dist/prompt/clack/index.d.cts +1 -1
- package/dist/prompt/clack/index.d.cts.map +1 -1
- package/dist/prompt/clack/index.d.ts +1 -1
- package/dist/prompt/clack/index.d.ts.map +1 -1
- package/dist/prompt/clack/index.js.map +1 -1
- package/dist/prompt/index.d.cts +1 -1
- package/dist/prompt/index.d.cts.map +1 -1
- package/dist/prompt/index.d.ts +1 -1
- package/dist/prompt/index.d.ts.map +1 -1
- package/dist/prompt/inquirer/index.cjs.map +1 -1
- package/dist/prompt/inquirer/index.d.cts +1 -1
- package/dist/prompt/inquirer/index.d.cts.map +1 -1
- package/dist/prompt/inquirer/index.d.ts +1 -1
- package/dist/prompt/inquirer/index.d.ts.map +1 -1
- package/dist/prompt/inquirer/index.js.map +1 -1
- package/dist/prompt-BKHqGrFw.js.map +1 -1
- package/dist/prompt-aXfSf27y.cjs.map +1 -1
- package/dist/{runner-DKAQBNNh.js → runner-BHeCMEa5.js} +309 -45
- package/dist/runner-BHeCMEa5.js.map +1 -0
- package/dist/{runner-CriXJlm4.cjs → runner-BcyR6Z8r.cjs} +320 -44
- package/dist/runner-BcyR6Z8r.cjs.map +1 -0
- package/dist/{subcommand-router-CqZX3orq.cjs → subcommand-router-DQy0KZU-.cjs} +41 -3
- package/dist/subcommand-router-DQy0KZU-.cjs.map +1 -0
- package/dist/{subcommand-router-ENeCymvX.js → subcommand-router-XZBWe8HN.js} +41 -3
- package/dist/subcommand-router-XZBWe8HN.js.map +1 -0
- package/package.json +16 -16
- package/dist/arg-registry-CB5gGtzp.d.cts.map +0 -1
- package/dist/arg-registry-Dw0f11Zc.d.ts.map +0 -1
- package/dist/completion-B5fgnUGm.cjs.map +0 -1
- package/dist/completion-Ca5ESJlG.js.map +0 -1
- package/dist/index-C1gGgUeB.d.cts.map +0 -1
- package/dist/index-Dg9Fpz0R.d.ts.map +0 -1
- package/dist/runner-CriXJlm4.cjs.map +0 -1
- package/dist/runner-DKAQBNNh.js.map +0 -1
- package/dist/subcommand-router-CqZX3orq.cjs.map +0 -1
- package/dist/subcommand-router-ENeCymvX.js.map +0 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { c as resolveSubCommandMeta, h as arg, i as resolveSubCommandAlias, l as extractFields, p as toCamelCase } from "./subcommand-router-
|
|
1
|
+
import { c as resolveSubCommandMeta, h as arg, i as resolveSubCommandAlias, l as extractFields, p as toCamelCase } from "./subcommand-router-XZBWe8HN.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { execSync, spawn } from "node:child_process";
|
|
4
6
|
|
|
5
7
|
//#region src/core/command.ts
|
|
6
8
|
function defineCommand(config) {
|
|
@@ -138,6 +140,8 @@ function fieldToOption(field) {
|
|
|
138
140
|
name: field.name,
|
|
139
141
|
cliName: field.cliName,
|
|
140
142
|
alias: field.alias,
|
|
143
|
+
negation: field.negationDisplay,
|
|
144
|
+
negationDescription: field.negationDescription,
|
|
141
145
|
description: field.description,
|
|
142
146
|
takesValue: field.type !== "boolean",
|
|
143
147
|
valueType: field.type,
|
|
@@ -289,6 +293,79 @@ function extractCompletionData(command, programName, globalArgsSchema) {
|
|
|
289
293
|
};
|
|
290
294
|
}
|
|
291
295
|
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/completion/header.ts
|
|
298
|
+
/**
|
|
299
|
+
* Static-script header utilities.
|
|
300
|
+
*
|
|
301
|
+
* Every completion script generated by politty starts with a small
|
|
302
|
+
* machine-readable header. The rc loader and the runMain background
|
|
303
|
+
* refresh path use the `# politty-bin-sig:` line to detect when the
|
|
304
|
+
* cached script is stale relative to the binary on disk.
|
|
305
|
+
*/
|
|
306
|
+
/** Schema version of the header itself. Bump when the header layout changes. */
|
|
307
|
+
const COMPLETION_VERSION = 1;
|
|
308
|
+
/**
|
|
309
|
+
* Read the binary's mtime in whole seconds (matches POSIX `stat -c %Y` /
|
|
310
|
+
* BSD `stat -f %m`). Returns `"0"` on failure so the header is always
|
|
311
|
+
* well-formed.
|
|
312
|
+
*/
|
|
313
|
+
function computeBinSig(binPath) {
|
|
314
|
+
try {
|
|
315
|
+
return Math.floor(statSync(binPath).mtimeMs / 1e3).toString();
|
|
316
|
+
} catch {
|
|
317
|
+
return "0";
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Walk `$PATH` looking for an executable named `programName`. Returns
|
|
322
|
+
* the first match's full path, or `null` when not found. We mirror the
|
|
323
|
+
* shell's `command -v <prog>` here so the sig embedded in the header
|
|
324
|
+
* (computed by Node) lines up with what the rc loader stat-checks at
|
|
325
|
+
* runtime — including pnpm/npm bin shims that wrap the real entrypoint.
|
|
326
|
+
* Without this alignment, shimmed installs would never match the
|
|
327
|
+
* embedded sig and the cache would regenerate on every shell startup.
|
|
328
|
+
*/
|
|
329
|
+
function findOnPath(programName) {
|
|
330
|
+
if (!programName || /[/\\\0]/.test(programName)) return null;
|
|
331
|
+
const path = process.env.PATH ?? "";
|
|
332
|
+
for (const dir of path.split(":")) {
|
|
333
|
+
if (!dir) continue;
|
|
334
|
+
const candidate = join(dir, programName);
|
|
335
|
+
try {
|
|
336
|
+
if (statSync(candidate).isFile()) return candidate;
|
|
337
|
+
} catch {}
|
|
338
|
+
}
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Resolve the binary path used for sig computation and stat checks.
|
|
343
|
+
*
|
|
344
|
+
* Order: explicit override → `$PATH` lookup of `programName` → `process.argv[1]`.
|
|
345
|
+
* The `$PATH` lookup keeps Node-side and shell-side stats pointed at the
|
|
346
|
+
* same shim file when the CLI is invoked through a package-manager bin shim.
|
|
347
|
+
*/
|
|
348
|
+
function resolveBinPath(programName, override) {
|
|
349
|
+
if (override) return override;
|
|
350
|
+
return findOnPath(programName) ?? process.argv[1] ?? "";
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Build the header lines (no trailing blank line). Returned without a
|
|
354
|
+
* leading `#!` so each generator can prepend its own shebang/compdef
|
|
355
|
+
* marker.
|
|
356
|
+
*/
|
|
357
|
+
function buildHeaderLines(opts) {
|
|
358
|
+
const sig = computeBinSig(resolveBinPath(opts.programName, opts.binPath));
|
|
359
|
+
const lines = [
|
|
360
|
+
`# politty-completion-version: ${1}`,
|
|
361
|
+
`# politty-bin-sig: ${sig}`,
|
|
362
|
+
`# program: ${opts.programName}`
|
|
363
|
+
];
|
|
364
|
+
if (opts.programVersion) lines.push(`# program-version: ${opts.programVersion}`);
|
|
365
|
+
lines.push(`# shell: ${opts.shell}`);
|
|
366
|
+
return lines;
|
|
367
|
+
}
|
|
368
|
+
|
|
292
369
|
//#endregion
|
|
293
370
|
//#region src/completion/bash.ts
|
|
294
371
|
/** Escape a string for use inside bash double-quotes */
|
|
@@ -416,7 +493,9 @@ function availableOptionLines$2(options, fn) {
|
|
|
416
493
|
else {
|
|
417
494
|
const patterns = [`"--${opt.cliName}"`];
|
|
418
495
|
if (opt.alias) for (const a of opt.alias) patterns.push(a.length === 1 ? `"-${a}"` : `"--${a}"`);
|
|
496
|
+
if (opt.negation) patterns.push(`"--${opt.negation}"`);
|
|
419
497
|
lines.push(` __${fn}_not_used ${patterns.join(" ")} && _avail+=(--${opt.cliName})`);
|
|
498
|
+
if (opt.negation) lines.push(` __${fn}_not_used ${patterns.join(" ")} && _avail+=(--${opt.negation})`);
|
|
420
499
|
}
|
|
421
500
|
lines.push(` __${fn}_not_used "--help" && _avail+=(--help)`);
|
|
422
501
|
return lines;
|
|
@@ -465,7 +544,12 @@ function generateBashCompletion(command, options) {
|
|
|
465
544
|
const root = data.command;
|
|
466
545
|
const visibleSubs = getVisibleSubs(root.subcommands);
|
|
467
546
|
const lines = [];
|
|
468
|
-
lines.push(
|
|
547
|
+
lines.push(...buildHeaderLines({
|
|
548
|
+
programName,
|
|
549
|
+
shell: "bash",
|
|
550
|
+
binPath: options.binPath,
|
|
551
|
+
programVersion: options.programVersion
|
|
552
|
+
}));
|
|
469
553
|
lines.push(`# Generated by politty`);
|
|
470
554
|
lines.push(``);
|
|
471
555
|
lines.push(`__${fn}_not_used() {`);
|
|
@@ -604,13 +688,21 @@ source ~/.bashrc`
|
|
|
604
688
|
* Completion directive flags (bitwise)
|
|
605
689
|
*/
|
|
606
690
|
const CompletionDirective = {
|
|
691
|
+
/** Default completion behavior */
|
|
607
692
|
Default: 0,
|
|
693
|
+
/** Don't add space after completion */
|
|
608
694
|
NoSpace: 1,
|
|
695
|
+
/** Don't offer file completion (even if no other completions) */
|
|
609
696
|
NoFileCompletion: 2,
|
|
697
|
+
/** Filter completions using current word as prefix */
|
|
610
698
|
FilterPrefix: 4,
|
|
699
|
+
/** Keep the order of completions */
|
|
611
700
|
KeepOrder: 8,
|
|
701
|
+
/** Trigger file completion */
|
|
612
702
|
FileCompletion: 16,
|
|
703
|
+
/** Trigger directory completion */
|
|
613
704
|
DirectoryCompletion: 32,
|
|
705
|
+
/** Error occurred during completion */
|
|
614
706
|
Error: 64
|
|
615
707
|
};
|
|
616
708
|
/**
|
|
@@ -736,13 +828,21 @@ function generateOptionNameCandidates(context) {
|
|
|
736
828
|
if (opt.valueType === "array") return true;
|
|
737
829
|
if (context.usedOptions.has(opt.cliName)) return false;
|
|
738
830
|
if (opt.alias && opt.alias.some((a) => context.usedOptions.has(a))) return false;
|
|
831
|
+
if (opt.negation && context.usedOptions.has(opt.negation)) return false;
|
|
739
832
|
return true;
|
|
740
833
|
});
|
|
741
|
-
for (const opt of availableOptions)
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
834
|
+
for (const opt of availableOptions) {
|
|
835
|
+
candidates.push({
|
|
836
|
+
value: `--${opt.cliName}`,
|
|
837
|
+
description: opt.description,
|
|
838
|
+
type: "option"
|
|
839
|
+
});
|
|
840
|
+
if (opt.negation) candidates.push({
|
|
841
|
+
value: `--${opt.negation}`,
|
|
842
|
+
description: opt.negationDescription ?? opt.description,
|
|
843
|
+
type: "option"
|
|
844
|
+
});
|
|
845
|
+
}
|
|
746
846
|
if (!context.usedOptions.has("help")) candidates.push({
|
|
747
847
|
value: "--help",
|
|
748
848
|
description: "Show help information",
|
|
@@ -808,6 +908,8 @@ function extractOptions(command) {
|
|
|
808
908
|
name: field.name,
|
|
809
909
|
cliName: field.cliName,
|
|
810
910
|
alias: field.alias,
|
|
911
|
+
negation: field.negationDisplay,
|
|
912
|
+
negationDescription: field.negationDescription,
|
|
811
913
|
description: field.description,
|
|
812
914
|
takesValue: field.type !== "boolean",
|
|
813
915
|
valueType: field.type,
|
|
@@ -889,6 +991,10 @@ function findOption(options, nameOrAlias) {
|
|
|
889
991
|
if (nameOrAlias.length > 1) {
|
|
890
992
|
if (opt.cliName.includes("-") && toCamelCase(opt.cliName) === nameOrAlias) return true;
|
|
891
993
|
if (opt.alias?.some((a) => a.includes("-") && toCamelCase(a) === nameOrAlias)) return true;
|
|
994
|
+
if (opt.negation) {
|
|
995
|
+
if (opt.negation === nameOrAlias) return true;
|
|
996
|
+
if (opt.negation.includes("-") && toCamelCase(opt.negation) === nameOrAlias) return true;
|
|
997
|
+
}
|
|
892
998
|
}
|
|
893
999
|
return false;
|
|
894
1000
|
});
|
|
@@ -921,6 +1027,7 @@ function parseCompletionContext(argv, rootCommand) {
|
|
|
921
1027
|
if (opt) {
|
|
922
1028
|
usedOptions.add(opt.cliName);
|
|
923
1029
|
if (opt.alias) for (const a of opt.alias) usedOptions.add(a);
|
|
1030
|
+
if (opt.negation) usedOptions.add(opt.negation);
|
|
924
1031
|
if (opt.takesValue && !hasInlineValue(word)) i++;
|
|
925
1032
|
}
|
|
926
1033
|
i++;
|
|
@@ -1239,11 +1346,14 @@ function availableOptionLines$1(options, fn) {
|
|
|
1239
1346
|
const lines = [];
|
|
1240
1347
|
for (const opt of options) {
|
|
1241
1348
|
const desc = escapeDesc$1(opt.description ?? "");
|
|
1349
|
+
const negDesc = opt.negationDescription ? escapeDesc$1(opt.negationDescription) : desc;
|
|
1242
1350
|
if (opt.valueType === "array") lines.push(` echo "--${opt.cliName}\t${desc}"`);
|
|
1243
1351
|
else {
|
|
1244
1352
|
const checks = [`"--${opt.cliName}"`];
|
|
1245
1353
|
if (opt.alias) for (const a of opt.alias) checks.push(a.length === 1 ? `"-${a}"` : `"--${a}"`);
|
|
1354
|
+
if (opt.negation) checks.push(`"--${opt.negation}"`);
|
|
1246
1355
|
lines.push(` __${fn}_not_used ${checks.join(" ")}; and echo "--${opt.cliName}\t${desc}"`);
|
|
1356
|
+
if (opt.negation) lines.push(` __${fn}_not_used ${checks.join(" ")}; and echo "--${opt.negation}\t${negDesc}"`);
|
|
1247
1357
|
}
|
|
1248
1358
|
}
|
|
1249
1359
|
lines.push(` __${fn}_not_used "--help"; and echo "--help\tShow help"`);
|
|
@@ -1313,9 +1423,32 @@ function generateFishCompletion(command, options) {
|
|
|
1313
1423
|
const root = data.command;
|
|
1314
1424
|
const visibleSubs = getVisibleSubs(root.subcommands);
|
|
1315
1425
|
const lines = [];
|
|
1316
|
-
lines.push(
|
|
1426
|
+
lines.push(...buildHeaderLines({
|
|
1427
|
+
programName,
|
|
1428
|
+
shell: "fish",
|
|
1429
|
+
binPath: options.binPath,
|
|
1430
|
+
programVersion: options.programVersion
|
|
1431
|
+
}));
|
|
1317
1432
|
lines.push(`# Generated by politty`);
|
|
1318
1433
|
lines.push(``);
|
|
1434
|
+
const sig = computeBinSig(resolveBinPath(programName, options.binPath));
|
|
1435
|
+
const refreshFn = `__${fn}_refresh_completion`;
|
|
1436
|
+
lines.push(`function ${refreshFn} --no-scope-shadowing`);
|
|
1437
|
+
lines.push(` set -l _bin (command -v ${programName})`);
|
|
1438
|
+
lines.push(` test -z "$_bin"; and return 1`);
|
|
1439
|
+
lines.push(` set -l _sig (stat -L -c '%Y' "$_bin" 2>/dev/null; or stat -L -f '%m' "$_bin" 2>/dev/null)`);
|
|
1440
|
+
lines.push(` test "$_sig" = "${sig}"; and return 1`);
|
|
1441
|
+
lines.push(` set -l _target "$__fish_config_dir/completions/${programName}.fish"`);
|
|
1442
|
+
lines.push(` "$_bin" __refresh-completion fish 2>/dev/null`);
|
|
1443
|
+
lines.push(` and source "$_target" 2>/dev/null`);
|
|
1444
|
+
lines.push(` and return 0`);
|
|
1445
|
+
lines.push(` return 1`);
|
|
1446
|
+
lines.push(`end`);
|
|
1447
|
+
lines.push(`${refreshFn}`);
|
|
1448
|
+
lines.push(`set -l _politty_refreshed $status`);
|
|
1449
|
+
lines.push(`functions -e ${refreshFn}`);
|
|
1450
|
+
lines.push(`test $_politty_refreshed -eq 0; and return`);
|
|
1451
|
+
lines.push(``);
|
|
1319
1452
|
lines.push(`function __${fn}_not_used --no-scope-shadowing`);
|
|
1320
1453
|
lines.push(` for _chk in $argv`);
|
|
1321
1454
|
lines.push(` if contains -- "$_chk" $_used_opts`);
|
|
@@ -1441,6 +1574,241 @@ source ~/.config/fish/completions/${programName}.fish`
|
|
|
1441
1574
|
};
|
|
1442
1575
|
}
|
|
1443
1576
|
|
|
1577
|
+
//#endregion
|
|
1578
|
+
//#region src/completion/loader.ts
|
|
1579
|
+
/**
|
|
1580
|
+
* Rc-loader generators (bash / zsh).
|
|
1581
|
+
*
|
|
1582
|
+
* These produce the small snippet a user adds once to `~/.bashrc` or
|
|
1583
|
+
* `~/.zshrc`. The snippet:
|
|
1584
|
+
*
|
|
1585
|
+
* 1. Looks up the binary on $PATH.
|
|
1586
|
+
* 2. Reads its mtime.
|
|
1587
|
+
* 3. If the on-disk completion cache is missing or its
|
|
1588
|
+
* `# politty-bin-sig:` header differs, regenerates the cache by
|
|
1589
|
+
* spawning the binary once.
|
|
1590
|
+
* 4. Sources the cache.
|
|
1591
|
+
*
|
|
1592
|
+
* All failure modes are silent no-ops so a broken / missing CLI never
|
|
1593
|
+
* blocks shell startup.
|
|
1594
|
+
*/
|
|
1595
|
+
/**
|
|
1596
|
+
* Single-quote escape: `'` -> `'\''`. Inside single quotes the shell
|
|
1597
|
+
* performs no expansion at all, so `$`, backticks, and `$(...)` are
|
|
1598
|
+
* inert. Used for hardcoded paths because callers may sources them
|
|
1599
|
+
* from env / config — we must not let metachars in the path execute as
|
|
1600
|
+
* commands when the rc snippet is sourced.
|
|
1601
|
+
*/
|
|
1602
|
+
function shSingleQuote(s) {
|
|
1603
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
1604
|
+
}
|
|
1605
|
+
function bashCachePathExpr(programName, cacheDir, shell) {
|
|
1606
|
+
if (cacheDir) return shSingleQuote(`${cacheDir}/completion.${shell}`);
|
|
1607
|
+
return `"\${XDG_CACHE_HOME:-$HOME/.cache}/${programName}/completion.${shell}"`;
|
|
1608
|
+
}
|
|
1609
|
+
function generateBashLoader(opts) {
|
|
1610
|
+
const fn = sanitize(opts.programName);
|
|
1611
|
+
const cache = bashCachePathExpr(opts.programName, opts.cacheDir, "bash");
|
|
1612
|
+
return `__${fn}_load_completion() {
|
|
1613
|
+
local _bin _cache _sig _hdr
|
|
1614
|
+
_bin=$(type -P ${opts.programName} 2>/dev/null)
|
|
1615
|
+
[[ -n "$_bin" ]] || return 0
|
|
1616
|
+
_cache=${cache}
|
|
1617
|
+
_sig=$(stat -L -c '%Y' "$_bin" 2>/dev/null || stat -L -f '%m' "$_bin" 2>/dev/null) || return 0
|
|
1618
|
+
_hdr="# politty-bin-sig: $_sig"
|
|
1619
|
+
if [[ ! -f "$_cache" ]] || ! head -5 "$_cache" 2>/dev/null | grep -qF "$_hdr"; then
|
|
1620
|
+
# Use the hidden __refresh-completion subcommand instead of
|
|
1621
|
+
# \`$_bin completion bash\`: the foreground completion command
|
|
1622
|
+
# is subject to user setup/cleanup/prompt and required
|
|
1623
|
+
# globalArgs validation, which can silently fail or block when
|
|
1624
|
+
# invoked from rc; runMain bypasses those for __-prefixed
|
|
1625
|
+
# internal subcommands.
|
|
1626
|
+
"$_bin" __refresh-completion bash 2>/dev/null
|
|
1627
|
+
fi
|
|
1628
|
+
# If regen failed but a stale cache survived from a previous run,
|
|
1629
|
+
# source it anyway — a stale completion is preferable to no
|
|
1630
|
+
# completion at all.
|
|
1631
|
+
[[ -f "$_cache" ]] || return 0
|
|
1632
|
+
# shellcheck disable=SC1090
|
|
1633
|
+
source "$_cache"
|
|
1634
|
+
}
|
|
1635
|
+
__${fn}_load_completion
|
|
1636
|
+
unset -f __${fn}_load_completion
|
|
1637
|
+
`;
|
|
1638
|
+
}
|
|
1639
|
+
function generateZshLoader(opts) {
|
|
1640
|
+
const fn = sanitize(opts.programName);
|
|
1641
|
+
const cache = bashCachePathExpr(opts.programName, opts.cacheDir, "zsh");
|
|
1642
|
+
return `__${fn}_load_completion() {
|
|
1643
|
+
emulate -L zsh
|
|
1644
|
+
setopt local_options no_aliases
|
|
1645
|
+
local _bin _cache _sig _hdr
|
|
1646
|
+
_bin=$(whence -p ${opts.programName} 2>/dev/null)
|
|
1647
|
+
[[ -n "$_bin" ]] || return 0
|
|
1648
|
+
_cache=${cache}
|
|
1649
|
+
_sig=$(stat -L -c '%Y' "$_bin" 2>/dev/null || stat -L -f '%m' "$_bin" 2>/dev/null) || return 0
|
|
1650
|
+
_hdr="# politty-bin-sig: $_sig"
|
|
1651
|
+
if [[ ! -f "$_cache" ]] || ! head -5 "$_cache" 2>/dev/null | grep -qF "$_hdr"; then
|
|
1652
|
+
# See bash loader for why we use __refresh-completion instead
|
|
1653
|
+
# of \`$_bin completion zsh\`.
|
|
1654
|
+
"$_bin" __refresh-completion zsh 2>/dev/null
|
|
1655
|
+
fi
|
|
1656
|
+
# See bash loader: keep stale completion over no completion.
|
|
1657
|
+
[[ -f "$_cache" ]] || return 0
|
|
1658
|
+
source "$_cache"
|
|
1659
|
+
}
|
|
1660
|
+
__${fn}_load_completion
|
|
1661
|
+
unfunction __${fn}_load_completion
|
|
1662
|
+
`;
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Build the rc-loader snippet for bash or zsh. Fish doesn't have an
|
|
1666
|
+
* rc-loader; instead, `<program> completion fish --install` writes a
|
|
1667
|
+
* self-rewriting autoload file.
|
|
1668
|
+
*/
|
|
1669
|
+
function generateLoader(opts) {
|
|
1670
|
+
switch (opts.shell) {
|
|
1671
|
+
case "bash": return generateBashLoader(opts);
|
|
1672
|
+
case "zsh": return generateZshLoader(opts);
|
|
1673
|
+
case "fish": throw new Error("fish does not use an rc loader. Run `<program> completion fish --install` to write the self-refreshing autoload file instead.");
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
/**
|
|
1677
|
+
* Default cache file path (used by `completion <bash|zsh> --install`
|
|
1678
|
+
* and the `__refresh-completion` subcommand). For fish, the install
|
|
1679
|
+
* path is `$__fish_config_dir/completions/<program>.fish` and is
|
|
1680
|
+
* computed inside `installPath()` instead.
|
|
1681
|
+
*/
|
|
1682
|
+
function defaultCacheDir(programName) {
|
|
1683
|
+
return `${process.env.XDG_CACHE_HOME ?? `${process.env.HOME ?? ""}/.cache`}/${programName}`;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
//#endregion
|
|
1687
|
+
//#region src/completion/install.ts
|
|
1688
|
+
/**
|
|
1689
|
+
* On-disk install + refresh helpers.
|
|
1690
|
+
*
|
|
1691
|
+
* `install` writes the generated script to its canonical cache /
|
|
1692
|
+
* autoload path. `refresh` is the body of the `__refresh-completion`
|
|
1693
|
+
* hidden subcommand and the runMain background hook — it regenerates
|
|
1694
|
+
* the cache only when the binary's mtime no longer matches the
|
|
1695
|
+
* embedded `# politty-bin-sig:` header.
|
|
1696
|
+
*
|
|
1697
|
+
* All file I/O is best-effort: failures fall through silently. A stale
|
|
1698
|
+
* (or missing) cache is preferable to crashing the user's shell.
|
|
1699
|
+
*/
|
|
1700
|
+
/**
|
|
1701
|
+
* Resolve where a script for the given shell should live on disk.
|
|
1702
|
+
*
|
|
1703
|
+
* - bash/zsh: `<cacheDir>/completion.<shell>` — sourced by the rc loader.
|
|
1704
|
+
* - fish: `$__fish_config_dir/completions/<program>.fish` — autoloaded
|
|
1705
|
+
* by fish on TAB. We approximate `$__fish_config_dir` from
|
|
1706
|
+
* `$XDG_CONFIG_HOME` / `$HOME`.
|
|
1707
|
+
*/
|
|
1708
|
+
function installPath(programName, shell, cacheDir) {
|
|
1709
|
+
if (shell === "fish") return join(process.env.XDG_CONFIG_HOME ?? `${process.env.HOME ?? ""}/.config`, "fish", "completions", `${programName}.fish`);
|
|
1710
|
+
return join(cacheDir ?? defaultCacheDir(programName), `completion.${shell}`);
|
|
1711
|
+
}
|
|
1712
|
+
/** Atomic write: tmp file in the same dir, then rename. */
|
|
1713
|
+
function writeAtomic(path, content) {
|
|
1714
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
1715
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
1716
|
+
writeFileSync(tmp, content);
|
|
1717
|
+
renameSync(tmp, path);
|
|
1718
|
+
}
|
|
1719
|
+
function generateScript(ctx, shell) {
|
|
1720
|
+
return generateCompletion(ctx.rootCommand, {
|
|
1721
|
+
shell,
|
|
1722
|
+
programName: ctx.programName,
|
|
1723
|
+
includeDescriptions: true,
|
|
1724
|
+
...ctx.programVersion !== void 0 && { programVersion: ctx.programVersion },
|
|
1725
|
+
...ctx.binPath !== void 0 && { binPath: ctx.binPath },
|
|
1726
|
+
...ctx.cacheDir !== void 0 && { cacheDir: ctx.cacheDir },
|
|
1727
|
+
...ctx.globalArgsSchema !== void 0 && { globalArgsSchema: ctx.globalArgsSchema }
|
|
1728
|
+
}).script;
|
|
1729
|
+
}
|
|
1730
|
+
/** Write the script for `shell` to its install path. Returns the path. */
|
|
1731
|
+
function install(ctx, shell) {
|
|
1732
|
+
const target = installPath(ctx.programName, shell, ctx.cacheDir);
|
|
1733
|
+
writeAtomic(target, generateScript(ctx, shell));
|
|
1734
|
+
return target;
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Read the first ~5 lines of an existing cache file and return its
|
|
1738
|
+
* embedded bin-sig. Returns `null` when the file is missing, unreadable,
|
|
1739
|
+
* or doesn't have a sig header.
|
|
1740
|
+
*/
|
|
1741
|
+
function readCachedSig(path) {
|
|
1742
|
+
try {
|
|
1743
|
+
if (!existsSync(path)) return null;
|
|
1744
|
+
const m = readFileSync(path, "utf8").split("\n", 6).join("\n").match(/^# politty-bin-sig: (\S+)/m);
|
|
1745
|
+
return m ? m[1] : null;
|
|
1746
|
+
} catch {
|
|
1747
|
+
return null;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* Rewrite the cache only when stale. Used by:
|
|
1752
|
+
* - `<program> __refresh-completion <shell>` (the hidden subcommand
|
|
1753
|
+
* spawned both by the rc loader and by the runMain background hook)
|
|
1754
|
+
*
|
|
1755
|
+
* Caller is responsible for gating: the runMain hook (`maybeSpawnRefresh`)
|
|
1756
|
+
* checks `hasManagedCache` before spawning so we don't silently create
|
|
1757
|
+
* a fish autoload the user never opted into. The rc loader / fish
|
|
1758
|
+
* autoload only run after the user has installed completion in the
|
|
1759
|
+
* first place, so they're allowed to refresh unconditionally.
|
|
1760
|
+
*
|
|
1761
|
+
* Must never throw — a stale completion is fine, a crash isn't.
|
|
1762
|
+
*/
|
|
1763
|
+
function refreshIfStale(ctx, shell) {
|
|
1764
|
+
try {
|
|
1765
|
+
const target = installPath(ctx.programName, shell, ctx.cacheDir);
|
|
1766
|
+
const binPath = resolveBinPath(ctx.programName, ctx.binPath);
|
|
1767
|
+
if (!binPath) return;
|
|
1768
|
+
let currentSig;
|
|
1769
|
+
try {
|
|
1770
|
+
currentSig = Math.floor(statSync(binPath).mtimeMs / 1e3).toString();
|
|
1771
|
+
} catch {
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
if (readCachedSig(target) === currentSig) return;
|
|
1775
|
+
writeAtomic(target, generateScript(ctx, shell));
|
|
1776
|
+
} catch {}
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Returns true when a politty-managed cache file already exists on disk
|
|
1780
|
+
* for the given shell — i.e. the user has installed completion via
|
|
1781
|
+
* `<program> completion <shell> --install` or the rc loader has already
|
|
1782
|
+
* sourced one. Used by the runMain background hook to avoid spawning
|
|
1783
|
+
* the refresher (and thereby silently creating files) on plain CLI runs
|
|
1784
|
+
* the user never opted into.
|
|
1785
|
+
*/
|
|
1786
|
+
function hasManagedCache(ctx, shell) {
|
|
1787
|
+
return readCachedSig(installPath(ctx.programName, shell, ctx.cacheDir)) !== null;
|
|
1788
|
+
}
|
|
1789
|
+
/**
|
|
1790
|
+
* Spawn a detached child process that runs `<program> __refresh-completion <shell>`.
|
|
1791
|
+
* The child is fully decoupled (`stdio: "ignore"` + `unref()`), so it
|
|
1792
|
+
* outlives the parent without holding any handles.
|
|
1793
|
+
*
|
|
1794
|
+
* Caller is expected to gate this on the right conditions (interactive
|
|
1795
|
+
* shell, not running inside `__complete` itself, etc.).
|
|
1796
|
+
*
|
|
1797
|
+
* Returns `void` and never throws — even spawn failures are absorbed.
|
|
1798
|
+
*/
|
|
1799
|
+
function spawnBackgroundRefresh(programArgv0, shell) {
|
|
1800
|
+
try {
|
|
1801
|
+
spawn(process.execPath, [
|
|
1802
|
+
programArgv0,
|
|
1803
|
+
"__refresh-completion",
|
|
1804
|
+
shell
|
|
1805
|
+
], {
|
|
1806
|
+
detached: true,
|
|
1807
|
+
stdio: "ignore"
|
|
1808
|
+
}).unref();
|
|
1809
|
+
} catch {}
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1444
1812
|
//#endregion
|
|
1445
1813
|
//#region src/completion/zsh.ts
|
|
1446
1814
|
function escapeDesc(s) {
|
|
@@ -1509,11 +1877,14 @@ function availableOptionLines(options, fn) {
|
|
|
1509
1877
|
const lines = [];
|
|
1510
1878
|
for (const opt of options) {
|
|
1511
1879
|
const desc = opt.description ? `:${escapeDesc(opt.description)}` : "";
|
|
1880
|
+
const negDesc = opt.negationDescription ? `:${escapeDesc(opt.negationDescription)}` : desc;
|
|
1512
1881
|
if (opt.valueType === "array") lines.push(` _opts+=("--${opt.cliName}${desc}")`);
|
|
1513
1882
|
else {
|
|
1514
1883
|
const patterns = [`"--${opt.cliName}"`];
|
|
1515
1884
|
if (opt.alias) for (const a of opt.alias) patterns.push(a.length === 1 ? `"-${a}"` : `"--${a}"`);
|
|
1885
|
+
if (opt.negation) patterns.push(`"--${opt.negation}"`);
|
|
1516
1886
|
lines.push(` __${fn}_not_used ${patterns.join(" ")} && _opts+=("--${opt.cliName}${desc}")`);
|
|
1887
|
+
if (opt.negation) lines.push(` __${fn}_not_used ${patterns.join(" ")} && _opts+=("--${opt.negation}${negDesc}")`);
|
|
1517
1888
|
}
|
|
1518
1889
|
}
|
|
1519
1890
|
lines.push(` __${fn}_not_used "--help" && _opts+=("--help:Show help")`);
|
|
@@ -1567,7 +1938,12 @@ function generateZshCompletion(command, options) {
|
|
|
1567
1938
|
const lines = [];
|
|
1568
1939
|
lines.push(`#compdef ${programName}`);
|
|
1569
1940
|
lines.push(``);
|
|
1570
|
-
lines.push(
|
|
1941
|
+
lines.push(...buildHeaderLines({
|
|
1942
|
+
programName,
|
|
1943
|
+
shell: "zsh",
|
|
1944
|
+
binPath: options.binPath,
|
|
1945
|
+
programVersion: options.programVersion
|
|
1946
|
+
}));
|
|
1571
1947
|
lines.push(`# Generated by politty`);
|
|
1572
1948
|
lines.push(``);
|
|
1573
1949
|
lines.push(`__${fn}_not_used() {`);
|
|
@@ -1763,8 +2139,19 @@ const completionArgsSchema = z.object({
|
|
|
1763
2139
|
instructions: arg(z.boolean().default(false), {
|
|
1764
2140
|
alias: "i",
|
|
1765
2141
|
description: "Show installation instructions"
|
|
1766
|
-
})
|
|
2142
|
+
}),
|
|
2143
|
+
loader: arg(z.boolean().default(false), { description: "Print just the rc loader snippet (bash/zsh). Add it to ~/.bashrc or ~/.zshrc; it auto-regenerates the cache when the binary changes." }),
|
|
2144
|
+
install: arg(z.boolean().default(false), { description: "Write the completion script to its on-disk cache (bash/zsh) or autoload location (fish) instead of printing it." })
|
|
1767
2145
|
});
|
|
2146
|
+
const refreshArgsSchema = z.object({ shell: arg(z.enum([
|
|
2147
|
+
"bash",
|
|
2148
|
+
"zsh",
|
|
2149
|
+
"fish"
|
|
2150
|
+
]), {
|
|
2151
|
+
positional: true,
|
|
2152
|
+
description: "Shell to refresh",
|
|
2153
|
+
placeholder: "SHELL"
|
|
2154
|
+
}) });
|
|
1768
2155
|
/**
|
|
1769
2156
|
* Create a completion subcommand for your CLI
|
|
1770
2157
|
*
|
|
@@ -1780,12 +2167,30 @@ const completionArgsSchema = z.object({
|
|
|
1780
2167
|
* });
|
|
1781
2168
|
* ```
|
|
1782
2169
|
*/
|
|
1783
|
-
function createCompletionCommand(rootCommand, programName, globalArgsSchema) {
|
|
2170
|
+
function createCompletionCommand(rootCommand, programName, globalArgsSchema, extra = {}) {
|
|
1784
2171
|
const resolvedProgramName = programName ?? rootCommand.name;
|
|
2172
|
+
const { cacheDir, programVersion } = extra;
|
|
2173
|
+
const refreshExtra = {
|
|
2174
|
+
...cacheDir !== void 0 && { cacheDir },
|
|
2175
|
+
...programVersion !== void 0 && { programVersion },
|
|
2176
|
+
...globalArgsSchema !== void 0 && { globalArgsSchema }
|
|
2177
|
+
};
|
|
2178
|
+
const installCtxBase = {
|
|
2179
|
+
programName: resolvedProgramName,
|
|
2180
|
+
...refreshExtra
|
|
2181
|
+
};
|
|
2182
|
+
const loaderOptsBase = {
|
|
2183
|
+
programName: resolvedProgramName,
|
|
2184
|
+
...cacheDir !== void 0 && { cacheDir }
|
|
2185
|
+
};
|
|
1785
2186
|
if (!rootCommand.subCommands?.__complete) rootCommand.subCommands = {
|
|
1786
2187
|
...rootCommand.subCommands,
|
|
1787
2188
|
__complete: createDynamicCompleteCommand(rootCommand, resolvedProgramName)
|
|
1788
2189
|
};
|
|
2190
|
+
if (!rootCommand.subCommands?.["__refresh-completion"]) rootCommand.subCommands = {
|
|
2191
|
+
...rootCommand.subCommands,
|
|
2192
|
+
"__refresh-completion": createRefreshCompletionCommand(rootCommand, resolvedProgramName, refreshExtra)
|
|
2193
|
+
};
|
|
1789
2194
|
return defineCommand({
|
|
1790
2195
|
name: "completion",
|
|
1791
2196
|
description: "Generate shell completion script",
|
|
@@ -1797,11 +2202,43 @@ function createCompletionCommand(rootCommand, programName, globalArgsSchema) {
|
|
|
1797
2202
|
process.exitCode = 1;
|
|
1798
2203
|
return;
|
|
1799
2204
|
}
|
|
2205
|
+
if (args.install) {
|
|
2206
|
+
let target;
|
|
2207
|
+
try {
|
|
2208
|
+
target = install({
|
|
2209
|
+
rootCommand,
|
|
2210
|
+
...installCtxBase
|
|
2211
|
+
}, shellType);
|
|
2212
|
+
} catch (e) {
|
|
2213
|
+
throw new Error(`install failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
2214
|
+
}
|
|
2215
|
+
console.error(`installed: ${target}`);
|
|
2216
|
+
if (shellType !== "fish") {
|
|
2217
|
+
console.error("");
|
|
2218
|
+
console.error(`Add to your ~/.${shellType}rc:`);
|
|
2219
|
+
console.error("");
|
|
2220
|
+
console.error(generateLoader({
|
|
2221
|
+
...loaderOptsBase,
|
|
2222
|
+
shell: shellType
|
|
2223
|
+
}).trim().replace(/^/gm, " "));
|
|
2224
|
+
}
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
if (args.loader) {
|
|
2228
|
+
if (shellType === "fish") throw new Error("fish does not use an rc loader. Run `<program> completion fish --install` to write the self-refreshing autoload file instead.");
|
|
2229
|
+
process.stdout.write(generateLoader({
|
|
2230
|
+
...loaderOptsBase,
|
|
2231
|
+
shell: shellType
|
|
2232
|
+
}));
|
|
2233
|
+
return;
|
|
2234
|
+
}
|
|
1800
2235
|
const result = generateCompletion(rootCommand, {
|
|
1801
2236
|
shell: shellType,
|
|
1802
2237
|
programName: resolvedProgramName,
|
|
1803
2238
|
includeDescriptions: true,
|
|
1804
|
-
...globalArgsSchema !== void 0 && { globalArgsSchema }
|
|
2239
|
+
...globalArgsSchema !== void 0 && { globalArgsSchema },
|
|
2240
|
+
...programVersion !== void 0 && { programVersion },
|
|
2241
|
+
...cacheDir !== void 0 && { cacheDir }
|
|
1805
2242
|
});
|
|
1806
2243
|
if (args.instructions) console.log(result.installInstructions);
|
|
1807
2244
|
else console.log(result.script);
|
|
@@ -1809,6 +2246,25 @@ function createCompletionCommand(rootCommand, programName, globalArgsSchema) {
|
|
|
1809
2246
|
});
|
|
1810
2247
|
}
|
|
1811
2248
|
/**
|
|
2249
|
+
* Hidden subcommand that the runMain background hook spawns. It does
|
|
2250
|
+
* the same stat-compare + atomic rewrite as the rc loader, but in a
|
|
2251
|
+
* detached child process so it's invisible to the user.
|
|
2252
|
+
*/
|
|
2253
|
+
function createRefreshCompletionCommand(rootCommand, programName, extra = {}) {
|
|
2254
|
+
return defineCommand({
|
|
2255
|
+
name: "__refresh-completion",
|
|
2256
|
+
description: "(internal) Refresh the on-disk completion cache if stale.",
|
|
2257
|
+
args: refreshArgsSchema,
|
|
2258
|
+
run(args) {
|
|
2259
|
+
refreshIfStale({
|
|
2260
|
+
rootCommand,
|
|
2261
|
+
programName,
|
|
2262
|
+
...extra
|
|
2263
|
+
}, args.shell);
|
|
2264
|
+
}
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2267
|
+
/**
|
|
1812
2268
|
* Wrap a command with a completion subcommand
|
|
1813
2269
|
*
|
|
1814
2270
|
* This avoids circular references that occur when a command references itself
|
|
@@ -1829,16 +2285,54 @@ function createCompletionCommand(rootCommand, programName, globalArgsSchema) {
|
|
|
1829
2285
|
* ```
|
|
1830
2286
|
*/
|
|
1831
2287
|
function withCompletionCommand(command, options) {
|
|
1832
|
-
const { programName, globalArgsSchema } = typeof options === "string" ? { programName: options } : options ?? {};
|
|
2288
|
+
const { programName, globalArgsSchema, cacheDir, programVersion } = typeof options === "string" ? { programName: options } : options ?? {};
|
|
2289
|
+
const resolvedProgramName = programName ?? command.name;
|
|
2290
|
+
const extra = {
|
|
2291
|
+
...cacheDir !== void 0 && { cacheDir },
|
|
2292
|
+
...programVersion !== void 0 && { programVersion },
|
|
2293
|
+
...globalArgsSchema !== void 0 && { globalArgsSchema }
|
|
2294
|
+
};
|
|
1833
2295
|
const wrappedCommand = { ...command };
|
|
1834
2296
|
wrappedCommand.subCommands = {
|
|
1835
2297
|
...command.subCommands,
|
|
1836
|
-
completion: createCompletionCommand(wrappedCommand, programName, globalArgsSchema),
|
|
1837
|
-
__complete: createDynamicCompleteCommand(wrappedCommand, programName)
|
|
2298
|
+
completion: createCompletionCommand(wrappedCommand, programName, globalArgsSchema, extra),
|
|
2299
|
+
__complete: createDynamicCompleteCommand(wrappedCommand, programName),
|
|
2300
|
+
"__refresh-completion": createRefreshCompletionCommand(wrappedCommand, resolvedProgramName, extra)
|
|
2301
|
+
};
|
|
2302
|
+
wrappedCommand.runMainHook = (argv) => {
|
|
2303
|
+
maybeSpawnRefresh(argv, {
|
|
2304
|
+
programName: resolvedProgramName,
|
|
2305
|
+
...cacheDir !== void 0 && { cacheDir }
|
|
2306
|
+
});
|
|
1838
2307
|
};
|
|
1839
2308
|
return wrappedCommand;
|
|
1840
2309
|
}
|
|
2310
|
+
/**
|
|
2311
|
+
* Background-refresh trigger fired from `runMain` via `runMainHook`.
|
|
2312
|
+
*
|
|
2313
|
+
* Skipped when:
|
|
2314
|
+
* - the user is invoking `__complete` / `__refresh-completion` /
|
|
2315
|
+
* `completion` themselves (avoids loops and double work)
|
|
2316
|
+
* - $SHELL doesn't resolve to a known shell
|
|
2317
|
+
* - the user opted out via $POLITTY_NO_COMPLETION_REFRESH
|
|
2318
|
+
* - process.argv[1] is missing (shouldn't happen for normal CLIs)
|
|
2319
|
+
* - no politty-managed cache exists yet — i.e. the user hasn't
|
|
2320
|
+
* installed completion. Without this gate the detached child would
|
|
2321
|
+
* create a fish autoload (or any cache file) on every CLI run,
|
|
2322
|
+
* even though the user never opted in via `--install` or the rc loader.
|
|
2323
|
+
*/
|
|
2324
|
+
function maybeSpawnRefresh(argv, ctx) {
|
|
2325
|
+
if (process.env.POLITTY_NO_COMPLETION_REFRESH) return;
|
|
2326
|
+
const firstPositional = argv.find((a) => !a.startsWith("-"));
|
|
2327
|
+
if (firstPositional === "__complete" || firstPositional === "__refresh-completion" || firstPositional === "completion") return;
|
|
2328
|
+
const shell = detectShell();
|
|
2329
|
+
if (!shell) return;
|
|
2330
|
+
const argv0 = process.argv[1];
|
|
2331
|
+
if (!argv0) return;
|
|
2332
|
+
if (!hasManagedCache(ctx, shell)) return;
|
|
2333
|
+
spawnBackgroundRefresh(argv0, shell);
|
|
2334
|
+
}
|
|
1841
2335
|
|
|
1842
2336
|
//#endregion
|
|
1843
|
-
export {
|
|
1844
|
-
//# sourceMappingURL=completion-
|
|
2337
|
+
export { defineCommand as _, getSupportedShells as a, hasCompleteCommand as c, CompletionDirective as d, generateCandidates as f, createDefineCommand as g, resolveValueCompletion as h, generateCompletion as i, formatForShell as l, extractPositionals as m, createRefreshCompletionCommand as n, withCompletionCommand as o, extractCompletionData as p, detectShell as r, createDynamicCompleteCommand as s, createCompletionCommand as t, parseCompletionContext as u };
|
|
2338
|
+
//# sourceMappingURL=completion-B04iiki9.js.map
|