diff options
author | Aiday Marlen Kyzy <t-aidaym@microsoft.com> | 2022-07-27 15:25:59 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-27 15:25:59 +0300 |
commit | 45e0ad107ab50573c8c089338ee10d65aa3889fc (patch) | |
tree | d96ec2754f3a80d98c9fa2ad73d5a3b0d63f208d /src/vs | |
parent | cb48abb0c0470c6060ba34586aeb7053f9684ee8 (diff) | |
parent | f1458c0b4cbec35a219a237f031c1a1ad1e711c1 (diff) |
Merge pull request #156306 from aiday-mar/aiday/semanticScroll
Fixing the sticky scroll with reviews from endgame
Diffstat (limited to 'src/vs')
-rw-r--r-- | src/vs/editor/common/config/editorOptions.ts | 2 | ||||
-rw-r--r-- | src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts | 133 | ||||
-rw-r--r-- | src/vs/platform/theme/common/colorRegistry.ts | 4 |
3 files changed, 84 insertions, 55 deletions
diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 066080e9ae3..943a8b7e018 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2537,7 +2537,7 @@ class EditorStickyScroll extends BaseEditorOption<EditorOption.stickyScroll, IEd 'editor.stickyScroll.enabled': { type: 'boolean', default: defaults.enabled, - description: nls.localize('editor.stickyScroll', "Enables the sticky scroll in the editor.") + description: nls.localize('editor.stickyScroll', "Shows the nested current scopes during the scroll at the top of the editor.") }, } ); diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 8de7e41b395..7d9cbf358ed 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor, ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; @@ -16,6 +16,7 @@ import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { SymbolKind } from 'vs/editor/common/languages'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; +import { RunOnceScheduler } from 'vs/base/common/async'; const enum ScrollDirection { Down = 0, @@ -23,32 +24,34 @@ const enum ScrollDirection { None = 2 } -class StickyScrollController implements IEditorContribution { +class StickyScrollController extends Disposable implements IEditorContribution { static readonly ID = 'store.contrib.stickyScrollController'; private readonly _editor: ICodeEditor; private readonly stickyScrollWidget: StickyScrollWidget; private readonly _languageFeaturesService: ILanguageFeaturesService; - - private readonly _store: DisposableStore = new DisposableStore(); private readonly _sessionStore: DisposableStore = new DisposableStore(); private _ranges: [number, number, number][] = []; + private _rangesVersionId: number = 0; private _cts: CancellationTokenSource | undefined; private _lastScrollPosition: number = -1; + private readonly _updateSoon: RunOnceScheduler; constructor( editor: ICodeEditor, @ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService, ) { + super(); this._editor = editor; this._languageFeaturesService = _languageFeaturesService; this.stickyScrollWidget = new StickyScrollWidget(this._editor); - this._store.add(this._editor.onDidChangeConfiguration(e => { + this._register(this._editor.onDidChangeConfiguration(e => { if (e.hasChanged(EditorOption.stickyScroll)) { this.onConfigurationChange(); } })); + this._updateSoon = this._register(new RunOnceScheduler(() => this._update(true), 50)); this.onConfigurationChange(); } @@ -63,7 +66,7 @@ class StickyScrollController implements IEditorContribution { this._editor.addOverlayWidget(this.stickyScrollWidget); this._sessionStore.add(this._editor.onDidChangeModel(() => this._update(true))); this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false))); - this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._update(true))); + this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._updateSoon.schedule())); this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true))); this._update(true); } @@ -119,11 +122,13 @@ class StickyScrollController implements IEditorContribution { private async _updateOutlineModel(token: CancellationToken) { if (this._editor.hasModel()) { const model = this._editor.getModel(); + const modelVersionId = model.getVersionId(); const outlineModel = await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, token); if (token.isCancellationRequested) { return; } this._ranges = []; + this._rangesVersionId = modelVersionId; for (const outline of outlineModel.children.values()) { if (outline instanceof OutlineElement) { const kind: SymbolKind = outline.symbol.kind; @@ -154,15 +159,17 @@ class StickyScrollController implements IEditorContribution { } } } - private _renderStickyScroll() { + private _renderStickyScroll() { if (!(this._editor.hasModel())) { return; } - const lineHeight: number = this._editor.getOption(EditorOption.lineHeight); const model = this._editor.getModel(); - + if (this._rangesVersionId !== model.getVersionId()) { + // Old _ranges not updated yet + return; + } const scrollTop = this._editor.getScrollTop(); let scrollDirection: ScrollDirection; if (this._lastScrollPosition < scrollTop) { @@ -183,37 +190,36 @@ class StickyScrollController implements IEditorContribution { for (const [index, arr] of this._ranges.entries()) { const [start, end, depth] = arr; - topOfElementAtDepth = this._editor.getScrollTop() + (depth - 1) * lineHeight; - bottomOfElementAtDepth = this._editor.getScrollTop() + depth * lineHeight; - bottomOfBeginningLine = start * lineHeight; - topOfEndLine = (end - 1) * lineHeight; - bottomOfEndLine = end * lineHeight; - - if (!beginningLinesConsidered.has(start)) { - if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { - beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + bottomOfEndLine - bottomOfElementAtDepth)); - break; - } - else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { - beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); - - } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || - scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { - beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + if (end - start > 0 && model.getLineContent(start) !== '') { + topOfElementAtDepth = this._editor.getScrollTop() + (depth - 1) * lineHeight; + bottomOfElementAtDepth = this._editor.getScrollTop() + depth * lineHeight; + bottomOfBeginningLine = start * lineHeight; + topOfEndLine = (end - 1) * lineHeight; + bottomOfEndLine = end * lineHeight; + if (!beginningLinesConsidered.has(start)) { + if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); + break; + } + else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); + } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || + scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); + } + } else { + this._ranges.splice(index, 1); } - } else { - this._ranges.splice(index, 1); } } - this.stickyScrollWidget.updateRootNode(); } - dispose(): void { - this._store.dispose(); + override dispose(): void { + super.dispose(); this._sessionStore.dispose(); } } @@ -221,27 +227,31 @@ class StickyScrollController implements IEditorContribution { const _ttPolicy = window.trustedTypes?.createPolicy('stickyScrollViewLayer', { createHTML: value => value }); class StickyScrollCodeLine { - constructor(private readonly _line: string, private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, - private readonly _zIndex: number, private readonly _position?: number) { } + public readonly effectiveLineHeight: number = 0; + + constructor(private readonly _line: string, private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, + private readonly _zIndex: number, private readonly _relativePosition: number) { + this.effectiveLineHeight = this._editor.getOption(EditorOption.lineHeight) + this._relativePosition; + } getDomNode() { const root: HTMLElement = document.createElement('div'); - const modifiedLine = this._line.replace(/\s/g, '\xa0'); const lineRenderingData = this._editor._getViewModel().getViewLineRenderingData(this._editor.getVisibleRangesPlusViewportAboveBelow()[0], this._lineNumber); + let actualInlineDecorations: LineDecoration[]; try { actualInlineDecorations = LineDecoration.filter(lineRenderingData.inlineDecorations, this._lineNumber, lineRenderingData.minColumn, lineRenderingData.maxColumn); } catch (err) { - console.log(err); actualInlineDecorations = []; } - const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData.continuesWithWrappedLine, + + const renderLineInput: RenderLineInput = new RenderLineInput(true, true, this._line, lineRenderingData.continuesWithWrappedLine, lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, actualInlineDecorations, lineRenderingData.tabSize, lineRenderingData.startVisibleColumn, 1, 1, 1, 100, 'none', true, true, null); - const sb = createStringBuilder(2000); + const sb = createStringBuilder(400); renderViewLine(renderLineInput, sb); let newLine; @@ -251,41 +261,51 @@ class StickyScrollCodeLine { newLine = sb.build(); } - const lineHTMLNode = document.createElement('div'); - lineHTMLNode.style.paddingLeft = this._editor.getLayoutInfo().contentLeft - this._editor.getLayoutInfo().lineNumbersLeft - this._editor.getLayoutInfo().lineNumbersWidth + 'px'; - lineHTMLNode.style.float = 'left'; - lineHTMLNode.style.width = this._editor.getLayoutInfo().width - this._editor.getLayoutInfo().contentLeft + 'px'; + const lineHTMLNode = document.createElement('span'); lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; + lineHTMLNode.style.overflow = 'hidden'; + lineHTMLNode.style.whiteSpace = 'nowrap'; + lineHTMLNode.style.display = 'inline-block'; + lineHTMLNode.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; lineHTMLNode.innerHTML = newLine as string; - const lineNumberHTMLNode = document.createElement('div'); + const lineNumberHTMLNode = document.createElement('span'); lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)'; + lineNumberHTMLNode.style.display = 'inline-block'; + lineNumberHTMLNode.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; - const innerLineNumberHTML = document.createElement('div'); + const innerLineNumberHTML = document.createElement('span'); innerLineNumberHTML.innerText = this._lineNumber.toString(); innerLineNumberHTML.style.paddingLeft = this._editor.getLayoutInfo().lineNumbersLeft.toString() + 'px'; innerLineNumberHTML.style.width = this._editor.getLayoutInfo().lineNumbersWidth.toString() + 'px'; innerLineNumberHTML.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; innerLineNumberHTML.style.textAlign = 'right'; innerLineNumberHTML.style.float = 'left'; + innerLineNumberHTML.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; lineNumberHTMLNode.appendChild(innerLineNumberHTML); - lineHTMLNode.onclick = e => { + root.onclick = e => { e.stopPropagation(); e.preventDefault(); this._editor.revealLine(this._lineNumber); }; - lineHTMLNode.onmouseover = e => { + root.onmouseover = e => { innerLineNumberHTML.style.background = `var(--vscode-editorStickyScrollHover-background)`; lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`; + lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`; + root.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`; innerLineNumberHTML.style.cursor = `pointer`; lineHTMLNode.style.cursor = `pointer`; + root.style.cursor = `pointer`; + lineNumberHTMLNode.style.cursor = `pointer`; }; - lineHTMLNode.onmouseleave = e => { + root.onmouseleave = e => { innerLineNumberHTML.style.background = `var(--vscode-editorStickyScroll-background)`; lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; + lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; + root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; }; this._editor.applyFontInfo(lineHTMLNode); @@ -296,11 +316,16 @@ class StickyScrollCodeLine { root.style.zIndex = this._zIndex.toString(); root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; + root.style.overflow = 'hidden'; + root.style.whiteSpace = 'nowrap'; + root.style.width = '100%'; + root.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; + root.style.height = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; // Special case for last line of sticky scroll - if (this._position) { - root.style.position = 'absolute'; - root.style.top = this._position + 'px'; + if (this._relativePosition) { + root.style.position = 'relative'; + root.style.top = this._relativePosition + 'px'; root.style.width = '100%'; } return root; @@ -315,6 +340,7 @@ class StickyScrollWidget implements IOverlayWidget { constructor(public readonly _editor: ICodeEditor) { this.rootDomNode = document.createElement('div'); this.rootDomNode.style.width = '100%'; + this.rootDomNode.style.boxShadow = `var(--vscode-scrollbar-shadow) 0 6px 6px -6px`; // '0px 0px 8px 2px #000000'; } get codeLineCount() { @@ -326,9 +352,12 @@ class StickyScrollWidget implements IOverlayWidget { } updateRootNode() { + let widgetHeight: number = 0; for (const line of this.arrayOfCodeLines) { + widgetHeight += line.effectiveLineHeight; this.rootDomNode.appendChild(line.getDomNode()); } + this.rootDomNode.style.height = widgetHeight.toString() + 'px'; } emptyRootNode() { diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 129959b9e23..c1f226c3601 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -315,8 +315,8 @@ export const editorForeground = registerColor('editor.foreground', { light: '#33 /** * Sticky scroll */ -export const editorStickyScrollBackground = registerColor('editorStickyScroll.background', { light: darken(editorBackground, 0.2), dark: lighten(editorBackground, 0.2), hcDark: lighten(editorBackground, 0.2), hcLight: darken(editorBackground, 0.2) }, nls.localize('editorStickyScrollBackground', "Sticky scroll background color for the editor")); -export const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background', { light: darken(editorBackground, 0.4), dark: lighten(editorBackground, 0.4), hcDark: lighten(editorBackground, 0.4), hcLight: darken(editorBackground, 0.4) }, nls.localize('editorStickyScrollHoverBackground', "Sticky scroll on hover background color for the editor")); +export const editorStickyScrollBackground = registerColor('editorStickyScroll.background', { light: editorBackground, dark: editorBackground, hcDark: editorBackground, hcLight: editorBackground }, nls.localize('editorStickyScrollBackground', "Sticky scroll background color for the editor")); +export const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background', { dark: '#2A2D2E', light: '#F0F0F0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) }, nls.localize('editorStickyScrollHoverBackground', "Sticky scroll on hover background color for the editor")); /** * Editor widgets |