pi-pretty-tui 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/extensions/index.ts +90 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A beautiful, polished TUI for the [Pi coding agent](https://pi.dev/).
|
|
|
8
8
|
|
|
9
9
|
- **Collapsible tool activity:** instead of filling the conversation with individual tool calls, supported tools are collected into a single `Running(...)` row while work is in progress and a quiet `Done(...)` row when it finishes. Click the group to reveal its compact child calls, click any child for full details, and click the parent again to collapse everything.
|
|
10
10
|
- **Useful details on demand:** tool-aware summaries keep paths, commands, results, diffs, file previews, and live shell output concise without removing access to the original content.
|
|
11
|
-
- **A cohesive visual finish:** rounded user messages and prompt input, theme-aware colors,
|
|
11
|
+
- **A cohesive visual finish:** rounded user messages and prompt input, theme-aware colors, a clear Markdown heading hierarchy, cleaner lists, and rounded syntax-highlighted code blocks make the entire TUI feel intentional. In fullscreen, each fenced code block also includes a native-feeling `[Copy]` control.
|
|
12
12
|
|
|
13
13
|
Collapsible grouping covers Pi's built-in `read`, `bash`, `edit`, `write`, `grep`, `find`, and `ls` tools. Third-party tools keep their own rendering, and Pi's cursor, IME, autocomplete, mouse interaction, and tool execution behavior remain intact.
|
|
14
14
|
|
package/README.zh-CN.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
- **可折叠的工具活动:** 不再让大量独立工具调用填满对话。工作进行时,受支持的工具会集中显示为一行 `Running(...)`;工作结束后,则变为低调的 `Done(...)`。点击分组可展开紧凑的子工具列表,点击任一子工具可查看完整详情,再次点击父级即可全部折叠。
|
|
10
10
|
- **按需查看有效信息:** 针对不同工具设计的摘要,会简洁呈现路径、命令、结果、diff、文件预览和实时 shell 输出,同时保留查看原始完整内容的能力。
|
|
11
|
-
- **统一、精致的视觉体验:**
|
|
11
|
+
- **统一、精致的视觉体验:** 圆角用户消息与输入框、主题感知配色、层级清晰的 Markdown 标题、更清爽的列表,以及带语法高亮的圆角代码块,让整个 TUI 更协调。在 fullscreen 模式下,每个围栏代码块还带有符合原生体验的 `[Copy]` 控件。
|
|
12
12
|
|
|
13
13
|
可折叠分组覆盖 Pi 内置的 `read`、`bash`、`edit`、`write`、`grep`、`find` 和 `ls` 工具。第三方工具保留自己的渲染方式,同时不会影响 Pi 原有的光标、输入法、自动补全、鼠标交互和工具执行行为。
|
|
14
14
|
|
package/extensions/index.ts
CHANGED
|
@@ -604,6 +604,96 @@ export default function prettyTui(pi: ExtensionAPI) {
|
|
|
604
604
|
nextTokenType?: string,
|
|
605
605
|
styleContext?: any,
|
|
606
606
|
): string[] {
|
|
607
|
+
if (token?.type === "heading") {
|
|
608
|
+
const level = Math.max(1, Math.min(6, Number(token.depth) || 1));
|
|
609
|
+
const maxWidth = Math.max(1, width);
|
|
610
|
+
const addHeadingSpacing = (lines: string[]) => {
|
|
611
|
+
if (nextTokenType && nextTokenType !== "space") lines.push("");
|
|
612
|
+
return lines;
|
|
613
|
+
};
|
|
614
|
+
const headingStyle = (text: string) => this.theme.heading(text);
|
|
615
|
+
const foregroundLuminance = (styled: string): number | undefined => {
|
|
616
|
+
const trueColor = /\x1b\[38;2;(\d+);(\d+);(\d+)m/.exec(styled);
|
|
617
|
+
if (!trueColor) return undefined;
|
|
618
|
+
const [, red, green, blue] = trueColor.map(Number);
|
|
619
|
+
return red * 0.2126 + green * 0.7152 + blue * 0.0722;
|
|
620
|
+
};
|
|
621
|
+
const defaultLuminance = foregroundLuminance(this.applyDefaultStyle("M"));
|
|
622
|
+
const headingLuminance = foregroundLuminance(headingStyle("M"));
|
|
623
|
+
const darkTheme =
|
|
624
|
+
defaultLuminance !== undefined
|
|
625
|
+
? defaultLuminance >= 128
|
|
626
|
+
: (headingLuminance ?? 255) >= 160;
|
|
627
|
+
const whiteStyle = (text: string) => `\x1b[97m${text}\x1b[39m`;
|
|
628
|
+
const titleStyle =
|
|
629
|
+
level === 1 || level === 3
|
|
630
|
+
? (text: string) => headingStyle(this.theme.bold(this.theme.underline(text)))
|
|
631
|
+
: level === 2
|
|
632
|
+
? (text: string) =>
|
|
633
|
+
(darkTheme ? whiteStyle : headingStyle)(
|
|
634
|
+
this.theme.bold(this.theme.underline(text)),
|
|
635
|
+
)
|
|
636
|
+
: level === 4
|
|
637
|
+
? (text: string) => headingStyle(this.theme.bold(text))
|
|
638
|
+
: level === 5
|
|
639
|
+
? headingStyle
|
|
640
|
+
: (text: string) => this.theme.quote(this.theme.italic(text));
|
|
641
|
+
const titleContext = {
|
|
642
|
+
applyText: titleStyle,
|
|
643
|
+
stylePrefix: this.getStylePrefix(titleStyle),
|
|
644
|
+
};
|
|
645
|
+
const title = this.renderInlineTokens(token.tokens || [], titleContext);
|
|
646
|
+
|
|
647
|
+
if (level === 1 && maxWidth >= 6) {
|
|
648
|
+
const maximumInnerWidth = maxWidth - 4;
|
|
649
|
+
const titleLines = wrapTextWithAnsi(title, Math.max(1, maximumInnerWidth));
|
|
650
|
+
const innerWidth = Math.max(
|
|
651
|
+
1,
|
|
652
|
+
...titleLines.map((line: string) => visibleWidth(line)),
|
|
653
|
+
);
|
|
654
|
+
const frameWidth = Math.min(maxWidth, innerWidth + 4);
|
|
655
|
+
const frameStyle = (text: string) => headingStyle(this.theme.bold(text));
|
|
656
|
+
const lines = [
|
|
657
|
+
frameStyle(`╔${"═".repeat(frameWidth - 2)}╗`),
|
|
658
|
+
...titleLines.map((line: string) => {
|
|
659
|
+
const padding = " ".repeat(Math.max(0, innerWidth - visibleWidth(line)));
|
|
660
|
+
return frameStyle("║ ") + line + frameStyle(`${padding} ║`);
|
|
661
|
+
}),
|
|
662
|
+
frameStyle(`╚${"═".repeat(frameWidth - 2)}╝`),
|
|
663
|
+
];
|
|
664
|
+
return addHeadingSpacing(lines);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (level === 2) {
|
|
668
|
+
// Reverse only the rendered title cells: the theme's heading color
|
|
669
|
+
// becomes a compact, content-width background label with no frame.
|
|
670
|
+
const lines = wrapTextWithAnsi(title, maxWidth).map((line: string) =>
|
|
671
|
+
darkTheme
|
|
672
|
+
? `\x1b[48;5;94m${line}\x1b[49m`
|
|
673
|
+
: `\x1b[107m\x1b[7m${line}\x1b[27m\x1b[49m`
|
|
674
|
+
);
|
|
675
|
+
return addHeadingSpacing(lines);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (level === 5 && maxWidth >= 8) {
|
|
679
|
+
const prefix = "┄┄ ";
|
|
680
|
+
const suffix = " ┄┄";
|
|
681
|
+
const contentWidth = Math.max(
|
|
682
|
+
1,
|
|
683
|
+
maxWidth - visibleWidth(prefix) - visibleWidth(suffix),
|
|
684
|
+
);
|
|
685
|
+
const wrapped = wrapTextWithAnsi(title, contentWidth);
|
|
686
|
+
const lines = wrapped.map((line: string, index: number) => {
|
|
687
|
+
const left = index === 0 ? this.theme.heading(prefix) : " ".repeat(visibleWidth(prefix));
|
|
688
|
+
const right = index === wrapped.length - 1 ? this.theme.heading(suffix) : "";
|
|
689
|
+
return left + line + right;
|
|
690
|
+
});
|
|
691
|
+
return addHeadingSpacing(lines);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return addHeadingSpacing(wrapTextWithAnsi(title, maxWidth));
|
|
695
|
+
}
|
|
696
|
+
|
|
607
697
|
if (token?.type !== "code") {
|
|
608
698
|
return originalRenderToken.call(this, token, width, nextTokenType, styleContext);
|
|
609
699
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-pretty-tui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "A beautiful, polished TUI for the Pi coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Kainan Yang <ykn0309@whu.edu.cn>",
|
|
@@ -52,6 +52,6 @@
|
|
|
52
52
|
"extensions": [
|
|
53
53
|
"./extensions/index.ts"
|
|
54
54
|
],
|
|
55
|
-
"image": "https://unpkg.com/pi-pretty-tui@0.1.
|
|
55
|
+
"image": "https://unpkg.com/pi-pretty-tui@0.1.8/assets/screenshot.png"
|
|
56
56
|
}
|
|
57
57
|
}
|