mirror of https://github.com/openclaw/openclaw.git
Terminal: refine table wrapping and width handling
This commit is contained in:
parent
f7f75519ad
commit
c58fffdab6
|
|
@ -83,6 +83,38 @@ describe("renderTable", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("trims leading spaces on wrapped ANSI-colored continuation lines", () => {
|
||||
const out = renderTable({
|
||||
width: 113,
|
||||
columns: [
|
||||
{ key: "Status", header: "Status", minWidth: 10 },
|
||||
{ key: "Skill", header: "Skill", minWidth: 18, flex: true },
|
||||
{ key: "Description", header: "Description", minWidth: 24, flex: true },
|
||||
{ key: "Source", header: "Source", minWidth: 10 },
|
||||
],
|
||||
rows: [
|
||||
{
|
||||
Status: "✓ ready",
|
||||
Skill: "🌤️ weather",
|
||||
Description:
|
||||
`\x1b[2mGet current weather and forecasts via wttr.in or Open-Meteo. ` +
|
||||
`Use when: user asks about weather, temperature, or forecasts for any location.` +
|
||||
`\x1b[0m`,
|
||||
Source: "openclaw-bundled",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const lines = out
|
||||
.trimEnd()
|
||||
.split("\n")
|
||||
.filter((line) => line.includes("Use when"));
|
||||
expect(lines).toHaveLength(1);
|
||||
expect(lines[0]).toContain("\u001b[2mUse when");
|
||||
expect(lines[0]).not.toContain("│ Use when");
|
||||
expect(lines[0]).not.toContain("│ \x1b[2m Use when");
|
||||
});
|
||||
|
||||
it("respects explicit newlines in cell values", () => {
|
||||
const out = renderTable({
|
||||
width: 48,
|
||||
|
|
|
|||
|
|
@ -151,6 +151,20 @@ function wrapLine(text: string, width: number): string[] {
|
|||
lines.push(cleaned);
|
||||
};
|
||||
|
||||
const trimLeadingSpaces = (tokens: Token[]) => {
|
||||
while (true) {
|
||||
const firstCharIndex = tokens.findIndex((token) => token.kind === "char");
|
||||
if (firstCharIndex < 0) {
|
||||
return;
|
||||
}
|
||||
const firstChar = tokens[firstCharIndex];
|
||||
if (!firstChar || !isSpaceChar(firstChar.value)) {
|
||||
return;
|
||||
}
|
||||
tokens.splice(firstCharIndex, 1);
|
||||
}
|
||||
};
|
||||
|
||||
const flushAt = (breakAt: number | null) => {
|
||||
if (buf.length === 0) {
|
||||
return;
|
||||
|
|
@ -166,10 +180,7 @@ function wrapLine(text: string, width: number): string[] {
|
|||
const left = buf.slice(0, breakAt);
|
||||
const rest = buf.slice(breakAt);
|
||||
pushLine(bufToString(left));
|
||||
|
||||
while (rest.length > 0 && rest[0]?.kind === "char" && isSpaceChar(rest[0].value)) {
|
||||
rest.shift();
|
||||
}
|
||||
trimLeadingSpaces(rest);
|
||||
|
||||
buf.length = 0;
|
||||
buf.push(...rest);
|
||||
|
|
@ -201,6 +212,9 @@ function wrapLine(text: string, width: number): string[] {
|
|||
if (bufVisible + charWidth > width && bufVisible > 0) {
|
||||
flushAt(lastBreakIndex);
|
||||
}
|
||||
if (bufVisible === 0 && isSpaceChar(ch)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.push(token);
|
||||
bufVisible += charWidth;
|
||||
|
|
@ -234,6 +248,10 @@ function normalizeWidth(n: number | undefined): number | undefined {
|
|||
return Math.floor(n);
|
||||
}
|
||||
|
||||
export function getTerminalTableWidth(minWidth = 60, fallbackWidth = 120): number {
|
||||
return Math.max(minWidth, process.stdout.columns ?? fallbackWidth);
|
||||
}
|
||||
|
||||
export function renderTable(opts: RenderTableOptions): string {
|
||||
const rows = opts.rows.map((row) => {
|
||||
const next: Record<string, string> = {};
|
||||
|
|
|
|||
Loading…
Reference in New Issue