Skip to content

Commit

Permalink
fixed notebook document metadata edit and added execute cells above/b…
Browse files Browse the repository at this point in the history
…elow commands (#13528)

* notebook workspace edits, document and cell metadata edits

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>

* fixed metadata edit and added  execute above/below commands

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>

* removed notebook debug functionality because its not yet supported

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>

* fixed cell and below start index

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>

---------

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>
  • Loading branch information
jonah-iden committed Mar 28, 2024
1 parent a828e58 commit 02acd2e
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ export namespace NotebookCellCommands {
export const EXECUTE_SINGLE_CELL_AND_FOCUS_NEXT_COMMAND = Command.toDefaultLocalizedCommand({
id: 'notebook.cell.execute-cell-and-focus-next',
});

export const EXECUTE_ABOVE_CELLS_COMMAND = Command.toDefaultLocalizedCommand({
id: 'notebookActions.executeAbove',
label: 'Execute Above Cells',
iconClass: codicon('run-above')
});

export const EXECUTE_CELL_AND_BELOW_COMMAND = Command.toDefaultLocalizedCommand({
id: 'notebookActions.executeBelow',
label: 'Execute Cell and Below',
iconClass: codicon('run-below')
});
/** Parameters: notebookModel: NotebookModel, cell: NotebookCellModel */
export const STOP_CELL_EXECUTION_COMMAND = Command.toDefaultLocalizedCommand({
id: 'notebook.cell.stop-cell-execution',
Expand Down Expand Up @@ -140,20 +152,30 @@ export class NotebookCellActionContribution implements MenuContribution, Command
label: nls.localizeByDefault('Stop Editing Cell'),
order: '10'
});

menus.registerMenuAction(NotebookCellActionContribution.ACTION_MENU, {
commandId: NotebookCellCommands.EXECUTE_SINGLE_CELL_COMMAND.id,
icon: NotebookCellCommands.EXECUTE_SINGLE_CELL_COMMAND.iconClass,
commandId: NotebookCellCommands.EXECUTE_ABOVE_CELLS_COMMAND.id,
icon: NotebookCellCommands.EXECUTE_ABOVE_CELLS_COMMAND.iconClass,
when: `${NOTEBOOK_CELL_TYPE} == 'code'`,
label: nls.localizeByDefault('Execute Cell'),
label: nls.localizeByDefault('Execute Above Cells'),
order: '10'
});

menus.registerMenuAction(NotebookCellActionContribution.ACTION_MENU, {
commandId: NotebookCellCommands.SPLIT_CELL_COMMAND.id,
icon: NotebookCellCommands.SPLIT_CELL_COMMAND.iconClass,
label: nls.localizeByDefault('Split Cell'),
commandId: NotebookCellCommands.EXECUTE_CELL_AND_BELOW_COMMAND.id,
icon: NotebookCellCommands.EXECUTE_CELL_AND_BELOW_COMMAND.iconClass,
when: `${NOTEBOOK_CELL_TYPE} == 'code'`,
label: nls.localizeByDefault('Execute Cell and Below'),
order: '20'
});

// menus.registerMenuAction(NotebookCellActionContribution.ACTION_MENU, {
// commandId: NotebookCellCommands.SPLIT_CELL_COMMAND.id,
// icon: NotebookCellCommands.SPLIT_CELL_COMMAND.iconClass,
// label: nls.localizeByDefault('Split Cell'),
// order: '20'
// });

menus.registerMenuAction(NotebookCellActionContribution.ACTION_MENU, {
commandId: NotebookCellCommands.DELETE_COMMAND.id,
icon: NotebookCellCommands.DELETE_COMMAND.iconClass,
Expand Down Expand Up @@ -190,9 +212,9 @@ export class NotebookCellActionContribution implements MenuContribution, Command
});

// Notebook Cell extra execution options
// menus.registerIndependentSubmenu(NotebookCellActionContribution.CONTRIBUTED_CELL_EXECUTION_MENU,
// nls.localizeByDefault('More...'),
// { role: CompoundMenuNodeRole.Flat, icon: codicon('chevron-down') });
menus.registerIndependentSubmenu(NotebookCellActionContribution.CONTRIBUTED_CELL_EXECUTION_MENU,
nls.localizeByDefault('More...'),
{ role: CompoundMenuNodeRole.Flat, icon: codicon('chevron-down') });
// menus.getMenu(NotebookCellActionContribution.CODE_CELL_SIDEBAR_MENU).addNode(menus.getMenuNode(NotebookCellActionContribution.CONTRIBUTED_CELL_EXECUTION_MENU));

// code cell output sidebar menu
Expand Down Expand Up @@ -247,6 +269,24 @@ export class NotebookCellActionContribution implements MenuContribution, Command
})
);

