mirror of
https://github.com/Microsoft/vscode
synced 2024-07-05 01:08:57 +00:00
allow copying cell output images from context menu
This commit is contained in:
parent
e40344eba7
commit
bd60cc529c
|
@ -1,124 +1,134 @@
|
|||
{
|
||||
"name": "ipynb",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"publisher": "vscode",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"vscode": "^1.57.0"
|
||||
},
|
||||
"enabledApiProposals": [
|
||||
"documentPaste",
|
||||
"diffContentOptions",
|
||||
"dropMetadata"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onNotebook:jupyter-notebook",
|
||||
"onNotebookSerializer:interactive"
|
||||
],
|
||||
"extensionKind": [
|
||||
"workspace",
|
||||
"ui"
|
||||
],
|
||||
"main": "./out/ipynbMain.js",
|
||||
"browser": "./dist/browser/ipynbMain.js",
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": true,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"contributes": {
|
||||
"configuration": [
|
||||
{
|
||||
"properties": {
|
||||
"ipynb.pasteImagesAsAttachments.enabled": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"markdownDescription": "%ipynb.pasteImagesAsAttachments.enabled%",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "ipynb.newUntitledIpynb",
|
||||
"title": "%newUntitledIpynb.title%",
|
||||
"shortTitle": "%newUntitledIpynb.shortTitle%",
|
||||
"category": "Create"
|
||||
},
|
||||
{
|
||||
"command": "ipynb.openIpynbInNotebookEditor",
|
||||
"title": "%openIpynbInNotebookEditor.title%"
|
||||
},
|
||||
{
|
||||
"command": "ipynb.cleanInvalidImageAttachment",
|
||||
"title": "%cleanInvalidImageAttachment.title%"
|
||||
}
|
||||
],
|
||||
"notebooks": [
|
||||
{
|
||||
"type": "jupyter-notebook",
|
||||
"displayName": "Jupyter Notebook",
|
||||
"selector": [
|
||||
{
|
||||
"filenamePattern": "*.ipynb"
|
||||
}
|
||||
],
|
||||
"priority": "default"
|
||||
}
|
||||
],
|
||||
"notebookRenderer": [
|
||||
{
|
||||
"id": "vscode.markdown-it-cell-attachment-renderer",
|
||||
"displayName": "%markdownAttachmentRenderer.displayName%",
|
||||
"entrypoint": {
|
||||
"extends": "vscode.markdown-it-renderer",
|
||||
"path": "./notebook-out/cellAttachmentRenderer.js"
|
||||
}
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"file/newFile": [
|
||||
{
|
||||
"command": "ipynb.newUntitledIpynb",
|
||||
"group": "notebook"
|
||||
}
|
||||
],
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "ipynb.newUntitledIpynb"
|
||||
},
|
||||
{
|
||||
"command": "ipynb.openIpynbInNotebookEditor",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "ipynb.cleanInvalidImageAttachment",
|
||||
"when": "false"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "npx gulp compile-extension:ipynb && npm run build-notebook",
|
||||
"watch": "npx gulp watch-extension:ipynb",
|
||||
"build-notebook": "node ./esbuild"
|
||||
},
|
||||
"dependencies": {
|
||||
"@enonic/fnv-plus": "^1.3.0",
|
||||
"detect-indent": "^6.0.0",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jupyterlab/nbformat": "^3.2.9",
|
||||
"@types/markdown-it": "12.2.3",
|
||||
"@types/uuid": "^8.3.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/vscode.git"
|
||||
}
|
||||
"name": "ipynb",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"publisher": "vscode",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"vscode": "^1.57.0"
|
||||
},
|
||||
"enabledApiProposals": [
|
||||
"documentPaste",
|
||||
"diffContentOptions",
|
||||
"dropMetadata"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onNotebook:jupyter-notebook",
|
||||
"onNotebookSerializer:interactive"
|
||||
],
|
||||
"extensionKind": [
|
||||
"workspace",
|
||||
"ui"
|
||||
],
|
||||
"main": "./out/ipynbMain.js",
|
||||
"browser": "./dist/browser/ipynbMain.js",
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": true,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"contributes": {
|
||||
"configuration": [
|
||||
{
|
||||
"properties": {
|
||||
"ipynb.pasteImagesAsAttachments.enabled": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"markdownDescription": "%ipynb.pasteImagesAsAttachments.enabled%",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "ipynb.newUntitledIpynb",
|
||||
"title": "%newUntitledIpynb.title%",
|
||||
"shortTitle": "%newUntitledIpynb.shortTitle%",
|
||||
"category": "Create"
|
||||
},
|
||||
{
|
||||
"command": "ipynb.openIpynbInNotebookEditor",
|
||||
"title": "%openIpynbInNotebookEditor.title%"
|
||||
},
|
||||
{
|
||||
"command": "ipynb.cleanInvalidImageAttachment",
|
||||
"title": "%cleanInvalidImageAttachment.title%"
|
||||
},
|
||||
{
|
||||
"command": "notebook.cellOutput.copyToClipboard",
|
||||
"title": "%copyOutputToClipboard.title%"
|
||||
}
|
||||
],
|
||||
"notebooks": [
|
||||
{
|
||||
"type": "jupyter-notebook",
|
||||
"displayName": "Jupyter Notebook",
|
||||
"selector": [
|
||||
{
|
||||
"filenamePattern": "*.ipynb"
|
||||
}
|
||||
],
|
||||
"priority": "default"
|
||||
}
|
||||
],
|
||||
"notebookRenderer": [
|
||||
{
|
||||
"id": "vscode.markdown-it-cell-attachment-renderer",
|
||||
"displayName": "%markdownAttachmentRenderer.displayName%",
|
||||
"entrypoint": {
|
||||
"extends": "vscode.markdown-it-renderer",
|
||||
"path": "./notebook-out/cellAttachmentRenderer.js"
|
||||
}
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"file/newFile": [
|
||||
{
|
||||
"command": "ipynb.newUntitledIpynb",
|
||||
"group": "notebook"
|
||||
}
|
||||
],
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "ipynb.newUntitledIpynb"
|
||||
},
|
||||
{
|
||||
"command": "ipynb.openIpynbInNotebookEditor",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "ipynb.cleanInvalidImageAttachment",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"webview/context": [
|
||||
{
|
||||
"command": "notebook.cellOutput.copyToClipboard",
|
||||
"when": "webviewId == 'notebook.output' && webviewSection == 'image'"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "npx gulp compile-extension:ipynb && npm run build-notebook",
|
||||
"watch": "npx gulp watch-extension:ipynb",
|
||||
"build-notebook": "node ./esbuild"
|
||||
},
|
||||
"dependencies": {
|
||||
"@enonic/fnv-plus": "^1.3.0",
|
||||
"detect-indent": "^6.0.0",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jupyterlab/nbformat": "^3.2.9",
|
||||
"@types/markdown-it": "12.2.3",
|
||||
"@types/uuid": "^8.3.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/vscode.git"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"newUntitledIpynb.shortTitle": "Jupyter Notebook",
|
||||
"openIpynbInNotebookEditor.title": "Open IPYNB File In Notebook Editor",
|
||||
"cleanInvalidImageAttachment.title": "Clean Invalid Image Attachment Reference",
|
||||
"copyOutputToClipboard.title": "Copy Output to Clipboard",
|
||||
"markdownAttachmentRenderer.displayName": {
|
||||
"message": "Markdown-It ipynb Cell Attachment renderer",
|
||||
"comment": [
|
||||
|
|
|
@ -37,6 +37,7 @@ function renderImage(outputInfo: OutputItem, element: HTMLElement): IDisposable
|
|||
if (alt) {
|
||||
image.alt = alt;
|
||||
}
|
||||
image.setAttribute('data-vscode-context', JSON.stringify({ webviewSection: 'image', outputId: outputInfo.id, 'preventDefaultContextMenuItems': true }));
|
||||
const display = document.createElement('div');
|
||||
display.classList.add('display');
|
||||
display.appendChild(image);
|
||||
|
|
|
@ -5,39 +5,51 @@
|
|||
|
||||
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { INotebookOutputActionContext, NotebookAction } from 'vs/workbench/contrib/notebook/browser/controller/coreActions';
|
||||
import { INotebookOutputActionContext, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/controller/coreActions';
|
||||
import { NOTEBOOK_CELL_HAS_OUTPUTS } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
|
||||
import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { copyCellOutput } from 'vs/workbench/contrib/notebook/browser/contrib/clipboard/cellOutputClipboard';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { ICellOutputViewModel, ICellViewModel, INotebookEditor, getNotebookEditorFromEditorPane } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
|
||||
export const COPY_OUTPUT_COMMAND_ID = 'notebook.cellOutput.copyToClipboard';
|
||||
|
||||
registerAction2(class CopyCellOutputAction extends NotebookAction {
|
||||
registerAction2(class CopyCellOutputAction extends Action2 {
|
||||
constructor() {
|
||||
super(
|
||||
{
|
||||
id: COPY_OUTPUT_COMMAND_ID,
|
||||
title: localize('notebookActions.copyOutput', "Copy Output to Clipboard"),
|
||||
menu: {
|
||||
id: MenuId.NotebookOutputToolbar,
|
||||
when: NOTEBOOK_CELL_HAS_OUTPUTS
|
||||
},
|
||||
icon: icons.copyIcon,
|
||||
});
|
||||
super({
|
||||
id: COPY_OUTPUT_COMMAND_ID,
|
||||
title: localize('notebookActions.copyOutput', "Copy Output to Clipboard"),
|
||||
menu: {
|
||||
id: MenuId.NotebookOutputToolbar,
|
||||
when: NOTEBOOK_CELL_HAS_OUTPUTS
|
||||
},
|
||||
category: NOTEBOOK_ACTIONS_CATEGORY,
|
||||
icon: icons.copyIcon,
|
||||
});
|
||||
}
|
||||
|
||||
async runWithContext(accessor: ServicesAccessor, context: INotebookOutputActionContext): Promise<void> {
|
||||
const outputViewModel = context.outputViewModel;
|
||||
async run(accessor: ServicesAccessor, outputContext: INotebookOutputActionContext | { outputViewModel: ICellOutputViewModel }): Promise<void> {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
let outputViewModel: ICellOutputViewModel | undefined;
|
||||
|
||||
if ('outputId' in outputContext && typeof outputContext.outputId === 'string') {
|
||||
outputViewModel = getOutputViewModelFromId(outputContext.outputId, editorService);
|
||||
} else {
|
||||
outputViewModel = outputContext.outputViewModel;
|
||||
}
|
||||
|
||||
if (!outputViewModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mimeType = outputViewModel.pickedMimeType?.mimeType;
|
||||
|
||||
if (mimeType?.startsWith('image/')) {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const editor = editorService.activeEditorPane?.getControl() as INotebookEditor;
|
||||
await editor.focusNotebookCell(outputViewModel.cellViewModel as ICellViewModel, 'output', { skipReveal: true, outputId: outputViewModel.model.outputId });
|
||||
editor.copyOutputImage(outputViewModel);
|
||||
|
@ -48,4 +60,20 @@ registerAction2(class CopyCellOutputAction extends NotebookAction {
|
|||
copyCellOutput(mimeType, outputViewModel, clipboardService, logService);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function getOutputViewModelFromId(outputId: string, editorService: IEditorService): ICellOutputViewModel | undefined {
|
||||
const notebookViewModel = getNotebookEditorFromEditorPane(editorService.activeEditorPane)?.getViewModel();
|
||||
if (notebookViewModel) {
|
||||
const codeCells = notebookViewModel.viewCells.filter(cell => cell.cellKind === CellKind.Code) as CodeCellViewModel[];
|
||||
for (const cell of codeCells) {
|
||||
const output = cell.outputsViewModels.find(output => output.model.outputId === outputId);
|
||||
if (output) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -1074,10 +1074,12 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
|
|||
allowScripts: true,
|
||||
localResourceRoots: this.localResourceRootsCache,
|
||||
},
|
||||
extension: undefined
|
||||
extension: undefined,
|
||||
providedViewType: 'notebook.output'
|
||||
});
|
||||
|
||||
webview.setHtml(content);
|
||||
webview.setContextKeyService(this.contextKeyService);
|
||||
return webview;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user