Skip to content

Commit d6e84bd

Browse files
committed
refactored
1 parent 4f8133e commit d6e84bd

10 files changed

Lines changed: 176 additions & 69 deletions

File tree

src/client/common/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ export namespace Commands {
1818
export const Tests_Select_And_Run_Method = 'python.selectAndRunTestMethod';
1919
export const Refactor_Extract_Variable = 'python.refactorExtractVariable';
2020
export const Refaactor_Extract_Method = 'python.refactorExtractMethod';
21+
22+
export namespace Jupyter {
23+
export const Get_All_KernelSpecs = 'jupyter:getAllKernelSpecs';
24+
export const Select_Kernel = 'jupyter:selectKernel';
25+
}
2126
}
2227
export namespace Octicons {
2328
export const Test_Pass = '$(check)';

src/client/jupyter/contracts.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as vscode from 'vscode';
12
// http://jupyter-client.readthedocs.io/en/latest/messaging.html#to-do
23

34
/**
@@ -17,6 +18,10 @@ export interface Kernelspec {
1718
resource_dir: string;
1819
}
1920

21+
export interface KernelEvents {
22+
onStatusChange: vscode.Event<[KernelspecMetadata, string]>;
23+
}
24+
2025
export interface JupyterMessage extends Object {
2126
parent_header: any;
2227
content: any;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as vscode from 'vscode';
2+
import {KernelspecMetadata} from '../contracts';
3+
import {Commands} from '../../common/constants';
4+
5+
export class KernelPicker extends vscode.Disposable {
6+
private disposables: vscode.Disposable[];
7+
constructor() {
8+
super(() => { });
9+
this.disposables = [];
10+
this.registerCommands();
11+
}
12+
public dispose() {
13+
this.disposables.forEach(d => d.dispose());
14+
}
15+
16+
private registerCommands() {
17+
this.disposables.push(vscode.commands.registerCommand(Commands.Jupyter.Select_Kernel, () => {
18+
return this.selectkernel();
19+
}));
20+
}
21+
22+
private selectkernel(): Promise<KernelspecMetadata> {
23+
return new Promise<KernelspecMetadata>(resolve => {
24+
vscode.commands.executeCommand(Commands.Jupyter.Get_All_KernelSpecs).then((kernelSpecs: KernelspecMetadata[]) => {
25+
if (kernelSpecs.length === 0) {
26+
return resolve();
27+
}
28+
this.displayKernelPicker(kernelSpecs).then(resolve);
29+
});
30+
});
31+
}
32+
private displayKernelPicker(kernelspecs: KernelspecMetadata[]): Promise<KernelspecMetadata> {
33+
const items = kernelspecs.map(spec => { return { label: spec.display_name, description: spec.language, kernelspec: spec }; });
34+
return new Promise<KernelspecMetadata>(resolve => {
35+
vscode.window.showQuickPick(items, { placeHolder: 'Select a kernel' }).then(item => {
36+
if (item) {
37+
resolve(item.kernelspec);
38+
}
39+
else {
40+
resolve();
41+
}
42+
});
43+
});
44+
}
45+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as vscode from 'vscode';
2+
import {KernelspecMetadata} from '../contracts';
3+
4+
export class KernelStatus extends vscode.Disposable {
5+
private disposables: vscode.Disposable[];
6+
private statusBar: vscode.StatusBarItem;
7+
8+
constructor() {
9+
super(() => { });
10+
this.disposables = [];
11+
this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
12+
this.disposables.push(this.statusBar);
13+
}
14+
private activeKernalDetails: string;
15+
public setActiveKernel(kernelspec: KernelspecMetadata) {
16+
this.activeKernalDetails = this.statusBar.text = `${kernelspec.display_name} Kernel`;
17+
}
18+
public setKernelStatus(status: string) {
19+
this.statusBar.text = `${this.activeKernalDetails} (${status})`;
20+
}
21+
public dispose() {
22+
this.disposables.forEach(d => d.dispose());
23+
}
24+
}

src/client/jupyter/display/main.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as vscode from 'vscode';
2+
import {KernelPicker} from './kernelPicker';
3+
4+
export class JupyterDisplay extends vscode.Disposable {
5+
private disposables: vscode.Disposable[];
6+
constructor() {
7+
super(() => { });
8+
this.disposables = [];
9+
this.disposables.push(new KernelPicker());
10+
}
11+
12+
public dispose() {
13+
this.disposables.forEach(d => d.dispose());
14+
}
15+
}

src/client/jupyter/kernel-manager.ts

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,27 @@ import {WSKernel} from './ws-kernel';
88
import {ZMQKernel} from './zmq-kernel';
99
import {launchSpec} from 'spawnteract';
1010
import {KernelspecMetadata, Kernelspec} from './contracts';
11+
import {Commands} from '../common/constants';
1112

12-
export class KernelManager extends vscode.Disposable {
13+
export class KernelManagerImpl extends vscode.Disposable {
1314
private _runningKernels: Map<string, Kernel>;
1415
private _kernelSpecs: { [key: string]: Kernelspec };
16+
private disposables: vscode.Disposable[];
1517
constructor() {
1618
super(() => { });
17-
// this.getKernelSpecsFromJupyter = this.getKernelSpecsFromJupyter.bind(this);
18-
// this.getAllKernelSpecs = this.getAllKernelSpecs.bind(this);
19+
this.disposables = [];
1920
this._runningKernels = new Map<string, Kernel>();
2021
this._kernelSpecs = this.getKernelSpecsFromSettings();
2122
}
22-
public dispose() {
23-
this.destroy();
23+
24+
private registerCommands() {
25+
this.disposables.push(vscode.commands.registerCommand(Commands.Jupyter.Get_All_KernelSpecs, () => {
26+
return this.getAllKernelSpecs();
27+
}));
2428
}
25-
public destroy() {
29+
public dispose() {
2630
this._runningKernels.forEach(kernel => {
27-
kernel.destroy();
31+
kernel.dispose();
2832
});
2933
this._runningKernels.clear();
3034
}
@@ -42,7 +46,7 @@ export class KernelManager extends vscode.Disposable {
4246
const kernel = this._runningKernels.get(language);
4347
this._runningKernels.delete(language);
4448
if (kernel != null) {
45-
kernel.destroy();
49+
kernel.dispose();
4650
}
4751
}
4852

@@ -116,18 +120,6 @@ export class KernelManager extends vscode.Disposable {
116120
const spawnOptions = {
117121
cwd: projectPath
118122
};
119-
// const that = this;
120-
// return launchSpec(kernelSpec, spawnOptions).then((function (_this) {
121-
// return function (arg) {
122-
// const config = arg.config, connectionFile = arg.connectionFile, spawn = arg.spawn;
123-
// const kernel = new ZMQKernel(kernelSpec, language, config, connectionFile, spawn);
124-
// (that.setRunningKernelFor as Function).call(that, language, kernel);
125-
// (that._executeStartupCode as Function).call(that, kernel);
126-
// return typeof onStarted === "function" ? onStarted(kernel) : void 0;
127-
// };
128-
// })(this), error => {
129-
// return Promise.reject(error);
130-
// });
131123
return launchSpec(kernelSpec, spawnOptions).then(result => {
132124
const kernel = new ZMQKernel(kernelSpec, language, result.config, result.connectionFile, result.spawn);
133125
this.setRunningKernelFor(language, kernel);
@@ -157,7 +149,6 @@ export class KernelManager extends vscode.Disposable {
157149
return this._runningKernels.has(language) ? this._runningKernels.get(language) : null;
158150
}
159151

160-
161152
public getAllKernelSpecs(): Promise<KernelspecMetadata[]> {
162153
if (Object.keys(this._kernelSpecs).length === 0) {
163154
return this.updateKernelSpecs().then(() => {

src/client/jupyter/kernel.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,28 @@
33
import * as vscode from 'vscode';
44
import * as child_process from 'child_process';
55
import * as path from 'path';
6-
import {KernelspecMetadata} from './contracts';
6+
import {KernelspecMetadata, KernelEvents} from './contracts';
77
const jmp = require('jmp');
88
const uuid = require('uuid');
99
const zmq = jmp.zmq;
1010

11-
export abstract class Kernel {
12-
protected statusBar: vscode.StatusBarItem;
11+
export abstract class Kernel extends vscode.Disposable implements KernelEvents {
1312
private watchCallbacks: any[];
1413
constructor(public kernelSpec: KernelspecMetadata, private language: string) {
14+
super(() => { });
1515
this.watchCallbacks = [];
16-
this.statusBar = vscode.window.createStatusBarItem();
1716
}
17+
public dispose() {
1818

19+
}
20+
21+
private _onStatusChange = new vscode.EventEmitter<[KernelspecMetadata, string]>();
22+
get onStatusChange(): vscode.Event<[KernelspecMetadata, string]> {
23+
return this._onStatusChange.event;
24+
}
25+
protected raiseOnStatusChange(status: string) {
26+
this._onStatusChange.fire([this.kernelSpec, status]);
27+
}
1928
public addWatchCallback(watchCallback) {
2029
return this.watchCallbacks.push(watchCallback);
2130
};
@@ -176,8 +185,4 @@ export abstract class Kernel {
176185
}
177186
return result;
178187
};
179-
180-
public destroy() {
181-
return console.log('Kernel: Destroying base kernel');
182-
};
183188
}

src/client/jupyter/main.ts

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
1-
import {KernelManager} from './kernel-manager';
1+
import {KernelManagerImpl} from './kernel-manager';
22
import {Kernel} from './kernel';
33
import * as vscode from 'vscode';
44
import {TextDocumentContentProvider} from './resultView';
5+
import {JupyterDisplay} from './display/main';
6+
import {KernelStatus} from './display/kernelStatus';
7+
58
const anser = require('anser');
69

710
const jupyterSchema = 'jupyter-result-viewer';
811
let previewUri = vscode.Uri.parse(jupyterSchema + '://authority/jupyter');
912

1013
let previewWindow: TextDocumentContentProvider;
11-
export function activate(): vscode.Disposable {
14+
let display: JupyterDisplay;
15+
export function activate(): vscode.Disposable[] {
1216
previewWindow = new TextDocumentContentProvider();
13-
let registration = vscode.workspace.registerTextDocumentContentProvider(jupyterSchema, previewWindow);
14-
return registration;
17+
let disposables: vscode.Disposable[] = [];
18+
disposables.push(vscode.workspace.registerTextDocumentContentProvider(jupyterSchema, previewWindow));
19+
display = new JupyterDisplay();
20+
disposables.push(display);
21+
return disposables;
1522
}
1623

1724
let displayed = false;
@@ -26,29 +33,33 @@ function showResults(result: any): any {
2633
vscode.window.showErrorMessage(reason);
2734
});
2835
}
29-
export class Jupyter {
30-
public subscriptions = null;
31-
public kernelManager: KernelManager;
36+
export class Jupyter extends vscode.Disposable {
37+
public kernelManager: KernelManagerImpl;
3238
public editor: vscode.TextEditor;
3339
public kernel: Kernel = null;
3440
public markerBubbleMap = null;
35-
public statusBarElement = null;
36-
public statusBarTile = null;
3741
public watchSidebar = null;
3842
public watchSidebarIsVisible = false;
43+
private status: KernelStatus;
44+
private disposables: vscode.Disposable[];
3945

46+
constructor() {
47+
super(() => { });
48+
this.disposables = [];
49+
}
4050
activate(state) {
41-
activate();
42-
this.kernelManager = new KernelManager();
51+
this.disposables.push(...activate());
52+
this.kernelManager = new KernelManagerImpl();
53+
this.disposables.push(this.kernelManager);
4354
this.markerBubbleMap = {};
44-
vscode.window.onDidChangeActiveTextEditor(this.onEditorChanged.bind(this));
55+
this.disposables.push(vscode.window.onDidChangeActiveTextEditor(this.onEditorChanged.bind(this)));
56+
this.status = new KernelStatus();
57+
this.disposables.push(this.status);
4558
}
46-
deactivate() {
47-
this.subscriptions.dispose();
48-
this.kernelManager.destroy();
49-
return this.statusBarTile.destroy();
59+
public dispose() {
60+
this.disposables.forEach(d => d.dispose());
5061
}
51-
onEditorChanged(editor) {
62+
private onEditorChanged(editor) {
5263
// Opening display (results) documents causes event to fire
5364
if (!editor) {
5465
return;
@@ -62,8 +73,20 @@ export class Jupyter {
6273
return this.onKernelChanged(kernel);
6374
}
6475
}
76+
private onKernalStatusChangeHandler: vscode.Disposable;
6577
onKernelChanged(kernel: Kernel) {
78+
// Unbind any previous handlers
79+
if (this.onKernalStatusChangeHandler) {
80+
this.onKernalStatusChangeHandler.dispose();
81+
this.onKernalStatusChangeHandler = null;
82+
}
83+
if (kernel) {
84+
this.onKernalStatusChangeHandler = kernel.onStatusChange(statusInfo => {
85+
this.status.setKernelStatus(statusInfo[1]);
86+
});
87+
}
6688
this.kernel = kernel;
89+
this.status.setActiveKernel(this.kernel ? this.kernel.kernelSpec : null);
6790
}
6891
createResultBubble(code): Promise<any> {
6992
if (this.kernel) {
@@ -87,20 +110,16 @@ export class Jupyter {
87110
return new Promise<any>((resolve, reject) => {
88111
let htmlResponse = '';
89112
return kernel.execute(code, (result: { type: string, stream: string, data: { [key: string]: string } | string }) => {
90-
if (result.type === 'text' && result.stream === 'stdout' && typeof result.data['text/plain'] === 'string') {
113+
if ((result.type === 'text' && result.stream === 'stdout' && typeof result.data['text/plain'] === 'string') ||
114+
(result.type === 'text' && result.stream === 'pyout' && typeof result.data['text/plain'] === 'string') ||
115+
(result.type === 'text' && result.stream === 'error' && typeof result.data['text/plain'] === 'string')) {
91116
const htmlText = anser.ansiToHtml(anser.escapeForHtml(result.data['text/plain']));
117+
// let rawError = htmlText.replace('\n', '<br/>');
92118
htmlResponse = htmlResponse + `<p><pre>${htmlText}</pre></p>`;
93-
}
94-
if (result.type === 'text' && result.stream === 'pyout' && typeof result.data['text/plain'] === 'string') {
95-
const htmlText = anser.ansiToHtml(anser.escapeForHtml(result.data['text/plain']));
96-
htmlResponse = htmlResponse + `<p><pre>${htmlText}</pre></p>`;
97-
}
98-
if (result.type === 'text' && result.stream === 'error' && typeof result.data['text/plain'] === 'string') {
99-
const htmlText = anser.ansiToHtml(anser.escapeForHtml(result.data['text/plain']));
100-
let rawError = htmlText.replace('\n', '<br/>');
101-
// htmlResponse = htmlResponse + `<p style="color:black;background-color:white">${rawError}</p>`;
102-
htmlResponse = htmlResponse + `<p><pre>${rawError}</pre></p>`;
103-
return resolve(htmlResponse);
119+
120+
if (result.stream === 'error') {
121+
return resolve(htmlResponse);
122+
}
104123
}
105124
if (result.type === 'text/html' && result.stream === 'pyout' && typeof result.data['text/html'] === 'string') {
106125
htmlResponse = htmlResponse + result.data['text/html'];

src/client/jupyter/ws-kernel.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export class WSKernel extends Kernel {
99
constructor(kernelSpec: KernelspecMetadata, language: string, private session: any) {
1010
super(kernelSpec, language);
1111

12-
this.session.statusChanged.connect(this._onStatusChange.bind(this));
13-
this._onStatusChange();
12+
this.session.statusChanged.connect(this.statusChangeHandler.bind(this));
13+
this.statusChangeHandler();
1414
}
1515

1616
public interrupt() {
@@ -25,9 +25,8 @@ export class WSKernel extends Kernel {
2525
return this.session.kernel.restart();
2626
};
2727

28-
public _onStatusChange() {
29-
// return this.statusView.setStatus(this.session.status);
30-
this.statusBar.text = `Sesion Status = ${this.session.status}`;
28+
public statusChangeHandler() {
29+
this.raiseOnStatusChange(this.session.status);
3130
};
3231

3332
public _execute(code, onResults, callWatches) {
@@ -104,9 +103,9 @@ export class WSKernel extends Kernel {
104103
});
105104
};
106105

107-
public destroy() {
106+
public dispose() {
108107
console.log('WSKernel: destroying jupyter-js-services Session');
109108
this.session.dispose();
110-
return super.destroy();
109+
super.dispose();
111110
};
112111
}

0 commit comments

Comments
 (0)