Allow commands in empty cells

Fix #102156
This commit is contained in:
Rob Lourens
2020-07-15 20:19:07 -07:00
parent 8ab815db54
commit 39af33aabe
2 changed files with 81 additions and 66 deletions
@@ -86,6 +86,17 @@ const enum CellToolbarOrder {
DeleteCell
}
export interface INotebookActionContext {
readonly cellTemplate?: BaseCellRenderTemplate;
readonly cell?: ICellViewModel;
readonly notebookEditor: INotebookEditor;
readonly ui?: boolean;
}
export interface INotebookCellActionContext extends INotebookActionContext {
cell: ICellViewModel;
}
abstract class NotebookAction extends Action2 {
constructor(desc: IAction2Options) {
if (desc.f1 !== false) {
@@ -112,9 +123,9 @@ abstract class NotebookAction extends Action2 {
super(desc);
}
async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise<void> {
if (!this.isCellActionContext(context)) {
context = this.getActiveCellContext(accessor);
async run(accessor: ServicesAccessor, context?: INotebookActionContext): Promise<void> {
if (!this.isNotebookActionContext(context)) {
context = this.getActiveEditorContext(accessor);
if (!context) {
return;
}
@@ -123,13 +134,13 @@ abstract class NotebookAction extends Action2 {
this.runWithContext(accessor, context);
}
abstract async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void>;
abstract async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void>;
private isCellActionContext(context?: INotebookCellActionContext): context is INotebookCellActionContext {
return !!context && !!context.cell && !!context.notebookEditor;
private isNotebookActionContext(context?: unknown): context is INotebookActionContext {
return !!context && !!(context as INotebookActionContext).notebookEditor;
}
private getActiveCellContext(accessor: ServicesAccessor): INotebookCellActionContext | undefined {
protected getActiveEditorContext(accessor: ServicesAccessor): INotebookActionContext | undefined {
const editorService = accessor.get(IEditorService);
const editor = getActiveNotebookEditor(editorService);
@@ -138,10 +149,6 @@ abstract class NotebookAction extends Action2 {
}
const activeCell = editor.getActiveCell();
if (!activeCell) {
return;
}
return {
cell: activeCell,
notebookEditor: editor
@@ -149,7 +156,28 @@ abstract class NotebookAction extends Action2 {
}
}
registerAction2(class extends NotebookAction {
abstract class NotebookCellAction extends NotebookAction {
protected isCellActionContext(context?: unknown): context is INotebookCellActionContext {
return !!context && !!(context as INotebookCellActionContext).notebookEditor && !!(context as INotebookCellActionContext).cell;
}
async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise<void> {
if (!this.isCellActionContext(context)) {
const activeEditorContext = this.getActiveEditorContext(accessor);
if (this.isCellActionContext(activeEditorContext)) {
context = activeEditorContext;
} else {
return;
}
}
this.runWithContext(accessor, context);
}
abstract async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void>;
}
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: EXECUTE_CELL_COMMAND_ID,
@@ -171,7 +199,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: CANCEL_CELL_COMMAND_ID,
@@ -222,7 +250,7 @@ export class CancelCellAction extends MenuItemAction {
}
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: EXECUTE_CELL_SELECT_BELOW,
@@ -258,7 +286,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: EXECUTE_CELL_INSERT_BELOW,
@@ -292,7 +320,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
renderAllMarkdownCells(context);
}
});
@@ -305,7 +333,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
renderAllMarkdownCells(context);
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -321,7 +349,7 @@ registerAction2(class extends NotebookAction {
}
});
function renderAllMarkdownCells(context: INotebookCellActionContext): void {
function renderAllMarkdownCells(context: INotebookActionContext): void {
context.notebookEditor.viewModel!.viewCells.forEach(cell => {
if (cell.cellKind === CellKind.Markdown) {
cell.editState = CellEditState.Preview;
@@ -337,7 +365,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
return context.notebookEditor.cancelNotebookExecution();
}
});
@@ -364,7 +392,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
when: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK)
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: CHANGE_CELL_TO_CODE_COMMAND_ID,
@@ -383,7 +411,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: CHANGE_CELL_TO_MARKDOWN_COMMAND_ID,
@@ -456,13 +484,6 @@ export async function changeCellToKind(kind: CellKind, context: INotebookCellAct
return newCell;
}
export interface INotebookCellActionContext {
readonly cellTemplate?: BaseCellRenderTemplate;
readonly cell: ICellViewModel;
readonly notebookEditor: INotebookEditor;
readonly ui?: boolean;
}
abstract class InsertCellCommand extends NotebookAction {
constructor(
desc: Readonly<IAction2Options>,
@@ -472,7 +493,7 @@ abstract class InsertCellCommand extends NotebookAction {
super(desc);
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
const newCell = context.notebookEditor.insertNotebookCell(context.cell, this.kind, this.direction, undefined, context.ui);
if (newCell) {
context.notebookEditor.focusNotebookCell(newCell, 'editor');
@@ -558,7 +579,7 @@ MenuRegistry.appendMenuItem(MenuId.NotebookCellBetween, {
group: 'inline'
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -587,7 +608,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -624,7 +645,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -657,12 +678,6 @@ registerAction2(class extends NotebookAction {
const nextCellIdx = index < context.notebookEditor.viewModel!.length ? index : context.notebookEditor.viewModel!.length - 1;
if (nextCellIdx >= 0) {
context.notebookEditor.focusNotebookCell(context.notebookEditor.viewModel!.viewCells[nextCellIdx], 'container');
} else {
// No cells left, insert a new empty one
const newCell = context.notebookEditor.insertNotebookCell(undefined, context.cell.cellKind);
if (newCell) {
context.notebookEditor.focusNotebookCell(newCell, 'editor');
}
}
}
}
@@ -688,7 +703,7 @@ async function copyCell(context: INotebookCellActionContext, direction: 'up' | '
}
}
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -708,7 +723,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -728,7 +743,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -750,7 +765,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -779,7 +794,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -848,7 +863,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext) {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext) {
const notebookService = accessor.get<INotebookService>(INotebookService);
const pasteCells = notebookService.getToCopy();
@@ -862,7 +877,7 @@ registerAction2(class extends NotebookAction {
return;
}
const currCellIndex = viewModel.getCellIndex(context!.cell);
const currCellIndex = context.cell && viewModel.getCellIndex(context.cell);
let topPastedCell: CellViewModel | undefined = undefined;
pasteCells.items.reverse().map(cell => {
@@ -880,8 +895,8 @@ registerAction2(class extends NotebookAction {
return cell;
}
}).forEach(pasteCell => {
topPastedCell = viewModel.insertCell(currCellIndex + 1, pasteCell, true);
return;
const newIdx = typeof currCellIndex === 'number' ? currCellIndex + 1 : 0;
topPastedCell = viewModel.insertCell(newIdx, pasteCell, true);
});
if (topPastedCell) {
@@ -890,7 +905,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -909,7 +924,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -928,7 +943,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: NOTEBOOK_FOCUS_NEXT_EDITOR,
@@ -975,7 +990,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: NOTEBOOK_FOCUS_PREVIOUS_EDITOR,
@@ -1019,7 +1034,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: FOCUS_IN_OUTPUT_COMMAND_ID,
@@ -1040,7 +1055,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: FOCUS_OUT_OUTPUT_COMMAND_ID,
@@ -1075,7 +1090,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
await context.notebookEditor.viewModel?.undo();
}
});
@@ -1093,7 +1108,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
await context.notebookEditor.viewModel?.redo();
}
});
@@ -1112,7 +1127,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
const editor = context.notebookEditor;
if (!editor.viewModel || !editor.viewModel.length) {
return;
@@ -1137,7 +1152,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
const editor = context.notebookEditor;
if (!editor.viewModel || !editor.viewModel.length) {
return;
@@ -1148,7 +1163,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: CLEAR_CELL_OUTPUTS_COMMAND_ID,
@@ -1183,7 +1198,7 @@ interface ILanguagePickInput extends IQuickPickItem {
description: string;
}
export class ChangeCellLanguageAction extends NotebookAction {
export class ChangeCellLanguageAction extends NotebookCellAction {
constructor() {
super({
id: CHANGE_CELL_LANGUAGE,
@@ -1293,7 +1308,7 @@ registerAction2(class extends NotebookAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
const editor = context.notebookEditor;
if (!editor.viewModel || !editor.viewModel.length) {
return;
@@ -1312,7 +1327,7 @@ async function splitCell(context: INotebookCellActionContext): Promise<void> {
}
}
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -1346,7 +1361,7 @@ async function joinCells(context: INotebookCellActionContext, direction: 'above'
}
}
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -1365,7 +1380,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super(
{
@@ -1384,7 +1399,7 @@ registerAction2(class extends NotebookAction {
}
});
registerAction2(class extends NotebookAction {
registerAction2(class extends NotebookCellAction {
constructor() {
super({
id: CENTER_ACTIVE_CELL,
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
import { INotebookCellActionContext, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
import { INotebookActionContext, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
import { INotebookEditor, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -31,7 +31,7 @@ registerAction2(class extends Action2 {
});
}
async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise<void> {
async run(accessor: ServicesAccessor, context?: INotebookActionContext): Promise<void> {
const editorService = accessor.get<IEditorService>(IEditorService);
const notebookService = accessor.get<INotebookService>(INotebookService);
const quickInputService = accessor.get<IQuickInputService>(IQuickInputService);