MCPcopy Create free account
hub / github.com/coder/ghostty-web / LinkDetector

Class LinkDetector

lib/link-detector.ts:14–219  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

12 * Manages link detection across multiple providers with intelligent caching
13 */
14export class LinkDetector {
15 private providers: ILinkProvider[] = [];
16
17 // Cache links by hyperlink_id for fast lookups
18 // Key format: `h${hyperlinkId}` for OSC 8 links
19 // Key format: `r${row}:${startX}-${endX}` for regex links (future)
20 private linkCache = new Map<string, ILink>();
21
22 // Track which rows have been scanned to avoid redundant provider calls
23 private scannedRows = new Set<number>();
24
25 // Terminal instance for buffer access
26 constructor(private terminal: ITerminalForLinkDetector) {}
27
28 /**
29 * Register a link provider
30 */
31 registerProvider(provider: ILinkProvider): void {
32 this.providers.push(provider);
33 this.invalidateCache(); // New provider may detect different links
34 }
35
36 /**
37 * Get link at the specified buffer position
38 * @param col Column (0-based)
39 * @param row Absolute row in buffer (0-based)
40 * @returns Link at position, or undefined if none
41 */
42 async getLinkAt(col: number, row: number): Promise<ILink | undefined> {
43 // First, check if this cell has a hyperlink_id (fast path for OSC 8)
44 const line = this.terminal.buffer.active.getLine(row);
45 if (!line || col < 0 || col >= line.length) {
46 return undefined;
47 }
48
49 const cell = line.getCell(col);
50 if (!cell) {
51 return undefined;
52 }
53 const hyperlinkId = cell.getHyperlinkId();
54
55 if (hyperlinkId > 0) {
56 // Fast path: check cache by hyperlink_id
57 const cacheKey = `h${hyperlinkId}`;
58 if (this.linkCache.has(cacheKey)) {
59 return this.linkCache.get(cacheKey);
60 }
61 }
62
63 // Slow path: scan this row if not already scanned
64 if (!this.scannedRows.has(row)) {
65 await this.scanRow(row);
66 }
67
68 // Check cache again (hyperlinkId or position-based)
69 if (hyperlinkId > 0) {
70 const cacheKey = `h${hyperlinkId}`;
71 const link = this.linkCache.get(cacheKey);

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…