提交 8cf97fef 编写于 作者: R rebornix

trust notebook prep

上级 d1280418
......@@ -1415,6 +1415,12 @@ declare module 'vscode' {
* The document's current run state
*/
runState?: NotebookRunState;
/**
* Whether the document is trusted, default to true
* When false, insecure outputs like HTML, JavaScript, SVG will not be rendered.
*/
trusted?: boolean;
}
export interface NotebookDocumentContentOptions {
......
......@@ -40,9 +40,8 @@ import { CancelCellAction, DeleteCellAction, ExecuteCellAction, INotebookCellAct
import { BaseCellRenderTemplate, CellEditState, CodeCellRenderTemplate, EXPAND_CELL_CONTENT_COMMAND_ID, ICellViewModel, INotebookEditor, isCodeCellRenderTemplate, MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys';
import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus';
import { CellEditorStatusBar } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets';
import { CellEditorStatusBar, CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets';
import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell';
import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/commonViewComponents';
import { CellDragAndDropController, DRAGGING_CLASS } from 'vs/workbench/contrib/notebook/browser/view/renderers/dnd';
import { StatefulMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
......
......@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { renderCodicons } from 'vs/base/browser/codicons';
import * as DOM from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { CodiconLabel } from 'vs/base/browser/ui/codicons/codiconLabel';
......@@ -13,10 +14,15 @@ import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { extUri } from 'vs/base/common/resources';
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
import { IDimension } from 'vs/editor/common/editorCommon';
import { IModeService } from 'vs/editor/common/services/modeService';
import { localize } from 'vs/nls';
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { MenuItemAction } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ChangeCellLanguageAction, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
......@@ -24,6 +30,7 @@ import { ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/b
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { CellKind, CellStatusbarAlignment, INotebookCellStatusBarEntry } from 'vs/workbench/contrib/notebook/common/notebookCommon';
const $ = DOM.$;
export interface IClickTarget {
......@@ -253,3 +260,87 @@ export class CellLanguageStatusBarItem extends Disposable {
this.labelElement.title = localize('notebook.cell.status.language', "Select Cell Language Mode");
}
}
export class CodiconActionViewItem extends MenuEntryActionViewItem {
constructor(
readonly _action: MenuItemAction,
keybindingService: IKeybindingService,
notificationService: INotificationService,
) {
super(_action, keybindingService, notificationService);
}
updateLabel(): void {
if (this.options.label && this.label) {
DOM.reset(this.label, ...renderCodicons(this._commandAction.label ?? ''));
}
}
}
declare const ResizeObserver: any;
export interface IResizeObserver {
startObserving: () => void;
stopObserving: () => void;
getWidth(): number;
getHeight(): number;
dispose(): void;
}
export class BrowserResizeObserver extends Disposable implements IResizeObserver {
private readonly referenceDomElement: HTMLElement | null;
private readonly observer: any;
private width: number;
private height: number;
constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) {
super();
this.referenceDomElement = referenceDomElement;
this.width = -1;
this.height = -1;
this.observer = new ResizeObserver((entries: any) => {
for (const entry of entries) {
if (entry.target === referenceDomElement && entry.contentRect) {
if (this.width !== entry.contentRect.width || this.height !== entry.contentRect.height) {
this.width = entry.contentRect.width;
this.height = entry.contentRect.height;
DOM.scheduleAtNextAnimationFrame(() => {
changeCallback();
});
}
}
}
});
}
getWidth(): number {
return this.width;
}
getHeight(): number {
return this.height;
}
startObserving(): void {
this.observer.observe(this.referenceDomElement!);
}
stopObserving(): void {
this.observer.unobserve(this.referenceDomElement!);
}
dispose(): void {
this.observer.disconnect();
super.dispose();
}
}
export function getResizesObserver(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void): IResizeObserver {
if (ResizeObserver) {
return new BrowserResizeObserver(referenceDomElement, dimension, changeCallback);
} else {
return new ElementSizeObserver(referenceDomElement, dimension, changeCallback);
}
}
......@@ -21,12 +21,11 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { EDITOR_BOTTOM_PADDING, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
import { CellFocusMode, CodeCellRenderTemplate, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/sizeObserver';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { BUILTIN_RENDERER_ID, CellOutputKind, CellUri, IInsetRenderOutput, IProcessedOutput, IRenderOutput, ITransformedDisplayOutputDto, outputHasDynamicHeight, RENDERER_NOT_AVAILABLE, RenderOutputType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { BUILTIN_RENDERER_ID, CellOutputKind, CellUri, IInsetRenderOutput, IProcessedOutput, IRenderOutput, ITransformedDisplayOutputDto, NotebookCellOutputsSplice, outputHasDynamicHeight, RENDERER_NOT_AVAILABLE, RenderOutputType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { ClickTargetType } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets';
import { ClickTargetType, getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets';
const OUTPUT_COUNT_LIMIT = 500;
interface IMimeTypeRenderer extends IQuickPickItem {
......@@ -365,76 +364,6 @@ export class CodeCell extends Disposable {
}
}));
this._register(viewCell.onDidChangeOutputs((splices) => {
if (!splices.length) {
return;
}
const previousOutputHeight = this.viewCell.layoutInfo.outputTotalHeight;
if (this.viewCell.outputs.length) {
this.templateData.outputContainer!.style.display = 'block';
} else {
this.templateData.outputContainer!.style.display = 'none';
}
const reversedSplices = splices.reverse();
reversedSplices.forEach(splice => {
viewCell.spliceOutputHeights(splice[0], splice[1], splice[2].map(_ => 0));
});
const removedKeys: IProcessedOutput[] = [];
this.outputEntries.forEach((value, key) => {
if (viewCell.outputs.indexOf(key) < 0) {
// already removed
removedKeys.push(key);
// remove element from DOM
this.templateData?.outputContainer?.removeChild(value.domNode);
this.notebookEditor.removeInset(key);
}
});
removedKeys.forEach(key => {
this.outputEntries.get(key)?.dispose();
this.outputEntries.delete(key);
});
let prevElement: HTMLElement | undefined = undefined;
const outputsToRender = this.viewCell.outputs.slice(0, Math.min(OUTPUT_COUNT_LIMIT, this.viewCell.outputs.length));
outputsToRender.reverse().forEach(output => {
if (this.outputEntries.has(output)) {
// already exist
prevElement = this.outputEntries.get(output)!.domNode;
return;
}
// newly added element
const currIndex = this.viewCell.outputs.indexOf(output);
this.renderOutput(output, currIndex, prevElement);
prevElement = this.outputEntries.get(output)?.domNode;
});
if (this.viewCell.outputs.length > OUTPUT_COUNT_LIMIT) {
this.templateData.outputShowMoreContainer.style.display = 'block';
this.viewCell.updateOutputShowMoreContainerHeight(46);
} else {
this.templateData.outputShowMoreContainer.style.display = 'none';
}
const editorHeight = templateData.editor!.getContentHeight();
viewCell.editorHeight = editorHeight;
if (previousOutputHeight === 0 || this.viewCell.outputs.length === 0) {
// first execution or removing all outputs
this.relayoutCell();
} else {
this.relayoutCellDebounced();
}
}));
this._register(viewCell.onDidChangeLayout(() => {
this.outputEntries.forEach((value, key) => {
const index = viewCell.outputs.indexOf(key);
......@@ -446,6 +375,7 @@ export class CodeCell extends Disposable {
}));
// Apply decorations
this._register(viewCell.onCellDecorationsChanged((e) => {
e.added.forEach(options => {
if (options.className) {
......@@ -467,7 +397,6 @@ export class CodeCell extends Disposable {
}
});
}));
// apply decorations
viewCell.getCellDecorations().forEach(options => {
if (options.className) {
......@@ -479,6 +408,7 @@ export class CodeCell extends Disposable {
}
});
// Mouse click handlers
this._register(templateData.statusBar.onDidClick(e => {
if (e.type !== ClickTargetType.ContributedItem) {
const target = templateData.editor.getTargetAtClientPoint(e.event.clientX, e.event.clientY - viewCell.getEditorStatusbarHeight());
......@@ -497,11 +427,11 @@ export class CodeCell extends Disposable {
}
}));
// Focus Mode
const updateFocusMode = () => viewCell.focusMode = templateData.editor!.hasWidgetFocus() ? CellFocusMode.Editor : CellFocusMode.Container;
this._register(templateData.editor!.onDidFocusEditorWidget(() => {
updateFocusMode();
}));
this._register(templateData.editor!.onDidBlurEditorWidget(() => {
// this is for a special case:
// users click the status bar empty space, which we will then focus the editor
......@@ -514,10 +444,19 @@ export class CodeCell extends Disposable {
updateFocusMode();
}
}));
updateFocusMode();
if (viewCell.outputs.length > 0) {
// Render Outputs
this.renderOutputs(editorHeight);
this._register(viewCell.onDidChangeOutputs((splices) => {
this.updateOutputs(splices);
}));
// Need to do this after the intial renderOutput
updateForCollapseState();
}
renderOutputs(editorHeight: number) {
if (this.viewCell.outputs.length > 0) {
let layoutCache = false;
if (this.viewCell.layoutInfo.totalHeight !== 0 && this.viewCell.layoutInfo.editorHeight > editorHeight) {
layoutCache = true;
......@@ -535,7 +474,7 @@ export class CodeCell extends Disposable {
this.renderOutput(currOutput, index, undefined);
}
viewCell.editorHeight = editorHeight;
this.viewCell.editorHeight = editorHeight;
if (this.viewCell.outputs.length > OUTPUT_COUNT_LIMIT) {
this.templateData.outputShowMoreContainer.style.display = 'block';
this.viewCell.updateOutputShowMoreContainerHeight(46);
......@@ -548,7 +487,7 @@ export class CodeCell extends Disposable {
}
} else {
// noop
viewCell.editorHeight = editorHeight;
this.viewCell.editorHeight = editorHeight;
this.relayoutCell();
this.templateData.outputContainer!.style.display = 'none';
}
......@@ -561,9 +500,76 @@ export class CodeCell extends Disposable {
this.templateData.outputShowMoreContainer.style.display = 'none';
this.viewCell.updateOutputShowMoreContainerHeight(0);
}
}
// Need to do this after the intial renderOutput
updateForCollapseState();
updateOutputs(splices: NotebookCellOutputsSplice[]) {
if (!splices.length) {
return;
}
const previousOutputHeight = this.viewCell.layoutInfo.outputTotalHeight;
if (this.viewCell.outputs.length) {
this.templateData.outputContainer!.style.display = 'block';
} else {
this.templateData.outputContainer!.style.display = 'none';
}
const reversedSplices = splices.reverse();
reversedSplices.forEach(splice => {
this.viewCell.spliceOutputHeights(splice[0], splice[1], splice[2].map(_ => 0));
});
const removedKeys: IProcessedOutput[] = [];
this.outputEntries.forEach((value, key) => {
if (this.viewCell.outputs.indexOf(key) < 0) {
// already removed
removedKeys.push(key);
// remove element from DOM
this.templateData?.outputContainer?.removeChild(value.domNode);
this.notebookEditor.removeInset(key);
}
});
removedKeys.forEach(key => {
this.outputEntries.get(key)?.dispose();
this.outputEntries.delete(key);
});
let prevElement: HTMLElement | undefined = undefined;
const outputsToRender = this.viewCell.outputs.slice(0, Math.min(OUTPUT_COUNT_LIMIT, this.viewCell.outputs.length));
outputsToRender.reverse().forEach(output => {
if (this.outputEntries.has(output)) {
// already exist
prevElement = this.outputEntries.get(output)!.domNode;
return;
}
// newly added element
const currIndex = this.viewCell.outputs.indexOf(output);
this.renderOutput(output, currIndex, prevElement);
prevElement = this.outputEntries.get(output)?.domNode;
});
if (this.viewCell.outputs.length > OUTPUT_COUNT_LIMIT) {
this.templateData.outputShowMoreContainer.style.display = 'block';
this.viewCell.updateOutputShowMoreContainerHeight(46);
} else {
this.templateData.outputShowMoreContainer.style.display = 'none';
}
const editorHeight = this.templateData.editor!.getContentHeight();
this.viewCell.editorHeight = editorHeight;
if (previousOutputHeight === 0 || this.viewCell.outputs.length === 0) {
// first execution or removing all outputs
this.relayoutCell();
} else {
this.relayoutCellDebounced();
}
}
generateShowMoreElement(): any {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as DOM from 'vs/base/browser/dom';
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { MenuItemAction } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { renderCodicons } from 'vs/base/browser/codicons';
export class CodiconActionViewItem extends MenuEntryActionViewItem {
constructor(
readonly _action: MenuItemAction,
keybindingService: IKeybindingService,
notificationService: INotificationService,
) {
super(_action, keybindingService, notificationService);
}
updateLabel(): void {
if (this.options.label && this.label) {
DOM.reset(this.label, ...renderCodicons(this._commandAction.label ?? ''));
}
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as DOM from 'vs/base/browser/dom';
import { Disposable } from 'vs/base/common/lifecycle';
import { IDimension } from 'vs/editor/common/editorCommon';
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
declare const ResizeObserver: any;
export interface IResizeObserver {
startObserving: () => void;
stopObserving: () => void;
getWidth(): number;
getHeight(): number;
dispose(): void;
}
export class BrowserResizeObserver extends Disposable implements IResizeObserver {
private readonly referenceDomElement: HTMLElement | null;
private readonly observer: any;
private width: number;
private height: number;
constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) {
super();
this.referenceDomElement = referenceDomElement;
this.width = -1;
this.height = -1;
this.observer = new ResizeObserver((entries: any) => {
for (const entry of entries) {
if (entry.target === referenceDomElement && entry.contentRect) {
if (this.width !== entry.contentRect.width || this.height !== entry.contentRect.height) {
this.width = entry.contentRect.width;
this.height = entry.contentRect.height;
DOM.scheduleAtNextAnimationFrame(() => {
changeCallback();
});
}
}
}
});
}
getWidth(): number {
return this.width;
}
getHeight(): number {
return this.height;
}
startObserving(): void {
this.observer.observe(this.referenceDomElement!);
}
stopObserving(): void {
this.observer.unobserve(this.referenceDomElement!);
}
dispose(): void {
this.observer.disconnect();
super.dispose();
}
}
export function getResizesObserver(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void): IResizeObserver {
if (ResizeObserver) {
return new BrowserResizeObserver(referenceDomElement, dimension, changeCallback);
} else {
return new ElementSizeObserver(referenceDomElement, dimension, changeCallback);
}
}
......@@ -73,7 +73,8 @@ export const notebookDocumentMetadataDefaults: Required<NotebookDocumentMetadata
cellHasExecutionOrder: true,
displayOrder: NOTEBOOK_DISPLAY_ORDER,
custom: {},
runState: NotebookRunState.Idle
runState: NotebookRunState.Idle,
trusted: true
};
export interface NotebookDocumentMetadata {
......@@ -85,6 +86,7 @@ export interface NotebookDocumentMetadata {
displayOrder?: (string | glob.IRelativePattern)[];
custom?: { [key: string]: unknown };
runState?: NotebookRunState;
trusted?: boolean;
}
export enum NotebookCellRunState {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册