Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fuzzy-docks-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@aliou/pi-processes": patch
---

Leave one terminal column unused in the collapsed log dock so long process output does not wrap into the editor.
29 changes: 29 additions & 0 deletions src/components/log-dock-component.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { visibleWidth } from "@earendil-works/pi-tui";
import { describe, expect, it } from "vitest";
import { renderCollapsedDockLine } from "./log-dock-component";

const LONG_LOG_LINE =
"build-step - 3f7a9c2 pending ↻ https://example.com/pipelines/project/service/123456/workflows/abcdef12-3456-7890-abcd-ef1234567890/jobs/integration-test?token=very-long-unbroken-log-segment-and-query-string";

describe("renderCollapsedDockLine", () => {
it("leaves a spare terminal column for long log lines", () => {
for (const width of [1, 2, 40, 80, 120]) {
const rendered = renderCollapsedDockLine(LONG_LOG_LINE, width);

expect(visibleWidth(rendered)).toBe(width - 1);
}
});

it("leaves a spare terminal column for ansi-styled log lines", () => {
const rendered = renderCollapsedDockLine(
`\u001b[2m${LONG_LOG_LINE}\u001b[22m`,
80,
);

expect(visibleWidth(rendered)).toBe(79);
});

it("renders nothing for zero width", () => {
expect(renderCollapsedDockLine(LONG_LOG_LINE, 0)).toBe("");
});
});
43 changes: 24 additions & 19 deletions src/components/log-dock-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ const PROCESS_COLORS: ThemeColor[] = [
"warning",
];

const COLLAPSED_DOCK_RIGHT_MARGIN = 1;

function getCollapsedDockLineWidth(width: number): number {
return Math.max(0, width - COLLAPSED_DOCK_RIGHT_MARGIN);
}

export function renderCollapsedDockLine(
content: string,
width: number,
): string {
const lineWidth = getCollapsedDockLineWidth(width);
if (lineWidth === 0) return "";

const innerWidth = Math.max(0, lineWidth - 2);
const line = truncateToWidth(content, innerWidth, "", true);
return ` ${line}${" ".repeat(Math.max(0, lineWidth - 1 - visibleWidth(line)))}`;
}

interface LogDockOptions {
manager: ProcessManager;
theme: Theme;
Expand Down Expand Up @@ -120,17 +138,12 @@ export class LogDockComponent implements Component {
const fg = (color: ThemeColor, s: string) => theme.fg(color, s);

const processes = this.manager.list();
const innerWidth = width - 2;
const padLine = (content: string) => {
const line =
visibleWidth(content) > innerWidth
? truncateToWidth(content, innerWidth, "", true)
: content;
return ` ${line}${" ".repeat(Math.max(0, width - 1 - visibleWidth(line)))}`;
};
const lineWidth = getCollapsedDockLineWidth(width);
const padLine = (content: string) =>
renderCollapsedDockLine(content, width);

if (processes.length === 0) {
return [renderPanelRule(width, theme), padLine(dim("No processes"))];
return [renderPanelRule(lineWidth, theme), padLine(dim("No processes"))];
}

const running = processes.filter((p) => LIVE_STATUSES.has(p.status));
Expand All @@ -146,20 +159,12 @@ export class LogDockComponent implements Component {
}

const firstLine = parts.join(" | ");
const lines = [
renderPanelRule(width, theme),
padLine(truncateToWidth(firstLine, innerWidth, "", true)),
];
const lines = [renderPanelRule(lineWidth, theme), padLine(firstLine)];

if (running.length > 0) {
const lastLogs = this.manager.getCombinedOutput(running[0].id, 1);
if (lastLogs && lastLogs.length > 0) {
const lastLog = truncateToWidth(
stripAnsi(lastLogs[lastLogs.length - 1].text),
innerWidth,
"",
true,
);
const lastLog = stripAnsi(lastLogs[lastLogs.length - 1].text);
lines.push(padLine(dim(lastLog)));
}
}
Expand Down