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