Skip to content

Commit 9332731

Browse files
author
Aiday Marlen Kyzy
authored
Merge pull request microsoft#159305 from microsoft/aiday/issue159136
Sticky Scroll : when several outline models are available, choose the one spanning the biggest total range
2 parents 3965d65 + d3a964d commit 9332731

File tree

3 files changed

+71
-19
lines changed

3 files changed

+71
-19
lines changed

src/vs/editor/contrib/documentSymbols/browser/outlineModel.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ export class OutlineModel extends TreeElement {
202202
const id = TreeElement.findId(`provider_${index}`, result);
203203
const group = new OutlineGroup(id, result, provider.displayName ?? 'Unknown Outline Provider', index);
204204

205+
205206
return Promise.resolve(provider.provideDocumentSymbols(textModel, cts.token)).then(result => {
206207
for (const info of result || []) {
207208
OutlineModel._makeOutlineElement(info, group);

src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
1313
import { Range } from 'vs/editor/common/core/range';
1414
import { Emitter } from 'vs/base/common/event';
1515
import { binarySearch } from 'vs/base/common/arrays';
16+
import { Iterable } from 'vs/base/common/iterator';
1617
import { FoldingController } from 'vs/editor/contrib/folding/browser/folding';
1718
import { FoldingModel } from 'vs/editor/contrib/folding/browser/foldingModel';
1819

@@ -44,6 +45,7 @@ export class StickyLineCandidateProvider extends Disposable {
4445
private _outlineModel: StickyOutlineElement | undefined;
4546
private readonly _sessionStore: DisposableStore = new DisposableStore();
4647
private _modelVersionId: number = 0;
48+
private _providerID: string | undefined = undefined;
4749

4850
constructor(
4951
editor: ICodeEditor,
@@ -67,10 +69,16 @@ export class StickyLineCandidateProvider extends Disposable {
6769
this._sessionStore.clear();
6870
return;
6971
} else {
70-
this._sessionStore.add(this._editor.onDidChangeModel(() => this.update()));
72+
this._sessionStore.add(this._editor.onDidChangeModel(() => {
73+
this._providerID = undefined;
74+
this.update();
75+
}));
7176
this._sessionStore.add(this._editor.onDidChangeHiddenAreas(() => this.update()));
7277
this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._updateSoon.schedule()));
73-
this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this.update()));
78+
this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => {
79+
this._providerID = undefined;
80+
this.update();
81+
}));
7482
this.update();
7583
}
7684
}
@@ -95,7 +103,9 @@ export class StickyLineCandidateProvider extends Disposable {
95103
return;
96104
}
97105
if (outlineModel.children.size !== 0) {
98-
this._outlineModel = StickyOutlineElement.fromOutlineModel(outlineModel, -1);
106+
const { stickyOutlineElement, providerID } = StickyOutlineElement.fromOutlineModel(outlineModel, this._providerID);
107+
this._outlineModel = stickyOutlineElement;
108+
this._providerID = providerID;
99109
} else {
100110
const foldingController = FoldingController.get(this._editor);
101111
const foldingModel = await foldingController?.getFoldingModel();
@@ -177,18 +187,16 @@ export class StickyLineCandidateProvider extends Disposable {
177187
}
178188

179189
class StickyOutlineElement {
180-
public static fromOutlineModel(outlineModel: OutlineModel | OutlineElement | OutlineGroup, previousStartLine: number): StickyOutlineElement {
181190

191+
public static fromOutlineElement(outlineElement: OutlineElement, previousStartLine: number): StickyOutlineElement {
182192
const children: StickyOutlineElement[] = [];
183-
for (const child of outlineModel.children.values()) {
184-
if (child instanceof OutlineGroup || child instanceof OutlineModel) {
185-
children.push(StickyOutlineElement.fromOutlineModel(child, previousStartLine));
186-
} else if (child instanceof OutlineElement && child.symbol.selectionRange.startLineNumber !== child.symbol.range.endLineNumber) {
193+
for (const child of outlineElement.children.values()) {
194+
if (child.symbol.selectionRange.startLineNumber !== child.symbol.range.endLineNumber) {
187195
if (child.symbol.selectionRange.startLineNumber !== previousStartLine) {
188-
children.push(StickyOutlineElement.fromOutlineModel(child, child.symbol.selectionRange.startLineNumber));
196+
children.push(StickyOutlineElement.fromOutlineElement(child, child.symbol.selectionRange.startLineNumber));
189197
} else {
190198
for (const subchild of child.children.values()) {
191-
children.push(StickyOutlineElement.fromOutlineModel(subchild, child.symbol.selectionRange.startLineNumber));
199+
children.push(StickyOutlineElement.fromOutlineElement(subchild, child.symbol.selectionRange.startLineNumber));
192200
}
193201
}
194202
}
@@ -202,17 +210,59 @@ class StickyOutlineElement {
202210
return child2.range.endLineNumber - child1.range.endLineNumber;
203211
}
204212
});
205-
let range: StickyRange | undefined;
206-
if (outlineModel instanceof OutlineElement) {
207-
range = new StickyRange(outlineModel.symbol.selectionRange.startLineNumber, outlineModel.symbol.range.endLineNumber);
213+
const range = new StickyRange(outlineElement.symbol.selectionRange.startLineNumber, outlineElement.symbol.range.endLineNumber);
214+
return new StickyOutlineElement(range, children, undefined);
215+
}
216+
217+
public static fromOutlineModel(outlineModel: OutlineModel, providerID: string | undefined): { stickyOutlineElement: StickyOutlineElement; providerID: string | undefined } {
218+
219+
let ID: string | undefined = providerID;
220+
let outlineElements: Map<string, OutlineElement>;
221+
// When several possible outline providers
222+
if (Iterable.first(outlineModel.children.values()) instanceof OutlineGroup) {
223+
const provider = Iterable.find(outlineModel.children.values(), outlineGroupOfModel => outlineGroupOfModel.id === providerID);
224+
if (provider) {
225+
outlineElements = provider.children;
226+
} else {
227+
let tempID = '';
228+
let maxTotalSumOfRanges = 0;
229+
let optimalOutlineGroup = undefined;
230+
for (const [_key, outlineGroup] of outlineModel.children.entries()) {
231+
const totalSumRanges = StickyOutlineElement.findSumOfRangesOfGroup(outlineGroup);
232+
if (totalSumRanges > maxTotalSumOfRanges) {
233+
optimalOutlineGroup = outlineGroup;
234+
maxTotalSumOfRanges = totalSumRanges;
235+
tempID = outlineGroup.id;
236+
}
237+
}
238+
ID = tempID;
239+
outlineElements = optimalOutlineGroup!.children;
240+
}
208241
} else {
209-
range = undefined;
242+
outlineElements = outlineModel.children as Map<string, OutlineElement>;
243+
}
244+
const stickyChildren: StickyOutlineElement[] = [];
245+
for (const outlineElement of outlineElements.values()) {
246+
stickyChildren.push(StickyOutlineElement.fromOutlineElement(outlineElement, outlineElement.symbol.selectionRange.startLineNumber));
247+
}
248+
const stickyOutlineElement = new StickyOutlineElement(undefined, stickyChildren, undefined);
249+
250+
return {
251+
stickyOutlineElement: stickyOutlineElement,
252+
providerID: ID
253+
};
254+
}
255+
256+
private static findSumOfRangesOfGroup(outline: OutlineGroup | OutlineElement): number {
257+
let res = 0;
258+
for (const child of outline.children.values()) {
259+
res += this.findSumOfRangesOfGroup(child);
260+
}
261+
if (outline instanceof OutlineElement) {
262+
return res + outline.symbol.range.endLineNumber - outline.symbol.selectionRange.startLineNumber;
263+
} else {
264+
return res;
210265
}
211-
return new StickyOutlineElement(
212-
range,
213-
children,
214-
undefined
215-
);
216266
}
217267

218268
public static fromFoldingModel(foldingModel: FoldingModel): StickyOutlineElement {

src/vs/editor/contrib/stickyScroll/test/browser/stickyScroll.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ suite('Sticky Scroll Tests', () => {
252252
await withAsyncTestCodeEditor(model, { serviceCollection }, async (editor, _viewModel, instantiationService) => {
253253

254254
const stickyScrollController: StickyScrollController = editor.registerAndInstantiateContribution(StickyScrollController.ID, StickyScrollController);
255+
await stickyScrollController.stickyScrollCandidateProvider.update();
255256
const lineHeight = editor.getOption(EditorOption.lineHeight);
256257

257258
const languageService = instantiationService.get(ILanguageFeaturesService);

0 commit comments

Comments
 (0)