Something went wrong. Try again.
small gleam coding and (not yet) persistent agent daemon with a detachable cli forked from okami.mom/albedo
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970// What the new session dialog's folder field asks for, as the terminal's /cd// reads it (cli/internal/tui/folder_query.go): a word filters the recent// folders, then the hosts it starts; text with an @ can only be user@host; a// path lists its folder, filtered by its last segment; host: and host:path// list that folder on the host.
import { rank } from './format';
export type FolderQuery = { kind: 'recent' | 'hosts' | 'listing'; dir: string; segment: string };
/** The host before the first colon and what follows it; text starting with / or ~, or with a slash before the colon, is local. */export function splitHost(text: string): [string | null, string] { if (!text || text[0] === '/' || text[0] === '~') return [null, text]; const bracket = text.indexOf(']:'); if (text[0] === '[' && bracket > 0) return [text.slice(0, bracket + 1), text.slice(bracket + 2)]; const colon = text.indexOf(':'); const host = text.slice(0, colon); if (colon < 0 || !host || host.includes('/')) return [null, text]; return [host, text.slice(colon + 1)];}
/** A [user@]host without its user. */export function bareHost(host: string): string { return host.slice(host.lastIndexOf('@') + 1);}
export function parseQuery(q: string): FolderQuery { if (q === '~') return { kind: 'listing', dir: '~', segment: '' }; const [host, rest] = splitHost(q); if (host) { const slash = rest.lastIndexOf('/'); if (slash >= 0) return { kind: 'listing', dir: `${host}:${rest.slice(0, slash + 1)}`, segment: rest.slice(slash + 1) }; return { kind: 'listing', dir: `${host}:~`, segment: rest === '~' ? '' : rest }; } const slash = q.lastIndexOf('/'); if (slash >= 0) return { kind: 'listing', dir: q.slice(0, slash + 1), segment: q.slice(slash + 1) }; return { kind: q.includes('@') ? 'hosts' : 'recent', dir: '', segment: q };}
/** The location to ask the daemon to list for a typed folder: a remote path as scp reads it, under its home, and a relative local one under ~. */export function folderRequest(typed: string): string { const [host, rest] = splitHost(typed); let path = rest === '/' ? rest : rest.replace(/\/$/, ''); if (path && path[0] !== '/' && path[0] !== '~') path = `~/${path}`; return host ? `${host}:${path || '~'}` : path || '~';}
/** The typed text with its last folder dropped: ~/proj/albedo/ goes up to ~/proj/. */export function upQuery(q: string): string { const dir = q.replace(/\/$/, ''); return dir.slice(0, dir.lastIndexOf('/') + 1);}
/** * The hosts the text completes: a word offers the hosts it starts (after the * folders it matches), and text with an @ matches every host by what follows * it, the typed user going with the completion. */export function hostRows(query: FolderQuery, known: string[]): string[] { if (query.kind === 'listing') return []; const at = query.segment.lastIndexOf('@'); if (query.kind === 'hosts') { const user = query.segment.slice(0, at + 1); const named = rank(known, query.segment.slice(at + 1), bareHost); return named.map((host) => (user.length > 1 ? user + bareHost(host) : host)); } const word = query.segment.toLowerCase(); return word ? known.filter((host) => bareHost(host).toLowerCase().startsWith(word)) : [];}