Skip to content

Commit 97fe17e

Browse files
jonah-idenmsujew
andauthored
Notebook API Support (#12442)
Full feature support including: * Notebook widget rendering * Kernel selection * Cell execution * Custom output rendering * Plugin host support Signed-off-by: Jonah Iden <[email protected]> Co-authored-by: Mark Sujew <[email protected]>
1 parent 109adc4 commit 97fe17e

File tree

98 files changed

+11549
-830
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+11549
-830
lines changed

examples/browser/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"@theia/mini-browser": "1.40.0",
3535
"@theia/monaco": "1.40.0",
3636
"@theia/navigator": "1.40.0",
37+
"@theia/notebook": "1.40.0",
3738
"@theia/outline-view": "1.40.0",
3839
"@theia/output": "1.40.0",
3940
"@theia/plugin-dev": "1.40.0",

examples/browser/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
{
6666
"path": "../../packages/navigator"
6767
},
68+
{
69+
"path": "../../packages/notebook"
70+
},
6871
{
6972
"path": "../../packages/outline-view"
7073
},

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@
113113
"vscode.git-base",
114114
"vscode.github",
115115
"vscode.github-authentication",
116-
"vscode.ipynb",
117116
"vscode.microsoft-authentication",
118117
"ms-vscode.references-view"
119118
]

packages/core/src/browser/saveable.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616

1717
import { Widget } from '@phosphor/widgets';
1818
import { Message } from '@phosphor/messaging';
19-
import { Event } from '../common/event';
19+
import { Emitter, Event } from '../common/event';
2020
import { MaybePromise } from '../common/types';
2121
import { Key } from './keyboard/keys';
2222
import { AbstractDialog } from './dialogs';
2323
import { waitForClosed } from './widgets';
2424
import { nls } from '../common/nls';
25-
import { isObject } from '../common';
25+
import { Disposable, isObject } from '../common';
2626

