to learn about notebook features",
- "StartPage.createAPythonFile": "Create a Python File",
- "StartPage.pythonFileDescription": "- Create a
new file
with a .py extension",
- "StartPage.openInteractiveWindow": "Use the Interactive Window to develop Python Scripts",
- "StartPage.interactiveWindowDesc": "- You can create cells on a Python file by typing \"#%%\". Make sure you have the Jupyter extension installed. - Use \"
Shift + Enter
\" to run a cell, the output will be shown in the interactive window",
- "StartPage.releaseNotes": "Take a look at our Release Notes to learn more about the latest features.",
- "StartPage.mailingList": "Sign up for tips and tutorials through our mailing list.",
- "StartPage.tutorialAndDoc": "Explore more features in our Tutorials or check Documentation for tips and troubleshooting.",
- "StartPage.dontShowAgain": "Don't show this page again",
- "StartPage.helloWorld": "Hello world",
- "StartPage.sampleNotebook": "Notebooks intro",
- "StartPage.openFolder": "Open a Folder or Workspace",
- "StartPage.folderDesc": "- Open a
Folder
- Open a
Workspace
",
- "StartPage.badWebPanelFormatString": "
{0} is not a valid file name
",
"Jupyter.extensionRequired": "The Jupyter extension is required to perform that task. Click Yes to open the Jupyter extension installation page.",
- "Jupyter.extensionNotInstalled": "This feature is available in the Jupyter extension, which isn't currently installed.",
"TensorBoard.missingSourceFile": "We could not locate the requested source file on disk. Please manually specify the file.",
"TensorBoard.selectMissingSourceFile": "Choose File",
"TensorBoard.selectMissingSourceFileDescription": "The source file's contents may not match the original contents in the trace.",
diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json
index a4d93c2d9b00..02fc3647ccda 100644
--- a/package.nls.zh-cn.json
+++ b/package.nls.zh-cn.json
@@ -27,7 +27,6 @@
"python.command.python.runLinting.title": "执行代码检查",
"python.command.python.enableSourceMapSupport.title": "为扩展调试启用 Source Map 支持",
"python.command.python.clearPersistentStorage.title": "清空扩展内部缓存",
- "python.command.python.startPage.open.title": "打开起始页",
"python.command.python.analysis.clearCache.title": "清除模块分析缓存",
"python.command.python.analysis.restartLanguageServer.title": "重启语言服务器",
"python.command.python.launchTensorBoard.title": "启动 TensorBoard",
@@ -205,23 +204,6 @@
"downloading.file.progress": "{2} 中的 {0}{1} KB ({3}%)",
"products.installingModule": "正在安装 {0}",
"OutdatedDebugger.updateDebuggerMessage": "您正在连接至 ptvsd (Python 调试器),而 ptvsd 已于2020年5月1日停止更新。请切换至 [debugpy](https://aka.ms/migrateToDebugpy)。",
- "StartPage.getStarted": "Python - 开始",
- "StartPage.pythonExtensionTitle": "Python 扩展",
- "StartPage.createJupyterNotebook": "创建 Jupyter 笔记本",
- "StartPage.notebookDescription": "- 在命令面板 (
",
"Jupyter.extensionRequired": "执行该任务需要 Jupyter 扩展。点击\"是 \"打开 Jupyter 扩展的安装页面。",
"Jupyter.extensionNotInstalled": "该功能需要安装 Jupyter 扩展才能使用。",
"TensorBoard.missingSourceFile": "源文件缺失,请手动定位文件。",
diff --git a/resources/report_issue_user_settings.json b/resources/report_issue_user_settings.json
index b2e45bb7b08e..8c8f6b0297a2 100644
--- a/resources/report_issue_user_settings.json
+++ b/resources/report_issue_user_settings.json
@@ -4,7 +4,6 @@
"onDidChange": false,
"defaultInterpreterPath": "placeholder",
"defaultLS": true,
- "showStartPage": true,
"downloadLanguageServer": true,
"jediPath": false,
"jediMemoryLimit": false,
@@ -38,7 +37,7 @@
"lintOnSave": true,
"maxNumberOfProblems": false,
"banditArgs": "placeholder",
- "banditEnabled" : true,
+ "banditEnabled": true,
"banditPath": "placeholder",
"mypyArgs": "placeholder",
"mypyCategorySeverity": false,
@@ -104,7 +103,7 @@
"typeshedPaths": "placeholder"
},
"workspaceSymbols": {
- "ctagsPath":"placeholder",
+ "ctagsPath": "placeholder",
"enabled": true,
"exclusionPatterns": true,
"rebuildOnFileSave": true,
diff --git a/src/client/application/diagnostics/checks/pylanceDefault.ts b/src/client/application/diagnostics/checks/pylanceDefault.ts
index 08b1ca2499e9..3ffb11830adc 100644
--- a/src/client/application/diagnostics/checks/pylanceDefault.ts
+++ b/src/client/application/diagnostics/checks/pylanceDefault.ts
@@ -4,7 +4,6 @@
// eslint-disable-next-line max-classes-per-file
import { inject, named } from 'inversify';
import { DiagnosticSeverity } from 'vscode';
-import { IStartPage } from '../../../common/startPage/types';
import { IDisposableRegistry, IExtensionContext, Resource } from '../../../common/types';
import { Diagnostics, Common } from '../../../common/utils/localize';
import { IServiceContainer } from '../../../ioc/types';
@@ -14,6 +13,7 @@ import { DiagnosticCommandPromptHandlerServiceId, MessageCommandPrompt } from '.
import { DiagnosticScope, IDiagnostic, IDiagnosticHandlerService } from '../types';
export const PYLANCE_PROMPT_MEMENTO = 'pylanceDefaultPromptMemento';
+const EXTENSION_VERSION_MEMENTO = 'extensionVersion';
export class PylanceDefaultDiagnostic extends BaseDiagnostic {
constructor(message: string, resource: Resource) {
@@ -30,16 +30,19 @@ export class PylanceDefaultDiagnostic extends BaseDiagnostic {
export const PylanceDefaultDiagnosticServiceId = 'PylanceDefaultDiagnosticServiceId';
export class PylanceDefaultDiagnosticService extends BaseDiagnosticsService {
+ public initialMementoValue: string | undefined = undefined;
+
constructor(
@inject(IServiceContainer) serviceContainer: IServiceContainer,
@inject(IExtensionContext) private readonly context: IExtensionContext,
- @inject(IStartPage) private readonly startPage: IStartPage,
@inject(IDiagnosticHandlerService)
@named(DiagnosticCommandPromptHandlerServiceId)
protected readonly messageService: IDiagnosticHandlerService,
@inject(IDisposableRegistry) disposableRegistry: IDisposableRegistry,
) {
super([DiagnosticCodes.PylanceDefaultDiagnostic], serviceContainer, disposableRegistry, true);
+
+ this.initialMementoValue = this.context.globalState.get(EXTENSION_VERSION_MEMENTO);
}
public async diagnose(resource: Resource): Promise {
@@ -73,7 +76,7 @@ export class PylanceDefaultDiagnosticService extends BaseDiagnosticsService {
}
private async shouldShowPrompt(): Promise {
- const savedVersion: string | undefined = this.startPage.initialMementoValue;
+ const savedVersion: string | undefined = this.initialMementoValue;
const promptShown: boolean | undefined = this.context.globalState.get(PYLANCE_PROMPT_MEMENTO);
// savedVersion being undefined means that this is the first time the user activates the extension,
diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts
index 6302ce01b12a..e4f98597eb3a 100644
--- a/src/client/common/application/commands.ts
+++ b/src/client/common/application/commands.ts
@@ -40,7 +40,6 @@ interface ICommandNameWithoutArgumentTypeMapping {
[Commands.Exec_Selection_In_Django_Shell]: [];
[Commands.Create_Terminal]: [];
[Commands.PickLocalProcess]: [];
- [Commands.OpenStartPage]: [];
[Commands.ClearStorage]: [];
[Commands.ReportIssue]: [];
[Commands.RefreshTensorBoard]: [];
diff --git a/src/client/common/application/types.ts b/src/client/common/application/types.ts
index 59388517417a..eac770efafa6 100644
--- a/src/client/common/application/types.ts
+++ b/src/client/common/application/types.ts
@@ -52,7 +52,6 @@ import {
UIKind,
Uri,
ViewColumn,
- WebviewPanel,
WindowState,
WorkspaceConfiguration,
WorkspaceEdit,
@@ -63,7 +62,7 @@ import {
import type { NotebookConcatTextDocument, NotebookDocument } from 'vscode-proposed';
import { Channel } from '../constants';
-import { IAsyncDisposable, Resource } from '../types';
+import { Resource } from '../types';
import { ICommandNameArgumentTypeMapping } from './commands';
import { ExtensionContextKey } from './contextKeys';
@@ -1044,119 +1043,6 @@ export interface IApplicationEnvironment {
readonly uiKind: UIKind;
}
-export interface IWebviewMessageListener {
- /**
- * Listens to webview messages
- * @param message: the message being sent
- * @param payload: extra data that came with the message
- */
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- onMessage(message: string, payload: any): void;
-}
-
-export const IWebviewPanelMessageListener = Symbol('IWebviewPanelMessageListener');
-export interface IWebviewPanelMessageListener extends IWebviewMessageListener, IAsyncDisposable {
- /**
- * Listens to web panel state changes
- */
- onChangeViewState(panel: IWebviewPanel): void;
-}
-
-export type WebviewMessage = {
- /**
- * Message type
- */
- type: string;
-
- /**
- * Payload
- */
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- payload?: any;
-};
-
-// Wraps a VS Code webview
-export const IWebview = Symbol('IWebview');
-export interface IWebview {
- /**
- * Sends a message to the hosted html page
- */
- postMessage(message: WebviewMessage): void;
- /**
- * Convert a uri for the local file system to one that can be used inside webviews.
- *
- * Webviews cannot directly load resources from the workspace or local file system using `file:` uris. The
- * `asWebviewUri` function takes a local `file:` uri and converts it into a uri that can be used inside of
- * a webview to load the same resource:
- *
- * ```ts
- * webview.html = ``
- * ```
- */
- asWebviewUri(localResource: Uri): Uri;
-}
-
-// Wraps the VS Code webview panel
-export const IWebviewPanel = Symbol('IWebviewPanel');
-export interface IWebviewPanel extends IWebview {
- /**
- * Event is fired when the load for a web panel fails
- */
- readonly loadFailed: Event;
- setTitle(val: string): void;
- /**
- * Makes the webpanel show up.
- * @return A Promise that can be waited on
- */
- show(preserveFocus: boolean): Promise;
-
- /**
- * Indicates if this web panel is visible or not.
- */
- isVisible(): boolean;
-
- /**
- * Attempts to close the panel if it's visible
- */
- close(): void;
- /**
- * Indicates if the webview has the focus or not.
- */
- isActive(): boolean;
- /**
- * Updates the current working directory for serving up files.
- * @param cwd
- */
- updateCwd(cwd: string): void;
-}
-
-export interface IWebviewOptions {
- rootPath: string;
- cwd: string;
- scripts: string[];
-}
-
-export interface IWebviewPanelOptions extends IWebviewOptions {
- viewColumn: ViewColumn;
- listener: IWebviewPanelMessageListener;
- title: string;
- /**
- * Additional paths apart from cwd and rootPath, that webview would allow loading resources/files from.
- * E.g. required for webview to serve images from worksapces when nb is in a nested folder.
- */
- additionalPaths?: string[];
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- settings?: any;
- // Web panel to use if supplied by VS code instead
- webViewPanel?: WebviewPanel;
-}
-
-// Wraps the VS Code api for creating a web panel
-export const IWebviewPanelProvider = Symbol('IWebviewPanelProvider');
-export interface IWebviewPanelProvider {
- create(options: IWebviewPanelOptions): Promise;
-}
-
export const ILanguageService = Symbol('ILanguageService');
export interface ILanguageService {
/**
@@ -1188,287 +1074,6 @@ export interface IActiveResourceService {
getActiveResource(): Resource;
}
-// Temporary hack to get the nyc compiler to find these types. vscode.proposed.d.ts doesn't work for some reason.
-
-// #region Custom editor https://github.com/microsoft/vscode/issues/77131
-
-/**
- * Represents a custom document used by a [`CustomEditorProvider`](#CustomEditorProvider).
- *
- * Custom documents are only used within a given `CustomEditorProvider`. The lifecycle of a `CustomDocument` is
- * managed by VS Code. When no more references remain to a `CustomDocument`, it is disposed of.
- */
-export interface CustomDocument {
- /**
- * The associated uri for this document.
- */
- readonly uri: Uri;
-
- /**
- * Dispose of the custom document.
- *
- * This is invoked by VS Code when there are no more references to a given `CustomDocument` (for example when
- * all editors associated with the document have been closed.)
- */
- dispose(): void;
-}
-
-/**
- * Event triggered by extensions to signal to VS Code that an edit has occurred on an [`CustomDocument`](#CustomDocument).
- *
- * @see [`CustomDocumentProvider.onDidChangeCustomDocument`](#CustomDocumentProvider.onDidChangeCustomDocument).
- */
-export interface CustomDocumentEditEvent {
- /**
- * The document that the edit is for.
- */
- readonly document: T;
-
- /**
- * Display name describing the edit.
- *
- * This is shown in the UI to users.
- */
- readonly label?: string;
-
- /**
- * Undo the edit operation.
- *
- * This is invoked by VS Code when the user undoes this edit. To implement `undo`, your
- * extension should restore the document and editor to the state they were in just before this
- * edit was added to VS Code's internal edit stack by `onDidChangeCustomDocument`.
- */
- undo(): Thenable | void;
-
- /**
- * Redo the edit operation.
- *
- * This is invoked by VS Code when the user redoes this edit. To implement `redo`, your
- * extension should restore the document and editor to the state they were in just after this
- * edit was added to VS Code's internal edit stack by `onDidChangeCustomDocument`.
- */
- redo(): Thenable | void;
-}
-
-/**
- * Event triggered by extensions to signal to VS Code that the content of a [`CustomDocument`](#CustomDocument)
- * has changed.
- *
- * @see [`CustomDocumentProvider.onDidChangeCustomDocument`](#CustomDocumentProvider.onDidChangeCustomDocument).
- */
-export interface CustomDocumentContentChangeEvent {
- /**
- * The document that the change is for.
- */
- readonly document: T;
-}
-
-/**
- * A backup for an [`CustomDocument`](#CustomDocument).
- */
-export interface CustomDocumentBackup {
- /**
- * Unique identifier for the backup.
- *
- * This id is passed back to your extension in `openCustomDocument` when opening a custom editor from a backup.
- */
- readonly id: string;
-
- /**
- * Delete the current backup.
- *
- * This is called by VS Code when it is clear the current backup is no longer needed, such as when a new backup
- * is made or when the file is saved.
- */
- delete(): void;
-}
-
-/**
- * Additional information used to implement [`CustomEditableDocument.backup`](#CustomEditableDocument.backup).
- */
-export interface CustomDocumentBackupContext {
- /**
- * Suggested file location to write the new backup.
- *
- * Note that your extension is free to ignore this and use its own strategy for backup.
- *
- * For editors for workspace resource, this destination will be in the workspace storage. The path may not
- */
- readonly destination: Uri;
-}
-
-/**
- * Additional information about the opening custom document.
- */
-export interface CustomDocumentOpenContext {
- /**
- * The id of the backup to restore the document from or `undefined` if there is no backup.
- *
- * If this is provided, your extension should restore the editor from the backup instead of reading the file
- * the user's workspace.
- */
- readonly backupId?: string;
-}
-
-/**
- * Provider for readonly custom editors that use a custom document model.
- *
- * Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument).
- *
- * You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple
- * text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead.
- *
- * @param T Type of the custom document returned by this provider.
- */
-export interface CustomReadonlyEditorProvider {
- /**
- * Create a new document for a given resource.
- *
- * `openCustomDocument` is called when the first editor for a given resource is opened, and the resolve document
- * is passed to `resolveCustomEditor`. The resolved `CustomDocument` is re-used for subsequent editor opens.
- * If all editors for a given resource are closed, the `CustomDocument` is disposed of. Opening an editor at
- * this point will trigger another call to `openCustomDocument`.
- *
- * @param uri Uri of the document to open.
- * @param openContext Additional information about the opening custom document.
- * @param token A cancellation token that indicates the result is no longer needed.
- *
- * @return The custom document.
- */
- openCustomDocument(uri: Uri, openContext: CustomDocumentOpenContext, token: CancellationToken): Thenable | T;
-
- /**
- * Resolve a custom editor for a given resource.
- *
- * This is called whenever the user opens a new editor for this `CustomEditorProvider`.
- *
- * To resolve a custom editor, the provider must fill in its initial html content and hook up all
- * the event listeners it is interested it. The provider can also hold onto the `WebviewPanel` to use later,
- * for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details.
- *
- * @param document Document for the resource being resolved.
- * @param webviewPanel Webview to resolve.
- * @param token A cancellation token that indicates the result is no longer needed.
- *
- * @return Optional thenable indicating that the custom editor has been resolved.
- */
- resolveCustomEditor(document: T, webviewPanel: WebviewPanel, token: CancellationToken): Thenable | void;
-}
-
-/**
- * Provider for editiable custom editors that use a custom document model.
- *
- * Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument).
- * This gives extensions full control over actions such as edit, save, and backup.
- *
- * You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple
- * text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead.
- *
- * @param T Type of the custom document returned by this provider.
- */
-export interface CustomEditorProvider
- extends CustomReadonlyEditorProvider {
- /**
- * Signal that an edit has occurred inside a custom editor.
- *
- * This event must be fired by your extension whenever an edit happens in a custom editor. An edit can be
- * anything from changing some text, to cropping an image, to reordering a list. Your extension is free to
- * define what an edit is and what data is stored on each edit.
- *
- * Firing `onDidChange` causes VS Code to mark the editors as being dirty. This is cleared when the user either
- * saves or reverts the file.
- *
- * Editors that support undo/redo must fire a `CustomDocumentEditEvent` whenever an edit happens. This allows
- * users to undo and redo the edit using VS Code's standard VS Code keyboard shortcuts. VS Code will also mark
- * the editor as no longer being dirty if the user undoes all edits to the last saved state.
- *
- * Editors that support editing but cannot use VS Code's standard undo/redo mechanism must fire a `CustomDocumentContentChangeEvent`.
- * The only way for a user to clear the dirty state of an editor that does not support undo/redo is to either
- * `save` or `revert` the file.
- *
- * An editor should only ever fire `CustomDocumentEditEvent` events, or only ever fire `CustomDocumentContentChangeEvent` events.
- */
- readonly onDidChangeCustomDocument: Event> | Event>;
-
- /**
- * Save a custom document.
- *
- * This method is invoked by VS Code when the user saves a custom editor. This can happen when the user
- * triggers save while the custom editor is active, by commands such as `save all`, or by auto save if enabled.
- *
- * To implement `save`, the implementer must persist the custom editor. This usually means writing the
- * file data for the custom document to disk. After `save` completes, any associated editor instances will
- * no longer be marked as dirty.
- *
- * @param document Document to save.
- * @param cancellation Token that signals the save is no longer required (for example, if another save was triggered).
- *
- * @return Thenable signaling that saving has completed.
- */
- saveCustomDocument(document: T, cancellation: CancellationToken): Thenable;
-
- /**
- * Save a custom document to a different location.
- *
- * This method is invoked by VS Code when the user triggers 'save as' on a custom editor. The implementer must
- * persist the custom editor to `destination`.
- *
- * When the user accepts save as, the current editor is be replaced by an non-dirty editor for the newly saved file.
- *
- * @param document Document to save.
- * @param destination Location to save to.
- * @param cancellation Token that signals the save is no longer required.
- *
- * @return Thenable signaling that saving has completed.
- */
- saveCustomDocumentAs(document: T, destination: Uri, cancellation: CancellationToken): Thenable;
-
- /**
- * Revert a custom document to its last saved state.
- *
- * This method is invoked by VS Code when the user triggers `File: Revert File` in a custom editor. (Note that
- * this is only used using VS Code's `File: Revert File` command and not on a `git revert` of the file).
- *
- * To implement `revert`, the implementer must make sure all editor instances (webviews) for `document`
- * are displaying the document in the same state is saved in. This usually means reloading the file from the
- * workspace.
- *
- * @param document Document to revert.
- * @param cancellation Token that signals the revert is no longer required.
- *
- * @return Thenable signaling that the change has completed.
- */
- revertCustomDocument(document: T, cancellation: CancellationToken): Thenable;
-
- /**
- * Back up a dirty custom document.
- *
- * Backups are used for hot exit and to prevent data loss. Your `backup` method should persist the resource in
- * its current state, i.e. with the edits applied. Most commonly this means saving the resource to disk in
- * the `ExtensionContext.storagePath`. When VS Code reloads and your custom editor is opened for a resource,
- * your extension should first check to see if any backups exist for the resource. If there is a backup, your
- * extension should load the file contents from there instead of from the resource in the workspace.
- *
- * `backup` is triggered whenever an edit it made. Calls to `backup` are debounced so that if multiple edits are
- * made in quick succession, `backup` is only triggered after the last one. `backup` is not invoked when
- * `auto save` is enabled (since auto save already persists resource ).
- *
- * @param document Document to backup.
- * @param context Information that can be used to backup the document.
- * @param cancellation Token that signals the current backup since a new backup is coming in. It is up to your
- * extension to decided how to respond to cancellation. If for example your extension is backing up a large file
- * in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather
- * than cancelling it to ensure that VS Code has some valid backup.
- */
- backupCustomDocument(
- document: T,
- context: CustomDocumentBackupContext,
- cancellation: CancellationToken,
- ): Thenable;
-}
-
-// #endregion
-
export const IClipboard = Symbol('IClipboard');
export interface IClipboard {
/**
diff --git a/src/client/common/application/webviewPanels/webviewPanel.ts b/src/client/common/application/webviewPanels/webviewPanel.ts
deleted file mode 100644
index 6413e6a66026..000000000000
--- a/src/client/common/application/webviewPanels/webviewPanel.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-/* eslint-disable */
-'use strict';
-import '../../extensions';
-
-import { Event, EventEmitter, Uri, WebviewOptions, WebviewPanel as vscodeWebviewPanel, window } from 'vscode';
-import { traceError } from '../../logger';
-import { IFileSystem } from '../../platform/types';
-import { IDisposableRegistry } from '../../types';
-import * as localize from '../../utils/localize';
-import { IWebviewPanel, IWebviewPanelOptions } from '../types';
-import { Webview } from '../webviews/webview';
-
-export class WebviewPanel extends Webview implements IWebviewPanel {
- private panel: vscodeWebviewPanel | undefined;
- private loadPromise: Promise;
- private loadFailedEmitter = new EventEmitter();
-
- constructor(
- fs: IFileSystem,
- private disposableRegistry: IDisposableRegistry,
- private panelOptions: IWebviewPanelOptions,
- additionalRootPaths: Uri[] = [],
- ) {
- super(fs, panelOptions);
-
- const webViewOptions: WebviewOptions = {
- enableScripts: true,
- localResourceRoots: [
- Uri.file(this.panelOptions.rootPath),
- Uri.file(this.panelOptions.cwd),
- ...additionalRootPaths,
- ],
- };
- if (panelOptions.webViewPanel) {
- this.panel = panelOptions.webViewPanel;
- this.panel.webview.options = webViewOptions;
- } else {
- this.panel = window.createWebviewPanel(
- panelOptions.title.toLowerCase().replace(' ', ''),
- panelOptions.title,
- { viewColumn: panelOptions.viewColumn, preserveFocus: true },
- {
- retainContextWhenHidden: true,
- enableFindWidget: true,
- ...webViewOptions,
- },
- );
- }
-
- // Set our base webview from the panel
- this.webview = this.panel.webview;
-
- this.loadPromise = this.load();
- }
-
- public get loadFailed(): Event {
- return this.loadFailedEmitter.event;
- }
- public async show(preserveFocus: boolean) {
- await this.loadPromise;
- if (this.panel) {
- this.panel.reveal(this.panel.viewColumn, preserveFocus);
- }
- }
-
- public updateCwd(_cwd: string) {
- // See issue https://github.com/microsoft/vscode-python/issues/8933 for implementing this.
- }
-
- public close() {
- if (this.panel) {
- this.panel.dispose();
- }
- }
-
- public isVisible(): boolean {
- return this.panel ? this.panel.visible : false;
- }
-
- public isActive(): boolean {
- return this.panel ? this.panel.active : false;
- }
-
- public setTitle(newTitle: string) {
- this.panelOptions.title = newTitle;
- if (this.panel) {
- this.panel.title = newTitle;
- }
- }
-
- private async load() {
- try {
- if (this.panel) {
- const localFilesExist = await Promise.all(this.panelOptions.scripts.map((s) => this.fs.fileExists(s)));
- if (localFilesExist.every((exists) => exists === true)) {
- // Call our special function that sticks this script inside of an html page
- // and translates all of the paths to vscode-resource URIs
- this.panel.webview.html = await this.generateLocalReactHtml();
-
- // Reset when the current panel is closed
- this.disposableRegistry.push(
- this.panel.onDidDispose(() => {
- this.panel = undefined;
- this.panelOptions.listener.dispose().ignoreErrors();
- }),
- );
-
- this.disposableRegistry.push(
- this.panel.webview.onDidReceiveMessage((message) => {
- // Pass the message onto our listener
- this.panelOptions.listener.onMessage(message.type, message.payload);
- }),
- );
-
- this.disposableRegistry.push(
- this.panel.onDidChangeViewState((_e) => {
- // Pass the state change onto our listener
- this.panelOptions.listener.onChangeViewState(this);
- }),
- );
-
- // Set initial state
- this.panelOptions.listener.onChangeViewState(this);
- } else {
- // Indicate that we can't load the file path
- const badPanelString = localize.StartPage.badWebPanelFormatString();
- this.panel.webview.html = badPanelString.format(this.panelOptions.scripts.join(', '));
- }
- }
- } catch (error) {
- // If our web panel failes to load, report that out so whatever
- // is hosting the panel can clean up
- traceError(`Error Loading WebPanel: ${error}`);
- this.loadFailedEmitter.fire();
- }
- }
-}
diff --git a/src/client/common/application/webviewPanels/webviewPanelProvider.ts b/src/client/common/application/webviewPanels/webviewPanelProvider.ts
deleted file mode 100644
index 68207bb6b3fc..000000000000
--- a/src/client/common/application/webviewPanels/webviewPanelProvider.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-import { inject, injectable } from 'inversify';
-import * as path from 'path';
-import { Uri } from 'vscode';
-import { IFileSystem } from '../../platform/types';
-import { IDisposableRegistry, IExtensionContext } from '../../types';
-import { IWebviewPanel, IWebviewPanelOptions, IWebviewPanelProvider } from '../types';
-import { WebviewPanel } from './webviewPanel';
-
-@injectable()
-export class WebviewPanelProvider implements IWebviewPanelProvider {
- constructor(
- @inject(IDisposableRegistry) private readonly disposableRegistry: IDisposableRegistry,
- @inject(IFileSystem) private readonly fs: IFileSystem,
- @inject(IExtensionContext) private readonly context: IExtensionContext,
- ) {}
-
- public async create(options: IWebviewPanelOptions): Promise {
- // Allow loading resources from the `/tmp` folder when in webiviews.
- // Used by widgets to place files that are not otherwise accessible.
- const additionalRootPaths = [Uri.file(path.join(this.context.extensionPath, 'tmp'))];
- if (Array.isArray(options.additionalPaths)) {
- additionalRootPaths.push(...options.additionalPaths.map((item) => Uri.file(item)));
- }
- return new WebviewPanel(this.fs, this.disposableRegistry, options, additionalRootPaths);
- }
-}
diff --git a/src/client/common/application/webviews/webview.ts b/src/client/common/application/webviews/webview.ts
deleted file mode 100644
index df675d1d396f..000000000000
--- a/src/client/common/application/webviews/webview.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-import '../../extensions';
-
-import * as path from 'path';
-import { Uri, Webview as vscodeWebview } from 'vscode';
-import { IFileSystem } from '../../platform/types';
-import { IWebview, IWebviewOptions, WebviewMessage } from '../types';
-
-// Wrapper over a vscode webview. To be used with either WebviewPanel or WebviewView
-export class Webview implements IWebview {
- protected webview?: vscodeWebview;
-
- constructor(protected fs: IFileSystem, protected options: IWebviewOptions) {}
-
- public asWebviewUri(localResource: Uri): Uri {
- if (!this.webview) {
- throw new Error('WebView not initialized, too early to get a Uri');
- }
- return this.webview.asWebviewUri(localResource);
- }
-
- public postMessage(message: WebviewMessage): void {
- if (this.webview) {
- this.webview.postMessage(message);
- }
- }
-
- protected async generateLocalReactHtml(): Promise {
- let webview: vscodeWebview;
- if (!this.webview) {
- throw new Error('WebView not initialized, too early to get a Uri');
- } else {
- webview = this.webview;
- }
-
- const uriBase = this.webview.asWebviewUri(Uri.file(this.options.cwd)).toString();
- const uris = this.options.scripts.map((script) => webview.asWebviewUri(Uri.file(script))); // NOSONAR
- const testFiles = await this.fs.getFiles(this.options.rootPath);
-
- // This method must be called so VSC is aware of files that can be pulled.
- // Allow js and js.map files to be loaded by webpack in the webview.
- testFiles
- .filter((f) => f.toLowerCase().endsWith('.js') || f.toLowerCase().endsWith('.js.map'))
- .forEach((f) => webview.asWebviewUri(Uri.file(f)));
-
- const rootPath = webview.asWebviewUri(Uri.file(this.options.rootPath)).toString();
- const fontAwesomePath = webview
- .asWebviewUri(
- Uri.file(
- path.join(this.options.rootPath, 'node_modules', 'font-awesome', 'css', 'font-awesome.min.css'),
- ),
- )
- .toString();
- return `
-
-
-
-
-
-
- VS Code Python React UI
-
-
-
-
-
-
-
- ${uris.map((uri) => ``).join('\n')}
-
- `;
- }
-}
diff --git a/src/client/common/configSettings.ts b/src/client/common/configSettings.ts
index 15239764306c..07437327635a 100644
--- a/src/client/common/configSettings.ts
+++ b/src/client/common/configSettings.ts
@@ -92,8 +92,6 @@ export class PythonSettings implements IPythonSettings {
private static pythonSettings: Map = new Map();
- public showStartPage = true;
-
public downloadLanguageServer = true;
public jediPath = '';
@@ -581,11 +579,6 @@ export class PythonSettings implements IPythonSettings {
optOutFrom: [],
};
- const showStartPage = pythonSettings.get('showStartPage');
- if (showStartPage !== undefined) {
- this.showStartPage = showStartPage;
- }
-
this.insidersChannel = pythonSettings.get('insidersChannel')!;
this.tensorBoard = pythonSettings.get('tensorBoard');
}
diff --git a/src/client/common/constants.ts b/src/client/common/constants.ts
index 62a6d6051716..288e4a71ebb2 100644
--- a/src/client/common/constants.ts
+++ b/src/client/common/constants.ts
@@ -57,7 +57,6 @@ export namespace Commands {
export const GetSelectedInterpreterPath = 'python.interpreterPath';
export const ClearStorage = 'python.clearPersistentStorage';
export const ClearWorkspaceInterpreter = 'python.clearWorkspaceInterpreter';
- export const OpenStartPage = 'python.startPage.open';
export const LaunchTensorBoard = 'python.launchTensorBoard';
export const RefreshTensorBoard = 'python.refreshTensorBoard';
export const ReportIssue = 'python.reportIssue';
@@ -95,8 +94,6 @@ export function isUnitTestExecution(): boolean {
return process.env.VSC_PYTHON_UNIT_TEST === '1';
}
-// Temporary constant, used to indicate whether we're using custom editor api or not.
-export const UseCustomEditorApi = Symbol('USE_CUSTOM_EDITOR');
export const UseProposedApi = Symbol('USE_VSC_PROPOSED_API');
export * from '../constants';
diff --git a/src/client/common/installer/serviceRegistry.ts b/src/client/common/installer/serviceRegistry.ts
index a7c7dee08866..539d448698e2 100644
--- a/src/client/common/installer/serviceRegistry.ts
+++ b/src/client/common/installer/serviceRegistry.ts
@@ -3,8 +3,6 @@
'use strict';
import { IServiceManager } from '../../ioc/types';
-import { IWebviewPanelProvider } from '../application/types';
-import { WebviewPanelProvider } from '../application/webviewPanels/webviewPanelProvider';
import { ProductType } from '../types';
import { InstallationChannelManager } from './channelManager';
import { CondaInstaller } from './condaInstaller';
@@ -75,5 +73,4 @@ export function registerTypes(serviceManager: IServiceManager) {
DataScienceProductPathService,
ProductType.DataScience,
);
- serviceManager.addSingleton(IWebviewPanelProvider, WebviewPanelProvider);
}
diff --git a/src/client/common/serviceRegistry.ts b/src/client/common/serviceRegistry.ts
index 9f5b79b61d5d..ec5fbdebfde8 100644
--- a/src/client/common/serviceRegistry.ts
+++ b/src/client/common/serviceRegistry.ts
@@ -89,10 +89,6 @@ import { PathUtils } from './platform/pathUtils';
import { CurrentProcess } from './process/currentProcess';
import { ProcessLogger } from './process/logger';
import { IProcessLogger } from './process/types';
-import { CodeCssGenerator } from './startPage/codeCssGenerator';
-import { StartPage } from './startPage/startPage';
-import { ThemeFinder } from './startPage/themeFinder';
-import { ICodeCssGenerator, IStartPage, IThemeFinder } from './startPage/types';
import { TerminalActivator } from './terminal/activator';
import { PowershellTerminalActivationFailedHandler } from './terminal/activator/powershellFailedHandler';
import { Bash } from './terminal/environmentActivationProviders/bash';
@@ -118,8 +114,6 @@ import {
import { IMultiStepInputFactory, MultiStepInputFactory } from './utils/multiStepInput';
import { Random } from './utils/random';
-import { JupyterNotInstalledNotificationHelper } from '../jupyter/jupyterNotInstalledNotificationHelper';
-import { IJupyterNotInstalledNotificationHelper } from '../jupyter/types';
import { InterpreterPathProxyService } from './interpreterPathProxyService';
import { ContextKeyManager } from './application/contextKeyManager';
@@ -147,10 +141,6 @@ export function registerTypes(serviceManager: IServiceManager): void {
IJupyterExtensionDependencyManager,
JupyterExtensionDependencyManager,
);
- serviceManager.addSingleton(
- IJupyterNotInstalledNotificationHelper,
- JupyterNotInstalledNotificationHelper,
- );
serviceManager.addSingleton(ICommandManager, CommandManager);
serviceManager.addSingleton(IContextKeyManager, ContextKeyManager);
serviceManager.addSingleton(IConfigurationService, ConfigurationService);
@@ -243,7 +233,4 @@ export function registerTypes(serviceManager: IServiceManager): void {
IExtensionSingleActivationService,
DebugSessionTelemetry,
);
- serviceManager.addSingleton(IStartPage, StartPage, undefined, [IExtensionSingleActivationService]);
- serviceManager.addSingleton(ICodeCssGenerator, CodeCssGenerator);
- serviceManager.addSingleton(IThemeFinder, ThemeFinder);
}
diff --git a/src/client/common/startPage/codeCssGenerator.ts b/src/client/common/startPage/codeCssGenerator.ts
deleted file mode 100644
index 270c1f201783..000000000000
--- a/src/client/common/startPage/codeCssGenerator.ts
+++ /dev/null
@@ -1,507 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-import { inject, injectable } from 'inversify';
-import { parse } from 'jsonc-parser';
-import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';
-import * as path from 'path';
-import { IWorkspaceService } from '../application/types';
-import { traceError, traceInfo, traceWarning } from '../logger';
-
-import { IFileSystem } from '../platform/types';
-import { ICodeCssGenerator, IThemeFinder, JSONArray, JSONObject } from './types';
-
-const DarkTheme = 'dark';
-const LightTheme = 'light';
-
-const MonacoColorRegEx = /^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;
-const ThreeColorRegEx = /^#?([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/;
-
-// These are based on the colors generated by 'Default Light+' and are only set when we
-// are ignoring themes.
-
-const DefaultCssVars: { [key: string]: string } = {
- light: `
- :root {
- --override-widget-background: #f3f3f3;
- --override-foreground: #000000;
- --override-background: #FFFFFF;
- --override-selection-background: #add6ff;
- --override-watermark-color: rgba(66, 66, 66, 0.75);
- --override-tabs-background: #f3f3f3;
- --override-progress-background: #0066bf;
- --override-badge-background: #c4c4c4;
- --override-lineHighlightBorder: #eeeeee;
- --override-peek-background: #f2f8fc;
- }
-`,
- dark: `
- :root {
- --override-widget-background: #1e1e1e;
- --override-foreground: #d4d4d4;
- --override-background: #1e1e1e;
- --override-selection-background: #264f78;
- --override-watermark-color: rgba(231, 231, 231, 0.6);
- --override-tabs-background: #252526;
- --override-progress-background: #0066bf;
- --override-badge-background: #4d4d4d;
- --override-lineHighlightBorder: #282828;
- --override-peek-background: #001f33;
- }
-`,
-};
-
-// These colors below should match colors that come from either the Default Light+ theme or the Default Dark+ theme.
-// They are used when we can't find a theme json file.
-const DefaultColors: { [key: string]: string } = {
- 'light.comment': '#008000',
- 'light.constant.numeric': '#09885a',
- 'light.string': '#a31515',
- 'light.keyword.control': '#AF00DB',
- 'light.keyword.operator': '#000000',
- 'light.variable': '#001080',
- 'light.entity.name.type': '#267f99',
- 'light.support.function': '#795E26',
- 'light.punctuation': '#000000',
- 'dark.comment': '#6A9955',
- 'dark.constant.numeric': '#b5cea8',
- 'dark.string': '#ce9178',
- 'dark.keyword.control': '#C586C0',
- 'dark.keyword.operator': '#d4d4d4',
- 'dark.variable': '#9CDCFE',
- 'dark.entity.name.type': '#4EC9B0',
- 'dark.support.function': '#DCDCAA',
- 'dark.punctuation': '#1e1e1e',
-};
-
-interface IApplyThemeArgs {
- tokenColors?: JSONArray | null;
- baseColors?: JSONObject | null;
- fontFamily: string;
- fontSize: number;
- isDark: boolean;
- defaultStyle: string | undefined;
-}
-
-// This class generates css using the current theme in order to colorize code.
-//
-// NOTE: This is all a big hack. It's relying on the theme json files to have a certain format
-// in order for this to work.
-// See this vscode issue for the real way we think this should happen:
-// https://github.com/Microsoft/vscode/issues/32813
-@injectable()
-export class CodeCssGenerator implements ICodeCssGenerator {
- constructor(
- @inject(IWorkspaceService) private workspaceService: IWorkspaceService,
- @inject(IThemeFinder) private themeFinder: IThemeFinder,
- @inject(IFileSystem) private fs: IFileSystem,
- ) {}
-
- public generateThemeCss(isDark: boolean, theme: string): Promise {
- return this.applyThemeData(isDark, theme, '', this.generateCss.bind(this));
- }
-
- public generateMonacoTheme(isDark: boolean, theme: string): Promise {
- return this.applyThemeData(isDark, theme, {} as any, this.generateMonacoThemeObject.bind(this));
- }
-
- private async applyThemeData(
- isDark: boolean,
- theme: string,
- defaultT: T,
- applier: (args: IApplyThemeArgs) => T,
- ): Promise {
- let result = defaultT;
- try {
- const editor = this.workspaceService.getConfiguration('editor', undefined);
- const fontFamily = editor
- ? editor.get('fontFamily', "Consolas, 'Courier New', monospace")
- : "Consolas, 'Courier New', monospace";
- const fontSize = editor ? editor.get('fontSize', 14) : 14;
- const isDarkUpdated = isDark;
-
- // Then we have to find where the theme resources are loaded from
- if (theme) {
- traceInfo('Searching for token colors ...');
- const tokenColors = await this.findTokenColors(theme);
- const baseColors = await this.findBaseColors(theme);
-
- // The tokens object then contains the necessary data to generate our css
- if (tokenColors && fontFamily && fontSize) {
- traceInfo('Using colors to generate CSS ...');
- result = applier({
- tokenColors,
- baseColors,
- fontFamily,
- fontSize,
- isDark: isDarkUpdated,
- defaultStyle: LightTheme,
- });
- } else if (tokenColors === null && fontFamily && fontSize) {
- // No colors found. See if we can figure out what type of theme we have
- const style = isDark ? DarkTheme : LightTheme;
- result = applier({
- fontFamily,
- fontSize,
- isDark: isDarkUpdated,
- defaultStyle: style,
- });
- }
- }
- } catch (err) {
- // On error don't fail, just log
- traceError(err);
- }
-
- return result;
- }
-
- private getScopes(entry: any): JSONArray {
- if (entry && entry.scope) {
- return Array.isArray(entry.scope) ? (entry.scope as JSONArray) : entry.scope.toString().split(',');
- }
- return [];
- }
-
- private matchTokenColor(tokenColors: JSONArray, scope: string): number {
- return tokenColors.findIndex((entry: any) => {
- const scopeArray = this.getScopes(entry);
- if (scopeArray.find((v) => v !== null && v !== undefined && v.toString().trim() === scope)) {
- return true;
- }
- return false;
- });
- }
-
- private getScopeStyle = (
- tokenColors: JSONArray | null | undefined,
- scope: string,
- secondary: string,
- defaultStyle: string | undefined,
- ): { color: string; fontStyle: string } => {
- // Search through the scopes on the json object
- if (tokenColors) {
- let match = this.matchTokenColor(tokenColors, scope);
- if (match < 0 && secondary) {
- match = this.matchTokenColor(tokenColors, secondary);
- }
- const found = match >= 0 ? (tokenColors[match] as any) : null;
- if (found !== null) {
- const { settings } = found;
- if (settings && settings !== null) {
- const fontStyle = settings.fontStyle ? settings.fontStyle : 'normal';
- const foreground = settings.foreground ? settings.foreground : 'var(--vscode-editor-foreground)';
-
- return { fontStyle, color: foreground };
- }
- }
- }
-
- // Default to editor foreground
- return { color: this.getDefaultColor(defaultStyle, scope), fontStyle: 'normal' };
- };
-
- private getDefaultColor(style: string | undefined, scope: string): string {
- return style
- ? DefaultColors[`${style}.${scope}`]
- : 'var(--override-foreground, var(--vscode-editor-foreground))';
- }
-
- private generateCss(args: IApplyThemeArgs): string {
- // There's a set of values that need to be found
- const commentStyle = this.getScopeStyle(args.tokenColors, 'comment', 'comment', args.defaultStyle);
- const numericStyle = this.getScopeStyle(args.tokenColors, 'constant.numeric', 'constant', args.defaultStyle);
- const stringStyle = this.getScopeStyle(args.tokenColors, 'string', 'string', args.defaultStyle);
- const variableStyle = this.getScopeStyle(args.tokenColors, 'variable', 'variable', args.defaultStyle);
- const entityTypeStyle = this.getScopeStyle(
- args.tokenColors,
- 'entity.name.type',
- 'entity.name.type',
- args.defaultStyle,
- );
-
- // Use these values to fill in our format string
- return `
-:root {
- --code-comment-color: ${commentStyle.color};
- --code-numeric-color: ${numericStyle.color};
- --code-string-color: ${stringStyle.color};
- --code-variable-color: ${variableStyle.color};
- --code-type-color: ${entityTypeStyle.color};
- --code-font-family: ${args.fontFamily};
- --code-font-size: ${args.fontSize}px;
-}
-
-${args.defaultStyle ? DefaultCssVars[args.defaultStyle] : ''}
-`;
- }
-
- // Based on this data here:
- // https://github.com/Microsoft/vscode/blob/master/src/vs/editor/standalone/common/themes.ts#L13
-
- private generateMonacoThemeObject(args: IApplyThemeArgs): monacoEditor.editor.IStandaloneThemeData {
- const result: monacoEditor.editor.IStandaloneThemeData = {
- base: args.isDark ? 'vs-dark' : 'vs',
- inherit: false,
- rules: [],
- colors: {},
- };
- // If we have token colors enumerate them and add them into the rules
- if (args.tokenColors && args.tokenColors.length) {
- const tokenSet = new Set();
- args.tokenColors.forEach((t: any) => {
- const scopes = this.getScopes(t);
- const settings = t && t.settings ? t.settings : undefined;
- if (scopes && settings) {
- scopes.forEach((s) => {
- const token = s ? s.toString() : '';
- if (!tokenSet.has(token)) {
- tokenSet.add(token);
-
- if (settings.foreground) {
- // Make sure matches the monaco requirements of having 6 values
- if (!MonacoColorRegEx.test(settings.foreground)) {
- const match = ThreeColorRegEx.exec(settings.foreground);
- if (match && match.length > 3) {
- settings.foreground = `#${match[1]}${match[1]}${match[2]}${match[2]}${match[3]}${match[3]}`;
- } else {
- settings.foreground = undefined;
- }
- }
- }
-
- if (settings.foreground) {
- result.rules.push({
- token,
- foreground: settings.foreground,
- background: settings.background,
- fontStyle: settings.fontStyle,
- });
- } else {
- result.rules.push({
- token,
- background: settings.background,
- fontStyle: settings.fontStyle,
- });
- }
-
- // Special case some items. punctuation.definition.comment doesn't seem to
- // be listed anywhere. Add it manually when we find a 'comment'
-
- if (token === 'comment') {
- result.rules.push({
- token: 'punctuation.definition.comment',
- foreground: settings.foreground,
- background: settings.background,
- fontStyle: settings.fontStyle,
- });
- }
-
- // Same for string
-
- if (token === 'string') {
- result.rules.push({
- token: 'punctuation.definition.string',
- foreground: settings.foreground,
- background: settings.background,
- fontStyle: settings.fontStyle,
- });
- }
- }
- });
- }
- });
-
- result.rules = result.rules.sort(
- (a: monacoEditor.editor.ITokenThemeRule, b: monacoEditor.editor.ITokenThemeRule) =>
- a.token.localeCompare(b.token),
- );
- } else {
- // Otherwise use our default values.
- result.base = args.defaultStyle === DarkTheme ? 'vs-dark' : 'vs';
- result.inherit = true;
-
- if (args.defaultStyle) {
- // Special case. We need rules for the comment beginning and the string beginning
- result.rules.push({
- token: 'punctuation.definition.comment',
- foreground: DefaultColors[`${args.defaultStyle}.comment`],
- });
- result.rules.push({
- token: 'punctuation.definition.string',
- foreground: DefaultColors[`${args.defaultStyle}.string`],
- });
- }
- }
- // If we have base colors enumerate them and add them to the colors
- if (args.baseColors) {
- const keys = Object.keys(args.baseColors);
- keys.forEach((k) => {
- const color = args.baseColors && args.baseColors[k] ? args.baseColors[k] : '#000000';
- result.colors[k] = color ? color.toString() : '#000000';
- });
- } // The else case here should end up inheriting.
- return result;
- }
-
- private mergeColors = (colors1: JSONArray, colors2: JSONArray): JSONArray => [...colors1, ...colors2];
-
- private mergeBaseColors = (colors1: JSONObject, colors2: JSONObject): JSONObject => ({ ...colors1, ...colors2 });
-
- private readTokenColors = async (themeFile: string): Promise => {
- try {
- const tokenContent = await this.fs.readFile(themeFile);
- const theme = parse(tokenContent);
- let tokenColors: JSONArray = [];
-
- if (typeof theme.tokenColors === 'string') {
- const style = await this.fs.readFile(theme.tokenColors);
- tokenColors = JSON.parse(style);
- } else {
- tokenColors = theme.tokenColors as JSONArray;
- }
-
- if (tokenColors && tokenColors.length > 0) {
- // This theme may include others. If so we need to combine the two together
- const include = theme ? theme.include : undefined;
- if (include) {
- const includePath = path.join(path.dirname(themeFile), include.toString());
- const includedColors = await this.readTokenColors(includePath);
- return this.mergeColors(tokenColors, includedColors);
- }
-
- // Theme is a root, don't need to include others
- return tokenColors;
- }
-
- // Might also have a 'settings' object that equates to token colors
- const settings = theme.settings as JSONArray;
- if (settings && settings.length > 0) {
- return settings;
- }
-
- return [];
- } catch (e) {
- traceError('Python Extension: Error reading custom theme', e);
- return [];
- }
- };
-
- private readBaseColors = async (themeFile: string): Promise => {
- const tokenContent = await this.fs.readFile(themeFile);
- const theme = parse(tokenContent);
- const colors = theme.colors as JSONObject;
-
- // This theme may include others. If so we need to combine the two together
- const include = theme ? theme.include : undefined;
- if (include) {
- const includePath = path.join(path.dirname(themeFile), include.toString());
- const includedColors = await this.readBaseColors(includePath);
- return this.mergeBaseColors(colors, includedColors);
- }
-
- // Theme is a root, don't need to include others
- return colors;
- };
-
- private findTokenColors = async (theme: string): Promise => {
- try {
- traceInfo('Attempting search for colors ...');
- const themeRoot = await this.themeFinder.findThemeRootJson(theme);
-
- // Use the first result if we have one
- if (themeRoot) {
- traceInfo(`Loading colors from ${themeRoot} ...`);
-
- // This should be the path to the file. Load it as a json object
- const contents = await this.fs.readFile(themeRoot);
- const json = parse(contents);
-
- // There should be a theme colors section
- const contributes = json.contributes as JSONObject;
-
- // If no contributes section, see if we have a tokenColors section. This means
- // this is a direct token colors file
- if (!contributes) {
- const tokenColors = json.tokenColors as JSONObject;
- if (tokenColors) {
- return await this.readTokenColors(themeRoot);
- }
- }
-
- // This should have a themes section
- const themes = contributes.themes as JSONArray;
-
- // One of these (it's an array), should have our matching theme entry
- const index = themes.findIndex((e: any) => e !== null && (e.id === theme || e.name === theme));
-
- const found = index >= 0 ? (themes[index] as any) : null;
- if (found !== null) {
- // Then the path entry should contain a relative path to the json file with
- // the tokens in it
- const themeFile = path.join(path.dirname(themeRoot), found.path);
- traceInfo(`Reading colors from ${themeFile}`);
- return await this.readTokenColors(themeFile);
- }
- } else {
- traceWarning(`Color theme ${theme} not found. Using default colors.`);
- }
- } catch (err) {
- // Swallow any exceptions with searching or parsing
- traceError(err);
- }
-
- // Force the colors to the defaults
- return null;
- };
-
- private findBaseColors = async (theme: string): Promise => {
- try {
- traceInfo('Attempting search for colors ...');
- const themeRoot = await this.themeFinder.findThemeRootJson(theme);
-
- // Use the first result if we have one
- if (themeRoot) {
- traceInfo(`Loading base colors from ${themeRoot} ...`);
-
- // This should be the path to the file. Load it as a json object
- const contents = await this.fs.readFile(themeRoot);
- const json = parse(contents);
-
- // There should be a theme colors section
- const contributes = json.contributes as JSONObject;
-
- // If no contributes section, see if we have a tokenColors section. This means
- // this is a direct token colors file
- if (!contributes) {
- return await this.readBaseColors(themeRoot);
- }
-
- // This should have a themes section
- const themes = contributes.themes as JSONArray;
-
- // One of these (it's an array), should have our matching theme entry
- const index = themes.findIndex((e: any) => e !== null && (e.id === theme || e.name === theme));
-
- const found = index >= 0 ? (themes[index] as any) : null;
- if (found !== null) {
- // Then the path entry should contain a relative path to the json file with
- // the tokens in it
- const themeFile = path.join(path.dirname(themeRoot), found.path);
- traceInfo(`Reading base colors from ${themeFile}`);
- return await this.readBaseColors(themeFile);
- }
- } else {
- traceWarning(`Color theme ${theme} not found. Using default colors.`);
- }
- } catch (err) {
- // Swallow any exceptions with searching or parsing
- traceError(err);
- }
-
- // Force the colors to the defaults
- return null;
- };
-}
diff --git a/src/client/common/startPage/constants.ts b/src/client/common/startPage/constants.ts
deleted file mode 100644
index 20d62d8e3a66..000000000000
--- a/src/client/common/startPage/constants.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-export const DefaultTheme = 'Default Light+';
-export const GatherExtension = 'ms-python.gather';
-
-export enum Telemetry {
- // DS_INTERNAL and DATASCIENCE names must be preserved to maintain telemetry continuity
- ShiftEnterBannerShown = 'DS_INTERNAL.SHIFTENTER_BANNER_SHOWN',
- EnableInteractiveShiftEnter = 'DATASCIENCE.ENABLE_INTERACTIVE_SHIFT_ENTER',
- DisableInteractiveShiftEnter = 'DATASCIENCE.DISABLE_INTERACTIVE_SHIFT_ENTER',
- WebviewStartup = 'DS_INTERNAL.WEBVIEW_STARTUP',
- WebviewStyleUpdate = 'DS_INTERNAL.WEBVIEW_STYLE_UPDATE',
- WebviewMonacoStyleUpdate = 'DS_INTERNAL.WEBVIEW_MONACO_STYLE_UPDATE',
- StartPageViewed = 'DS_INTERNAL.STARTPAGE_VIEWED',
- StartPageOpenedFromCommandPalette = 'DS_INTERNAL.STARTPAGE_OPENED_FROM_COMMAND_PALETTE',
- StartPageOpenedFromNewInstall = 'DS_INTERNAL.STARTPAGE_OPENED_FROM_NEW_INSTALL',
- StartPageOpenedFromNewUpdate = 'DS_INTERNAL.STARTPAGE_OPENED_FROM_NEW_UPDATE',
- StartPageWebViewError = 'DS_INTERNAL.STARTPAGE_WEBVIEWERROR',
- StartPageTime = 'DS_INTERNAL.STARTPAGE_TIME',
- StartPageClickedDontShowAgain = 'DATASCIENCE.STARTPAGE_DONT_SHOW_AGAIN',
- StartPageClosedWithoutAction = 'DATASCIENCE.STARTPAGE_CLOSED_WITHOUT_ACTION',
- StartPageUsedAnActionOnFirstTime = 'DATASCIENCE.STARTPAGE_USED_ACTION_ON_FIRST_TIME',
- StartPageOpenBlankNotebook = 'DATASCIENCE.STARTPAGE_OPEN_BLANK_NOTEBOOK',
- StartPageOpenBlankPythonFile = 'DATASCIENCE.STARTPAGE_OPEN_BLANK_PYTHON_FILE',
- StartPageOpenInteractiveWindow = 'DATASCIENCE.STARTPAGE_OPEN_INTERACTIVE_WINDOW',
- StartPageOpenCommandPalette = 'DATASCIENCE.STARTPAGE_OPEN_COMMAND_PALETTE',
- StartPageOpenCommandPaletteWithOpenNBSelected = 'DATASCIENCE.STARTPAGE_OPEN_COMMAND_PALETTE_WITH_OPENNBSELECTED',
- StartPageOpenSampleNotebook = 'DATASCIENCE.STARTPAGE_OPEN_SAMPLE_NOTEBOOK',
- StartPageOpenFileBrowser = 'DATASCIENCE.STARTPAGE_OPEN_FILE_BROWSER',
- StartPageOpenFolder = 'DATASCIENCE.STARTPAGE_OPEN_FOLDER',
- StartPageOpenWorkspace = 'DATASCIENCE.STARTPAGE_OPEN_WORKSPACE',
-}
diff --git a/src/client/common/startPage/messages.ts b/src/client/common/startPage/messages.ts
deleted file mode 100644
index 66eba958f8ff..000000000000
--- a/src/client/common/startPage/messages.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-export enum CssMessages {
- GetCssRequest = 'get_css_request',
- GetCssResponse = 'get_css_response',
- GetMonacoThemeRequest = 'get_monaco_theme_request',
- GetMonacoThemeResponse = 'get_monaco_theme_response',
-}
-
-export enum SharedMessages {
- UpdateSettings = 'update_settings',
- Started = 'started',
- LocInit = 'loc_init',
- StyleUpdate = 'style_update',
-}
-
-export interface IGetCssRequest {
- isDark: boolean;
-}
-
-export interface IGetMonacoThemeRequest {
- isDark: boolean;
-}
-
-export interface IGetCssResponse {
- css: string;
- theme: string;
- knownDark?: boolean;
-}
diff --git a/src/client/common/startPage/startPage.ts b/src/client/common/startPage/startPage.ts
deleted file mode 100644
index 00dc7bd773eb..000000000000
--- a/src/client/common/startPage/startPage.ts
+++ /dev/null
@@ -1,353 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-import { inject, injectable, named } from 'inversify';
-import * as path from 'path';
-import { ConfigurationTarget, EventEmitter, UIKind, Uri, ViewColumn } from 'vscode';
-import { IExtensionSingleActivationService } from '../../activation/types';
-import { EXTENSION_ROOT_DIR } from '../../constants';
-import { IJupyterNotInstalledNotificationHelper, JupyterNotInstalledOrigin } from '../../jupyter/types';
-import { sendTelemetryEvent } from '../../telemetry';
-import {
- IApplicationEnvironment,
- IApplicationShell,
- ICommandManager,
- IDocumentManager,
- IJupyterExtensionDependencyManager,
- IWebviewPanelProvider,
- IWorkspaceService,
-} from '../application/types';
-import { CommandSource, STANDARD_OUTPUT_CHANNEL } from '../constants';
-import { IFileSystem } from '../platform/types';
-import { IConfigurationService, IExtensionContext, IOutputChannel, Resource } from '../types';
-import * as localize from '../utils/localize';
-import { Jupyter } from '../utils/localize';
-import { StopWatch } from '../utils/stopWatch';
-import { Telemetry } from './constants';
-import { StartPageMessageListener } from './startPageMessageListener';
-import { ICodeCssGenerator, IStartPage, IStartPageMapping, IThemeFinder, StartPageMessages } from './types';
-import { WebviewPanelHost } from './webviewPanelHost';
-
-const startPageDir = path.join(EXTENSION_ROOT_DIR, 'out', 'startPage-ui', 'viewers');
-
-export const EXTENSION_VERSION_MEMENTO = 'extensionVersion';
-
-// Class that opens, disposes and handles messages and actions for the Python Extension Start Page.
-// It also runs when the extension activates.
-@injectable()
-export class StartPage extends WebviewPanelHost
- implements IStartPage, IExtensionSingleActivationService {
- protected closedEvent: EventEmitter = new EventEmitter();
-
- private timer: StopWatch;
-
- private actionTaken = false;
-
- private actionTakenOnFirstTime = false;
-
- private firstTime = false;
-
- private webviewDidLoad = false;
-
- public initialMementoValue: string | undefined = undefined;
-
- constructor(
- @inject(IWebviewPanelProvider) provider: IWebviewPanelProvider,
- @inject(ICodeCssGenerator) cssGenerator: ICodeCssGenerator,
- @inject(IThemeFinder) themeFinder: IThemeFinder,
- @inject(IConfigurationService) protected configuration: IConfigurationService,
- @inject(IWorkspaceService) workspaceService: IWorkspaceService,
- @inject(IFileSystem) private file: IFileSystem,
- @inject(ICommandManager) private readonly commandManager: ICommandManager,
- @inject(IDocumentManager) private readonly documentManager: IDocumentManager,
- @inject(IApplicationShell) private appShell: IApplicationShell,
- @inject(IExtensionContext) private readonly context: IExtensionContext,
- @inject(IApplicationEnvironment) private appEnvironment: IApplicationEnvironment,
- @inject(IJupyterNotInstalledNotificationHelper)
- private notificationHelper: IJupyterNotInstalledNotificationHelper,
- @inject(IJupyterExtensionDependencyManager) private depsManager: IJupyterExtensionDependencyManager,
- @inject(IOutputChannel) @named(STANDARD_OUTPUT_CHANNEL) private readonly output: IOutputChannel,
- ) {
- super(
- configuration,
- provider,
- cssGenerator,
- themeFinder,
- workspaceService,
- (c, v, d) => new StartPageMessageListener(c, v, d),
- startPageDir,
- [path.join(startPageDir, 'commons.initial.bundle.js'), path.join(startPageDir, 'startPage.js')],
- localize.StartPage.getStarted(),
- ViewColumn.One,
- false,
- );
- this.timer = new StopWatch();
- this.initialMementoValue = this.context.globalState.get(EXTENSION_VERSION_MEMENTO);
- }
-
- public async activate(): Promise {
- if (this.appEnvironment.uiKind === UIKind.Web) {
- // We're running in Codespaces browser-based editor, do not open start page.
- }
- }
-
- public dispose(): Promise {
- if (!this.isDisposed) {
- super.dispose();
- }
- return this.close();
- }
-
- public async open(): Promise {
- sendTelemetryEvent(Telemetry.StartPageViewed);
- setTimeout(async () => {
- await this.loadWebPanel(process.cwd());
- // open webview
- await super.show(true);
-
- setTimeout(() => {
- if (!this.webviewDidLoad) {
- sendTelemetryEvent(Telemetry.StartPageWebViewError);
- }
- }, 5000);
- }, 3000);
- }
-
- // eslint-disable-next-line class-methods-use-this
- public get owningResource(): Resource {
- return undefined;
- }
-
- public async close(): Promise {
- if (!this.actionTaken) {
- sendTelemetryEvent(Telemetry.StartPageClosedWithoutAction);
- }
- if (this.actionTakenOnFirstTime) {
- sendTelemetryEvent(Telemetry.StartPageUsedAnActionOnFirstTime);
- }
- sendTelemetryEvent(Telemetry.StartPageTime, this.timer.elapsedTime);
- // Fire our event
- this.closedEvent.fire(this);
- }
-
- public async onMessage(message: string, payload: unknown): Promise {
- const shouldShowJupyterNotInstalledPrompt = await this.notificationHelper.shouldShowJupypterExtensionNotInstalledPrompt();
- const isJupyterInstalled = this.depsManager.isJupyterExtensionInstalled;
-
- switch (message) {
- case StartPageMessages.Started:
- this.webviewDidLoad = true;
- break;
- case StartPageMessages.RequestShowAgainSetting: {
- const settings = this.configuration.getSettings();
- await this.postMessage(StartPageMessages.SendSetting, {
- showAgainSetting: settings.showStartPage,
- });
- break;
- }
- case StartPageMessages.OpenBlankNotebook: {
- if (!isJupyterInstalled) {
- this.output.appendLine(Jupyter.jupyterExtensionNotInstalled());
-
- if (shouldShowJupyterNotInstalledPrompt) {
- await this.notificationHelper.showJupyterNotInstalledPrompt(
- JupyterNotInstalledOrigin.StartPageOpenBlankNotebook,
- );
- }
- } else {
- sendTelemetryEvent(Telemetry.StartPageOpenBlankNotebook);
- this.setTelemetryFlags();
-
- const savedVersion: string | undefined = this.context.globalState.get(EXTENSION_VERSION_MEMENTO);
-
- if (savedVersion) {
- await this.commandManager.executeCommand(
- 'jupyter.opennotebook',
- undefined,
- CommandSource.commandPalette,
- );
- } else {
- this.openSampleNotebook().ignoreErrors();
- }
- }
- break;
- }
- case StartPageMessages.OpenBlankPythonFile: {
- sendTelemetryEvent(Telemetry.StartPageOpenBlankPythonFile);
- this.setTelemetryFlags();
-
- const doc = await this.documentManager.openTextDocument({
- language: 'python',
- content: `print("${localize.StartPage.helloWorld()}")`,
- });
- await this.documentManager.showTextDocument(doc, 1, true);
- break;
- }
- case StartPageMessages.OpenInteractiveWindow: {
- if (!isJupyterInstalled) {
- this.output.appendLine(Jupyter.jupyterExtensionNotInstalled());
-
- if (shouldShowJupyterNotInstalledPrompt) {
- await this.notificationHelper.showJupyterNotInstalledPrompt(
- JupyterNotInstalledOrigin.StartPageOpenInteractiveWindow,
- );
- }
- } else {
- sendTelemetryEvent(Telemetry.StartPageOpenInteractiveWindow);
- this.setTelemetryFlags();
-
- const doc2 = await this.documentManager.openTextDocument({
- language: 'python',
- content: `#%%\nprint("${localize.StartPage.helloWorld()}")`,
- });
- await this.documentManager.showTextDocument(doc2, 1, true);
- await this.commandManager.executeCommand('jupyter.runallcells', doc2.uri);
- }
- break;
- }
- case StartPageMessages.OpenCommandPalette:
- sendTelemetryEvent(Telemetry.StartPageOpenCommandPalette);
- this.setTelemetryFlags();
-
- await this.commandManager.executeCommand('workbench.action.showCommands');
- break;
- case StartPageMessages.OpenCommandPaletteWithOpenNBSelected:
- sendTelemetryEvent(Telemetry.StartPageOpenCommandPaletteWithOpenNBSelected);
- this.setTelemetryFlags();
-
- await this.commandManager.executeCommand('workbench.action.quickOpen', '>Create New Blank Notebook');
- break;
- case StartPageMessages.OpenSampleNotebook:
- if (!isJupyterInstalled) {
- this.output.appendLine(Jupyter.jupyterExtensionNotInstalled());
-
- if (shouldShowJupyterNotInstalledPrompt) {
- await this.notificationHelper.showJupyterNotInstalledPrompt(
- JupyterNotInstalledOrigin.StartPageOpenSampleNotebook,
- );
- }
- } else {
- sendTelemetryEvent(Telemetry.StartPageOpenSampleNotebook);
- this.setTelemetryFlags();
-
- this.openSampleNotebook().ignoreErrors();
- }
- break;
- case StartPageMessages.OpenFileBrowser: {
- sendTelemetryEvent(Telemetry.StartPageOpenFileBrowser);
- this.setTelemetryFlags();
-
- const uri = await this.appShell.showOpenDialog({
- filters: {
- Python: ['py', 'ipynb'],
- },
- canSelectMany: false,
- });
- if (uri) {
- const doc3 = await this.documentManager.openTextDocument(uri[0]);
- await this.documentManager.showTextDocument(doc3);
- }
- break;
- }
- case StartPageMessages.OpenFolder:
- sendTelemetryEvent(Telemetry.StartPageOpenFolder);
- this.setTelemetryFlags();
- this.commandManager.executeCommand('workbench.action.files.openFolder');
- break;
- case StartPageMessages.OpenWorkspace:
- sendTelemetryEvent(Telemetry.StartPageOpenWorkspace);
- this.setTelemetryFlags();
- this.commandManager.executeCommand('workbench.action.openWorkspace');
- break;
- case StartPageMessages.UpdateSettings:
- if (payload === false) {
- sendTelemetryEvent(Telemetry.StartPageClickedDontShowAgain);
- }
- await this.configuration.updateSetting('showStartPage', payload, undefined, ConfigurationTarget.Global);
- break;
- default:
- break;
- }
-
- super.onMessage(message, payload);
- }
-
- // Public for testing
- public async extensionVersionChanged(): Promise {
- const savedVersion: string | undefined = this.context.globalState.get(EXTENSION_VERSION_MEMENTO);
- const { version } = this.appEnvironment.packageJson;
- let shouldShowStartPage: boolean;
-
- if (savedVersion) {
- if (savedVersion === version || this.savedVersionisOlder(savedVersion, version)) {
- // There has not been an update
- shouldShowStartPage = false;
- } else {
- sendTelemetryEvent(Telemetry.StartPageOpenedFromNewUpdate);
- shouldShowStartPage = true;
- }
- } else {
- sendTelemetryEvent(Telemetry.StartPageOpenedFromNewInstall);
- shouldShowStartPage = true;
- }
-
- // savedVersion being undefined means this is the first time the user activates the extension.
- // if savedVersion != version, there was an update
- await this.context.globalState.update(EXTENSION_VERSION_MEMENTO, version);
- return shouldShowStartPage;
- }
-
- // eslint-disable-next-line class-methods-use-this
- private savedVersionisOlder(savedVersion: string, actualVersion: string): boolean {
- const saved = savedVersion.split('.');
- const actual = actualVersion.split('.');
-
- switch (true) {
- case Number(actual[0]) > Number(saved[0]):
- return false;
- case Number(actual[0]) < Number(saved[0]):
- return true;
- case Number(actual[1]) > Number(saved[1]):
- return false;
- case Number(actual[1]) < Number(saved[1]):
- return true;
- case Number(actual[2][0]) > Number(saved[2][0]):
- return false;
- case Number(actual[2][0]) < Number(saved[2][0]):
- return true;
- default:
- return false;
- }
- }
-
- private async openSampleNotebook(): Promise {
- const ipynb = '.ipynb';
- const localizedFilePath = path.join(
- EXTENSION_ROOT_DIR,
- 'pythonFiles',
- localize.StartPage.sampleNotebook() + ipynb,
- );
- let sampleNotebookPath: string;
-
- if (await this.file.fileExists(localizedFilePath)) {
- sampleNotebookPath = localizedFilePath;
- } else {
- sampleNotebookPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'Notebooks intro.ipynb');
- }
-
- await this.commandManager.executeCommand(
- 'jupyter.opennotebook',
- Uri.file(sampleNotebookPath),
- CommandSource.commandPalette,
- );
- }
-
- private setTelemetryFlags() {
- if (this.firstTime) {
- this.actionTakenOnFirstTime = true;
- }
- this.actionTaken = true;
- }
-}
diff --git a/src/client/common/startPage/startPageMessageListener.ts b/src/client/common/startPage/startPageMessageListener.ts
deleted file mode 100644
index 7c8e6688f004..000000000000
--- a/src/client/common/startPage/startPageMessageListener.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-'use strict';
-import { IWebviewPanel, IWebviewPanelMessageListener } from '../application/types';
-import '../extensions';
-
-// This class listens to messages that come from the local Python Interactive window
-export class StartPageMessageListener implements IWebviewPanelMessageListener {
- private disposedCallback: () => void;
- private callback: (message: string, payload: any) => void;
- private viewChanged: (panel: IWebviewPanel) => void;
-
- constructor(
- callback: (message: string, payload: any) => void,
- viewChanged: (panel: IWebviewPanel) => void,
- disposed: () => void,
- ) {
- // Save our dispose callback so we remove our interactive window
- this.disposedCallback = disposed;
-
- // Save our local callback so we can handle the non broadcast case(s)
- this.callback = callback;
-
- // Save view changed so we can forward view change events.
- this.viewChanged = viewChanged;
- }
-
- public async dispose() {
- this.disposedCallback();
- }
-
- public onMessage(message: string, payload: any) {
- // Send to just our local callback.
- this.callback(message, payload);
- }
-
- public onChangeViewState(panel: IWebviewPanel) {
- // Forward this onto our callback
- this.viewChanged(panel);
- }
-}
diff --git a/src/client/common/startPage/themeFinder.ts b/src/client/common/startPage/themeFinder.ts
deleted file mode 100644
index 1b812940bc26..000000000000
--- a/src/client/common/startPage/themeFinder.ts
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-import { inject, injectable } from 'inversify';
-import * as path from 'path';
-
-import { LanguageConfiguration } from 'vscode';
-import { EXTENSION_ROOT_DIR, PYTHON_LANGUAGE } from '../constants';
-import { traceError } from '../logger';
-
-import { getLanguageConfiguration } from '../../language/languageConfiguration';
-import { IFileSystem } from '../platform/types';
-import { ICurrentProcess, IExtensions } from '../types';
-import { IThemeFinder } from './types';
-
-interface IThemeData {
- rootFile: string;
- isDark: boolean;
-}
-
-@injectable()
-export class ThemeFinder implements IThemeFinder {
- private themeCache: { [key: string]: IThemeData | undefined } = {};
-
- private languageCache: { [key: string]: string | undefined } = {};
-
- constructor(
- @inject(IExtensions) private extensions: IExtensions,
- @inject(ICurrentProcess) private currentProcess: ICurrentProcess,
- @inject(IFileSystem) private fs: IFileSystem,
- ) {}
-
- public async findThemeRootJson(themeName: string): Promise {
- // find our data
- const themeData = await this.findThemeData(themeName);
-
- // Use that data if it worked
- if (themeData) {
- return themeData.rootFile;
- }
- }
-
- public async findTmLanguage(language: string): Promise {
- // See if already found it or not
- if (!this.themeCache.hasOwnProperty(language)) {
- try {
- this.languageCache[language] = await this.findMatchingLanguage(language);
- } catch (exc) {
- traceError(exc);
- }
- }
- return this.languageCache[language];
- }
-
- public async findLanguageConfiguration(language: string): Promise {
- if (language === PYTHON_LANGUAGE) {
- // Custom for python. Some of these are required by monaco.
- const config: unknown = {
- comments: {
- lineComment: '#',
- blockComment: ['"""', '"""'],
- },
- brackets: [
- ['{', '}'],
- ['[', ']'],
- ['(', ')'],
- ],
- autoClosingPairs: [
- { open: '{', close: '}' },
- { open: '[', close: ']' },
- { open: '(', close: ')' },
- { open: '"', close: '"', notIn: ['string'] },
- { open: "'", close: "'", notIn: ['string', 'comment'] },
- ],
- surroundingPairs: [
- { open: '{', close: '}' },
- { open: '[', close: ']' },
- { open: '(', close: ')' },
- { open: '"', close: '"' },
- { open: "'", close: "'" },
- ],
- folding: {
- offSide: true,
- markers: {
- start: new RegExp('^\\s*#region\\b'),
- end: new RegExp('^\\s*#endregion\\b'),
- },
- },
- ...getLanguageConfiguration(),
- };
-
- return config as LanguageConfiguration;
- }
- return this.findMatchingLanguageConfiguration(language);
- }
-
- public async isThemeDark(themeName: string): Promise {
- // find our data
- const themeData = await this.findThemeData(themeName);
-
- // Use that data if it worked
- if (themeData) {
- return themeData.isDark;
- }
- }
-
- private async findThemeData(themeName: string): Promise {
- // See if already found it or not
- if (!this.themeCache.hasOwnProperty(themeName)) {
- try {
- this.themeCache[themeName] = await this.findMatchingTheme(themeName);
- } catch (exc) {
- traceError(exc);
- }
- }
- return this.themeCache[themeName];
- }
-
- private async findMatchingLanguage(language: string): Promise {
- const currentExe = this.currentProcess.execPath;
- let currentPath = path.dirname(currentExe);
-
- // Should be somewhere under currentPath/resources/app/extensions inside of a json file
- let extensionsPath = path.join(currentPath, 'resources', 'app', 'extensions');
- if (!(await this.fs.directoryExists(extensionsPath))) {
- // Might be on mac or linux. try a different path
- currentPath = path.resolve(currentPath, '../../../..');
- extensionsPath = path.join(currentPath, 'resources', 'app', 'extensions');
- }
-
- // Search through all of the files in this folder
- let results = await this.findMatchingLanguages(language, extensionsPath);
-
- // If that didn't work, see if it's our MagicPython predefined tmLanguage
- if (!results && language === PYTHON_LANGUAGE) {
- results = await this.fs.readFile(path.join(EXTENSION_ROOT_DIR, 'resources', 'MagicPython.tmLanguage.json'));
- }
-
- return results;
- }
-
- private async findMatchingLanguageConfiguration(language: string): Promise {
- try {
- const currentExe = this.currentProcess.execPath;
- let currentPath = path.dirname(currentExe);
-
- // Should be somewhere under currentPath/resources/app/extensions inside of a json file
- let extensionsPath = path.join(currentPath, 'resources', 'app', 'extensions', language);
- if (!(await this.fs.directoryExists(extensionsPath))) {
- // Might be on mac or linux. try a different path
- currentPath = path.resolve(currentPath, '../../../..');
- extensionsPath = path.join(currentPath, 'resources', 'app', 'extensions', language);
- }
-
- // See if the 'language-configuration.json' file exists
- const filePath = path.join(extensionsPath, 'language-configuration.json');
- if (await this.fs.fileExists(filePath)) {
- const contents = await this.fs.readFile(filePath);
- return JSON.parse(contents) as LanguageConfiguration;
- }
- } catch {
- // Do nothing if an error
- }
-
- return {};
- }
-
- private async findMatchingLanguages(language: string, rootPath: string): Promise {
- // Environment variable to mimic missing json problem
- if (process.env.VSC_PYTHON_MIMIC_REMOTE) {
- return undefined;
- }
-
- // Search through all package.json files in the directory and below, looking
- // for the themeName in them.
- const foundPackages = await this.fs.search('**/package.json', rootPath);
- if (foundPackages && foundPackages.length > 0) {
- // For each one, open it up and look for the theme name.
- for (const f of foundPackages) {
- const fpath = path.join(rootPath, f);
- const data = await this.findMatchingLanguageFromJson(fpath, language);
- if (data) {
- return data;
- }
- }
- }
- }
-
- private async findMatchingTheme(themeName: string): Promise {
- // Environment variable to mimic missing json problem
- if (process.env.VSC_PYTHON_MIMIC_REMOTE) {
- return undefined;
- }
-
- // Look through all extensions to find the theme. This will search
- // the default extensions folder and our installed extensions.
- const extensions = this.extensions.all;
- for (const e of extensions) {
- const result = await this.findMatchingThemeFromJson(path.join(e.extensionPath, 'package.json'), themeName);
- if (result) {
- return result;
- }
- }
-
- // If didn't find in the extensions folder, then try searching manually. This shouldn't happen, but
- // this is our backup plan in case vscode changes stuff.
- const currentExe = this.currentProcess.execPath;
- let currentPath = path.dirname(currentExe);
-
- // Should be somewhere under currentPath/resources/app/extensions inside of a json file
- let extensionsPath = path.join(currentPath, 'resources', 'app', 'extensions');
- if (!(await this.fs.directoryExists(extensionsPath))) {
- // Might be on mac or linux. try a different path
- currentPath = path.resolve(currentPath, '../../../..');
- extensionsPath = path.join(currentPath, 'resources', 'app', 'extensions');
- }
- const other = await this.findMatchingThemes(extensionsPath, themeName);
- if (other) {
- return other;
- }
- }
-
- private async findMatchingThemes(rootPath: string, themeName: string): Promise {
- // Search through all package.json files in the directory and below, looking
- // for the themeName in them.
- const foundPackages = await this.fs.search('**/package.json', rootPath);
- if (foundPackages && foundPackages.length > 0) {
- // For each one, open it up and look for the theme name.
- for (const f of foundPackages) {
- const fpath = path.join(rootPath, f);
- const data = await this.findMatchingThemeFromJson(fpath, themeName);
- if (data) {
- return data;
- }
- }
- }
- }
-
- private async findMatchingLanguageFromJson(packageJson: string, language: string): Promise {
- // Read the contents of the json file
- const text = await this.fs.readFile(packageJson);
- const json = JSON.parse(text);
-
- // Should have a name entry and a contributes entry
- if (json.hasOwnProperty('name') && json.hasOwnProperty('contributes')) {
- // See if contributes has a grammars
- const { contributes } = json;
- if (contributes.hasOwnProperty('grammars')) {
- const grammars = contributes.grammars as any[];
- // Go through each theme, seeing if the label matches our theme name
- for (const t of grammars) {
- if (t.hasOwnProperty('language') && t.language === language) {
- // Path is relative to the package.json file.
- const rootFile = t.hasOwnProperty('path')
- ? path.join(path.dirname(packageJson), t.path.toString())
- : '';
- return this.fs.readFile(rootFile);
- }
- }
- }
- }
- }
-
- private async findMatchingThemeFromJson(packageJson: string, themeName: string): Promise {
- // Read the contents of the json file
- const text = await this.fs.readFile(packageJson);
- const json = JSON.parse(text);
-
- // Should have a name entry and a contributes entry
- if (json.hasOwnProperty('name') && json.hasOwnProperty('contributes')) {
- // See if contributes has a theme
- const { contributes } = json;
- if (contributes.hasOwnProperty('themes')) {
- const themes = contributes.themes as any[];
- // Go through each theme, seeing if the label matches our theme name
- for (const t of themes) {
- if (
- (t.hasOwnProperty('label') && t.label === themeName) ||
- (t.hasOwnProperty('id') && t.id === themeName)
- ) {
- const isDark = t.hasOwnProperty('uiTheme') && t.uiTheme === 'vs-dark';
- // Path is relative to the package.json file.
- const rootFile = t.hasOwnProperty('path')
- ? path.join(path.dirname(packageJson), t.path.toString())
- : '';
-
- return { isDark, rootFile };
- }
- }
- }
- }
- }
-}
diff --git a/src/client/common/startPage/types.ts b/src/client/common/startPage/types.ts
deleted file mode 100644
index 589c53c7389b..000000000000
--- a/src/client/common/startPage/types.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-import { LanguageConfiguration } from 'vscode';
-
-export type JSONPrimitive = string | number | boolean | null;
-export type JSONValue = JSONPrimitive | JSONObject | JSONArray;
-export type JSONObject = { [member: string]: JSONValue };
-export type JSONArray = JSONValue[];
-
-export const IStartPage = Symbol('IStartPage');
-export interface IStartPage {
- readonly initialMementoValue?: string;
- open(): Promise;
- extensionVersionChanged(): Promise;
-}
-
-export interface ISettingPackage {
- showAgainSetting: boolean;
-}
-
-export enum StartPageMessages {
- Started = 'started',
- UpdateSettings = 'update_settings',
- RequestShowAgainSetting = 'RequestShowAgainSetting',
- SendSetting = 'SendSetting',
- OpenBlankNotebook = 'OpenBlankNotebook',
- OpenBlankPythonFile = 'OpenBlankPythonFile',
- OpenInteractiveWindow = 'OpenInteractiveWindow',
- OpenCommandPalette = 'OpenCommandPalette',
- OpenCommandPaletteWithOpenNBSelected = 'OpenCommandPaletteWithOpenNBSelected',
- OpenSampleNotebook = 'OpenSampleNotebook',
- OpenFileBrowser = 'OpenFileBrowser',
- OpenFolder = 'OpenFolder',
- OpenWorkspace = 'OpenWorkspace',
-}
-
-export class IStartPageMapping {
- public [StartPageMessages.RequestShowAgainSetting]: ISettingPackage;
-
- public [StartPageMessages.SendSetting]: ISettingPackage;
-
- public [StartPageMessages.Started]: never | undefined;
-
- public [StartPageMessages.UpdateSettings]: boolean;
-
- public [StartPageMessages.OpenBlankNotebook]: never | undefined;
-
- public [StartPageMessages.OpenBlankPythonFile]: never | undefined;
-
- public [StartPageMessages.OpenInteractiveWindow]: never | undefined;
-
- public [StartPageMessages.OpenCommandPalette]: never | undefined;
-
- public [StartPageMessages.OpenCommandPaletteWithOpenNBSelected]: never | undefined;
-
- public [StartPageMessages.OpenSampleNotebook]: never | undefined;
-
- public [StartPageMessages.OpenFileBrowser]: never | undefined;
-
- public [StartPageMessages.OpenFolder]: never | undefined;
-
- public [StartPageMessages.OpenWorkspace]: never | undefined;
-}
-
-type WebViewViewState = {
- readonly visible: boolean;
- readonly active: boolean;
-};
-export type WebViewViewChangeEventArgs = { current: WebViewViewState; previous: WebViewViewState };
-
-export const ICodeCssGenerator = Symbol('ICodeCssGenerator');
-export interface ICodeCssGenerator {
- generateThemeCss(isDark: boolean, theme: string): Promise;
- generateMonacoTheme(isDark: boolean, theme: string): Promise;
-}
-
-export const IThemeFinder = Symbol('IThemeFinder');
-export interface IThemeFinder {
- findThemeRootJson(themeName: string): Promise;
- findTmLanguage(language: string): Promise;
- findLanguageConfiguration(language: string): Promise;
- isThemeDark(themeName: string): Promise;
-}
diff --git a/src/client/common/startPage/webviewHost.ts b/src/client/common/startPage/webviewHost.ts
deleted file mode 100644
index 40227b0a7d17..000000000000
--- a/src/client/common/startPage/webviewHost.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-import '../extensions';
-
-import { injectable, unmanaged } from 'inversify';
-import { ConfigurationChangeEvent, Uri } from 'vscode';
-
-import { captureTelemetry } from '../../telemetry';
-import { IWebview, IWorkspaceService } from '../application/types';
-import { createDeferred, Deferred } from '../utils/async';
-import * as localize from '../utils/localize';
-import { DefaultTheme, Telemetry } from './constants';
-import { ICodeCssGenerator, IThemeFinder } from './types';
-
-import { PythonSettings } from '../configSettings';
-import { isTestExecution } from '../constants';
-import { IConfigurationService, IDisposable, IPythonSettings, Resource } from '../types';
-import { CssMessages, IGetCssRequest, IGetMonacoThemeRequest, SharedMessages } from './messages';
-
-@injectable() // For some reason this is necessary to get the class hierarchy to work.
-export abstract class WebviewHost implements IDisposable {
- protected webview?: IWebview;
-
- protected disposed = false;
-
- protected themeIsDarkPromise: Deferred | undefined = createDeferred();
-
- protected webviewInit: Deferred | undefined = createDeferred();
-
- protected readonly _disposables: IDisposable[] = [];
-
- constructor(
- @unmanaged() protected configService: IConfigurationService,
- @unmanaged() private cssGenerator: ICodeCssGenerator,
- @unmanaged() protected themeFinder: IThemeFinder,
- @unmanaged() protected workspaceService: IWorkspaceService,
- @unmanaged() protected readonly useCustomEditorApi: boolean,
- ) {
- // Listen for settings changes from vscode.
- this._disposables.push(this.workspaceService.onDidChangeConfiguration(this.onPossibleSettingsChange, this));
-
- // Listen for settings changes
- this._disposables.push(
- this.configService.getSettings(undefined).onDidChange(this.onSettingsChanged.bind(this)),
- );
- }
-
- public dispose(): void {
- if (!this.disposed) {
- this.disposed = true;
- this.themeIsDarkPromise = undefined;
- this._disposables.forEach((item) => item.dispose());
- }
-
- this.webviewInit = undefined;
- }
-
- public setTheme(isDark: boolean): void {
- if (this.themeIsDarkPromise && !this.themeIsDarkPromise.resolved) {
- this.themeIsDarkPromise.resolve(isDark);
- } else {
- this.themeIsDarkPromise = createDeferred();
- this.themeIsDarkPromise.resolve(isDark);
- }
- }
-
- // Post a message to our webview and update our new settings
- protected onSettingsChanged = async (): Promise => {
- // Stringify our settings to send over to the panel
- const settings = JSON.stringify(await this.generateExtraSettings());
- this.postMessageInternal(SharedMessages.UpdateSettings, settings).ignoreErrors();
- };
-
- protected asWebviewUri(localResource: Uri): Uri {
- if (!this.webview) {
- throw new Error('asWebViewUri called too early');
- }
- return this.webview?.asWebviewUri(localResource);
- }
-
- protected abstract get owningResource(): Resource;
-
- protected postMessage(type: T, payload?: M[T]): Promise {
- // Then send it the message
- return this.postMessageInternal(type.toString(), payload);
- }
-
- protected onMessage(message: string, payload: any): void {
- switch (message) {
- case CssMessages.GetCssRequest:
- this.handleCssRequest(payload as IGetCssRequest).ignoreErrors();
- break;
-
- case CssMessages.GetMonacoThemeRequest:
- this.handleMonacoThemeRequest(payload as IGetMonacoThemeRequest).ignoreErrors();
- break;
-
- default:
- break;
- }
- }
-
- protected async generateExtraSettings(): Promise {
- const settings = this.configService.getSettings(this.owningResource);
- return PythonSettings.toSerializable(settings);
- }
-
- protected async sendLocStrings() {
- const locStrings = isTestExecution() ? '{}' : localize.getCollectionJSON();
- this.postMessageInternal(SharedMessages.LocInit, locStrings).ignoreErrors();
- }
-
- protected async postMessageInternal(type: string, payload?: any): Promise {
- if (this.webviewInit) {
- // Make sure the webpanel is up before we send it anything.
- await this.webviewInit.promise;
-
- // Then send it the message
- this.webview?.postMessage({ type: type.toString(), payload });
- }
- }
-
- protected isDark(): Promise {
- return this.themeIsDarkPromise ? this.themeIsDarkPromise.promise : Promise.resolve(false);
- }
-
- @captureTelemetry(Telemetry.WebviewStyleUpdate)
- private async handleCssRequest(request: IGetCssRequest): Promise {
- const workbench = this.workspaceService.getConfiguration('workbench');
- const theme = !workbench ? DefaultTheme : workbench.get('colorTheme', DefaultTheme);
- const requestIsDark = request?.isDark;
- this.setTheme(requestIsDark);
- const isDark = await this.themeFinder.isThemeDark(theme);
- const css = await this.cssGenerator.generateThemeCss(requestIsDark, theme);
- return this.postMessageInternal(CssMessages.GetCssResponse, {
- css,
- theme: theme,
- knownDark: isDark,
- });
- }
-
- @captureTelemetry(Telemetry.WebviewMonacoStyleUpdate)
- private async handleMonacoThemeRequest(request: IGetMonacoThemeRequest): Promise {
- const workbench = this.workspaceService.getConfiguration('workbench');
- const theme = !workbench ? DefaultTheme : workbench.get('colorTheme', DefaultTheme);
- const isDark = request?.isDark;
- this.setTheme(isDark);
- const monacoTheme = await this.cssGenerator.generateMonacoTheme(isDark, theme);
- return this.postMessageInternal(CssMessages.GetMonacoThemeResponse, { theme: monacoTheme });
- }
-
- // Post a message to our webpanel and update our new settings
- private onPossibleSettingsChange = async (event: ConfigurationChangeEvent) => {
- if (event.affectsConfiguration('workbench.colorTheme')) {
- // See if the theme changed
- const newSettings = await this.generateExtraSettings();
- if (newSettings) {
- const dsSettings = JSON.stringify(newSettings);
- this.postMessageInternal(SharedMessages.UpdateSettings, dsSettings).ignoreErrors();
- }
- }
- };
-}
diff --git a/src/client/common/startPage/webviewPanelHost.ts b/src/client/common/startPage/webviewPanelHost.ts
deleted file mode 100644
index 100989c3caec..000000000000
--- a/src/client/common/startPage/webviewPanelHost.ts
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-'use strict';
-
-import '../extensions';
-
-import { injectable, unmanaged } from 'inversify';
-import { Uri, ViewColumn, WebviewPanel } from 'vscode';
-
-import {
- IWebviewPanel,
- IWebviewPanelMessageListener,
- IWebviewPanelProvider,
- IWorkspaceService,
-} from '../application/types';
-import { traceInfo } from '../logger';
-import { createDeferred } from '../utils/async';
-import { noop } from '../utils/misc';
-import { StopWatch } from '../utils/stopWatch';
-import { ICodeCssGenerator, IThemeFinder, WebViewViewChangeEventArgs } from './types';
-
-import { sendTelemetryEvent } from '../../telemetry';
-import { IConfigurationService, IDisposable } from '../types';
-import { Telemetry } from './constants';
-import { SharedMessages } from './messages';
-import { WebviewHost } from './webviewHost';
-
-@injectable() // For some reason this is necessary to get the class hierarchy to work.
-export abstract class WebviewPanelHost extends WebviewHost implements IDisposable {
- protected get isDisposed(): boolean {
- return this.disposed;
- }
-
- protected viewState: { visible: boolean; active: boolean } = { visible: false, active: false };
-
- private webPanel: IWebviewPanel | undefined;
-
- private messageListener: IWebviewPanelMessageListener;
-
- private startupStopwatch = new StopWatch();
-
- constructor(
- @unmanaged() protected configService: IConfigurationService,
- @unmanaged() private provider: IWebviewPanelProvider,
- @unmanaged() cssGenerator: ICodeCssGenerator,
- @unmanaged() protected themeFinder: IThemeFinder,
- @unmanaged() protected workspaceService: IWorkspaceService,
- @unmanaged()
- messageListenerCtor: (
- callback: (message: string, payload: {}) => void,
- viewChanged: (panel: IWebviewPanel) => void,
- disposed: () => void,
- ) => IWebviewPanelMessageListener,
- @unmanaged() private rootPath: string,
- @unmanaged() private scripts: string[],
- @unmanaged() private _title: string,
- @unmanaged() private viewColumn: ViewColumn,
- @unmanaged() protected readonly useCustomEditorApi: boolean,
- ) {
- super(configService, cssGenerator, themeFinder, workspaceService, useCustomEditorApi);
-
- // Create our message listener for our web panel.
- this.messageListener = messageListenerCtor(
- this.onMessage.bind(this),
- this.webPanelViewStateChanged.bind(this),
- this.dispose.bind(this),
- );
- }
-
- public async show(preserveFocus: boolean): Promise {
- if (!this.isDisposed) {
- // Then show our web panel.
- if (this.webPanel) {
- await this.webPanel.show(preserveFocus);
- }
- }
- }
-
- public updateCwd(cwd: string): void {
- if (this.webPanel) {
- this.webPanel.updateCwd(cwd);
- }
- }
-
- public dispose() {
- if (!this.isDisposed) {
- this.disposed = true;
- if (this.webPanel) {
- this.webPanel.close();
- this.webPanel = undefined;
- }
- }
-
- super.dispose();
- }
-
- public get title() {
- return this._title;
- }
-
- public setTitle(newTitle: string) {
- this._title = newTitle;
- if (!this.isDisposed && this.webPanel) {
- this.webPanel.setTitle(newTitle);
- }
- }
-
- protected onMessage(message: string, payload: any) {
- switch (message) {
- case SharedMessages.Started:
- this.webPanelRendered();
- break;
-
- default:
- // Forward unhandled messages to the base class
- super.onMessage(message, payload);
- break;
- }
- }
-
- protected shareMessage(type: T, payload?: M[T]) {
- // Send our remote message.
- this.messageListener.onMessage(type.toString(), payload);
- }
-
- protected onViewStateChanged(_args: WebViewViewChangeEventArgs) {
- noop();
- }
-
- protected async loadWebPanel(cwd: string, webViewPanel?: WebviewPanel) {
- // Make not disposed anymore
- this.disposed = false;
-
- // Setup our init promise for the web panel. We use this to make sure we're in sync with our
- // react control.
- this.webviewInit = this.webviewInit || createDeferred();
-
- // Setup a promise that will wait until the webview passes back
- // a message telling us what them is in use
- this.themeIsDarkPromise = this.themeIsDarkPromise ? this.themeIsDarkPromise : createDeferred();
-
- // Load our actual web panel
-
- traceInfo(`Loading web panel. Panel is ${this.webPanel ? 'set' : 'notset'}`);
-
- // Create our web panel (it's the UI that shows up for the history)
- if (this.webPanel === undefined) {
- // Get our settings to pass along to the react control
- const settings = await this.generateExtraSettings();
-
- traceInfo('Loading web view...');
-
- const workspaceFolder = this.workspaceService.getWorkspaceFolder(Uri.file(cwd))?.uri;
-
- // Use this script to create our web view panel. It should contain all of the necessary
- // script to communicate with this class.
- this.webPanel = await this.provider.create({
- viewColumn: this.viewColumn,
- listener: this.messageListener,
- title: this.title,
- rootPath: this.rootPath,
- scripts: this.scripts,
- settings,
- cwd,
- webViewPanel,
- additionalPaths: workspaceFolder ? [workspaceFolder.fsPath] : [],
- });
-
- // Set our webview after load
- this.webview = this.webPanel;
-
- // Track to seee if our web panel fails to load
- this._disposables.push(this.webPanel.loadFailed(this.onWebPanelLoadFailed, this));
-
- traceInfo('Web view created.');
- }
-
- // Send the first settings message
- this.onSettingsChanged().ignoreErrors();
-
- // Send the loc strings (skip during testing as it takes up a lot of memory)
- this.sendLocStrings().ignoreErrors();
- }
-
- // If our webpanel fails to load then just dispose ourselves
- private onWebPanelLoadFailed = async () => {
- this.dispose();
- };
-
- private webPanelViewStateChanged = (webPanel: IWebviewPanel) => {
- const visible = webPanel.isVisible();
- const active = webPanel.isActive();
- const current = { visible, active };
- const previous = { visible: this.viewState.visible, active: this.viewState.active };
- this.viewState.visible = visible;
- this.viewState.active = active;
- this.onViewStateChanged({ current, previous });
- };
-
- private webPanelRendered() {
- if (this.webviewInit && !this.webviewInit.resolved) {
- // Send telemetry for startup
- sendTelemetryEvent(Telemetry.WebviewStartup, this.startupStopwatch.elapsedTime, { type: this.title });
-
- // Resolve our started promise. This means the webpanel is ready to go.
- this.webviewInit.resolve();
-
- traceInfo('Web view react rendered');
- }
-
- // On started, resend our init data.
- this.sendLocStrings().ignoreErrors();
- this.onSettingsChanged().ignoreErrors();
- }
-}
diff --git a/src/client/common/types.ts b/src/client/common/types.ts
index 7ff71aa96aea..5cccc64a22c5 100644
--- a/src/client/common/types.ts
+++ b/src/client/common/types.ts
@@ -175,7 +175,6 @@ export interface IPythonSettings {
readonly poetryPath: string;
readonly insidersChannel: ExtensionChannels;
readonly downloadLanguageServer: boolean;
- readonly showStartPage: boolean;
readonly jediPath: string;
readonly jediMemoryLimit: number;
readonly devOptions: string[];
@@ -510,17 +509,6 @@ export interface IAsyncDisposableRegistry extends IAsyncDisposable {
push(disposable: IDisposable | IAsyncDisposable): void;
}
-/* ABExperiments field carries the identity, and the range of the experiment,
- where the experiment is valid for users falling between the number 'min' and 'max'
- More details: https://en.wikipedia.org/wiki/A/B_testing
-*/
-export type ABExperiments = {
- name: string; // Name of the experiment
- salt: string; // Salt string for the experiment
- min: number; // Lower limit for the experiment
- max: number; // Upper limit for the experiment
-}[];
-
/**
* Experiment service leveraging VS Code's experiment framework.
*/
diff --git a/src/client/common/utils/localize.ts b/src/client/common/utils/localize.ts
index 5506c58b7f15..a9aecbfec9f5 100644
--- a/src/client/common/utils/localize.ts
+++ b/src/client/common/utils/localize.ts
@@ -131,13 +131,6 @@ export namespace Pylance {
export const pylanceRevertToJedi = localize('Pylance.pylanceRevertToJedi', 'Revert to Jedi');
}
-export namespace Jupyter {
- export const jupyterExtensionNotInstalled = localize(
- 'Jupyter.extensionNotInstalled',
- "This feature is available in the Jupyter extension, which isn't currently installed.",
- );
-}
-
export namespace TensorBoard {
export const enterRemoteUrl = localize('TensorBoard.enterRemoteUrl', 'Enter remote URL');
export const enterRemoteUrlDetail = localize(
@@ -426,57 +419,6 @@ export namespace ExtensionSurveyBanner {
export namespace Products {
export const installingModule = localize('products.installingModule', 'Installing {0}');
}
-
-export namespace StartPage {
- export const getStarted = localize('StartPage.getStarted', 'Python - Get Started');
- export const pythonExtensionTitle = localize('StartPage.pythonExtensionTitle', 'Python Extension');
- export const createJupyterNotebook = localize('StartPage.createJupyterNotebook', 'Create a Jupyter Notebook');
- export const notebookDescription = localize(
- 'StartPage.notebookDescription',
- '- Run "
Create New Blank Notebook
" in the Command Palette (
Shift + Command + P
) - Explore our
sample notebook
to learn about notebook features',
- );
- export const createAPythonFile = localize('StartPage.createAPythonFile', 'Create a Python File');
- export const pythonFileDescription = localize(
- 'StartPage.pythonFileDescription',
- '- Create a
new file
with a .py extension',
- );
- export const openInteractiveWindow = localize(
- 'StartPage.openInteractiveWindow',
- 'Use the Interactive Window to develop Python Scripts',
- );
- export const interactiveWindowDesc = localize(
- 'StartPage.interactiveWindowDesc',
- '- You can create cells on a Python file by typing "#%%". Make sure you have the Jupyter extension installed. - Use "
Shift + Enter
" to run a cell, the output will be shown in the interactive window',
- );
-
- export const releaseNotes = localize(
- 'StartPage.releaseNotes',
- 'Take a look at our Release Notes to learn more about the latest features.',
- );
- export const tutorialAndDoc = localize(
- 'StartPage.tutorialAndDoc',
- 'Explore more features in our Tutorials or check Documentation for tips and troubleshooting.',
- );
- export const mailingList = localize(
- 'StartPage.mailingList',
- 'Sign up for tips and tutorials through our mailing list.',
- );
- export const dontShowAgain = localize('StartPage.dontShowAgain', "Don't show this page again");
- export const helloWorld = localize('StartPage.helloWorld', 'Hello world');
- // When localizing sampleNotebook, the translated notebook must also be included in
- // pythonFiles\*
- export const sampleNotebook = localize('StartPage.sampleNotebook', 'Notebooks intro');
- export const openFolder = localize('StartPage.openFolder', 'Open a Folder or Workspace');
- export const folderDesc = localize(
- 'StartPage.folderDesc',
- '- Open a
" to run a cell, the output will be shown in the interactive window',
- ),
- }}
- />
- );
- }
-
- // eslint-disable-next-line class-methods-use-this
- private renderFolderDescription(): JSX.Element {
- return (
-