mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 18:55:22 +00:00
chore: initialize my-pi extension bundle
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import { advanceQuoteEscapeState, readShellChars, type QuoteEscapeState } from "./shell-quote-state.js";
|
||||
|
||||
interface WindowsBashCompatibilityResult {
|
||||
command: string;
|
||||
applied: string[];
|
||||
}
|
||||
|
||||
interface LeadingCdSlashDParse {
|
||||
rawPath: string;
|
||||
operator: string;
|
||||
tail: string;
|
||||
}
|
||||
|
||||
const PYTHON_UTF8_ENV_PREFIX = "PYTHONIOENCODING=utf-8";
|
||||
|
||||
function normalizeWindowsPathForBash(rawPath: string): string {
|
||||
const trimmed = rawPath.trim();
|
||||
const unquoted =
|
||||
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
||||
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
||||
? trimmed.slice(1, -1)
|
||||
: trimmed;
|
||||
return unquoted.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
function quoteForBash(value: string): string {
|
||||
const escaped = value.replace(/"/g, '\\"');
|
||||
return `"${escaped}"`;
|
||||
}
|
||||
|
||||
function parseLeadingCdSlashD(command: string): LeadingCdSlashDParse | null {
|
||||
const prefixMatch = command.match(/^\s*cd\s+\/d\s+/i);
|
||||
if (!prefixMatch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pathStart = prefixMatch[0].length;
|
||||
const state: QuoteEscapeState = { quote: null, escaped: false };
|
||||
|
||||
for (let index = pathStart; index < command.length; index += 1) {
|
||||
const { character, nextCharacter } = readShellChars(command, index);
|
||||
|
||||
if (advanceQuoteEscapeState(state, character, "\"'")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (character === "&" && nextCharacter === "&") {
|
||||
return {
|
||||
rawPath: command.slice(pathStart, index),
|
||||
operator: "&&",
|
||||
tail: command.slice(index + 2),
|
||||
};
|
||||
}
|
||||
|
||||
if (character === "|" && nextCharacter === "|") {
|
||||
return {
|
||||
rawPath: command.slice(pathStart, index),
|
||||
operator: "||",
|
||||
tail: command.slice(index + 2),
|
||||
};
|
||||
}
|
||||
|
||||
if (character === "|" || character === ";") {
|
||||
return {
|
||||
rawPath: command.slice(pathStart, index),
|
||||
operator: character,
|
||||
tail: command.slice(index + 1),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rawPath: command.slice(pathStart),
|
||||
operator: "",
|
||||
tail: "",
|
||||
};
|
||||
}
|
||||
|
||||
function rewriteLeadingCdSlashD(command: string): { command: string; changed: boolean } {
|
||||
const parsed = parseLeadingCdSlashD(command);
|
||||
if (!parsed) {
|
||||
return { command, changed: false };
|
||||
}
|
||||
|
||||
const normalizedPath = quoteForBash(normalizeWindowsPathForBash(parsed.rawPath));
|
||||
if (!parsed.operator) {
|
||||
return {
|
||||
command: `cd ${normalizedPath}`,
|
||||
changed: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
command: `cd ${normalizedPath} ${parsed.operator} ${parsed.tail.trimStart()}`,
|
||||
changed: true,
|
||||
};
|
||||
}
|
||||
|
||||
function ensurePythonUtf8(command: string): { command: string; changed: boolean } {
|
||||
if (/\bPYTHONIOENCODING\s*=/.test(command)) {
|
||||
return { command, changed: false };
|
||||
}
|
||||
|
||||
if (!/(^|[;&|]\s*|&&\s*|\|\|\s*)python(?:3(?:\.\d+)?)?\b/i.test(command)) {
|
||||
return { command, changed: false };
|
||||
}
|
||||
|
||||
return {
|
||||
command: `${PYTHON_UTF8_ENV_PREFIX} ${command}`,
|
||||
changed: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function applyWindowsBashCompatibilityFixes(
|
||||
command: string,
|
||||
platform: string = process.platform,
|
||||
): WindowsBashCompatibilityResult {
|
||||
if (platform !== "win32") {
|
||||
return { command, applied: [] };
|
||||
}
|
||||
|
||||
let nextCommand = command;
|
||||
const applied: string[] = [];
|
||||
|
||||
const cdFix = rewriteLeadingCdSlashD(nextCommand);
|
||||
if (cdFix.changed) {
|
||||
nextCommand = cdFix.command;
|
||||
applied.push("cd-/d");
|
||||
}
|
||||
|
||||
const pythonFix = ensurePythonUtf8(nextCommand);
|
||||
if (pythonFix.changed) {
|
||||
nextCommand = pythonFix.command;
|
||||
applied.push("python-utf8");
|
||||
}
|
||||
|
||||
return { command: nextCommand, applied };
|
||||
}
|
||||
Reference in New Issue
Block a user