From 4e2acd612ac17ae19ce2d551e079e0c5b22cc4d4 Mon Sep 17 00:00:00 2001 From: Kim-Adeline Miguel Date: Fri, 23 Jul 2021 11:35:50 -0700 Subject: [PATCH 01/19] First deletion pass --- .eslintignore | 24 +- .sonarcloud.properties | 2 +- .vscodeignore | 1 - package.json | 3 - package.nls.json | 18 - package.nls.zh-cn.json | 17 - resources/report_issue_user_settings.json | 5 +- src/client/common/application/commands.ts | 1 - src/client/common/configSettings.ts | 7 - src/client/common/constants.ts | 1 - src/client/common/serviceRegistry.ts | 7 - .../common/startPage/codeCssGenerator.ts | 507 ----------------- src/client/common/startPage/constants.ts | 35 -- src/client/common/startPage/messages.ts | 32 -- src/client/common/startPage/startPage.ts | 370 ------------- .../startPage/startPageMessageListener.ts | 41 -- src/client/common/startPage/themeFinder.ts | 295 ---------- src/client/common/startPage/types.ts | 84 --- src/client/common/startPage/webviewHost.ts | 166 ------ .../common/startPage/webviewPanelHost.ts | 216 -------- src/client/common/types.ts | 1 - src/client/common/utils/localize.ts | 51 -- src/client/extensionActivation.ts | 4 - src/client/telemetry/index.ts | 28 - src/startPage-ui/common/index.css | 5 - src/startPage-ui/common/main.ts | 10 - src/startPage-ui/react-common/image.tsx | 63 --- .../images/StartPage/Interactive-inverse.svg | 3 - .../images/StartPage/Interactive.svg | 3 - .../images/StartPage/Notebook-inverse.svg | 3 - .../images/StartPage/Notebook.svg | 3 - .../images/StartPage/OpenFolder-inverse.svg | 3 - .../images/StartPage/OpenFolder.svg | 3 - .../images/StartPage/Python-color.svg | 14 - .../images/StartPage/Python-inverse.svg | 4 - .../react-common/images/StartPage/Python.svg | 4 - src/startPage-ui/react-common/locReactSide.ts | 20 - src/startPage-ui/react-common/logger.ts | 15 - src/startPage-ui/react-common/postOffice.ts | 113 ---- .../react-common/themeDetector.ts | 25 - src/startPage-ui/startPage/index.html | 356 ------------ src/startPage-ui/startPage/index.tsx | 31 -- src/startPage-ui/startPage/startPage.css | 93 ---- src/startPage-ui/startPage/startPage.tsx | 387 ------------- src/test/startPage/mockCommandManager.ts | 56 -- src/test/startPage/mockDocument.ts | 195 ------- src/test/startPage/mockDocumentManager.ts | 145 ----- src/test/startPage/mockExtensions.ts | 20 - src/test/startPage/mockPythonSettings.ts | 17 - src/test/startPage/mockTextEditor.ts | 111 ---- src/test/startPage/mockWorkspaceConfig.ts | 57 -- src/test/startPage/mockWorkspaceFolder.ts | 15 - src/test/startPage/mountedWebView.ts | 257 --------- src/test/startPage/mountedWebViewFactory.ts | 45 -- src/test/startPage/reactHelpers.ts | 521 ------------------ .../startPage/startPage.functional.test.tsx | 114 ---- src/test/startPage/startPage.unit.test.ts | 279 ---------- src/test/startPage/startPageIocContainer.ts | 473 ---------------- src/test/startPage/webBrowserPanel.ts | 241 -------- src/test/startPage/webBrowserPanelProvider.ts | 16 - tsconfig.extension.json | 1 - 61 files changed, 4 insertions(+), 5633 deletions(-) delete mode 100644 src/client/common/startPage/codeCssGenerator.ts delete mode 100644 src/client/common/startPage/constants.ts delete mode 100644 src/client/common/startPage/messages.ts delete mode 100644 src/client/common/startPage/startPage.ts delete mode 100644 src/client/common/startPage/startPageMessageListener.ts delete mode 100644 src/client/common/startPage/themeFinder.ts delete mode 100644 src/client/common/startPage/types.ts delete mode 100644 src/client/common/startPage/webviewHost.ts delete mode 100644 src/client/common/startPage/webviewPanelHost.ts delete mode 100644 src/startPage-ui/common/index.css delete mode 100644 src/startPage-ui/common/main.ts delete mode 100644 src/startPage-ui/react-common/image.tsx delete mode 100644 src/startPage-ui/react-common/images/StartPage/Interactive-inverse.svg delete mode 100644 src/startPage-ui/react-common/images/StartPage/Interactive.svg delete mode 100644 src/startPage-ui/react-common/images/StartPage/Notebook-inverse.svg delete mode 100644 src/startPage-ui/react-common/images/StartPage/Notebook.svg delete mode 100644 src/startPage-ui/react-common/images/StartPage/OpenFolder-inverse.svg delete mode 100644 src/startPage-ui/react-common/images/StartPage/OpenFolder.svg delete mode 100644 src/startPage-ui/react-common/images/StartPage/Python-color.svg delete mode 100644 src/startPage-ui/react-common/images/StartPage/Python-inverse.svg delete mode 100644 src/startPage-ui/react-common/images/StartPage/Python.svg delete mode 100644 src/startPage-ui/react-common/locReactSide.ts delete mode 100644 src/startPage-ui/react-common/logger.ts delete mode 100644 src/startPage-ui/react-common/postOffice.ts delete mode 100644 src/startPage-ui/react-common/themeDetector.ts delete mode 100644 src/startPage-ui/startPage/index.html delete mode 100644 src/startPage-ui/startPage/index.tsx delete mode 100644 src/startPage-ui/startPage/startPage.css delete mode 100644 src/startPage-ui/startPage/startPage.tsx delete mode 100644 src/test/startPage/mockCommandManager.ts delete mode 100644 src/test/startPage/mockDocument.ts delete mode 100644 src/test/startPage/mockDocumentManager.ts delete mode 100644 src/test/startPage/mockExtensions.ts delete mode 100644 src/test/startPage/mockPythonSettings.ts delete mode 100644 src/test/startPage/mockTextEditor.ts delete mode 100644 src/test/startPage/mockWorkspaceConfig.ts delete mode 100644 src/test/startPage/mockWorkspaceFolder.ts delete mode 100644 src/test/startPage/mountedWebView.ts delete mode 100644 src/test/startPage/mountedWebViewFactory.ts delete mode 100644 src/test/startPage/reactHelpers.ts delete mode 100644 src/test/startPage/startPage.functional.test.tsx delete mode 100644 src/test/startPage/startPage.unit.test.ts delete mode 100644 src/test/startPage/startPageIocContainer.ts delete mode 100644 src/test/startPage/webBrowserPanel.ts delete mode 100644 src/test/startPage/webBrowserPanelProvider.ts diff --git a/.eslintignore b/.eslintignore index 57cc8abca260..bfa0e8720192 100644 --- a/.eslintignore +++ b/.eslintignore @@ -494,7 +494,7 @@ src/client/common/nuget/types.ts src/client/common/nuget/nugetService.ts src/client/common/cancellation.ts src/client/common/interpreterPathService.ts -src/client/common/startPage/startPageMessageListener.ts + src/client/common/application/customEditorService.ts src/client/common/application/applicationShell.ts src/client/common/application/languageService.ts @@ -620,25 +620,3 @@ src/client/workspaceSymbols/generator.ts src/client/workspaceSymbols/parser.ts src/client/workspaceSymbols/provider.ts -src/client/common/startPage/codeCssGenerator.ts -src/client/common/startPage/themeFinder.ts -src/client/common/startPage/webviewHost.ts -src/client/common/startPage/webviewPanelHost.ts -src/startPage-ui/common/main.ts -src/startPage-ui/react-common/image.tsx -src/startPage-ui/react-common/locReactSide.ts -src/startPage-ui/react-common/logger.ts -src/startPage-ui/react-common/postOffice.ts -src/startPage-ui/startPage/index.tsx -src/test/startPage/mockCommandManager.ts -src/test/startPage/mockDocument.ts -src/test/startPage/mockDocumentManager.ts -src/test/startPage/mockExtensions.ts -src/test/startPage/mockTextEditor.ts -src/test/startPage/mockWorkspaceConfig.ts -src/test/startPage/mockWorkspaceFolder.ts -src/test/startPage/mountedWebView.ts -src/test/startPage/mountedWebViewFactory.ts -src/test/startPage/reactHelpers.ts -src/test/startPage/webBrowserPanel.ts -src/test/startPage/webBrowserPanelProvider.ts diff --git a/.sonarcloud.properties b/.sonarcloud.properties index a5ccae9a98e7..9e466689a90a 100644 --- a/.sonarcloud.properties +++ b/.sonarcloud.properties @@ -1,4 +1,4 @@ -sonar.sources=src/client,src/startPage-ui +sonar.sources=src/client sonar.tests=src/test sonar.cfamily.build-wrapper-output.bypass=true sonar.cpd.exclusions=src/client/activation/**/*.ts diff --git a/.vscodeignore b/.vscodeignore index 7c5cb570ab04..d33521e3e642 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -1,6 +1,5 @@ **/*.map **/*.analyzer.html -!out/startPage-ui/viewers/ *.vsix .editorconfig .env diff --git a/package.json b/package.json index bf1c45255e9e..7f82fb9b8d05 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,6 @@ "onCommand:python.switchToDailyChannel", "onCommand:python.switchToWeeklyChannel", "onCommand:python.clearWorkspaceInterpreter", - "onCommand:python.startPage.open", "onCommand:python.enableSourceMapSupport", "onCommand:python.launchTensorBoard", "onCommand:python.clearPersistentStorage", @@ -2043,8 +2042,6 @@ "compile": "tsc -watch -p ./", "compiled": "deemon npm run compile", "kill-compiled": "deemon --kill npm run compile", - "compile-webviews-watch": "cross-env NODE_OPTIONS=--max_old_space_size=9096 webpack --config ./build/webpack/webpack.startPage-ui-viewers.config.js --watch", - "compile-webviews-watchd": "deemon npm run compile-webviews-watch", "kill-compile-webviews-watchd": "deemon --kill npm run compile-webviews-watch", "checkDependencies": "gulp checkDependencies", "test": "node ./out/test/standardTest.js && node ./out/test/multiRootTest.js", diff --git a/package.nls.json b/package.nls.json index 0940a7309557..f363d2adffb8 100644 --- a/package.nls.json +++ b/package.nls.json @@ -34,7 +34,6 @@ "python.command.python.runLinting.title": "Run Linting", "python.command.python.enableSourceMapSupport.title": "Enable Source Map Support For Extension Debugging", "python.command.python.clearPersistentStorage.title": "Clear Internal Extension Cache", - "python.command.python.startPage.open.title": "Open Start Page", "python.command.python.analysis.clearCache.title": "Clear Module Analysis Cache", "python.command.python.analysis.restartLanguageServer.title": "Restart Language Server", "python.command.python.launchTensorBoard.title": "Launch TensorBoard", @@ -213,23 +212,6 @@ "downloading.file.progress": "{0}{1} of {2} KB ({3}%)", "products.installingModule": "Installing {0}", "OutdatedDebugger.updateDebuggerMessage": "We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).", - "StartPage.getStarted": "Python - Get Started", - "StartPage.pythonExtensionTitle": "Python Extension", - "StartPage.createJupyterNotebook": "Create a Jupyter Notebook", - "StartPage.notebookDescription": "- Run \"\" in the Command Palette (
Shift + Command + P
)
- Explore our
sample notebook
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.", diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index df3c5ccdf158..613732b7793f 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -32,7 +32,6 @@ "python.command.python.enableLinting.title": "启用代码检查", "python.command.python.runLinting.title": "执行代码检查", "python.command.python.enableSourceMapSupport.title": "为扩展调试启用 Source Map 支持", - "python.command.python.startPage.open.title": "打开起始页", "python.command.python.analysis.clearCache.title": "清除模块分析缓存", "python.command.python.analysis.restartLanguageServer.title": "重启语言服务器", "python.command.python.launchTensorBoard.title": "启动 TensorBoard", @@ -198,22 +197,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": "- 在命令面板 (
Shift + Command + P
) 中运行 \"\"
- 探索
示例笔记本
来了解笔记本的功能", - "StartPage.createAPythonFile": "创建 Python 文件", - "StartPage.pythonFileDescription": "- 创建以 .py 为扩展名的
新文件
", - "StartPage.openInteractiveWindow": "使用交互式窗口开发 Python 脚本", - "StartPage.interactiveWindowDesc": "- 您可以在 Python 文件中输入 \"#%%\" 来创建一个单元
- 使用 \"
Shift + Enter
\" 来运行一个单元,输出将显示在交互式窗口中", - "StartPage.releaseNotes": "请查看 发行说明,了解更多最新功能。", - "StartPage.tutorialAndDoc": "在 教程 中探索更多的功能,或查看 文档 以获得提示和排除故障。", - "StartPage.dontShowAgain": "不再显示此页面", - "StartPage.helloWorld": "Hello world", - "StartPage.sampleNotebook": "笔记本介绍", - "StartPage.openFolder": "打开文件夹或工作区", - "StartPage.folderDesc": "- 打开
文件夹

