feat(cli): Handle Punctuation in @ Command Parsing (#5482)

This commit is contained in:
Sandy Tao
2025-08-04 10:49:15 -07:00
committed by GitHub
parent e506b40c27
commit b9fe4fc263
6 changed files with 917 additions and 15 deletions

View File

@@ -13,6 +13,13 @@ export const GOOGLE_ACCOUNTS_FILENAME = 'google_accounts.json';
const TMP_DIR_NAME = 'tmp';
const COMMANDS_DIR_NAME = 'commands';
/**
* Special characters that need to be escaped in file paths for shell compatibility.
* Includes: spaces, parentheses, brackets, braces, semicolons, ampersands, pipes,
* asterisks, question marks, dollar signs, backticks, quotes, hash, and other shell metacharacters.
*/
export const SHELL_SPECIAL_CHARS = /[ \t()[\]{};|*?$`'"#&<>!~]/;
/**
* Replaces the home directory with a tilde.
* @param path - The path to tildeify.
@@ -119,26 +126,43 @@ export function makeRelative(
}
/**
* Escapes spaces in a file path.
* Escapes special characters in a file path like macOS terminal does.
* Escapes: spaces, parentheses, brackets, braces, semicolons, ampersands, pipes,
* asterisks, question marks, dollar signs, backticks, quotes, hash, and other shell metacharacters.
*/
export function escapePath(filePath: string): string {
let result = '';
for (let i = 0; i < filePath.length; i++) {
// Only escape spaces that are not already escaped.
if (filePath[i] === ' ' && (i === 0 || filePath[i - 1] !== '\\')) {
result += '\\ ';
const char = filePath[i];
// Count consecutive backslashes before this character
let backslashCount = 0;
for (let j = i - 1; j >= 0 && filePath[j] === '\\'; j--) {
backslashCount++;
}
// Character is already escaped if there's an odd number of backslashes before it
const isAlreadyEscaped = backslashCount % 2 === 1;
// Only escape if not already escaped
if (!isAlreadyEscaped && SHELL_SPECIAL_CHARS.test(char)) {
result += '\\' + char;
} else {
result += filePath[i];
result += char;
}
}
return result;
}
/**
* Unescapes spaces in a file path.
* Unescapes special characters in a file path.
* Removes backslash escaping from shell metacharacters.
*/
export function unescapePath(filePath: string): string {
return filePath.replace(/\\ /g, ' ');
return filePath.replace(
new RegExp(`\\\\([${SHELL_SPECIAL_CHARS.source.slice(1, -1)}])`, 'g'),
'$1',
);
}
/**