Work in progress

This commit is contained in:
aiday-mar 2022-08-16 10:47:03 +02:00
parent 22c1836f97
commit 930de5510d
4 changed files with 346 additions and 119 deletions

View file

@ -16,21 +16,23 @@ import { IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';
export class StickyScrollController extends Disposable implements IEditorContribution {
static readonly ID = 'store.contrib.stickyScrollController';
private readonly editor: ICodeEditor;
private readonly stickyScrollWidget: StickyScrollWidget;
private readonly stickyLineCandidateProvider: StickyLineCandidateProvider;
private readonly sessionStore: DisposableStore = new DisposableStore();
private readonly _editor: ICodeEditor;
private readonly _stickyScrollWidget: StickyScrollWidget;
private readonly _stickyLineCandidateProvider: StickyLineCandidateProvider;
private readonly _sessionStore: DisposableStore = new DisposableStore();
private _widgetState: StickyScrollWidgetState;
constructor(
editor: ICodeEditor,
@ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService,
@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,
) {
super();
this.editor = editor;
this.stickyScrollWidget = new StickyScrollWidget(this.editor);
this.stickyLineCandidateProvider = new StickyLineCandidateProvider(this.editor, _languageFeaturesService);
this._editor = editor;
this._stickyScrollWidget = new StickyScrollWidget(this._editor);
this._stickyLineCandidateProvider = new StickyLineCandidateProvider(this._editor, languageFeaturesService);
this._widgetState = new StickyScrollWidgetState([], 0);
this._register(this.editor.onDidChangeConfiguration(e => {
this._register(this._editor.onDidChangeConfiguration(e => {
if (e.hasChanged(EditorOption.experimental)) {
this.readConfiguration();
}
@ -38,27 +40,35 @@ export class StickyScrollController extends Disposable implements IEditorContrib
this.readConfiguration();
}
public get stickyScrollCandidateProvider() {
return this._stickyLineCandidateProvider;
}
public get stickyScrollWidgetState() {
return this._widgetState;
}
private readConfiguration() {
const options = this.editor.getOption(EditorOption.experimental);
const options = this._editor.getOption(EditorOption.experimental);
if (options.stickyScroll.enabled === false) {
this.editor.removeOverlayWidget(this.stickyScrollWidget);
this.sessionStore.clear();
this._editor.removeOverlayWidget(this._stickyScrollWidget);
this._sessionStore.clear();
return;
} else {
this.editor.addOverlayWidget(this.stickyScrollWidget);
this.sessionStore.add(this.editor.onDidScrollChange(() => this.renderStickyScroll()));
this.sessionStore.add(this.editor.onDidLayoutChange(() => this.onDidResize()));
this.sessionStore.add(this.editor.onDidChangeModelTokens((e) => this.onTokensChange(e)));
this.sessionStore.add(this.stickyLineCandidateProvider.onStickyScrollChange(() => this.renderStickyScroll()));
const lineNumberOption = this.editor.getOption(EditorOption.lineNumbers);
this._editor.addOverlayWidget(this._stickyScrollWidget);
this._sessionStore.add(this._editor.onDidScrollChange(() => this.renderStickyScroll()));
this._sessionStore.add(this._editor.onDidLayoutChange(() => this.onDidResize()));
this._sessionStore.add(this._editor.onDidChangeModelTokens((e) => this.onTokensChange(e)));
this._sessionStore.add(this._stickyLineCandidateProvider.onStickyScrollChange(() => this.renderStickyScroll()));
const lineNumberOption = this._editor.getOption(EditorOption.lineNumbers);
if (lineNumberOption.renderType === RenderLineNumbersType.Relative) {
this.sessionStore.add(this.editor.onDidChangeCursorPosition(() => this.renderStickyScroll()));
this._sessionStore.add(this._editor.onDidChangeCursorPosition(() => this.renderStickyScroll()));
}
}
}
private needsUpdate(event: IModelTokensChangedEvent) {
const stickyLineNumbers = this.stickyScrollWidget.getCurrentLines();
const stickyLineNumbers = this._stickyScrollWidget.getCurrentLines();
for (const stickyLineNumber of stickyLineNumbers) {
for (const range of event.ranges) {
if (stickyLineNumber >= range.fromLineNumber && stickyLineNumber <= range.toLineNumber) {
@ -76,31 +86,32 @@ export class StickyScrollController extends Disposable implements IEditorContrib
}
private onDidResize() {
const width = this.editor.getLayoutInfo().width - this.editor.getLayoutInfo().minimap.minimapCanvasOuterWidth - this.editor.getLayoutInfo().verticalScrollbarWidth;
this.stickyScrollWidget.getDomNode().style.width = `${width}px`;
const width = this._editor.getLayoutInfo().width - this._editor.getLayoutInfo().minimap.minimapCanvasOuterWidth - this._editor.getLayoutInfo().verticalScrollbarWidth;
this._stickyScrollWidget.getDomNode().style.width = `${width}px`;
}
private renderStickyScroll() {
if (!(this.editor.hasModel())) {
if (!(this._editor.hasModel())) {
return;
}
const model = this.editor.getModel();
if (this.stickyLineCandidateProvider.getVersionId() !== model.getVersionId()) {
const model = this._editor.getModel();
if (this._stickyLineCandidateProvider.getVersionId() !== model.getVersionId()) {
// Old _ranges not updated yet
return;
}
this.stickyScrollWidget.setState(this.getScrollWidgetState());
this._widgetState = this.getScrollWidgetState();
this._stickyScrollWidget.setState(this._widgetState);
}
private getScrollWidgetState(): StickyScrollWidgetState {
const lineHeight: number = this.editor.getOption(EditorOption.lineHeight);
const scrollTop: number = this.editor.getScrollTop();
public getScrollWidgetState(): StickyScrollWidgetState {
const lineHeight: number = this._editor.getOption(EditorOption.lineHeight);
const scrollTop: number = this._editor.getScrollTop();
let lastLineRelativePosition: number = 0;
const lineNumbers: number[] = [];
const arrayVisibleRanges = this.editor.getVisibleRanges();
const arrayVisibleRanges = this._editor.getVisibleRanges();
if (arrayVisibleRanges.length !== 0) {
const fullVisibleRange = new StickyRange(arrayVisibleRanges[0].startLineNumber, arrayVisibleRanges[arrayVisibleRanges.length - 1].endLineNumber);
const candidateRanges = this.stickyLineCandidateProvider.getCandidateStickyLinesIntersecting(fullVisibleRange);
const candidateRanges = this._stickyLineCandidateProvider.getCandidateStickyLinesIntersecting(fullVisibleRange);
for (const range of candidateRanges) {
const start = range.startLineNumber;
const end = range.endLineNumber;
@ -109,9 +120,9 @@ export class StickyScrollController extends Disposable implements IEditorContrib
const topOfElementAtDepth = (depth - 1) * lineHeight;
const bottomOfElementAtDepth = depth * lineHeight;
const bottomOfBeginningLine = this.editor.getBottomForLineNumber(start) - scrollTop;
const topOfEndLine = this.editor.getTopForLineNumber(end) - scrollTop;
const bottomOfEndLine = this.editor.getBottomForLineNumber(end) - scrollTop;
const bottomOfBeginningLine = this._editor.getBottomForLineNumber(start) - scrollTop;
const topOfEndLine = this._editor.getTopForLineNumber(end) - scrollTop;
const bottomOfEndLine = this._editor.getBottomForLineNumber(end) - scrollTop;
if (topOfElementAtDepth > topOfEndLine && topOfElementAtDepth <= bottomOfEndLine) {
lineNumbers.push(start);
@ -129,7 +140,7 @@ export class StickyScrollController extends Disposable implements IEditorContrib
override dispose(): void {
super.dispose();
this.sessionStore.dispose();
this._sessionStore.dispose();
}
}

View file

@ -33,24 +33,24 @@ export class StickyLineCandidateProvider extends Disposable {
public readonly onStickyScrollChange = this.onStickyScrollChangeEmitter.event;
static readonly ID = 'store.contrib.stickyScrollController';
private readonly editor: ICodeEditor;
private readonly languageFeaturesService: ILanguageFeaturesService;
private readonly updateSoon: RunOnceScheduler;
private readonly _editor: ICodeEditor;
private readonly _languageFeaturesService: ILanguageFeaturesService;
private readonly _updateSoon: RunOnceScheduler;
private cts: CancellationTokenSource | undefined;
private outlineModel: StickyOutlineElement | undefined;
private readonly sessionStore: DisposableStore = new DisposableStore();
private modelVersionId: number = 0;
private _cts: CancellationTokenSource | undefined;
private _outlineModel: StickyOutlineElement | undefined;
private readonly _sessionStore: DisposableStore = new DisposableStore();
private _modelVersionId: number = 0;
constructor(
editor: ICodeEditor,
@ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService,
@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,
) {
super();
this.editor = editor;
this.languageFeaturesService = _languageFeaturesService;
this.updateSoon = this._register(new RunOnceScheduler(() => this.update(), 50));
this._register(this.editor.onDidChangeConfiguration(e => {
this._editor = editor;
this._languageFeaturesService = languageFeaturesService;
this._updateSoon = this._register(new RunOnceScheduler(() => this.update(), 50));
this._register(this._editor.onDidChangeConfiguration(e => {
if (e.hasChanged(EditorOption.experimental)) {
this.readConfiguration();
}
@ -59,40 +59,40 @@ export class StickyLineCandidateProvider extends Disposable {
}
private readConfiguration() {
const options = this.editor.getOption(EditorOption.experimental);
const options = this._editor.getOption(EditorOption.experimental);
if (options.stickyScroll.enabled === false) {
this.sessionStore.clear();
this._sessionStore.clear();
return;
} else {
this.sessionStore.add(this.editor.onDidChangeModel(() => this.update()));
this.sessionStore.add(this.editor.onDidChangeHiddenAreas(() => this.update()));
this.sessionStore.add(this.editor.onDidChangeModelContent(() => this.updateSoon.schedule()));
this.sessionStore.add(this.languageFeaturesService.documentSymbolProvider.onDidChange(() => this.update()));
this._sessionStore.add(this._editor.onDidChangeModel(() => this.update()));
this._sessionStore.add(this._editor.onDidChangeHiddenAreas(() => this.update()));
this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._updateSoon.schedule()));
this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this.update()));
this.update();
}
}
public getVersionId() {
return this.modelVersionId;
return this._modelVersionId;
}
private async update(): Promise<void> {
this.cts?.dispose(true);
this.cts = new CancellationTokenSource();
await this.updateOutlineModel(this.cts.token);
public async update(): Promise<void> {
this._cts?.dispose(true);
this._cts = new CancellationTokenSource();
await this.updateOutlineModel(this._cts.token);
this.onStickyScrollChangeEmitter.fire();
}
private async updateOutlineModel(token: CancellationToken) {
if (this.editor.hasModel()) {
const model = this.editor.getModel();
if (this._editor.hasModel()) {
const model = this._editor.getModel();
const modelVersionId = model.getVersionId();
const outlineModel = await OutlineModel.create(this.languageFeaturesService.documentSymbolProvider, model, token) as OutlineModel;
const outlineModel = await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, token) as OutlineModel;
if (token.isCancellationRequested) {
return;
}
this.outlineModel = StickyOutlineElement.fromOutlineModel(outlineModel);
this.modelVersionId = modelVersionId;
this._outlineModel = StickyOutlineElement.fromOutlineModel(outlineModel);
this._modelVersionId = modelVersionId;
}
}
@ -115,8 +115,8 @@ export class StickyLineCandidateProvider extends Disposable {
public getCandidateStickyLinesIntersecting(range: StickyRange): StickyLineCandidate[] {
let stickyLineCandidates: StickyLineCandidate[] = [];
this.getCandidateStickyLinesIntersectingFromOutline(range, this.outlineModel as StickyOutlineElement, stickyLineCandidates, 0, -1);
const hiddenRanges: Range[] | undefined = this.editor._getViewModel()?.getHiddenAreas();
this.getCandidateStickyLinesIntersectingFromOutline(range, this._outlineModel as StickyOutlineElement, stickyLineCandidates, 0, -1);
const hiddenRanges: Range[] | undefined = this._editor._getViewModel()?.getHiddenAreas();
if (hiddenRanges) {
for (const hiddenRange of hiddenRanges) {
stickyLineCandidates = stickyLineCandidates.filter(stickyLine => !(stickyLine.startLineNumber >= hiddenRange.startLineNumber && stickyLine.endLineNumber <= hiddenRange.endLineNumber + 1));
@ -127,7 +127,7 @@ export class StickyLineCandidateProvider extends Disposable {
override dispose(): void {
super.dispose();
this.sessionStore.dispose();
this._sessionStore.dispose();
}
}

View file

@ -23,61 +23,65 @@ const _ttPolicy = window.trustedTypes?.createPolicy('stickyScrollViewLayer', { c
export class StickyScrollWidget extends Disposable implements IOverlayWidget {
private readonly layoutInfo: EditorLayoutInfo;
private readonly rootDomNode: HTMLElement = document.createElement('div');
private readonly disposableStore = this._register(new DisposableStore());
private lineHeight: number;
private lineNumbers: number[];
private lastLineRelativePosition: number;
private readonly _layoutInfo: EditorLayoutInfo;
private readonly _rootDomNode: HTMLElement = document.createElement('div');
private readonly _disposableStore = this._register(new DisposableStore());
private _lineHeight: number;
private _lineNumbers: number[];
private _lastLineRelativePosition: number;
constructor(private readonly _editor: ICodeEditor) {
constructor(private readonly editor: ICodeEditor) {
super();
this.layoutInfo = this._editor.getLayoutInfo();
this.rootDomNode = document.createElement('div');
this.rootDomNode.className = 'sticky-widget';
this.rootDomNode.style.width = `${this.layoutInfo.width - this.layoutInfo.minimap.minimapCanvasOuterWidth - this.layoutInfo.verticalScrollbarWidth}px`;
this._layoutInfo = this.editor.getLayoutInfo();
this._rootDomNode = document.createElement('div');
this._rootDomNode.className = 'sticky-widget';
this._rootDomNode.style.width = `${this._layoutInfo.width - this._layoutInfo.minimap.minimapCanvasOuterWidth - this._layoutInfo.verticalScrollbarWidth}px`;
this.lineNumbers = [];
this.lastLineRelativePosition = 0;
this._lineNumbers = [];
this._lastLineRelativePosition = 0;
this.lineHeight = this._editor.getOption(EditorOption.lineHeight);
this._register(this._editor.onDidChangeConfiguration(e => {
this._lineHeight = this.editor.getOption(EditorOption.lineHeight);
this._register(this.editor.onDidChangeConfiguration(e => {
if (e.hasChanged(EditorOption.lineHeight)) {
this.lineHeight = this._editor.getOption(EditorOption.lineHeight);
this._lineHeight = this.editor.getOption(EditorOption.lineHeight);
}
}));
}
public get lineNumbers(): number[] {
return this._lineNumbers;
}
public get codeLineCount(): number {
return this.lineNumbers.length;
return this._lineNumbers.length;
}
public getCurrentLines(): readonly number[] {
return this.lineNumbers;
return this._lineNumbers;
}
public setState(state: StickyScrollWidgetState): void {
this.disposableStore.clear();
this.lineNumbers.length = 0;
dom.clearNode(this.rootDomNode);
this._disposableStore.clear();
this._lineNumbers.length = 0;
dom.clearNode(this._rootDomNode);
this.lastLineRelativePosition = state.lastLineRelativePosition;
this.lineNumbers = state.lineNumbers;
this._lastLineRelativePosition = state.lastLineRelativePosition;
this._lineNumbers = state.lineNumbers;
this.renderRootNode();
}
private getChildNode(index: number, line: number): HTMLElement {
const child = document.createElement('div');
const viewModel = this._editor._getViewModel();
const viewModel = this.editor._getViewModel();
const viewLineNumber = viewModel!.coordinatesConverter.convertModelPositionToViewPosition(new Position(line, 1)).lineNumber;
const lineRenderingData = viewModel!.getViewLineRenderingData(viewLineNumber);
const layoutInfo = this._editor.getLayoutInfo();
const layoutInfo = this.editor.getLayoutInfo();
const width = layoutInfo.width - layoutInfo.minimap.minimapCanvasOuterWidth - layoutInfo.verticalScrollbarWidth;
const minimapSide = this._editor.getOption(EditorOption.minimap).side;
const lineHeight = this._editor.getOption(EditorOption.lineHeight);
const lineNumberOption = this._editor.getOption(EditorOption.lineNumbers);
const minimapSide = this.editor.getOption(EditorOption.minimap).side;
const lineHeight = this.editor.getOption(EditorOption.lineHeight);
const lineNumberOption = this.editor.getOption(EditorOption.lineNumbers);
let actualInlineDecorations: LineDecoration[];
try {
@ -122,7 +126,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
if (lineNumberOption.renderType === RenderLineNumbersType.On || lineNumberOption.renderType === RenderLineNumbersType.Interval && line % 10 === 0) {
innerLineNumberHTML.innerText = line.toString();
} else if (lineNumberOption.renderType === RenderLineNumbersType.Relative) {
innerLineNumberHTML.innerText = Math.abs(line - this._editor.getPosition()!.lineNumber).toString();
innerLineNumberHTML.innerText = Math.abs(line - this.editor.getPosition()!.lineNumber).toString();
}
innerLineNumberHTML.className = 'sticky-line-number';
innerLineNumberHTML.style.lineHeight = `${lineHeight}px`;
@ -134,8 +138,8 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
}
lineNumberHTMLNode.appendChild(innerLineNumberHTML);
this._editor.applyFontInfo(lineHTMLNode);
this._editor.applyFontInfo(innerLineNumberHTML);
this.editor.applyFontInfo(lineHTMLNode);
this.editor.applyFontInfo(innerLineNumberHTML);
child.appendChild(lineNumberHTMLNode);
child.appendChild(lineHTMLNode);
@ -147,15 +151,15 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
child.style.zIndex = '0';
// Special case for the last line of sticky scroll
if (index === this.lineNumbers.length - 1) {
if (index === this._lineNumbers.length - 1) {
child.style.position = 'relative';
child.style.zIndex = '-1';
child.style.top = this.lastLineRelativePosition + 'px';
child.style.top = this._lastLineRelativePosition + 'px';
}
this.disposableStore.add(dom.addDisposableListener(child, 'click', e => {
this._disposableStore.add(dom.addDisposableListener(child, 'click', e => {
e.stopPropagation();
e.preventDefault();
this._editor.revealPosition({ lineNumber: line - index, column: 1 });
this.editor.revealPosition({ lineNumber: line - index, column: 1 });
}));
return child;
@ -163,20 +167,20 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
private renderRootNode(): void {
if (!this._editor._getViewModel()) {
if (!this.editor._getViewModel()) {
return;
}
for (const [index, line] of this.lineNumbers.entries()) {
this.rootDomNode.appendChild(this.getChildNode(index, line));
for (const [index, line] of this._lineNumbers.entries()) {
this._rootDomNode.appendChild(this.getChildNode(index, line));
}
const widgetHeight: number = this.lineNumbers.length * this.lineHeight + this.lastLineRelativePosition;
this.rootDomNode.style.height = widgetHeight.toString() + 'px';
const minimapSide = this._editor.getOption(EditorOption.minimap).side;
const widgetHeight: number = this._lineNumbers.length * this._lineHeight + this._lastLineRelativePosition;
this._rootDomNode.style.height = widgetHeight.toString() + 'px';
const minimapSide = this.editor.getOption(EditorOption.minimap).side;
if (minimapSide === 'left') {
this.rootDomNode.style.marginLeft = this._editor.getLayoutInfo().minimap.minimapCanvasOuterWidth + 'px';
this._rootDomNode.style.marginLeft = this.editor.getLayoutInfo().minimap.minimapCanvasOuterWidth + 'px';
} else if (minimapSide === 'right') {
this.rootDomNode.style.marginLeft = '0px';
this._rootDomNode.style.marginLeft = '0px';
}
}
@ -185,7 +189,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
}
public getDomNode(): HTMLElement {
return this.rootDomNode;
return this._rootDomNode;
}
public getPosition(): IOverlayWidgetPosition | null {
@ -196,6 +200,6 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
override dispose(): void {
super.dispose();
this.disposableStore.dispose();
this._disposableStore.dispose();
}
}

View file

@ -3,21 +3,233 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ITestCodeEditor, withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
import { withAsyncTestCodeEditor, withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
import { StickyScrollController } from 'vs/editor/contrib/stickyScroll/browser/stickyScroll';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { createTextModel } from 'vs/editor/test/common/testTextModel';
import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService';
import { DocumentSymbol, SymbolKind } from 'vs/editor/common/languages';
import { CoreEditingCommands, CoreNavigationCommands } from 'vs/editor/browser/coreCommands';
import { StickyLineCandidate, StickyLineCandidateProvider } from 'vs/editor/contrib/stickyScroll/browser/stickyScrollProvider';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
// To run this test file : ./test.bat --glob **/stickyScroll.test.js in the scripts folder
suite('Sticky Scroll Tests', () => {
test('issue #8817: Cursor position changes when you cancel multicursor', () => {
withTestCodeEditor([
'var x = (3 * 5)',
'var y = (3 * 5)',
'var z = (3 * 5)',
], {}, (editor) => {
const serviceCollection = new ServiceCollection(
[ILanguageFeaturesService, new LanguageFeaturesService()]
);
const stickyScrollController = editor.registerAndInstantiateContribution(StickyScrollController.ID, StickyScrollController);
const model = createTextModel([
'function foo() {',
'',
'}',
'/* comment related to TestClass',
' end of the comment */',
'@classDecorator',
'class TestClass {',
'// comment related to the function functionOfClass',
'functionOfClass(){',
'function function1(){',
'}',
'}}',
'function bar() { function insideBar() {}',
'}'
].join('\n'));
function documentSymbolProviderForTestModel() {
return {
provideDocumentSymbols() {
return [
{
name: 'foo',
detail: 'foo',
kind: SymbolKind.Function,
tags: [],
range: { startLineNumber: 1, endLineNumber: 3, startColumn: 1, endColumn: 1 },
selectionRange: { startLineNumber: 1, endLineNumber: 1, startColumn: 1, endColumn: 1 }
} as DocumentSymbol,
{
name: 'TestClass',
detail: 'TestClass',
kind: SymbolKind.Class,
tags: [],
range: { startLineNumber: 4, endLineNumber: 12, startColumn: 1, endColumn: 1 },
selectionRange: { startLineNumber: 7, endLineNumber: 7, startColumn: 1, endColumn: 1 },
children: [
{
name: 'functionOfClass',
detail: 'functionOfClass',
kind: SymbolKind.Function,
tags: [],
range: { startLineNumber: 8, endLineNumber: 12, startColumn: 1, endColumn: 1 },
selectionRange: { startLineNumber: 9, endLineNumber: 9, startColumn: 1, endColumn: 1 },
children: [
{
name: 'function1',
detail: 'function1',
kind: SymbolKind.Function,
tags: [],
range: { startLineNumber: 10, endLineNumber: 11, startColumn: 1, endColumn: 1 },
selectionRange: { startLineNumber: 10, endLineNumber: 10, startColumn: 1, endColumn: 1 },
}
]
} as DocumentSymbol
]
} as DocumentSymbol,
{
name: 'bar',
detail: 'bar',
kind: SymbolKind.Function,
tags: [],
range: { startLineNumber: 13, endLineNumber: 14, startColumn: 1, endColumn: 1 },
selectionRange: { startLineNumber: 13, endLineNumber: 13, startColumn: 1, endColumn: 1 },
children: [
{
name: 'insideBar',
detail: 'insideBar',
kind: SymbolKind.Function,
tags: [],
range: { startLineNumber: 13, endLineNumber: 13, startColumn: 1, endColumn: 1 },
selectionRange: { startLineNumber: 13, endLineNumber: 13, startColumn: 1, endColumn: 1 },
} as DocumentSymbol
]
} as DocumentSymbol
];
}
};
}
test('Testing the function getCandidateStickyLinesIntersecting', async () => {
await withAsyncTestCodeEditor(model, { serviceCollection }, async (editor, _viewModel, instantiationService) => {
const languageService = instantiationService.get(ILanguageFeaturesService);
languageService.documentSymbolProvider.register('*', documentSymbolProviderForTestModel());
const provider: StickyLineCandidateProvider = new StickyLineCandidateProvider(editor, languageService);
/*
provider.onStickyScrollChange(() => {
console.log('resolve');
});
*/
// TODO: The below times out doesn't return after 5000 ms
/*
await new Promise<void>(resolve => {
const disposable = provider.onStickyScrollChange(() => {
console.log('resolve');
resolve();
});
disposable.dispose();
});
*/
// console.log('before update of provider');
await provider.update();
assert.deepStrictEqual(provider.getCandidateStickyLinesIntersecting({ startLineNumber: 1, endLineNumber: 4 }), [new StickyLineCandidate(1, 2, 1)]);
assert.deepStrictEqual(provider.getCandidateStickyLinesIntersecting({ startLineNumber: 1, endLineNumber: 10 }), [new StickyLineCandidate(1, 2, 1), new StickyLineCandidate(7, 11, 1), new StickyLineCandidate(9, 11, 2), new StickyLineCandidate(10, 10, 3)]);
assert.deepStrictEqual(provider.getCandidateStickyLinesIntersecting({ startLineNumber: 1, endLineNumber: 13 }), [new StickyLineCandidate(1, 2, 1), new StickyLineCandidate(7, 11, 1), new StickyLineCandidate(9, 11, 2), new StickyLineCandidate(10, 10, 3), new StickyLineCandidate(13, 13, 1)]);
provider.dispose();
});
});
test('issue #157180: Render the correct line corresponding to the scope definition', async () => {
await withAsyncTestCodeEditor(model, { serviceCollection }, async (editor, _viewModel, instantiationService) => {
const stickyScrollController: StickyScrollController = editor.registerAndInstantiateContribution(StickyScrollController.ID, StickyScrollController);
await stickyScrollController.stickyScrollCandidateProvider.update();
const lineHeight: number = editor.getOption(EditorOption.lineHeight);
const languageService: ILanguageFeaturesService = instantiationService.get(ILanguageFeaturesService);
languageService.documentSymbolProvider.register('*', documentSymbolProviderForTestModel());
let state;
editor.setScrollTop(lineHeight + 1);
state = stickyScrollController.getScrollWidgetState();
assert.deepStrictEqual(state.lineNumbers, [1]);
editor.setScrollTop(4 * lineHeight + 1);
state = stickyScrollController.getScrollWidgetState();
assert.deepStrictEqual(state.lineNumbers, []);
editor.setScrollTop(8 * lineHeight + 1);
state = stickyScrollController.getScrollWidgetState();
assert.deepStrictEqual(state.lineNumbers, [7, 9]);
editor.setScrollTop(9 * lineHeight + 1);
state = stickyScrollController.getScrollWidgetState();
assert.deepStrictEqual(state.lineNumbers, [7, 9]);
editor.setScrollTop(10 * lineHeight + 1);
state = stickyScrollController.getScrollWidgetState();
assert.deepStrictEqual(state.lineNumbers, [7]);
stickyScrollController.dispose();
});
});
test('issue #157809: Reveal the correct range taking into account the widget height', async () => {
await withAsyncTestCodeEditor(model, { serviceCollection }, async (editor, viewModel, instantiationService) => {
const stickyScrollController = editor.registerAndInstantiateContribution(StickyScrollController.ID, StickyScrollController);
await stickyScrollController.stickyScrollCandidateProvider.update();
const lineHeight = editor.getOption(EditorOption.lineHeight);
const languageService = instantiationService.get(ILanguageFeaturesService);
languageService.documentSymbolProvider.register('*', documentSymbolProviderForTestModel());
// editor.setPosition({ lineNumber: 5, column: 1 }, 'test');
editor.setScrollTop(11 * lineHeight);
/*
CoreNavigationCommands.CreateCursor.runCoreEditorCommand(viewModel, {
source: 'mouse',
position: new Position(2, 1),
viewPosition: new Position(2, 1),
wholeLine: true
});
*/
// CoreNavigationCommands.MoveTo.runCoreEditorCommand(viewModel, { position: new Position(2, 1) });
console.log('visible ranges : ', editor.getVisibleRanges()[0].startLineNumber);
console.log('scroll top : ', Math.floor(editor.getScrollTop() / lineHeight));
console.log('position : ', editor.getPosition().lineNumber);
/*
editor.trigger('keyboard', Handler.Type, { text: 'd' });
CoreNavigationCommands.RevealLine.runCoreEditorCommand(viewModel, { lineNumber: 5, source: undefined });
*/
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
console.log('visible ranges : ', editor.getVisibleRanges()[0].startLineNumber);
console.log('scroll top : ', Math.floor(editor.getScrollTop() / lineHeight));
console.log('position : ', editor.getPosition().lineNumber);
stickyScrollController.dispose();
});
});
test('issue #156268 : Do not reveal sticky lines when they are in a folded region ', async () => {
await withAsyncTestCodeEditor(model, { serviceCollection }, async (editor, viewModel, instantiationService) => {
const stickyScrollController = editor.registerAndInstantiateContribution(StickyScrollController.ID, StickyScrollController);
await stickyScrollController.stickyScrollCandidateProvider.update();
const lineHeight = editor.getOption(EditorOption.lineHeight);
const languageService = instantiationService.get(ILanguageFeaturesService);
languageService.documentSymbolProvider.register('*', documentSymbolProviderForTestModel());
stickyScrollController.dispose();
});
});
});