diff --git a/src/commands/find.ts b/src/commands/find.ts index 7aad60e..6d3efd4 100644 --- a/src/commands/find.ts +++ b/src/commands/find.ts @@ -29,10 +29,14 @@ export async function run(flags: { json?: boolean }, query: string) { const limit = pLimit(8); const results = await Promise.all( hits.map((hit) => - limit(async () => ({ - ...hit, - owner: (await resolveDid(hit.did)).handle, - })), + limit(async () => { + const owner = (await resolveDid(hit.did)).handle; + return { + ...hit, + owner, + url: `https://tangled.org/${owner}/${hit.name}`, + }; + }), ), ); spin?.stop(`${results.length} repos match`); @@ -49,15 +53,26 @@ export async function run(flags: { json?: boolean }, query: string) { const clip = (s: string, max = 50) => s.length > max ? `${s.slice(0, max - 1)}…` : s; + // osc 8 hyperlink (st-terminated — wider terminal support than bel), + // underlined cyan so it reads as a link even where osc 8 is unsupported + const link = (text: string, url: string) => + process.stdout.isTTY + ? `\x1b]8;;${url}\x1b\\${styleText(["cyan", "underline"], text)}\x1b]8;;\x1b\\` + : text; const rows = results.map((r) => [ - r.name, + link(r.name, r.url), `@${r.owner}`, r.knot, dim(clip(r.description ?? "")), ]); const header = ["NAME", "OWNER", "KNOT", "DESCRIPTION"]; - // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping our own ansi colors for width math - const visible = (s: string) => s.replace(/\x1b\[\d+m/g, "").length; + // strips our own ansi styles + osc8 hyperlink wrappers (bel- or st-terminated) for width math + // biome-ignore lint/complexity/useRegexLiterals: a literal here trips noControlCharactersInRegex instead + const invisibles = new RegExp( + "\x1b\\]8;;[^\x07\x1b]*(?:\x07|\x1b\\\\)|\x1b\\[\\d+m", + "g", + ); + const visible = (s: string) => s.replace(invisibles, "").length; const widths = header.map((h, i) => Math.max(h.length, ...rows.map((r) => visible(r[i]))), );