diff --git a/StartPageReleaseNotes.md b/StartPageReleaseNotes.md new file mode 100644 index 000000000000..5fb96d33988a --- /dev/null +++ b/StartPageReleaseNotes.md @@ -0,0 +1,3 @@ +Added a start page for the extension. Launched in experimental mode such that it opens to new users or when there is a new release. It can be disabled with the setting 'Python: Show Start Page' and it can be opened at any time with the command 'Python: Open Start Page'. +Removed `python.jediEnabled` setting in favor of `python.languageServer`. Instead of `"python.jediEnabled": true` please use `"python.languageServer": "Jedi"`. +Made the variable explorer in the Notebook editor resizable. diff --git a/images/dataviewer.gif b/images/dataviewer.gif index 17e13a8391c7..b2f5e080a401 100644 Binary files a/images/dataviewer.gif and b/images/dataviewer.gif differ diff --git a/images/kernelchange.gif b/images/kernelchange.gif index eef0f5d4ebcc..a414e2252efa 100644 Binary files a/images/kernelchange.gif and b/images/kernelchange.gif differ diff --git a/images/plotviewer.gif b/images/plotviewer.gif index b88a379a5f7a..d1f6524f3769 100644 Binary files a/images/plotviewer.gif and b/images/plotviewer.gif differ diff --git a/images/remoteserver.gif b/images/remoteserver.gif index bcf5f27c2867..be836e673b72 100644 Binary files a/images/remoteserver.gif and b/images/remoteserver.gif differ diff --git a/images/runbyline.gif b/images/runbyline.gif new file mode 100644 index 000000000000..1c0679f9a458 Binary files /dev/null and b/images/runbyline.gif differ diff --git a/images/savetopythonfile.png b/images/savetopythonfile.png index 02045f630463..ccb0a7bfa387 100644 Binary files a/images/savetopythonfile.png and b/images/savetopythonfile.png differ diff --git a/images/variableexplorer.png b/images/variableexplorer.png index 3d1db79a5ca0..0f6c9f73b4de 100644 Binary files a/images/variableexplorer.png and b/images/variableexplorer.png differ diff --git a/package.json b/package.json index a2294bdee15d..d1d5806f0b54 100644 --- a/package.json +++ b/package.json @@ -1114,8 +1114,7 @@ { "command": "python.startPage.open", "title": "%python.command.python.startPage.open.title%", - "category": "Python", - "when": "python.datascience.startpageenabled" + "category": "Python" }, { "command": "python.datascience.runtoline", diff --git a/package.nls.json b/package.nls.json index fb3aa83dc05a..a9e0540f7888 100644 --- a/package.nls.json +++ b/package.nls.json @@ -495,16 +495,18 @@ "StartPage.getStarted": "Python - Get Started", "StartPage.pythonExtensionTitle": "Python Extension", "StartPage.createJupyterNotebook": "Create a Jupyter Notebook", - "StartPage.notebookDescription": "- Use \"
Shift + Command + P
\" to open the
Command Palette

- Type \" \"
- Explore our
sample notebook
to learn about notebook features", + "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 and use the .py extension
-
Open a file or workspace
to continue work", - "StartPage.openInteractiveWindow": "Open the Interactive Window", + "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 \"#%%\"
- 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.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": "Welcome_To_VSCode_Notebooks.ipynb", + "StartPage.sampleNotebook": "Notebooks intro", + "StartPage.openFolder": "Open a Folder or Workspace", + "StartPage.folderDesc": "- Open a
Folder

- Open a
Workspace
", "DataScience.libraryRequiredToLaunchJupyterKernelNotInstalledInterpreter": "{0} requires {1} to be installed.", "DataScience.runByLine": "Run by line (F10)", "DataScience.stopRunByLine": "Stop", diff --git a/pythonFiles/Notebooks intro.ipynb b/pythonFiles/Notebooks intro.ipynb new file mode 100644 index 000000000000..4fcd31fad674 --- /dev/null +++ b/pythonFiles/Notebooks intro.ipynb @@ -0,0 +1,203 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Creating a new notebook\n", + "\n", + "\n", + "\n", + "1.

Open the command palette with the shortcut: ", + " \n", + " Ctrl/Command\n", + " +\n", + " Shift\n", + " +\n", + " P\n", + "

\n", + "\n", + "2.

Search for the command Create New Blank Jupyter Notebook

\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "# How to get back to the start page\n", + "\n", + "1.

Open the command palette with the shortcut:\n", + " \n", + " Ctrl/Command\n", + " +\n", + " Shift\n", + " +\n", + " P\n", + "

\n", + "\n", + "2.

Search for the command Python: Open Start Page

\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "# Getting started\n", + "\n", + "You are currently viewing what we call our Notebook Editor. It is an interactive document based on Jupyter Notebooks that supports the intermixing of code, outputs and markdown documentation. \n", + "\n", + "This cell is a markdown cell. To edit the text in this cell, simply click on the cell to change it into edit mode.\n", + "\n", + "

The next cell below is a code cell. You can switch a cell between code and markdown by clicking on the code \n", + "\n", + "/markdown \n", + "\n", + " icons or using the keyboard shortcut\n", + " \n", + " M\n", + " \n", + "and\n", + " \n", + " Y\n", + " \n", + "respectively.

\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('hello world')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*

To execute the code in the cell above, click on the cell to select it and then either press the play \n", + "\n", + "\n", + " button in the cell toolbar, or use the keyboard shortcut\n", + " \n", + " Ctrl/Command\n", + " +\n", + " Enter\n", + " \n", + "

\n", + "* To edit the code, just click in cell and start editing.\n", + "*

To add a new cell below, click the Add Cell icon \n", + "\n", + "\n", + " \n", + "at the bottom left of the cell or enter command mode with the\n", + " \n", + " ESC\n", + " \n", + "Key and then use the keyboard shortcut\n", + " \n", + " B\n", + " \n", + "to create the new cell below.

\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "# Features\n", + "\n", + "**Variable explorer**\n", + "\n", + "

To view all your active variables and their current values in the notebook, click on the variable explorer icon \n", + "\n", + "\n", + "\n", + "in the top toolbar.

\n", + "\n", + "\n", + "\n", + "**Data Viewer**\n", + "\n", + "

To view your data frame in a more visual \"Excel\" like format, open the variable explorer and to the left of any dataframe object, you will see the data viewer icon\n", + "\n", + "\n", + "\n", + "which you can click to open the data viewer.

\n", + "\n", + "\n", + "\n", + "**Convert to Python File**\n", + "\n", + "

To export your notebook to a Python file (.py), click on the Convert to Python script icon \n", + "\n", + "\n", + "\n", + "\n", + "in the top toolbar \n", + "

\n", + "\n", + "\n", + "\n", + "**Plot Viewer**\n", + "\n", + "

If you have a graph (such as matplotlib) in your output, you'll notice if you hover over the graph, the Plot Viewer icon \n", + "\n", + "\n", + "\n", + "will appear in the top left. Click the icon to open up the graph in the Plotviewer which allows you to zoom on your plots and export it in formats such as png and jpeg.

\n", + "\n", + "\n", + "\n", + "**Switching Kernels**\n", + "\n", + "The notebook editor will detect all kernels in your system by default. To change your notebook kernel, click on the kernel status in the top toolbar at the far right. For example, your kernel status may say \"Python 3: Idle\". This will open up the kernel selector where you can choose your desired kernel.\n", + "\n", + "\n", + "\n", + "**Remote Jupyter Server**\n", + "\n", + "

To connect to a remote Jupyter server, open the command prompt and search for the command Specify remote or local Jupyter server for connections. Then select Existing and enter the remote Jupyter server URL. Afterwards, you'll be prompted to reload the window and the Notebook will be opened connected to the remote Jupyter server.

\n", + "\n", + "", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "-Rh3-Vt9Nev9" + }, + "source": [ + "---\n", + "## More Resources\n", + "\n", + "- [Data science tutorial for Visual Studio Code](https://code.visualstudio.com/docs/python/data-science-tutorial)\n", + "- [Jupyter Notebooks in Visual Studio Code documentation](https://code.visualstudio.com/docs/python/jupyter-support)\n" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/pythonFiles/Welcome_To_VSCode_Notebooks.ipynb b/pythonFiles/Welcome_To_VSCode_Notebooks.ipynb deleted file mode 100644 index 8e77908d6fa0..000000000000 --- a/pythonFiles/Welcome_To_VSCode_Notebooks.ipynb +++ /dev/null @@ -1,192 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Creating a new notebook\n", - "\n", - "\n", - "\n", - "1.
\n", - "
Open the command palette with the shortcut:
\n", - "
\n", - "
\n", - " Ctrl/Command\n", - " +\n", - " Shift\n", - " +\n", - " P\n", - "
\n", - "
\n", - "
\n", - "\n", - "2.

Search for the command Create New Blank Jupyter Notebook

\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to get back to the start page\n", - "\n", - "1.
\n", - "
Open the command palette with the shortcut:
\n", - "
\n", - "
\n", - " Ctrl/Command\n", - " +\n", - " Shift\n", - " +\n", - " P\n", - "
\n", - "
\n", - "
\n", - "\n", - "2.

Search for the command Python: Open Start Page

\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Getting started\n", - "\n", - "This view is what we call our Notebook Editor, an interactive environment that lets you write and execute code." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print('hello world')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "-
\n", - "
To execute the code in the cell above, click on the cell to select it and then either press the play \n", - "\n", - "\n", - " button in the cell toolbar, or use the keyboard shortcut
\n", - "
\n", - "
\n", - " Ctrl/Command\n", - " +\n", - " Enter\n", - "
\n", - "
\n", - "
\n", - "- To edit the code, just click in cell and start editing.\n", - "-
\n", - "
To add a new cell below, click the Add Cell icon \n", - "\n", - "\n", - " \n", - "at the bottom left of the cell or enter command mode with the
\n", - "
\n", - "
\n", - " ESC\n", - "
\n", - "
\n", - "
Key and then use the keyboard shortcut
\n", - "
\n", - "
\n", - " B\n", - "
\n", - "
\n", - "
to create the new cell below.
\n", - "
\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Features\n", - "\n", - "**Variable explorer**\n", - "\n", - "

To view all your active variables and their current values in the notebook, click on the variable explorer icon \n", - "\n", - "\n", - "\n", - "in the top toolbar.

\n", - "\n", - "\n", - "\n", - "**Data Viewer**\n", - "\n", - "

To view your data frame in a more visual \"Excel\" like format, open the variable explorer and to the left of any dataframe object, you will see the data viewer icon\n", - "\n", - "\n", - "\n", - "which you can click to open the data viewer.

\n", - "\n", - "\n", - "\n", - "**Convert to Python File**\n", - "\n", - "

To export your notebook to a Python file (.py), click on the Convert to Python script icon \n", - "\n", - "\n", - "\n", - "\n", - "in the top toolbar \n", - "

\n", - "\n", - "\n", - "\n", - "**Plot Viewer**\n", - "\n", - "

If you have a graph (such as matplotlib) in your output, you'll notice if you hover over the graph, the Plot Viewer icon \n", - "\n", - "\n", - "\n", - "will appear in the top left. Click the icon to open up the graph in the Plotviewer which allows you to zoom on your plots and export it in formats such as png and jpeg.

\n", - "\n", - "\n", - "\n", - "**Switching Kernels**\n", - "\n", - "The notebook editor will detect all kernels in your system by default. To change your notebook kernel, click on the kernel status in the top toolbar at the far right. For example, your kernel status may say \"Python 3: Idle\". This will open up the kernel selector where you can choose your desired kernel.\n", - "\n", - "\n", - "\n", - "**Remote Jupyter Server**\n", - "\n", - "

To connect to a remote Jupyter server, open the command prompt and search for the command Specify remote or local Jupyter server for connections. Then select Existing and enter the remote Jupyter server URL. Afterwards, you'll be prompted to reload the window and the Notebook will be opened connected to the remote Jupyter server.

\n", - "\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "-Rh3-Vt9Nev9" - }, - "source": [ - "## More Resources\n", - "\n", - "- [Data science tutorial for Visual Studio Code](https://code.visualstudio.com/docs/python/data-science-tutorial)\n", - "- [Jupyter Notebooks in Visual Studio Code documentation](https://code.visualstudio.com/docs/python/jupyter-support)\n" - ] - } - ], - "metadata": {}, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index bddacd149337..9e99bf6f3ca9 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -88,6 +88,8 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu ['vscode.openWith']: [Uri, string]; ['workbench.action.quickOpen']: [string]; ['workbench.extensions.installExtension']: [Uri | 'ms-python.python']; + ['workbench.action.files.openFolder']: []; + ['workbench.action.openWorkspace']: []; ['setContext']: [string, boolean]; ['python.reloadVSCode']: [string]; ['revealLine']: [{ lineNumber: number; at: 'top' | 'center' | 'bottom' }]; diff --git a/src/client/common/experiments/groups.ts b/src/client/common/experiments/groups.ts index dde206554c7a..6ad564bad56b 100644 --- a/src/client/common/experiments/groups.ts +++ b/src/client/common/experiments/groups.ts @@ -110,3 +110,8 @@ export enum CustomEditorSupport { control = 'CustomEditorSupport - control', experiment = 'CustomEditorSupport - experiment' } + +// Experiment to turn on the start page +export enum EnableStartPage { + experiment = 'EnableStartPage' +} diff --git a/src/client/common/startPage/startPage.ts b/src/client/common/startPage/startPage.ts index e6c57370c33b..9f360466f87c 100644 --- a/src/client/common/startPage/startPage.ts +++ b/src/client/common/startPage/startPage.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import { ConfigurationTarget, EventEmitter, ViewColumn } from 'vscode'; import { IExtensionSingleActivationService } from '../../activation/types'; import { EXTENSION_ROOT_DIR } from '../../constants'; -import { Commands, EditorContexts, Telemetry } from '../../datascience/constants'; +import { Commands, Telemetry } from '../../datascience/constants'; import { ICodeCssGenerator, INotebookEditorProvider, IThemeFinder } from '../../datascience/types'; import { WebViewHost } from '../../datascience/webViewHost'; import { sendTelemetryEvent } from '../../telemetry'; @@ -19,13 +19,13 @@ import { IWebPanelProvider, IWorkspaceService } from '../application/types'; -import { ContextKey } from '../contextKey'; +import { EnableStartPage } from '../experiments/groups'; import { IFileSystem } from '../platform/types'; import { IConfigurationService, IExperimentService, IExtensionContext, Resource } from '../types'; import * as localize from '../utils/localize'; import { StopWatch } from '../utils/stopWatch'; import { StartPageMessageListener } from './startPageMessageListener'; -import { EnableStartPage, IStartPage, IStartPageMapping, StartPageMessages } from './types'; +import { IStartPage, IStartPageMapping, StartPageMessages } from './types'; const startPageDir = path.join(EXTENSION_ROOT_DIR, 'out', 'datascience-ui', 'viewers'); @@ -38,6 +38,7 @@ export class StartPage extends WebViewHost implements IStartP private actionTaken = false; private actionTakenOnFirstTime = false; private firstTime = false; + private webviewDidLoad = false; constructor( @inject(IWebPanelProvider) provider: IWebPanelProvider, @inject(ICodeCssGenerator) cssGenerator: ICodeCssGenerator, @@ -88,7 +89,13 @@ export class StartPage extends WebViewHost implements IStartP await this.loadWebPanel(process.cwd()); // open webview await super.show(true); - }, 0); + + setTimeout(() => { + if (!this.webviewDidLoad) { + sendTelemetryEvent(Telemetry.StartPageWebViewError); + } + }, 5000); + }, 3000); } public async getOwningResource(): Promise { @@ -110,6 +117,9 @@ export class StartPage extends WebViewHost implements IStartP // tslint:disable-next-line: no-any public async onMessage(message: string, payload: any) { switch (message) { + case StartPageMessages.Started: + this.webviewDidLoad = true; + break; case StartPageMessages.RequestReleaseNotesAndShowAgainSetting: const settings = this.configuration.getSettings(); const filteredNotes = await this.handleReleaseNotesRequest(); @@ -134,7 +144,10 @@ export class StartPage extends WebViewHost implements IStartP sendTelemetryEvent(Telemetry.StartPageOpenBlankPythonFile); this.setTelemetryFlags(); - const doc = await this.documentManager.openTextDocument({ language: 'python' }); + const doc = await this.documentManager.openTextDocument({ + language: 'python', + content: `print("${localize.StartPage.helloWorld()}")` + }); await this.documentManager.showTextDocument(doc, 1, true); break; case StartPageMessages.OpenInteractiveWindow: @@ -184,6 +197,16 @@ export class StartPage extends WebViewHost implements IStartP 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); @@ -197,44 +220,36 @@ export class StartPage extends WebViewHost implements IStartP super.onMessage(message, payload); } - // This gets the most recent Enhancements and date from CHANGELOG.md - // This is public for testing - public async handleReleaseNotesRequest(): Promise { - const changelog = await this.file.readFile(path.join(EXTENSION_ROOT_DIR, 'CHANGELOG.md')); - const changelogBeginning = changelog.indexOf('### Enhancements'); - const changelogEnding = changelog.indexOf('### Fixes', changelogBeginning); - const startOfLog = changelog.substring(changelogBeginning, changelogEnding); - - const scrappedNotes = startOfLog.splitLines(); - return scrappedNotes - .filter((line) => line.startsWith('1.')) - .slice(0, 5) - .map((line) => line.substr(3)); - } - // Public for testing public async extensionVersionChanged(): Promise { const savedVersion: string | undefined = this.context.globalState.get('extensionVersion'); const version: string = this.appEnvironment.packageJson.version; + let shouldShowStartPage: boolean; if (savedVersion && (savedVersion === version || this.savedVersionisOlder(savedVersion, version))) { // There has not been an update - return false; + shouldShowStartPage = false; + } else { + 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('extensionVersion', version); - return true; + return shouldShowStartPage; + } + + // This gets the release notes from StartPageReleaseNotes.md + private async handleReleaseNotesRequest(): Promise { + const releaseNotes = await this.file.readFile(path.join(EXTENSION_ROOT_DIR, 'StartPageReleaseNotes.md')); + return releaseNotes.splitLines(); } private async activateBackground(): Promise { const enabled = await this.expService.inExperiment(EnableStartPage.experiment); - const editorContext = new ContextKey(EditorContexts.StartPageEnabled, this.commandManager); - editorContext.set(enabled).ignoreErrors(); const settings = this.configuration.getSettings(); - if (enabled && settings.showStartPage && this.appEnvironment.extensionChannel === 'insiders') { + if (enabled && 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(); @@ -269,17 +284,22 @@ export class StartPage extends WebViewHost implements IStartP } private async openSampleNotebook(): Promise { - const localizedFilePath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', localize.StartPage.sampleNotebook()); + 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', 'Welcome_To_VSCode_Notebooks.ipynb'); + sampleNotebookPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'Notebooks intro.ipynb'); } const content = await this.file.readFile(sampleNotebookPath); - await this.notebookEditorProvider.createNew(content); + await this.notebookEditorProvider.createNew(content, localize.StartPage.sampleNotebook()); } private setTelemetryFlags() { diff --git a/src/client/common/startPage/types.ts b/src/client/common/startPage/types.ts index 66e0a3f632fb..0e724d7bff2d 100644 --- a/src/client/common/startPage/types.ts +++ b/src/client/common/startPage/types.ts @@ -2,16 +2,9 @@ // Licensed under the MIT License. import { SharedMessages } from '../../datascience/messages'; -// Move to common/experiments/groups.ts when the VS Code webview bug is fixed -export enum EnableStartPage { - control = 'EnableStartPage - control', - experiment = 'EnableStartPage - experiment' -} - export const IStartPage = Symbol('IStartPage'); export interface IStartPage { open(): Promise; - handleReleaseNotesRequest(): Promise; extensionVersionChanged(): Promise; } @@ -32,6 +25,8 @@ export namespace StartPageMessages { export const OpenCommandPaletteWithOpenNBSelected = 'OpenCommandPaletteWithOpenNBSelected'; export const OpenSampleNotebook = 'OpenSampleNotebook'; export const OpenFileBrowser = 'OpenFileBrowser'; + export const OpenFolder = 'OpenFolder'; + export const OpenWorkspace = 'OpenWorkspace'; } export class IStartPageMapping { @@ -46,4 +41,6 @@ export class IStartPageMapping { 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; } diff --git a/src/client/common/utils/localize.ts b/src/client/common/utils/localize.ts index 5053b51d24dc..1472ebee0447 100644 --- a/src/client/common/utils/localize.ts +++ b/src/client/common/utils/localize.ts @@ -961,14 +961,17 @@ export namespace StartPage { export const createJupyterNotebook = localize('StartPage.createJupyterNotebook', 'Create a Jupyter Notebook'); export const notebookDescription = localize( 'StartPage.notebookDescription', - '- Use "
Shift + Command + P
" to open the
- Type " "
- Explore our to learn about notebook features' + '- 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 new file and use the .py extension
- to continue work' + '- Create a with a .py extension' + ); + export const openInteractiveWindow = localize( + 'StartPage.openInteractiveWindow', + 'Use the Interactive Window to develop Python Scripts' ); - export const openInteractiveWindow = localize('StartPage.openInteractiveWindow', 'Open the Interactive Window'); export const interactiveWindowDesc = localize( 'StartPage.interactiveWindowDesc', '- You can create cells on a Python file by typing "#%%"
- Use "
Shift + Enter
" to run a cell, the output will be shown in the interactive window' @@ -986,7 +989,12 @@ export namespace StartPage { 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', 'Welcome_To_VSCode_Notebooks.ipynb'); + 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 namespace DebugConfigStrings { diff --git a/src/client/datascience/commands/commandRegistry.ts b/src/client/datascience/commands/commandRegistry.ts index 7c80b52ca677..4d1d24bbe8cc 100644 --- a/src/client/datascience/commands/commandRegistry.ts +++ b/src/client/datascience/commands/commandRegistry.ts @@ -8,8 +8,8 @@ import { CodeLens, ConfigurationTarget, env, Range, Uri } from 'vscode'; import { ICommandNameArgumentTypeMapping } from '../../common/application/commands'; import { IApplicationShell, ICommandManager, IDebugService, IDocumentManager } from '../../common/application/types'; import { Commands as coreCommands } from '../../common/constants'; -import { EnableStartPage, IStartPage } from '../../common/startPage/types'; -import { IConfigurationService, IDisposable, IExperimentService, IOutputChannel } from '../../common/types'; +import { IStartPage } from '../../common/startPage/types'; +import { IConfigurationService, IDisposable, IOutputChannel } from '../../common/types'; import { DataScience } from '../../common/utils/localize'; import { noop } from '../../common/utils/misc'; import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; @@ -43,8 +43,7 @@ export class CommandRegistry implements IDisposable { @inject(IConfigurationService) private configService: IConfigurationService, @inject(IApplicationShell) private appShell: IApplicationShell, @inject(IOutputChannel) @named(JUPYTER_OUTPUT_CHANNEL) private jupyterOutput: IOutputChannel, - @inject(IStartPage) private startPage: IStartPage, - @inject(IExperimentService) private readonly expService: IExperimentService + @inject(IStartPage) private startPage: IStartPage ) { this.disposables.push(this.serverSelectedCommand); this.disposables.push(this.kernelSwitcherCommand); @@ -350,9 +349,7 @@ export class CommandRegistry implements IDisposable { } private async openStartPage(): Promise { - if (await this.expService.inExperiment(EnableStartPage.experiment)) { - return this.startPage.open(); - } + return this.startPage.open(); } private viewJupyterOutput() { diff --git a/src/client/datascience/common.ts b/src/client/datascience/common.ts index a87ff374bcc3..65c4d61d0435 100644 --- a/src/client/datascience/common.ts +++ b/src/client/datascience/common.ts @@ -132,7 +132,7 @@ export function translateKernelLanguageToMonaco(kernelLanguage: string): string return kernelLanguage.toLowerCase(); } -export function generateNewNotebookUri(counter: number): Uri { +export function generateNewNotebookUri(counter: number, title?: string): Uri { // Because of this bug here: // https://github.com/microsoft/vscode/issues/93441 // We can't create 'untitled' files anymore. The untitled scheme will just be ignored. @@ -141,7 +141,7 @@ export function generateNewNotebookUri(counter: number): Uri { // However if there are files already on disk, we should be able to overwrite them because // they will only ever be used by 'open' editors. So just use the current counter for our untitled count. - const fileName = `${DataScience.untitledNotebookFileName()}-${counter}.ipynb`; + const fileName = title ? `${title}-${counter}.ipynb` : `${DataScience.untitledNotebookFileName()}-${counter}.ipynb`; const filePath = Uri.file(path.join(os.tmpdir(), fileName)); // Turn this back into an untitled return filePath.with({ scheme: 'untitled', path: filePath.fsPath }); diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index 5f02993742d9..5b4b6659e57e 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -113,7 +113,6 @@ export namespace EditorContexts { export const IsPythonOrInteractiveActive = 'python.datascience.ispythonorinteractiveeactive'; export const IsPythonOrInteractiveOrNativeActive = 'python.datascience.ispythonorinteractiveornativeeactive'; export const HaveCellSelected = 'python.datascience.havecellselected'; - export const StartPageEnabled = 'python.datascience.startpageenabled'; } export namespace RegExpValues { @@ -318,6 +317,7 @@ export enum Telemetry { RawKernelSessionStartException = 'DS_INTERNAL.RAWKERNEL_SESSION_START_EXCEPTION', RawKernelProcessLaunch = 'DS_INTERNAL.RAWKERNEL_PROCESS_LAUNCH', StartPageViewed = 'DS_INTERNAL.STARTPAGE_VIEWED', + StartPageWebViewError = 'DS_INTERNAL.STARTPAGE_WEBVIEWERROR', StartPageTime = 'DS_INTERNAL.STARTPAGE_TIME', StartPageClickedDontShowAgain = 'DATASCIENCE.STARTPAGE_DONT_SHOW_AGAIN', StartPageClosedWithoutAction = 'DATASCIENCE.STARTPAGE_CLOSED_WITHOUT_ACTION', @@ -328,7 +328,9 @@ export enum Telemetry { 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' + StartPageOpenFileBrowser = 'DATASCIENCE.STARTPAGE_OPEN_FILE_BROWSER', + StartPageOpenFolder = 'DATASCIENCE.STARTPAGE_OPEN_FOLDER', + StartPageOpenWorkspace = 'DATASCIENCE.STARTPAGE_OPEN_WORKSPACE' } export enum NativeKeyboardCommandTelemetry { diff --git a/src/client/datascience/interactive-ipynb/nativeEditorProvider.ts b/src/client/datascience/interactive-ipynb/nativeEditorProvider.ts index 0b82dc08e0fb..451d048d83f1 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditorProvider.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditorProvider.ts @@ -192,9 +192,9 @@ export class NativeEditorProvider implements INotebookEditorProvider, CustomEdit } @captureTelemetry(Telemetry.CreateNewNotebook, undefined, false) - public async createNew(contents?: string): Promise { + public async createNew(contents?: string, title?: string): Promise { // Create a new URI for the dummy file using our root workspace path - const uri = this.getNextNewNotebookUri(); + const uri = this.getNextNewNotebookUri(title); // Update number of notebooks in the workspace this.notebookCount += 1; @@ -281,7 +281,7 @@ export class NativeEditorProvider implements INotebookEditorProvider, CustomEdit } } - private getNextNewNotebookUri(): Uri { - return generateNewNotebookUri(this.untitledCounter); + private getNextNewNotebookUri(title?: string): Uri { + return generateNewNotebookUri(this.untitledCounter, title); } } diff --git a/src/client/datascience/types.ts b/src/client/datascience/types.ts index e989d077ed1f..3103e313bbcb 100644 --- a/src/client/datascience/types.ts +++ b/src/client/datascience/types.ts @@ -529,7 +529,7 @@ export interface INotebookEditorProvider { readonly onDidCloseNotebookEditor: Event; open(file: Uri): Promise; show(file: Uri): Promise; - createNew(contents?: string): Promise; + createNew(contents?: string, title?: string): Promise; } // For native editing, the INotebookEditor acts like a TextEditor and a TextDocument together diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index d44aca371adf..916071751483 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -2121,6 +2121,7 @@ export interface IEventNamePropertyMapping { // Start Page Events [Telemetry.StartPageViewed]: never | undefined; + [Telemetry.StartPageWebViewError]: never | undefined; [Telemetry.StartPageTime]: never | undefined; [Telemetry.StartPageClickedDontShowAgain]: never | undefined; [Telemetry.StartPageClosedWithoutAction]: never | undefined; @@ -2132,4 +2133,6 @@ export interface IEventNamePropertyMapping { [Telemetry.StartPageOpenCommandPaletteWithOpenNBSelected]: never | undefined; [Telemetry.StartPageOpenSampleNotebook]: never | undefined; [Telemetry.StartPageOpenFileBrowser]: never | undefined; + [Telemetry.StartPageOpenFolder]: never | undefined; + [Telemetry.StartPageOpenWorkspace]: never | undefined; } diff --git a/src/datascience-ui/react-common/image.tsx b/src/datascience-ui/react-common/image.tsx index 87c117a26199..6248f8f789d0 100644 --- a/src/datascience-ui/react-common/image.tsx +++ b/src/datascience-ui/react-common/image.tsx @@ -50,6 +50,7 @@ export enum ImageName { Interactive, Python, PythonColor, + OpenFolder, RunByLine } @@ -218,6 +219,10 @@ const images: { [key: string]: { light: string; dark: string } } = { 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') + }, RunByLine: { light: require('./images/RunByLine/runbyline_light.svg'), dark: require('./images/RunByLine/runbyline_dark.svg') diff --git a/src/datascience-ui/react-common/images/StartPage/OpenFolder-inverse.svg b/src/datascience-ui/react-common/images/StartPage/OpenFolder-inverse.svg new file mode 100644 index 000000000000..e3d0f3e933e7 --- /dev/null +++ b/src/datascience-ui/react-common/images/StartPage/OpenFolder-inverse.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/datascience-ui/react-common/images/StartPage/OpenFolder.svg b/src/datascience-ui/react-common/images/StartPage/OpenFolder.svg new file mode 100644 index 000000000000..309858c9f469 --- /dev/null +++ b/src/datascience-ui/react-common/images/StartPage/OpenFolder.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/datascience-ui/startPage/startPage.css b/src/datascience-ui/startPage/startPage.css index fb0b558563c7..de64fbe8538a 100644 --- a/src/datascience-ui/startPage/startPage.css +++ b/src/datascience-ui/startPage/startPage.css @@ -19,7 +19,8 @@ background-color: var(--vscode-titleBar-activeBackground); } -.icon:hover { +.icon:hover, +.text:hover { background-color: var(--vscode-editorIndentGuide-activeBackground); cursor: pointer; } @@ -38,6 +39,7 @@ .text { font-weight: 100; font-size: x-large; + width: fit-content; } .block { @@ -48,6 +50,7 @@ .row { display: block; min-height: 120px; + white-space: nowrap; } .link { @@ -72,8 +75,13 @@ .paragraph { display: block; - margin-block-start: 1em; - margin-block-end: 1em; + 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/datascience-ui/startPage/startPage.tsx b/src/datascience-ui/startPage/startPage.tsx index cef8a1f61fd9..84f1ad076062 100644 --- a/src/datascience-ui/startPage/startPage.tsx +++ b/src/datascience-ui/startPage/startPage.tsx @@ -38,11 +38,15 @@ export class StartPage extends React.Component implements IMess // Add ourselves as a handler for the post office this.postOffice.addHandler(this); - // Tell the plot viewer code we have started. + // 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 any).openBlankNotebook = this.openBlankNotebook.bind(this); + (window as any).createPythonFile = this.createPythonFile.bind(this); (window as any).openFileBrowser = this.openFileBrowser.bind(this); + (window as any).openFolder = this.openFolder.bind(this); + (window as any).openWorkspace = this.openWorkspace.bind(this); (window as any).openCommandPalette = this.openCommandPalette.bind(this); (window as any).openCommandPaletteWithSelection = this.openCommandPaletteWithSelection.bind(this); (window as any).openSampleNotebook = this.openSampleNotebook.bind(this); @@ -71,7 +75,7 @@ export class StartPage extends React.Component implements IMess />
-
+
{getLocString('StartPage.CreateJupyterNotebook', 'Create a Jupyter Notebook')}
{this.renderNotebookDescription()} @@ -86,12 +90,27 @@ export class StartPage extends React.Component implements IMess />
-
+
{getLocString('StartPage.createAPythonFile', 'Create a Python File')}
{this.renderPythonFileDescription()}
+
+
+ +
+
+
+ {getLocString('StartPage.openFolder', 'Open a Folder or Workspace')} +
+ {this.renderFolderDescription()} +
+
implements IMess />
-
- {getLocString('StartPage.openInteractiveWindow', 'Open the Interactive Window')} +
+ {getLocString( + 'StartPage.openInteractiveWindow', + 'Use the Interactive Window to develop Python Scripts' + )}
{this.renderInteractiveWindowDescription()}
@@ -142,16 +164,24 @@ export class StartPage extends React.Component implements IMess this.postOffice.sendMessage(StartPageMessages.OpenFileBrowser); } + public openFolder = () => { + this.postOffice.sendMessage(StartPageMessages.OpenFolder); + }; + + public openWorkspace() { + this.postOffice.sendMessage(StartPageMessages.OpenWorkspace); + } + private renderNotebookDescription(): JSX.Element { // tslint:disable: react-no-dangerous-html return (
Shift + Command + P
" to open the
- Type " "
- Explore our to learn about notebook features' - ).format('openCommandPalette()', 'openCommandPaletteWithSelection()', 'openSampleNotebook()') + '- Run "" in the Command Palette (
Shift + Command + P
)
- Explore our to learn about notebook features' + ).format('openCommandPaletteWithSelection()', 'openSampleNotebook()') }} /> ); @@ -161,12 +191,12 @@ export class StartPage extends React.Component implements IMess // tslint:disable: react-no-dangerous-html return (
- to continue work' - ).format('openFileBrowser()') + '- Create a with a .py extension' + ).format('createPythonFile()') }} /> ); @@ -175,7 +205,8 @@ export class StartPage extends React.Component implements IMess private renderInteractiveWindowDescription(): JSX.Element { // tslint:disable: react-no-dangerous-html return ( -

implements IMess ); } + private renderFolderDescription(): JSX.Element { + // tslint:disable: react-no-dangerous-html + return ( +


- Open a ' + ).format('openFolder()', 'openWorkspace()') + }} + /> + ); + } + private renderReleaseNotesLink(): JSX.Element { // tslint:disable: react-no-dangerous-html return ( @@ -206,7 +252,7 @@ export class StartPage extends React.Component implements IMess this.releaseNotes.notes.forEach((rel, index) => { notes.push(
  • {rel}
  • ); }); - return
      {notes}
    ; + return
      {notes}
    ; } private renderTutorialAndDoc(): JSX.Element { diff --git a/src/test/datascience/commands/commandRegistry.unit.test.ts b/src/test/datascience/commands/commandRegistry.unit.test.ts index 776cc28e8599..d3fffecca536 100644 --- a/src/test/datascience/commands/commandRegistry.unit.test.ts +++ b/src/test/datascience/commands/commandRegistry.unit.test.ts @@ -7,7 +7,6 @@ import { DebugService } from '../../../client/common/application/debugService'; import { DocumentManager } from '../../../client/common/application/documentManager'; import { ICommandManager } from '../../../client/common/application/types'; import { ConfigurationService } from '../../../client/common/configuration/service'; -import { ExperimentService } from '../../../client/common/experiments/service'; import { StartPage } from '../../../client/common/startPage/startPage'; import { JupyterCommandLineSelectorCommand } from '../../../client/datascience/commands/commandLineSelector'; import { CommandRegistry } from '../../../client/datascience/commands/commandRegistry'; @@ -38,7 +37,6 @@ suite('Data Science - Commands', () => { const configService = mock(ConfigurationService); const appShell = mock(ApplicationShell); const startPage = mock(StartPage); - const experiment = mock(ExperimentService); commandRegistry = new CommandRegistry( documentManager, @@ -53,8 +51,7 @@ suite('Data Science - Commands', () => { instance(configService), instance(appShell), new MockOutputChannel('Jupyter'), - instance(startPage), - instance(experiment) + instance(startPage) ); }); diff --git a/src/test/startPage/startPage.unit.test.ts b/src/test/startPage/startPage.unit.test.ts index e8dbd1bd0bab..cc59785760df 100644 --- a/src/test/startPage/startPage.unit.test.ts +++ b/src/test/startPage/startPage.unit.test.ts @@ -39,264 +39,6 @@ suite('StartPage tests', () => { let experiment: typemoq.IMock; const dummySettings = new MockPythonSettings(undefined, new MockAutoSelectionService()); - const releaseNotes1 = `# Changelog - -## 2020.5.1 (19 May 2020) - -### Fixes - -1. Do not execute shebang as an interpreter until user has clicked on the codelens enclosing the shebang. - ([#11687](https://github.com/Microsoft/vscode-python/issues/11687)) - -### Thanks - -Thanks to the following projects which we fully rely on to provide some of -our features: - -- [debugpy](https://pypi.org/project/debugpy/) -- [isort](https://pypi.org/project/isort/) -- [jedi](https://pypi.org/project/jedi/) - and [parso](https://pypi.org/project/parso/) -- [Microsoft Python Language Server](https://github.com/microsoft/python-language-server) -- [ptvsd](https://pypi.org/project/ptvsd/) -- [exuberant ctags](http://ctags.sourceforge.net/) (user-installed) -- [rope](https://pypi.org/project/rope/) (user-installed) - -Also thanks to the various projects we provide integrations with which help -make this extension useful: - -- Debugging support: - [Django](https://pypi.org/project/Django/), - [Flask](https://pypi.org/project/Flask/), - [gevent](https://pypi.org/project/gevent/), - [Jinja](https://pypi.org/project/Jinja/), - [Pyramid](https://pypi.org/project/pyramid/), - [PySpark](https://pypi.org/project/pyspark/), - [Scrapy](https://pypi.org/project/Scrapy/), - [Watson](https://pypi.org/project/Watson/) -- Formatting: - [autopep8](https://pypi.org/project/autopep8/), - [black](https://pypi.org/project/black/), - [yapf](https://pypi.org/project/yapf/) -- Interpreter support: - [conda](https://conda.io/), - [direnv](https://direnv.net/), - [pipenv](https://pypi.org/project/pipenv/), - [pyenv](https://github.com/pyenv/pyenv), - [venv](https://docs.python.org/3/library/venv.html#module-venv), - [virtualenv](https://pypi.org/project/virtualenv/) -- Linting: - [bandit](https://pypi.org/project/bandit/), - [flake8](https://pypi.org/project/flake8/), - [mypy](https://pypi.org/project/mypy/), - [prospector](https://pypi.org/project/prospector/), - [pylint](https://pypi.org/project/pylint/), - [pydocstyle](https://pypi.org/project/pydocstyle/), - [pylama](https://pypi.org/project/pylama/) -- Testing: - [nose](https://pypi.org/project/nose/), - [pytest](https://pypi.org/project/pytest/), - [unittest](https://docs.python.org/3/library/unittest.html#module-unittest) - -And finally thanks to the [Python](https://www.python.org/) development team and -community for creating a fantastic programming language and community to be a -part of! - -## 2020.5.0 (12 May 2020) - -### Enhancements - -1. Added ability to manually enter a path to interpreter in the select interpreter dropdown. - ([#216](https://github.com/Microsoft/vscode-python/issues/216)) -1. Add status bar item with icon when installing Insiders/Stable build. - (thanks to [ErwanDL](https://github.com/ErwanDL/)) - ([#10495](https://github.com/Microsoft/vscode-python/issues/10495)) -1. Support for language servers that don't allow incremental document updates inside of notebooks and the interactive window. - ([#10818](https://github.com/Microsoft/vscode-python/issues/10818)) -1. Add telemetry for "Python is not installed" prompt. - ([#10885](https://github.com/Microsoft/vscode-python/issues/10885)) -1. Add basic liveshare support for raw kernels. - ([#10988](https://github.com/Microsoft/vscode-python/issues/10988)) -1. Do a one-off transfer of existing values for 'python.pythonPath' setting to new Interpreter storage if in DeprecatePythonPath experiment. - ([#11052](https://github.com/Microsoft/vscode-python/issues/11052)) -1. Ensure the language server can query pythonPath when in the Deprecate PythonPath experiment. - ([#11083](https://github.com/Microsoft/vscode-python/issues/11083)) -1. Added prompt asking users to delete 'python.pythonPath' key from their workspace settings when in Deprecate PythonPath experiment. - ([#11108](https://github.com/Microsoft/vscode-python/issues/11108)) -1. Added 'getDebuggerPackagePath' extension API to get the debugger package path. - ([#11236](https://github.com/Microsoft/vscode-python/issues/11236)) -1. Expose currently selected interpreter path using API. - ([#11294](https://github.com/Microsoft/vscode-python/issues/11294)) -1. Show a prompt asking user to upgrade Code runner to new version to keep using it when in Deprecate PythonPath experiment. - ([#11327](https://github.com/Microsoft/vscode-python/issues/11327)) -1. Rename string '' which is used in 'launch.json' to refer to interpreter path set in settings, to. - ([#11446](https://github.com/Microsoft/vscode-python/issues/11446)) - -### Fixes - -1. Added 'Enable Scrolling For Cell Outputs' setting. Works together with the 'Max Output Size' setting. - ([#9801](https://github.com/Microsoft/vscode-python/issues/9801)) -1. Fix ctrl+enter on markdown cells. Now they render. - ([#10006](https://github.com/Microsoft/vscode-python/issues/10006))`; - - const filteredReleaseNotes1 = [ - 'Added ability to manually enter a path to interpreter in the select interpreter dropdown.', - 'Add status bar item with icon when installing Insiders/Stable build.', - "Support for language servers that don't allow incremental document updates inside of notebooks and the interactive window.", - 'Add telemetry for "Python is not installed" prompt.', - 'Add basic liveshare support for raw kernels.' - ]; - - const releaseNotes2 = `# Changelog - -## 2020.5.1 (19 May 2020) - -### Enhancements - -1. Enhancement 1 - ([#216](https://github.com/Microsoft/vscode-python/issues/216)) -1. Enhancement 2 - ([#10495](https://github.com/Microsoft/vscode-python/issues/10495)) -1. Enhancement 3 - ([#10818](https://github.com/Microsoft/vscode-python/issues/10818)) - -### Fixes - -1. Do not execute shebang as an interpreter until user has clicked on the codelens enclosing the shebang. - ([#11687](https://github.com/Microsoft/vscode-python/issues/11687)) - -### Thanks - -Thanks to the following projects which we fully rely on to provide some of -our features: - -- [debugpy](https://pypi.org/project/debugpy/) -- [isort](https://pypi.org/project/isort/) -- [jedi](https://pypi.org/project/jedi/) - and [parso](https://pypi.org/project/parso/) -- [Microsoft Python Language Server](https://github.com/microsoft/python-language-server) -- [ptvsd](https://pypi.org/project/ptvsd/) -- [exuberant ctags](http://ctags.sourceforge.net/) (user-installed) -- [rope](https://pypi.org/project/rope/) (user-installed) - -Also thanks to the various projects we provide integrations with which help -make this extension useful: - -- Debugging support: - [Django](https://pypi.org/project/Django/), - [Flask](https://pypi.org/project/Flask/), - [gevent](https://pypi.org/project/gevent/), - [Jinja](https://pypi.org/project/Jinja/), - [Pyramid](https://pypi.org/project/pyramid/), - [PySpark](https://pypi.org/project/pyspark/), - [Scrapy](https://pypi.org/project/Scrapy/), - [Watson](https://pypi.org/project/Watson/) -- Formatting: - [autopep8](https://pypi.org/project/autopep8/), - [black](https://pypi.org/project/black/), - [yapf](https://pypi.org/project/yapf/) -- Interpreter support: - [conda](https://conda.io/), - [direnv](https://direnv.net/), - [pipenv](https://pypi.org/project/pipenv/), - [pyenv](https://github.com/pyenv/pyenv), - [venv](https://docs.python.org/3/library/venv.html#module-venv), - [virtualenv](https://pypi.org/project/virtualenv/) -- Linting: - [bandit](https://pypi.org/project/bandit/), - [flake8](https://pypi.org/project/flake8/), - [mypy](https://pypi.org/project/mypy/), - [prospector](https://pypi.org/project/prospector/), - [pylint](https://pypi.org/project/pylint/), - [pydocstyle](https://pypi.org/project/pydocstyle/), - [pylama](https://pypi.org/project/pylama/) -- Testing: - [nose](https://pypi.org/project/nose/), - [pytest](https://pypi.org/project/pytest/), - [unittest](https://docs.python.org/3/library/unittest.html#module-unittest) - -And finally thanks to the [Python](https://www.python.org/) development team and -community for creating a fantastic programming language and community to be a -part of! - -## 2020.5.0 (12 May 2020) - -### Enhancements - -1. Added ability to manually enter a path to interpreter in the select interpreter dropdown. - ([#216](https://github.com/Microsoft/vscode-python/issues/216)) -1. Add status bar item with icon when installing Insiders/Stable build. - (thanks to [ErwanDL](https://github.com/ErwanDL/)) - ([#10495](https://github.com/Microsoft/vscode-python/issues/10495)) -1. Support for language servers that don't allow incremental document updates inside of notebooks and the interactive window. - ([#10818](https://github.com/Microsoft/vscode-python/issues/10818)) -1. Add telemetry for "Python is not installed" prompt. - ([#10885](https://github.com/Microsoft/vscode-python/issues/10885)) -1. Add basic liveshare support for raw kernels. - ([#10988](https://github.com/Microsoft/vscode-python/issues/10988)) -1. Do a one-off transfer of existing values for 'python.pythonPath' setting to new Interpreter storage if in DeprecatePythonPath experiment. - ([#11052](https://github.com/Microsoft/vscode-python/issues/11052)) -1. Ensure the language server can query pythonPath when in the Deprecate PythonPath experiment. - ([#11083](https://github.com/Microsoft/vscode-python/issues/11083)) -1. Added prompt asking users to delete 'python.pythonPath' key from their workspace settings when in Deprecate PythonPath experiment. - ([#11108](https://github.com/Microsoft/vscode-python/issues/11108)) -1. Added 'getDebuggerPackagePath' extension API to get the debugger package path. - ([#11236](https://github.com/Microsoft/vscode-python/issues/11236)) -1. Expose currently selected interpreter path using API. - ([#11294](https://github.com/Microsoft/vscode-python/issues/11294)) -1. Show a prompt asking user to upgrade Code runner to new version to keep using it when in Deprecate PythonPath experiment. - ([#11327](https://github.com/Microsoft/vscode-python/issues/11327)) -1. Rename string '' which is used in 'launch.json' to refer to interpreter path set in settings, to. - ([#11446](https://github.com/Microsoft/vscode-python/issues/11446)) - -### Fixes - -1. Added 'Enable Scrolling For Cell Outputs' setting. Works together with the 'Max Output Size' setting. - ([#9801](https://github.com/Microsoft/vscode-python/issues/9801)) -1. Fix ctrl+enter on markdown cells. Now they render. - ([#10006](https://github.com/Microsoft/vscode-python/issues/10006))`; - - const filteredReleaseNotes2 = ['Enhancement 1', 'Enhancement 2', 'Enhancement 3']; - - const releaseNotes3 = `# Changelog - -## 2020.5.0 (12 May 2020) - -### Enhancements - -1. Added ability to manually enter a path to interpreter in the select interpreter dropdown. - ([#216](https://github.com/Microsoft/vscode-python/issues/216)) -1. Add status bar item with icon when installing Insiders/Stable build. - (thanks to [ErwanDL](https://github.com/ErwanDL/)) - ([#10495](https://github.com/Microsoft/vscode-python/issues/10495)) -1. Support for language servers that don't allow incremental document updates inside of notebooks and the interactive window. - ([#10818](https://github.com/Microsoft/vscode-python/issues/10818)) -1. Add telemetry for "Python is not installed" prompt. - ([#10885](https://github.com/Microsoft/vscode-python/issues/10885)) -1. Add basic liveshare support for raw kernels. - ([#10988](https://github.com/Microsoft/vscode-python/issues/10988)) -1. Do a one-off transfer of existing values for 'python.pythonPath' setting to new Interpreter storage if in DeprecatePythonPath experiment. - ([#11052](https://github.com/Microsoft/vscode-python/issues/11052)) -1. Ensure the language server can query pythonPath when in the Deprecate PythonPath experiment. - ([#11083](https://github.com/Microsoft/vscode-python/issues/11083)) -1. Added prompt asking users to delete 'python.pythonPath' key from their workspace settings when in Deprecate PythonPath experiment. - ([#11108](https://github.com/Microsoft/vscode-python/issues/11108)) -1. Added 'getDebuggerPackagePath' extension API to get the debugger package path. - ([#11236](https://github.com/Microsoft/vscode-python/issues/11236)) -1. Expose currently selected interpreter path using API. - ([#11294](https://github.com/Microsoft/vscode-python/issues/11294)) -1. Show a prompt asking user to upgrade Code runner to new version to keep using it when in Deprecate PythonPath experiment. - ([#11327](https://github.com/Microsoft/vscode-python/issues/11327)) -1. Rename string '' which is used in 'launch.json' to refer to interpreter path set in settings, to. - ([#11446](https://github.com/Microsoft/vscode-python/issues/11446)) - -### Fixes - -1. Added 'Enable Scrolling For Cell Outputs' setting. Works together with the 'Max Output Size' setting. - ([#9801](https://github.com/Microsoft/vscode-python/issues/9801)) -1. Fix ctrl+enter on markdown cells. Now they render. - ([#10006](https://github.com/Microsoft/vscode-python/issues/10006))`; - function setupVersions(savedVersion: string, actualVersion: string) { context.setup((c) => c.globalState).returns(() => memento.object); memento.setup((m) => m.get(typemoq.It.isAnyString())).returns(() => savedVersion); @@ -350,23 +92,6 @@ part of! ); }); - test('Release notes', async () => { - // There was a point release without new enhancements - file.setup((fs) => fs.readFile(typemoq.It.isAnyString())).returns(() => Promise.resolve(releaseNotes1)); - const test1 = await startPage.handleReleaseNotesRequest(); - assert.deepEqual(test1, filteredReleaseNotes1, 'The release notes are not being filtered correctly.'); - - // There was a point release with 3 new enhancements - file.setup((fs) => fs.readFile(typemoq.It.isAnyString())).returns(() => Promise.resolve(releaseNotes2)); - const test2 = await startPage.handleReleaseNotesRequest(); - assert.deepEqual(test2, filteredReleaseNotes2, 'The release notes are not being filtered correctly.'); - - // Regular release - file.setup((fs) => fs.readFile(typemoq.It.isAnyString())).returns(() => Promise.resolve(releaseNotes3)); - const test3 = await startPage.handleReleaseNotesRequest(); - assert.deepEqual(test3, filteredReleaseNotes1, 'The release notes are not being filtered correctly.'); - }); - test('Check extension version', async () => { let savedVersion: string; let actualVersion: string;