From 5c99a53301bd0706f32e2af979a27b38470cb961 Mon Sep 17 00:00:00 2001 From: Rich Chiodo Date: Thu, 23 May 2019 15:28:24 -0700 Subject: [PATCH 1/3] Fix command prompt to look like Spyder (#5744) * Fix command prompt to look like Spyder * Add news entry --- news/2 Fixes/5729.md | 1 + package-lock.json | 28 +++++++++---------- .../history-react/MainPanel.tsx | 2 ++ src/datascience-ui/history-react/cell.tsx | 4 +-- src/datascience-ui/history-react/code.css | 1 + .../history-react/contentPanel.tsx | 1 + .../history-react/executionCount.css | 1 + 7 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 news/2 Fixes/5729.md diff --git a/news/2 Fixes/5729.md b/news/2 Fixes/5729.md new file mode 100644 index 000000000000..7de7e25dc8d4 --- /dev/null +++ b/news/2 Fixes/5729.md @@ -0,0 +1 @@ +Adjust input box prompt to look more an IPython console prompt. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fdce826e48fb..d286f426343e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6728,7 +6728,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -12347,7 +12347,7 @@ "dependencies": { "convert-source-map": { "version": "1.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { @@ -12356,7 +12356,7 @@ }, "execa": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { @@ -12382,7 +12382,7 @@ }, "find-up": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { @@ -12397,7 +12397,7 @@ }, "get-stream": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { @@ -12406,7 +12406,7 @@ }, "glob": { "version": "7.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { @@ -12420,7 +12420,7 @@ }, "locate-path": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { @@ -12440,7 +12440,7 @@ }, "os-locale": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { @@ -12451,7 +12451,7 @@ }, "path-exists": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, @@ -12463,7 +12463,7 @@ }, "pkg-dir": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { @@ -12472,7 +12472,7 @@ }, "pump": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { @@ -12488,13 +12488,13 @@ }, "resolve-from": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "rimraf": { "version": "2.6.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { @@ -13681,7 +13681,7 @@ }, "queue": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/queue/-/queue-3.1.0.tgz", + "resolved": "http://registry.npmjs.org/queue/-/queue-3.1.0.tgz", "integrity": "sha1-bEnQHwCeIlZ4h4nyv/rGuLmZBYU=", "dev": true, "requires": { diff --git a/src/datascience-ui/history-react/MainPanel.tsx b/src/datascience-ui/history-react/MainPanel.tsx index f2c507118796..2eb8fbc86240 100644 --- a/src/datascience-ui/history-react/MainPanel.tsx +++ b/src/datascience-ui/history-react/MainPanel.tsx @@ -290,6 +290,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 executionCount = this.getInputExecutionCount(this.state.cellVMs); return (
@@ -309,6 +310,7 @@ export class MainPanel extends React.Component ref={this.saveEditCellRef} gotoCode={noop} delete={noop} + editExecutionCount={executionCount} onCodeCreated={this.editableCodeCreated} onCodeChange={this.codeChange} monacoTheme={this.state.monacoTheme} diff --git a/src/datascience-ui/history-react/cell.tsx b/src/datascience-ui/history-react/cell.tsx index 3d07c770d3fe..c797334c20fe 100644 --- a/src/datascience-ui/history-react/cell.tsx +++ b/src/datascience-ui/history-react/cell.tsx @@ -21,7 +21,6 @@ import './cell.css'; import { CellButton } from './cellButton'; import { Code } from './code'; import { CollapseButton } from './collapseButton'; -import { CommandPrompt } from './commandPrompt'; import { ExecutionCount } from './executionCount'; import { Image, ImageName } from './image'; import { InputHistory } from './inputHistory'; @@ -41,6 +40,7 @@ interface ICellProps { errorBackgroundColor: string; monacoTheme: string | undefined; editorOptions: monacoEditor.editor.IEditorOptions; + editExecutionCount: number; gotoCode(): void; delete(): void; submitNewCode(code: string): void; @@ -187,7 +187,7 @@ export class Cell extends React.Component { return this.props.cellVM.editable ? (
- +
) : (
diff --git a/src/datascience-ui/history-react/code.css b/src/datascience-ui/history-react/code.css index 8657534e3dc0..e5ab31041827 100644 --- a/src/datascience-ui/history-react/code.css +++ b/src/datascience-ui/history-react/code.css @@ -3,6 +3,7 @@ position: relative; width:100%; margin-bottom:16px; + top: -2px; /* Account for spacing removed from the monaco editor */ } .code-area-editable { diff --git a/src/datascience-ui/history-react/contentPanel.tsx b/src/datascience-ui/history-react/contentPanel.tsx index 80ae1a05bbe5..b084d6a4cda2 100644 --- a/src/datascience-ui/history-react/contentPanel.tsx +++ b/src/datascience-ui/history-react/contentPanel.tsx @@ -75,6 +75,7 @@ export class ContentPanel extends React.Component { baseTheme={baseTheme} codeTheme={this.props.codeTheme} showWatermark={false} + editExecutionCount={0} errorBackgroundColor={actualErrorBackgroundColor} gotoCode={() => this.props.gotoCellCode(index)} delete={() => this.props.deleteCell(index)} diff --git a/src/datascience-ui/history-react/executionCount.css b/src/datascience-ui/history-react/executionCount.css index 9473d225fea0..861c10dd984c 100644 --- a/src/datascience-ui/history-react/executionCount.css +++ b/src/datascience-ui/history-react/executionCount.css @@ -3,6 +3,7 @@ font-weight: bold; display:flex; color: var(--code-comment-color); + font-family: var(--code-font-family); } .execution-count-busy-outer { From 6104071e232b5e6b025dff6c9640e0f4f1481efd Mon Sep 17 00:00:00 2001 From: Rich Chiodo Date: Fri, 24 May 2019 08:18:44 -0700 Subject: [PATCH 2/3] Fix magics and comments parsing (#5746) * Fix magics and comments parsing * Fix mime types without real jupyter --- news/2 Fixes/5537.md | 1 + src/client/datascience/cellMatcher.ts | 5 +++ src/client/datascience/common.ts | 31 ++++++++++--------- .../datascience/jupyter/jupyterServer.ts | 6 ++-- src/test/datascience/datascience.unit.test.ts | 11 ++++++- src/test/datascience/mockJupyterManager.ts | 4 ++- .../datascience/notebook.functional.test.ts | 4 +-- 7 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 news/2 Fixes/5537.md diff --git a/news/2 Fixes/5537.md b/news/2 Fixes/5537.md new file mode 100644 index 000000000000..8a515c152c40 --- /dev/null +++ b/news/2 Fixes/5537.md @@ -0,0 +1 @@ +Fix magics running from a python file. \ No newline at end of file diff --git a/src/client/datascience/cellMatcher.ts b/src/client/datascience/cellMatcher.ts index 7892a662269c..fdf8999f140e 100644 --- a/src/client/datascience/cellMatcher.ts +++ b/src/client/datascience/cellMatcher.ts @@ -32,6 +32,11 @@ export class CellMatcher { return this.codeMatchRegEx.test(code); } + public stripMarkers(code: string) : string { + const lines = code.splitLines({trim: false, removeEmptyEntries: false}); + return lines.filter(l => !this.isCode(l) && !this.isMarkdown(l)).join('\n'); + } + public exec(code: string) : string | undefined { let result: RegExpExecArray | null = null; if (this.codeMatchRegEx.test(code)) { diff --git a/src/client/datascience/common.ts b/src/client/datascience/common.ts index cd19b5f13ff7..b60024563045 100644 --- a/src/client/datascience/common.ts +++ b/src/client/datascience/common.ts @@ -24,12 +24,13 @@ export function concatMultilineString(str: nbformat.MultilineString): string { } // Strip out comment lines from code -export function stripComments(str: nbformat.MultilineString): nbformat.MultilineString { - if (Array.isArray(str)) { - return extractNonComments(str); - } else { - return extractNonComments([str]); - } +export function stripComments(str: string): string { + let result: string = ''; + parseForComments( + str.splitLines({trim: false, removeEmptyEntries: false}), + (_s) => noop, + (s) => result = result.concat(`${s}\n`)); + return result; } export function formatStreamText(str: string): string { @@ -77,6 +78,7 @@ export function generateMarkdownFromCodeLines(lines: string[]) { return appendLineFeed(extractComments(lines.slice(1))); } +// tslint:disable-next-line: cyclomatic-complexity export function parseForComments( lines: string[], foundCommentLine: (s: string, i: number) => void, @@ -109,15 +111,20 @@ export function parseForComments( } // Not inside either, see if starting a quote } else if (isMultilineQuote && !isMultilineComment) { - insideMultilineQuote = isMultilineQuote; + // Make sure doesn't begin and end on the same line. + const beginQuote = trim.indexOf(isMultilineQuote); + const endQuote = trim.lastIndexOf(isMultilineQuote); + insideMultilineQuote = endQuote !== beginQuote ? undefined : isMultilineQuote; foundNonCommentLine(l, pos); // Not starting a quote, might be starting a comment } else if (isMultilineComment) { - insideMultilineComment = isMultilineComment; + // See if this line ends the comment too or not + const endIndex = trim.indexOf(isMultilineComment, 3); + insideMultilineComment = endIndex >= 0 ? undefined : isMultilineComment; // Might end with text too if (trim.length > 3) { - foundCommentLine(trim.slice(3), pos); + foundCommentLine(trim.slice(3, endIndex >= 0 ? endIndex : undefined), pos); } } else { // Normal line @@ -136,9 +143,3 @@ function extractComments(lines: string[]): string[] { parseForComments(lines, (s) => result.push(s), (_s) => noop()); return result; } - -function extractNonComments(lines: string[]): string[] { - const result: string[] = []; - parseForComments(lines, (_s) => noop, (s) => result.push(s)); - return result; -} diff --git a/src/client/datascience/jupyter/jupyterServer.ts b/src/client/datascience/jupyter/jupyterServer.ts index 2df5c5f16a87..f08f81b872b6 100644 --- a/src/client/datascience/jupyter/jupyterServer.ts +++ b/src/client/datascience/jupyter/jupyterServer.ts @@ -21,6 +21,7 @@ import { createDeferred, Deferred, sleep } from '../../common/utils/async'; import * as localize from '../../common/utils/localize'; import { noop } from '../../common/utils/misc'; import { generateCells } from '../cellFactory'; +import { CellMatcher } from '../cellMatcher'; import { concatMultilineString } from '../common'; import { Identifiers } from '../constants'; import { @@ -514,10 +515,11 @@ export class JupyterServerBase implements INotebookServer { private generateRequest = (code: string, silent?: boolean): Kernel.IFuture | undefined => { //this.logger.logInformation(`Executing code in jupyter : ${code}`) try { + const cellMatcher = new CellMatcher(this.configService.getSettings().datascience); return this.session ? this.session.requestExecute( { - // Replace windows line endings with unix line endings. - code: code.replace(/\r\n/g, '\n'), + // Remove the cell marker if we have one. + code: cellMatcher.stripMarkers(code), stop_on_error: false, allow_stdin: false, store_history: !silent // Silent actually means don't output anything. Store_history is what affects execution_count diff --git a/src/test/datascience/datascience.unit.test.ts b/src/test/datascience/datascience.unit.test.ts index a34457e37e00..07bfb0e849cf 100644 --- a/src/test/datascience/datascience.unit.test.ts +++ b/src/test/datascience/datascience.unit.test.ts @@ -4,7 +4,7 @@ import { assert } from 'chai'; import { generateCells } from '../../client/datascience/cellFactory'; -import { formatStreamText } from '../../client/datascience/common'; +import { formatStreamText, stripComments } from '../../client/datascience/common'; import { InputHistory } from '../../datascience-ui/history-react/inputHistory'; // tslint:disable: max-func-body-length @@ -219,5 +219,14 @@ class Pizza(object): assert.equal(cells[1].data.cell_type, 'code', 'code cell not generated'); assert.equal(cells[1].data.source.length, 7, 'Lines for code not emitted'); assert.equal(cells[1].data.source[3], ' self.toppings = toppings\n', 'Lines for cell not emitted'); + + // Non comments tests + let nonComments = stripComments(multilineCode); + assert.ok(nonComments.startsWith('myvar = """ # Lorem Ipsum'), 'Variable set to multiline string not working'); + nonComments = stripComments(multilineTwo); + assert.equal(nonComments, '', 'Multline comment is not being stripped'); + nonComments = stripComments(multilineQuoteInFunc); + assert.equal(nonComments.splitLines().length, 6, 'Splitting quote in func wrong number of lines'); }); + }); diff --git a/src/test/datascience/mockJupyterManager.ts b/src/test/datascience/mockJupyterManager.ts index b089ddd32ef5..014287f9fd4c 100644 --- a/src/test/datascience/mockJupyterManager.ts +++ b/src/test/datascience/mockJupyterManager.ts @@ -17,6 +17,7 @@ import { ExecutionResult, IProcessServiceFactory, IPythonExecutionFactory, Outpu import { IAsyncDisposableRegistry, IConfigurationService } from '../../client/common/types'; import { EXTENSION_ROOT_DIR } from '../../client/constants'; import { generateCells } from '../../client/datascience/cellFactory'; +import { CellMatcher } from '../../client/datascience/cellMatcher'; import { concatMultilineString } from '../../client/datascience/common'; import { Identifiers } from '../../client/datascience/constants'; import { @@ -192,7 +193,8 @@ export class MockJupyterManager implements IJupyterSessionManager { public addCell(code: string, result?: undefined | string | number | nbformat.IUnrecognizedOutput | nbformat.IExecuteResult | nbformat.IDisplayData | nbformat.IStream | nbformat.IError, mimeType?: string) { const cells = generateCells(undefined, code, 'foo.py', 1, true, uuid()); cells.forEach(c => { - const key = concatMultilineString(c.data.source).replace(LineFeedRegEx, ''); + const cellMatcher = new CellMatcher(); + const key = cellMatcher.stripMarkers(concatMultilineString(c.data.source)).replace(LineFeedRegEx, ''); if (c.data.cell_type === 'code') { const massagedResult = this.massageCellResult(result, mimeType); const data: nbformat.ICodeCell = c.data as nbformat.ICodeCell; diff --git a/src/test/datascience/notebook.functional.test.ts b/src/test/datascience/notebook.functional.test.ts index 8e8e7e874bcd..97c3710999b2 100644 --- a/src/test/datascience/notebook.functional.test.ts +++ b/src/test/datascience/notebook.functional.test.ts @@ -661,10 +661,10 @@ df.head()`, }, { // Important to test as multiline cell magics only work if they are the first item in the cell - // Doesn't work with a comment though. markdownRegEx: undefined, code: - `%%bash + `#%% +%%bash echo 'hello'`, mimeType: 'text/plain', cellType: 'code', From 0e41049507c6e980a5a1d492718474de82b48ff2 Mon Sep 17 00:00:00 2001 From: Rich Chiodo Date: Fri, 24 May 2019 08:19:03 -0700 Subject: [PATCH 3/3] Fix scrolling (#5747) --- news/2 Fixes/5560.md | 1 + package-lock.json | 60 ++++++++++++------- .../history-react/contentPanel.tsx | 22 ++----- 3 files changed, 46 insertions(+), 37 deletions(-) create mode 100644 news/2 Fixes/5560.md diff --git a/news/2 Fixes/5560.md b/news/2 Fixes/5560.md new file mode 100644 index 000000000000..f62b1c3897a7 --- /dev/null +++ b/news/2 Fixes/5560.md @@ -0,0 +1 @@ +Change scrolling to not animate to workaround async updates breaking the animation. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d286f426343e..5b0cad043f6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3959,12 +3959,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3979,17 +3981,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4106,7 +4111,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4118,6 +4124,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4132,6 +4139,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4139,12 +4147,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4163,6 +4173,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4243,7 +4254,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4255,6 +4267,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4376,6 +4389,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7467,12 +7481,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7492,7 +7508,8 @@ "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", @@ -7640,6 +7657,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -12347,7 +12365,7 @@ "dependencies": { "convert-source-map": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "resolved": false, "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { @@ -12356,7 +12374,7 @@ }, "execa": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "resolved": false, "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { @@ -12382,7 +12400,7 @@ }, "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "resolved": false, "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { @@ -12397,7 +12415,7 @@ }, "get-stream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "resolved": false, "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { @@ -12406,7 +12424,7 @@ }, "glob": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "resolved": false, "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { @@ -12420,7 +12438,7 @@ }, "locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "resolved": false, "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { @@ -12440,7 +12458,7 @@ }, "os-locale": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "resolved": false, "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { @@ -12451,7 +12469,7 @@ }, "path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "resolved": false, "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, @@ -12463,7 +12481,7 @@ }, "pkg-dir": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "resolved": false, "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { @@ -12472,7 +12490,7 @@ }, "pump": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "resolved": false, "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { @@ -12488,13 +12506,13 @@ }, "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "resolved": false, "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "rimraf": { "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "resolved": false, "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { diff --git a/src/datascience-ui/history-react/contentPanel.tsx b/src/datascience-ui/history-react/contentPanel.tsx index b084d6a4cda2..521c9fe57060 100644 --- a/src/datascience-ui/history-react/contentPanel.tsx +++ b/src/datascience-ui/history-react/contentPanel.tsx @@ -30,7 +30,7 @@ export interface IContentPanelProps { } export class ContentPanel extends React.Component { - private bottom: HTMLDivElement | undefined; + private bottomRef: React.RefObject = React.createRef(); constructor(prop: IContentPanelProps) { super(prop); } @@ -51,7 +51,7 @@ export class ContentPanel extends React.Component { {this.renderCells()}
-
+
); } @@ -88,20 +88,10 @@ export class ContentPanel extends React.Component { } private scrollToBottom = () => { - if (this.bottom && this.bottom.scrollIntoView && !this.props.skipNextScroll && !this.props.testMode) { - // Delay this until we are about to render. React hasn't setup the size of the bottom element - // yet so we need to delay. 10ms looks good from a user point of view - setTimeout(() => { - if (this.bottom) { - this.bottom.scrollIntoView({behavior: 'smooth', block : 'end', inline: 'end'}); - } - }, 100); - } - } - - private updateBottom = (newBottom: HTMLDivElement) => { - if (newBottom !== this.bottom) { - this.bottom = newBottom; + if (this.bottomRef.current && !this.props.skipNextScroll && !this.props.testMode) { + // Force auto here as smooth scrolling can be canceled by updates to the window + // from elsewhere (and keeping track of these would make this hard to maintain) + this.bottomRef.current.scrollIntoView({behavior: 'auto', block: 'start', inline: 'nearest'}); } }