Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
73 lines
2.3 KiB
TypeScript
73 lines
2.3 KiB
TypeScript
/**
|
|
* Tokenize a command-line argument string into discrete args, and format an
|
|
* arg array back into an editable string.
|
|
*
|
|
* Used by the custom local-shell config (#1221): the user types launch args
|
|
* like `--login -i` in a single field; we store them as a string[] that flows
|
|
* into `pty.spawn(shell, args)`.
|
|
*
|
|
* Quoting model (POSIX single-quote style, so format ⇄ parse round-trips):
|
|
* - Both quote types are fully literal inside their span — nothing is escaped.
|
|
* This keeps Windows paths (`C:\msys64\…`, even a trailing `\`) and embedded
|
|
* double quotes intact.
|
|
* - Outside quotes a backslash is literal too, EXCEPT `\'` which yields a
|
|
* literal single quote. That is the only escape, and it exists solely to
|
|
* support the POSIX `'\''` idiom that `formatShellArgs` emits for tokens that
|
|
* themselves contain a single quote. Every other backslash stays literal, so
|
|
* unquoted Windows paths survive.
|
|
*/
|
|
export function parseShellArgs(input: string): string[] {
|
|
const args: string[] = [];
|
|
let current = "";
|
|
let inToken = false;
|
|
let quote: '"' | "'" | null = null;
|
|
|
|
for (let i = 0; i < input.length; i++) {
|
|
const ch = input[i];
|
|
if (quote) {
|
|
if (ch === quote) quote = null;
|
|
else current += ch;
|
|
continue;
|
|
}
|
|
if (ch === "\\" && input[i + 1] === "'") {
|
|
current += "'";
|
|
inToken = true;
|
|
i++;
|
|
continue;
|
|
}
|
|
if (ch === '"' || ch === "'") {
|
|
quote = ch;
|
|
inToken = true;
|
|
continue;
|
|
}
|
|
if (/\s/.test(ch)) {
|
|
if (inToken) {
|
|
args.push(current);
|
|
current = "";
|
|
inToken = false;
|
|
}
|
|
continue;
|
|
}
|
|
current += ch;
|
|
inToken = true;
|
|
}
|
|
if (inToken) args.push(current);
|
|
return args;
|
|
}
|
|
|
|
/**
|
|
* Inverse of {@link parseShellArgs} for re-display in the editor. Single-quote
|
|
* quoting keeps the contents literal (Windows paths and double quotes need no
|
|
* escaping); an embedded single quote uses the POSIX `'\''` idiom. An explicit
|
|
* empty arg is emitted as `''` so it is not dropped on the next save.
|
|
*/
|
|
export function formatShellArgs(args: string[]): string {
|
|
return args
|
|
.map((arg) => {
|
|
if (arg === "") return "''";
|
|
if (!/[\s"']/.test(arg)) return arg;
|
|
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
})
|
|
.join(" ");
|
|
}
|