diff --git a/news/1 Enhancements/4640.md b/news/1 Enhancements/4640.md new file mode 100644 index 000000000000..4240bef308d6 --- /dev/null +++ b/news/1 Enhancements/4640.md @@ -0,0 +1 @@ +Add 'ignoreVscodeTheme' setting to allow a user to skip using the theme for VS Code in the Python Interactive Window. diff --git a/package.json b/package.json index a243ba5122f3..e56d75f24014 100644 --- a/package.json +++ b/package.json @@ -1370,6 +1370,12 @@ "description": "Allow the Python Interactive window to be shared during a Live Share session", "scope": "resource" }, + "python.dataScience.ignoreVscodeTheme": { + "type": "boolean", + "default": false, + "description": "Don't use the VS Code theme in the Python Interactive window (requires reload of VS Code). This forces the Python Interactive window to use 'Light +(default light)' and disables matplotlib defaults.", + "scope": "resource" + }, "python.disableInstallationCheck": { "type": "boolean", "default": false, diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 51d14455aa13..c442303c4074 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -300,6 +300,7 @@ export interface IDataScienceSettings { codeRegularExpression: string; allowLiveShare? : boolean; errorBackgroundColor: string; + ignoreVscodeTheme?: boolean; } export const IConfigurationService = Symbol('IConfigurationService'); diff --git a/src/client/datascience/codeCssGenerator.ts b/src/client/datascience/codeCssGenerator.ts index 63da744d1d6c..3000cb6fa27c 100644 --- a/src/client/datascience/codeCssGenerator.ts +++ b/src/client/datascience/codeCssGenerator.ts @@ -8,13 +8,28 @@ import * as path from 'path'; import * as stripJsonComments from 'strip-json-comments'; import { IWorkspaceService } from '../common/application/types'; -import { ILogger } from '../common/types'; +import { IConfigurationService, ILogger } from '../common/types'; import { EXTENSION_ROOT_DIR } from '../constants'; -import { Identifiers } from './constants'; +import { DefaultTheme, Identifiers } from './constants'; import { ICodeCssGenerator, IThemeFinder } from './types'; // tslint:disable:no-any +// These are based on the colors generated by 'Default Light+' and are only set when we +// are ignoring themes. +//tslint:disable-next-line:no-multiline-string +const DefaultStyle = ` + :root { + --override-widget-background: #f3f3f3; + --override-foreground: #000000; + --override-background: #FFFFFF; + --override-selection-background: #add6ff; + --override-watermark-color: #cccedb; + --override-tabs-background: #f3f3f3; + --override-progress-background: #0066bf; + } +`; + // 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 @@ -26,14 +41,17 @@ export class CodeCssGenerator implements ICodeCssGenerator { constructor( @inject(IWorkspaceService) private workspaceService: IWorkspaceService, @inject(IThemeFinder) private themeFinder: IThemeFinder, + @inject(IConfigurationService) private configService: IConfigurationService, @inject(ILogger) private logger: ILogger) { } public generateThemeCss = async (): Promise => { + let css : string = ''; try { // First compute our current theme. const workbench = this.workspaceService.getConfiguration('workbench'); - const theme = workbench.get('colorTheme'); + const ignoreTheme = this.configService.getSettings().datascience.ignoreVscodeTheme ? true : false; + const theme = ignoreTheme ? DefaultTheme : workbench.get('colorTheme'); const terminalCursor = workbench.get('terminal.integrated.cursorStyle', 'block'); const editor = this.workspaceService.getConfiguration('editor', undefined); const font = editor.get('fontFamily'); @@ -47,7 +65,7 @@ export class CodeCssGenerator implements ICodeCssGenerator { // The tokens object then contains the necessary data to generate our css if (tokenColors && font && fontSize) { this.logger.logInformation('Using colors to generate CSS ...'); - return this.generateCss(theme, tokenColors, font, fontSize, terminalCursor); + css = this.generateCss(theme, tokenColors, font, fontSize, terminalCursor, ignoreTheme); } } } catch (err) { @@ -55,7 +73,7 @@ export class CodeCssGenerator implements ICodeCssGenerator { this.logger.logError(err); } - return ''; + return css; } private matchTokenColor(tokenColors: JSONArray, scope: string) : number { @@ -96,7 +114,7 @@ export class CodeCssGenerator implements ICodeCssGenerator { } // tslint:disable-next-line:max-func-body-length - private generateCss(theme: string, tokenColors: JSONArray, fontFamily: string, fontSize: number, cursorType: string): string { + private generateCss(theme: string, tokenColors: JSONArray, fontFamily: string, fontSize: number, cursorType: string, generateDefaults: boolean): string { const escapedThemeName = Identifiers.GeneratedThemeName; // There's a set of values that need to be found @@ -109,6 +127,7 @@ export class CodeCssGenerator implements ICodeCssGenerator { // const atomic = this.getScopeColor(tokenColors, 'atomic'); const builtinStyle = this.getScopeStyle(tokenColors, 'support.function'); const punctuationStyle = this.getScopeStyle(tokenColors, 'punctuation'); + const overrides = generateDefaults ? DefaultStyle : ''; const def = 'var(--vscode-editor-foreground)'; @@ -123,8 +142,11 @@ export class CodeCssGenerator implements ICodeCssGenerator { :root { --code-comment-color: ${commentStyle.color}; --code-font-family: ${fontFamily}; - --code-font-size:${fontSize}px; + --code-font-size: ${fontSize}px; } + + ${overrides} + .cm-header, .cm-strong {font-weight: bold;} .cm-em {font-style: italic;} .cm-link {text-decoration: underline;} diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index ad3f97932377..3acfb7da60a7 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -5,6 +5,8 @@ import { IS_WINDOWS } from '../common/platform/constants'; +export const DefaultTheme = 'Default Light+'; + export namespace Commands { export const RunAllCells = 'python.datascience.runallcells'; export const RunAllCellsAbove = 'python.datascience.runallcellsabove'; diff --git a/src/client/datascience/historyProvider.ts b/src/client/datascience/historyProvider.ts index d8f083f3b28e..13c962da0015 100644 --- a/src/client/datascience/historyProvider.ts +++ b/src/client/datascience/historyProvider.ts @@ -77,7 +77,8 @@ export class HistoryProvider implements IHistoryProvider, IAsyncDisposable { const workbench = this.workspaceService.getConfiguration('workbench'); if (workbench) { const theme = workbench.get('colorTheme'); - if (theme) { + const ignoreTheme = this.configService.getSettings().datascience.ignoreVscodeTheme ? true : false; + if (theme && !ignoreTheme) { darkTheme = await this.themeFinder.isThemeDark(theme); } } diff --git a/src/datascience-ui/history-react/MainPanel.tsx b/src/datascience-ui/history-react/MainPanel.tsx index b56552ddda6e..b83a92c20a6b 100644 --- a/src/datascience-ui/history-react/MainPanel.tsx +++ b/src/datascience-ui/history-react/MainPanel.tsx @@ -76,36 +76,37 @@ export class MainPanel extends React.Component this.renderCount = this.renderCount + 1; } + const baseTheme = getSettings().ignoreVscodeTheme ? 'vscode-light' : this.props.baseTheme; const progressBar = this.state.busy && !this.props.testMode ? : undefined; return (
- + {this.renderExtraButtons()} - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + +
@@ -214,7 +215,8 @@ export class MainPanel extends React.Component private renderExtraButtons = () => { if (!this.props.skipDefault) { - return M; + const baseTheme = getSettings().ignoreVscodeTheme ? 'vscode-light' : this.props.baseTheme; + return M; } return null; @@ -225,6 +227,7 @@ export class MainPanel extends React.Component const errorBackgroundColor = getSettings().errorBackgroundColor; const actualErrorBackgroundColor = errorBackgroundColor ? errorBackgroundColor : '#FFFFFF'; const maxTextSize = maxOutputSize && maxOutputSize < 10000 && maxOutputSize > 0 ? maxOutputSize : undefined; + const baseTheme = getSettings().ignoreVscodeTheme ? 'vscode-light' : this.props.baseTheme; return this.state.cellVMs.map((cellVM: ICellViewModel, index: number) => testMode={this.props.testMode} cellVM={cellVM} submitNewCode={this.submitInput} - baseTheme={this.props.baseTheme} + baseTheme={baseTheme} codeTheme={this.props.codeTheme} showWatermark={!this.state.submittedText} errorBackgroundColor={actualErrorBackgroundColor} diff --git a/src/datascience-ui/history-react/cell.css b/src/datascience-ui/history-react/cell.css index c955bbe8a44c..9c20ca7bec57 100644 --- a/src/datascience-ui/history-react/cell.css +++ b/src/datascience-ui/history-react/cell.css @@ -2,7 +2,7 @@ margin: 0px; padding: 2px; display: block; - border-bottom-color: var(--vscode-editorGroupHeader-tabsBackground); + border-bottom-color: var(--override-widget-background, var(--vscode-editorGroupHeader-tabsBackground)); border-bottom-style: solid; border-bottom-width: 1px; } @@ -57,7 +57,7 @@ .cell-output { margin-top: 5px; - background: var(--vscode-notifications-background); + background: var(--override-widget-background, var(--vscode-notifications-background)); white-space: pre-wrap; font-family: monospace; } @@ -77,7 +77,7 @@ } .cell-output thead { - border-bottom-color: var(--vscode-editor-foreground); + border-bottom-color: var(--override-foreground, var(--vscode-editor-foreground)); border-bottom-style: solid; border-bottom-width: 1px; vertical-align: bottom; @@ -98,10 +98,10 @@ font-weight: bold; } .cell-output tbody tr:nth-child(even) { - background: var(--vscode-editor-background); /* Force to white because the default color for output is gray */ + background: var(--override-background, var(--vscode-editor-background)); /* Force to white because the default color for output is gray */ } .cell-output tbody tr:hover { - background: var(--vscode-editor-selectionBackground); + background: var(--override-selection-background, var(--vscode-editor-selectionBackground)); } .cell-output * + table { margin-top: 1em; diff --git a/src/datascience-ui/history-react/code.css b/src/datascience-ui/history-react/code.css index 47a124abefa6..e676ca8f4bf1 100644 --- a/src/datascience-ui/history-react/code.css +++ b/src/datascience-ui/history-react/code.css @@ -1,15 +1,15 @@ .CodeMirror { text-align: left!important; - background-color: var(--vscode-editor-background); - color: var(--vscode-editor-foreground); + background-color: var(--override-background, var(--vscode-editor-background)); + color: var(--override-foreground, var(--vscode-editor-foreground)); font-family: var(--vscode-editor-font-family); font-weight: var(--vscode-editor-font-weight); font-size: var(--vscode-editor-font-size); } .cm-s-default { - background-color: var(--vscode-editor-background); - color: var(--vscode-editor-foreground); + background-color: var(--override-background, var(--vscode-editor-background)); + color: var(--override-foreground, var(--vscode-editor-foreground)); font-family: var(--code-font-family); font-weight: var(--vscode-editor-font-weight); font-size: var(--code-font-size); @@ -43,7 +43,7 @@ left: 30px; z-index: 500; font-style: italic; - color: var(--vscode-pickerGroup-border); + color: var(--override-watermark-color, var(--vscode-pickerGroup-border)); } .hide { diff --git a/src/datascience-ui/history-react/cursor.css b/src/datascience-ui/history-react/cursor.css index b1c79454ad39..e1c29ef1f33e 100644 --- a/src/datascience-ui/history-react/cursor.css +++ b/src/datascience-ui/history-react/cursor.css @@ -6,18 +6,18 @@ } .cursor-block { - border: .05px solid var(--vscode-editor-foreground); + border: .05px solid var(--override-foreground, var(--vscode-editor-foreground)); min-width: 5px; margin-left: -1px; margin-right: -1px; } .cursor-line { - border-left: 1px solid var(--vscode-editor-foreground); + border-left: 1px solid var(--override-foreground, var(--vscode-editor-foreground)); } .cursor-underline { - border-bottom: 1px solid var(--vscode-editor-foreground); + border-bottom: 1px solid var(--override-foreground, var(--vscode-editor-foreground)); min-width: 5px; } @@ -25,9 +25,6 @@ visibility: hidden; } -.cursor-text { -} - .cursor-line-overlay { border-left-width: 1px; border-left-style: solid; @@ -53,15 +50,15 @@ @keyframes blinkCursorLine { 0%, 49% {border-left-color: transparent;} - 50%, 100% {border-left-color: var(--vscode-editor-foreground);} + 50%, 100% {border-left-color: var(--override-foreground, var(--vscode-editor-foreground));} } @keyframes blinkCursorUnderline { 0%, 49% {border-bottom-color: transparent;} - 50%, 100% {border-bottom-color: var(--vscode-editor-foreground); } + 50%, 100% {border-bottom-color: var(--override-foreground, var(--vscode-editor-foreground)); } } @keyframes blinkCursorBlock { 0%, 49% {background-color: transparent; color: transparent;} - 50%, 100% {background-color: var(--vscode-editor-foreground); color: var(--vscode-editor-background);} + 50%, 100% {background-color: var(--override-foreground, var(--vscode-editor-foreground)); color: var(--override-background, var(--vscode-editor-background));} } diff --git a/src/datascience-ui/history-react/mainPanel.css b/src/datascience-ui/history-react/mainPanel.css index 592ef948e228..71505b67805e 100644 --- a/src/datascience-ui/history-react/mainPanel.css +++ b/src/datascience-ui/history-react/mainPanel.css @@ -10,3 +10,8 @@ .cell-table-body { display: table-row-group; } + +.main-panel { + background: var(--override-background, var(--vscode-editor-background)); + color: var(--override-foreground, var(--vscode-editor-foreground)); +} diff --git a/src/datascience-ui/history-react/menuBar.css b/src/datascience-ui/history-react/menuBar.css index b6d3746517e9..d157cdd451cb 100644 --- a/src/datascience-ui/history-react/menuBar.css +++ b/src/datascience-ui/history-react/menuBar.css @@ -44,8 +44,8 @@ border-left-width: 0px; margin-bottom: 1px; border-style:solid; - background-color: var(--vscode-editor-background); - border-color: var(--vscode-editorGroupHeader-tabsBackground); + background-color: var(--override-background, var(--vscode-editor-background)); + border-color: var(--override-tabs-background, var(--vscode-editorGroupHeader-tabsBackground)); } .menuBar-top-fixed:after{ diff --git a/src/datascience-ui/history-react/sysInfo.css b/src/datascience-ui/history-react/sysInfo.css index f0a2e18a3ebd..9d5688231c0d 100644 --- a/src/datascience-ui/history-react/sysInfo.css +++ b/src/datascience-ui/history-react/sysInfo.css @@ -2,13 +2,13 @@ margin: 10px; padding: 2px; display: block; - border-bottom-color: var(--vscode-editorGroupHeader-tabsBackground); + border-bottom-color: var(--override-tabs-background, var(--vscode-editorGroupHeader-tabsBackground)); border-bottom-style: solid; border-bottom-width: 1px; } .sysinfo-outer { - background: var(--vscode-notifications-background); + background: var(--override-widget-background, var(--vscode-notifications-background)); white-space: pre-wrap; font-family: monospace; width: 100%; diff --git a/src/test/datascience/color.test.ts b/src/test/datascience/color.test.ts index 275a127f0d7d..7a8149cdc882 100644 --- a/src/test/datascience/color.test.ts +++ b/src/test/datascience/color.test.ts @@ -7,11 +7,15 @@ import { WorkspaceConfiguration } from 'vscode'; import { Extensions } from '../../client/common/application/extensions'; import { IWorkspaceService } from '../../client/common/application/types'; +import { PythonSettings } from '../../client/common/configSettings'; import { Logger } from '../../client/common/logger'; import { CurrentProcess } from '../../client/common/process/currentProcess'; +import { IConfigurationService } from '../../client/common/types'; import { CodeCssGenerator } from '../../client/datascience/codeCssGenerator'; import { ThemeFinder } from '../../client/datascience/themeFinder'; +import { MockAutoSelectionService } from '../mocks/autoSelector'; +// tslint:disable:max-func-body-length suite('Theme colors', () => { let themeFinder: ThemeFinder; let extensions : Extensions; @@ -20,6 +24,8 @@ suite('Theme colors', () => { let workspaceService : TypeMoq.IMock; let workspaceConfig : TypeMoq.IMock; let cssGenerator: CodeCssGenerator; + let configService : TypeMoq.IMock; + const settings : PythonSettings = new PythonSettings(undefined, new MockAutoSelectionService()); setup(() => { extensions = new Extensions(); @@ -41,11 +47,33 @@ suite('Theme colors', () => { return d; }); + settings.datascience = { + allowImportFromNotebook: true, + jupyterLaunchTimeout: 20000, + enabled: true, + jupyterServerURI: 'local', + notebookFileRoot: 'WORKSPACE', + changeDirOnImportExport: true, + useDefaultConfigForJupyter: true, + jupyterInterruptTimeout: 10000, + searchForJupyter: true, + showCellInputCode: true, + collapseCellInputCodeByDefault: true, + allowInput: true, + maxOutputSize: 400, + errorBackgroundColor: '#FFFFFF', + sendSelectionToInteractiveWindow: false, + codeRegularExpression: '^(#\\s*%%|#\\s*\\|#\\s*In\\[\\d*?\\]|#\\s*In\\[ \\])', + markdownRegularExpression: '^(#\\s*%%\\s*\\[markdown\\]|#\\s*\\)' + }; + configService = TypeMoq.Mock.ofType(); + configService.setup(x => x.getSettings(TypeMoq.It.isAny())).returns(() => settings); + workspaceService = TypeMoq.Mock.ofType(); workspaceService.setup(c => c.getConfiguration(TypeMoq.It.isAny())).returns(() => workspaceConfig.object); workspaceService.setup(c => c.getConfiguration(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => workspaceConfig.object); - cssGenerator = new CodeCssGenerator(workspaceService.object, themeFinder, logger); + cssGenerator = new CodeCssGenerator(workspaceService.object, themeFinder, configService.object, logger); }); function runTest(themeName: string, isDark: boolean, shouldExist: boolean) {