src/vs/base/common/scrollable.ts

522 LOC · 263 covered · 259 uncovered · 44 ranges · 2071 concepts · 3 introducers · 1053 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filetextModel.ts ×6 · 31 introduced LOCtextModel.ts ×6computeAutomaticInstructions.ts ×1 · 2 introduced LOCcomputeAutomaticInstruct…computeAutomaticInstructions.ts ×1 · 2 introduced LOCcomputeAutomaticInstruct…computeAutomaticInstructions.ts ×2 · 6 introduced LOCcomputeAutomaticInstruct…modelService.ts ×4 · 8 introduced LOCmodelService.ts ×4extHostTerminalService.ts ×31 · 156 introduced LOCextHostTerminalService.t…extHostSCM.ts ×86 · 432 introduced LOCextHostSCM.ts ×86extHostChatAgents2.ts ×98 · 451 introduced LOCextHostChatAgents2.ts ×9…textModel.ts ×1 · 1 introduced LOCtextModel.ts ×1textModel.ts ×20 · 342 introduced LOCtextModel.ts ×20extHostTerminalService.ts ×109 · 894 introduced LOCextHostTerminalService.t…testRPCProtocol.ts ×2 · 5 introduced LOCtestRPCProtocol.ts ×2testRPCProtocol.ts ×9 · 119 introduced LOCtestRPCProtocol.ts ×9extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions roundtrip from -> to preserves data|occurrence=1 · 0 introduced LOCextHostTypeConverters.te…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 6 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×4 · 12 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions to handles Dto with UriComponents|occurrence=1 · 0 introduced LOCextHostTypeConverters.te…extHostTypeConverters.ts ×3 · 14 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×13 · 70 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 5 introduced LOCextHostTypeConverters.ts…themables.ts ×1 · 5 introduced LOCthemables.ts ×1extHostRpcService.ts ×2 · 38 introduced LOCextHostRpcService.ts ×2extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHost.protocol.ts ×3 · 4200 introduced LOCextHost.protocol.ts ×3extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×2 · 11 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×1 · 1 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×3 · 3 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×3 · 3 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×2 · 2 introduced LOCextHostTypeConverters.ts…extHostTypeConverters.ts ×2 · 2 introduced LOCextHostTypeConverters.ts…extHostTypes.ts ×270 · 6339 introduced LOCextHostTypes.ts ×270textModel.ts ×2 · 6 introduced LOCtextModel.ts ×2pieceTreeBase.ts ×1 · 2 introduced LOCpieceTreeBase.ts ×1pieceTreeBase.ts ×1 · 2 introduced LOCpieceTreeBase.ts ×1testThemeService.ts ×18 · 401 introduced LOCtestThemeService.ts ×18modelService.ts ×30 · 152 introduced LOCmodelService.ts ×30pieceTreeTextBufferBuilder.ts ×19 · 149 introduced LOCpieceTreeTextBufferBuild…modelLineProjectionData.ts ×2 · 13 introduced LOCmodelLineProjectionData.…pieceTreeTextBuffer.ts ×1 · 3 introduced LOCpieceTreeTextBuffer.ts ×…pieceTreeTextBuffer.ts ×4 · 31 introduced LOCpieceTreeTextBuffer.ts ×…textModel.ts ×3 · 10 introduced LOCtextModel.ts ×3textModel.ts ×190 · 2948 introduced LOCtextModel.ts ×190brackets.ts ×1 · 3 introduced LOCbrackets.ts ×1tokenizer.ts ×18 · 196 introduced LOCtokenizer.ts ×18languageConfigurationRegistry.ts ×5 · 64 introduced LOClanguageConfigurationReg…languageConfiguration.ts ×1 · 1 introduced LOClanguageConfiguration.ts…testLanguageConfigurationService.ts ×4 · 23 introduced LOCtestLanguageConfiguratio…languageConfigurationRegistry.ts ×28 · 260 introduced LOClanguageConfigurationReg…linesLayout.ts ×3 · 29 introduced LOClinesLayout.ts ×3modelLineProjectionData.ts ×1 · 17 introduced LOCmodelLineProjectionData.…modelLineProjectionData.ts ×18 · 97 introduced LOCmodelLineProjectionData.…linesLayout.ts ×2 · 27 introduced LOClinesLayout.ts ×2linesLayout.ts ×7 · 44 introduced LOClinesLayout.ts ×7textModelEvents.ts ×25 · 438 introduced LOCtextModelEvents.ts ×25linesLayout.test|title=Editor ViewLayout - LinesLayout LinesLayout Bug|occurrence=1 · 0 introduced LOClinesLayout.test|title=E…linesLayout.ts ×2 · 6 introduced LOClinesLayout.ts ×2linesLayout.ts ×1 · 4 introduced LOClinesLayout.ts ×1linesLayout.ts ×2 · 12 introduced LOClinesLayout.ts ×2linesLayout.ts ×1 · 4 introduced LOClinesLayout.ts ×1linesLayout.ts ×13 · 72 introduced LOClinesLayout.ts ×13linesLayout.ts ×3 · 5 introduced LOClinesLayout.ts ×3linesLayout.ts ×3 · 8 introduced LOClinesLayout.ts ×3linesLayout.ts ×46 · 279 introduced LOClinesLayout.ts ×46onEnter.ts ×1 · 7 introduced LOConEnter.ts ×1onEnter.ts ×2 · 4 introduced LOConEnter.ts ×2onEnter.ts ×8 · 32 introduced LOConEnter.ts ×8lineHeights.ts ×2 · 3 introduced LOClineHeights.ts ×2lineHeights.ts ×24 · 127 introduced LOClineHeights.ts ×24onEnter.ts ×6 · 37 introduced LOConEnter.ts ×6strings.ts ×1 · 7 introduced LOCstrings.ts ×1editorOptions.ts ×92 · 6015 introduced LOCeditorOptions.ts ×92scrollable.ts ×3 · 16 introduced LOCscrollable.ts ×3scrollable.ts ×9 · 42 introduced LOCscrollable.ts ×9scrollable.ts ×32 · 205 introduced LOCscrollable.ts ×32scrollable.test|title=SmoothScrollingOperation scroll 100 lines (40 fit)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/scrollable.test|title=SmoothScrollingOperation scroll 100 lines (40 fit)|occurrence=1scrollable.test|title=Sm…scrollable.test|title=SmoothScrollingOperation scroll 125 lines (40 fit)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/scrollable.test|title=SmoothScrollingOperation scroll 125 lines (40 fit)|occurrence=1scrollable.test|title=Sm…scrollable.test|title=SmoothScrollingOperation scroll 25 lines (40 fit)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/scrollable.test|title=SmoothScrollingOperation scroll 25 lines (40 fit)|occurrence=1scrollable.test|title=Sm…scrollable.test|title=SmoothScrollingOperation scroll 500 lines (40 fit)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/scrollable.test|title=SmoothScrollingOperation scroll 500 lines (40 fit)|occurrence=1scrollable.test|title=Sm…scrollable.test|title=SmoothScrollingOperation scroll 75 lines (40 fit)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/scrollable.test|title=SmoothScrollingOperation scroll 75 lines (40 fit)|occurrence=1scrollable.test|title=Sm…brackets.test|title=Bracket Pair Colorizer - Brackets Basic|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/bracketPairColorizer/brackets.test|title=Bracket Pair Colorizer - Brackets Basic|occurrence=1brackets.test|title=Brac…linesTextBuffer.test|title=PieceTreeTextBuffer._getInverseEdits multiline delete|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test|title=PieceTreeTextBuffer._getInverseEdits multiline delete|occurrence=1linesTextBuffer.test|tit…linesTextBuffer.test|title=PieceTreeTextBuffer._getInverseEdits single delete|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test|title=PieceTreeTextBuffer._getInverseEdits single delete|occurrence=1linesTextBuffer.test|tit…modelInjectedText.test|title=Editor Model - Injected Text Events Basic|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/modelInjectedText.test|title=Editor Model - Injected Text Events Basic|occurrence=1modelInjectedText.test|t…languageConfiguration.test|title=StandardAutoClosingPairConditional Missing notIn|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/modes/languageConfiguration.test|title=StandardAutoClosingPairConditional Missing notIn|occurrence=1languageConfiguration.te…onEnter.test|title=OnEnter uses brackets|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/modes/supports/onEnter.test|title=OnEnter uses brackets|occurrence=1onEnter.test|title=OnEnt…modelService.test|title=ModelService EOL setting respected depending on root|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/modelService.test|title=ModelService EOL setting respected depending on root|occurrence=1modelService.test|title=…linesLayout.test|title=Editor ViewLayout - LinesLayout LinesLayout Bug|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewLayout/linesLayout.test|title=Editor ViewLayout - LinesLayout LinesLayout Bug|occurrence=1linesLayout.test|title=E…linesLayout.test|title=Editor ViewLayout - LinesLayout LinesLayout getLinesViewportData 2 & getWhitespaceViewportData|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewLayout/linesLayout.test|title=Editor ViewLayout - LinesLayout LinesLayout getLinesViewportData 2 & getWhitespaceViewportData|occurrence=1linesLayout.test|title=E…linesLayout.test|title=Editor ViewLayout - LinesLayout LinesLayout getWhitespaceAtVerticalOffset|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewLayout/linesLayout.test|title=Editor ViewLayout - LinesLayout LinesLayout getWhitespaceAtVerticalOffset|occurrence=1linesLayout.test|title=E…lineBreakData.test|title=Editor ViewModel - LineBreakData Basic|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/lineBreakData.test|title=Editor ViewModel - LineBreakData Basic|occurrence=1lineBreakData.test|title…extHostChatAgents2.test|title=ExtHostChatAgents2 reports anchor before resolving it|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostChatAgents2.test|title=ExtHostChatAgents2 reports anchor before resolving it|occurrence=1extHostChatAgents2.test|…extHostSCM.test|title=ExtHostSCM disposed source controls are removed from extension bookkeeping|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostSCM.test|title=ExtHostSCM disposed source controls are removed from extension bookkeeping|occurrence=1extHostSCM.test|title=Ex…extHostTerminalService.test|title=ExtHostTerminalService $acceptTerminalClosed cancels in-flight link providers and clears the link cache|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalService.test|title=ExtHostTerminalService $acceptTerminalClosed cancels in-flight link providers and clears the link cache|occurrence=1extHostTerminalService.t…extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions from converts API type to IChatRequestModeInstructions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions from converts API type to IChatRequestModeInstructions|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions from handles missing toolReferences|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions from handles missing toolReferences|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions from returns undefined for undefined input|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions from returns undefined for undefined input|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions roundtrip from -> to preserves data|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions roundtrip from -> to preserves data|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions to converts IChatRequestModeInstructions to API type|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions to converts IChatRequestModeInstructions to API type|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions to handles Dto with UriComponents|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions to handles Dto with UriComponents|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions to returns undefined for undefined input|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters ChatRequestModeInstructions to returns undefined for undefined input|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters ChatToolInvocationPart converts subagent data with its model name|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters ChatToolInvocationPart converts subagent data with its model name|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters IconPath from ThemeIcon|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters IconPath from ThemeIcon|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters IconPath from URI|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters IconPath from URI|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters IconPath from undefined|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters IconPath from undefined|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters IconPath to ThemeIcon|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters IconPath to ThemeIcon|occurrence=1extHostTypeConverters.te…extHostTypeConverters.test|title=extHostTypeConverters IconPath to URI|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters IconPath to URI|occurrence=1extHostTypeConverters.te…light|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters IconPath to dark/light|occurrence=1light|occurrence=1extHostTypeConverters.test|title=extHostTypeConverters IconPath to undefined|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTypeConverters.test|title=extHostTypeConverters IconPath to undefined|occurrence=1extHostTypeConverters.te…computeAutomaticInstructions.test|title=getFilePath should return uri.toString() for other schemes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/computeAutomaticInstructions.test|title=getFilePath should return uri.toString() for other schemes|occurrence=1computeAutomaticInstruct… URIs when connected to a Windows remote|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/computeAutomaticInstructions.test|title=getFilePath should return vscode-local:/ URI string for file:// URIs when connected to a Windows remote|occurrence=1 URIs when connected to … URIs when connected to a remote|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/computeAutomaticInstructions.test|title=getFilePath should return vscode-local:/ URI string for file:// URIs when connected to a remote|occurrence=1 URIs when connected to …Focused file · src/vs/base/common/scrollable.ts · 522 LOCcommon/scrollable.ts

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- scrollable.ts ×32
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Emitter, Event } from './event.js';
7 > import { Disposable, IDisposable } from './lifecycle.js';
8 >
9 > export const enum ScrollbarVisibility {
10 > Auto = 1,
11 > Hidden = 2,
12 > Visible = 3
13 > }
14 >
15 > export interface ScrollEvent {
16 > inSmoothScrolling: boolean;
17 >
18 > oldWidth: number;
19 > oldScrollWidth: number;
20 > oldScrollLeft: number;
21 >
22 > width: number;
23 > scrollWidth: number;
24 > scrollLeft: number;
25 >
26 > oldHeight: number;
27 > oldScrollHeight: number;
28 > oldScrollTop: number;
29 >
30 > height: number;
31 > scrollHeight: number;
32 > scrollTop: number;
33 >
34 > widthChanged: boolean;
35 > scrollWidthChanged: boolean;
36 > scrollLeftChanged: boolean;
37 >
38 > heightChanged: boolean;
39 > scrollHeightChanged: boolean;
40 > scrollTopChanged: boolean;
41 > }
42 >
43 > export class ScrollState implements IScrollDimensions, IScrollPosition {
44 > _scrollStateBrand: void = undefined;
45 >
46 > public readonly rawScrollLeft: number;
47 > public readonly rawScrollTop: number;
48 >
49 > public readonly width: number;
50 > public readonly scrollWidth: number;
51 > public readonly scrollLeft: number;
52 > public readonly height: number;
53 > public readonly scrollHeight: number;
54 > public readonly scrollTop: number;
55 >
56 > constructor(
57 private readonly _forceIntegerValues: boolean,
58 width: number,
59 scrollWidth: number,
60 scrollLeft: number,
61 height: number,
62 scrollHeight: number,
63 scrollTop: number
64 ) {
65 if (this._forceIntegerValues) {
66 width = width | 0;
67 scrollWidth = scrollWidth | 0;
68 scrollLeft = scrollLeft | 0;
69 height = height | 0;
70 scrollHeight = scrollHeight | 0;
71 scrollTop = scrollTop | 0;
72 }
73
74 this.rawScrollLeft = scrollLeft; // before validation
75 this.rawScrollTop = scrollTop; // before validation
76
77 if (width < 0) {
78 width = 0;
79 }
80 if (scrollLeft + width > scrollWidth) {
81 scrollLeft = scrollWidth - width;
82 }
83 if (scrollLeft < 0) {
84 scrollLeft = 0;
85 }
86
87 if (height < 0) {
88 height = 0;
89 }
90 if (scrollTop + height > scrollHeight) {
91 scrollTop = scrollHeight - height;
92 }
93 if (scrollTop < 0) {
94 scrollTop = 0;
95 }
96
97 this.width = width;
98 this.scrollWidth = scrollWidth;
99 this.scrollLeft = scrollLeft;
100 this.height = height;
101 this.scrollHeight = scrollHeight;
102 this.scrollTop = scrollTop;
103 }
105 > public equals(other: ScrollState): boolean {
106 return (
107 this.rawScrollLeft === other.rawScrollLeft
108 && this.rawScrollTop === other.rawScrollTop
109 && this.width === other.width
110 && this.scrollWidth === other.scrollWidth
111 && this.scrollLeft === other.scrollLeft
112 && this.height === other.height
113 && this.scrollHeight === other.scrollHeight
114 && this.scrollTop === other.scrollTop
115 );
116 }
118 > public withScrollDimensions(update: INewScrollDimensions, useRawScrollPositions: boolean): ScrollState {
119 return new ScrollState(
120 this._forceIntegerValues,
121 (typeof update.width !== 'undefined' ? update.width : this.width),
122 (typeof update.scrollWidth !== 'undefined' ? update.scrollWidth : this.scrollWidth),
123 useRawScrollPositions ? this.rawScrollLeft : this.scrollLeft,
124 (typeof update.height !== 'undefined' ? update.height : this.height),
125 (typeof update.scrollHeight !== 'undefined' ? update.scrollHeight : this.scrollHeight),
126 useRawScrollPositions ? this.rawScrollTop : this.scrollTop
127 );
128 }
130 > public withScrollPosition(update: INewScrollPosition): ScrollState {
131 return new ScrollState(
132 this._forceIntegerValues,
133 this.width,
134 this.scrollWidth,
135 (typeof update.scrollLeft !== 'undefined' ? update.scrollLeft : this.rawScrollLeft),
136 this.height,
137 this.scrollHeight,
138 (typeof update.scrollTop !== 'undefined' ? update.scrollTop : this.rawScrollTop)
139 );
140 }
142 > public createScrollEvent(previous: ScrollState, inSmoothScrolling: boolean): ScrollEvent {
143 const widthChanged = (this.width !== previous.width);
144 const scrollWidthChanged = (this.scrollWidth !== previous.scrollWidth);
145 const scrollLeftChanged = (this.scrollLeft !== previous.scrollLeft);
146
147 const heightChanged = (this.height !== previous.height);
148 const scrollHeightChanged = (this.scrollHeight !== previous.scrollHeight);
149 const scrollTopChanged = (this.scrollTop !== previous.scrollTop);
150
151 return {
152 inSmoothScrolling: inSmoothScrolling,
153 oldWidth: previous.width,
154 oldScrollWidth: previous.scrollWidth,
155 oldScrollLeft: previous.scrollLeft,
156
157 width: this.width,
158 scrollWidth: this.scrollWidth,
159 scrollLeft: this.scrollLeft,
160
161 oldHeight: previous.height,
162 oldScrollHeight: previous.scrollHeight,
163 oldScrollTop: previous.scrollTop,
164
165 height: this.height,
166 scrollHeight: this.scrollHeight,
167 scrollTop: this.scrollTop,
168
169 widthChanged: widthChanged,
170 scrollWidthChanged: scrollWidthChanged,
171 scrollLeftChanged: scrollLeftChanged,
172
173 heightChanged: heightChanged,
174 scrollHeightChanged: scrollHeightChanged,
175 scrollTopChanged: scrollTopChanged,
176 };
177 }
179 > }
180 >
181 > export interface IScrollDimensions {
182 > readonly width: number;
183 > readonly scrollWidth: number;
184 > readonly height: number;
185 > readonly scrollHeight: number;
186 > }
187 > export interface INewScrollDimensions {
188 > width?: number;
189 > scrollWidth?: number;
190 > height?: number;
191 > scrollHeight?: number;
192 > }
193 >
194 > export interface IScrollPosition {
195 > readonly scrollLeft: number;
196 > readonly scrollTop: number;
197 > }
198 > export interface ISmoothScrollPosition {
199 > readonly scrollLeft: number;
200 > readonly scrollTop: number;
201 >
202 > readonly width: number;
203 > readonly height: number;
204 > }
205 > export interface INewScrollPosition {
206 > scrollLeft?: number;
207 > scrollTop?: number;
208 > }
209 >
210 > export interface IScrollableOptions {
211 > /**
212 > * Define if the scroll values should always be integers.
213 > */
214 > forceIntegerValues: boolean;
215 > /**
216 > * Set the duration (ms) used for smooth scroll animations.
217 > */
218 > smoothScrollDuration: number;
219 > /**
220 > * A function to schedule an update at the next frame (used for smooth scroll animations).
221 > */
222 > scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable;
223 > }
224 >
225 > export class Scrollable extends Disposable {
226 >
227 > _scrollableBrand: void = undefined;
228 >
229 > private _smoothScrollDuration: number;
230 > private readonly _scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable;
231 > private _state: ScrollState;
232 > private _smoothScrolling: SmoothScrollingOperation | null;
233 >
234 > private _onScroll = this._register(new Emitter<ScrollEvent>());
235 > public readonly onScroll: Event<ScrollEvent> = this._onScroll.event;
236 >
237 > constructor(options: IScrollableOptions) {
238 super();
239
240 this._smoothScrollDuration = options.smoothScrollDuration;
241 this._scheduleAtNextAnimationFrame = options.scheduleAtNextAnimationFrame;
242 this._state = new ScrollState(options.forceIntegerValues, 0, 0, 0, 0, 0, 0);
243 this._smoothScrolling = null;
244 }
246 > public override dispose(): void {
247 if (this._smoothScrolling) {
248 this._smoothScrolling.dispose();
249 this._smoothScrolling = null;
250 }
251 super.dispose();
252 }
254 > public setSmoothScrollDuration(smoothScrollDuration: number): void {
255 this._smoothScrollDuration = smoothScrollDuration;
256 }
258 > public validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition {
259 return this._state.withScrollPosition(scrollPosition);
260 }
262 > public getScrollDimensions(): IScrollDimensions {
263 return this._state;
264 }
266 > public setScrollDimensions(dimensions: INewScrollDimensions, useRawScrollPositions: boolean): void {
267 const newState = this._state.withScrollDimensions(dimensions, useRawScrollPositions);
268 this._setState(newState, Boolean(this._smoothScrolling));
269
270 // Validate outstanding animated scroll position target
271 this._smoothScrolling?.acceptScrollDimensions(this._state);
272 }
274 > /**
275 > * Returns the final scroll position that the instance will have once the smooth scroll animation concludes.
276 > * If no scroll animation is occurring, it will return the current scroll position instead.
277 > */
278 > public getFutureScrollPosition(): IScrollPosition {
279 if (this._smoothScrolling) {
280 return this._smoothScrolling.to;
281 }
282 return this._state;
283 }
285 > /**
286 > * Returns the current scroll position.
287 > * Note: This result might be an intermediate scroll position, as there might be an ongoing smooth scroll animation.
288 > */
289 > public getCurrentScrollPosition(): IScrollPosition {
290 return this._state;
291 }
293 > public setScrollPositionNow(update: INewScrollPosition): void {
294 // no smooth scrolling requested
295 const newState = this._state.withScrollPosition(update);
296
297 // Terminate any outstanding smooth scrolling
298 if (this._smoothScrolling) {
299 this._smoothScrolling.dispose();
300 this._smoothScrolling = null;
301 }
302
303 this._setState(newState, false);
304 }
306 > public setScrollPositionSmooth(update: INewScrollPosition, reuseAnimation?: boolean): void {
307 if (this._smoothScrollDuration === 0) {
308 // Smooth scrolling not supported.
309 return this.setScrollPositionNow(update);
310 }
311
312 if (this._smoothScrolling) {
313 // Combine our pending scrollLeft/scrollTop with incoming scrollLeft/scrollTop
314 update = {
315 scrollLeft: (typeof update.scrollLeft === 'undefined' ? this._smoothScrolling.to.scrollLeft : update.scrollLeft),
316 scrollTop: (typeof update.scrollTop === 'undefined' ? this._smoothScrolling.to.scrollTop : update.scrollTop)
317 };
318
319 // Validate `update`
320 const validTarget = this._state.withScrollPosition(update);
321
322 if (this._smoothScrolling.to.scrollLeft === validTarget.scrollLeft && this._smoothScrolling.to.scrollTop === validTarget.scrollTop) {
323 // No need to interrupt or extend the current animation since we're going to the same place
324 return;
325 }
326 let newSmoothScrolling: SmoothScrollingOperation;
327 if (reuseAnimation) {
328 newSmoothScrolling = new SmoothScrollingOperation(this._smoothScrolling.from, validTarget, this._smoothScrolling.startTime, this._smoothScrolling.duration);
329 } else {
330 newSmoothScrolling = this._smoothScrolling.combine(this._state, validTarget, this._smoothScrollDuration);
331 }
332 this._smoothScrolling.dispose();
333 this._smoothScrolling = newSmoothScrolling;
334 } else {
335 // Validate `update`
336 const validTarget = this._state.withScrollPosition(update);
337
338 this._smoothScrolling = SmoothScrollingOperation.start(this._state, validTarget, this._smoothScrollDuration);
339 }
340
341 // Begin smooth scrolling animation
342 this._smoothScrolling.animationFrameDisposable = this._scheduleAtNextAnimationFrame(() => {
343 if (!this._smoothScrolling) {
344 return;
345 }
346 this._smoothScrolling.animationFrameDisposable = null;
347 this._performSmoothScrolling();
348 });
349 }
351 > public hasPendingScrollAnimation(): boolean {
352 return Boolean(this._smoothScrolling);
353 }
355 > private _performSmoothScrolling(): void {
356 if (!this._smoothScrolling) {
357 return;
358 }
359 const update = this._smoothScrolling.tick();
360 const newState = this._state.withScrollPosition(update);
361
362 this._setState(newState, true);
363
364 if (!this._smoothScrolling) {
365 // Looks like someone canceled the smooth scrolling
366 // from the scroll event handler
367 return;
368 }
369
370 if (update.isDone) {
371 this._smoothScrolling.dispose();
372 this._smoothScrolling = null;
373 return;
374 }
375
376 // Continue smooth scrolling animation
377 this._smoothScrolling.animationFrameDisposable = this._scheduleAtNextAnimationFrame(() => {
378 if (!this._smoothScrolling) {
379 return;
380 }
381 this._smoothScrolling.animationFrameDisposable = null;
382 this._performSmoothScrolling();
383 });
384 }
386 > private _setState(newState: ScrollState, inSmoothScrolling: boolean): void {
387 const oldState = this._state;
388 if (oldState.equals(newState)) {
389 // no change
390 return;
391 }
392 this._state = newState;
393 this._onScroll.fire(this._state.createScrollEvent(oldState, inSmoothScrolling));
394 }
396 >
397 > export class SmoothScrollingUpdate {
398 >
399 > public readonly scrollLeft: number;
400 > public readonly scrollTop: number;
401 > public readonly isDone: boolean;
402 >
403 > constructor(scrollLeft: number, scrollTop: number, isDone: boolean) {
404 > this.scrollLeft = scrollLeft; scrollable.ts ×9
405 > this.scrollTop = scrollTop;
406 > this.isDone = isDone;
407 > }
409 > }
410 >
411 > interface IAnimation {
412 > (completion: number): number;
413 > }
414 >
415 > function createEaseOutCubic(from: number, to: number): IAnimation { scrollable.ts ×9
416 > const delta = to - from;
417 > return function (completion: number): number {
418 > return from + delta * easeOutCubic(completion);
419 > };
420 > }
422 > function createComposed(a: IAnimation, b: IAnimation, cut: number): IAnimation { scrollable.ts ×3
423 > return function (completion: number): number {
424 > if (completion < cut) {
425 > return a(completion / cut);
426 > }
427 > return b((completion - cut) / (1 - cut));
428 > };
429 > }
431 > export class SmoothScrollingOperation {
432 >
433 > public readonly from: ISmoothScrollPosition;
434 > public to: ISmoothScrollPosition;
435 > public readonly duration: number;
436 > public readonly startTime: number;
437 > public animationFrameDisposable: IDisposable | null;
438 >
439 > private scrollLeft!: IAnimation;
440 > private scrollTop!: IAnimation;
441 >
442 > constructor(from: ISmoothScrollPosition, to: ISmoothScrollPosition, startTime: number, duration: number) {
443 > this.from = from; scrollable.ts ×9
444 > this.to = to;
445 > this.duration = duration;
446 > this.startTime = startTime;
447 >
448 > this.animationFrameDisposable = null;
449 >
450 > this._initAnimations();
451 > }
453 > private _initAnimations(): void {
454 > this.scrollLeft = this._initAnimation(this.from.scrollLeft, this.to.scrollLeft, this.to.width); scrollable.ts ×9
455 > this.scrollTop = this._initAnimation(this.from.scrollTop, this.to.scrollTop, this.to.height);
456 > }
458 > private _initAnimation(from: number, to: number, viewportSize: number): IAnimation {
459 > const delta = Math.abs(from - to); scrollable.ts ×9
460 > if (delta > 2.5 * viewportSize) {
461 > let stop1: number, stop2: number; scrollable.ts ×3
462 > if (from < to) {
463 > // scroll to 75% of the viewportSize
464 > stop1 = from + 0.75 * viewportSize;
465 > stop2 = to - 0.75 * viewportSize;
466 > } else {
467 stop1 = from - 0.75 * viewportSize;
468 stop2 = to + 0.75 * viewportSize;
469 }
470 > return createComposed(createEaseOutCubic(from, stop1), createEaseOutCubic(stop2, to), 0.33); scrollable.ts ×3
471 > }
472 > return createEaseOutCubic(from, to); scrollable.ts ×9
473 > }
475 > public dispose(): void {
476 if (this.animationFrameDisposable !== null) {
477 this.animationFrameDisposable.dispose();
478 this.animationFrameDisposable = null;
479 }
480 }
482 > public acceptScrollDimensions(state: ScrollState): void {
483 this.to = state.withScrollPosition(this.to);
484 this._initAnimations();
485 }
487 > public tick(): SmoothScrollingUpdate {
488 return this._tick(Date.now());
489 }
491 > protected _tick(now: number): SmoothScrollingUpdate {
492 > const completion = (now - this.startTime) / this.duration; scrollable.ts ×9
493 >
494 > if (completion < 1) {
495 > const newScrollLeft = this.scrollLeft(completion);
496 > const newScrollTop = this.scrollTop(completion);
497 > return new SmoothScrollingUpdate(newScrollLeft, newScrollTop, false);
498 > }
499 >
500 > return new SmoothScrollingUpdate(this.to.scrollLeft, this.to.scrollTop, true);
501 > }
503 > public combine(from: ISmoothScrollPosition, to: ISmoothScrollPosition, duration: number): SmoothScrollingOperation {
504 return SmoothScrollingOperation.start(from, to, duration);
505 }
507 > public static start(from: ISmoothScrollPosition, to: ISmoothScrollPosition, duration: number): SmoothScrollingOperation {
508 // +10 / -10 : pretend the animation already started for a quicker response to a scroll request
509 duration = duration + 10;
510 const startTime = Date.now() - 10;
511
512 return new SmoothScrollingOperation(from, to, startTime, duration);
513 }
515 >
516 > function easeInCubic(t: number) { scrollable.ts ×9
517 > return Math.pow(t, 3);
518 > }
520 > function easeOutCubic(t: number) { scrollable.ts ×9
521 > return 1 - easeInCubic(1 - t);
522 > }