2727
export interface Saveable {
2828
readonly dirty: boolean;
@@ -50,6 +50,45 @@ export interface SaveableSource {
5050
readonly saveable: Saveable;
5151
}
5252

53+
export class SaveableDelegate implements Saveable {
54+
dirty = false;
55+
protected readonly onDirtyChangedEmitter = new Emitter<void>();
56+
57+
get onDirtyChanged(): Event<void> {
58+
return this.onDirtyChangedEmitter.event;
59+
}
60+
autoSave: 'off' | 'afterDelay' | 'onFocusChange' | 'onWindowChange' = 'off';
61+
62+
async save(options?: SaveOptions): Promise<void> {
63+
await this.delegate?.save(options);
64+
}
65+
66+
revert?(options?: Saveable.RevertOptions): Promise<void>;
67+
createSnapshot?(): Saveable.Snapshot;
68+
applySnapshot?(snapshot: object): void;
69+
70+
protected delegate?: Saveable;
71+
protected toDispose?: Disposable;
72+
73+
set(delegate: Saveable): void {
74+
this.toDispose?.dispose();
75+
this.delegate = delegate;
76+
this.toDispose = this.delegate.onDirtyChanged(() => {
77+
this.dirty = delegate.dirty;
78+
this.onDirtyChangedEmitter.fire();
79+
});
80+
this.autoSave = delegate.autoSave;
81+
if (this.dirty !== delegate.dirty) {
82+
this.dirty = delegate.dirty;
83+
this.onDirtyChangedEmitter.fire();
84+
}
85+
this.revert = delegate.revert?.bind(delegate);
86+
this.createSnapshot = delegate.createSnapshot?.bind(delegate);
87+
this.applySnapshot = delegate.applySnapshot?.bind(delegate);
88+
}
89+
90+
}
91+
5392
export namespace Saveable {
5493
export interface RevertOptions {
5594
/**

packages/core/src/common/array-utils.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,24 @@ export namespace ArrayUtils {
106106
export function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
107107
return <T[]>array.filter(e => !!e);
108108
}
109+
110+
/**
111+
* groups array elements through a comparator function
112+
* @param data array of elements to group
113+
* @param compare comparator function: return of 0 means should group, anything above means not group
114+
* @returns array of arrays with grouped elements
115+
*/
116+
export function groupBy<T>(data: ReadonlyArray<T>, compare: (a: T, b: T) => number): T[][] {
117+
const result: T[][] = [];
118+
let currentGroup: T[] | undefined = undefined;
119+
for (const element of data.slice(0).sort(compare)) {
120+
if (!currentGroup || compare(currentGroup[0], element) !== 0) {
121+
currentGroup = [element];
122+
result.push(currentGroup);
123+
} else {
124+
currentGroup.push(element);
125+
}
126+
}
127+
return result;
128+
}
109129
}

packages/core/src/common/event.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
/* eslint-disable @typescript-eslint/no-explicit-any */
1818

19-
import { Disposable, DisposableGroup } from './disposable';
19+
import { Disposable, DisposableGroup, DisposableCollection } from './disposable';
2020
import { MaybePromise } from './types';
2121

2222
/**
@@ -67,6 +67,16 @@ export namespace Event {
6767
set maxListeners(maxListeners: number) { }
6868
});
6969
}
70+
71+
/**
72+
* Given a collection of events, returns a single event which emits whenever any of the provided events emit.
73+
*/
74+
export function any<T>(...events: Event<T>[]): Event<T>;
75+
export function any(...events: Event<any>[]): Event<void>;
76+
export function any<T>(...events: Event<T>[]): Event<T> {
77+
return (listener, thisArgs = undefined, disposables?: Disposable[]) =>
78+
new DisposableCollection(...events.map(event => event(e => listener.call(thisArgs, e), undefined, disposables)));
79+
}
7080
}
7181

7282
type Callback = (...args: any[]) => any;
@@ -276,7 +286,7 @@ export class Emitter<T = any> {
276286
*/
277287
fire(event: T): any {
278288
if (this._callbacks) {
279-
this._callbacks.invoke(event);
289+
return this._callbacks.invoke(event);
280290
}
281291
}
282292

packages/core/src/common/types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ export function isFunction<T extends (...args: unknown[]) => unknown>(value: unk
5656
return typeof value === 'function';
5757
}
5858

59+
/**
60+
* @returns whether the provided parameter is an empty JavaScript Object or not.
61+
*/
62+
export function isEmptyObject(obj: unknown): obj is object {
63+
if (!isObject(obj)) {
64+
return false;
65+
}
66+
67+
for (const key in obj) {
68+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
69+
return false;
70+
}
71+
}
72+
73+
return true;
74+
}
75+
5976
export function isObject<T extends object>(value: unknown): value is UnknownObject<T> {
6077
// eslint-disable-next-line no-null/no-null
6178
return typeof value === 'object' && value !== null;

packages/core/src/common/uri.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export class URI {
2727
return new URI(Uri.file(path));
2828
}
2929

30+
public static isUri(uri: unknown): boolean {
31+
return Uri.isUri(uri);
32+
}
33+
3034
private readonly codeUri: Uri;
3135
private _path: Path | undefined;
3236

packages/editor/src/browser/editor-frontend-module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { QuickAccessContribution } from '@theia/core/lib/browser/quick-input/qui
3838
import { QuickEditorService } from './quick-editor-service';
3939
import { EditorLanguageStatusService } from './language-status/editor-language-status-service';
4040
import { EditorLineNumberContribution } from './editor-linenumber-contribution';
41+
import { UndoRedoService } from './undo-redo-service';
4142

4243
export default new ContainerModule(bind => {
4344
bindEditorPreferences(bind);
@@ -86,4 +87,6 @@ export default new ContainerModule(bind => {
8687
bind(ActiveEditorAccess).toSelf().inSingletonScope();
8788
bind(EditorAccess).to(CurrentEditorAccess).inSingletonScope().whenTargetNamed(EditorAccess.CURRENT);
8889
bind(EditorAccess).to(ActiveEditorAccess).inSingletonScope().whenTargetNamed(EditorAccess.ACTIVE);
90+
91+
bind(UndoRedoService).toSelf().inSingletonScope();
8992
});

packages/plugin-ext/src/main/browser/custom-editors/undo-redo-service.ts renamed to packages/editor/src/browser/undo-redo-service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,16 @@ export class ResourceEditStack {
9494
this.past.push(element);
9595
}
9696

97-
getClosestPastElement(): StackElement | null {
97+
getClosestPastElement(): StackElement | undefined {
9898
if (this.past.length === 0) {
99-
return null;
99+
return undefined;
100100
}
101101
return this.past[this.past.length - 1];
102102
}
103103

104-
getClosestFutureElement(): StackElement | null {
104+
getClosestFutureElement(): StackElement | undefined {
105105
if (this.future.length === 0) {
106-
return null;
106+
return undefined;
107107
}
108108
return this.future[this.future.length - 1];
109109
}

0 commit comments

Comments
 (0)