Skip to content

Commit

Permalink
put stdout / stderr in output channel instead of cell output
Browse files Browse the repository at this point in the history
fixes  #40
  • Loading branch information
Jake Donham committed Jun 21, 2024
1 parent 5121bb6 commit 608f8f4
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 68 deletions.
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,6 @@ import { foo } from "./bar.ts";
and changes to the imported file will cause dependent cells to re-execute as
above.

## Environment variables

`vitale` inherits the environment variable setup from Vite, see [Env Variables
and Modes](https://vitejs.dev/guide/env-and-mode.html).

Since code in cells is transformed by Vite, you need to prefix variables with
`VITE_` in order for them to be visible.

## Output panes

Cell output is displayed below the cell. You can open the output in a separate
Expand Down Expand Up @@ -193,6 +185,20 @@ document.getElementById(__vitale_cell_output_root_id__).innerText =
It should be possible to render non-React frameworks this way but I haven't
tried it.

## Logging

Standard output and error streams are captured when running cells and sent to a
per-cell output channel. Press the ![output](./assets/CodiconOutput.svg) button
in the cell status bar to view the channel.

## Environment variables

`vitale` inherits the environment variable setup from Vite, see [Env Variables
and Modes](https://vitejs.dev/guide/env-and-mode.html).

Since code in cells is transformed by Vite, you need to prefix variables with
`VITE_` in order for them to be visible.

## Known issues

- cancelling an execution only cancels it client-side; if you get your server
Expand Down
1 change: 1 addition & 0 deletions assets/CodiconOutput.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 4 additions & 8 deletions packages/server/src/domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,11 @@ process.stderr.write = (chunk, ...args) => {
};

export function createDomain(
stdoutChunks: Buffer[],
stderrChunks: Buffer[]
stdoutWrite: (chunk: Buffer) => void,
stderrWrite: (chunk: Buffer) => void
): DomainWithWriters {
const domain: DomainWithWriters = Domain.create();
domain.stdoutWrite = (chunk: Buffer) => {
stdoutChunks.push(chunk);
};
domain.stderrWrite = (chunk: Buffer) => {
stderrChunks.push(chunk);
};
domain.stdoutWrite = stdoutWrite;
domain.stderrWrite = stderrWrite;
return domain;
}
24 changes: 8 additions & 16 deletions packages/server/src/executeCell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,6 @@ export async function executeCell(
}

let mimeTaggedResult;
const stdoutChunks: Buffer[] = [];
const stderrChunks: Buffer[] = [];

try {
const cell = cells.get(id);
if (!cell) throw new Error(`cell not found: ${id}`);
Expand Down Expand Up @@ -115,7 +112,14 @@ export async function executeCell(

// server execution
else {
const domain = createDomain(stdoutChunks, stderrChunks);
const domain = createDomain(
(chunk) => {
rpc.outputStdout(path, cellId, chunk.toString("utf8"));
},
(chunk) => {
rpc.outputStderr(path, cellId, chunk.toString("utf8"));
}
);
let { default: result } = await domain.run(
async () => await runtime.executeUrl(id)
);
Expand All @@ -142,18 +146,6 @@ export async function executeCell(
mime: mimeTaggedResult.mime,
});
}
if (stdoutChunks.length > 0) {
items.push({
data: [...Buffer.concat(stdoutChunks).values()],
mime: "application/vnd.code.notebook.stdout",
});
}
if (stderrChunks.length > 0) {
items.push({
data: [...Buffer.concat(stderrChunks).values()],
mime: "application/vnd.code.notebook.stderr",
});
}
const cellOutput: CellOutput = { items };

await rpc.endCellExecution(path, cellId, cellOutput);
Expand Down
2 changes: 2 additions & 0 deletions packages/server/src/rpc-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export type ClientFunctions = {
cellId: string,
force: boolean
) => Promise<boolean>;
outputStdout: (path: string, cellId: string, output: string) => void;
outputStderr: (path: string, cellId: string, output: string) => void;
endCellExecution: (
path: string,
cellId: string,
Expand Down
12 changes: 12 additions & 0 deletions packages/server/src/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ export class Rpc {
).then((oks) => oks.every((ok) => ok));
}

outputStdout(path: string, cellId: string, output: string) {
for (const client of this.clients.values()) {
client.outputStdout(path, cellId, output);
}
}

outputStderr(path: string, cellId: string, output: string) {
for (const client of this.clients.values()) {
client.outputStderr(path, cellId, output);
}
}

endCellExecution(path: string, cellId: string, cellOutput: CellOutput) {
return Promise.all(
Array.from(this.clients.values()).map((client) =>
Expand Down
36 changes: 26 additions & 10 deletions packages/vscode/src/cellStatusBarItemProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ export class NotebookCellStatusBarItemProvider
provideCellStatusBarItems(cell: vscode.NotebookCell) {
const items: vscode.NotebookCellStatusBarItem[] = [];

const idItem = new vscode.NotebookCellStatusBarItem(
cell.metadata.id,
vscode.NotebookCellStatusBarAlignment.Right
);
idItem.command = {
title: "Copy to clipboard",
command: "vitale.copyToClipboard",
arguments: [cell.metadata.id],
};
items.push(idItem);
if (false) {
const idItem = new vscode.NotebookCellStatusBarItem(
cell.metadata.id,
vscode.NotebookCellStatusBarAlignment.Right
);
idItem.command = {
title: "Copy to clipboard",
command: "vitale.copyToClipboard",
arguments: [cell.metadata.id],
};
items.push(idItem);
}

if (cell.metadata.dirty || cell.metadata.docDirty) {
const dirtyItem = new vscode.NotebookCellStatusBarItem(
Expand All @@ -40,6 +42,20 @@ export class NotebookCellStatusBarItemProvider
};
items.push(pauseItem);

// TODO(jaked)
// it would be nice to show this only if there is any output
const stdoutItem = new vscode.NotebookCellStatusBarItem(
"$(output)",
vscode.NotebookCellStatusBarAlignment.Right
);
stdoutItem.tooltip = "Stdout";
stdoutItem.command = {
title: "Show stdout",
command: "vitale.showStdout",
arguments: [cell],
};
items.push(stdoutItem);

return items;
}
}
14 changes: 14 additions & 0 deletions packages/vscode/src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ export class NotebookController {
{
markCellsDirty: this.markCellsDirty.bind(this),
startCellExecution: this.startCellExecution.bind(this),
outputStdout: this.outputStdout.bind(this),
outputStderr: this.outputStderr.bind(this),
endCellExecution: this.endCellExecution.bind(this),
},
{
Expand Down Expand Up @@ -370,6 +372,18 @@ export class NotebookController {
return true;
}

private outputStdout(path: string, cellId: string, output: string) {
const name = `${path}-${cellId}-stdout`;
const channel = vscode.window.createOutputChannel(name, { log: true });
channel.append(output);
}

private outputStderr(path: string, cellId: string, output: string) {
const name = `${path}-${cellId}-stderr`;
const channel = vscode.window.createOutputChannel(name, { log: true });
channel.append(output);
}

private cancelCellExecution(path: string, id: string) {
// TODO(jaked) notify server to cancel execution
const key = `${path}-${id}`;
Expand Down
2 changes: 2 additions & 0 deletions packages/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { makeHandleDidChangeNotebookDocument } from "./handleDidChangeNotebookDo
import { makeHandleDidChangeNotebookEditorSelection } from "./handleDidChangeNotebookEditorSelection";
import { handleDidChangeTextDocument } from "./handleDidChangeTextDocument";
import { pauseCell } from "./pauseCell";
import { showStdout } from "./showStdout";
import { NotebookSerializer } from "./serializer";
import { CellOutputPanes } from "./cellOutputPanes";

Expand Down Expand Up @@ -33,6 +34,7 @@ export function activate(context: vscode.ExtensionContext) {
vscode.env.clipboard.writeText(s);
}),
vscode.commands.registerCommand("vitale.pauseCell", pauseCell),
vscode.commands.registerCommand("vitale.showStdout", showStdout),
vscode.commands.registerCommand(
"vitale.viewCellOutputInPane",
cellOutputPanes.makeViewCellOutputInPane()
Expand Down
27 changes: 1 addition & 26 deletions packages/vscode/src/log.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,3 @@
import { window } from "vscode";

const _log = window.createOutputChannel("Vitale");
export const log = {
info: (...args: any[]) => {
// eslint-disable-next-line no-console
console.log(...args);
const time = new Date().toLocaleTimeString();
_log.appendLine(`[INFO ${time}] ${args.join(" ")}`);
},
error: (...args: any[]) => {
console.error(...args);
const time = new Date().toLocaleTimeString();
for (let i = 0; i < args.length; i++) {
if (args[i] instanceof Error) {
const err = args[i] as Error;
args[i] = `[Error ${err.name}] ${err.message}\n${err.stack}`;
}
}
_log.appendLine(`[Error ${time}] ${args.join(" ")}`);
},
workspaceInfo: (folder: string, ...args: any[]) => {
log.info(`[Workspace ${folder}]`, ...args);
},
workspaceError: (folder: string, ...args: any[]) => {
log.error(`[Workspace ${folder}]`, ...args);
},
} as const;
export const log = window.createOutputChannel("Vitale", { log: true });
7 changes: 7 additions & 0 deletions packages/vscode/src/showStdout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as vscode from "vscode";

export const showStdout = async (cell: vscode.NotebookCell) => {
const name = `${cell.notebook.uri.fsPath}-${cell.metadata.id}-stdout`;
const channel = vscode.window.createOutputChannel(name, { log: true });
channel.show(/* preserveFocus: */ true);
};

0 comments on commit 608f8f4

Please sign in to comment.