UNPKG

sussudio

Version:

An unofficial VS Code Internal API

249 lines (248 loc) 12.5 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import { toErrorMessage } from "../../../base/common/errorMessage.mjs"; import { isCancellationError } from "../../../base/common/errors.mjs"; import { matchesContiguousSubString, matchesPrefix, matchesWords, or } from "../../../base/common/filters.mjs"; import { Disposable } from "../../../base/common/lifecycle.mjs"; import { LRUCache } from "../../../base/common/map.mjs"; import Severity from "../../../base/common/severity.mjs"; import { withNullAsUndefined } from "../../../base/common/types.mjs"; import { localize } from "../../../nls.mjs"; import { ICommandService } from "../../commands/common/commands.mjs"; import { IConfigurationService } from "../../configuration/common/configuration.mjs"; import { IDialogService } from "../../dialogs/common/dialogs.mjs"; import { IInstantiationService } from "../../instantiation/common/instantiation.mjs"; import { IKeybindingService } from "../../keybinding/common/keybinding.mjs"; import { PickerQuickAccessProvider } from "./pickerQuickAccess.mjs"; import { IStorageService } from "../../storage/common/storage.mjs"; import { ITelemetryService } from "../../telemetry/common/telemetry.mjs"; let AbstractCommandsQuickAccessProvider = class AbstractCommandsQuickAccessProvider extends PickerQuickAccessProvider { instantiationService; keybindingService; commandService; telemetryService; dialogService; static PREFIX = '>'; static WORD_FILTER = or(matchesPrefix, matchesWords, matchesContiguousSubString); commandsHistory = this._register(this.instantiationService.createInstance(CommandsHistory)); options; constructor(options, instantiationService, keybindingService, commandService, telemetryService, dialogService) { super(AbstractCommandsQuickAccessProvider.PREFIX, options); this.instantiationService = instantiationService; this.keybindingService = keybindingService; this.commandService = commandService; this.telemetryService = telemetryService; this.dialogService = dialogService; this.options = options; } async _getPicks(filter, _disposables, token) { // Ask subclass for all command picks const allCommandPicks = await this.getCommandPicks(token); if (token.isCancellationRequested) { return []; } // Filter const filteredCommandPicks = []; for (const commandPick of allCommandPicks) { const labelHighlights = withNullAsUndefined(AbstractCommandsQuickAccessProvider.WORD_FILTER(filter, commandPick.label)); const aliasHighlights = commandPick.commandAlias ? withNullAsUndefined(AbstractCommandsQuickAccessProvider.WORD_FILTER(filter, commandPick.commandAlias)) : undefined; // Add if matching in label or alias if (labelHighlights || aliasHighlights) { commandPick.highlights = { label: labelHighlights, detail: this.options.showAlias ? aliasHighlights : undefined }; filteredCommandPicks.push(commandPick); } // Also add if we have a 100% command ID match else if (filter === commandPick.commandId) { filteredCommandPicks.push(commandPick); } } // Add description to commands that have duplicate labels const mapLabelToCommand = new Map(); for (const commandPick of filteredCommandPicks) { const existingCommandForLabel = mapLabelToCommand.get(commandPick.label); if (existingCommandForLabel) { commandPick.description = commandPick.commandId; existingCommandForLabel.description = existingCommandForLabel.commandId; } else { mapLabelToCommand.set(commandPick.label, commandPick); } } // Sort by MRU order and fallback to name otherwise filteredCommandPicks.sort((commandPickA, commandPickB) => { const commandACounter = this.commandsHistory.peek(commandPickA.commandId); const commandBCounter = this.commandsHistory.peek(commandPickB.commandId); if (commandACounter && commandBCounter) { return commandACounter > commandBCounter ? -1 : 1; // use more recently used command before older } if (commandACounter) { return -1; // first command was used, so it wins over the non used one } if (commandBCounter) { return 1; // other command was used so it wins over the command } // both commands were never used, so we sort by name return commandPickA.label.localeCompare(commandPickB.label); }); const commandPicks = []; let addSeparator = false; for (let i = 0; i < filteredCommandPicks.length; i++) { const commandPick = filteredCommandPicks[i]; const keybinding = this.keybindingService.lookupKeybinding(commandPick.commandId); const ariaLabel = keybinding ? localize('commandPickAriaLabelWithKeybinding', "{0}, {1}", commandPick.label, keybinding.getAriaLabel()) : commandPick.label; // Separator: recently used if (i === 0 && this.commandsHistory.peek(commandPick.commandId)) { commandPicks.push({ type: 'separator', label: localize('recentlyUsed', "recently used") }); addSeparator = true; } // Separator: other commands if (i !== 0 && addSeparator && !this.commandsHistory.peek(commandPick.commandId)) { commandPicks.push({ type: 'separator', label: localize('morecCommands', "other commands") }); addSeparator = false; // only once } // Command commandPicks.push({ ...commandPick, ariaLabel, detail: this.options.showAlias && commandPick.commandAlias !== commandPick.label ? commandPick.commandAlias : undefined, keybinding, accept: async () => { // Add to history this.commandsHistory.push(commandPick.commandId); // Telementry this.telemetryService.publicLog2('workbenchActionExecuted', { id: commandPick.commandId, from: 'quick open' }); // Run try { await this.commandService.executeCommand(commandPick.commandId); } catch (error) { if (!isCancellationError(error)) { this.dialogService.show(Severity.Error, localize('canNotRun', "Command '{0}' resulted in an error ({1})", commandPick.label, toErrorMessage(error))); } } } }); } return commandPicks; } }; AbstractCommandsQuickAccessProvider = __decorate([ __param(1, IInstantiationService), __param(2, IKeybindingService), __param(3, ICommandService), __param(4, ITelemetryService), __param(5, IDialogService) ], AbstractCommandsQuickAccessProvider); export { AbstractCommandsQuickAccessProvider }; let CommandsHistory = class CommandsHistory extends Disposable { storageService; configurationService; static DEFAULT_COMMANDS_HISTORY_LENGTH = 50; static PREF_KEY_CACHE = 'commandPalette.mru.cache'; static PREF_KEY_COUNTER = 'commandPalette.mru.counter'; static cache; static counter = 1; configuredCommandsHistoryLength = 0; constructor(storageService, configurationService) { super(); this.storageService = storageService; this.configurationService = configurationService; this.updateConfiguration(); this.load(); this.registerListeners(); } registerListeners() { this._register(this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration(e))); } updateConfiguration(e) { if (e && !e.affectsConfiguration('workbench.commandPalette.history')) { return; } this.configuredCommandsHistoryLength = CommandsHistory.getConfiguredCommandHistoryLength(this.configurationService); if (CommandsHistory.cache && CommandsHistory.cache.limit !== this.configuredCommandsHistoryLength) { CommandsHistory.cache.limit = this.configuredCommandsHistoryLength; CommandsHistory.saveState(this.storageService); } } load() { const raw = this.storageService.get(CommandsHistory.PREF_KEY_CACHE, 0 /* StorageScope.PROFILE */); let serializedCache; if (raw) { try { serializedCache = JSON.parse(raw); } catch (error) { // invalid data } } const cache = CommandsHistory.cache = new LRUCache(this.configuredCommandsHistoryLength, 1); if (serializedCache) { let entries; if (serializedCache.usesLRU) { entries = serializedCache.entries; } else { entries = serializedCache.entries.sort((a, b) => a.value - b.value); } entries.forEach(entry => cache.set(entry.key, entry.value)); } CommandsHistory.counter = this.storageService.getNumber(CommandsHistory.PREF_KEY_COUNTER, 0 /* StorageScope.PROFILE */, CommandsHistory.counter); } push(commandId) { if (!CommandsHistory.cache) { return; } CommandsHistory.cache.set(commandId, CommandsHistory.counter++); // set counter to command CommandsHistory.saveState(this.storageService); } peek(commandId) { return CommandsHistory.cache?.peek(commandId); } static saveState(storageService) { if (!CommandsHistory.cache) { return; } const serializedCache = { usesLRU: true, entries: [] }; CommandsHistory.cache.forEach((value, key) => serializedCache.entries.push({ key, value })); storageService.store(CommandsHistory.PREF_KEY_CACHE, JSON.stringify(serializedCache), 0 /* StorageScope.PROFILE */, 0 /* StorageTarget.USER */); storageService.store(CommandsHistory.PREF_KEY_COUNTER, CommandsHistory.counter, 0 /* StorageScope.PROFILE */, 0 /* StorageTarget.USER */); } static getConfiguredCommandHistoryLength(configurationService) { const config = configurationService.getValue(); const configuredCommandHistoryLength = config.workbench?.commandPalette?.history; if (typeof configuredCommandHistoryLength === 'number') { return configuredCommandHistoryLength; } return CommandsHistory.DEFAULT_COMMANDS_HISTORY_LENGTH; } static clearHistory(configurationService, storageService) { const commandHistoryLength = CommandsHistory.getConfiguredCommandHistoryLength(configurationService); CommandsHistory.cache = new LRUCache(commandHistoryLength); CommandsHistory.counter = 1; CommandsHistory.saveState(storageService); } }; CommandsHistory = __decorate([ __param(0, IStorageService), __param(1, IConfigurationService) ], CommandsHistory); export { CommandsHistory };