<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { DocumentSymbol, DocumentSymbolProviderRegistry } from 'vs/editor/common/modes';
import { IModelService } from 'vs/editor/common/services/modelService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ITextModelService } from 'vs/editor/common/services/resolverService';

export function getDocumentSymbols(model: ITextModel, flat: boolean, token: CancellationToken): Promise<DocumentSymbol[]> {

	let roots: DocumentSymbol[] = [];

	let promises = DocumentSymbolProviderRegistry.all(model).map(support => {

		return Promise.resolve(support.provideDocumentSymbols(model, token)).then(result => {
			if (Array.isArray(result)) {
				roots.push(...result);
			}
		}, err => {
			onUnexpectedExternalError(err);
		});
	});

	return Promise.all(promises).then(() => {
		let flatEntries: DocumentSymbol[] = [];
		if (token.isCancellationRequested) {
			return flatEntries;
		}
		if (flat) {
			flatten(flatEntries, roots, '');
		} else {
			flatEntries = roots;
		}
		flatEntries.sort(compareEntriesUsingStart);
		return flatEntries;
	});
}

function compareEntriesUsingStart(a: DocumentSymbol, b: DocumentSymbol): number {
	return Range.compareRangesUsingStarts(a.range, b.range);
}

function flatten(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideContainerLabel: string): void {
	for (let entry of entries) {
		bucket.push({
			kind: entry.kind,
			tags: entry.tags,
			name: entry.name,
			detail: entry.detail,
			containerName: entry.containerName || overrideContainerLabel,
			range: entry.range,
			selectionRange: entry.selectionRange,
			children: undefined, // we flatten it...
		});
		if (entry.children) {
			flatten(bucket, entry.children, entry.name);
		}
	}
}


registerLanguageCommand('_executeDocumentSymbolProvider', function (accessor, args) {
	const { resource } = args;
	if (!(resource instanceof URI)) {
		throw illegalArgument('resource');
	}
	const model = accessor.get(IModelService).getModel(resource);
	if (model) {
		return getDocumentSymbols(model, false, CancellationToken.None);
	}

	return accessor.get(ITextModelService).createModelReference(resource).then(reference => {
		return new Promise((resolve, reject) => {
			try {
				const result = getDocumentSymbols(reference.object.textEditorModel, false, CancellationToken.None);
				resolve(result);
			} catch (err) {
				reject(err);
			}
		}).finally(() => {
			reference.dispose();
		});
	});
});
<commit_msg>debt - quick outline using the same model cache as breadcrumbs and outline tree<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { illegalArgument } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { DocumentSymbol } from 'vs/editor/common/modes';
import { IModelService } from 'vs/editor/common/services/modelService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
import { values } from 'vs/base/common/collections';

export async function getDocumentSymbols(document: ITextModel, flat: boolean, token: CancellationToken): Promise<DocumentSymbol[]> {

	const model = await OutlineModel.create(document, token);
	const roots: DocumentSymbol[] = [];
	for (const child of values(model.children)) {
		if (child instanceof OutlineElement) {
			roots.push(child.symbol);
		} else {
			roots.push(...values(child.children).map(child => child.symbol));
		}
	}

	let flatEntries: DocumentSymbol[] = [];
	if (token.isCancellationRequested) {
		return flatEntries;
	}
	if (flat) {
		flatten(flatEntries, roots, '');
	} else {
		flatEntries = roots;
	}

	return flatEntries.sort(compareEntriesUsingStart);
}

function compareEntriesUsingStart(a: DocumentSymbol, b: DocumentSymbol): number {
	return Range.compareRangesUsingStarts(a.range, b.range);
}

function flatten(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideContainerLabel: string): void {
	for (let entry of entries) {
		bucket.push({
			kind: entry.kind,
			tags: entry.tags,
			name: entry.name,
			detail: entry.detail,
			containerName: entry.containerName || overrideContainerLabel,
			range: entry.range,
			selectionRange: entry.selectionRange,
			children: undefined, // we flatten it...
		});
		if (entry.children) {
			flatten(bucket, entry.children, entry.name);
		}
	}
}


registerLanguageCommand('_executeDocumentSymbolProvider', function (accessor, args) {
	const { resource } = args;
	if (!(resource instanceof URI)) {
		throw illegalArgument('resource');
	}
	const model = accessor.get(IModelService).getModel(resource);
	if (model) {
		return getDocumentSymbols(model, false, CancellationToken.None);
	}

	return accessor.get(ITextModelService).createModelReference(resource).then(reference => {
		return new Promise((resolve, reject) => {
			try {
				const result = getDocumentSymbols(reference.object.textEditorModel, false, CancellationToken.None);
				resolve(result);
			} catch (err) {
				reject(err);
			}
		}).finally(() => {
			reference.dispose();
		});
	});
});

{'fraction_non_alphanumeric': 0.18274111675126903, 'fraction_numerical': 0.0, 'mean_word_length': 3.572153734590283, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4545547', 'n_tokens_mistral': 1869, 'n_tokens_neox': 1750, 'n_words': 404}