提交 f005bafd 编写于 作者: C Christopher Maynard

Allows focus to be moved inside notebook output.

上级 9be0faf2
......@@ -4,24 +4,24 @@
*--------------------------------------------------------------------------------------------*/
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { URI } from 'vs/base/common/uri';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { localize } from 'vs/nls';
import { Action2, IAction2Options, MenuId, MenuItemAction, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext, InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { BaseCellRenderTemplate, CellEditState, CellRunState, ICellViewModel, INotebookEditor, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_RUNNABLE, NOTEBOOK_CELL_TYPE, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_EDITABLE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
import { BaseCellRenderTemplate, CellEditState, CellRunState, ICellViewModel, INotebookEditor, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_RUNNABLE, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
import { URI } from 'vs/base/common/uri';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
// Notebook Commands
const EXECUTE_NOTEBOOK_COMMAND_ID = 'notebook.execute';
......@@ -66,6 +66,7 @@ const EXECUTE_CELL_INSERT_BELOW = 'notebook.cell.executeAndInsertBelow';
const CLEAR_CELL_OUTPUTS_COMMAND_ID = 'notebook.cell.clearOutputs';
const CHANGE_CELL_LANGUAGE = 'notebook.cell.changeLanguage';
const FOCUS_OUTPUT_COMMAND_ID = "notebook.cell.focusOutput";
export const NOTEBOOK_ACTIONS_CATEGORY = localize('notebookActions.category', "Notebook");
......@@ -1093,6 +1094,35 @@ registerAction2(class extends Action2 {
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: FOCUS_OUTPUT_COMMAND_ID,
title: localize('focusOutput', 'Focus output'),
category: NOTEBOOK_ACTIONS_CATEGORY,
keybinding: {
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.has(InputFocusedContextKey), EditorContextKeys.editorTextFocus),
primary: KeyMod.CtrlCmd | KeyCode.DownArrow,
weight: EDITOR_WIDGET_ACTION_WEIGHT
}
});
}
async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise<void> {
if (!isCellActionContext(context)) {
context = getActiveCellContext(accessor);
if (!context) {
return;
}
}
const editor = context.notebookEditor;
const activeCell = context.cell;
editor.focusNotebookCell(activeCell, false, true);
}
});
registerAction2(class extends Action2 {
constructor() {
super({
......
......@@ -15,10 +15,10 @@ import { ScrollEvent } from 'vs/base/common/scrollable';
import { URI } from 'vs/base/common/uri';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { Range } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position';
import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { Range } from 'vs/editor/common/core/range';
import { FindMatch, IReadonlyTextBuffer, ITextModel } from 'vs/editor/common/model';
import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { CellLanguageStatusBarItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
......@@ -224,7 +224,7 @@ export interface INotebookEditor {
/**
* Focus the container of a cell (the monaco editor inside is not focused).
*/
focusNotebookCell(cell: ICellViewModel, focusEditor: boolean): void;
focusNotebookCell(cell: ICellViewModel, focusEditor: boolean, focusOutput?: boolean): void;
/**
* Execute the given notebook cell
......
......@@ -3,17 +3,19 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/notebook';
import { getZoomLevel } from 'vs/base/browser/browser';
import * as DOM from 'vs/base/browser/dom';
import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { Color, RGBA } from 'vs/base/common/color';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore, MutableDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { combinedDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import 'vs/css!./media/notebook';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { ICompositeCodeEditor, IEditor } from 'vs/editor/common/editorCommon';
import * as nls from 'vs/nls';
......@@ -28,25 +30,23 @@ import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/com
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
import { EditorOptions, IEditorCloseEvent, IEditorMemento } from 'vs/workbench/common/editor';
import { CELL_MARGIN, CELL_RUN_GUTTER, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
import { CellEditState, CellFocusMode, ICellRange, ICellViewModel, INotebookCellList, INotebookEditor, INotebookEditorMouseEvent, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, INotebookEditorContribution, NOTEBOOK_EDITOR_RUNNABLE, IEditableCellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CELL_MARGIN, CELL_RUN_GUTTER, EDITOR_BOTTOM_PADDING, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
import { CellEditState, CellFocusMode, ICellRange, ICellViewModel, IEditableCellViewModel, INotebookCellList, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
import { CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate, CellDragAndDropController } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
import { CellDragAndDropController, CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellKind, CellUri, IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IPosition, Position } from 'vs/editor/common/core/position';
const $ = DOM.$;
const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState';
......@@ -1116,7 +1116,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
}
focusNotebookCell(cell: ICellViewModel, focusEditor: boolean) {
focusNotebookCell(cell: ICellViewModel, focusEditor: boolean, focusOuput?: boolean) {
if (focusEditor) {
this.selectElement(cell);
this.list?.focusView();
......@@ -1124,6 +1124,18 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
cell.editState = CellEditState.Editing;
cell.focusMode = CellFocusMode.Editor;
this.revealInCenterIfOutsideViewport(cell);
} else if (focusOuput) {
this.selectElement(cell);
this.list?.focusView();
if (!this.webview) {
return;
}
this.webview.focusOutput(cell.id);
cell.editState = CellEditState.Preview;
cell.focusMode = CellFocusMode.Container;
this.revealInCenterIfOutsideViewport(cell);
} else {
let itemDOM = this.list?.domElementOfElement(cell);
if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) {
......
......@@ -4,22 +4,22 @@
*--------------------------------------------------------------------------------------------*/
import * as DOM from 'vs/base/browser/dom';
import { getPathFromAmdModule } from 'vs/base/common/amd';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import * as path from 'vs/base/common/path';
import { isWeb } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import * as UUID from 'vs/base/common/uuid';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { CELL_MARGIN, CELL_RUN_GUTTER } from 'vs/workbench/contrib/notebook/browser/constants';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/resourceLoader';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { CELL_MARGIN, CELL_RUN_GUTTER } from 'vs/workbench/contrib/notebook/browser/constants';
import { Emitter, Event } from 'vs/base/common/event';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { getPathFromAmdModule } from 'vs/base/common/amd';
import { isWeb } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
export interface IDimensionMessage {
__vscode_notebook_message: boolean;
......@@ -54,10 +54,22 @@ export interface IScrollAckMessage {
version: number;
}
export interface IBlurOutputMessage {
__vscode_notebook_message: boolean;
type: 'focus-editor';
id: string;
focusNext?: boolean;
}
export interface IClearMessage {
type: 'clear';
}
export interface IFocusOutputMessage {
type: 'focus-output';
id: string;
}
export interface ICreationRequestMessage {
type: 'html';
content: string;
......@@ -93,7 +105,7 @@ export interface IUpdatePreloadResourceMessage {
resources: string[];
}
type IMessage = IDimensionMessage | IScrollAckMessage | IWheelMessage | IMouseEnterMessage | IMouseLeaveMessage;
type IMessage = IDimensionMessage | IScrollAckMessage | IWheelMessage | IMouseEnterMessage | IMouseLeaveMessage | IBlurOutputMessage;
let version = 0;
export class BackLayerWebView extends Disposable {
......@@ -108,6 +120,7 @@ export class BackLayerWebView extends Disposable {
private readonly _onMessage = this._register(new Emitter<any>());
public readonly onMessage: Event<any> = this._onMessage.event;
private _initalized: Promise<void>;
private activeCellId: string | undefined;
constructor(
......@@ -288,10 +301,23 @@ ${loaderJs}
let cellOutputContainer = document.getElementById(id);
let outputId = event.data.outputId;
if (!cellOutputContainer) {
const container = document.getElementById('container');
let upperWrapperElement = document.createElement('div');
upperWrapperElement.tabIndex = 0;
container.appendChild(upperWrapperElement);
upperWrapperElement.addEventListener('focus', () => {
vscode.postMessage({
__vscode_notebook_message: true,
type: 'focus-editor',
id: outputId,
});
});
let newElement = document.createElement('div');
newElement.id = id;
document.getElementById('container').appendChild(newElement);
container.appendChild(newElement);
cellOutputContainer = newElement;
cellOutputContainer.addEventListener('mouseenter', () => {
......@@ -310,6 +336,32 @@ ${loaderJs}
data: { }
});
});
const handleKeyDown = (event) => {
if (event.defaultPrevented || !(event.key === 'ArrowUp' && event.ctrlKey)) {
return;
}
vscode.postMessage({
__vscode_notebook_message: true,
type: 'focus-editor',
id: outputId,
});
};
cellOutputContainer.addEventListener("keydown", handleKeyDown);
let lowerWrapperElement = document.createElement('div');
lowerWrapperElement.tabIndex = 0;
container.appendChild(lowerWrapperElement);
lowerWrapperElement.addEventListener('focus', () => {
vscode.postMessage({
__vscode_notebook_message: true,
type: 'focus-editor',
id: outputId,
focusNext: true
});
});
}
let outputNode = document.createElement('div');
......@@ -384,6 +436,15 @@ ${loaderJs}
preloadsContainer.appendChild(scriptTag)
}
break;
case 'focus-output':
{
let cellOutputContainer = document.getElementById(id);
if(cellOutputContainer){
const focusableElement = cellOutputContainer.querySelector('[tabindex="0"], [href], button, input, option, select, textarea');
focusableElement && focusableElement.focus();
}
break;
}
}
});
}());
......@@ -405,6 +466,14 @@ ${loaderJs}
initialize(content: string) {
this.webview = this._createInset(this.webviewService, content);
this.webview.mountTo(this.element);
this.webview.onDidFocus(() => {
if (this.activeCellId) {
this.webview.sendMessage({
type: 'focus-output',
id: this.activeCellId
});
}
});
this._register(this.webview.onDidClickLink(link => {
this.openerService.open(link, { fromUserGesture: true });
......@@ -445,6 +514,25 @@ ${loaderJs}
preventDefault: () => { },
stopPropagation: () => { }
});
} else if (data.type === 'focus-editor') {
const info = this.resolveOutputId(data.id);
if (info) {
if (data.focusNext) {
const idx = this.notebookEditor.viewModel?.getCellIndex(info.cell);
if (typeof idx !== 'number') {
return;
}
const newCell = this.notebookEditor.viewModel?.viewCells[idx + 1];
if (!newCell) {
return;
}
this.notebookEditor.focusNotebookCell(newCell, true);
} else {
this.notebookEditor.focusNotebookCell(info.cell, true);
}
}
}
return;
}
......@@ -589,6 +677,11 @@ ${loaderJs}
this.reversedInsetMapping = new Map();
}
focusOutput(cellId: string) {
this.activeCellId = cellId;
this.webview.focus();
}
updateRendererPreloads(preloads: Set<number>) {
let resources: string[] = [];
let extensionLocations: URI[] = [];
......
......@@ -3,24 +3,24 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { CellKind, IOutput, CellUri, NotebookCellMetadata, INotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookViewModel, IModelDecorationsChangeAccessor, CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { INotebookEditor, NotebookLayoutInfo, ICellViewModel, ICellRange, INotebookEditorMouseEvent, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { Range } from 'vs/editor/common/core/range';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { EditorModel } from 'vs/workbench/common/editor';
import { ICellRange, ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CellKind, CellUri, INotebookEditorModel, IOutput, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { EditorModel } from 'vs/workbench/common/editor';
export class TestCell extends NotebookCellTextModel {
constructor(
public viewType: string,
......@@ -171,7 +171,7 @@ export class TestNotebookEditor implements INotebookEditor {
saveNotebookCell(cell: CellViewModel): void {
// throw new Error('Method not implemented.');
}
focusNotebookCell(cell: CellViewModel, focusEditor: boolean): void {
focusNotebookCell(cell: CellViewModel, focusEditor: boolean, focusOutput?: boolean): void {
// throw new Error('Method not implemented.');
}
getActiveCell(): CellViewModel | undefined {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册