Something went wrong. Try again.
more up to date at codeberg https://codeberg.org/cowie/tau.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119import { accessSync, constants } from "node:fs";import { access } from "node:fs/promises";import { normalizePath, resolvePath } from "../../utils/paths.ts";
const NARROW_NO_BREAK_SPACE = "\u202F";
function tryMacOSScreenshotPath(filePath: string): string { return filePath.replace(/ (AM|PM)\./gi, `${NARROW_NO_BREAK_SPACE}$1.`);}
function tryNFDVariant(filePath: string): string { // macOS stores filenames in NFD (decomposed) form, try converting user input to NFD return filePath.normalize("NFD");}
function tryCurlyQuoteVariant(filePath: string): string { // macOS uses U+2019 (right single quotation mark) in screenshot names like "Capture d'écran" // Users typically type U+0027 (straight apostrophe) return filePath.replace(/'/g, "\u2019");}
function fileExists(filePath: string): boolean { try { accessSync(filePath, constants.F_OK); return true; } catch { return false; }}
export async function pathExists(filePath: string): Promise<boolean> { try { await access(filePath, constants.F_OK); return true; } catch { return false; }}
export function expandPath(filePath: string): string { return normalizePath(filePath, { normalizeUnicodeSpaces: true, stripAtPrefix: true });}
/** * Resolve a path relative to the given cwd. * Handles ~ expansion and absolute paths. */export function resolveToCwd(filePath: string, cwd: string): string { return resolvePath(filePath, cwd, { normalizeUnicodeSpaces: true, stripAtPrefix: true });}
export function resolveReadPath(filePath: string, cwd: string): string { const resolved = resolveToCwd(filePath, cwd);
if (fileExists(resolved)) { return resolved; }
// Try macOS AM/PM variant (narrow no-break space before AM/PM) const amPmVariant = tryMacOSScreenshotPath(resolved); if (amPmVariant !== resolved && fileExists(amPmVariant)) { return amPmVariant; }
// Try NFD variant (macOS stores filenames in NFD form) const nfdVariant = tryNFDVariant(resolved); if (nfdVariant !== resolved && fileExists(nfdVariant)) { return nfdVariant; }
// Try curly quote variant (macOS uses U+2019 in screenshot names) const curlyVariant = tryCurlyQuoteVariant(resolved); if (curlyVariant !== resolved && fileExists(curlyVariant)) { return curlyVariant; }
// Try combined NFD + curly quote (for French macOS screenshots like "Capture d'écran") const nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant); if (nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant)) { return nfdCurlyVariant; }
return resolved;}
export async function resolveReadPathAsync(filePath: string, cwd: string): Promise<string> { const resolved = resolveToCwd(filePath, cwd);
if (await pathExists(resolved)) { return resolved; }
// Try macOS AM/PM variant (narrow no-break space before AM/PM) const amPmVariant = tryMacOSScreenshotPath(resolved); if (amPmVariant !== resolved && (await pathExists(amPmVariant))) { return amPmVariant; }
// Try NFD variant (macOS stores filenames in NFD form) const nfdVariant = tryNFDVariant(resolved); if (nfdVariant !== resolved && (await pathExists(nfdVariant))) { return nfdVariant; }
// Try curly quote variant (macOS uses U+2019 in screenshot names) const curlyVariant = tryCurlyQuoteVariant(resolved); if (curlyVariant !== resolved && (await pathExists(curlyVariant))) { return curlyVariant; }
// Try combined NFD + curly quote (for French macOS screenshots like "Capture d'écran") const nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant); if (nfdCurlyVariant !== resolved && (await pathExists(nfdCurlyVariant))) { return nfdCurlyVariant; }
return resolved;}