Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable IW in web #10131

Merged
merged 7 commits into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -296,6 +303,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 @@ -488,7 +496,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 @@ -571,10 +579,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