mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-06-13 07:10:26 +08:00
171 lines
5.2 KiB
TypeScript
171 lines
5.2 KiB
TypeScript
import {
|
|
CancellationTokenSource,
|
|
Disposable,
|
|
ExtensionContext,
|
|
NotebookCellOutputItem,
|
|
OutputChannel,
|
|
QuickPickItem,
|
|
commands,
|
|
extensions,
|
|
window,
|
|
workspace,
|
|
} from 'vscode';
|
|
import { Jupyter, Kernel } from '@vscode/jupyter-extension';
|
|
import * as path from 'path';
|
|
import { TextDecoder } from 'util';
|
|
|
|
export function activate(context: ExtensionContext) {
|
|
const jupyterExt = extensions.getExtension<Jupyter>('ms-toolsai.jupyter');
|
|
if (!jupyterExt) {
|
|
throw new Error('Jupyter Extension not installed');
|
|
}
|
|
if (!jupyterExt.isActive) {
|
|
jupyterExt.activate();
|
|
}
|
|
const output = window.createOutputChannel('Jupyter Kernel Execution');
|
|
context.subscriptions.push(output);
|
|
context.subscriptions.push(
|
|
commands.registerCommand('jupyterKernelExecution.listKernels', async () => {
|
|
const kernel = await selectKernel();
|
|
if (!kernel) {
|
|
return;
|
|
}
|
|
const code = await selectCodeToRunAgainstKernel();
|
|
if (!code) {
|
|
return;
|
|
}
|
|
await executeCode(kernel, code, output);
|
|
})
|
|
);
|
|
}
|
|
|
|
const ErrorMimeType = NotebookCellOutputItem.error(new Error('')).mime;
|
|
// const StdOutMimeType = NotebookCellOutputItem.stdout('').mime;
|
|
// const StdErrMimeType = NotebookCellOutputItem.stderr('').mime;
|
|
// const MarkdownMimeType = 'text/markdown';
|
|
// const HtmlMimeType = 'text/html';
|
|
const textDecoder = new TextDecoder();
|
|
async function executeCode(kernel: Kernel, code: string, logger: OutputChannel) {
|
|
logger.show();
|
|
logger.appendLine(`>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`);
|
|
logger.appendLine(`Executing code against kernel ${code}`);
|
|
const tokenSource = new CancellationTokenSource();
|
|
try {
|
|
for await (const output of kernel.executeCode(code, tokenSource.token)) {
|
|
for (const outputItem of output.items) {
|
|
if (outputItem.mime === ErrorMimeType) {
|
|
const error = JSON.parse(textDecoder.decode(outputItem.data)) as Error;
|
|
logger.appendLine(
|
|
`Error executing code ${error.name}: ${error.message},/n ${error.stack}`
|
|
);
|
|
} else {
|
|
logger.appendLine(
|
|
`${outputItem.mime} Output: ${textDecoder.decode(outputItem.data)}`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
logger.appendLine('Code execution completed');
|
|
logger.appendLine(`<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<`);
|
|
} catch (ex) {
|
|
logger.appendLine(`Code execution failed with an error '${ex}'`);
|
|
logger.appendLine(`<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<`);
|
|
} finally {
|
|
tokenSource.dispose();
|
|
}
|
|
}
|
|
|
|
const printHelloWorld = `print('Hello World')`;
|
|
const throwAnError = `raise Exception('Hello World')`;
|
|
const displayMarkdown = `from IPython.display import display, Markdown
|
|
display(Markdown('*some markdown*'))`;
|
|
const displayHtml = `from IPython.display import display, HTML
|
|
display(HTML('<div>Hello World</div>'))`;
|
|
const printToStdErr = `import sys
|
|
print('Hello World', file=sys.stderr)`;
|
|
const streamOutput = `import time
|
|
for i in range(10):
|
|
print(i)
|
|
time.sleep(1)`;
|
|
|
|
const codeSnippets = new Map([
|
|
['Print Hello World', printHelloWorld],
|
|
['Stream Output', streamOutput],
|
|
['Display Markdown', displayMarkdown],
|
|
['Display HTML', displayHtml],
|
|
['Print to StdErr', printToStdErr],
|
|
['Throw an Error', throwAnError],
|
|
]);
|
|
|
|
async function selectCodeToRunAgainstKernel() {
|
|
const selection = await window.showQuickPick(Array.from(codeSnippets.keys()), {
|
|
placeHolder: 'Select code to execute against the kernel',
|
|
});
|
|
if (!selection) {
|
|
return;
|
|
}
|
|
return codeSnippets.get(selection);
|
|
}
|
|
|
|
async function selectKernel(): Promise<Kernel | undefined> {
|
|
const extension = extensions.getExtension<Jupyter>('ms-toolsai.jupyter');
|
|
if (!extension) {
|
|
throw new Error('Jupyter extension not installed');
|
|
}
|
|
await extension.activate();
|
|
|
|
if (workspace.notebookDocuments.length === 0) {
|
|
window.showErrorMessage(
|
|
'No notebooks open. Open a notebook, run a cell and then try this command'
|
|
);
|
|
return;
|
|
}
|
|
const toDispose: Disposable[] = [];
|
|
|
|
return new Promise<Kernel | undefined>((resolve) => {
|
|
const quickPick = window.createQuickPick<QuickPickItem & { kernel: Kernel }>();
|
|
toDispose.push(quickPick);
|
|
const quickPickItems: (QuickPickItem & { kernel: Kernel })[] = [];
|
|
quickPick.title = 'Select a Kernel';
|
|
quickPick.placeholder = 'Select a Python Kernel to execute some code';
|
|
quickPick.busy = true;
|
|
quickPick.show();
|
|
|
|
const api = extension.exports;
|
|
Promise.all(
|
|
workspace.notebookDocuments.map(async (document) => {
|
|
const kernel = await api.kernels.getKernel(document.uri);
|
|
if (kernel && kernel.language === 'python') {
|
|
quickPickItems.push({
|
|
label: `Kernel for ${path.basename(document.uri.fsPath)}`,
|
|
kernel,
|
|
});
|
|
quickPick.items = quickPickItems;
|
|
}
|
|
})
|
|
).finally(() => {
|
|
quickPick.busy = false;
|
|
if (quickPickItems.length === 0) {
|
|
quickPick.hide();
|
|
window.showErrorMessage(
|
|
'No active kernels associated with any of the open notebooks, try opening a notebook and running a Python cell'
|
|
);
|
|
return resolve(undefined);
|
|
}
|
|
});
|
|
|
|
quickPick.onDidAccept(
|
|
() => {
|
|
quickPick.hide();
|
|
if (quickPick.selectedItems.length > 0) {
|
|
return resolve(quickPick.selectedItems[0].kernel);
|
|
}
|
|
resolve(undefined);
|
|
},
|
|
undefined,
|
|
toDispose
|
|
);
|
|
quickPick.onDidHide(() => resolve(undefined), undefined, toDispose);
|
|
}).finally(() => Disposable.from(...toDispose).dispose());
|
|
}
|