- 打开
工作区
", - "StartPage.badWebPanelFormatString": "

{0} 文件名无效

", "Jupyter.extensionRequired": "执行该任务需要 Jupyter 扩展。点击\"是 \"打开 Jupyter 扩展的安装页面。", "TensorBoard.useCurrentWorkingDirectory": "使用当前工作目录", "TensorBoard.currentDirectory": "当前:{0}", 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/common/application/commands.ts b/src/client/common/application/commands.ts index fa6735a6d0fa..7b496a8e6d0d 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -45,7 +45,6 @@ interface ICommandNameWithoutArgumentTypeMapping { [Commands.Tests_Ask_To_Stop_Test]: []; [Commands.Tests_Discovering]: []; [Commands.PickLocalProcess]: []; - [Commands.OpenStartPage]: []; [Commands.ClearStorage]: []; [Commands.ReportIssue]: []; [Commands.RefreshTensorBoard]: []; diff --git a/src/client/common/configSettings.ts b/src/client/common/configSettings.ts index fc06923aba8e..245e665dc733 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 = ''; @@ -592,11 +590,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 3435966dd2ac..c42d90693e60 100644 --- a/src/client/common/constants.ts +++ b/src/client/common/constants.ts @@ -80,7 +80,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'; diff --git a/src/client/common/serviceRegistry.ts b/src/client/common/serviceRegistry.ts index 16a4d99fd49c..02363e592f50 100644 --- a/src/client/common/serviceRegistry.ts +++ b/src/client/common/serviceRegistry.ts @@ -88,10 +88,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'; @@ -240,7 +236,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 c75708676065..000000000000 --- a/src/client/common/startPage/startPage.ts +++ /dev/null @@ -1,370 +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. - return; - } - this.activateBackground().ignoreErrors(); - } - - 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; - } - - private async activateBackground(): Promise { - const settings = this.configuration.getSettings(); - - if (settings.showStartPage && this.appEnvironment.extensionChannel === 'stable') { - // extesionVersionChanged() reads CHANGELOG.md - // So we use separate if's to try and avoid reading a file every time - const firstTimeOrUpdate = await this.extensionVersionChanged(); - - if (firstTimeOrUpdate) { - this.firstTime = true; - this.open().ignoreErrors(); - } - } - } - - // 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 bf437ff3d493..255798c1053d 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -181,7 +181,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[]; diff --git a/src/client/common/utils/localize.ts b/src/client/common/utils/localize.ts index 82bfacd3fee6..eb4e2c41bdb9 100644 --- a/src/client/common/utils/localize.ts +++ b/src/client/common/utils/localize.ts @@ -430,57 +430,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 "" in the Command Palette (
Shift + Command + P
)
- Explore our to learn about notebook features', - ); - export const createAPythonFile = localize('StartPage.createAPythonFile', 'Create a Python File'); - export const pythonFileDescription = localize( - 'StartPage.pythonFileDescription', - '- Create a 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
- Open a ', - ); - export const badWebPanelFormatString = localize( - 'StartPage.badWebPanelFormatString', - '

{0} is not a valid file name

', - ); -} - export namespace DebugConfigStrings { export const selectConfiguration = { title: localize('debug.selectConfigurationTitle'), diff --git a/src/client/extensionActivation.ts b/src/client/extensionActivation.ts index 56aa7b112d70..2edddac19dad 100644 --- a/src/client/extensionActivation.ts +++ b/src/client/extensionActivation.ts @@ -15,8 +15,6 @@ import { Commands, PYTHON, PYTHON_LANGUAGE, STANDARD_OUTPUT_CHANNEL, UseProposed import { registerTypes as installerRegisterTypes } from './common/installer/serviceRegistry'; import { traceError } from './common/logger'; import { IFileSystem } from './common/platform/types'; -import { StartPage } from './common/startPage/startPage'; -import { IStartPage } from './common/startPage/types'; import { IConfigurationService, IDisposableRegistry, @@ -156,8 +154,6 @@ async function activateLegacy(ext: ExtensionState): Promise { const cmdManager = serviceContainer.get(ICommandManager); const outputChannel = serviceManager.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); disposables.push(cmdManager.registerCommand(Commands.ViewOutput, () => outputChannel.show())); - const startPage = serviceManager.get(IStartPage); - cmdManager.registerCommand(Commands.OpenStartPage, () => startPage.open()); cmdManager.executeCommand('setContext', 'python.vscode.channel', applicationEnv.channel).then(noop, noop); serviceContainer.get(IApplicationDiagnostics).register(); diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index db98680a919e..e0613574cfb1 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -9,7 +9,6 @@ import { DiagnosticCodes } from '../application/diagnostics/constants'; import { IWorkspaceService } from '../common/application/types'; import { AppinsightsKey, isTestExecution, isUnitTestExecution, PVSC_EXTENSION_ID } from '../common/constants'; import { traceError, traceInfo } from '../common/logger'; -import { Telemetry } from '../common/startPage/constants'; import type { TerminalShellType } from '../common/terminal/types'; import { StopWatch } from '../common/utils/stopWatch'; import { isPromise } from '../common/utils/async'; @@ -1696,33 +1695,6 @@ export interface IEventNamePropertyMapping { selection: 'Do not show again' | undefined; }; - [Telemetry.WebviewStyleUpdate]: never | undefined; - [Telemetry.WebviewMonacoStyleUpdate]: never | undefined; - [Telemetry.WebviewStartup]: { type: string }; - [Telemetry.EnableInteractiveShiftEnter]: never | undefined; - [Telemetry.DisableInteractiveShiftEnter]: never | undefined; - [Telemetry.ShiftEnterBannerShown]: never | undefined; - - // Start Page Events - [Telemetry.StartPageViewed]: never | undefined; - [Telemetry.StartPageOpenedFromCommandPalette]: never | undefined; - [Telemetry.StartPageOpenedFromNewInstall]: never | undefined; - [Telemetry.StartPageOpenedFromNewUpdate]: never | undefined; - [Telemetry.StartPageWebViewError]: never | undefined; - [Telemetry.StartPageTime]: never | undefined; - [Telemetry.StartPageClickedDontShowAgain]: never | undefined; - [Telemetry.StartPageClosedWithoutAction]: never | undefined; - [Telemetry.StartPageUsedAnActionOnFirstTime]: never | undefined; - [Telemetry.StartPageOpenBlankNotebook]: never | undefined; - [Telemetry.StartPageOpenBlankPythonFile]: never | undefined; - [Telemetry.StartPageOpenInteractiveWindow]: never | undefined; - [Telemetry.StartPageOpenCommandPalette]: never | undefined; - [Telemetry.StartPageOpenCommandPaletteWithOpenNBSelected]: never | undefined; - [Telemetry.StartPageOpenSampleNotebook]: never | undefined; - [Telemetry.StartPageOpenFileBrowser]: never | undefined; - [Telemetry.StartPageOpenFolder]: never | undefined; - [Telemetry.StartPageOpenWorkspace]: never | undefined; - // TensorBoard integration events /** * Telemetry event sent after the user has clicked on an option in the prompt we display diff --git a/src/startPage-ui/common/index.css b/src/startPage-ui/common/index.css deleted file mode 100644 index 22f8f1897100..000000000000 --- a/src/startPage-ui/common/index.css +++ /dev/null @@ -1,5 +0,0 @@ -body { - margin: 0; - padding: 0; - font-family: sans-serif; -} diff --git a/src/startPage-ui/common/main.ts b/src/startPage-ui/common/main.ts deleted file mode 100644 index c709d726672b..000000000000 --- a/src/startPage-ui/common/main.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -declare let __webpack_public_path__: string; - -if ((window as any).__PVSC_Public_Path) { - // This variable tells Webpack to this as the root path used to request webpack bundles. - - __webpack_public_path__ = (window as any).__PVSC_Public_Path; -} diff --git a/src/startPage-ui/react-common/image.tsx b/src/startPage-ui/react-common/image.tsx deleted file mode 100644 index afeabf6854f6..000000000000 --- a/src/startPage-ui/react-common/image.tsx +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as React from 'react'; - -import InlineSVG from 'svg-inline-react'; - -// This react component loads our svg files inline so that we can load them in vscode as it no longer -// supports loading svgs from disk. Please put new images in this list as appropriate. -export enum ImageName { - Notebook, - Interactive, - Python, - PythonColor, - OpenFolder, -} - -// All of the images must be 'require' so that webpack doesn't rewrite the import as requiring a .default. - -const images: { [key: string]: { light: string; dark: string } } = { - Notebook: { - light: require('./images/StartPage/Notebook.svg'), - dark: require('./images/StartPage/Notebook-inverse.svg'), - }, - Interactive: { - light: require('./images/StartPage/Interactive.svg'), - dark: require('./images/StartPage/Interactive-inverse.svg'), - }, - Python: { - light: require('./images/StartPage/Python.svg'), - dark: require('./images/StartPage/Python-inverse.svg'), - }, - PythonColor: { - light: require('./images/StartPage/Python-color.svg'), - dark: require('./images/StartPage/Python-color.svg'), - }, - OpenFolder: { - light: require('./images/StartPage/OpenFolder.svg'), - dark: require('./images/StartPage/OpenFolder-inverse.svg'), - }, -}; - -interface IImageProps { - baseTheme: string; - image: ImageName; - class: string; - title?: string; -} - -export class Image extends React.Component { - constructor(props: IImageProps) { - super(props); - } - - public render() { - const key = ImageName[this.props.image].toString(); - const image = images.hasOwnProperty(key) ? images[key] : images.Cancel; // Default is cancel. - const source = this.props.baseTheme.includes('dark') ? image.dark : image.light; - return ; - } -} diff --git a/src/startPage-ui/react-common/images/StartPage/Interactive-inverse.svg b/src/startPage-ui/react-common/images/StartPage/Interactive-inverse.svg deleted file mode 100644 index 87819244977e..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/Interactive-inverse.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/startPage-ui/react-common/images/StartPage/Interactive.svg b/src/startPage-ui/react-common/images/StartPage/Interactive.svg deleted file mode 100644 index 6731d50fee39..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/Interactive.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/startPage-ui/react-common/images/StartPage/Notebook-inverse.svg b/src/startPage-ui/react-common/images/StartPage/Notebook-inverse.svg deleted file mode 100644 index 12b217d48fb8..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/Notebook-inverse.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/startPage-ui/react-common/images/StartPage/Notebook.svg b/src/startPage-ui/react-common/images/StartPage/Notebook.svg deleted file mode 100644 index 5e058afb30eb..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/Notebook.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/startPage-ui/react-common/images/StartPage/OpenFolder-inverse.svg b/src/startPage-ui/react-common/images/StartPage/OpenFolder-inverse.svg deleted file mode 100644 index e3d0f3e933e7..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/OpenFolder-inverse.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/startPage-ui/react-common/images/StartPage/OpenFolder.svg b/src/startPage-ui/react-common/images/StartPage/OpenFolder.svg deleted file mode 100644 index 309858c9f469..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/OpenFolder.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/startPage-ui/react-common/images/StartPage/Python-color.svg b/src/startPage-ui/react-common/images/StartPage/Python-color.svg deleted file mode 100644 index e9b909eab46b..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/Python-color.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/startPage-ui/react-common/images/StartPage/Python-inverse.svg b/src/startPage-ui/react-common/images/StartPage/Python-inverse.svg deleted file mode 100644 index 73708a57db29..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/Python-inverse.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/startPage-ui/react-common/images/StartPage/Python.svg b/src/startPage-ui/react-common/images/StartPage/Python.svg deleted file mode 100644 index 9a4d621e91c0..000000000000 --- a/src/startPage-ui/react-common/images/StartPage/Python.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/startPage-ui/react-common/locReactSide.ts b/src/startPage-ui/react-common/locReactSide.ts deleted file mode 100644 index dec1f5fa6946..000000000000 --- a/src/startPage-ui/react-common/locReactSide.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; -// The react code can't use the localize.ts module because it reads from -// disk. This isn't allowed inside a browser, so we pass the collection -// through the javascript. -let loadedCollection: Record | undefined; - -export function getLocString(key: string, defValue: string): string { - if (loadedCollection && loadedCollection.hasOwnProperty(key)) { - return loadedCollection[key]; - } - - return defValue; -} - -export function storeLocStrings(collection: Record) { - loadedCollection = collection; -} diff --git a/src/startPage-ui/react-common/logger.ts b/src/startPage-ui/react-common/logger.ts deleted file mode 100644 index 9d0fc55b5758..000000000000 --- a/src/startPage-ui/react-common/logger.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; -import { isTestExecution } from '../../client/common/constants'; - -const enableLogger = !isTestExecution() || process.env.VSC_PYTHON_FORCE_LOGGING || process.env.VSC_PYTHON_LOG_FILE; - -// Might want to post this back to the other side too. This was -export function logMessage(message: string) { - // put here to prevent having to disable the console log warning - if (enableLogger) { - console.log(message); - } -} diff --git a/src/startPage-ui/react-common/postOffice.ts b/src/startPage-ui/react-common/postOffice.ts deleted file mode 100644 index 6c3e6e4943c1..000000000000 --- a/src/startPage-ui/react-common/postOffice.ts +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { Observable } from 'rxjs/Observable'; -import { Subject } from 'rxjs/Subject'; -import { WebviewMessage } from '../../client/common/application/types'; -import { IDisposable } from '../../client/common/types'; -import { logMessage } from './logger'; - -export interface IVsCodeApi { - postMessage(msg: any): void; - - setState(state: any): void; - - getState(): any; -} - -export interface IMessageHandler { - handleMessage(type: string, payload?: any): boolean; - dispose?(): void; -} - -// This special function talks to vscode from a web panel -export declare function acquireVsCodeApi(): IVsCodeApi; - -export type PostOfficeMessage = { type: string; payload?: any }; - -export class PostOffice implements IDisposable { - private registered: boolean = false; - private vscodeApi: IVsCodeApi | undefined; - private handlers: IMessageHandler[] = []; - private baseHandler = this.handleMessages.bind(this); - private readonly subject = new Subject(); - private readonly observable: Observable; - constructor() { - this.observable = this.subject.asObservable(); - } - public asObservable(): Observable { - return this.observable; - } - public dispose() { - if (this.registered) { - this.registered = false; - window.removeEventListener('message', this.baseHandler); - } - } - - public sendMessage(type: T, payload?: M[T]) { - return this.sendUnsafeMessage(type.toString(), payload); - } - - public sendUnsafeMessage(type: string, payload?: any) { - const api = this.acquireApi(); - if (api) { - api.postMessage({ type: type, payload }); - } else { - logMessage(`No vscode API to post message ${type}`); - } - } - - public addHandler(handler: IMessageHandler) { - // Acquire here too so that the message handlers are setup during tests. - this.acquireApi(); - this.handlers.push(handler); - } - - public removeHandler(handler: IMessageHandler) { - this.handlers = this.handlers.filter((f) => f !== handler); - } - - private acquireApi(): IVsCodeApi | undefined { - // Only do this once as it crashes if we ask more than once - - if (!this.vscodeApi && typeof acquireVsCodeApi !== 'undefined') { - this.vscodeApi = acquireVsCodeApi(); // NOSONAR - } - if (!this.registered) { - this.registered = true; - window.addEventListener('message', this.baseHandler); - - try { - // For testing, we might use a browser to load the stuff. - // In such instances the `acquireVSCodeApi` will return the event handler to get messages from extension. - // See ./src/startPage-ui/startPage/index.html - - const api = (this.vscodeApi as any) as { handleMessage?: Function }; - if (api && api.handleMessage) { - api.handleMessage(this.handleMessages.bind(this)); - } - } catch { - // Ignore. - } - } - - return this.vscodeApi; - } - - private async handleMessages(ev: MessageEvent) { - if (this.handlers) { - const msg = ev.data as WebviewMessage; - if (msg) { - this.subject.next({ type: msg.type, payload: msg.payload }); - this.handlers.forEach((h: IMessageHandler | null) => { - if (h) { - h.handleMessage(msg.type, msg.payload); - } - }); - } - } - } -} diff --git a/src/startPage-ui/react-common/themeDetector.ts b/src/startPage-ui/react-common/themeDetector.ts deleted file mode 100644 index 35df18efaadc..000000000000 --- a/src/startPage-ui/react-common/themeDetector.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -// From here: -// https://stackoverflow.com/questions/37257911/detect-light-dark-theme-programatically-in-visual-studio-code -// Detect vscode-light, vscode-dark, and vscode-high-contrast class name on the body element. -export function detectBaseTheme(): 'vscode-light' | 'vscode-dark' | 'vscode-high-contrast' { - const { body } = document; - if (body) { - switch (body.className) { - case 'vscode-light': - return 'vscode-light'; - case 'vscode-dark': - return 'vscode-dark'; - case 'vscode-high-contrast': - return 'vscode-high-contrast'; - default: - return 'vscode-light'; - } - } - - return 'vscode-light'; -} diff --git a/src/startPage-ui/startPage/index.html b/src/startPage-ui/startPage/index.html deleted file mode 100644 index b405e61a8e80..000000000000 --- a/src/startPage-ui/startPage/index.html +++ /dev/null @@ -1,356 +0,0 @@ - - - - - - - Python Extension Plot Viewer - - - - -
- - - diff --git a/src/startPage-ui/startPage/index.tsx b/src/startPage-ui/startPage/index.tsx deleted file mode 100644 index e26d8a6821f3..000000000000 --- a/src/startPage-ui/startPage/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -// This must be on top, do not change. Required by webpack. -import '../common/main'; -// This must be on top, do not change. Required by webpack. - -import '../common/index.css'; - -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; - -import { IVsCodeApi } from '../react-common/postOffice'; -import { detectBaseTheme } from '../react-common/themeDetector'; -import { StartPage } from './startPage'; - -// This special function talks to vscode from a web panel -export declare function acquireVsCodeApi(): IVsCodeApi; - -const baseTheme = detectBaseTheme(); - -const testMode = (window as any).inTestMode; - -const skipDefault = testMode ? false : typeof acquireVsCodeApi !== 'undefined'; - -ReactDOM.render( - , - document.getElementById('root') as HTMLElement, -); diff --git a/src/startPage-ui/startPage/startPage.css b/src/startPage-ui/startPage/startPage.css deleted file mode 100644 index 035610dcebf8..000000000000 --- a/src/startPage-ui/startPage/startPage.css +++ /dev/null @@ -1,93 +0,0 @@ -.main-page { - margin: 50px; - font-family: var(--font-family); - min-width: 700px; -} - -.title-icon { - display: inline-block; - vertical-align: top; - width: 40px; - margin-right: 10px; -} - -.icon { - display: inline-block; - width: 45px; - padding: 20px 25px 20px 25px; - margin-right: 30px; - background-color: var(--vscode-titleBar-activeBackground); -} - -.icon:hover, -.text:hover { - background-color: var(--vscode-editorIndentGuide-activeBackground); - cursor: pointer; -} - -.title { - display: inline-block; - vertical-align: top; - font-size: xx-large; -} - -.title-row { - display: block; - height: 80px; -} - -.text { - font-weight: 100; - font-size: x-large; - width: fit-content; -} - -.block { - display: inline-block; - vertical-align: top; -} - -.row { - display: block; - min-height: 120px; - white-space: nowrap; -} - -.releaseNotesRow { - display: block; - min-height: 50px; - white-space: nowrap; -} - -.link { - display: inline; - color: var(--vscode-debugIcon-continueForeground); - text-decoration: none; -} - -.link:hover { - cursor: pointer; - color: var(--vscode-button-hoverBackground); -} - -.italics { - display: inline; - font-style: italic; -} - -.checkbox { - margin: 1em 1em 1em 0em; -} - -.paragraph { - display: block; - margin-block-start: 5px; - margin-block-end: 5px; - margin-inline-start: 0px; - margin-inline-end: 0px; -} - -.list { - line-height: 1.5; - white-space: initial; -} diff --git a/src/startPage-ui/startPage/startPage.tsx b/src/startPage-ui/startPage/startPage.tsx deleted file mode 100644 index 54a08d7fd51a..000000000000 --- a/src/startPage-ui/startPage/startPage.tsx +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -/* eslint-disable react/sort-comp */ - -import * as React from 'react'; -import '../../client/common/extensions'; -import { SharedMessages } from '../../client/common/startPage/messages'; -import { ISettingPackage, IStartPageMapping, StartPageMessages } from '../../client/common/startPage/types'; -import { Image, ImageName } from '../react-common/image'; -import { getLocString, storeLocStrings } from '../react-common/locReactSide'; -import { IMessageHandler, PostOffice } from '../react-common/postOffice'; -import './startPage.css'; - -export interface IStartPageProps { - skipDefault?: boolean; - baseTheme: string; - testMode?: boolean; -} - -type StartPageWindowType = typeof window & { - openBlankNotebook(): void; - createPythonFile(): void; - openFileBrowser(): void; - openFolder(): void; - openWorkspace(): void; - openCommandPalette(): void; - openCommandPaletteWithSelection(): void; - openSampleNotebook(): void; -}; - -// Front end of the Python extension start page. -// In general it consists of its render method and methods that send and receive messages. -export class StartPage extends React.Component implements IMessageHandler { - private releaseNotes: ISettingPackage = { - showAgainSetting: false, - }; - - private postOffice: PostOffice = new PostOffice(); - - public componentWillMount(): void { - // Add ourselves as a handler for the post office - this.postOffice.addHandler(this); - - // Tell the start page code we have started. - this.postOffice.sendMessage(StartPageMessages.Started); - - // Bind some functions to the window, as we need them to be accessible with clean HTML to use translations - (window as StartPageWindowType).openBlankNotebook = this.openBlankNotebook.bind(this); - (window as StartPageWindowType).createPythonFile = this.createPythonFile.bind(this); - (window as StartPageWindowType).openFileBrowser = this.openFileBrowser.bind(this); - (window as StartPageWindowType).openFolder = this.openFolder.bind(this); - (window as StartPageWindowType).openWorkspace = this.openWorkspace.bind(this); - (window as StartPageWindowType).openCommandPalette = this.openCommandPalette.bind(this); - (window as StartPageWindowType).openCommandPaletteWithSelection = this.openCommandPaletteWithSelection.bind( - this, - ); - (window as StartPageWindowType).openSampleNotebook = this.openSampleNotebook.bind(this); - } - - public componentDidMount(): void { - this.postOffice.sendMessage(StartPageMessages.RequestShowAgainSetting); - } - - public render(): React.ReactNode { - const { baseTheme } = this.props; - - return ( -
-
-
- -
-
{getLocString('StartPage.pythonExtensionTitle', 'Python Extension')}
-
-
-
- -
-
-
- {getLocString('StartPage.createJupyterNotebook', 'Create a Jupyter Notebook')} -
- {this.renderNotebookDescription()} -
-
-
-
- -
-
-
- {getLocString('StartPage.createAPythonFile', 'Create a Python File')} -
- {this.renderPythonFileDescription()} -
-
-
-
- -
-
-
- {getLocString('StartPage.openFolder', 'Open a Folder or Workspace')} -
- {this.renderFolderDescription()} -
-
-
-
- -
-
-
- {getLocString( - 'StartPage.openInteractiveWindow', - 'Use the Interactive Window to develop Python Scripts', - )} -
- {this.renderInteractiveWindowDescription()} -
-
-
- {this.renderReleaseNotesLink()} - {this.renderTutorialAndDoc()} - {this.renderMailingList()} -
-
- -
-
-

{getLocString('StartPage.dontShowAgain', "Don't show this page again")}

-
-
- ); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types - public handleMessage = (msg: string, payload?: any): boolean => { - switch (msg) { - case StartPageMessages.SendSetting: - this.releaseNotes.showAgainSetting = payload.showAgainSetting; - this.setState({}); - break; - - case SharedMessages.LocInit: - { - // Initialize localization. - const locJSON = JSON.parse(payload); - storeLocStrings(locJSON); - } - break; - - default: - break; - } - - return false; - }; - - public openFileBrowser(): void { - this.postOffice.sendMessage(StartPageMessages.OpenFileBrowser); - } - - public openFolder = (): void => { - this.postOffice.sendMessage(StartPageMessages.OpenFolder); - }; - - public openWorkspace(): void { - this.postOffice.sendMessage(StartPageMessages.OpenWorkspace); - } - - // eslint-disable-next-line class-methods-use-this - private renderNotebookDescription(): JSX.Element { - return ( - " in the Command Palette (
Shift + Command + P
)
- Explore our to learn about notebook features', - ).format('openCommandPaletteWithSelection()', 'openSampleNotebook()'), - }} - /> - ); - } - - // eslint-disable-next-line class-methods-use-this - private renderPythonFileDescription(): JSX.Element { - return ( - with a .py extension', - ).format('createPythonFile()'), - }} - /> - ); - } - - // eslint-disable-next-line class-methods-use-this - private renderInteractiveWindowDescription(): JSX.Element { - return ( -
- Use "
Shift + Enter
" 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 ( -
- Open a ', - ).format('openFolder()', 'openWorkspace()'), - }} - /> - ); - } - - // eslint-disable-next-line class-methods-use-this - private renderReleaseNotesLink(): JSX.Element { - return ( -