UNPKG

monaco-editor-core

Version:

A browser based code editor

105 lines (104 loc) 4.26 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { CancellationToken } from '../../../../base/common/cancellation.js'; import { illegalArgument, onUnexpectedExternalError } from '../../../../base/common/errors.js'; import { DisposableStore } from '../../../../base/common/lifecycle.js'; import { assertType } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import { IModelService } from '../../../common/services/model.js'; import { CommandsRegistry } from '../../../../platform/commands/common/commands.js'; import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js'; export class CodeLensModel { constructor() { this.lenses = []; this._disposables = new DisposableStore(); } dispose() { this._disposables.dispose(); } get isDisposed() { return this._disposables.isDisposed; } add(list, provider) { this._disposables.add(list); for (const symbol of list.lenses) { this.lenses.push({ symbol, provider }); } } } export async function getCodeLensModel(registry, model, token) { const provider = registry.ordered(model); const providerRanks = new Map(); const result = new CodeLensModel(); const promises = provider.map(async (provider, i) => { providerRanks.set(provider, i); try { const list = await Promise.resolve(provider.provideCodeLenses(model, token)); if (list) { result.add(list, provider); } } catch (err) { onUnexpectedExternalError(err); } }); await Promise.all(promises); result.lenses = result.lenses.sort((a, b) => { // sort by lineNumber, provider-rank, and column if (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) { return -1; } else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) { return 1; } else if ((providerRanks.get(a.provider)) < (providerRanks.get(b.provider))) { return -1; } else if ((providerRanks.get(a.provider)) > (providerRanks.get(b.provider))) { return 1; } else if (a.symbol.range.startColumn < b.symbol.range.startColumn) { return -1; } else if (a.symbol.range.startColumn > b.symbol.range.startColumn) { return 1; } else { return 0; } }); return result; } CommandsRegistry.registerCommand('_executeCodeLensProvider', function (accessor, ...args) { let [uri, itemResolveCount] = args; assertType(URI.isUri(uri)); assertType(typeof itemResolveCount === 'number' || !itemResolveCount); const { codeLensProvider } = accessor.get(ILanguageFeaturesService); const model = accessor.get(IModelService).getModel(uri); if (!model) { throw illegalArgument(); } const result = []; const disposables = new DisposableStore(); return getCodeLensModel(codeLensProvider, model, CancellationToken.None).then(value => { disposables.add(value); const resolve = []; for (const item of value.lenses) { if (itemResolveCount === undefined || itemResolveCount === null || Boolean(item.symbol.command)) { result.push(item.symbol); } else if (itemResolveCount-- > 0 && item.provider.resolveCodeLens) { resolve.push(Promise.resolve(item.provider.resolveCodeLens(model, item.symbol, CancellationToken.None)).then(symbol => result.push(symbol || item.symbol))); } } return Promise.all(resolve); }).then(() => { return result; }).finally(() => { // make sure to return results, then (on next tick) // dispose the results setTimeout(() => disposables.dispose(), 100); }); });