-
Notifications
You must be signed in to change notification settings - Fork 67
Expand file tree
/
Copy pathrender-helpers.ts
More file actions
78 lines (70 loc) · 2.47 KB
/
render-helpers.ts
File metadata and controls
78 lines (70 loc) · 2.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import type { Theme } from "@mariozechner/pi-coding-agent";
import { visibleWidth } from "@mariozechner/pi-tui";
function fuzzyScore(query: string, text: string): number {
const lq = query.toLowerCase();
const lt = text.toLowerCase();
if (lt.includes(lq)) return 100 + (lq.length / lt.length) * 50;
let score = 0;
let qi = 0;
let consecutive = 0;
for (let i = 0; i < lt.length && qi < lq.length; i++) {
if (lt[i] === lq[qi]) {
score += 10 + consecutive;
consecutive += 5;
qi++;
} else {
consecutive = 0;
}
}
return qi === lq.length ? score : 0;
}
export function fuzzyFilter<T extends { name: string; description: string; model?: string }>(items: T[], query: string): T[] {
const q = query.trim();
if (!q) return items;
return items
.map((item) => ({ item, score: Math.max(fuzzyScore(q, item.name), fuzzyScore(q, item.description) * 0.8, fuzzyScore(q, item.model ?? "") * 0.6) }))
.filter((x) => x.score > 0)
.sort((a, b) => b.score - a.score)
.map((x) => x.item);
}
export function pad(s: string, len: number): string {
const vis = visibleWidth(s);
return s + " ".repeat(Math.max(0, len - vis));
}
export function row(content: string, width: number, theme: Theme): string {
const innerW = width - 2;
return theme.fg("border", "│") + pad(content, innerW) + theme.fg("border", "│");
}
export function renderHeader(text: string, width: number, theme: Theme): string {
const innerW = width - 2;
const padLen = Math.max(0, innerW - visibleWidth(text));
const padLeft = Math.floor(padLen / 2);
const padRight = padLen - padLeft;
return (
theme.fg("border", "╭" + "─".repeat(padLeft)) +
theme.fg("accent", text) +
theme.fg("border", "─".repeat(padRight) + "╮")
);
}
export function formatPath(filePath: string): string {
const home = process.env.HOME;
if (home && filePath.startsWith(home)) return `~${filePath.slice(home.length)}`;
return filePath;
}
export function formatScrollInfo(above: number, below: number): string {
let info = "";
if (above > 0) info += `↑ ${above} more`;
if (below > 0) info += `${info ? " " : ""}↓ ${below} more`;
return info;
}
export function renderFooter(text: string, width: number, theme: Theme): string {
const innerW = width - 2;
const padLen = Math.max(0, innerW - visibleWidth(text));
const padLeft = Math.floor(padLen / 2);
const padRight = padLen - padLeft;
return (
theme.fg("border", "╰" + "─".repeat(padLeft)) +
theme.fg("dim", text) +
theme.fg("border", "─".repeat(padRight) + "╯")
);
}