Skip to content
Closed
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
9 changes: 5 additions & 4 deletions apps/web/src/components/files/FilePreviewPanel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,15 +296,15 @@ Third}`;
},
],
});
// IPython traceback frames can omit trailing newlines or place ANSI resets after them.
// IPython traceback frames carry ANSI SGR colors and can omit trailing newlines.
const failed = openNotebook(
bytes(
JSON.stringify({
nbformat: 4,
cells: [
{
cell_type: "code",
source: "fail()",
source: 'print("\u001b[32m")\nfail()',
outputs: [
{
output_type: "error",
Expand All @@ -330,7 +330,7 @@ Third}`;
"\u001b[31mTraceback (most recent call last):\n\u001b[0m",
"\u001b[32mCell In[3], line 1\n----> 1 fail()\n\u001b[0m\u001b[39m",
"\u001b[31mValueError: preview proof\u001b[0m",
"final entry",
"final entry \\x1b[31m kept",
],
},
],
Expand All @@ -340,6 +340,7 @@ Third}`;
),
);
if (failed.type !== "notebook") throw new Error("Expected notebook");
expect(failed.cells[0]!.source).toBe('print("\u001b[32m")\nfail()');
expect(failed.cells[0]!.outputs).toEqual([
{
kind: "text",
Expand All @@ -351,7 +352,7 @@ Third}`;
},
{
kind: "text",
text: "\u001b[31mTraceback (most recent call last):\n\u001b[0m\u001b[32mCell In[3], line 1\n----> 1 fail()\n\u001b[0m\u001b[39m\u001b[31mValueError: preview proof\u001b[0m\nfinal entry",
text: "Traceback (most recent call last):\nCell In[3], line 1\n----> 1 fail()\nValueError: preview proof\nfinal entry \\x1b[31m kept",
},
]);
expect(() => openNotebook(bytes('{"nbformat":3,"cells":[]}'))).toThrow("version 4");
Expand Down
8 changes: 5 additions & 3 deletions apps/web/src/components/files/extendedDocumentPreview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,12 +431,14 @@ function notebookText(value: unknown, limit = 256_000): string {
if (result.length > limit) throw new Error("A notebook cell is too large to preview.");
return result;
}
// IPython traceback frames may omit a final newline or follow it with ANSI SGR sequences.
// IPython traceback frames carry ANSI SGR colors a <pre> cannot render and may omit a final newline.
function tracebackLines(value: unknown): unknown {
if (!Array.isArray(value)) return value;
const frames = value.filter((frame): frame is string => typeof frame === "string");
const frames = value
.filter((frame): frame is string => typeof frame === "string")
.map((frame) => frame.replaceAll(/\u001b\[[\d;:]*m/g, ""));
return frames.map((frame, index) =>
index && !/\n(?:\u001b\[[\d;:]*m)*$/.test(frames[index - 1]!) ? `\n${frame}` : frame,
index && !frames[index - 1]!.endsWith("\n") ? `\n${frame}` : frame,
);
}
export function openNotebook(bytes: ArrayBuffer): OfficeWorkerResult {
Expand Down
Loading