diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index b28472f8120a2..81cb5ed54c504 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -171,6 +171,7 @@ "./vs/editor/contrib/comment/test/lineCommentCommand.test.ts", "./vs/editor/contrib/contextmenu/contextmenu.ts", "./vs/editor/contrib/cursorUndo/cursorUndo.ts", + "./vs/editor/contrib/documentSymbols/outlineModel.ts", "./vs/editor/contrib/dnd/dnd.ts", "./vs/editor/contrib/dnd/dragAndDropCommand.ts", "./vs/editor/contrib/find/findController.ts", @@ -531,6 +532,8 @@ "./vs/workbench/browser/parts/editor/baseEditor.ts", "./vs/workbench/browser/parts/editor/binaryDiffEditor.ts", "./vs/workbench/browser/parts/editor/binaryEditor.ts", + "./vs/workbench/browser/parts/editor/breadcrumbs.ts", + "./vs/workbench/browser/parts/editor/breadcrumbsModel.ts", "./vs/workbench/browser/parts/editor/editor.ts", "./vs/workbench/browser/parts/editor/editorControl.ts", "./vs/workbench/browser/parts/editor/editorWidgets.ts", diff --git a/src/vs/editor/contrib/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts index 4373e21fbec85..cf559331c5277 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineModel.ts @@ -20,12 +20,14 @@ export abstract class TreeElement { abstract id: string; abstract children: { [id: string]: TreeElement }; - abstract parent: TreeElement; + abstract parent: TreeElement | undefined; abstract adopt(newParent: TreeElement): TreeElement; remove(): void { - delete this.parent.children[this.id]; + if (this.parent) { + delete this.parent.children[this.id]; + } } static findId(candidate: DocumentSymbol | string, container: TreeElement): string { @@ -88,18 +90,18 @@ export abstract class TreeElement { export class OutlineElement extends TreeElement { children: { [id: string]: OutlineElement; } = Object.create(null); - score: FuzzyScore = FuzzyScore.Default; - marker: { count: number, topSev: MarkerSeverity }; + score: FuzzyScore | undefined = FuzzyScore.Default; + marker: { count: number, topSev: MarkerSeverity } | undefined; constructor( readonly id: string, - public parent: OutlineModel | OutlineGroup | OutlineElement, + public parent: TreeElement | undefined, readonly symbol: DocumentSymbol ) { super(); } - adopt(parent: OutlineModel | OutlineGroup | OutlineElement): OutlineElement { + adopt(parent: TreeElement): OutlineElement { let res = new OutlineElement(this.id, parent, this.symbol); forEach(this.children, entry => res.children[entry.key] = entry.value.adopt(res)); return res; @@ -112,33 +114,33 @@ export class OutlineGroup extends TreeElement { constructor( readonly id: string, - public parent: OutlineModel, + public parent: TreeElement | undefined, readonly provider: DocumentSymbolProvider, readonly providerIndex: number, ) { super(); } - adopt(parent: OutlineModel): OutlineGroup { + adopt(parent: TreeElement): OutlineGroup { let res = new OutlineGroup(this.id, parent, this.provider, this.providerIndex); forEach(this.children, entry => res.children[entry.key] = entry.value.adopt(res)); return res; } - updateMatches(pattern: string, topMatch: OutlineElement): OutlineElement { + updateMatches(pattern: string, topMatch: OutlineElement | undefined): OutlineElement | undefined { for (const key in this.children) { topMatch = this._updateMatches(pattern, this.children[key], topMatch); } return topMatch; } - private _updateMatches(pattern: string, item: OutlineElement, topMatch: OutlineElement): OutlineElement { + private _updateMatches(pattern: string, item: OutlineElement, topMatch: OutlineElement | undefined): OutlineElement | undefined { item.score = pattern ? fuzzyScore(pattern, pattern.toLowerCase(), 0, item.symbol.name, item.symbol.name.toLowerCase(), 0, true) : FuzzyScore.Default; - if (item.score && (!topMatch || item.score[0] > topMatch.score[0])) { + if (item.score && (!topMatch || !topMatch.score || item.score[0] > topMatch.score[0])) { topMatch = item; } for (const key in item.children) { @@ -152,11 +154,11 @@ export class OutlineGroup extends TreeElement { return topMatch; } - getItemEnclosingPosition(position: IPosition): OutlineElement { + getItemEnclosingPosition(position: IPosition): OutlineElement | undefined { return position ? this._getItemEnclosingPosition(position, this.children) : undefined; } - private _getItemEnclosingPosition(position: IPosition, children: { [id: string]: OutlineElement }): OutlineElement { + private _getItemEnclosingPosition(position: IPosition, children: { [id: string]: OutlineElement }): OutlineElement | undefined { for (let key in children) { let item = children[key]; if (!item.symbol.range || !Range.containsPosition(item.symbol.range, position)) { @@ -174,7 +176,6 @@ export class OutlineGroup extends TreeElement { } private _updateMarker(markers: IMarker[], item: OutlineElement): void { - item.marker = undefined; // find the proper start index to check for item/marker overlap. @@ -190,14 +191,14 @@ export class OutlineGroup extends TreeElement { } let myMarkers: IMarker[] = []; - let myTopSev: MarkerSeverity; + let myTopSev: MarkerSeverity | undefined; for (; start < markers.length && Range.areIntersecting(item.symbol.range, markers[start]); start++) { // remove markers intersecting with this outline element // and store them in a 'private' array. let marker = markers[start]; myMarkers.push(marker); - markers[start] = undefined; + (markers as Array)[start] = undefined; if (!myTopSev || marker.severity > myTopSev) { myTopSev = marker.severity; } @@ -224,7 +225,7 @@ export class OutlineGroup extends TreeElement { export class OutlineModel extends TreeElement { - private static readonly _requests = new LRUCache, model: OutlineModel }>(9, 0.75); + private static readonly _requests = new LRUCache, model: OutlineModel | undefined }>(9, 0.75); private static readonly _keys = new class { private _counter = 1; @@ -265,25 +266,25 @@ export class OutlineModel extends TreeElement { OutlineModel._requests.set(key, data); } - if (data.model) { + if (data!.model) { // resolved -> return data return Promise.resolve(data.model); } // increase usage counter - data.promiseCnt += 1; + data!.promiseCnt += 1; token.onCancellationRequested(() => { // last -> cancel provider request, remove cached promise - if (--data.promiseCnt === 0) { - data.source.cancel(); + if (--data!.promiseCnt === 0) { + data!.source.cancel(); OutlineModel._requests.delete(key); } }); return new Promise((resolve, reject) => { - data.promise.then(model => { - data.model = model; + data!.promise.then(model => { + data!.model = model; resolve(model); }, err => { OutlineModel._requests.delete(key); @@ -331,7 +332,7 @@ export class OutlineModel extends TreeElement { container.children[res.id] = res; } - static get(element: TreeElement): OutlineModel { + static get(element: TreeElement | undefined): OutlineModel | undefined { while (element) { if (element instanceof OutlineModel) { return element; @@ -373,8 +374,8 @@ export class OutlineModel extends TreeElement { } else { // adopt all elements of the first group let group = first(this._groups); - for (let key in group.children) { - let child = group.children[key]; + for (let key in group!.children) { + let child = group!.children[key]; child.parent = this; this.children[child.id] = child; } @@ -394,13 +395,13 @@ export class OutlineModel extends TreeElement { return true; } - private _matches: [string, OutlineElement]; + private _matches: [string, OutlineElement | undefined]; - updateMatches(pattern: string): OutlineElement { + updateMatches(pattern: string): OutlineElement | undefined { if (this._matches && this._matches[0] === pattern) { return this._matches[1]; } - let topMatch: OutlineElement; + let topMatch: OutlineElement | undefined; for (const key in this._groups) { topMatch = this._groups[key].updateMatches(pattern, topMatch); } @@ -408,9 +409,9 @@ export class OutlineModel extends TreeElement { return topMatch; } - getItemEnclosingPosition(position: IPosition, context?: OutlineElement): OutlineElement { + getItemEnclosingPosition(position: IPosition, context?: OutlineElement): OutlineElement | undefined { - let preferredGroup: OutlineGroup; + let preferredGroup: OutlineGroup | undefined; if (context) { let candidate = context.parent; while (candidate && !preferredGroup) { @@ -432,7 +433,7 @@ export class OutlineModel extends TreeElement { return result; } - getItemById(id: string): TreeElement { + getItemById(id: string): TreeElement | undefined { return TreeElement.getElementById(id, this); } diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts index 93f4fe6aeaa9f..43ae1ecc38388 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts @@ -23,7 +23,7 @@ export interface IBreadcrumbsService { register(group: GroupIdentifier, widget: BreadcrumbsWidget): IDisposable; - getWidget(group: GroupIdentifier): BreadcrumbsWidget; + getWidget(group: GroupIdentifier): BreadcrumbsWidget | undefined; } @@ -43,7 +43,7 @@ export class BreadcrumbsService implements IBreadcrumbsService { }; } - getWidget(group: number): BreadcrumbsWidget { + getWidget(group: number): BreadcrumbsWidget | undefined { return this._map.get(group); } } @@ -90,10 +90,18 @@ export abstract class BreadcrumbsConfig { readonly name = name; readonly onDidChange = onDidChange.event; getValue(overrides?: IConfigurationOverrides): T { - return service.getValue(name, overrides); + if (overrides) { + return service.getValue(name, overrides); + } else { + return service.getValue(name); + } } updateValue(newValue: T, overrides?: IConfigurationOverrides): Promise { - return service.updateValue(name, newValue, overrides); + if (overrides) { + return service.updateValue(name, newValue, overrides); + } else { + return service.updateValue(name, newValue); + } } dispose(): void { listener.dispose(); diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts index 9ef5e5681faca..5edc694dd8518 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts @@ -31,7 +31,7 @@ export class FileElement { export type BreadcrumbElement = FileElement | OutlineModel | OutlineGroup | OutlineElement; -type FileInfo = { path: FileElement[], folder: IWorkspaceFolder }; +type FileInfo = { path: FileElement[], folder?: IWorkspaceFolder }; export class EditorBreadcrumbsModel { @@ -105,17 +105,19 @@ export class EditorBreadcrumbsModel { } let info: FileInfo = { - folder: workspaceService.getWorkspaceFolder(uri), + folder: workspaceService.getWorkspaceFolder(uri) || undefined, path: [] }; - while (uri.path !== '/') { - if (info.folder && isEqual(info.folder.uri, uri)) { + + let uriPrefix: URI | null = uri; + while (uriPrefix && uriPrefix.path !== '/') { + if (info.folder && isEqual(info.folder.uri, uriPrefix)) { break; } - info.path.unshift(new FileElement(uri, info.path.length === 0 ? FileKind.FILE : FileKind.FOLDER)); - let prevPathLength = uri.path.length; - uri = dirname(uri); - if (uri.path.length === prevPathLength) { + info.path.unshift(new FileElement(uriPrefix, info.path.length === 0 ? FileKind.FILE : FileKind.FOLDER)); + let prevPathLength = uriPrefix.path.length; + uriPrefix = dirname(uriPrefix); + if (!uriPrefix || uriPrefix.path.length === prevPathLength) { break; } } @@ -148,7 +150,9 @@ export class EditorBreadcrumbsModel { this._updateOutlineElements([]); } - const buffer = this._editor.getModel(); + const editor = this._editor!; + + const buffer = editor.getModel(); if (!buffer || !DocumentSymbolProviderRegistry.has(buffer) || !isEqual(buffer.uri, this._uri)) { return; } @@ -174,11 +178,11 @@ export class EditorBreadcrumbsModel { // copy the model model = model.adopt(); - this._updateOutlineElements(this._getOutlineElements(model, this._editor.getPosition())); - this._outlineDisposables.push(this._editor.onDidChangeCursorPosition(_ => { + this._updateOutlineElements(this._getOutlineElements(model, editor.getPosition())); + this._outlineDisposables.push(editor.onDidChangeCursorPosition(_ => { timeout.cancelAndSet(() => { - if (!buffer.isDisposed() && versionIdThen === buffer.getVersionId() && this._editor.getModel()) { - this._updateOutlineElements(this._getOutlineElements(model, this._editor.getPosition())); + if (!buffer.isDisposed() && versionIdThen === buffer.getVersionId() && editor.getModel()) { + this._updateOutlineElements(this._getOutlineElements(model, editor.getPosition())); } }, 150); })); @@ -189,11 +193,11 @@ export class EditorBreadcrumbsModel { }); } - private _getOutlineElements(model: OutlineModel, position: IPosition): Array { - if (!model) { + private _getOutlineElements(model: OutlineModel, position: IPosition | null): Array { + if (!model || !position) { return []; } - let item: OutlineGroup | OutlineElement = model.getItemEnclosingPosition(position); + let item: OutlineGroup | OutlineElement | undefined = model.getItemEnclosingPosition(position); if (!item) { return [model]; } @@ -204,7 +208,7 @@ export class EditorBreadcrumbsModel { if (parent instanceof OutlineModel) { break; } - if (parent instanceof OutlineGroup && size(parent.parent.children) === 1) { + if (parent instanceof OutlineGroup && parent.parent && size(parent.parent.children) === 1) { break; } item = parent;