Skip to content

Commit

Permalink
Enable IW in web (#10131)
Browse files Browse the repository at this point in the history
* enabling IW commands
* show 'no kernel' message when creating IW without any server connection
  • Loading branch information
amunger authored May 26, 2022
1 parent c8466dd commit 981500b
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 29 deletions.
1 change: 1 addition & 0 deletions news/1 Enhancements/9717.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Enabled the Interactive Window in web.
27 changes: 13 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@
"command": "jupyter.runcurrentcell",
"title": "%jupyter.command.jupyter.runcurrentcell.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.debugcell",
Expand Down Expand Up @@ -490,19 +490,19 @@
"command": "jupyter.runcurrentcelladvance",
"title": "%jupyter.command.jupyter.runcurrentcelladvance.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.runcurrentcellandallbelow.palette",
"title": "%jupyter.command.jupyter.runcurrentcellandallbelow.palette.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.runallcellsabove.palette",
"title": "%jupyter.command.jupyter.runallcellsabove.palette.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.debugcurrentcell.palette",
Expand All @@ -520,13 +520,13 @@
"command": "jupyter.createnewinteractive",
"title": "%jupyter.command.jupyter.createnewinteractive.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.runFileInteractive",
"title": "%jupyter.command.jupyter.runFileInteractive.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.debugFileInteractive",
Expand All @@ -538,25 +538,25 @@
"command": "jupyter.runallcells",
"title": "%jupyter.command.jupyter.runallcells.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.runallcellsabove",
"title": "%jupyter.command.jupyter.runallcellsabove.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.runcellandallbelow",
"title": "%jupyter.command.jupyter.runcellandallbelow.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.runcell",
"title": "%jupyter.command.jupyter.runcell.title%",
"category": "Jupyter",
"enablement": "isWorkspaceTrusted && !jupyter.webExtension"
"enablement": "isWorkspaceTrusted"
},
{
"command": "jupyter.runtoline",
Expand Down Expand Up @@ -806,7 +806,6 @@
"command": "jupyter.interactive.clearAllCells",
"title": "%DataScience.interactiveClearAllCells%",
"icon": "$(close)",
"enablement": "!jupyter.webExtension",
"category": "Jupyter"
},
{
Expand All @@ -828,7 +827,7 @@
"title": "%DataScience.exportDialogTitle%",
"shortTitle": "%DataScience.exportAsNotebook.shorttitle%",
"icon": "$(save-as)",
"enablement": "notebookType == interactive",
"enablement": "notebookType == interactive && !jupyter.webExtension",
"category": "Jupyter"
},
{
Expand All @@ -838,7 +837,7 @@
"light": "resources/light/export_to_python.svg",
"dark": "resources/dark/export_to_python.svg"
},
"enablement": "notebookType == interactive",
"enablement": "notebookType == interactive && !jupyter.webExtension",
"category": "Jupyter"
},
{
Expand Down Expand Up @@ -1807,7 +1806,7 @@
},
"jupyter.codeLenses": {
"type": "string",
"default": "jupyter.runcell, jupyter.runallcellsabove, jupyter.debugcell",
"default": "jupyter.runcell, jupyter.runallcellsabove, jupyter.debugcell",
"description": "Set of commands to put as code lens above a cell.",
"scope": "resource"
},
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@
"DataScience.interactiveWindowModeBannerSwitchYes": "Yes",
"DataScience.interactiveWindowModeBannerSwitchAlways": "Always",
"DataScience.interactiveWindowModeBannerSwitchNo": "No",
"DataScience.noKernelsSpecifyRemote": "No kernel available for cell execution, please [specify a Jupyter server for connections](command:jupyter.selectjupyteruri)",
"DataScience.ipykernelNotInstalled": "IPyKernel not installed into interpreter {0}",
"DataScience.ipykernelNotInstalledBecauseCanceled": "IPyKernel not installed into interpreter. Installation canceled.",
"DataScience.needIpykernel6": "Ipykernel setup required for this feature",
Expand Down
22 changes: 18 additions & 4 deletions src/interactive-window/editor-integration/codeLensFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ import {
import { IDocumentManager, IVSCodeNotebook, IWorkspaceService } from '../../platform/common/application/types';
import { traceWarning, traceInfoIfCI } from '../../platform/logging';

import { ICellRange, IConfigurationService, IDisposableRegistry, Resource } from '../../platform/common/types';
import {
ICellRange,
IConfigurationService,
IDisposableRegistry,
IsWebExtension,
Resource
} from '../../platform/common/types';
import * as localize from '../../platform/common/utils/localize';
import { getInteractiveCellMetadata } from '../helpers';
import { IKernelProvider } from '../../kernels/types';
Expand Down Expand Up @@ -57,7 +63,8 @@ export class CodeLensFactory implements ICodeLensFactory {
@inject(IDisposableRegistry) disposables: IDisposableRegistry,
@inject(IGeneratedCodeStorageFactory)
private readonly generatedCodeStorageFactory: IGeneratedCodeStorageFactory,
@inject(IKernelProvider) kernelProvider: IKernelProvider
@inject(IKernelProvider) kernelProvider: IKernelProvider,
@inject(IsWebExtension) private readonly isWebExtension: boolean
) {
this.documentManager.onDidCloseTextDocument(this.onClosedDocument, this, disposables);
this.workspace.onDidGrantWorkspaceTrust(() => this.codeLensCache.clear(), this, disposables);
Expand Down Expand Up @@ -234,9 +241,10 @@ export class CodeLensFactory implements ICodeLensFactory {
fullCommandList = fullCommandList.concat(CodeLensCommands.DefaultDebuggingLenses);
}

let commandsToBeDisabled: string[] = [];
// If workspace is not trusted, then exclude execution related commands.
if (!this.workspace.isTrusted) {
const commandsToBeDisabledIfNotTrusted = [
commandsToBeDisabled = [
...CodeLensCommands.DebuggerCommands,
...CodeLensCommands.DebuggerCommands,
Commands.RunAllCells,
Expand All @@ -256,8 +264,14 @@ export class CodeLensFactory implements ICodeLensFactory {
Commands.DebugStop,
Commands.RunCellAndAllBelowPalette
];
fullCommandList = fullCommandList.filter((item) => !commandsToBeDisabledIfNotTrusted.includes(item));
}
if (this.isWebExtension) {
commandsToBeDisabled.push(Commands.DebugCell);
}
if (commandsToBeDisabled) {
fullCommandList = fullCommandList.filter((item) => !commandsToBeDisabled.includes(item));
}

return fullCommandList;
}

Expand Down
24 changes: 18 additions & 6 deletions src/interactive-window/interactiveWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,16 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
private readonly exportDialog: IExportDialog,
private readonly notebookControllerManager: INotebookControllerManager,
private readonly serviceContainer: IServiceContainer,
private readonly interactiveWindowDebugger: IInteractiveWindowDebugger,
private readonly interactiveWindowDebugger: IInteractiveWindowDebugger | undefined,
private readonly errorHandler: IDataScienceErrorHandler,
preferredController: IVSCodeNotebookController | undefined,
public readonly notebookEditor: NotebookEditor,
public readonly inputUri: Uri,
public readonly appShell: IApplicationShell,
private readonly codeGeneratorFactory: ICodeGeneratorFactory,
private readonly storageFactory: IGeneratedCodeStorageFactory,
private readonly debuggingManager: IInteractiveWindowDebuggingManager
private readonly debuggingManager: IInteractiveWindowDebuggingManager,
private readonly isWebExtension: boolean
) {
// Set our owner and first submitter
if (this._owner) {
Expand All @@ -160,6 +161,8 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
if (preferredController) {
// Also start connecting to our kernel but don't wait for it to finish
this.startKernel(preferredController.controller, preferredController.connection).ignoreErrors();
} else if (this.isWebExtension) {
this.insertInfoMessage(DataScience.noKernelsSpecifyRemote()).ignoreErrors();
}
}

Expand Down Expand Up @@ -277,9 +280,13 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
kernelMetadata: KernelConnectionMetadata,
reason: SysInfoReason
): Promise<NotebookCell> {
const message = this.getSysInfoMessage(kernelMetadata, reason);
return this.insertInfoMessage(message);
}

private async insertInfoMessage(message: string): Promise<NotebookCell> {
if (!this._insertSysInfoPromise) {
const func = async () => {
const message = this.getSysInfoMessage(kernelMetadata, reason);
await chainWithPendingUpdates(this.notebookDocument, (edit) => {
const markdownCell = new NotebookCellData(NotebookCellKind.Markup, message, MARKDOWN_LANGUAGE);
markdownCell.metadata = { isInteractiveWindowMessageCell: true, isPlaceholder: true };
Expand All @@ -293,6 +300,7 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
}
return this._insertSysInfoPromise;
}

private updateSysInfoMessage(newMessage: string, finish: boolean, cellPromise: Promise<NotebookCell>) {
if (finish) {
this._insertSysInfoPromise = undefined;
Expand Down Expand Up @@ -481,7 +489,7 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {

private async submitCodeImpl(code: string, fileUri: Uri, line: number, isDebug: boolean) {
// Do not execute or render empty cells
if (this.cellMatcher.isEmptyCell(code)) {
if (this.cellMatcher.isEmptyCell(code) || !this.currentKernelInfo.controller) {
return true;
}

Expand Down Expand Up @@ -564,10 +572,14 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
if (isDebug && (settings.forceIPyKernelDebugger || !isLocalConnection(kernel.kernelConnectionMetadata))) {
// New ipykernel 7 debugger using the Jupyter protocol.
await this.debuggingManager.start(this.notebookEditor, cell);
} else if (isDebug && isLocalConnection(kernel.kernelConnectionMetadata)) {
} else if (
isDebug &&
isLocalConnection(kernel.kernelConnectionMetadata) &&
this.interactiveWindowDebugger
) {
// Old ipykernel 6 debugger.
// If debugging attach to the kernel but don't enable tracing just yet
detachKernel = async () => this.interactiveWindowDebugger.detach(kernel);
detachKernel = async () => this.interactiveWindowDebugger?.detach(kernel);
await this.interactiveWindowDebugger.attach(kernel);
await this.interactiveWindowDebugger.updateSourceMaps(
this.storageFactory.get({ notebook: cell.notebook })?.all || []
Expand Down
6 changes: 4 additions & 2 deletions src/interactive-window/interactiveWindowProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
IDisposableRegistry,
IMemento,
InteractiveWindowMode,
IsWebExtension,
Resource
} from '../platform/common/types';
import { chainable } from '../platform/common/utils/decorators';
Expand Down Expand Up @@ -166,15 +167,16 @@ export class InteractiveWindowProvider implements IInteractiveWindowProvider, IA
this.serviceContainer.get<IExportDialog>(IExportDialog),
this.notebookControllerManager,
this.serviceContainer,
this.serviceContainer.get<IInteractiveWindowDebugger>(IInteractiveWindowDebugger),
this.serviceContainer.tryGet<IInteractiveWindowDebugger>(IInteractiveWindowDebugger),
this.serviceContainer.get<IDataScienceErrorHandler>(IDataScienceErrorHandler),
preferredController,
editor,
inputUri,
this.appShell,
this.serviceContainer.get<ICodeGeneratorFactory>(ICodeGeneratorFactory),
this.serviceContainer.get<IGeneratedCodeStorageFactory>(IGeneratedCodeStorageFactory),
this.serviceContainer.get<IInteractiveWindowDebuggingManager>(IInteractiveWindowDebuggingManager)
this.serviceContainer.get<IInteractiveWindowDebuggingManager>(IInteractiveWindowDebuggingManager),
this.serviceContainer.get<boolean>(IsWebExtension)
);
this._windows.push(result);

Expand Down
3 changes: 2 additions & 1 deletion src/notebooks/controllers/notebookControllerManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ export class NotebookControllerManager implements INotebookControllerManager, IE
? this.notebook.notebookDocuments.find((item) => item.notebookType === notebookType)
: undefined;
const controller = await this.createDefaultRemoteController(notebookType, notebook);
if (controller) {
// If we're running on web, there is no active interpreter to fall back to
if (controller || this.isWeb) {
return controller;
}
traceVerbose('No default remote controller, hence returning the active interpreter');
Expand Down
4 changes: 4 additions & 0 deletions src/platform/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,10 @@ export namespace DataScience {
);
export const connected = localize('DataScience.connected', 'Connected');
export const disconnected = localize('DataScience.disconnected', 'Disconnected');
export const noKernelsSpecifyRemote = localize(
'DataScience.noKernelsSpecifyRemote',
'No kernel available for cell execution, please [specify a Jupyter server for connections](command:jupyter.selectjupyteruri)'
);
export const ipykernelNotInstalled = localize(
'DataScience.ipykernelNotInstalled',
'IPyKernel not installed into interpreter {0}'
Expand Down
3 changes: 2 additions & 1 deletion src/test/datascience/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@
// Python experiments have to be on for insiders to work
"python.experiments.enabled": true,
"jupyter.generateSVGPlots": false,
"jupyter.forceIPyKernelDebugger": false
"jupyter.forceIPyKernelDebugger": true,
"python.defaultInterpreterPath": "python"
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ suite('DataScience Code Watcher Unit Tests', () => {
instance(notebook),
disposables,
instance(storageFactory),
instance(kernelProvider)
instance(kernelProvider),
false
);
serviceContainer
.setup((c) => c.get(TypeMoq.It.isValue(ICodeWatcher)))
Expand Down

0 comments on commit 981500b

Please sign in to comment.