diff --git a/news/2 Fixes/11554.md b/news/2 Fixes/11554.md new file mode 100644 index 000000000000..e2352638df84 --- /dev/null +++ b/news/2 Fixes/11554.md @@ -0,0 +1 @@ +Fix scrolling when clicking in the interactive window to not jump around. \ No newline at end of file diff --git a/package.json b/package.json index e659b4d2d41b..36a615ef489c 100644 --- a/package.json +++ b/package.json @@ -1761,6 +1761,12 @@ "description": "Maximum size (in pixels) of text output in the Python Interactive window and Notebook Editor before a scrollbar appears. First enable scrolling for cell outputs in settings.", "scope": "resource" }, + "python.dataScience.alwaysScrollOnNewCell": { + "type": "boolean", + "default": false, + "description": "If a new cell comes in, scroll the interactive window to the bottom regardless of where the scroll bar is. The default is to only scroll if the current position was already at the bottom when the new cell is created", + "scope": "resource" + }, "python.dataScience.enableScrollingForCellOutputs": { "type": "boolean", "default": true, diff --git a/src/client/common/types.ts b/src/client/common/types.ts index bd9d6da77f13..06e827798a18 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -389,6 +389,7 @@ export interface IDataScienceSettings { disableJupyterAutoStart?: boolean; jupyterCommandLineArguments: string[]; widgetScriptSources: WidgetCDNs[]; + alwaysScrollOnNewCell?: boolean; } export type WidgetCDNs = 'unpkg.com' | 'jsdelivr.com'; diff --git a/src/datascience-ui/history-react/interactivePanel.tsx b/src/datascience-ui/history-react/interactivePanel.tsx index 66a06e711a9e..0cbec0042ce3 100644 --- a/src/datascience-ui/history-react/interactivePanel.tsx +++ b/src/datascience-ui/history-react/interactivePanel.tsx @@ -373,7 +373,9 @@ ${buildSettingsCss(this.props.settings)}`} if (this.internalScrollCount > 0) { this.internalScrollCount -= 1; } else if (this.contentPanelRef.current) { - const isAtBottom = this.contentPanelRef.current.computeIsAtBottom(e.currentTarget); + const isAtBottom = this.props.settings?.alwaysScrollOnNewCell + ? true + : this.contentPanelRef.current.computeIsAtBottom(e.currentTarget); this.props.scroll(isAtBottom); } }; diff --git a/src/datascience-ui/interactive-common/contentPanel.tsx b/src/datascience-ui/interactive-common/contentPanel.tsx index fba2e3ad5be3..f8653aa48fa4 100644 --- a/src/datascience-ui/interactive-common/contentPanel.tsx +++ b/src/datascience-ui/interactive-common/contentPanel.tsx @@ -3,6 +3,7 @@ 'use strict'; import * as React from 'react'; +import * as fastDeepEqual from 'fast-deep-equal'; import { IDataScienceExtraSettings } from '../../client/datascience/types'; import { InputHistory } from './inputHistory'; import { ICellViewModel } from './mainState'; @@ -37,8 +38,12 @@ export class ContentPanel extends React.Component { public componentDidMount() { this.scrollToBottom(); } - public componentWillReceiveProps() { - this.scrollToBottom(); + public componentWillReceiveProps(prevProps: IContentPanelProps) { + // Scroll if we suddenly finished or updated a cell. This should happen on + // finish, updating output, etc. + if (!fastDeepEqual(prevProps.cellVMs.map(this.outputCheckable), this.props.cellVMs.map(this.outputCheckable))) { + this.scrollToBottom(); + } } public computeIsAtBottom(parent: HTMLDivElement): boolean { @@ -61,6 +66,14 @@ export class ContentPanel extends React.Component { ); } + private outputCheckable = (cellVM: ICellViewModel) => { + // Return the properties that if they change means a cell updated something + return { + outputs: cellVM.cell.data.outputs, + state: cellVM.cell.state + }; + }; + private renderCells = () => { return this.props.cellVMs.map((cellVM: ICellViewModel, index: number) => { return this.props.renderCell(cellVM, index);