94 lines · 3.1 KB · TypeScript
RawDownload
/** * Path display utilities for shortening file paths in tight UI spaces. * * Strategy: * 1. Strip project root to make relative * 2. Replace home directory with ~ * 3. Middle-truncate if still too long, preserving first and last segments * * Also provides resolveAbsolutePath() for clipboard copy (~ → real home, relative → absolute). */ /** * Shorten a file path for display in compact UI elements. * Full path should still be available via tooltip (title attribute). * * Examples: * - `/Users/name/.claude/projects/-Users-name-project/memory/MEMORY.md` → `~/.claude/…/memory/MEMORY.md` * - `/Users/name/project/.claude/rules/tailwind.md` (with projectRoot) → `.claude/rules/tailwind.md` * - `~/.claude/CLAUDE.md` → `~/.claude/CLAUDE.md` (already short) */export function shortenDisplayPath(fullPath: string, projectRoot?: string, maxLength = 40): string {  let p = fullPath;   // 1. Make relative to project root  if (projectRoot) {    const root = projectRoot.replace(/[/\\]$/, '');    if (p.startsWith(root + '/') || p.startsWith(root + '\\')) {      p = p.slice(root.length + 1);    }  }   // 2. Replace home directory with ~  p = p    .replace(/^\/Users\/[^/]+/, '~')    .replace(/^\/home\/[^/]+/, '~')    .replace(/^[A-Z]:\\Users\\[^\\]+/, '~');   // 3. If short enough, return as-is  if (p.length <= maxLength) return p;   // 4. Middle-truncate: keep first meaningful segments + … + last 2 segments  const sep = p.includes('\\') ? '\\' : '/';  const segments = p.split(sep);   // Determine where content starts (skip leading empty segment from absolute paths or ~)  let startIdx = 0;  if (segments[0] === '' || segments[0] === '~') startIdx = 1;   // Need at least 4 content segments to truncate the middle  if (segments.length - startIdx <= 3) return p;   const head = segments.slice(0, startIdx + 1).join(sep);  const tail = segments.slice(-2).join(sep);   return `${head}${sep}\u2026${sep}${tail}`;} /** * Infer the user's home directory from a known absolute project path. * Works for macOS (/Users/x), Linux (/home/x), and Windows (C:\Users\x). */function inferHomeDir(projectRoot: string): string | null {  const match =    /^(\/Users\/[^/]+)/.exec(projectRoot) ??    /^(\/home\/[^/]+)/.exec(projectRoot) ??    /^([A-Z]:\\Users\\[^\\]+)/.exec(projectRoot);  return match?.[1] ?? null;} /** * Resolve a possibly-shortened path to its full absolute form for clipboard copy. * * - `~/...` → `/Users/username/...` (home dir inferred from projectRoot) * - `src/foo/bar` → `{projectRoot}/src/foo/bar` * - Already absolute → returned as-is */export function resolveAbsolutePath(filePath: string, projectRoot?: string): string {  let p = filePath;   // Resolve ~ using home dir inferred from projectRoot  if (p.startsWith('~/') && projectRoot) {    const homeDir = inferHomeDir(projectRoot);    if (homeDir) {      p = homeDir + p.slice(1);    }  }   // Make relative paths absolute by prepending projectRoot  if (projectRoot && !p.startsWith('/') && !p.startsWith('~') && !/^[A-Z]:[/\\]/.test(p)) {    p = projectRoot.replace(/[/\\]$/, '') + '/' + p;  }   return p;}