Skip to content

Commit b70b3ad

Browse files
committed
refactor jupyter changes #757
1 parent 04c5859 commit b70b3ad

File tree

4 files changed

+212
-0
lines changed

4 files changed

+212
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
export const PythonLanguage = { language: 'python', scheme: 'file' };
3+
4+
export namespace Commands {
5+
export namespace Jupyter {
6+
export const Get_All_KernelSpecs_For_Language = 'jupyter.getAllKernelSpecsForLanguage';
7+
export const Get_All_KernelSpecs = 'jupyter.getAllKernelSpecs';
8+
export const Kernel_Options = 'jupyter.kernelOptions';
9+
export const StartKernelForKernelSpeck = 'jupyter.sartKernelForKernelSpecs';
10+
export const ExecuteRangeInKernel = 'jupyter.execRangeInKernel';
11+
export const ExecuteSelectionOrLineInKernel = 'jupyter.runSelectionLine';
12+
export namespace Cell {
13+
export const ExecuteCurrentCell = 'jupyter.execCurrentCell';
14+
export const ExecuteCurrentCellAndAdvance = 'jupyter.execCurrentCellAndAdvance';
15+
export const AdcanceToCell = 'jupyter.advanceToNextCell';
16+
export const DisplayCellMenu = 'jupyter.displayCellMenu';
17+
export const GoToPreviousCell = 'jupyter.gotToPreviousCell';
18+
export const GoToNextCell = 'jupyter.gotToNextCell';
19+
}
20+
export namespace Kernel {
21+
export const Select = 'jupyter.selectKernel';
22+
export const Interrupt = 'jupyter.kernelInterrupt';
23+
export const Restart = 'jupyter.kernelRestart';
24+
export const Shutdown = 'jupyter.kernelShutDown';
25+
export const Details = 'jupyter.kernelDetails';
26+
}
27+
export namespace Notebook {
28+
export const ShutDown = 'jupyter.shutdown';
29+
}
30+
}
31+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
export interface JupyterSettings {
3+
appendResults: boolean;
4+
pythonPath: string;
5+
languages: JupyterLanguageSetting[];
6+
}
7+
8+
export interface JupyterLanguageSetting {
9+
languageId: string;
10+
defaultKernel?: string;
11+
startupCode?: string[];
12+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Range, Position, TextDocument, workspace } from 'vscode';
2+
import { JupyterLanguageSetting } from './contracts';
3+
import { EOL } from 'os';
4+
5+
/**
6+
* Language providers
7+
*
8+
* @export
9+
* @interface LanguageProvider
10+
*/
11+
export interface LanguageProvider {
12+
/**
13+
* Returns a Regular Expression used to determine whether a line is a Cell delimiter or not
14+
*
15+
* @type {RegExp}
16+
* @memberOf LanguageProvider
17+
*/
18+
cellIdentifier: RegExp;
19+
20+
/**
21+
* Returns the selected code
22+
* If not implemented, then the currently active line or selected code is taken.
23+
* Can be implemented to ensure valid blocks of code are selected.
24+
* E.g if user selects only the If statement, code can be impelemented to ensure all code within the if statement (block) is returned
25+
* @param {string} selectedCode The selected code as identified by this extension.
26+
* @param {Range} [currentCell] Range of the currently active cell
27+
* @returns {Promise<string>} The code selected. If nothing is to be done, return the parameter value.
28+
*
29+
* @memberOf LanguageProvider
30+
*/
31+
getSelectedCode(selectedCode: string, currentCell?: Range): Promise<string>;
32+
33+
/**
34+
* Gets the first line (position) of executable code within a range
35+
*
36+
* @param {TextDocument} document
37+
* @param {number} startLine
38+
* @param {number} endLine
39+
* @returns {Promise<Position>}
40+
*
41+
* @memberOf LanguageProvider
42+
*/
43+
getFirstLineOfExecutableCode(document: TextDocument, range: Range): Promise<Position>;
44+
}
45+
46+
export class LanguageProviders {
47+
private static providers: Map<string, LanguageProvider> = new Map<string, LanguageProvider>();
48+
public static registerLanguageProvider(language: string, provider: LanguageProvider) {
49+
if (typeof language !== 'string' || language.length === 0) {
50+
throw new Error(`Argument 'language' is invalid`);
51+
}
52+
if (typeof provider !== 'object' || language === null) {
53+
throw new Error(`Argument 'provider' is invalid`);
54+
}
55+
LanguageProviders.providers.set(language, provider);
56+
}
57+
public static cellIdentifier(language: string): RegExp {
58+
return LanguageProviders.providers.has(language) ?
59+
LanguageProviders.providers.get(language).cellIdentifier : null;
60+
}
61+
public static getSelectedCode(language: string, selectedCode: string, currentCell?: Range): Promise<string> {
62+
return LanguageProviders.providers.has(language) ?
63+
LanguageProviders.providers.get(language).getSelectedCode(selectedCode, currentCell) :
64+
Promise.resolve(selectedCode);
65+
}
66+
public static getFirstLineOfExecutableCode(language: string, defaultRange: Range, document: TextDocument, range: Range): Promise<Position> | Promise<Range> {
67+
return LanguageProviders.providers.has(language) ?
68+
LanguageProviders.providers.get(language).getFirstLineOfExecutableCode(document, range) :
69+
Promise.resolve(defaultRange);
70+
}
71+
private static getLanguageSetting(language: string): JupyterLanguageSetting {
72+
let jupyterConfig = workspace.getConfiguration('jupyter');
73+
let langSettings = jupyterConfig.get('languages') as JupyterLanguageSetting[];
74+
let lowerLang = language.toLowerCase();
75+
return langSettings.find(setting => setting.languageId.toLowerCase() === lowerLang);
76+
}
77+
78+
public static getDefaultKernel(language: string): string {
79+
let langSetting = LanguageProviders.getLanguageSetting(language);
80+
return langSetting ? langSetting.defaultKernel : null;
81+
}
82+
public static getStartupCode(language: string): string {
83+
let langSetting = LanguageProviders.getLanguageSetting(language);
84+
if (!langSetting || langSetting.startupCode.length === 0) {
85+
return null;
86+
}
87+
return langSetting.startupCode.join(EOL);
88+
}
89+
}

src/client/jupyter/common/utils.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
2+
'use strict';
3+
// TODO: Cleanup this place
4+
// Add options for execPythonFile
5+
import * as path from 'path';
6+
import * as fs from 'fs';
7+
8+
export const IS_WINDOWS = /^win/.test(process.platform);
9+
export const PATH_VARIABLE_NAME = IS_WINDOWS ? 'Path' : 'PATH';
10+
11+
const PathValidity: Map<string, boolean> = new Map<string, boolean>();
12+
export function validatePath(filePath: string): Promise<string> {
13+
if (filePath.length === 0) {
14+
return Promise.resolve('');
15+
}
16+
if (PathValidity.has(filePath)) {
17+
return Promise.resolve(PathValidity.get(filePath) ? filePath : '');
18+
}
19+
return new Promise<string>(resolve => {
20+
fs.exists(filePath, exists => {
21+
PathValidity.set(filePath, exists);
22+
return resolve(exists ? filePath : '');
23+
});
24+
});
25+
}
26+
export function fsExistsAsync(filePath: string): Promise<boolean> {
27+
return new Promise<boolean>(resolve => {
28+
fs.exists(filePath, exists => {
29+
PathValidity.set(filePath, exists);
30+
return resolve(exists);
31+
});
32+
});
33+
}
34+
35+
export function formatErrorForLogging(error: Error | string): string {
36+
let message: string = '';
37+
if (typeof error === 'string') {
38+
message = error;
39+
}
40+
else {
41+
if (error.message) {
42+
message = `Error Message: ${error.message}`;
43+
}
44+
if (error.name && error.message.indexOf(error.name) === -1) {
45+
message += `, (${error.name})`;
46+
}
47+
const innerException = (error as any).innerException;
48+
if (innerException && (innerException.message || innerException.name)) {
49+
if (innerException.message) {
50+
message += `, Inner Error Message: ${innerException.message}`;
51+
}
52+
if (innerException.name && innerException.message.indexOf(innerException.name) === -1) {
53+
message += `, (${innerException.name})`;
54+
}
55+
}
56+
}
57+
return message;
58+
}
59+
60+
export function getSubDirectories(rootDir: string): Promise<string[]> {
61+
return new Promise<string[]>(resolve => {
62+
fs.readdir(rootDir, (error, files) => {
63+
if (error) {
64+
return resolve([]);
65+
}
66+
const subDirs = [];
67+
files.forEach(name => {
68+
const fullPath = path.join(rootDir, name);
69+
try {
70+
if (fs.statSync(fullPath).isDirectory()) {
71+
subDirs.push(fullPath);
72+
}
73+
}
74+
catch (ex) {
75+
}
76+
});
77+
resolve(subDirs);
78+
});
79+
});
80+
}

0 commit comments

Comments
 (0)