commands.registerCommand(NotebookCellCommands.EXECUTE_ABOVE_CELLS_COMMAND, this.editableCellCommandHandler(
(notebookModel, cell) => {
const index = notebookModel.cells.indexOf(cell);
if (index > 0) {
this.notebookExecutionService.executeNotebookCells(notebookModel, notebookModel.cells.slice(0, index).filter(c => c.cellKind === CellKind.Code));
}
})
);

commands.registerCommand(NotebookCellCommands.EXECUTE_CELL_AND_BELOW_COMMAND, this.editableCellCommandHandler(
(notebookModel, cell) => {
const index = notebookModel.cells.indexOf(cell);
if (index < notebookModel.cells.length - 1) {
this.notebookExecutionService.executeNotebookCells(notebookModel, notebookModel.cells.slice(index).filter(c => c.cellKind === CellKind.Code));
}
})
);

commands.registerCommand(NotebookCellCommands.STOP_CELL_EXECUTION_COMMAND, {
execute: (notebookModel: NotebookModel, cell: NotebookCellModel) => {
notebookModel = notebookModel ?? this.notebookEditorWidgetService.focusedEditor?.model;
Expand Down
14 changes: 13 additions & 1 deletion packages/notebook/src/browser/notebook-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import {
CellData, CellEditType, CellMetadataEdit, CellOutput, CellOutputItem, CellRange, NotebookCellContentChangeEvent,
NotebookCellInternalMetadata,
NotebookCellMetadata,
NotebookCellsChangeInternalMetadataEvent,
NotebookCellsChangeLanguageEvent,
NotebookCellsChangeMetadataEvent,
Expand Down Expand Up @@ -152,13 +153,24 @@ export interface CellReplaceEdit {
cells: CellData[];
}

export interface CellPartialMetadataEdit {
editType: CellEditType.PartialMetadata;
index: number;
metadata: NullablePartialNotebookCellMetadata;
}

export type ImmediateCellEditOperation = CellOutputEditByHandle | CellOutputItemEdit | CellPartialInternalMetadataEditByHandle; // add more later on
export type CellEditOperation = ImmediateCellEditOperation | CellReplaceEdit | CellOutputEdit |
CellMetadataEdit | CellLanguageEdit | DocumentMetadataEdit | CellMoveEdit; // add more later on
CellMetadataEdit | CellLanguageEdit | DocumentMetadataEdit | CellMoveEdit | CellPartialMetadataEdit; // add more later on

export type NullablePartialNotebookCellInternalMetadata = {
[Key in keyof Partial<NotebookCellInternalMetadata>]: NotebookCellInternalMetadata[Key] | null
};

export type NullablePartialNotebookCellMetadata = {
[Key in keyof Partial<NotebookCellMetadata>]: NotebookCellMetadata[Key] | null
};

export interface CellPartialInternalMetadataEditByHandle {
editType: CellEditType.PartialInternalMetadata;
handle: number;
Expand Down
21 changes: 21 additions & 0 deletions packages/notebook/src/browser/service/notebook-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
import { NotebookCellModel, NotebookCellModelFactory, NotebookCellModelProps } from '../view-model/notebook-cell-model';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { CellEditOperation } from '../notebook-types';

export const NotebookProvider = Symbol('notebook provider');

Expand All @@ -37,6 +38,13 @@ export interface NotebookSerializer {
fromNotebook(data: NotebookData): Promise<BinaryBuffer>;
}

export interface NotebookWorkspaceEdit {
edits: {
resource: URI;
edit: CellEditOperation
}[]
}

@injectable()
export class NotebookService implements Disposable {

Expand Down Expand Up @@ -178,4 +186,17 @@ export class NotebookService implements Disposable {
listNotebookDocuments(): NotebookModel[] {
return [...this.notebookModels.values()];
}

applyWorkspaceEdit(workspaceEdit: NotebookWorkspaceEdit): boolean {
try {
workspaceEdit.edits.forEach(edit => {
const notebook = this.getNotebookEditorModel(edit.resource);
notebook?.applyEdits([edit.edit], true);
});
return true;
} catch (e) {
console.error(e);
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ export class NotebookCellModel implements NotebookCell, Disposable {
return this._metadata;
}

set metadata(newMetadata: NotebookCellMetadata) {
this._metadata = newMetadata;
this.onDidChangeMetadataEmitter.fire();
}

protected _metadata: NotebookCellMetadata;

protected toDispose = new DisposableCollection();
Expand Down
59 changes: 57 additions & 2 deletions packages/notebook/src/browser/view-model/notebook-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ import { Disposable, Emitter, Event, Resource, URI } from '@theia/core';
import { Saveable, SaveOptions } from '@theia/core/lib/browser';
import {
CellData, CellEditType, CellUri, NotebookCellInternalMetadata,
NotebookCellMetadata,
NotebookCellsChangeType, NotebookCellTextModelSplice, NotebookData,
NotebookDocumentMetadata,
} from '../../common';
import { NotebookContentChangedEvent, NotebookModelWillAddRemoveEvent, CellEditOperation, NullablePartialNotebookCellInternalMetadata } from '../notebook-types';
import {
NotebookContentChangedEvent, NotebookModelWillAddRemoveEvent,
CellEditOperation, NullablePartialNotebookCellInternalMetadata,
NullablePartialNotebookCellMetadata
} from '../notebook-types';
import { NotebookSerializer } from '../service/notebook-service';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { NotebookCellModel, NotebookCellModelFactory } from './notebook-cell-model';
Expand Down Expand Up @@ -285,7 +290,10 @@ export class NotebookModel implements Saveable, Disposable {
cell.changeOutputItems(edit.outputId, !!edit.append, edit.items);
break;
case CellEditType.Metadata:
this.updateNotebookMetadata(edit.metadata, computeUndoRedo);
this.changeCellMetadata(this.cells[cellIndex], edit.metadata, computeUndoRedo);
break;
case CellEditType.PartialMetadata:
this.changeCellMetadataPartial(this.cells[cellIndex], edit.metadata, computeUndoRedo);
break;
case CellEditType.PartialInternalMetadata:
this.changeCellInternalMetadataPartial(this.cells[cellIndex], edit.internalMetadata);
Expand All @@ -294,6 +302,7 @@ export class NotebookModel implements Saveable, Disposable {
this.changeCellLanguage(this.cells[cellIndex], edit.language, computeUndoRedo);
break;
case CellEditType.DocumentMetadata:
this.updateNotebookMetadata(edit.metadata, computeUndoRedo);
break;
case CellEditType.Move:
this.moveCellToIndex(cellIndex, edit.length, edit.newIdx, computeUndoRedo);
Expand Down Expand Up @@ -379,6 +388,38 @@ export class NotebookModel implements Saveable, Disposable {
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata }]);
}

protected changeCellMetadataPartial(cell: NotebookCellModel, metadata: NullablePartialNotebookCellMetadata, computeUndoRedo: boolean): void {
const newMetadata: NotebookCellMetadata = {
...cell.metadata
};
let k: keyof NullablePartialNotebookCellMetadata;
// eslint-disable-next-line guard-for-in
for (k in metadata) {
const value = metadata[k] ?? undefined;
newMetadata[k] = value as unknown;
}

this.changeCellMetadata(cell, newMetadata, computeUndoRedo);
}

protected changeCellMetadata(cell: NotebookCellModel, metadata: NotebookCellMetadata, computeUndoRedo: boolean): void {
const triggerDirtyChange = this.isCellMetadataChanged(cell.metadata, metadata);

if (triggerDirtyChange) {
if (computeUndoRedo) {
const oldMetadata = cell.metadata;
cell.metadata = metadata;
this.undoRedoService.pushElement(this.uri,
async () => { cell.metadata = oldMetadata; },
async () => { cell.metadata = metadata; }
);
}
}

cell.metadata = metadata;
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.ChangeCellMetadata, index: this.cells.indexOf(cell), metadata: cell.metadata }]);
}

protected changeCellLanguage(cell: NotebookCellModel, languageId: string, computeUndoRedo: boolean): void {
if (cell.language === languageId) {
return;
Expand Down Expand Up @@ -407,4 +448,18 @@ export class NotebookModel implements Saveable, Disposable {
protected getCellIndexByHandle(handle: number): number {
return this.cells.findIndex(c => c.handle === handle);
}

protected isCellMetadataChanged(a: NotebookCellMetadata, b: NotebookCellMetadata): boolean {
const keys = new Set([...Object.keys(a || {}), ...Object.keys(b || {})]);
for (const key of keys) {
if (
(a[key as keyof NotebookCellMetadata] !== b[key as keyof NotebookCellMetadata])
) {
return true;
}
}

return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ export class NotebookCellToolbarFactory {
anchor: e.nativeEvent,
menuPath,
includeAnchorArg: false,
args: [notebookModel, cell, output]
args: [cell],
context: this.notebookContextManager.context
}) :
() => this.commandRegistry.executeCommand(menuNode.command!, notebookModel, cell, output),
isVisible: () => menuPath ? true : Boolean(this.commandRegistry.getVisibleHandler(menuNode.command!, notebookModel, cell, output)),
Expand Down
13 changes: 13 additions & 0 deletions packages/notebook/src/common/notebook-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,19 @@ export namespace NotebookModelResource {
}
}

export interface NotebookCellModelResource {
notebookCellModelUri: URI;
}

export namespace NotebookCellModelResource {
export function is(item: unknown): item is NotebookCellModelResource {
return isObject<NotebookCellModelResource>(item) && item.notebookCellModelUri instanceof URI;
}
export function create(uri: URI): NotebookCellModelResource {
return { notebookCellModelUri: uri };
}
}

export enum NotebookCellExecutionState {
Unconfirmed = 1,
Pending = 2,
Expand Down
14 changes: 14 additions & 0 deletions packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1563,6 +1563,16 @@ export interface WorkspaceNotebookCellEditDto {
cellEdit: CellEditOperationDto;
}

export namespace WorkspaceNotebookCellEditDto {
export function is(arg: WorkspaceNotebookCellEditDto | WorkspaceFileEditDto | WorkspaceTextEditDto): arg is WorkspaceNotebookCellEditDto {
return !!arg
&& 'resource' in arg
&& 'cellEdit' in arg
&& arg.cellEdit !== null
&& typeof arg.cellEdit === 'object';
}
}

export interface WorkspaceEditDto {
edits: Array<WorkspaceTextEditDto | WorkspaceFileEditDto | WorkspaceNotebookCellEditDto>;
}
Expand Down Expand Up @@ -2464,6 +2474,10 @@ export type NotebookRawContentEventDto =
readonly outputItems: NotebookOutputItemDto[];
readonly append: boolean;
}
| {
readonly kind: notebookCommon.NotebookCellsChangeType.ChangeDocumentMetadata
readonly metadata: notebookCommon.NotebookDocumentMetadata;
}
| notebookCommon.NotebookCellsChangeLanguageEvent
| notebookCommon.NotebookCellsChangeMetadataEvent
| notebookCommon.NotebookCellsChangeInternalMetadataEvent
Expand Down
1 change: 0 additions & 1 deletion packages/plugin-ext/src/main/browser/languages-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1434,7 +1434,6 @@ export function toMonacoWorkspaceEdit(data: WorkspaceEditDto | undefined): monac
metadata: fileEdit.metadata
};
}
// TODO implement WorkspaceNotebookCellEditDto
})
};
}
4 changes: 1 addition & 3 deletions packages/plugin-ext/src/main/browser/main-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import { EditorManager } from '@theia/editor/lib/browser';
import { EditorModelService } from './text-editor-model-service';
import { OpenerService } from '@theia/core/lib/browser/opener-service';
import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
import { MonacoBulkEditService } from '@theia/monaco/lib/browser/monaco-bulk-edit-service';
import { MainFileSystemEventService } from './main-file-system-event-service';
import { LabelServiceMainImpl } from './label-service-main';
import { TimelineMainImpl } from './timeline-main';
Expand Down Expand Up @@ -109,8 +108,7 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container
rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOK_DOCUMENTS_AND_EDITORS_MAIN, new NotebooksAndEditorsMain(rpc, container, notebookDocumentsMain, notebookEditorsMain));
rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOK_KERNELS_MAIN, new NotebookKernelsMainImpl(rpc, container));

const bulkEditService = container.get(MonacoBulkEditService);
const editorsMain = new TextEditorsMainImpl(editorsAndDocuments, documentsMain, rpc, bulkEditService);
const editorsMain = new TextEditorsMainImpl(editorsAndDocuments, documentsMain, rpc, container);
rpc.set(PLUGIN_RPC_CONTEXT.TEXT_EDITORS_MAIN, editorsMain);

// start listening only after all clients are subscribed to events
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ export class NotebookDocumentsMainImpl implements NotebookDocumentsMain {
case NotebookCellsChangeType.ChangeCellInternalMetadata:
eventDto.rawEvents.push(e);
break;
case NotebookCellsChangeType.ChangeDocumentMetadata:
eventDto.rawEvents.push({
kind: e.kind,
metadata: e.metadata
});
break;
}
}

Expand Down
Loading

0 comments on commit 02acd2e

Please sign in to comment.